blob: fae3b3149f152e2479ccc1019cf508f0fcebe24e [file] [log] [blame]
//===--- InstrumenterSupport.cpp - Instrumenter Support -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the supporting functions for writing instrumenters of
// the Swift AST.
//
//===----------------------------------------------------------------------===//
#include "InstrumenterSupport.h"
#include "swift/AST/DiagnosticSuppression.h"
#include "swift/AST/SourceFile.h"
#include "swift/Demangling/Punycode.h"
#include "llvm/Support/Path.h"
using namespace swift;
using namespace swift::instrumenter_support;
namespace {
class ErrorGatherer : public DiagnosticConsumer {
private:
bool error = false;
DiagnosticEngine &diags;
public:
ErrorGatherer(DiagnosticEngine &diags) : diags(diags) {
diags.addConsumer(*this);
}
~ErrorGatherer() override { diags.takeConsumers(); }
void handleDiagnostic(SourceManager &SM,
const DiagnosticInfo &Info) override {
if (Info.Kind == swift::DiagnosticKind::Error) {
error = true;
}
DiagnosticEngine::formatDiagnosticText(llvm::errs(), Info.FormatString,
Info.FormatArgs);
llvm::errs() << "\n";
}
bool hadError() { return error; }
};
class ErrorFinder : public ASTWalker {
bool error = false;
public:
ErrorFinder() {}
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
if (isa<ErrorExpr>(E) || !E->getType() || E->getType()->hasError()) {
error = true;
return {false, E};
}
return {true, E};
}
bool walkToDeclPre(Decl *D) override {
if (auto *VD = dyn_cast<ValueDecl>(D)) {
if (!VD->hasInterfaceType() || VD->getInterfaceType()->hasError()) {
error = true;
return false;
}
}
return true;
}
bool hadError() { return error; }
};
} // end anonymous namespace
InstrumenterBase::InstrumenterBase(ASTContext &C, DeclContext *DC)
: Context(C), TypeCheckDC(DC), CF(*this) {
// Prefixes for module and file vars
const std::string builtinPrefix = "__builtin";
const std::string modulePrefix = "_pg_module_";
const std::string filePrefix = "_pg_file_";
// Setup Module identifier
std::string moduleName =
std::string(TypeCheckDC->getParentModule()->getName());
Identifier moduleIdentifier =
Context.getIdentifier(builtinPrefix + modulePrefix + moduleName);
SmallVector<ValueDecl *, 1> results;
TypeCheckDC->getParentModule()->lookupValue(
moduleIdentifier, NLKind::UnqualifiedLookup, results);
if (results.size() == 1)
ModuleIdentifier = results.front()->createNameRef();
// Setup File identifier
StringRef filePath = TypeCheckDC->getParentSourceFile()->getFilename();
StringRef fileName = llvm::sys::path::stem(filePath);
std::string filePunycodeName;
Punycode::encodePunycodeUTF8(fileName, filePunycodeName, true);
Identifier fileIdentifier =
Context.getIdentifier(builtinPrefix + modulePrefix + moduleName +
filePrefix + filePunycodeName);
results.clear();
TypeCheckDC->getParentModule()->lookupValue(
fileIdentifier, NLKind::UnqualifiedLookup, results);
if (results.size() == 1)
FileIdentifier = results.front()->createNameRef();
}
void InstrumenterBase::anchor() {}
bool InstrumenterBase::doTypeCheckImpl(ASTContext &Ctx, DeclContext *DC,
Expr * &parsedExpr) {
DiagnosticSuppression suppression(Ctx.Diags);
ErrorGatherer errorGatherer(Ctx.Diags);
TypeChecker::typeCheckExpression(parsedExpr, DC, /*contextualInfo=*/{});
if (parsedExpr) {
ErrorFinder errorFinder;
parsedExpr->walk(errorFinder);
if (!errorFinder.hadError() && !errorGatherer.hadError()) {
return true;
}
}
return false;
}
Expr *InstrumenterBase::buildIDArgumentExpr(Optional<DeclNameRef> name,
SourceRange SR) {
if (!name)
return IntegerLiteralExpr::createFromUnsigned(Context, 0);
return new (Context) UnresolvedDeclRefExpr(*name, DeclRefKind::Ordinary,
DeclNameLoc(SR.End));
}