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