teak-llvm/clang/lib/Lex/PreprocessingRecord.cpp
Chandler Carruth 3cc331a160 Add a 'RawPath' parameter to the PPCallbacks interface. This allows
clients to observe the exact path through which an #included file was
located. This is very useful when trying to record and replay inclusion
operations without it beind influenced by the aggressive caching done
inside the FileManager to avoid redundant system calls and filesystem
operations.

The work to compute and return this is only done in the presence of
callbacks, so it should have no effect on normal compilation.

Patch by Manuel Klimek.

llvm-svn: 127742
2011-03-16 18:34:36 +00:00

186 lines
6.2 KiB
C++

//===--- PreprocessingRecord.cpp - Record of Preprocessing ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the PreprocessingRecord class, which maintains a record
// of what occurred during preprocessing, and its helpers.
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Token.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { }
InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
InclusionKind Kind,
llvm::StringRef FileName,
bool InQuotes, const FileEntry *File,
SourceRange Range)
: PreprocessingDirective(InclusionDirectiveKind, Range),
InQuotes(InQuotes), Kind(Kind), File(File)
{
char *Memory
= (char*)PPRec.Allocate(FileName.size() + 1, llvm::alignOf<char>());
memcpy(Memory, FileName.data(), FileName.size());
Memory[FileName.size()] = 0;
this->FileName = llvm::StringRef(Memory, FileName.size());
}
void PreprocessingRecord::MaybeLoadPreallocatedEntities() const {
if (!ExternalSource || LoadedPreallocatedEntities)
return;
LoadedPreallocatedEntities = true;
ExternalSource->ReadPreprocessedEntities();
}
PreprocessingRecord::PreprocessingRecord()
: ExternalSource(0), NumPreallocatedEntities(0),
LoadedPreallocatedEntities(false)
{
}
PreprocessingRecord::iterator
PreprocessingRecord::begin(bool OnlyLocalEntities) {
if (OnlyLocalEntities)
return PreprocessedEntities.begin() + NumPreallocatedEntities;
MaybeLoadPreallocatedEntities();
return PreprocessedEntities.begin();
}
PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) {
if (!OnlyLocalEntities)
MaybeLoadPreallocatedEntities();
return PreprocessedEntities.end();
}
PreprocessingRecord::const_iterator
PreprocessingRecord::begin(bool OnlyLocalEntities) const {
if (OnlyLocalEntities)
return PreprocessedEntities.begin() + NumPreallocatedEntities;
MaybeLoadPreallocatedEntities();
return PreprocessedEntities.begin();
}
PreprocessingRecord::const_iterator
PreprocessingRecord::end(bool OnlyLocalEntities) const {
if (!OnlyLocalEntities)
MaybeLoadPreallocatedEntities();
return PreprocessedEntities.end();
}
void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
PreprocessedEntities.push_back(Entity);
}
void PreprocessingRecord::SetExternalSource(
ExternalPreprocessingRecordSource &Source,
unsigned NumPreallocatedEntities) {
assert(!ExternalSource &&
"Preprocessing record already has an external source");
ExternalSource = &Source;
this->NumPreallocatedEntities = NumPreallocatedEntities;
PreprocessedEntities.insert(PreprocessedEntities.begin(),
NumPreallocatedEntities, 0);
}
void PreprocessingRecord::SetPreallocatedEntity(unsigned Index,
PreprocessedEntity *Entity) {
assert(Index < NumPreallocatedEntities &&"Out-of-bounds preallocated entity");
PreprocessedEntities[Index] = Entity;
}
void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
MacroDefinition *MD) {
MacroDefinitions[Macro] = MD;
}
MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
= MacroDefinitions.find(MI);
if (Pos == MacroDefinitions.end())
return 0;
return Pos->second;
}
void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) {
if (MacroDefinition *Def = findMacroDefinition(MI))
PreprocessedEntities.push_back(
new (*this) MacroInstantiation(Id.getIdentifierInfo(),
Id.getLocation(),
Def));
}
void PreprocessingRecord::MacroDefined(const Token &Id,
const MacroInfo *MI) {
SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
MacroDefinition *Def
= new (*this) MacroDefinition(Id.getIdentifierInfo(),
MI->getDefinitionLoc(),
R);
MacroDefinitions[MI] = Def;
PreprocessedEntities.push_back(Def);
}
void PreprocessingRecord::MacroUndefined(const Token &Id,
const MacroInfo *MI) {
llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
= MacroDefinitions.find(MI);
if (Pos != MacroDefinitions.end())
MacroDefinitions.erase(Pos);
}
void PreprocessingRecord::InclusionDirective(
SourceLocation HashLoc,
const clang::Token &IncludeTok,
llvm::StringRef FileName,
bool IsAngled,
const FileEntry *File,
clang::SourceLocation EndLoc,
const llvm::SmallVectorImpl<char> &RawPath) {
InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
case tok::pp_include:
Kind = InclusionDirective::Include;
break;
case tok::pp_import:
Kind = InclusionDirective::Import;
break;
case tok::pp_include_next:
Kind = InclusionDirective::IncludeNext;
break;
case tok::pp___include_macros:
Kind = InclusionDirective::IncludeMacros;
break;
default:
llvm_unreachable("Unknown include directive kind");
return;
}
clang::InclusionDirective *ID
= new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
File, SourceRange(HashLoc, EndLoc));
PreprocessedEntities.push_back(ID);
}