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 <rdar://problem/9389320>.

llvm-svn: 130990
This commit is contained in:
Douglas Gregor
2011-05-06 16:33:08 +00:00
parent 705d25a1f4
commit 998caead70
13 changed files with 98 additions and 26 deletions

View File

@@ -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
};
/**

View File

@@ -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<Diagnostic> &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.

View File

@@ -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),

View File

@@ -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) {

View File

@@ -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.

View File

@@ -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<ASTUnit> 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<ASTUnit>
@@ -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<ASTUnit>
@@ -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<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,

View File

@@ -227,7 +227,8 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
}
if (PPOpts.DetailedRecord)
PP->createPreprocessingRecord();
PP->createPreprocessingRecord(
PPOpts.DetailedRecordIncludesNestedMacroInstantiations);
InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);

View File

@@ -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(),

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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]

View File

@@ -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);

View File

@@ -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.