diff options
Diffstat (limited to 'lib/Frontend/FrontendActions.cpp')
| -rw-r--r-- | lib/Frontend/FrontendActions.cpp | 254 | 
1 files changed, 248 insertions, 6 deletions
| diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index ffa5b410d2d8..9344e673c7ac 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -18,17 +18,36 @@  #include "clang/Lex/HeaderSearch.h"  #include "clang/Lex/Preprocessor.h"  #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Sema/TemplateInstCallback.h"  #include "clang/Serialization/ASTReader.h"  #include "clang/Serialization/ASTWriter.h"  #include "llvm/Support/FileSystem.h"  #include "llvm/Support/MemoryBuffer.h"  #include "llvm/Support/Path.h"  #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/YAMLTraits.h"  #include <memory>  #include <system_error>  using namespace clang; +namespace { +CodeCompleteConsumer *GetCodeCompletionConsumer(CompilerInstance &CI) { +  return CI.hasCodeCompletionConsumer() ? &CI.getCodeCompletionConsumer() +                                        : nullptr; +} + +void EnsureSemaIsCreated(CompilerInstance &CI, FrontendAction &Action) { +  if (Action.hasCodeCompletionSupport() && +      !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) +    CI.createCodeCompletionConsumer(); + +  if (!CI.hasSema()) +    CI.createSema(Action.getTranslationUnitKind(), +                  GetCodeCompletionConsumer(CI)); +} +} // namespace +  //===----------------------------------------------------------------------===//  // Custom Actions  //===----------------------------------------------------------------------===// @@ -55,7 +74,8 @@ ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {  std::unique_ptr<ASTConsumer>  ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { -  return CreateASTDumper(CI.getFrontendOpts().ASTDumpFilter, +  return CreateASTDumper(nullptr /*Dump to stdout.*/, +                         CI.getFrontendOpts().ASTDumpFilter,                           CI.getFrontendOpts().ASTDumpDecls,                           CI.getFrontendOpts().ASTDumpAll,                           CI.getFrontendOpts().ASTDumpLookups); @@ -92,14 +112,14 @@ GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {    if (!CI.getFrontendOpts().RelocatablePCH)      Sysroot.clear(); +  const auto &FrontendOpts = CI.getFrontendOpts();    auto Buffer = std::make_shared<PCHBuffer>();    std::vector<std::unique_ptr<ASTConsumer>> Consumers;    Consumers.push_back(llvm::make_unique<PCHGenerator>(                          CI.getPreprocessor(), OutputFile, Sysroot, -                        Buffer, CI.getFrontendOpts().ModuleFileExtensions, -      /*AllowASTWithErrors*/CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, -                        /*IncludeTimestamps*/ -                          +CI.getFrontendOpts().IncludeTimestamps)); +                        Buffer, FrontendOpts.ModuleFileExtensions, +                        CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, +                        FrontendOpts.IncludeTimestamps));    Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(        CI, InFile, OutputFile, std::move(OS), Buffer)); @@ -262,7 +282,141 @@ void VerifyPCHAction::ExecuteAction() {  }  namespace { -  /// \brief AST reader listener that dumps module information for a module +struct TemplightEntry { +  std::string Name; +  std::string Kind; +  std::string Event; +  std::string DefinitionLocation; +  std::string PointOfInstantiation; +}; +} // namespace + +namespace llvm { +namespace yaml { +template <> struct MappingTraits<TemplightEntry> { +  static void mapping(IO &io, TemplightEntry &fields) { +    io.mapRequired("name", fields.Name); +    io.mapRequired("kind", fields.Kind); +    io.mapRequired("event", fields.Event); +    io.mapRequired("orig", fields.DefinitionLocation); +    io.mapRequired("poi", fields.PointOfInstantiation); +  } +}; +} // namespace yaml +} // namespace llvm + +namespace { +class DefaultTemplateInstCallback : public TemplateInstantiationCallback { +  using CodeSynthesisContext = Sema::CodeSynthesisContext; + +public: +  void initialize(const Sema &) override {} + +  void finalize(const Sema &) override {} + +  void atTemplateBegin(const Sema &TheSema, +                       const CodeSynthesisContext &Inst) override { +    displayTemplightEntry<true>(llvm::outs(), TheSema, Inst); +  } + +  void atTemplateEnd(const Sema &TheSema, +                     const CodeSynthesisContext &Inst) override { +    displayTemplightEntry<false>(llvm::outs(), TheSema, Inst); +  } + +private: +  static std::string toString(CodeSynthesisContext::SynthesisKind Kind) { +    switch (Kind) { +    case CodeSynthesisContext::TemplateInstantiation: +      return "TemplateInstantiation"; +    case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: +      return "DefaultTemplateArgumentInstantiation"; +    case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: +      return "DefaultFunctionArgumentInstantiation"; +    case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: +      return "ExplicitTemplateArgumentSubstitution"; +    case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: +      return "DeducedTemplateArgumentSubstitution"; +    case CodeSynthesisContext::PriorTemplateArgumentSubstitution: +      return "PriorTemplateArgumentSubstitution"; +    case CodeSynthesisContext::DefaultTemplateArgumentChecking: +      return "DefaultTemplateArgumentChecking"; +    case CodeSynthesisContext::ExceptionSpecInstantiation: +      return "ExceptionSpecInstantiation"; +    case CodeSynthesisContext::DeclaringSpecialMember: +      return "DeclaringSpecialMember"; +    case CodeSynthesisContext::DefiningSynthesizedFunction: +      return "DefiningSynthesizedFunction"; +    case CodeSynthesisContext::Memoization: +      return "Memoization"; +    } +    return ""; +  } + +  template <bool BeginInstantiation> +  static void displayTemplightEntry(llvm::raw_ostream &Out, const Sema &TheSema, +                                    const CodeSynthesisContext &Inst) { +    std::string YAML; +    { +      llvm::raw_string_ostream OS(YAML); +      llvm::yaml::Output YO(OS); +      TemplightEntry Entry = +          getTemplightEntry<BeginInstantiation>(TheSema, Inst); +      llvm::yaml::EmptyContext Context; +      llvm::yaml::yamlize(YO, Entry, true, Context); +    } +    Out << "---" << YAML << "\n"; +  } + +  template <bool BeginInstantiation> +  static TemplightEntry getTemplightEntry(const Sema &TheSema, +                                          const CodeSynthesisContext &Inst) { +    TemplightEntry Entry; +    Entry.Kind = toString(Inst.Kind); +    Entry.Event = BeginInstantiation ? "Begin" : "End"; +    if (auto *NamedTemplate = dyn_cast_or_null<NamedDecl>(Inst.Entity)) { +      llvm::raw_string_ostream OS(Entry.Name); +      NamedTemplate->getNameForDiagnostic(OS, TheSema.getLangOpts(), true); +      const PresumedLoc DefLoc =  +        TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation()); +      if(!DefLoc.isInvalid()) +        Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" + +                                   std::to_string(DefLoc.getLine()) + ":" + +                                   std::to_string(DefLoc.getColumn()); +    } +    const PresumedLoc PoiLoc = +        TheSema.getSourceManager().getPresumedLoc(Inst.PointOfInstantiation); +    if (!PoiLoc.isInvalid()) { +      Entry.PointOfInstantiation = std::string(PoiLoc.getFilename()) + ":" + +                                   std::to_string(PoiLoc.getLine()) + ":" + +                                   std::to_string(PoiLoc.getColumn()); +    } +    return Entry; +  } +}; +} // namespace + +std::unique_ptr<ASTConsumer> +TemplightDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { +  return llvm::make_unique<ASTConsumer>(); +} + +void TemplightDumpAction::ExecuteAction() { +  CompilerInstance &CI = getCompilerInstance(); + +  // This part is normally done by ASTFrontEndAction, but needs to happen +  // before Templight observers can be created +  // FIXME: Move the truncation aspect of this into Sema, we delayed this till +  // here so the source manager would be initialized. +  EnsureSemaIsCreated(CI, *this); + +  CI.getSema().TemplateInstCallbacks.push_back( +      llvm::make_unique<DefaultTemplateInstCallback>()); +  ASTFrontendAction::ExecuteAction(); +} + +namespace { +  /// AST reader listener that dumps module information for a module    /// file.    class DumpModuleInfoListener : public ASTReaderListener {      llvm::raw_ostream &Out; @@ -406,6 +560,45 @@ namespace {        Out << "\n";      } + +    /// Tells the \c ASTReaderListener that we want to receive the +    /// input files of the AST file via \c visitInputFile. +    bool needsInputFileVisitation() override { return true; } + +    /// Tells the \c ASTReaderListener that we want to receive the +    /// input files of the AST file via \c visitInputFile. +    bool needsSystemInputFileVisitation() override { return true; } + +    /// Indicates that the AST file contains particular input file. +    /// +    /// \returns true to continue receiving the next input file, false to stop. +    bool visitInputFile(StringRef Filename, bool isSystem, +                        bool isOverridden, bool isExplicitModule) override { + +      Out.indent(2) << "Input file: " << Filename; + +      if (isSystem || isOverridden || isExplicitModule) { +        Out << " ["; +        if (isSystem) { +          Out << "System"; +          if (isOverridden || isExplicitModule) +            Out << ", "; +        } +        if (isOverridden) { +          Out << "Overridden"; +          if (isExplicitModule) +            Out << ", "; +        } +        if (isExplicitModule) +          Out << "ExplicitModule"; + +        Out << "]"; +      } + +      Out << "\n"; + +      return true; +    }  #undef DUMP_BOOLEAN    };  } @@ -579,6 +772,7 @@ void PrintPreambleAction::ExecuteAction() {    case InputKind::ObjCXX:    case InputKind::OpenCL:    case InputKind::CUDA: +  case InputKind::HIP:      break;    case InputKind::Unknown: @@ -601,3 +795,51 @@ void PrintPreambleAction::ExecuteAction() {      llvm::outs().write((*Buffer)->getBufferStart(), Preamble);    }  } + +void DumpCompilerOptionsAction::ExecuteAction() { +  CompilerInstance &CI = getCompilerInstance(); +  std::unique_ptr<raw_ostream> OSP = +      CI.createDefaultOutputFile(false, getCurrentFile()); +  if (!OSP) +    return; + +  raw_ostream &OS = *OSP; +  const Preprocessor &PP = CI.getPreprocessor(); +  const LangOptions &LangOpts = PP.getLangOpts(); + +  // FIXME: Rather than manually format the JSON (which is awkward due to +  // needing to remove trailing commas), this should make use of a JSON library. +  // FIXME: Instead of printing enums as an integral value and specifying the +  // type as a separate field, use introspection to print the enumerator. + +  OS << "{\n"; +  OS << "\n\"features\" : [\n"; +  { +    llvm::SmallString<128> Str; +#define FEATURE(Name, Predicate)                                               \ +  ("\t{\"" #Name "\" : " + llvm::Twine(Predicate ? "true" : "false") + "},\n") \ +      .toVector(Str); +#include "clang/Basic/Features.def" +#undef FEATURE +    // Remove the newline and comma from the last entry to ensure this remains +    // valid JSON. +    OS << Str.substr(0, Str.size() - 2); +  } +  OS << "\n],\n"; + +  OS << "\n\"extensions\" : [\n"; +  { +    llvm::SmallString<128> Str; +#define EXTENSION(Name, Predicate)                                             \ +  ("\t{\"" #Name "\" : " + llvm::Twine(Predicate ? "true" : "false") + "},\n") \ +      .toVector(Str); +#include "clang/Basic/Features.def" +#undef EXTENSION +    // Remove the newline and comma from the last entry to ensure this remains +    // valid JSON. +    OS << Str.substr(0, Str.size() - 2); +  } +  OS << "\n]\n"; + +  OS << "}"; +} | 
