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 "clang/Basic/IdentifierTable.h"
18 #include "llvm/Support/ErrorHandling.h"
19 #include "llvm/Support/Capacity.h"
20 
21 using namespace clang;
22 
23 ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { }
24 
25 
26 InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
27                                        InclusionKind Kind,
28                                        StringRef FileName,
29                                        bool InQuotes, const FileEntry *File,
30                                        SourceRange Range)
31   : PreprocessingDirective(InclusionDirectiveKind, Range),
32     InQuotes(InQuotes), Kind(Kind), File(File)
33 {
34   char *Memory
35     = (char*)PPRec.Allocate(FileName.size() + 1, llvm::alignOf<char>());
36   memcpy(Memory, FileName.data(), FileName.size());
37   Memory[FileName.size()] = 0;
38   this->FileName = StringRef(Memory, FileName.size());
39 }
40 
41 void PreprocessingRecord::MaybeLoadPreallocatedEntities() const {
42   if (!ExternalSource || LoadedPreallocatedEntities)
43     return;
44 
45   LoadedPreallocatedEntities = true;
46   ExternalSource->ReadPreprocessedEntities();
47 }
48 
49 PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroExpansions)
50   : IncludeNestedMacroExpansions(IncludeNestedMacroExpansions),
51     ExternalSource(0), LoadedPreallocatedEntities(false)
52 {
53 }
54 
55 PreprocessingRecord::iterator
56 PreprocessingRecord::begin(bool OnlyLocalEntities) {
57   if (OnlyLocalEntities)
58     return iterator(this, 0);
59 
60   MaybeLoadPreallocatedEntities();
61   return iterator(this, -(int)LoadedPreprocessedEntities.size());
62 }
63 
64 PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) {
65   if (!OnlyLocalEntities)
66     MaybeLoadPreallocatedEntities();
67 
68   return iterator(this, PreprocessedEntities.size());
69 }
70 
71 void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
72   PreprocessedEntities.push_back(Entity);
73 }
74 
75 void PreprocessingRecord::SetExternalSource(
76                                     ExternalPreprocessingRecordSource &Source) {
77   assert(!ExternalSource &&
78          "Preprocessing record already has an external source");
79   ExternalSource = &Source;
80 }
81 
82 unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) {
83   unsigned Result = LoadedPreprocessedEntities.size();
84   LoadedPreprocessedEntities.resize(LoadedPreprocessedEntities.size()
85                                     + NumEntities);
86   return Result;
87 }
88 
89 void
90 PreprocessingRecord::setLoadedPreallocatedEntity(unsigned Index,
91                                                  PreprocessedEntity *Entity) {
92   assert(Index < LoadedPreprocessedEntities.size() &&
93          "Out-of-bounds preallocated entity");
94   LoadedPreprocessedEntities[Index] = Entity;
95 }
96 
97 void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
98                                                   MacroDefinition *MD) {
99   MacroDefinitions[Macro] = MD;
100 }
101 
102 MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
103   llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
104     = MacroDefinitions.find(MI);
105   if (Pos == MacroDefinitions.end())
106     return 0;
107 
108   return Pos->second;
109 }
110 
111 void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) {
112   if (!IncludeNestedMacroExpansions && Id.getLocation().isMacroID())
113     return;
114 
115   if (MacroDefinition *Def = findMacroDefinition(MI))
116     PreprocessedEntities.push_back(
117                        new (*this) MacroExpansion(Id.getIdentifierInfo(),
118                                                   Id.getLocation(), Def));
119 }
120 
121 void PreprocessingRecord::MacroDefined(const Token &Id,
122                                        const MacroInfo *MI) {
123   SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
124   MacroDefinition *Def
125       = new (*this) MacroDefinition(Id.getIdentifierInfo(),
126                                     MI->getDefinitionLoc(),
127                                     R);
128   MacroDefinitions[MI] = Def;
129   PreprocessedEntities.push_back(Def);
130 }
131 
132 void PreprocessingRecord::MacroUndefined(const Token &Id,
133                                          const MacroInfo *MI) {
134   llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
135     = MacroDefinitions.find(MI);
136   if (Pos != MacroDefinitions.end())
137     MacroDefinitions.erase(Pos);
138 }
139 
140 void PreprocessingRecord::InclusionDirective(
141     SourceLocation HashLoc,
142     const clang::Token &IncludeTok,
143     StringRef FileName,
144     bool IsAngled,
145     const FileEntry *File,
146     clang::SourceLocation EndLoc,
147     StringRef SearchPath,
148     StringRef RelativePath) {
149   InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
150 
151   switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) {
152   case tok::pp_include:
153     Kind = InclusionDirective::Include;
154     break;
155 
156   case tok::pp_import:
157     Kind = InclusionDirective::Import;
158     break;
159 
160   case tok::pp_include_next:
161     Kind = InclusionDirective::IncludeNext;
162     break;
163 
164   case tok::pp___include_macros:
165     Kind = InclusionDirective::IncludeMacros;
166     break;
167 
168   default:
169     llvm_unreachable("Unknown include directive kind");
170     return;
171   }
172 
173   clang::InclusionDirective *ID
174     = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled,
175                                             File, SourceRange(HashLoc, EndLoc));
176   PreprocessedEntities.push_back(ID);
177 }
178 
179 size_t PreprocessingRecord::getTotalMemory() const {
180   return BumpAlloc.getTotalMemory()
181     + llvm::capacity_in_bytes(MacroDefinitions)
182     + llvm::capacity_in_bytes(PreprocessedEntities)
183     + llvm::capacity_in_bytes(LoadedPreprocessedEntities);
184 }
185