blob: 3fbbc459dd6dc033689aadfd2fe96582ad969345 [file] [log] [blame]
John Thompson94faa4d2013-07-26 23:56:42 +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// The Basic Idea
9//
10// Basically we install a PPCallbacks-derived object to track preprocessor
11// activity, namely when a header file is entered/exited, when a macro
12// is expanded, when “defined” is used, and when #if, #elif, #ifdef,
13// and #ifndef are used. We save the state of macro and “defined”
14// expressions in a map, keyed on a name/file/line/column quadruple.
15// The map entries store the different states (values) a macro expansion,
16// “defined” expression, or condition expression has in the course of
17// processing for the one location in the one header containing it,
18// plus a list of the nested include stacks for the states. When a macro
19// or “defined” expression evaluates to the same value, which is the
20// desired case, only one state is stored. Similarly, for conditional
21// directives, we save the condition expression states in a separate map.
22//
23// This information is collected as modularize compiles all the headers
24// given to it to process. After all the compilations are performed,
25// a check is performed for any entries in the map that contain more
26// than one different state, and an output message is generated, such
27// as the one shown previously.
28//
29// Design and Implementation Details
30//
31// A PreprocessorTrackerImpl class implements the PreprocessorTracker
32// interface. It uses a PreprocessorCallbacks class derived from PPCallbacks
33// to track preprocessor activity, namely entering/exiting a header, macro
34// expansions, use of “defined” expressions, and #if, #elif, #ifdef, and
35// #ifndef conditional directives. PreprocessorTrackerImpl stores a map
36// of MacroExpansionTracker objects keyed on a name/file/line/column
37// value represented by a light-weight PPItemKey value object. This
38// is the key top-level data structure tracking the values of macro
39// expansion instances. Similarly, it stores a map of ConditionalTracker
40// objects with the same kind of key, for tracking preprocessor conditional
41// directives.
42//
43// The MacroExpansionTracker object represents one macro reference or use
44// of a “defined” expression in a header file. It stores a handle to a
45// string representing the unexpanded macro instance, a handle to a string
46// representing the unpreprocessed source line containing the unexpanded
47// macro instance, and a vector of one or more MacroExpansionInstance
48// objects.
49//
50// The MacroExpansionInstance object represents one or more expansions
51// of a macro reference, for the case where the macro expands to the same
52// value. MacroExpansionInstance stores a handle to a string representing
53// the expanded macro value, a PPItemKey representing the file/line/column
54// where the macro was defined, a handle to a string representing the source
55// line containing the macro definition, and a vector of InclusionPathHandle
56// values that represents the hierarchies of include files for each case
57// where the particular header containing the macro reference was referenced
58// or included.
59
60// In the normal case where a macro instance always expands to the same
61// value, the MacroExpansionTracker object will only contain one
62// MacroExpansionInstance representing all the macro expansion instances.
63// If a case was encountered where a macro instance expands to a value
64// that is different from that seen before, or the macro was defined in
65// a different place, a new MacroExpansionInstance object representing
66// that case will be added to the vector in MacroExpansionTracker. If a
67// macro instance expands to a value already seen before, the
68// InclusionPathHandle representing that case’s include file hierarchy
69// will be added to the existing MacroExpansionInstance object.
70
71// For checking conditional directives, the ConditionalTracker class
72// functions similarly to MacroExpansionTracker, but tracks an #if,
73// #elif, #ifdef, or #ifndef directive in a header file. It stores
74// a vector of one or two ConditionalExpansionInstance objects,
75// representing the cases where the conditional expression evaluates
76// to true or false. This latter object stores the evaluated value
77// of the condition expression (a bool) and a vector of
78// InclusionPathHandles.
79//
80// To reduce the instances of string and object copying, the
81// PreprocessorTrackerImpl class uses a StringPool to save all stored
82// strings, and defines a StringHandle type to abstract the references
83// to the strings.
84//
85// PreprocessorTrackerImpl also maintains a list representing the unique
86// headers, which is just a vector of StringHandles for the header file
87// paths. A HeaderHandle abstracts a reference to a header, and is simply
88// the index of the stored header file path.
89//
90// A HeaderInclusionPath class abstract a unique hierarchy of header file
91// inclusions. It simply stores a vector of HeaderHandles ordered from the
92// top-most header (the one from the header list passed to modularize) down
93// to the header containing the macro reference. PreprocessorTrackerImpl
94// stores a vector of these objects. An InclusionPathHandle typedef
95// abstracts a reference to one of the HeaderInclusionPath objects, and is
96// simply the index of the stored HeaderInclusionPath object. The
97// MacroExpansionInstance object stores a vector of these handle so that
98// the reporting function can display the include hierarchies for the macro
99// expansion instances represented by that object, to help the user
100// understand how the header was included. (A future enhancement might
101// be to associate a line number for the #include directives, but I
102// think not doing so is good enough for the present.)
103//
104// A key reason for using these opaque handles was to try to keep all the
105// internal objects light-weight value objects, in order to reduce string
106// and object copying overhead, and to abstract this implementation detail.
107//
108// The key data structures are built up while modularize runs the headers
109// through the compilation. A PreprocessorTracker instance is created and
110// passed down to the AST action and consumer objects in modularize. For
111// each new compilation instance, the consumer calls the
112// PreprocessorTracker’s handleNewPreprocessorEntry function, which sets
113// up a PreprocessorCallbacks object for the preprocessor. At the end of
114// the compilation instance, the PreprocessorTracker’s
115// handleNewPreprocessorExit function handles cleaning up with respect
116// to the preprocessing instance.
117//
118// The PreprocessorCallbacks object uses an overidden FileChanged callback
119// to determine when a header is entered and exited (including exiting the
120// header during #include directives). It calls PreprocessorTracker’s
121// handleHeaderEntry and handleHeaderExit functions upon entering and
122// exiting a header. These functions manage a stack of header handles
123// representing by a vector, pushing and popping header handles as headers
124// are entered and exited. When a HeaderInclusionPath object is created,
125// it simply copies this stack.
126//
127// The PreprocessorCallbacks object uses an overridden MacroExpands callback
128// to track when a macro expansion is performed. It calls a couple of helper
129// functions to get the unexpanded and expanded macro values as strings, but
130// then calls PreprocessorTrackerImpl’s addMacroExpansionInstance function to
131// do the rest of the work. The getMacroExpandedString function uses the
132// preprocessor’s getSpelling to convert tokens to strings using the
133// information passed to the MacroExpands callback, and simply concatenates
134// them. It makes recursive calls to itself to handle nested macro
135// definitions, and also handles function-style macros.
136//
137// PreprocessorTrackerImpl’s addMacroExpansionInstance function looks for
138// an existing MacroExpansionTracker entry in its map of MacroExampleTracker
139// objects. If none exists, it adds one with one MacroExpansionInstance and
140// returns. If a MacroExpansionTracker object already exists, it looks for
141// an existing MacroExpansionInstance object stored in the
142// MacroExpansionTracker object, one that matches the macro expanded value
143// and the macro definition location. If a matching MacroExpansionInstance
144// object is found, it just adds the current HeaderInclusionPath object to
145// it. If not found, it creates and stores a new MacroExpantionInstance
146// object. The addMacroExpansionInstance function calls a couple of helper
147// functions to get the pre-formatted location and source line strings for
148// the macro reference and the macro definition stored as string handles.
149// These helper functions use the current source manager from the
150// preprocessor. This is done in advance at this point in time because the
151// source manager doesn’t exist at the time of the reporting.
152//
153// For conditional check, the PreprocessorCallbacks class overrides the
154// PPCallbacks handlers for #if, #elif, #ifdef, and #ifndef. These handlers
155// call the addConditionalExpansionInstance method of
156// PreprocessorTrackerImpl. The process is similar to that of macros, but
157// with some different data and error messages. A lookup is performed for
158// the conditional, and if a ConditionalTracker object doesn’t yet exist for
159// the conditional, a new one is added, including adding a
160// ConditionalExpansionInstance object to it to represent the condition
161// expression state. If a ConditionalTracker for the conditional does
162// exist, a lookup is made for a ConditionalExpansionInstance object
163// matching the condition expression state. If one exists, a
164// HeaderInclusionPath is added to it. Otherwise a new
165// ConditionalExpansionInstance entry is made. If a ConditionalTracker
166// has two ConditionalExpansionInstance objects, it means there was a
167// conflict, meaning the conditional expression evaluated differently in
168// one or more cases.
169//
170// After modularize has performed all the compilations, it enters a phase
171// of error reporting. This new feature adds to this reporting phase calls
172// to the PreprocessorTracker’s reportInconsistentMacros and
173// reportInconsistentConditionals functions. These functions walk the maps
174// of MacroExpansionTracker’s and ConditionalTracker’s respectively. If
175// any of these objects have more than one MacroExpansionInstance or
176// ConditionalExpansionInstance objects, it formats and outputs an error
177// message like the example shown previously, using the stored data.
178//
179// A potential issue is that there is some overlap between the #if/#elif
180// conditional and macro reporting. I could disable the #if and #elif,
181// leaving just the #ifdef and #ifndef, since these don’t overlap. Or,
182// to make clearer the separate reporting phases, I could add an output
183// message marking the phases.
184//
185// Future Directions
186//
187// We probably should add options to disable any of the checks, in case
188// there is some problem with them, or the messages get too verbose.
189//
190// With the map of all the macro and conditional expansion instances,
191// it might be possible to add to the existing modularize error messages
192// (the second part referring to definitions being different), attempting
193// to tie them to the last macro conflict encountered with respect to the
194// order of the code encountered.
195//
196//===--------------------------------------------------------------------===//
197
198#include "clang/Lex/LexDiagnostic.h"
199#include "clang/Lex/MacroArgs.h"
200#include "clang/Lex/PPCallbacks.h"
201#include "llvm/Support/raw_ostream.h"
202#include "llvm/Support/StringPool.h"
203#include "PreprocessorTracker.h"
204
205namespace Modularize {
206
207// Forwards.
208class PreprocessorTrackerImpl;
209
210// Some handle types
211typedef llvm::PooledStringPtr StringHandle;
212
213typedef int HeaderHandle;
214const HeaderHandle HeaderHandleInvalid = -1;
215
216typedef int InclusionPathHandle;
217const InclusionPathHandle InclusionPathHandleInvalid = -1;
218
219// Some utility functions.
220
221// Get a "file:line:column" source location string.
222static std::string getSourceLocationString(clang::Preprocessor &PP,
223 clang::SourceLocation Loc) {
224 if (Loc.isInvalid())
225 return std::string("(none)");
226 else
227 return Loc.printToString(PP.getSourceManager());
228}
229
230// Get just the file name from a source location.
231static std::string getSourceLocationFile(clang::Preprocessor &PP,
232 clang::SourceLocation Loc) {
233 std::string Source(getSourceLocationString(PP, Loc));
234 size_t Offset = Source.find(':', 2);
235 if (Offset == std::string::npos)
236 return Source;
237 return Source.substr(0, Offset);
238}
239
240// Get just the line and column from a source location.
241static void getSourceLocationLineAndColumn(clang::Preprocessor &PP,
242 clang::SourceLocation Loc, int &Line,
243 int &Column) {
244 clang::PresumedLoc PLoc = PP.getSourceManager().getPresumedLoc(Loc);
245 if (PLoc.isInvalid()) {
246 Line = 0;
247 Column = 0;
248 return;
249 }
250 Line = PLoc.getLine();
251 Column = PLoc.getColumn();
252}
253
254// Retrieve source snippet from file image.
255std::string getSourceString(clang::Preprocessor &PP, clang::SourceRange Range) {
256 clang::SourceLocation BeginLoc = Range.getBegin();
257 clang::SourceLocation EndLoc = Range.getEnd();
258 const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
259 const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc);
260 size_t Length = EndPtr - BeginPtr;
261 return llvm::StringRef(BeginPtr, Length).trim().str();
262}
263
264// Retrieve source line from file image.
265std::string getSourceLine(clang::Preprocessor &PP, clang::SourceLocation Loc) {
266 const llvm::MemoryBuffer *MemBuffer =
267 PP.getSourceManager().getBuffer(PP.getSourceManager().getFileID(Loc));
268 const char *Buffer = MemBuffer->getBufferStart();
269 const char *BufferEnd = MemBuffer->getBufferEnd();
270 const char *BeginPtr = PP.getSourceManager().getCharacterData(Loc);
271 const char *EndPtr = BeginPtr;
272 while (BeginPtr > Buffer) {
273 if (*BeginPtr == '\n') {
274 BeginPtr++;
275 break;
276 }
277 BeginPtr--;
278 }
279 while (EndPtr < BufferEnd) {
280 if (*EndPtr == '\n') {
281 break;
282 }
283 EndPtr++;
284 }
285 size_t Length = EndPtr - BeginPtr;
286 return llvm::StringRef(BeginPtr, Length).str();
287}
288
289// Get the string for the Unexpanded macro instance.
290// The soureRange is expected to end at the last token
291// for the macro instance, which in the case of a function-style
292// macro will be a ')', but for an object-style macro, it
293// will be the macro name itself.
294std::string getMacroUnexpandedString(clang::SourceRange Range,
295 clang::Preprocessor &PP,
296 llvm::StringRef MacroName,
297 const clang::MacroInfo *MI) {
298 clang::SourceLocation BeginLoc(Range.getBegin());
299 const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
300 size_t Length;
301 std::string Unexpanded;
302 if (MI->isFunctionLike()) {
303 clang::SourceLocation EndLoc(Range.getEnd());
304 const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc) + 1;
305 Length = (EndPtr - BeginPtr) + 1; // +1 is ')' width.
306 } else
307 Length = MacroName.size();
308 return llvm::StringRef(BeginPtr, Length).trim().str();
309}
310
311// Get the expansion for a macro instance, given the information
312// provided by PPCallbacks.
313std::string getMacroExpandedString(clang::Preprocessor &PP,
314 llvm::StringRef MacroName,
315 const clang::MacroInfo *MI,
316 const clang::MacroArgs *Args) {
317 std::string Expanded;
318 // Walk over the macro Tokens.
319 typedef clang::MacroInfo::tokens_iterator Iter;
320 for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
321 clang::IdentifierInfo *II = I->getIdentifierInfo();
322 int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
323 if (ArgNo == -1) {
324 // This isn't an argument, just add it.
325 if (II == NULL)
326 Expanded += PP.getSpelling((*I)); // Not an identifier.
327 else {
328 // Token is for an identifier.
329 std::string Name = II->getName().str();
330 // Check for nexted macro references.
331 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
332 if (MacroInfo != NULL)
333 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
334 else
335 Expanded += Name;
336 }
337 continue;
338 }
339 // We get here if it's a function-style macro with arguments.
340 const clang::Token *ResultArgToks;
341 const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
342 if (Args->ArgNeedsPreexpansion(ArgTok, PP))
343 ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
344 ->getPreExpArgument(ArgNo, MI, PP)[0];
345 else
346 ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
347 // If the arg token didn't expand into anything, ignore it.
348 if (ResultArgToks->is(clang::tok::eof))
349 continue;
350 unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
351 // Append the resulting argument expansions.
352 for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
353 const clang::Token &AT = ResultArgToks[ArgumentIndex];
354 clang::IdentifierInfo *II = AT.getIdentifierInfo();
355 if (II == NULL)
356 Expanded += PP.getSpelling(AT); // Not an identifier.
357 else {
358 // It's an identifier. Check for further expansion.
359 std::string Name = II->getName().str();
360 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
361 if (MacroInfo != NULL)
362 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
363 else
364 Expanded += Name;
365 }
366 }
367 }
368 return Expanded;
369}
370
371// Get the string representing a vector of Tokens.
372std::string
373getTokensSpellingString(clang::Preprocessor &PP,
374 llvm::SmallVectorImpl<clang::Token> &Tokens) {
375 std::string Expanded;
376 // Walk over the macro Tokens.
377 typedef llvm::SmallVectorImpl<clang::Token>::iterator Iter;
378 for (Iter I = Tokens.begin(), E = Tokens.end(); I != E; ++I)
379 Expanded += PP.getSpelling(*I); // Not an identifier.
380 return llvm::StringRef(Expanded).trim().str();
381}
382
383// Get the expansion for a macro instance, given the information
384// provided by PPCallbacks.
385std::string getExpandedString(clang::Preprocessor &PP,
386 llvm::StringRef MacroName,
387 const clang::MacroInfo *MI,
388 const clang::MacroArgs *Args) {
389 std::string Expanded;
390 // Walk over the macro Tokens.
391 typedef clang::MacroInfo::tokens_iterator Iter;
392 for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
393 clang::IdentifierInfo *II = I->getIdentifierInfo();
394 int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
395 if (ArgNo == -1) {
396 // This isn't an argument, just add it.
397 if (II == NULL)
398 Expanded += PP.getSpelling((*I)); // Not an identifier.
399 else {
400 // Token is for an identifier.
401 std::string Name = II->getName().str();
402 // Check for nexted macro references.
403 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
404 if (MacroInfo != NULL)
405 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
406 else
407 Expanded += Name;
408 }
409 continue;
410 }
411 // We get here if it's a function-style macro with arguments.
412 const clang::Token *ResultArgToks;
413 const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
414 if (Args->ArgNeedsPreexpansion(ArgTok, PP))
415 ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
416 ->getPreExpArgument(ArgNo, MI, PP)[0];
417 else
418 ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
419 // If the arg token didn't expand into anything, ignore it.
420 if (ResultArgToks->is(clang::tok::eof))
421 continue;
422 unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
423 // Append the resulting argument expansions.
424 for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
425 const clang::Token &AT = ResultArgToks[ArgumentIndex];
426 clang::IdentifierInfo *II = AT.getIdentifierInfo();
427 if (II == NULL)
428 Expanded += PP.getSpelling(AT); // Not an identifier.
429 else {
430 // It's an identifier. Check for further expansion.
431 std::string Name = II->getName().str();
432 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
433 if (MacroInfo != NULL)
434 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
435 else
436 Expanded += Name;
437 }
438 }
439 }
440 return Expanded;
441}
442
443// We need some operator overloads for string handles.
444bool operator==(const StringHandle &H1, const StringHandle &H2) {
445 const char *S1 = (H1 ? *H1 : "");
446 const char *S2 = (H2 ? *H2 : "");
447 int Diff = strcmp(S1, S2);
448 return Diff == 0;
449}
450bool operator!=(const StringHandle &H1, const StringHandle &H2) {
451 const char *S1 = (H1 ? *H1 : "");
452 const char *S2 = (H2 ? *H2 : "");
453 int Diff = strcmp(S1, S2);
454 return Diff != 0;
455}
456bool operator<(const StringHandle &H1, const StringHandle &H2) {
457 const char *S1 = (H1 ? *H1 : "");
458 const char *S2 = (H2 ? *H2 : "");
459 int Diff = strcmp(S1, S2);
460 return Diff < 0;
461}
462bool operator>(const StringHandle &H1, const StringHandle &H2) {
463 const char *S1 = (H1 ? *H1 : "");
464 const char *S2 = (H2 ? *H2 : "");
465 int Diff = strcmp(S1, S2);
466 return Diff > 0;
467}
468
469// Preprocessor item key.
470//
471// This class represents a location in a source file, for use
472// as a key representing a unique name/file/line/column quadruplet,
473// which in this case is used to identify a macro expansion instance,
474// but could be used for other things as well.
475// The file is a header file handle, the line is a line number,
476// and the column is a column number.
477class PPItemKey {
478public:
479 PPItemKey(clang::Preprocessor &PP, StringHandle Name, HeaderHandle File,
480 clang::SourceLocation Loc)
481 : Name(Name), File(File) {
482 getSourceLocationLineAndColumn(PP, Loc, Line, Column);
483 }
484 PPItemKey(StringHandle Name, HeaderHandle File, int Line, int Column)
485 : Name(Name), File(File), Line(Line), Column(Column) {}
486 PPItemKey(const PPItemKey &Other)
487 : Name(Other.Name), File(Other.File), Line(Other.Line),
488 Column(Other.Column) {}
489 PPItemKey() : File(HeaderHandleInvalid), Line(0), Column(0) {}
490 bool operator==(const PPItemKey &Other) const {
491 if (Name != Other.Name)
492 return false;
493 if (File != Other.File)
494 return false;
495 if (Line != Other.Line)
496 return false;
497 return Column == Other.Column;
498 }
499 bool operator<(const PPItemKey &Other) const {
500 if (Name < Other.Name)
501 return true;
502 else if (Name > Other.Name)
503 return false;
504 if (File < Other.File)
505 return true;
506 else if (File > Other.File)
507 return false;
508 if (Line < Other.Line)
509 return true;
510 else if (Line > Other.Line)
511 return false;
512 return Column < Other.Column;
513 }
514 StringHandle Name;
515 HeaderHandle File;
516 int Line;
517 int Column;
518};
519
520// Header inclusion path.
521class HeaderInclusionPath {
522public:
523 HeaderInclusionPath(std::vector<HeaderHandle> HeaderInclusionPath)
524 : Path(HeaderInclusionPath) {}
525 HeaderInclusionPath(const HeaderInclusionPath &Other) : Path(Other.Path) {}
526 HeaderInclusionPath() {}
527 std::vector<HeaderHandle> Path;
528};
529
530// Macro expansion instance.
531//
532// This class represents an instance of a macro expansion with a
533// unique value. It also stores the unique header inclusion paths
534// for use in telling the user the nested include path f
535class MacroExpansionInstance {
536public:
537 MacroExpansionInstance(StringHandle MacroExpanded,
538 PPItemKey &DefinitionLocation,
539 StringHandle DefinitionSourceLine,
540 InclusionPathHandle H)
541 : MacroExpanded(MacroExpanded), DefinitionLocation(DefinitionLocation),
542 DefinitionSourceLine(DefinitionSourceLine) {
543 InclusionPathHandles.push_back(H);
544 }
545 MacroExpansionInstance() {}
546
547 // Check for the presence of a header inclusion path handle entry.
548 // Return false if not found.
549 bool haveInclusionPathHandle(InclusionPathHandle H) {
550 for (std::vector<InclusionPathHandle>::iterator
551 I = InclusionPathHandles.begin(),
552 E = InclusionPathHandles.end();
553 I != E; ++I) {
554 if (*I == H)
555 return true;
556 }
557 return InclusionPathHandleInvalid;
558 }
559 // Add a new header inclusion path entry, if not already present.
560 void addInclusionPathHandle(InclusionPathHandle H) {
561 if (!haveInclusionPathHandle(H))
562 InclusionPathHandles.push_back(H);
563 }
564
565 // A string representing the macro instance after preprocessing.
566 StringHandle MacroExpanded;
567 // A file/line/column triplet representing the macro definition location.
568 PPItemKey DefinitionLocation;
569 // A place to save the macro definition line string.
570 StringHandle DefinitionSourceLine;
571 // The header inclusion path handles for all the instances.
572 std::vector<InclusionPathHandle> InclusionPathHandles;
573};
574
575// Macro expansion instance tracker.
576//
577// This class represents one macro expansion, keyed by a PPItemKey.
578// It stores a string representing the macro reference in the source,
579// and a list of ConditionalExpansionInstances objects representing
580// the unique value the condition expands to in instances of the header.
581class MacroExpansionTracker {
582public:
583 MacroExpansionTracker(StringHandle MacroUnexpanded,
584 StringHandle MacroExpanded,
585 StringHandle InstanceSourceLine,
586 PPItemKey &DefinitionLocation,
587 StringHandle DefinitionSourceLine,
588 InclusionPathHandle InclusionPathHandle)
589 : MacroUnexpanded(MacroUnexpanded),
590 InstanceSourceLine(InstanceSourceLine) {
591 addMacroExpansionInstance(MacroExpanded, DefinitionLocation,
592 DefinitionSourceLine, InclusionPathHandle);
593 }
594 MacroExpansionTracker() {}
595
596 // Find a matching macro expansion instance.
597 MacroExpansionInstance *
598 findMacroExpansionInstance(StringHandle MacroExpanded,
599 PPItemKey &DefinitionLocation) {
600 for (std::vector<MacroExpansionInstance>::iterator
601 I = MacroExpansionInstances.begin(),
602 E = MacroExpansionInstances.end();
603 I != E; ++I) {
604 if ((I->MacroExpanded == MacroExpanded) &&
605 (I->DefinitionLocation == DefinitionLocation)) {
606 return &*I; // Found.
607 }
608 }
609 return NULL; // Not found.
610 }
611
612 // Add a macro expansion instance.
613 void addMacroExpansionInstance(StringHandle MacroExpanded,
614 PPItemKey &DefinitionLocation,
615 StringHandle DefinitionSourceLine,
616 InclusionPathHandle InclusionPathHandle) {
617 MacroExpansionInstances.push_back(
618 MacroExpansionInstance(MacroExpanded, DefinitionLocation,
619 DefinitionSourceLine, InclusionPathHandle));
620 }
621
622 // Return true if there is a mismatch.
623 bool hasMismatch() { return MacroExpansionInstances.size() > 1; }
624
625 // A string representing the macro instance without expansion.
626 StringHandle MacroUnexpanded;
627 // A place to save the macro instance source line string.
628 StringHandle InstanceSourceLine;
629 // The macro expansion instances.
630 // If all instances of the macro expansion expand to the same value,
631 // This vector will only have one instance.
632 std::vector<MacroExpansionInstance> MacroExpansionInstances;
633};
634
635// Conditional expansion instance.
636//
637// This class represents an instance of a macro expansion with a
638// unique value. It also stores the unique header inclusion paths
639// for use in telling the user the nested include path f
640class ConditionalExpansionInstance {
641public:
642 ConditionalExpansionInstance(bool ConditionValue, InclusionPathHandle H)
643 : ConditionValue(ConditionValue) {
644 InclusionPathHandles.push_back(H);
645 }
646 ConditionalExpansionInstance() {}
647
648 // Check for the presence of a header inclusion path handle entry.
649 // Return false if not found.
650 bool haveInclusionPathHandle(InclusionPathHandle H) {
651 for (std::vector<InclusionPathHandle>::iterator
652 I = InclusionPathHandles.begin(),
653 E = InclusionPathHandles.end();
654 I != E; ++I) {
655 if (*I == H)
656 return true;
657 }
658 return InclusionPathHandleInvalid;
659 }
660 // Add a new header inclusion path entry, if not already present.
661 void addInclusionPathHandle(InclusionPathHandle H) {
662 if (!haveInclusionPathHandle(H))
663 InclusionPathHandles.push_back(H);
664 }
665
666 // A flag representing the evaluated condition value.
667 bool ConditionValue;
668 // The header inclusion path handles for all the instances.
669 std::vector<InclusionPathHandle> InclusionPathHandles;
670};
671
672// Conditional directive instance tracker.
673//
674// This class represents one conditional directive, keyed by a PPItemKey.
675// It stores a string representing the macro reference in the source,
676// and a list of MacroExpansionInstance objects representing
677// the unique value the macro expands to in instances of the header.
678class ConditionalTracker {
679public:
680 ConditionalTracker(clang::tok::PPKeywordKind DirectiveKind,
681 bool ConditionValue, StringHandle ConditionUnexpanded,
682 InclusionPathHandle InclusionPathHandle)
683 : DirectiveKind(DirectiveKind), ConditionUnexpanded(ConditionUnexpanded) {
684 addConditionalExpansionInstance(ConditionValue, InclusionPathHandle);
685 }
686 ConditionalTracker() {}
687
688 // Find a matching condition expansion instance.
689 ConditionalExpansionInstance *
690 findConditionalExpansionInstance(bool ConditionValue) {
691 for (std::vector<ConditionalExpansionInstance>::iterator
692 I = ConditionalExpansionInstances.begin(),
693 E = ConditionalExpansionInstances.end();
694 I != E; ++I) {
695 if (I->ConditionValue == ConditionValue) {
696 return &*I; // Found.
697 }
698 }
699 return NULL; // Not found.
700 }
701
702 // Add a conditional expansion instance.
703 void
704 addConditionalExpansionInstance(bool ConditionValue,
705 InclusionPathHandle InclusionPathHandle) {
706 ConditionalExpansionInstances.push_back(
707 ConditionalExpansionInstance(ConditionValue, InclusionPathHandle));
708 }
709
710 // Return true if there is a mismatch.
711 bool hasMismatch() { return ConditionalExpansionInstances.size() > 1; }
712
713 // The kind of directive.
714 clang::tok::PPKeywordKind DirectiveKind;
715 // A string representing the macro instance without expansion.
716 StringHandle ConditionUnexpanded;
717 // The condition expansion instances.
718 // If all instances of the conditional expression expand to the same value,
719 // This vector will only have one instance.
720 std::vector<ConditionalExpansionInstance> ConditionalExpansionInstances;
721};
722
723// Preprocessor callbacks for modularize.
724//
725// This class derives from the Clang PPCallbacks class to track preprocessor
726// actions, such as changing files and handling preprocessor directives and
727// macro expansions. It has to figure out when a new header file is entered
728// and left, as the provided handler is not particularly clear about it.
729class PreprocessorCallbacks : public clang::PPCallbacks {
730public:
731 PreprocessorCallbacks(PreprocessorTrackerImpl &ppTracker,
732 clang::Preprocessor &PP, llvm::StringRef rootHeaderFile)
733 : PPTracker(ppTracker), PP(PP), RootHeaderFile(rootHeaderFile) {}
734 ~PreprocessorCallbacks() {}
735
736 // Overridden handlers.
737 void FileChanged(clang::SourceLocation Loc,
738 clang::PPCallbacks::FileChangeReason Reason,
739 clang::SrcMgr::CharacteristicKind FileType,
740 clang::FileID PrevFID = clang::FileID());
741 void MacroExpands(const clang::Token &MacroNameTok,
742 const clang::MacroDirective *MD, clang::SourceRange Range,
743 const clang::MacroArgs *Args);
744 void Defined(const clang::Token &MacroNameTok,
745 const clang::MacroDirective *MD, clang::SourceRange Range);
746 void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
747 bool ConditionResult);
748 void Elif(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
749 bool ConditionResult, clang::SourceLocation IfLoc);
750 void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
751 const clang::MacroDirective *MD);
752 void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
753 const clang::MacroDirective *MD);
754
755private:
756 PreprocessorTrackerImpl &PPTracker;
757 clang::Preprocessor &PP;
758 std::string RootHeaderFile;
759};
760
761// Preprocessor macro expansion item map types.
762typedef std::map<PPItemKey, MacroExpansionTracker> MacroExpansionMap;
763typedef std::map<PPItemKey, MacroExpansionTracker>::iterator
764MacroExpansionMapIter;
765
766// Preprocessor conditional expansion item map types.
767typedef std::map<PPItemKey, ConditionalTracker> ConditionalExpansionMap;
768typedef std::map<PPItemKey, ConditionalTracker>::iterator
769ConditionalExpansionMapIter;
770
771// Preprocessor tracker for modularize.
772//
773// This class stores information about all the headers processed in the
774// course of running modularize.
775class PreprocessorTrackerImpl : public PreprocessorTracker {
776public:
777 PreprocessorTrackerImpl()
778 : CurrentInclusionPathHandle(InclusionPathHandleInvalid) {}
779 ~PreprocessorTrackerImpl() {}
780
781 // Handle entering a preprocessing session.
782 void handlePreprocessorEntry(clang::Preprocessor &PP,
783 llvm::StringRef rootHeaderFile) {
784 assert((HeaderStack.size() == 0) && "Header stack should be empty.");
785 pushHeaderHandle(addHeader(rootHeaderFile));
786 PP.addPPCallbacks(new PreprocessorCallbacks(*this, PP, rootHeaderFile));
787 }
788 // Handle exiting a preprocessing session.
789 void handlePreprocessorExit() { HeaderStack.clear(); }
790
791 // Handle entering a header source file.
792 void handleHeaderEntry(clang::Preprocessor &PP, llvm::StringRef HeaderPath) {
793 // Ignore <built-in> and <command-line> to reduce message clutter.
794 if (HeaderPath.startswith("<"))
795 return;
796 HeaderHandle H = addHeader(HeaderPath);
797 if (H != getCurrentHeaderHandle())
798 pushHeaderHandle(H);
799 }
800 // Handle exiting a header source file.
801 void handleHeaderExit(llvm::StringRef HeaderPath) {
802 // Ignore <built-in> and <command-line> to reduce message clutter.
803 if (HeaderPath.startswith("<"))
804 return;
805 HeaderHandle H = findHeaderHandle(HeaderPath);
806 if (isHeaderHandleInStack(H)) {
807 while ((H != getCurrentHeaderHandle()) && (HeaderStack.size() != 0))
808 popHeaderHandle();
809 }
810 }
811
812 // Lookup/add string.
813 StringHandle addString(llvm::StringRef Str) { return Strings.intern(Str); }
814
815 // Get the handle of a header file entry.
816 // Return HeaderHandleInvalid if not found.
817 HeaderHandle findHeaderHandle(llvm::StringRef HeaderPath) const {
818 HeaderHandle H = 0;
819 for (std::vector<StringHandle>::const_iterator I = HeaderPaths.begin(),
820 E = HeaderPaths.end();
821 I != E; ++I, ++H) {
822 if (**I == HeaderPath)
823 return H;
824 }
825 return HeaderHandleInvalid;
826 }
827
828 // Add a new header file entry, or return existing handle.
829 // Return the header handle.
830 HeaderHandle addHeader(llvm::StringRef HeaderPath) {
831 std::string canonicalPath(HeaderPath);
832 std::replace(canonicalPath.begin(), canonicalPath.end(), '\\', '/');
833 HeaderHandle H = findHeaderHandle(canonicalPath);
834 if (H == HeaderHandleInvalid) {
835 H = HeaderPaths.size();
836 HeaderPaths.push_back(addString(canonicalPath));
837 }
838 return H;
839 }
840
841 // Return a header file path string given its handle.
842 StringHandle getHeaderFilePath(HeaderHandle H) const {
843 if ((H >= 0) && (H < (HeaderHandle)HeaderPaths.size()))
844 return HeaderPaths[H];
845 return StringHandle();
846 }
847
848 // Returns a handle to the inclusion path.
849 InclusionPathHandle pushHeaderHandle(HeaderHandle H) {
850 HeaderStack.push_back(H);
851 return CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
852 }
853 // Pops the last header handle from the stack;
854 void popHeaderHandle() {
855 // assert((HeaderStack.size() != 0) && "Header stack already empty.");
856 if (HeaderStack.size() != 0) {
857 HeaderStack.pop_back();
858 CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
859 }
860 }
861 // Get the top handle on the header stack.
862 HeaderHandle getCurrentHeaderHandle() const {
863 if (HeaderStack.size() != 0)
864 return HeaderStack.back();
865 return HeaderHandleInvalid;
866 }
867
868 // Check for presence of header handle in the header stack.
869 bool isHeaderHandleInStack(HeaderHandle H) const {
870 for (std::vector<HeaderHandle>::const_iterator I = HeaderStack.begin(),
871 E = HeaderStack.end();
872 I != E; ++I) {
873 if (*I == H)
874 return true;
875 }
876 return false;
877 }
878
879 // Get the handle of a header inclusion path entry.
880 // Return InclusionPathHandleInvalid if not found.
881 InclusionPathHandle
882 findInclusionPathHandle(const std::vector<HeaderHandle> &Path) const {
883 InclusionPathHandle H = 0;
884 for (std::vector<HeaderInclusionPath>::const_iterator
885 I = InclusionPaths.begin(),
886 E = InclusionPaths.end();
887 I != E; ++I, ++H) {
888 if (I->Path == Path)
889 return H;
890 }
891 return HeaderHandleInvalid;
892 }
893 // Add a new header inclusion path entry, or return existing handle.
894 // Return the header inclusion path entry handle.
895 InclusionPathHandle
896 addInclusionPathHandle(const std::vector<HeaderHandle> &Path) {
897 InclusionPathHandle H = findInclusionPathHandle(Path);
898 if (H == HeaderHandleInvalid) {
899 H = InclusionPaths.size();
900 InclusionPaths.push_back(HeaderInclusionPath(Path));
901 }
902 return H;
903 }
904 // Return the current inclusion path handle.
905 InclusionPathHandle getCurrentInclusionPathHandle() const {
906 return CurrentInclusionPathHandle;
907 }
908
909 // Return an inclusion path given its handle.
910 const std::vector<HeaderHandle> &
911 getInclusionPath(InclusionPathHandle H) const {
912 if ((H >= 0) && (H <= (InclusionPathHandle)InclusionPaths.size()))
913 return InclusionPaths[H].Path;
914 static std::vector<HeaderHandle> Empty;
915 return Empty;
916 }
917
918 // Add a macro expansion instance.
919 void addMacroExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
920 clang::SourceLocation InstanceLoc,
921 clang::SourceLocation DefinitionLoc,
922 clang::IdentifierInfo *II,
923 llvm::StringRef MacroUnexpanded,
924 llvm::StringRef MacroExpanded,
925 InclusionPathHandle InclusionPathHandle) {
926 StringHandle MacroName = addString(II->getName());
927 PPItemKey InstanceKey(PP, MacroName, H, InstanceLoc);
928 PPItemKey DefinitionKey(PP, MacroName, H, DefinitionLoc);
929 MacroExpansionMapIter I = MacroExpansions.find(InstanceKey);
930 if (I == MacroExpansions.end()) {
931 std::string InstanceSourceLine =
932 getSourceLocationString(PP, InstanceLoc) + ":\n" +
933 getSourceLine(PP, InstanceLoc) + "\n";
934 std::string DefinitionSourceLine =
935 getSourceLocationString(PP, DefinitionLoc) + ":\n" +
936 getSourceLine(PP, DefinitionLoc) + "\n";
937 MacroExpansions[InstanceKey] = MacroExpansionTracker(
938 addString(MacroUnexpanded), addString(MacroExpanded),
939 addString(InstanceSourceLine), DefinitionKey,
940 addString(DefinitionSourceLine), InclusionPathHandle);
941 } else {
942 MacroExpansionTracker &CondTracker = I->second;
943 MacroExpansionInstance *MacroInfo =
944 CondTracker.findMacroExpansionInstance(addString(MacroExpanded),
945 DefinitionKey);
946 if (MacroInfo != NULL)
947 MacroInfo->addInclusionPathHandle(InclusionPathHandle);
948 else {
949 std::string DefinitionSourceLine =
950 getSourceLocationString(PP, DefinitionLoc) + ":\n" +
951 getSourceLine(PP, DefinitionLoc) + "\n";
952 CondTracker.addMacroExpansionInstance(
953 addString(MacroExpanded), DefinitionKey,
954 addString(DefinitionSourceLine), InclusionPathHandle);
955 }
956 }
957 }
958
959 // Add a conditional expansion instance.
960 void
961 addConditionalExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
962 clang::SourceLocation InstanceLoc,
963 clang::tok::PPKeywordKind DirectiveKind,
964 bool ConditionValue,
965 llvm::StringRef ConditionUnexpanded,
966 InclusionPathHandle InclusionPathHandle) {
967 StringHandle ConditionUnexpandedHandle(addString(ConditionUnexpanded));
968 PPItemKey InstanceKey(PP, ConditionUnexpandedHandle, H, InstanceLoc);
969 ConditionalExpansionMapIter I = ConditionalExpansions.find(InstanceKey);
970 if (I == ConditionalExpansions.end()) {
971 std::string InstanceSourceLine =
972 getSourceLocationString(PP, InstanceLoc) + ":\n" +
973 getSourceLine(PP, InstanceLoc) + "\n";
974 ConditionalExpansions[InstanceKey] =
975 ConditionalTracker(DirectiveKind, ConditionValue, ConditionUnexpandedHandle,
976 InclusionPathHandle);
977 } else {
978 ConditionalTracker &CondTracker = I->second;
979 ConditionalExpansionInstance *MacroInfo =
980 CondTracker.findConditionalExpansionInstance(ConditionValue);
981 if (MacroInfo != NULL)
982 MacroInfo->addInclusionPathHandle(InclusionPathHandle);
983 else {
984 CondTracker.addConditionalExpansionInstance(ConditionValue,
985 InclusionPathHandle);
986 }
987 }
988 }
989
990 // Report on inconsistent macro instances.
991 // Returns true if any mismatches.
992 bool reportInconsistentMacros(llvm::raw_ostream &OS) {
993 bool ReturnValue = false;
994 for (MacroExpansionMapIter I = MacroExpansions.begin(),
995 E = MacroExpansions.end();
996 I != E; ++I) {
997 const PPItemKey &ItemKey = I->first;
998 MacroExpansionTracker &MacroExpTracker = I->second;
999 if (!MacroExpTracker.hasMismatch())
1000 continue;
1001 ReturnValue = true;
1002 OS << *MacroExpTracker.InstanceSourceLine;
1003 if (ItemKey.Column > 0)
1004 OS << std::string(ItemKey.Column - 1, ' ') << "^\n";
1005 OS << "error: Macro instance '" << *MacroExpTracker.MacroUnexpanded
1006 << "' has different values in this header, depending on how it was "
1007 "included.\n";
1008 for (std::vector<MacroExpansionInstance>::iterator
1009 IMT = MacroExpTracker.MacroExpansionInstances.begin(),
1010 EMT = MacroExpTracker.MacroExpansionInstances.end();
1011 IMT != EMT; ++IMT) {
1012 MacroExpansionInstance &MacroInfo = *IMT;
1013 OS << " '" << *MacroExpTracker.MacroUnexpanded << "' expanded to: '"
1014 << *MacroInfo.MacroExpanded
1015 << "' with respect to these inclusion paths:\n";
1016 for (std::vector<InclusionPathHandle>::iterator
1017 IIP = MacroInfo.InclusionPathHandles.begin(),
1018 EIP = MacroInfo.InclusionPathHandles.end();
1019 IIP != EIP; ++IIP) {
1020 const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
1021 int Count = (int)ip.size();
1022 for (int Index = 0; Index < Count; ++Index) {
1023 HeaderHandle H = ip[Index];
1024 OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
1025 << "\n";
1026 }
1027 }
1028 // For a macro that wasn't defined, we flag it by using the
1029 // instance location.
1030 // If there is a definition...
1031 if (MacroInfo.DefinitionLocation.Line != ItemKey.Line) {
1032 OS << *MacroInfo.DefinitionSourceLine;
1033 if (MacroInfo.DefinitionLocation.Column > 0)
1034 OS << std::string(MacroInfo.DefinitionLocation.Column - 1, ' ')
1035 << "^\n";
1036 OS << "Macro defined here.\n";
1037 } else
1038 OS << "(no macro definition)"
1039 << "\n";
1040 }
1041 }
1042 return ReturnValue;
1043 }
1044
1045 // Report on inconsistent conditional instances.
1046 // Returns true if any mismatches.
1047 bool reportInconsistentConditionals(llvm::raw_ostream &OS) {
1048 bool ReturnValue = false;
1049 for (ConditionalExpansionMapIter I = ConditionalExpansions.begin(),
1050 E = ConditionalExpansions.end();
1051 I != E; ++I) {
1052 const PPItemKey &ItemKey = I->first;
1053 ConditionalTracker &CondTracker = I->second;
1054 if (!CondTracker.hasMismatch())
1055 continue;
1056 ReturnValue = true;
1057 OS << *HeaderPaths[ItemKey.File] << ":" << ItemKey.Line << ":"
1058 << ItemKey.Column << "\n";
1059 OS << "#" << getDirectiveSpelling(CondTracker.DirectiveKind) << " "
1060 << *CondTracker.ConditionUnexpanded << "\n";
1061 OS << "^\n";
1062 OS << "error: Conditional expression instance '"
1063 << *CondTracker.ConditionUnexpanded
1064 << "' has different values in this header, depending on how it was "
1065 "included.\n";
1066 for (std::vector<ConditionalExpansionInstance>::iterator
1067 IMT = CondTracker.ConditionalExpansionInstances.begin(),
1068 EMT = CondTracker.ConditionalExpansionInstances.end();
1069 IMT != EMT; ++IMT) {
1070 ConditionalExpansionInstance &MacroInfo = *IMT;
1071 OS << " '" << *CondTracker.ConditionUnexpanded << "' expanded to: '"
1072 << (MacroInfo.ConditionValue ? "true" : "false")
1073 << "' with respect to these inclusion paths:\n";
1074 for (std::vector<InclusionPathHandle>::iterator
1075 IIP = MacroInfo.InclusionPathHandles.begin(),
1076 EIP = MacroInfo.InclusionPathHandles.end();
1077 IIP != EIP; ++IIP) {
1078 const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
1079 int Count = (int)ip.size();
1080 for (int Index = 0; Index < Count; ++Index) {
1081 HeaderHandle H = ip[Index];
1082 OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
1083 << "\n";
1084 }
1085 }
1086 }
1087 }
1088 return ReturnValue;
1089 }
1090
1091 // Get directive spelling.
1092 static const char *getDirectiveSpelling(clang::tok::PPKeywordKind kind) {
1093 switch (kind) {
1094 case clang::tok::pp_if:
1095 return "if";
1096 case clang::tok::pp_elif:
1097 return "elif";
1098 case clang::tok::pp_ifdef:
1099 return "ifdef";
1100 case clang::tok::pp_ifndef:
1101 return "ifndef";
1102 default:
1103 return "(unknown)";
1104 }
1105 }
1106
1107private:
1108 llvm::StringPool Strings;
1109 std::vector<StringHandle> HeaderPaths;
1110 std::vector<HeaderHandle> HeaderStack;
1111 std::vector<HeaderInclusionPath> InclusionPaths;
1112 InclusionPathHandle CurrentInclusionPathHandle;
1113 MacroExpansionMap MacroExpansions;
1114 ConditionalExpansionMap ConditionalExpansions;
1115};
1116
1117// PreprocessorTracker functions.
1118
1119// PreprocessorTracker desctructor.
1120PreprocessorTracker::~PreprocessorTracker() {}
1121
1122// Create instance of PreprocessorTracker.
1123PreprocessorTracker *PreprocessorTracker::create() {
1124 return new PreprocessorTrackerImpl();
1125}
1126
1127// Preprocessor callbacks for modularize.
1128
1129// Handle file entry/exit.
1130void PreprocessorCallbacks::FileChanged(
1131 clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason,
1132 clang::SrcMgr::CharacteristicKind FileType, clang::FileID PrevFID) {
1133 switch (Reason) {
1134 case EnterFile:
1135 PPTracker.handleHeaderEntry(PP, getSourceLocationFile(PP, Loc));
1136 break;
1137 case ExitFile:
1138 if (PrevFID.isInvalid())
1139 PPTracker.handleHeaderExit(RootHeaderFile);
1140 else
1141 PPTracker.handleHeaderExit(getSourceLocationFile(PP, Loc));
1142 break;
1143 case SystemHeaderPragma:
1144 return;
1145 case RenameFile:
1146 return;
1147 default:
1148 return;
1149 }
1150}
1151
1152// Handle macro expansion.
1153void PreprocessorCallbacks::MacroExpands(const clang::Token &MacroNameTok,
1154 const clang::MacroDirective *MD,
1155 clang::SourceRange Range,
1156 const clang::MacroArgs *Args) {
1157 clang::SourceLocation Loc = Range.getBegin();
1158 clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
1159 const clang::MacroInfo *MI = PP.getMacroInfo(II);
1160 std::string MacroName = II->getName().str();
1161 std::string Unexpanded(getMacroUnexpandedString(Range, PP, MacroName, MI));
1162 std::string Expanded(getMacroExpandedString(PP, MacroName, MI, Args));
1163 PPTracker.addMacroExpansionInstance(
1164 PP, PPTracker.getCurrentHeaderHandle(), Loc, MI->getDefinitionLoc(), II,
1165 Unexpanded, Expanded, PPTracker.getCurrentInclusionPathHandle());
1166}
1167
1168void PreprocessorCallbacks::Defined(const clang::Token &MacroNameTok,
1169 const clang::MacroDirective *MD,
1170 clang::SourceRange Range) {
1171 clang::SourceLocation Loc(Range.getBegin());
1172 clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
1173 const clang::MacroInfo *MI = PP.getMacroInfo(II);
1174 std::string MacroName = II->getName().str();
1175 std::string Unexpanded(getSourceString(PP, Range));
1176 PPTracker.addMacroExpansionInstance(
1177 PP, PPTracker.getCurrentHeaderHandle(), Loc,
1178 (MI ? MI->getDefinitionLoc() : Loc), II, Unexpanded,
1179 (MI ? "true" : "false"), PPTracker.getCurrentInclusionPathHandle());
1180}
1181
1182void PreprocessorCallbacks::If(clang::SourceLocation Loc,
1183 clang::SourceRange ConditionRange,
1184 bool ConditionResult) {
1185 std::string Unexpanded(getSourceString(PP, ConditionRange));
1186 PPTracker.addConditionalExpansionInstance(
1187 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_if,
1188 ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
1189}
1190
1191void PreprocessorCallbacks::Elif(clang::SourceLocation Loc,
1192 clang::SourceRange ConditionRange,
1193 bool ConditionResult,
1194 clang::SourceLocation IfLoc) {
1195 std::string Unexpanded(getSourceString(PP, ConditionRange));
1196 PPTracker.addConditionalExpansionInstance(
1197 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_elif,
1198 ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
1199}
1200
1201void PreprocessorCallbacks::Ifdef(clang::SourceLocation Loc,
1202 const clang::Token &MacroNameTok,
1203 const clang::MacroDirective *MD) {
1204 bool IsDefined = (MD != 0);
1205 PPTracker.addConditionalExpansionInstance(
1206 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifdef,
1207 IsDefined, PP.getSpelling(MacroNameTok),
1208 PPTracker.getCurrentInclusionPathHandle());
1209}
1210
1211void PreprocessorCallbacks::Ifndef(clang::SourceLocation Loc,
1212 const clang::Token &MacroNameTok,
1213 const clang::MacroDirective *MD) {
1214 bool IsNotDefined = (MD == 0);
1215 PPTracker.addConditionalExpansionInstance(
1216 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifndef,
1217 IsNotDefined, PP.getSpelling(MacroNameTok),
1218 PPTracker.getCurrentInclusionPathHandle());
1219}
1220} // end namespace Modularize