Optionally store a PreprocessingRecord in the preprocessor itself, and

tie its creation to a CC1 flag -detailed-preprocessing-record.

llvm-svn: 98963
This commit is contained in:
Douglas Gregor 2010-03-19 16:15:56 +00:00
parent 45a967cd62
commit 7f6d60dcc2
12 changed files with 93 additions and 73 deletions

View File

@ -448,7 +448,9 @@ def U : JoinedOrSeparate<"-U">, MetaVarName<"<macro>">,
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
//===----------------------------------------------------------------------===//

View File

@ -54,7 +54,6 @@ class ASTUnit {
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 @@ public:
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 @@ public:
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 @@ public:
bool OnlyLocalDecls = false,
RemappedFile *RemappedFiles = 0,
unsigned NumRemappedFiles = 0,
bool CaptureDiagnostics = false,
bool WantPreprocessingRecord = false);
bool CaptureDiagnostics = false);
};
} // namespace clang

View File

@ -234,6 +234,9 @@ public:
///
/// \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);

View File

@ -36,6 +36,10 @@ public:
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:
}
public:
PreprocessorOptions() : UsePredefines(true) {}
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false) {}
void addMacroDef(llvm::StringRef Name) {
Macros.push_back(std::make_pair(Name, false));

View File

@ -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 @@ namespace clang {
/// \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,

View File

@ -43,7 +43,8 @@ class ScratchBuffer;
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 @@ class Preprocessor {
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 @@ public:
/// 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();

View File

@ -278,8 +278,7 @@ public:
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 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
// 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 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
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 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
CI->getFrontendOpts().DisableFree = true;
return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
CaptureDiagnostics,
WantPreprocessingRecord);
CaptureDiagnostics);
}

View File

@ -224,6 +224,9 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
PP->setPTHManager(PTHMgr);
}
if (PPOpts.DetailedRecord)
PP->createPreprocessingRecord();
InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
// Handle generating dependencies, if requested.

View File

@ -575,6 +575,8 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
}
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 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
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) {

View File

@ -21,19 +21,3 @@ void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
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);
}

View File

@ -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 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) {
}
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));
}

View File

@ -430,11 +430,11 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
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 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
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 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
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 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
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);