llvm-project/clang/lib/Lex/PreprocessingRecord.cpp
Douglas Gregor 998caead70 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
2011-05-06 16:33:08 +00:00

191 lines
6.4 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(bool IncludeNestedMacroInstantiations)
: IncludeNestedMacroInstantiations(IncludeNestedMacroInstantiations),
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 (!IncludeNestedMacroInstantiations && Id.getLocation().isMacroID())
return;
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,
llvm::StringRef SearchPath,
llvm::StringRef RelativePath) {
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);
}