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