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