text: //===- AnnotateFunctions.cpp ----------------------------------------------===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  //
  // Example clang plugin which adds an annotation to every function in
  // translation units that start with #pragma enable_annotate.
  //
  //===----------------------------------------------------------------------===//
  
  #include "clang/Frontend/FrontendPluginRegistry.h"
  #include "clang/AST/AST.h"
  #include "clang/AST/ASTConsumer.h"
  #include "clang/Lex/Preprocessor.h"
  #include "clang/Lex/LexDiagnostic.h"
  using namespace clang;
  
  namespace {
  
  static bool EnableAnnotate = false;
  static bool HandledDecl = false;
  
  class AnnotateFunctionsConsumer : public ASTConsumer {
  public:
    bool HandleTopLevelDecl(DeclGroupRef DG) override {
      HandledDecl = true;
      if (!EnableAnnotate)
        return true;
      for (auto D : DG)
        if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
          FD->addAttr(AnnotateAttr::CreateImplicit(FD->getASTContext(),
                                                   "example_annotation"));
      return true;
    }
  };
  
  class AnnotateFunctionsAction : public PluginASTAction {
  public:
    std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                   llvm::StringRef) override {
      return std::make_unique<AnnotateFunctionsConsumer>();
    }
  
    bool ParseArgs(const CompilerInstance &CI,
                   const std::vector<std::string> &args) override {
      return true;
    }
  
    PluginASTAction::ActionType getActionType() override {
      return AddBeforeMainAction;
    }
  };
  
  class PragmaAnnotateHandler : public PragmaHandler {
  public:
    PragmaAnnotateHandler() : PragmaHandler("enable_annotate") { }
  
    void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
                      Token &PragmaTok) override {
  
      Token Tok;
      PP.LexUnexpandedToken(Tok);
      if (Tok.isNot(tok::eod))
        PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
  
      if (HandledDecl) {
        DiagnosticsEngine &D = PP.getDiagnostics();
        unsigned ID = D.getCustomDiagID(
          DiagnosticsEngine::Error,
          "#pragma enable_annotate not allowed after declarations");
        D.Report(PragmaTok.getLocation(), ID);
      }
  
      EnableAnnotate = true;
    }
  };
  
  }
  
  static FrontendPluginRegistry::Add<AnnotateFunctionsAction>
  X("annotate-fns", "annotate functions");
  
  static PragmaHandlerRegistry::Add<PragmaAnnotateHandler>
  Y("enable_annotate","enable annotation");
  