* 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
};
/**
/// \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);
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.
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.
/// 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;
public:
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
+ DetailedRecordIncludesNestedMacroInstantiations(true),
DisablePCHValidation(false), DisableStatCache(false),
DumpDeserializedPCHDecls(false),
PrecompiledPreambleBytes(0, true),
/// 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;
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) {
/// \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.
ConcurrencyCheckValue(CheckUnlocked),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
ShouldCacheCodeCompletionResults(false),
+ NestedMacroInstantiations(true),
CompletionCacheTopLevelHashValue(0),
PreambleTopLevelHashValue(0),
CurrentTopLevelHashValue(0),
// 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);
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));
AST->CompleteTranslationUnit = CompleteTranslationUnit;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->Invocation = CI;
+ AST->NestedMacroInstantiations = NestedMacroInstantiations;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
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.
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>
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,
}
if (PPOpts.DetailedRecord)
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(
+ PPOpts.DetailedRecordIncludesNestedMacroInstantiations);
InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
ExternalSource->ReadPreprocessedEntities();
}
-PreprocessingRecord::PreprocessingRecord()
- : ExternalSource(0), NumPreallocatedEntities(0),
+PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroInstantiations)
+ : IncludeNestedMacroInstantiations(IncludeNestedMacroInstantiations),
+ ExternalSource(0), NumPreallocatedEntities(0),
LoadedPreallocatedEntities(false)
{
}
}
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(),
CodeCompletionHandler::~CodeCompletionHandler() { }
-void Preprocessor::createPreprocessingRecord() {
+void Preprocessor::createPreprocessingRecord(
+ bool IncludeNestedMacroInstantiations) {
if (Record)
return;
- Record = new PreprocessingRecord;
+ Record = new PreprocessingRecord(IncludeNestedMacroInstantiations);
addPPCallbacks(Record);
}
PP->getHeaderSearchInfo().SetExternalLookup(this);
if (TotalNumPreallocatedPreprocessingEntities > 0) {
if (!PP->getPreprocessingRecord())
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(true);
PP->getPreprocessingRecord()->SetExternalSource(*this,
TotalNumPreallocatedPreprocessingEntities);
}
TotalNum += Chain[I]->NumPreallocatedPreprocessingEntities;
if (TotalNum) {
if (!PP->getPreprocessingRecord())
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(true);
PP->getPreprocessingRecord()->SetExternalSource(*this, TotalNum);
}
}
--- /dev/null
+#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]
options |= clang_defaultEditingTranslationUnitOptions();
if (getenv("CINDEXTEST_COMPLETION_CACHING"))
options |= CXTranslationUnit_CacheCompletionResults;
+ if (getenv("CINDEXTEST_NESTED_MACROS"))
+ options |= CXTranslationUnit_NestedMacroInstantiations;
return options;
}
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);
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);
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 {
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();
CompleteTranslationUnit,
CacheCodeCompetionResults,
CXXPrecompilePreamble,
- CXXChainedPCH));
+ CXXChainedPCH,
+ NestedMacroInstantiations));
if (NumErrors != Diags->getClient()->getNumErrors()) {
// Make sure to check that 'Unit' is non-NULL.