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 << "}"; +} |