1 //===--- PreprocessingRecord.cpp - Record of Preprocessing ------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements the PreprocessingRecord class, which maintains a record 11 // of what occurred during preprocessing, and its helpers. 12 // 13 //===----------------------------------------------------------------------===// 14 #include "clang/Lex/PreprocessingRecord.h" 15 #include "clang/Lex/MacroInfo.h" 16 #include "clang/Lex/Token.h" 17 #include "llvm/Support/ErrorHandling.h" 18 #include "llvm/Support/Capacity.h" 19 20 using namespace clang; 21 22 ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { } 23 24 25 InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec, 26 InclusionKind Kind, 27 StringRef FileName, 28 bool InQuotes, const FileEntry *File, 29 SourceRange Range) 30 : PreprocessingDirective(InclusionDirectiveKind, Range), 31 InQuotes(InQuotes), Kind(Kind), File(File) 32 { 33 char *Memory 34 = (char*)PPRec.Allocate(FileName.size() + 1, llvm::alignOf<char>()); 35 memcpy(Memory, FileName.data(), FileName.size()); 36 Memory[FileName.size()] = 0; 37 this->FileName = StringRef(Memory, FileName.size()); 38 } 39 40 PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroExpansions) 41 : IncludeNestedMacroExpansions(IncludeNestedMacroExpansions), 42 ExternalSource(0) 43 { 44 } 45 46 PreprocessingRecord::iterator 47 PreprocessingRecord::begin(bool OnlyLocalEntities) { 48 if (OnlyLocalEntities) 49 return iterator(this, 0); 50 51 return iterator(this, -(int)LoadedPreprocessedEntities.size()); 52 } 53 54 PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) { 55 return iterator(this, PreprocessedEntities.size()); 56 } 57 58 void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) { 59 PreprocessedEntities.push_back(Entity); 60 } 61 62 void PreprocessingRecord::SetExternalSource( 63 ExternalPreprocessingRecordSource &Source) { 64 assert(!ExternalSource && 65 "Preprocessing record already has an external source"); 66 ExternalSource = &Source; 67 } 68 69 unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) { 70 unsigned Result = LoadedPreprocessedEntities.size(); 71 LoadedPreprocessedEntities.resize(LoadedPreprocessedEntities.size() 72 + NumEntities); 73 return Result; 74 } 75 76 void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro, 77 PPEntityID PPID) { 78 MacroDefinitions[Macro] = PPID; 79 } 80 81 /// \brief Retrieve the preprocessed entity at the given ID. 82 PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){ 83 if (PPID < 0) { 84 assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() && 85 "Out-of bounds loaded preprocessed entity"); 86 return getLoadedPreprocessedEntity(LoadedPreprocessedEntities.size()+PPID); 87 } 88 assert(unsigned(PPID) < PreprocessedEntities.size() && 89 "Out-of bounds local preprocessed entity"); 90 return PreprocessedEntities[PPID]; 91 } 92 93 /// \brief Retrieve the loaded preprocessed entity at the given index. 94 PreprocessedEntity * 95 PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) { 96 assert(Index < LoadedPreprocessedEntities.size() && 97 "Out-of bounds loaded preprocessed entity"); 98 assert(ExternalSource && "No external source to load from"); 99 PreprocessedEntity *&Entity = LoadedPreprocessedEntities[Index]; 100 if (!Entity) { 101 Entity = ExternalSource->ReadPreprocessedEntity(Index); 102 if (!Entity) // Failed to load. 103 Entity = new (*this) 104 PreprocessedEntity(PreprocessedEntity::InvalidKind, SourceRange()); 105 } 106 return Entity; 107 } 108 109 MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) { 110 llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos 111 = MacroDefinitions.find(MI); 112 if (Pos == MacroDefinitions.end()) 113 return 0; 114 115 PreprocessedEntity *Entity = getPreprocessedEntity(Pos->second); 116 if (Entity->isInvalid()) 117 return 0; 118 return cast<MacroDefinition>(Entity); 119 } 120 121 void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI, 122 SourceRange Range) { 123 if (!IncludeNestedMacroExpansions && Id.getLocation().isMacroID()) 124 return; 125 126 if (MI->isBuiltinMacro()) 127 PreprocessedEntities.push_back( 128 new (*this) MacroExpansion(Id.getIdentifierInfo(),Range)); 129 else if (MacroDefinition *Def = findMacroDefinition(MI)) 130 PreprocessedEntities.push_back( 131 new (*this) MacroExpansion(Def, Range)); 132 } 133 134 void PreprocessingRecord::MacroDefined(const Token &Id, 135 const MacroInfo *MI) { 136 SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc()); 137 MacroDefinition *Def 138 = new (*this) MacroDefinition(Id.getIdentifierInfo(), 139 MI->getDefinitionLoc(), 140 R); 141 PreprocessedEntities.push_back(Def); 142 MacroDefinitions[MI] = getPPEntityID(PreprocessedEntities.size()-1, 143 /*isLoaded=*/false); 144 } 145 146 void PreprocessingRecord::MacroUndefined(const Token &Id, 147 const MacroInfo *MI) { 148 llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos 149 = MacroDefinitions.find(MI); 150 if (Pos != MacroDefinitions.end()) 151 MacroDefinitions.erase(Pos); 152 } 153 154 void PreprocessingRecord::InclusionDirective( 155 SourceLocation HashLoc, 156 const clang::Token &IncludeTok, 157 StringRef FileName, 158 bool IsAngled, 159 const FileEntry *File, 160 clang::SourceLocation EndLoc, 161 StringRef SearchPath, 162 StringRef RelativePath) { 163 InclusionDirective::InclusionKind Kind = InclusionDirective::Include; 164 165 switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { 166 case tok::pp_include: 167 Kind = InclusionDirective::Include; 168 break; 169 170 case tok::pp_import: 171 Kind = InclusionDirective::Import; 172 break; 173 174 case tok::pp_include_next: 175 Kind = InclusionDirective::IncludeNext; 176 break; 177 178 case tok::pp___include_macros: 179 Kind = InclusionDirective::IncludeMacros; 180 break; 181 182 default: 183 llvm_unreachable("Unknown include directive kind"); 184 return; 185 } 186 187 clang::InclusionDirective *ID 188 = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled, 189 File, SourceRange(HashLoc, EndLoc)); 190 PreprocessedEntities.push_back(ID); 191 } 192 193 size_t PreprocessingRecord::getTotalMemory() const { 194 return BumpAlloc.getTotalMemory() 195 + llvm::capacity_in_bytes(MacroDefinitions) 196 + llvm::capacity_in_bytes(PreprocessedEntities) 197 + llvm::capacity_in_bytes(LoadedPreprocessedEntities); 198 } 199