tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CustomAttributes.cpp (4687B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "CustomAttributes.h"
      6 #include "plugin.h"
      7 #include "clang/Frontend/FrontendPluginRegistry.h"
      8 
      9 /* Having annotations in the AST unexpectedly impacts codegen.
     10 * Ideally, we'd avoid having annotations at all, by using an API such as
     11 * the one from https://reviews.llvm.org/D31338, and storing the attributes
     12 * data separately from the AST on our own. Unfortunately, there is no such
     13 * API currently in clang, so we must do without.
     14 * We can do something similar, though, where we go through the AST before
     15 * running the checks, create a mapping of AST nodes to attributes, and
     16 * remove the attributes/annotations from the AST nodes.
     17 * Not all declarations can be reached from the decl() AST matcher, though,
     18 * so we do our best effort (getting the other declarations we look at in
     19 * checks). We emit a warning when checks look at a note that still has
     20 * annotations attached (aka, hasn't been seen during our first pass),
     21 * so that those don't go unnoticed. (-Werror should then take care of
     22 * making that an error)
     23 */
     24 
     25 using namespace clang;
     26 using namespace llvm;
     27 
     28 static DenseMap<const Decl *, CustomAttributesSet> AttributesCache;
     29 
     30 static CustomAttributesSet CacheAttributes(const Decl *D) {
     31  CustomAttributesSet attrs = {};
     32  for (auto Attr : D->specific_attrs<AnnotateAttr>()) {
     33    auto annotation = Attr->getAnnotation();
     34 #define ATTR(a)                                                                \
     35  if (annotation == #a) {                                                      \
     36    attrs.has_##a = true;                                                      \
     37  } else
     38 #include "CustomAttributes.inc"
     39 #include "external/CustomAttributes.inc"
     40 #undef ATTR
     41    {}
     42  }
     43  const_cast<Decl *>(D)->dropAttr<AnnotateAttr>();
     44  AttributesCache.insert(std::make_pair(D, attrs));
     45  return attrs;
     46 }
     47 
     48 #ifndef CLANG_TIDY
     49 static void Report(const Decl *D, const char *message) {
     50  ASTContext &Context = D->getASTContext();
     51  DiagnosticsEngine &Diag = Context.getDiagnostics();
     52  unsigned ID =
     53      Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Warning, message);
     54  Diag.Report(D->getBeginLoc(), ID);
     55 }
     56 
     57 class CustomAttributesMatcher
     58    : public ast_matchers::MatchFinder::MatchCallback {
     59 public:
     60  void run(const ast_matchers::MatchFinder::MatchResult &Result) final {
     61    if (auto D = Result.Nodes.getNodeAs<Decl>("decl")) {
     62      CacheAttributes(D);
     63    } else if (auto L = Result.Nodes.getNodeAs<LambdaExpr>("lambda")) {
     64      CacheAttributes(L->getCallOperator());
     65      CacheAttributes(L->getLambdaClass());
     66    }
     67  }
     68 };
     69 
     70 class CustomAttributesAction : public PluginASTAction {
     71 public:
     72  ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI,
     73                                   StringRef FileName) override {
     74    auto &Context = CI.getASTContext();
     75    auto AstMatcher = new (Context.Allocate<MatchFinder>()) MatchFinder();
     76    auto Matcher = new (Context.Allocate<CustomAttributesMatcher>())
     77        CustomAttributesMatcher();
     78    AstMatcher->addMatcher(decl().bind("decl"), Matcher);
     79    AstMatcher->addMatcher(lambdaExpr().bind("lambda"), Matcher);
     80    return AstMatcher->newASTConsumer();
     81  }
     82 
     83  bool ParseArgs(const CompilerInstance &CI,
     84                 const std::vector<std::string> &Args) override {
     85    return true;
     86  }
     87 
     88  ActionType getActionType() override { return AddBeforeMainAction; }
     89 };
     90 
     91 static FrontendPluginRegistry::Add<CustomAttributesAction>
     92    X("moz-custom-attributes", "prepare custom attributes for moz-check");
     93 #endif
     94 
     95 CustomAttributesSet GetAttributes(const Decl *D) {
     96  CustomAttributesSet attrs = {};
     97  if (D->hasAttr<AnnotateAttr>()) {
     98 // If we are not in clang-tidy env push warnings, most likely we are in the
     99 // build environment and this should have been done in AstMatcher -
    100 // CustomAttributesMatcher
    101 #ifndef CLANG_TIDY
    102    Report(D, "Declaration has unhandled annotations.");
    103 #endif
    104    attrs = CacheAttributes(D);
    105  } else {
    106    auto attributes = AttributesCache.find(D);
    107    if (attributes != AttributesCache.end()) {
    108      attrs = attributes->second;
    109    }
    110  }
    111  return attrs;
    112 }
    113 
    114 bool hasCustomAttribute(const clang::Decl *D, CustomAttributes A) {
    115  CustomAttributesSet attrs = GetAttributes(D);
    116  switch (A) {
    117 #define ATTR(a)                                                                \
    118  case a:                                                                      \
    119    return attrs.has_##a;
    120 #include "CustomAttributes.inc"
    121 #include "external/CustomAttributes.inc"
    122 #undef ATTR
    123  }
    124  return false;
    125 }