blob: 8f2f52e8d77cdfc35458674f3a3e4ab0645790ea [file] [log] [blame]
John Thompson1e010142013-07-26 18:16:22 +00001//=- PreprocessorTracker.cpp - Preprocessor tracking -*- 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#include "clang/Lex/LexDiagnostic.h"
11#include "clang/Lex/MacroArgs.h"
12#include "clang/Lex/PPCallbacks.h"
13#include "llvm/Support/raw_ostream.h"
14#include "llvm/Support/StringPool.h"
15#include "PreprocessorTracker.h"
16
17namespace Modularize {
18
19// Forwards.
20class PreprocessorTrackerImpl;
21
22// Some handle types
23
24// String handle.
25typedef llvm::PooledStringPtr StringHandle;
26
27// Header handle.
28typedef int HeaderHandle;
29const HeaderHandle HeaderHandleInvalid = -1;
30
31// Header inclusion path handle.
32typedef int InclusionPathHandle;
33const InclusionPathHandle InclusionPathHandleInvalid = -1;
34
35// Some utility functions.
36
37// Get a "file:line:column" source location string.
38static std::string getSourceLocationString(clang::Preprocessor &PP,
39 clang::SourceLocation Loc) {
40 if (Loc.isInvalid())
41 return std::string("(none)");
42 else
43 return Loc.printToString(PP.getSourceManager());
44}
45
46// Get just the file name from a source location.
47static std::string getSourceLocationFile(clang::Preprocessor &PP,
48 clang::SourceLocation Loc) {
49 std::string Source(getSourceLocationString(PP, Loc));
50 size_t Offset = Source.find(':', 2);
51 if (Offset == std::string::npos)
52 return Source;
53 return Source.substr(0, Offset);
54}
55
56// Get just the line and column from a source location.
57static void getSourceLocationLineAndColumn(clang::Preprocessor &PP,
58 clang::SourceLocation Loc, int &Line,
59 int &Column) {
60 clang::PresumedLoc PLoc = PP.getSourceManager().getPresumedLoc(Loc);
61 if (PLoc.isInvalid()) {
62 Line = 0;
63 Column = 0;
64 return;
65 }
66 Line = PLoc.getLine();
67 Column = PLoc.getColumn();
68}
69
70// Retrieve source snippet from file image.
71std::string getSourceString(clang::Preprocessor &PP, clang::SourceRange Range) {
72 clang::SourceLocation BeginLoc = Range.getBegin();
73 clang::SourceLocation EndLoc = Range.getEnd();
74 const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
75 const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc);
76 size_t Length = EndPtr - BeginPtr;
77 return llvm::StringRef(BeginPtr, Length).trim().str();
78}
79
80// Retrieve source line from file image.
81std::string getSourceLine(clang::Preprocessor &PP, clang::SourceLocation Loc) {
82 const llvm::MemoryBuffer *MemBuffer =
83 PP.getSourceManager().getBuffer(PP.getSourceManager().getFileID(Loc));
84 const char *Buffer = MemBuffer->getBufferStart();
85 const char *BufferEnd = MemBuffer->getBufferEnd();
86 const char *BeginPtr = PP.getSourceManager().getCharacterData(Loc);
87 const char *EndPtr = BeginPtr;
88 while (BeginPtr > Buffer) {
89 if (*BeginPtr == '\n') {
90 BeginPtr++;
91 break;
92 }
93 BeginPtr--;
94 }
95 while (EndPtr < BufferEnd) {
96 if (*EndPtr == '\n') {
97 break;
98 }
99 EndPtr++;
100 }
101 size_t Length = EndPtr - BeginPtr;
102 return llvm::StringRef(BeginPtr, Length).str();
103}
104
105// Get the string for the Unexpanded macro instance.
106// The soureRange is expected to end at the last token
107// for the macro instance, which in the case of a function-style
108// macro will be a ')', but for an object-style macro, it
109// will be the macro name itself.
110std::string getMacroUnexpandedString(clang::SourceRange Range,
111 clang::Preprocessor &PP,
112 llvm::StringRef MacroName,
113 const clang::MacroInfo *MI) {
114 clang::SourceLocation BeginLoc(Range.getBegin());
115 const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
116 size_t Length;
117 std::string Unexpanded;
118 if (MI->isFunctionLike()) {
119 clang::SourceLocation EndLoc(Range.getEnd());
120 const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc) + 1;
121 Length = (EndPtr - BeginPtr) + 1; // +1 is ')' width.
122 } else
123 Length = MacroName.size();
124 return llvm::StringRef(BeginPtr, Length).trim().str();
125}
126
127// Get the expansion for a macro instance, given the information
128// provided by PPCallbacks.
129std::string getMacroExpandedString(clang::Preprocessor &PP,
130 llvm::StringRef MacroName,
131 const clang::MacroInfo *MI,
132 const clang::MacroArgs *Args) {
133 std::string Expanded;
134 // Walk over the macro Tokens.
135 typedef clang::MacroInfo::tokens_iterator Iter;
136 for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
137 clang::IdentifierInfo *II = I->getIdentifierInfo();
138 int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
139 if (ArgNo == -1) {
140 // This isn't an argument, just add it.
141 if (II == NULL)
142 Expanded += PP.getSpelling((*I)); // Not an identifier.
143 else {
144 // Token is for an identifier.
145 std::string Name = II->getName().str();
146 // Check for nexted macro references.
147 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
148 if (MacroInfo != NULL)
149 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
150 else
151 Expanded += Name;
152 }
153 continue;
154 }
155 // We get here if it's a function-style macro with arguments.
156 const clang::Token *ResultArgToks;
157 const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
158 if (Args->ArgNeedsPreexpansion(ArgTok, PP))
159 ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
160 ->getPreExpArgument(ArgNo, MI, PP)[0];
161 else
162 ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
163 // If the arg token didn't expand into anything, ignore it.
164 if (ResultArgToks->is(clang::tok::eof))
165 continue;
166 unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
167 // Append the resulting argument expansions.
168 for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
169 const clang::Token &AT = ResultArgToks[ArgumentIndex];
170 clang::IdentifierInfo *II = AT.getIdentifierInfo();
171 if (II == NULL)
172 Expanded += PP.getSpelling(AT); // Not an identifier.
173 else {
174 // It's an identifier. Check for further expansion.
175 std::string Name = II->getName().str();
176 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
177 if (MacroInfo != NULL)
178 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
179 else
180 Expanded += Name;
181 }
182 }
183 }
184 return Expanded;
185}
186
187// Get the string representing a vector of Tokens.
188std::string
189getTokensSpellingString(clang::Preprocessor &PP,
190 llvm::SmallVectorImpl<clang::Token> &Tokens) {
191 std::string Expanded;
192 // Walk over the macro Tokens.
193 typedef llvm::SmallVectorImpl<clang::Token>::iterator Iter;
194 for (Iter I = Tokens.begin(), E = Tokens.end(); I != E; ++I)
195 Expanded += PP.getSpelling(*I); // Not an identifier.
196 return llvm::StringRef(Expanded).trim().str();
197}
198
199// Get the expansion for a macro instance, given the information
200// provided by PPCallbacks.
201std::string getExpandedString(clang::Preprocessor &PP,
202 llvm::StringRef MacroName,
203 const clang::MacroInfo *MI,
204 const clang::MacroArgs *Args) {
205 std::string Expanded;
206 // Walk over the macro Tokens.
207 typedef clang::MacroInfo::tokens_iterator Iter;
208 for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
209 clang::IdentifierInfo *II = I->getIdentifierInfo();
210 int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
211 if (ArgNo == -1) {
212 // This isn't an argument, just add it.
213 if (II == NULL)
214 Expanded += PP.getSpelling((*I)); // Not an identifier.
215 else {
216 // Token is for an identifier.
217 std::string Name = II->getName().str();
218 // Check for nexted macro references.
219 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
220 if (MacroInfo != NULL)
221 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
222 else
223 Expanded += Name;
224 }
225 continue;
226 }
227 // We get here if it's a function-style macro with arguments.
228 const clang::Token *ResultArgToks;
229 const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
230 if (Args->ArgNeedsPreexpansion(ArgTok, PP))
231 ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
232 ->getPreExpArgument(ArgNo, MI, PP)[0];
233 else
234 ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
235 // If the arg token didn't expand into anything, ignore it.
236 if (ResultArgToks->is(clang::tok::eof))
237 continue;
238 unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
239 // Append the resulting argument expansions.
240 for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
241 const clang::Token &AT = ResultArgToks[ArgumentIndex];
242 clang::IdentifierInfo *II = AT.getIdentifierInfo();
243 if (II == NULL)
244 Expanded += PP.getSpelling(AT); // Not an identifier.
245 else {
246 // It's an identifier. Check for further expansion.
247 std::string Name = II->getName().str();
248 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
249 if (MacroInfo != NULL)
250 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
251 else
252 Expanded += Name;
253 }
254 }
255 }
256 return Expanded;
257}
258
259// We need some operator overloads for string handles.
260bool operator==(const StringHandle &H1, const StringHandle &H2) {
261 const char *S1 = (H1 ? *H1 : "");
262 const char *S2 = (H2 ? *H2 : "");
263 int Diff = strcmp(S1, S2);
264 return Diff == 0;
265}
266bool operator!=(const StringHandle &H1, const StringHandle &H2) {
267 const char *S1 = (H1 ? *H1 : "");
268 const char *S2 = (H2 ? *H2 : "");
269 int Diff = strcmp(S1, S2);
270 return Diff != 0;
271}
272bool operator<(const StringHandle &H1, const StringHandle &H2) {
273 const char *S1 = (H1 ? *H1 : "");
274 const char *S2 = (H2 ? *H2 : "");
275 int Diff = strcmp(S1, S2);
276 return Diff < 0;
277}
278bool operator>(const StringHandle &H1, const StringHandle &H2) {
279 const char *S1 = (H1 ? *H1 : "");
280 const char *S2 = (H2 ? *H2 : "");
281 int Diff = strcmp(S1, S2);
282 return Diff > 0;
283}
284
285// Preprocessor item key.
286//
287// This class represents a location in a source file, for use
288// as a key representing a unique name/file/line/column quadruplet,
289// which in this case is used to identify a macro expansion instance,
290// but could be used for other things as well.
291// The file is a header file handle, the line is a line number,
292// and the column is a column number.
293class PPItemKey {
294public:
295 PPItemKey(clang::Preprocessor &PP, StringHandle Name, HeaderHandle File,
296 clang::SourceLocation Loc)
297 : Name(Name), File(File) {
298 getSourceLocationLineAndColumn(PP, Loc, Line, Column);
299 }
300 PPItemKey(StringHandle Name, HeaderHandle File, int Line, int Column)
301 : Name(Name), File(File), Line(Line), Column(Column) {}
302 PPItemKey(const PPItemKey &Other)
303 : Name(Other.Name), File(Other.File), Line(Other.Line),
304 Column(Other.Column) {}
305 PPItemKey() : File(HeaderHandleInvalid), Line(0), Column(0) {}
306 bool operator==(const PPItemKey &Other) const {
307 if (Name != Other.Name)
308 return false;
309 if (File != Other.File)
310 return false;
311 if (Line != Other.Line)
312 return false;
313 return Column == Other.Column;
314 }
315 bool operator<(const PPItemKey &Other) const {
316 if (Name < Other.Name)
317 return true;
318 else if (Name > Other.Name)
319 return false;
320 if (File < Other.File)
321 return true;
322 else if (File > Other.File)
323 return false;
324 if (Line < Other.Line)
325 return true;
326 else if (Line > Other.Line)
327 return false;
328 return Column < Other.Column;
329 }
330 StringHandle Name;
331 HeaderHandle File;
332 int Line;
333 int Column;
334};
335
336// Header inclusion path.
337class HeaderInclusionPath {
338public:
339 HeaderInclusionPath(std::vector<HeaderHandle> HeaderInclusionPath)
340 : Path(HeaderInclusionPath) {}
341 HeaderInclusionPath(const HeaderInclusionPath &Other) : Path(Other.Path) {}
342 HeaderInclusionPath() {}
343 std::vector<HeaderHandle> Path;
344};
345
346// Macro expansion instance.
347//
348// This class represents an instance of a macro expansion with a
349// unique value. It also stores the unique header inclusion paths
350// for use in telling the user the nested include path f
351class MacroExpansionInstance {
352public:
353 MacroExpansionInstance(StringHandle MacroExpanded,
354 PPItemKey &DefinitionLocation,
355 StringHandle DefinitionSourceLine,
356 InclusionPathHandle H)
357 : MacroExpanded(MacroExpanded), DefinitionLocation(DefinitionLocation),
358 DefinitionSourceLine(DefinitionSourceLine) {
359 InclusionPathHandles.push_back(H);
360 }
361 MacroExpansionInstance() {}
362
363 // Check for the presence of a header inclusion path handle entry.
364 // Return false if not found.
365 bool haveInclusionPathHandle(InclusionPathHandle H) {
366 for (std::vector<InclusionPathHandle>::iterator
367 I = InclusionPathHandles.begin(),
368 E = InclusionPathHandles.end();
369 I != E; ++I) {
370 if (*I == H)
371 return true;
372 }
373 return InclusionPathHandleInvalid;
374 }
375 // Add a new header inclusion path entry, if not already present.
376 void addInclusionPathHandle(InclusionPathHandle H) {
377 if (!haveInclusionPathHandle(H))
378 InclusionPathHandles.push_back(H);
379 }
380
381 // A string representing the macro instance after preprocessing.
382 StringHandle MacroExpanded;
383 // A file/line/column triplet representing the macro definition location.
384 PPItemKey DefinitionLocation;
385 // A place to save the macro definition line string.
386 StringHandle DefinitionSourceLine;
387 // The header inclusion path handles for all the instances.
388 std::vector<InclusionPathHandle> InclusionPathHandles;
389};
390
391// Macro expansion instance tracker.
392//
393// This class represents one macro expansion, keyed by a PPItemKey.
394// It stores a string representing the macro reference in the source,
395// and a list of ConditionalExpansionInstances objects representing
396// the unique value the condition expands to in instances of the header.
397class MacroExpansionTracker {
398public:
399 MacroExpansionTracker(StringHandle MacroUnexpanded,
400 StringHandle MacroExpanded,
401 StringHandle InstanceSourceLine,
402 PPItemKey &DefinitionLocation,
403 StringHandle DefinitionSourceLine,
404 InclusionPathHandle InclusionPathHandle)
405 : MacroUnexpanded(MacroUnexpanded),
406 InstanceSourceLine(InstanceSourceLine) {
407 addMacroExpansionInstance(MacroExpanded, DefinitionLocation,
408 DefinitionSourceLine, InclusionPathHandle);
409 }
410 MacroExpansionTracker() {}
411
412 // Find a matching macro expansion instance.
413 MacroExpansionInstance *
414 findMacroExpansionInstance(StringHandle MacroExpanded,
415 PPItemKey &DefinitionLocation) {
416 for (std::vector<MacroExpansionInstance>::iterator
417 I = MacroExpansionInstances.begin(),
418 E = MacroExpansionInstances.end();
419 I != E; ++I) {
420 if ((I->MacroExpanded == MacroExpanded) &&
421 (I->DefinitionLocation == DefinitionLocation)) {
422 return &*I; // Found.
423 }
424 }
425 return NULL; // Not found.
426 }
427
428 // Add a macro expansion instance.
429 void addMacroExpansionInstance(StringHandle MacroExpanded,
430 PPItemKey &DefinitionLocation,
431 StringHandle DefinitionSourceLine,
432 InclusionPathHandle InclusionPathHandle) {
433 MacroExpansionInstances.push_back(
434 MacroExpansionInstance(MacroExpanded, DefinitionLocation,
435 DefinitionSourceLine, InclusionPathHandle));
436 }
437
438 // Return true if there is a mismatch.
439 bool hasMismatch() { return MacroExpansionInstances.size() > 1; }
440
441 // A string representing the macro instance without expansion.
442 StringHandle MacroUnexpanded;
443 // A place to save the macro instance source line string.
444 StringHandle InstanceSourceLine;
445 // The macro expansion instances.
446 // If all instances of the macro expansion expand to the same value,
447 // This vector will only have one instance.
448 std::vector<MacroExpansionInstance> MacroExpansionInstances;
449};
450
451// Conditional expansion instance.
452//
453// This class represents an instance of a macro expansion with a
454// unique value. It also stores the unique header inclusion paths
455// for use in telling the user the nested include path f
456class ConditionalExpansionInstance {
457public:
458 ConditionalExpansionInstance(bool ConditionValue, InclusionPathHandle H)
459 : ConditionValue(ConditionValue) {
460 InclusionPathHandles.push_back(H);
461 }
462 ConditionalExpansionInstance() {}
463
464 // Check for the presence of a header inclusion path handle entry.
465 // Return false if not found.
466 bool haveInclusionPathHandle(InclusionPathHandle H) {
467 for (std::vector<InclusionPathHandle>::iterator
468 I = InclusionPathHandles.begin(),
469 E = InclusionPathHandles.end();
470 I != E; ++I) {
471 if (*I == H)
472 return true;
473 }
474 return InclusionPathHandleInvalid;
475 }
476 // Add a new header inclusion path entry, if not already present.
477 void addInclusionPathHandle(InclusionPathHandle H) {
478 if (!haveInclusionPathHandle(H))
479 InclusionPathHandles.push_back(H);
480 }
481
482 // A flag representing the evaluated condition value.
483 bool ConditionValue;
484 // The header inclusion path handles for all the instances.
485 std::vector<InclusionPathHandle> InclusionPathHandles;
486};
487
488// Conditional directive instance tracker.
489//
490// This class represents one conditional directive, keyed by a PPItemKey.
491// It stores a string representing the macro reference in the source,
492// and a list of MacroExpansionInstance objects representing
493// the unique value the macro expands to in instances of the header.
494class ConditionalTracker {
495public:
496 ConditionalTracker(clang::tok::PPKeywordKind DirectiveKind,
497 bool ConditionValue, StringHandle ConditionUnexpanded,
498 InclusionPathHandle InclusionPathHandle)
499 : DirectiveKind(DirectiveKind), ConditionUnexpanded(ConditionUnexpanded) {
500 addConditionalExpansionInstance(ConditionValue, InclusionPathHandle);
501 }
502 ConditionalTracker() {}
503
504 // Find a matching condition expansion instance.
505 ConditionalExpansionInstance *
506 findConditionalExpansionInstance(bool ConditionValue) {
507 for (std::vector<ConditionalExpansionInstance>::iterator
508 I = ConditionalExpansionInstances.begin(),
509 E = ConditionalExpansionInstances.end();
510 I != E; ++I) {
511 if (I->ConditionValue == ConditionValue) {
512 return &*I; // Found.
513 }
514 }
515 return NULL; // Not found.
516 }
517
518 // Add a conditional expansion instance.
519 void
520 addConditionalExpansionInstance(bool ConditionValue,
521 InclusionPathHandle InclusionPathHandle) {
522 ConditionalExpansionInstances.push_back(
523 ConditionalExpansionInstance(ConditionValue, InclusionPathHandle));
524 }
525
526 // Return true if there is a mismatch.
527 bool hasMismatch() { return ConditionalExpansionInstances.size() > 1; }
528
529 // The kind of directive.
530 clang::tok::PPKeywordKind DirectiveKind;
531 // A string representing the macro instance without expansion.
532 StringHandle ConditionUnexpanded;
533 // The condition expansion instances.
534 // If all instances of the conditional expression expand to the same value,
535 // This vector will only have one instance.
536 std::vector<ConditionalExpansionInstance> ConditionalExpansionInstances;
537};
538
539// Preprocessor callbacks for modularize.
540//
541// This class derives from the Clang PPCallbacks class to track preprocessor
542// actions, such as changing files and handling preprocessor directives and
543// macro expansions. It has to figure out when a new header file is entered
544// and left, as the provided handler is not particularly clear about it.
545class PreprocessorCallbacks : public clang::PPCallbacks {
546public:
547 PreprocessorCallbacks(PreprocessorTrackerImpl &ppTracker,
548 clang::Preprocessor &PP, llvm::StringRef rootHeaderFile)
549 : PPTracker(ppTracker), PP(PP), RootHeaderFile(rootHeaderFile) {}
550 ~PreprocessorCallbacks() {}
551
552 // Overidden handlers.
553 void FileChanged(clang::SourceLocation Loc,
554 clang::PPCallbacks::FileChangeReason Reason,
555 clang::SrcMgr::CharacteristicKind FileType,
556 clang::FileID PrevFID = clang::FileID());
557 void MacroExpands(const clang::Token &MacroNameTok,
558 const clang::MacroDirective *MD, clang::SourceRange Range,
559 const clang::MacroArgs *Args);
560 void Defined(const clang::Token &MacroNameTok,
561 const clang::MacroDirective *MD, clang::SourceRange Range);
562 void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
563 bool ConditionResult);
564 void Elif(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
565 bool ConditionResult, clang::SourceLocation IfLoc);
566 void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
567 const clang::MacroDirective *MD);
568 void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
569 const clang::MacroDirective *MD);
570
571private:
572 PreprocessorTrackerImpl &PPTracker;
573 clang::Preprocessor &PP;
574 std::string RootHeaderFile;
575};
576
577// Preprocessor macro expansion item map types.
578typedef std::map<PPItemKey, MacroExpansionTracker> MacroExpansionMap;
579typedef std::map<PPItemKey, MacroExpansionTracker>::iterator
580MacroExpansionMapIter;
581
582// Preprocessor conditional expansion item map types.
583typedef std::map<PPItemKey, ConditionalTracker> ConditionalExpansionMap;
584typedef std::map<PPItemKey, ConditionalTracker>::iterator
585ConditionalExpansionMapIter;
586
587// Preprocessor tracker for modularize.
588//
589// This class stores information about all the headers processed in the
590// course of running modularize.
591class PreprocessorTrackerImpl : public PreprocessorTracker {
592public:
593 PreprocessorTrackerImpl()
594 : CurrentInclusionPathHandle(InclusionPathHandleInvalid) {}
595 ~PreprocessorTrackerImpl() {}
596
597 // Handle entering a preprocessing session.
598 void handlePreprocessorEntry(clang::Preprocessor &PP,
599 llvm::StringRef rootHeaderFile) {
600 assert((HeaderStack.size() == 0) && "Header stack should be empty.");
601 pushHeaderHandle(addHeader(rootHeaderFile));
602 PP.addPPCallbacks(new PreprocessorCallbacks(*this, PP, rootHeaderFile));
603 }
604 // Handle exiting a preprocessing session.
605 void handlePreprocessorExit() { HeaderStack.clear(); }
606
607 // Handle entering a header source file.
608 void handleHeaderEntry(clang::Preprocessor &PP, llvm::StringRef HeaderPath) {
609 // Ignore <built-in> and <command-line> to reduce message clutter.
610 if (HeaderPath.startswith("<"))
611 return;
612 HeaderHandle H = addHeader(HeaderPath);
613 if (H != getCurrentHeaderHandle())
614 pushHeaderHandle(H);
615 }
616 // Handle exiting a header source file.
617 void handleHeaderExit(llvm::StringRef HeaderPath) {
618 // Ignore <built-in> and <command-line> to reduce message clutter.
619 if (HeaderPath.startswith("<"))
620 return;
621 HeaderHandle H = findHeaderHandle(HeaderPath);
622 if (isHeaderHandleInStack(H)) {
623 while ((H != getCurrentHeaderHandle()) && (HeaderStack.size() != 0))
624 popHeaderHandle();
625 }
626 }
627
628 // Lookup/add string.
629 StringHandle addString(llvm::StringRef Str) { return Strings.intern(Str); }
630
631 // Get the handle of a header file entry.
632 // Return HeaderHandleInvalid if not found.
633 HeaderHandle findHeaderHandle(llvm::StringRef HeaderPath) const {
634 HeaderHandle H = 0;
635 for (std::vector<StringHandle>::const_iterator I = HeaderPaths.begin(),
636 E = HeaderPaths.end();
637 I != E; ++I, ++H) {
638 if (**I == HeaderPath)
639 return H;
640 }
641 return HeaderHandleInvalid;
642 }
643
644 // Add a new header file entry, or return existing handle.
645 // Return the header handle.
646 HeaderHandle addHeader(llvm::StringRef HeaderPath) {
647 std::string canonicalPath(HeaderPath);
648 std::replace(canonicalPath.begin(), canonicalPath.end(), '\\', '/');
649 HeaderHandle H = findHeaderHandle(canonicalPath);
650 if (H == HeaderHandleInvalid) {
651 H = HeaderPaths.size();
652 HeaderPaths.push_back(addString(canonicalPath));
653 }
654 return H;
655 }
656
657 // Return a header file path string given its handle.
658 StringHandle getHeaderFilePath(HeaderHandle H) const {
659 if ((H >= 0) && (H < (HeaderHandle)HeaderPaths.size()))
660 return HeaderPaths[H];
661 return StringHandle();
662 }
663
664 // Returns a handle to the inclusion path.
665 InclusionPathHandle pushHeaderHandle(HeaderHandle H) {
666 HeaderStack.push_back(H);
667 return CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
668 }
669 // Pops the last header handle from the stack;
670 void popHeaderHandle() {
671 // assert((HeaderStack.size() != 0) && "Header stack already empty.");
672 if (HeaderStack.size() != 0) {
673 HeaderStack.pop_back();
674 CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
675 }
676 }
677 // Get the top handle on the header stack.
678 HeaderHandle getCurrentHeaderHandle() const {
679 if (HeaderStack.size() != 0)
680 return HeaderStack.back();
681 return HeaderHandleInvalid;
682 }
683
684 // Check for presence of header handle in the header stack.
685 bool isHeaderHandleInStack(HeaderHandle H) const {
686 for (std::vector<HeaderHandle>::const_iterator I = HeaderStack.begin(),
687 E = HeaderStack.end();
688 I != E; ++I) {
689 if (*I == H)
690 return true;
691 }
692 return false;
693 }
694
695 // Get the handle of a header inclusion path entry.
696 // Return InclusionPathHandleInvalid if not found.
697 InclusionPathHandle
698 findInclusionPathHandle(const std::vector<HeaderHandle> &Path) const {
699 InclusionPathHandle H = 0;
700 for (std::vector<HeaderInclusionPath>::const_iterator
701 I = InclusionPaths.begin(),
702 E = InclusionPaths.end();
703 I != E; ++I, ++H) {
704 if (I->Path == Path)
705 return H;
706 }
707 return HeaderHandleInvalid;
708 }
709 // Add a new header inclusion path entry, or return existing handle.
710 // Return the header inclusion path entry handle.
711 InclusionPathHandle
712 addInclusionPathHandle(const std::vector<HeaderHandle> &Path) {
713 InclusionPathHandle H = findInclusionPathHandle(Path);
714 if (H == HeaderHandleInvalid) {
715 H = InclusionPaths.size();
716 InclusionPaths.push_back(HeaderInclusionPath(Path));
717 }
718 return H;
719 }
720 // Return the current inclusion path handle.
721 InclusionPathHandle getCurrentInclusionPathHandle() const {
722 return CurrentInclusionPathHandle;
723 }
724
725 // Return an inclusion path given its handle.
726 const std::vector<HeaderHandle> &
727 getInclusionPath(InclusionPathHandle H) const {
728 if ((H >= 0) && (H <= (InclusionPathHandle)InclusionPaths.size()))
729 return InclusionPaths[H].Path;
730 static std::vector<HeaderHandle> Empty;
731 return Empty;
732 }
733
734 // Add a macro expansion instance.
735 void addMacroExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
736 clang::SourceLocation InstanceLoc,
737 clang::SourceLocation DefinitionLoc,
738 clang::IdentifierInfo *II,
739 llvm::StringRef MacroUnexpanded,
740 llvm::StringRef MacroExpanded,
741 InclusionPathHandle InclusionPathHandle) {
742 StringHandle MacroName = addString(II->getName());
743 PPItemKey instanceKey(PP, MacroName, H, InstanceLoc);
744 PPItemKey definitionKey(PP, MacroName, H, DefinitionLoc);
745 MacroExpansionMapIter I = MacroExpansions.find(instanceKey);
746 if (I == MacroExpansions.end()) {
747 std::string instanceSourceLine =
748 getSourceLocationString(PP, InstanceLoc) + ":\n" +
749 getSourceLine(PP, InstanceLoc) + "\n";
750 std::string definitionSourceLine =
751 getSourceLocationString(PP, DefinitionLoc) + ":\n" +
752 getSourceLine(PP, DefinitionLoc) + "\n";
753 MacroExpansions[instanceKey] = MacroExpansionTracker(
754 addString(MacroUnexpanded), addString(MacroExpanded),
755 addString(instanceSourceLine), definitionKey,
756 addString(definitionSourceLine), InclusionPathHandle);
757 } else {
758 MacroExpansionTracker &CondTracker = I->second;
759 MacroExpansionInstance *MacroInfo =
760 CondTracker.findMacroExpansionInstance(addString(MacroExpanded),
761 definitionKey);
762 if (MacroInfo != NULL)
763 MacroInfo->addInclusionPathHandle(InclusionPathHandle);
764 else {
765 std::string definitionSourceLine =
766 getSourceLocationString(PP, DefinitionLoc) + ":\n" +
767 getSourceLine(PP, DefinitionLoc) + "\n";
768 CondTracker.addMacroExpansionInstance(
769 addString(MacroExpanded), definitionKey,
770 addString(definitionSourceLine), InclusionPathHandle);
771 }
772 }
773 }
774
775 // Add a conditional expansion instance.
776 void
777 addConditionalExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
778 clang::SourceLocation InstanceLoc,
779 clang::tok::PPKeywordKind DirectiveKind,
780 bool ConditionValue,
781 llvm::StringRef ConditionUnexpanded,
782 InclusionPathHandle InclusionPathHandle) {
783 StringHandle conditionUnexpanded(addString(ConditionUnexpanded));
784 PPItemKey instanceKey(PP, conditionUnexpanded, H, InstanceLoc);
785 ConditionalExpansionMapIter I = ConditionalExpansions.find(instanceKey);
786 if (I == ConditionalExpansions.end()) {
787 std::string instanceSourceLine =
788 getSourceLocationString(PP, InstanceLoc) + ":\n" +
789 getSourceLine(PP, InstanceLoc) + "\n";
790 ConditionalExpansions[instanceKey] =
791 ConditionalTracker(DirectiveKind, ConditionValue, conditionUnexpanded,
792 InclusionPathHandle);
793 } else {
794 ConditionalTracker &CondTracker = I->second;
795 ConditionalExpansionInstance *MacroInfo =
796 CondTracker.findConditionalExpansionInstance(ConditionValue);
797 if (MacroInfo != NULL)
798 MacroInfo->addInclusionPathHandle(InclusionPathHandle);
799 else {
800 CondTracker.addConditionalExpansionInstance(ConditionValue,
801 InclusionPathHandle);
802 }
803 }
804 }
805
806 // Report on inconsistent macro instances.
807 // Returns true if any mismatches.
808 bool reportInconsistentMacros(llvm::raw_ostream &OS) {
809 bool returnValue = false;
810 for (MacroExpansionMapIter I = MacroExpansions.begin(),
811 E = MacroExpansions.end();
812 I != E; ++I) {
813 const PPItemKey &ItemKey = I->first;
814 MacroExpansionTracker &MacroExpTracker = I->second;
815 if (!MacroExpTracker.hasMismatch())
816 continue;
817 returnValue = true;
818 OS << *MacroExpTracker.InstanceSourceLine;
819 if (ItemKey.Column > 0)
820 OS << std::string(ItemKey.Column - 1, ' ') << "^\n";
821 OS << "error: Macro instance '" << *MacroExpTracker.MacroUnexpanded
822 << "' has different values in this header, depending on how it was "
823 "included.\n";
824 for (std::vector<MacroExpansionInstance>::iterator
825 IMT = MacroExpTracker.MacroExpansionInstances.begin(),
826 EMT = MacroExpTracker.MacroExpansionInstances.end();
827 IMT != EMT; ++IMT) {
828 MacroExpansionInstance &MacroInfo = *IMT;
829 OS << " '" << *MacroExpTracker.MacroUnexpanded << "' Expanded to: '"
830 << *MacroInfo.MacroExpanded
831 << "' with respect to these inclusion paths:\n";
832 for (std::vector<InclusionPathHandle>::iterator
833 IIP = MacroInfo.InclusionPathHandles.begin(),
834 EIP = MacroInfo.InclusionPathHandles.end();
835 IIP != EIP; ++IIP) {
836 const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
837 int Count = (int)ip.size();
838 for (int Index = 0; Index < Count; ++Index) {
839 HeaderHandle H = ip[Index];
840 OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
841 << "\n";
842 }
843 }
844 // For a macro that wasn't defined, we flag it by using the
845 // instance location.
846 // If there is a definition...
847 if (MacroInfo.DefinitionLocation.Line != ItemKey.Line) {
848 OS << *MacroInfo.DefinitionSourceLine;
849 if (MacroInfo.DefinitionLocation.Column > 0)
850 OS << std::string(MacroInfo.DefinitionLocation.Column - 1, ' ')
851 << "^\n";
852 OS << "Macro defined here.\n";
853 } else
854 OS << "(no macro definition)"
855 << "\n";
856 }
857 }
858 return returnValue;
859 }
860
861 // Report on inconsistent conditional instances.
862 // Returns true if any mismatches.
863 bool reportInconsistentConditionals(llvm::raw_ostream &OS) {
864 bool returnValue = false;
865 for (ConditionalExpansionMapIter I = ConditionalExpansions.begin(),
866 E = ConditionalExpansions.end();
867 I != E; ++I) {
868 const PPItemKey &ItemKey = I->first;
869 ConditionalTracker &CondTracker = I->second;
870 if (!CondTracker.hasMismatch())
871 continue;
872 returnValue = true;
873 OS << *HeaderPaths[ItemKey.File] << ":" << ItemKey.Line << ":"
874 << ItemKey.Column << "\n";
875 OS << "#" << getDirectiveSpelling(CondTracker.DirectiveKind) << " "
876 << *CondTracker.ConditionUnexpanded << "\n";
877 OS << "^\n";
878 OS << "error: Conditional expression instance '"
879 << *CondTracker.ConditionUnexpanded
880 << "' has different values in this header, depending on how it was "
881 "included.\n";
882 for (std::vector<ConditionalExpansionInstance>::iterator
883 IMT = CondTracker.ConditionalExpansionInstances.begin(),
884 EMT = CondTracker.ConditionalExpansionInstances.end();
885 IMT != EMT; ++IMT) {
886 ConditionalExpansionInstance &MacroInfo = *IMT;
887 OS << " '" << *CondTracker.ConditionUnexpanded << "' Expanded to: '"
888 << (MacroInfo.ConditionValue ? "true" : "false")
889 << "' with respect to these inclusion paths:\n";
890 for (std::vector<InclusionPathHandle>::iterator
891 IIP = MacroInfo.InclusionPathHandles.begin(),
892 EIP = MacroInfo.InclusionPathHandles.end();
893 IIP != EIP; ++IIP) {
894 const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
895 int Count = (int)ip.size();
896 for (int Index = 0; Index < Count; ++Index) {
897 HeaderHandle H = ip[Index];
898 OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
899 << "\n";
900 }
901 }
902 }
903 }
904 return returnValue;
905 }
906
907 // Get directive spelling.
908 static const char *getDirectiveSpelling(clang::tok::PPKeywordKind kind) {
909 switch (kind) {
910 case clang::tok::pp_if:
911 return "if";
912 case clang::tok::pp_elif:
913 return "elif";
914 case clang::tok::pp_ifdef:
915 return "ifdef";
916 case clang::tok::pp_ifndef:
917 return "ifndef";
918 default:
919 return "(unknown)";
920 }
921 }
922
923private:
924 llvm::StringPool Strings;
925 std::vector<StringHandle> HeaderPaths;
926 std::vector<HeaderHandle> HeaderStack;
927 std::vector<HeaderInclusionPath> InclusionPaths;
928 InclusionPathHandle CurrentInclusionPathHandle;
929 MacroExpansionMap MacroExpansions;
930 ConditionalExpansionMap ConditionalExpansions;
931};
932
933// PreprocessorTracker functions.
934
935// PreprocessorTracker desctructor.
936PreprocessorTracker::~PreprocessorTracker() {}
937
938// Create instance of PreprocessorTracker.
939PreprocessorTracker *PreprocessorTracker::create() {
940 return new PreprocessorTrackerImpl();
941}
942
943// Preprocessor callbacks for modularize.
944
945// Handle file entry/exit.
946void PreprocessorCallbacks::FileChanged(
947 clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason,
948 clang::SrcMgr::CharacteristicKind FileType, clang::FileID PrevFID) {
949 switch (Reason) {
950 case EnterFile:
951 PPTracker.handleHeaderEntry(PP, getSourceLocationFile(PP, Loc));
952 break;
953 case ExitFile:
954 if (PrevFID.isInvalid())
955 PPTracker.handleHeaderExit(RootHeaderFile);
956 else
957 PPTracker.handleHeaderExit(getSourceLocationFile(PP, Loc));
958 break;
959 case SystemHeaderPragma:
960 return;
961 case RenameFile:
962 return;
963 default:
964 return;
965 }
966}
967
968// Handle macro expansion.
969void PreprocessorCallbacks::MacroExpands(const clang::Token &MacroNameTok,
970 const clang::MacroDirective *MD,
971 clang::SourceRange Range,
972 const clang::MacroArgs *Args) {
973 clang::SourceLocation Loc = Range.getBegin();
974 clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
975 const clang::MacroInfo *MI = PP.getMacroInfo(II);
976 std::string MacroName = II->getName().str();
977 std::string Unexpanded(getMacroUnexpandedString(Range, PP, MacroName, MI));
978 std::string Expanded(getMacroExpandedString(PP, MacroName, MI, Args));
979 PPTracker.addMacroExpansionInstance(
980 PP, PPTracker.getCurrentHeaderHandle(), Loc, MI->getDefinitionLoc(), II,
981 Unexpanded, Expanded, PPTracker.getCurrentInclusionPathHandle());
982}
983
984void PreprocessorCallbacks::Defined(const clang::Token &MacroNameTok,
985 const clang::MacroDirective *MD,
986 clang::SourceRange Range) {
987 clang::SourceLocation Loc(Range.getBegin());
988 clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
989 const clang::MacroInfo *MI = PP.getMacroInfo(II);
990 std::string MacroName = II->getName().str();
991 std::string Unexpanded(getSourceString(PP, Range));
992 PPTracker.addMacroExpansionInstance(
993 PP, PPTracker.getCurrentHeaderHandle(), Loc,
994 (MI ? MI->getDefinitionLoc() : Loc), II, Unexpanded,
995 (MI ? "true" : "false"), PPTracker.getCurrentInclusionPathHandle());
996}
997
998void PreprocessorCallbacks::If(clang::SourceLocation Loc,
999 clang::SourceRange ConditionRange,
1000 bool ConditionResult) {
1001 std::string Unexpanded(getSourceString(PP, ConditionRange));
1002 PPTracker.addConditionalExpansionInstance(
1003 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_if,
1004 ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
1005}
1006
1007void PreprocessorCallbacks::Elif(clang::SourceLocation Loc,
1008 clang::SourceRange ConditionRange,
1009 bool ConditionResult,
1010 clang::SourceLocation IfLoc) {
1011 std::string Unexpanded(getSourceString(PP, ConditionRange));
1012 PPTracker.addConditionalExpansionInstance(
1013 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_elif,
1014 ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
1015}
1016
1017void PreprocessorCallbacks::Ifdef(clang::SourceLocation Loc,
1018 const clang::Token &MacroNameTok,
1019 const clang::MacroDirective *MD) {
1020 bool IsDefined = (MD != 0);
1021 PPTracker.addConditionalExpansionInstance(
1022 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifdef,
1023 IsDefined, PP.getSpelling(MacroNameTok),
1024 PPTracker.getCurrentInclusionPathHandle());
1025}
1026
1027void PreprocessorCallbacks::Ifndef(clang::SourceLocation Loc,
1028 const clang::Token &MacroNameTok,
1029 const clang::MacroDirective *MD) {
1030 bool IsNotDefined = (MD == 0);
1031 PPTracker.addConditionalExpansionInstance(
1032 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifndef,
1033 IsNotDefined, PP.getSpelling(MacroNameTok),
1034 PPTracker.getCurrentInclusionPathHandle());
1035}
1036} // end namespace Modularize