From: Douglas Gregor Date: Fri, 6 May 2011 16:33:08 +0000 (+0000) Subject: Introduce a new libclang parsing flag, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dca8ee8b7bc86076916a3a80f553f7a4e98c14af;p=clang Introduce a new libclang parsing flag, CXTranslationUnit_NestedMacroInstantiations, which indicates whether we want to see "nested" macro instantiations (e.g., those that occur inside other macro instantiations) within the detailed preprocessing record. Many clients (e.g., those that only care about visible tokens) don't care about this information, and in code that uses preprocessor metaprogramming, this information can have a very high cost. Addresses . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130990 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 011999bfe9..97c0c7c0da 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -829,7 +829,18 @@ enum CXTranslationUnit_Flags { * Note: this is a *temporary* option that is available only while * we are testing C++ precompiled preamble support. */ - CXTranslationUnit_CXXChainedPCH = 0x20 + CXTranslationUnit_CXXChainedPCH = 0x20, + + /** + * \brief Used to indicate that the "detailed" preprocessing record, + * if requested, should also contain nested macro instantiations. + * + * Nested macro instantiations (i.e., macro instantiations that occur + * inside another macro instantiation) can, in some code bases, require + * a large amount of storage to due preprocessor metaprogramming. Moreover, + * its fairly rare that this information is useful for libclang clients. + */ + CXTranslationUnit_NestedMacroInstantiations = 0x40 }; /** diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 57d9f712aa..339297eb93 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -249,6 +249,10 @@ private: /// \brief Whether we should be caching code-completion results. bool ShouldCacheCodeCompletionResults; + /// \brief Whether we want to include nested macro instantiations in the + /// detailed preprocessing record. + bool NestedMacroInstantiations; + static void ConfigureDiags(llvm::IntrusiveRefCntPtr &Diags, const char **ArgBegin, const char **ArgEnd, ASTUnit &AST, bool CaptureDiagnostics); @@ -607,7 +611,8 @@ public: bool CaptureDiagnostics = false, bool PrecompilePreamble = false, bool CompleteTranslationUnit = true, - bool CacheCodeCompletionResults = false); + bool CacheCodeCompletionResults = false, + bool NestedMacroInstantiations = true); /// LoadFromCommandLine - Create an ASTUnit from a vector of command line /// arguments, which must specify exactly one source file. @@ -636,7 +641,8 @@ public: bool CompleteTranslationUnit = true, bool CacheCodeCompletionResults = false, bool CXXPrecompilePreamble = false, - bool CXXChainedPCH = false); + bool CXXChainedPCH = false, + bool NestedMacroInstantiations = true); /// \brief Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h index e875ec1fef..e471c5cf1d 100644 --- a/include/clang/Frontend/PreprocessorOptions.h +++ b/include/clang/Frontend/PreprocessorOptions.h @@ -41,6 +41,10 @@ public: /// record of all macro definitions and /// instantiations. + /// \brief Whether the detailed preprocessing record includes nested macro + /// instantiations. + unsigned DetailedRecordIncludesNestedMacroInstantiations : 1; + /// The implicit PCH included at the start of the translation unit, or empty. std::string ImplicitPCHInclude; @@ -136,6 +140,7 @@ public: public: PreprocessorOptions() : UsePredefines(true), DetailedRecord(false), + DetailedRecordIncludesNestedMacroInstantiations(true), DisablePCHValidation(false), DisableStatCache(false), DumpDeserializedPCHDecls(false), PrecompiledPreambleBytes(0, true), diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h index d1534496b3..e498e9d0a0 100644 --- a/include/clang/Lex/PreprocessingRecord.h +++ b/include/clang/Lex/PreprocessingRecord.h @@ -258,6 +258,10 @@ namespace clang { /// including the various preprocessing directives processed, macros /// instantiated, etc. class PreprocessingRecord : public PPCallbacks { + /// \brief Whether we should include nested macro instantiations in + /// the preprocessing record. + bool IncludeNestedMacroInstantiations; + /// \brief Allocator used to store preprocessing objects. llvm::BumpPtrAllocator BumpAlloc; @@ -281,7 +285,8 @@ namespace clang { void MaybeLoadPreallocatedEntities() const ; public: - PreprocessingRecord(); + /// \brief Construct + explicit PreprocessingRecord(bool IncludeNestedMacroInstantiations); /// \brief Allocate memory in the preprocessing record. void *Allocate(unsigned Size, unsigned Align = 8) { diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 616507a914..817fab57d3 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -441,7 +441,7 @@ public: /// \brief Create a new preprocessing record, which will keep track of /// all macro expansions, macro definitions, etc. - void createPreprocessingRecord(); + void createPreprocessingRecord(bool IncludeNestedMacroInstantiations); /// EnterMainSourceFile - Enter the specified FileID as the main source file, /// which implicitly adds the builtin defines etc. diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 0d0fecdcf4..8827116f2e 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -102,6 +102,7 @@ ASTUnit::ASTUnit(bool _MainFileIsAST) ConcurrencyCheckValue(CheckUnlocked), PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0), ShouldCacheCodeCompletionResults(false), + NestedMacroInstantiations(true), CompletionCacheTopLevelHashValue(0), PreambleTopLevelHashValue(0), CurrentTopLevelHashValue(0), @@ -927,6 +928,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts(); + PreprocessorOpts.DetailedRecordIncludesNestedMacroInstantiations + = NestedMacroInstantiations; std::string PriorImplicitPCHInclude; if (OverrideMainBuffer) { PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); @@ -1712,7 +1715,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, bool CaptureDiagnostics, bool PrecompilePreamble, bool CompleteTranslationUnit, - bool CacheCodeCompletionResults) { + bool CacheCodeCompletionResults, + bool NestedMacroInstantiations) { // Create the AST unit. llvm::OwningPtr AST; AST.reset(new ASTUnit(false)); @@ -1723,6 +1727,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, AST->CompleteTranslationUnit = CompleteTranslationUnit; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->Invocation = CI; + AST->NestedMacroInstantiations = NestedMacroInstantiations; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar @@ -1747,7 +1752,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, bool CompleteTranslationUnit, bool CacheCodeCompletionResults, bool CXXPrecompilePreamble, - bool CXXChainedPCH) { + bool CXXChainedPCH, + bool NestedMacroInstantiations) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -1814,6 +1820,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); AST->StoredDiagnostics.swap(StoredDiagnostics); AST->Invocation = CI; + AST->NestedMacroInstantiations = NestedMacroInstantiations; // Recover resources if we crash before exiting this method. llvm::CrashRecoveryContextCleanupRegistrar @@ -2265,6 +2272,9 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, PreprocessorOpts.PrecompiledPreambleBytes.second = false; } + // Disable the preprocessing record + PreprocessorOpts.DetailedRecord = false; + llvm::OwningPtr Act; Act.reset(new SyntaxOnlyAction); if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second, diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index ace3c5adb1..38fcfe3c47 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -227,7 +227,8 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, } if (PPOpts.DetailedRecord) - PP->createPreprocessingRecord(); + PP->createPreprocessingRecord( + PPOpts.DetailedRecordIncludesNestedMacroInstantiations); InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp index 9555611dc5..0c8d948ce0 100644 --- a/lib/Lex/PreprocessingRecord.cpp +++ b/lib/Lex/PreprocessingRecord.cpp @@ -45,8 +45,9 @@ void PreprocessingRecord::MaybeLoadPreallocatedEntities() const { ExternalSource->ReadPreprocessedEntities(); } -PreprocessingRecord::PreprocessingRecord() - : ExternalSource(0), NumPreallocatedEntities(0), +PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroInstantiations) + : IncludeNestedMacroInstantiations(IncludeNestedMacroInstantiations), + ExternalSource(0), NumPreallocatedEntities(0), LoadedPreallocatedEntities(false) { } @@ -120,6 +121,9 @@ MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) { } void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) { + if (!IncludeNestedMacroInstantiations && Id.getLocation().isMacroID()) + return; + if (MacroDefinition *Def = findMacroDefinition(MI)) PreprocessedEntities.push_back( new (*this) MacroInstantiation(Id.getIdentifierInfo(), diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 31fd667a65..fdc18f8781 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -527,10 +527,11 @@ CommentHandler::~CommentHandler() { } CodeCompletionHandler::~CodeCompletionHandler() { } -void Preprocessor::createPreprocessingRecord() { +void Preprocessor::createPreprocessingRecord( + bool IncludeNestedMacroInstantiations) { if (Record) return; - Record = new PreprocessingRecord; + Record = new PreprocessingRecord(IncludeNestedMacroInstantiations); addPPCallbacks(Record); } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index bad18ff02e..bdc46f590f 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2382,7 +2382,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, PP->getHeaderSearchInfo().SetExternalLookup(this); if (TotalNumPreallocatedPreprocessingEntities > 0) { if (!PP->getPreprocessingRecord()) - PP->createPreprocessingRecord(); + PP->createPreprocessingRecord(true); PP->getPreprocessingRecord()->SetExternalSource(*this, TotalNumPreallocatedPreprocessingEntities); } @@ -2581,7 +2581,7 @@ void ASTReader::setPreprocessor(Preprocessor &pp) { TotalNum += Chain[I]->NumPreallocatedPreprocessingEntities; if (TotalNum) { if (!PP->getPreprocessingRecord()) - PP->createPreprocessingRecord(); + PP->createPreprocessingRecord(true); PP->getPreprocessingRecord()->SetExternalSource(*this, TotalNum); } } diff --git a/test/Index/nested-macro-instantiations.cpp b/test/Index/nested-macro-instantiations.cpp new file mode 100644 index 0000000000..d0c9bbb1e7 --- /dev/null +++ b/test/Index/nested-macro-instantiations.cpp @@ -0,0 +1,20 @@ +#define FOO(x) x +#define BAR(x) FOO(x) +#define WIBBLE(x) BAR(x) + +WIBBLE(int x); + +// RUN: env CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s +// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: macro instantiation=WIBBLE:3:9 Extent=[5:1 - 5:7] +// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:3:19: macro instantiation=BAR:2:9 Extent=[3:19 - 5:14] +// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:2:16: macro instantiation=FOO:1:9 Extent=[2:16 - 5:14] +// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14] + +// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s +// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s +// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s +// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: macro instantiation=WIBBLE:3:9 Extent=[5:1 - 5:7] +// CHECK-WITHOUT-NESTED-NOT: nested-macro-instantiations.cpp:3:19: macro instantiation=BAR:2:9 Extent=[3:19 - 5:14] +// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14] diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index e43ac0699f..a5d4909e63 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -37,6 +37,8 @@ static unsigned getDefaultParsingOptions() { options |= clang_defaultEditingTranslationUnitOptions(); if (getenv("CINDEXTEST_COMPLETION_CACHING")) options |= CXTranslationUnit_CacheCompletionResults; + if (getenv("CINDEXTEST_NESTED_MACROS")) + options |= CXTranslationUnit_NestedMacroInstantiations; return options; } @@ -713,11 +715,11 @@ int perform_test_load_source(int argc, const char **argv, return -1; } - TU = clang_createTranslationUnitFromSourceFile(Idx, 0, - argc - num_unsaved_files, - argv + num_unsaved_files, - num_unsaved_files, - unsaved_files); + TU = clang_parseTranslationUnit(Idx, 0, + argv + num_unsaved_files, + argc - num_unsaved_files, + unsaved_files, num_unsaved_files, + getDefaultParsingOptions()); if (!TU) { fprintf(stderr, "Unable to load translation unit!\n"); free_remapped_files(unsaved_files, num_unsaved_files); @@ -1231,11 +1233,12 @@ int perform_token_annotation(int argc, const char **argv) { return -1; CIdx = clang_createIndex(0, 1); - TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], - argc - num_unsaved_files - 3, - argv + num_unsaved_files + 2, - num_unsaved_files, - unsaved_files); + TU = clang_parseTranslationUnit(CIdx, argv[argc - 1], + argv + num_unsaved_files + 2, + argc - num_unsaved_files - 3, + unsaved_files, + num_unsaved_files, + getDefaultParsingOptions()); if (!TU) { fprintf(stderr, "unable to parse input\n"); clang_disposeIndex(CIdx); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 7234da3f63..f17a415f44 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -2376,10 +2376,12 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, const char * const *command_line_args, unsigned num_unsaved_files, struct CXUnsavedFile *unsaved_files) { + unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord | + CXTranslationUnit_NestedMacroInstantiations; return clang_parseTranslationUnit(CIdx, source_filename, command_line_args, num_command_line_args, unsaved_files, num_unsaved_files, - CXTranslationUnit_DetailedPreprocessingRecord); + Options); } struct ParseTranslationUnitInfo { @@ -2480,9 +2482,12 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { Args->push_back(source_filename); // Do we need the detailed preprocessing record? + bool NestedMacroInstantiations = false; if (options & CXTranslationUnit_DetailedPreprocessingRecord) { Args->push_back("-Xclang"); Args->push_back("-detailed-preprocessing-record"); + NestedMacroInstantiations + = (options & CXTranslationUnit_NestedMacroInstantiations); } unsigned NumErrors = Diags->getClient()->getNumErrors(); @@ -2501,7 +2506,8 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { CompleteTranslationUnit, CacheCodeCompetionResults, CXXPrecompilePreamble, - CXXChainedPCH)); + CXXChainedPCH, + NestedMacroInstantiations)); if (NumErrors != Diags->getClient()->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL.