Optionally store a PreprocessingRecord in the preprocessor itself, and
tie its creation to a CC1 flag -detailed-preprocessing-record.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98963 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 1ecd8d6..6a4bec1 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -448,7 +448,9 @@
HelpText<"Undefine the specified macro">;
def undef : Flag<"-undef">, MetaVarName<"<macro>">,
HelpText<"undef all system defines">;
-
+def detailed_preprocessing_record : Flag<"-detailed-preprocessing-record">,
+ HelpText<"include a detailed record of preprocessing actions">;
+
//===----------------------------------------------------------------------===//
// Preprocessed Output Options
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 0616d03..e9a982b 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -54,7 +54,6 @@
llvm::OwningPtr<TargetInfo> Target;
llvm::OwningPtr<Preprocessor> PP;
llvm::OwningPtr<ASTContext> Ctx;
- llvm::OwningPtr<PreprocessingRecord> Preprocessing;
/// Optional owned invocation, just used to make the invocation used in
/// LoadFromCommandLine available.
@@ -137,12 +136,6 @@
const ASTContext &getASTContext() const { return *Ctx.get(); }
ASTContext &getASTContext() { return *Ctx.get(); }
- const PreprocessingRecord &getPreprocessingRecord() const {
- return *Preprocessing.get();
- }
- PreprocessingRecord &getPreprocessingRecord() { return *Preprocessing.get(); }
- bool hasPreprocessingRecord() { return Preprocessing.get() != 0; }
-
const FileManager &getFileManager() const { return FileMgr; }
FileManager &getFileManager() { return FileMgr; }
@@ -212,8 +205,7 @@
static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI,
Diagnostic &Diags,
bool OnlyLocalDecls = false,
- bool CaptureDiagnostics = false,
- bool WantPreprocessingRecord = false);
+ bool CaptureDiagnostics = false);
/// LoadFromCommandLine - Create an ASTUnit from a vector of command line
/// arguments, which must specify exactly one source file.
@@ -236,8 +228,7 @@
bool OnlyLocalDecls = false,
RemappedFile *RemappedFiles = 0,
unsigned NumRemappedFiles = 0,
- bool CaptureDiagnostics = false,
- bool WantPreprocessingRecord = false);
+ bool CaptureDiagnostics = false);
};
} // namespace clang
diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h
index 212130e..c05e243 100644
--- a/include/clang/Frontend/PCHWriter.h
+++ b/include/clang/Frontend/PCHWriter.h
@@ -234,6 +234,9 @@
///
/// \param isysroot if non-NULL, write a relocatable PCH file whose headers
/// are relative to the given system root.
+ ///
+ /// \param PPRec Record of the preprocessing actions that occurred while
+ /// preprocessing this file, e.g., macro instantiations
void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
const char* isysroot);
diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h
index 7ba7c5c..891359b 100644
--- a/include/clang/Frontend/PreprocessorOptions.h
+++ b/include/clang/Frontend/PreprocessorOptions.h
@@ -36,6 +36,10 @@
unsigned UsePredefines : 1; /// Initialize the preprocessor with the compiler
/// and target specific predefines.
+ unsigned DetailedRecord : 1; /// Whether we should maintain a detailed
+ /// record of all macro definitions and
+ /// instantiations.
+
/// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude;
@@ -77,7 +81,7 @@
}
public:
- PreprocessorOptions() : UsePredefines(true) {}
+ PreprocessorOptions() : UsePredefines(true), DetailedRecord(false) {}
void addMacroDef(llvm::StringRef Name) {
Macros.push_back(std::make_pair(Name, false));
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index e673b4a..c00da56 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -14,10 +14,7 @@
#ifndef LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
#define LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
-#include "clang/Lex/PPCallbacks.h"
#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Allocator.h"
#include <vector>
@@ -206,24 +203,6 @@
/// \brief Add a new preprocessed entity to this record.
void addPreprocessedEntity(PreprocessedEntity *Entity);
};
-
- /// \brief Preprocessor callback action used to populate a preprocessing
- /// record.
- class PopulatePreprocessingRecord : public PPCallbacks {
- /// \brief The preprocessing record this action will populate.
- PreprocessingRecord &Record;
-
- /// \brief Mapping from MacroInfo structures to their definitions.
- llvm::DenseMap<const MacroInfo *, MacroDefinition *> MacroDefinitions;
-
- public:
- explicit PopulatePreprocessingRecord(PreprocessingRecord &Record)
- : Record(Record) { }
-
- virtual void MacroExpands(const Token &Id, const MacroInfo* MI);
- virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
- };
-
} // end namespace clang
inline void* operator new(size_t bytes, clang::PreprocessingRecord& PR,
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index a4910f7..81fbedc 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -43,7 +43,8 @@
class TargetInfo;
class PPCallbacks;
class DirectoryLookup;
-
+class PreprocessingRecord;
+
/// Preprocessor - This object engages in a tight little dance with the lexer to
/// efficiently preprocess tokens. Lexers know only about tokens within a
/// single source file, and don't know anything about preprocessor-level issues
@@ -209,6 +210,13 @@
unsigned NumCachedTokenLexers;
TokenLexer *TokenLexerCache[TokenLexerCacheSize];
+ /// \brief A record of the macro definitions and instantiations that
+ /// occurred during preprocessing.
+ ///
+ /// This is an optional side structure that can be enabled with
+ /// \c createPreprocessingRecord() prior to preprocessing.
+ llvm::OwningPtr<PreprocessingRecord> Record;
+
private: // Cached tokens state.
typedef llvm::SmallVector<Token, 1> CachedTokensTy;
@@ -348,6 +356,14 @@
/// It is an error to remove a handler that has not been registered.
void RemoveCommentHandler(CommentHandler *Handler);
+ /// \brief Retrieve the preprocessing record, or NULL if there is no
+ /// preprocessing record.
+ PreprocessingRecord *getPreprocessingRecord() const { return Record.get(); }
+
+ /// \brief Create a new preprocessing record, which will keep track of
+ /// all macro expansions, macro definitions, etc.
+ void createPreprocessingRecord();
+
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
bool EnterMainSourceFile();
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 1aaa536..935c415 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -278,8 +278,7 @@
ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
Diagnostic &Diags,
bool OnlyLocalDecls,
- bool CaptureDiagnostics,
- bool WantPreprocessingRecord) {
+ bool CaptureDiagnostics) {
// Create the compiler instance to use for building the AST.
CompilerInstance Clang;
llvm::OwningPtr<ASTUnit> AST;
@@ -329,15 +328,6 @@
// Create the preprocessor.
Clang.createPreprocessor();
- // If the ASTUnit was requested to store information about preprocessing,
- // create storage for that information and attach an appropriate callback to
- // populate that storage.
- if (WantPreprocessingRecord) {
- AST->Preprocessing.reset(new PreprocessingRecord);
- Clang.getPreprocessor().addPPCallbacks(
- new PopulatePreprocessingRecord(*AST->Preprocessing));
- }
-
Act.reset(new TopLevelDeclTrackerAction(*AST));
if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
/*IsAST=*/false))
@@ -377,8 +367,7 @@
bool OnlyLocalDecls,
RemappedFile *RemappedFiles,
unsigned NumRemappedFiles,
- bool CaptureDiagnostics,
- bool WantPreprocessingRecord) {
+ bool CaptureDiagnostics) {
llvm::SmallVector<const char *, 16> Args;
Args.push_back("<clang>"); // FIXME: Remove dummy argument.
Args.insert(Args.end(), ArgBegin, ArgEnd);
@@ -430,6 +419,5 @@
CI->getFrontendOpts().DisableFree = true;
return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
- CaptureDiagnostics,
- WantPreprocessingRecord);
+ CaptureDiagnostics);
}
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 5d399bd..bb0d308 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -224,6 +224,9 @@
PP->setPTHManager(PTHMgr);
}
+ if (PPOpts.DetailedRecord)
+ PP->createPreprocessingRecord();
+
InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
// Handle generating dependencies, if requested.
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 5798f2f..d47fcf6 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -575,6 +575,8 @@
}
if (!Opts.UsePredefines)
Res.push_back("-undef");
+ if (Opts.DetailedRecord)
+ Res.push_back("-detailed-preprocessing-record");
if (!Opts.ImplicitPCHInclude.empty()) {
Res.push_back("-include-pch");
Res.push_back(Opts.ImplicitPCHInclude);
@@ -1232,7 +1234,7 @@
else
Opts.TokenCache = Opts.ImplicitPTHInclude;
Opts.UsePredefines = !Args.hasArg(OPT_undef);
-
+ Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record);
// Add macros from the command line.
for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U),
ie = Args.filtered_end(); it != ie; ++it) {
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 3e0a03b..83268e0 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -21,19 +21,3 @@
PreprocessedEntities.push_back(Entity);
}
-void PopulatePreprocessingRecord::MacroExpands(const Token &Id,
- const MacroInfo* MI) {
- Record.addPreprocessedEntity(
- new (Record) MacroInstantiation(Id.getIdentifierInfo(),
- Id.getLocation(),
- MacroDefinitions[MI]));
-}
-
-void PopulatePreprocessingRecord::MacroDefined(const IdentifierInfo *II,
- const MacroInfo *MI) {
- SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
- MacroDefinition *Def
- = new (Record) MacroDefinition(II, MI->getDefinitionLoc(), R);
- MacroDefinitions[MI] = Def;
- Record.addPreprocessedEntity(Def);
-}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 917a2e7..d9aaed4 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -31,6 +31,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Pragma.h"
+#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/ScratchBuffer.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -627,3 +628,47 @@
}
CommentHandler::~CommentHandler() { }
+
+namespace {
+ /// \brief Preprocessor callback action used to populate a preprocessing
+ /// record.
+ class PopulatePreprocessingRecord : public PPCallbacks {
+ /// \brief The preprocessing record this action will populate.
+ PreprocessingRecord &Record;
+
+ /// \brief Mapping from MacroInfo structures to their definitions.
+ llvm::DenseMap<const MacroInfo *, MacroDefinition *> MacroDefinitions;
+
+ public:
+ explicit PopulatePreprocessingRecord(PreprocessingRecord &Record)
+ : Record(Record) { }
+
+ virtual void MacroExpands(const Token &Id, const MacroInfo* MI);
+ virtual void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI);
+ };
+}
+
+void PopulatePreprocessingRecord::MacroExpands(const Token &Id,
+ const MacroInfo* MI) {
+ Record.addPreprocessedEntity(
+ new (Record) MacroInstantiation(Id.getIdentifierInfo(),
+ Id.getLocation(),
+ MacroDefinitions[MI]));
+}
+
+void PopulatePreprocessingRecord::MacroDefined(const IdentifierInfo *II,
+ const MacroInfo *MI) {
+ SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
+ MacroDefinition *Def
+ = new (Record) MacroDefinition(II, MI->getDefinitionLoc(), R);
+ MacroDefinitions[MI] = Def;
+ Record.addPreprocessedEntity(Def);
+}
+
+void Preprocessor::createPreprocessingRecord() {
+ if (Record)
+ return;
+
+ Record.reset(new PreprocessingRecord);
+ addPPCallbacks(new PopulatePreprocessingRecord(*Record));
+}
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index c51ca7f..f20bb75 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -430,11 +430,11 @@
return true;
// Walk the preprocessing record.
- if (CXXUnit->hasPreprocessingRecord()) {
+ if (PreprocessingRecord *PPRec
+ = CXXUnit->getPreprocessor().getPreprocessingRecord()) {
// FIXME: Once we have the ability to deserialize a preprocessing record,
// do so.
- PreprocessingRecord &PPRec = CXXUnit->getPreprocessingRecord();
- for (PreprocessingRecord::iterator E = PPRec.begin(), EEnd = PPRec.end();
+ for (PreprocessingRecord::iterator E = PPRec->begin(),EEnd = PPRec->end();
E != EEnd; ++E) {
if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) {
if (Visit(MakeMacroInstantiationCursor(MI, CXXUnit)))
@@ -1014,7 +1014,8 @@
Args.push_back(source_filename);
Args.insert(Args.end(), command_line_args,
command_line_args + num_command_line_args);
-
+ Args.push_back("-Xclang");
+ Args.push_back("-detailed-preprocessing-record");
unsigned NumErrors = Diags->getNumErrors();
#ifdef USE_CRASHTRACER
@@ -1028,8 +1029,7 @@
CXXIdx->getOnlyLocalDecls(),
RemappedFiles.data(),
RemappedFiles.size(),
- /*CaptureDiagnostics=*/true,
- /*WantPreprocessingRecord=*/true));
+ /*CaptureDiagnostics=*/true));
// FIXME: Until we have broader testing, just drop the entire AST if we
// encountered an error.
@@ -1114,6 +1114,9 @@
TemporaryFiles.push_back(DiagnosticsFile);
argv.push_back("-fdiagnostics-binary");
+ argv.push_back("-Xclang");
+ argv.push_back("-detailed-preprocessing-record");
+
// Add the null terminator.
argv.push_back(NULL);