1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
//===--- 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() {}
MacroWalking getMacroWalkingBehavior() const override {
return MacroWalking::Expansion;
}
PreWalkResult<Expr *> walkToExprPre(Expr *E) override {
if (isa<ErrorExpr>(E) || !E->getType() || E->getType()->hasError())
error = true;
return Action::StopIf(error, E);
}
PreWalkAction walkToDeclPre(Decl *D) override {
if (auto *VD = dyn_cast<ValueDecl>(D)) {
if (!VD->hasInterfaceType() || VD->getInterfaceType()->hasError())
error = true;
}
return Action::StopIf(error);
}
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(std::optional<DeclNameRef> name,
SourceRange SR) {
if (!name)
return IntegerLiteralExpr::createFromUnsigned(Context, 0, SR.End);
return new (Context) UnresolvedDeclRefExpr(*name, DeclRefKind::Ordinary,
DeclNameLoc(SR.End));
}
|