blob: 566e2f15a33238879eeb4f5bf42d44511f0c41c1 [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"
John Thompson4ed963a2013-08-07 18:49:47 +0000226#include "llvm/ADT/SmallSet.h"
John Thompson94faa4d2013-07-26 23:56:42 +0000227#include "PreprocessorTracker.h"
228
229namespace Modularize {
230
231// Forwards.
232class PreprocessorTrackerImpl;
233
234// Some handle types
235typedef llvm::PooledStringPtr StringHandle;
236
237typedef int HeaderHandle;
238const HeaderHandle HeaderHandleInvalid = -1;
239
240typedef int InclusionPathHandle;
241const InclusionPathHandle InclusionPathHandleInvalid = -1;
242
243// Some utility functions.
244
245// Get a "file:line:column" source location string.
246static std::string getSourceLocationString(clang::Preprocessor &PP,
247 clang::SourceLocation Loc) {
248 if (Loc.isInvalid())
249 return std::string("(none)");
250 else
251 return Loc.printToString(PP.getSourceManager());
252}
253
254// Get just the file name from a source location.
255static std::string getSourceLocationFile(clang::Preprocessor &PP,
256 clang::SourceLocation Loc) {
257 std::string Source(getSourceLocationString(PP, Loc));
258 size_t Offset = Source.find(':', 2);
259 if (Offset == std::string::npos)
260 return Source;
261 return Source.substr(0, Offset);
262}
263
264// Get just the line and column from a source location.
265static void getSourceLocationLineAndColumn(clang::Preprocessor &PP,
266 clang::SourceLocation Loc, int &Line,
267 int &Column) {
268 clang::PresumedLoc PLoc = PP.getSourceManager().getPresumedLoc(Loc);
269 if (PLoc.isInvalid()) {
270 Line = 0;
271 Column = 0;
272 return;
273 }
274 Line = PLoc.getLine();
275 Column = PLoc.getColumn();
276}
277
278// Retrieve source snippet from file image.
279std::string getSourceString(clang::Preprocessor &PP, clang::SourceRange Range) {
280 clang::SourceLocation BeginLoc = Range.getBegin();
281 clang::SourceLocation EndLoc = Range.getEnd();
282 const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
283 const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc);
284 size_t Length = EndPtr - BeginPtr;
285 return llvm::StringRef(BeginPtr, Length).trim().str();
286}
287
288// Retrieve source line from file image.
289std::string getSourceLine(clang::Preprocessor &PP, clang::SourceLocation Loc) {
290 const llvm::MemoryBuffer *MemBuffer =
291 PP.getSourceManager().getBuffer(PP.getSourceManager().getFileID(Loc));
292 const char *Buffer = MemBuffer->getBufferStart();
293 const char *BufferEnd = MemBuffer->getBufferEnd();
294 const char *BeginPtr = PP.getSourceManager().getCharacterData(Loc);
295 const char *EndPtr = BeginPtr;
296 while (BeginPtr > Buffer) {
297 if (*BeginPtr == '\n') {
298 BeginPtr++;
299 break;
300 }
301 BeginPtr--;
302 }
303 while (EndPtr < BufferEnd) {
304 if (*EndPtr == '\n') {
305 break;
306 }
307 EndPtr++;
308 }
309 size_t Length = EndPtr - BeginPtr;
310 return llvm::StringRef(BeginPtr, Length).str();
311}
312
313// Get the string for the Unexpanded macro instance.
314// The soureRange is expected to end at the last token
315// for the macro instance, which in the case of a function-style
316// macro will be a ')', but for an object-style macro, it
317// will be the macro name itself.
318std::string getMacroUnexpandedString(clang::SourceRange Range,
319 clang::Preprocessor &PP,
320 llvm::StringRef MacroName,
321 const clang::MacroInfo *MI) {
322 clang::SourceLocation BeginLoc(Range.getBegin());
323 const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
324 size_t Length;
325 std::string Unexpanded;
326 if (MI->isFunctionLike()) {
327 clang::SourceLocation EndLoc(Range.getEnd());
328 const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc) + 1;
329 Length = (EndPtr - BeginPtr) + 1; // +1 is ')' width.
330 } else
331 Length = MacroName.size();
332 return llvm::StringRef(BeginPtr, Length).trim().str();
333}
334
335// Get the expansion for a macro instance, given the information
336// provided by PPCallbacks.
John Thompson91555bd2013-08-09 00:22:20 +0000337// FIXME: This doesn't support function-style macro instances
338// passed as arguments to another function-style macro. However,
339// since it still expands the inner arguments, it still
340// allows modularize to effectively work with respect to macro
341// consistency checking, although it displays the incorrect
342// expansion in error messages.
John Thompson94faa4d2013-07-26 23:56:42 +0000343std::string getMacroExpandedString(clang::Preprocessor &PP,
344 llvm::StringRef MacroName,
345 const clang::MacroInfo *MI,
346 const clang::MacroArgs *Args) {
347 std::string Expanded;
348 // Walk over the macro Tokens.
349 typedef clang::MacroInfo::tokens_iterator Iter;
350 for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
351 clang::IdentifierInfo *II = I->getIdentifierInfo();
352 int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
353 if (ArgNo == -1) {
354 // This isn't an argument, just add it.
355 if (II == NULL)
356 Expanded += PP.getSpelling((*I)); // Not an identifier.
357 else {
358 // Token is for an identifier.
359 std::string Name = II->getName().str();
360 // Check for nexted macro references.
361 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
362 if (MacroInfo != NULL)
363 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
364 else
365 Expanded += Name;
366 }
367 continue;
368 }
369 // We get here if it's a function-style macro with arguments.
370 const clang::Token *ResultArgToks;
371 const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
372 if (Args->ArgNeedsPreexpansion(ArgTok, PP))
373 ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
374 ->getPreExpArgument(ArgNo, MI, PP)[0];
375 else
376 ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
377 // If the arg token didn't expand into anything, ignore it.
378 if (ResultArgToks->is(clang::tok::eof))
379 continue;
380 unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
381 // Append the resulting argument expansions.
382 for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
383 const clang::Token &AT = ResultArgToks[ArgumentIndex];
384 clang::IdentifierInfo *II = AT.getIdentifierInfo();
385 if (II == NULL)
386 Expanded += PP.getSpelling(AT); // Not an identifier.
387 else {
388 // It's an identifier. Check for further expansion.
389 std::string Name = II->getName().str();
390 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
391 if (MacroInfo != NULL)
392 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
393 else
394 Expanded += Name;
395 }
396 }
397 }
398 return Expanded;
399}
400
401// Get the string representing a vector of Tokens.
402std::string
403getTokensSpellingString(clang::Preprocessor &PP,
404 llvm::SmallVectorImpl<clang::Token> &Tokens) {
405 std::string Expanded;
406 // Walk over the macro Tokens.
407 typedef llvm::SmallVectorImpl<clang::Token>::iterator Iter;
408 for (Iter I = Tokens.begin(), E = Tokens.end(); I != E; ++I)
409 Expanded += PP.getSpelling(*I); // Not an identifier.
410 return llvm::StringRef(Expanded).trim().str();
411}
412
413// Get the expansion for a macro instance, given the information
414// provided by PPCallbacks.
415std::string getExpandedString(clang::Preprocessor &PP,
416 llvm::StringRef MacroName,
417 const clang::MacroInfo *MI,
418 const clang::MacroArgs *Args) {
419 std::string Expanded;
420 // Walk over the macro Tokens.
421 typedef clang::MacroInfo::tokens_iterator Iter;
422 for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
423 clang::IdentifierInfo *II = I->getIdentifierInfo();
424 int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
425 if (ArgNo == -1) {
426 // This isn't an argument, just add it.
427 if (II == NULL)
428 Expanded += PP.getSpelling((*I)); // Not an identifier.
429 else {
430 // Token is for an identifier.
431 std::string Name = II->getName().str();
432 // Check for nexted macro references.
433 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
434 if (MacroInfo != NULL)
435 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
436 else
437 Expanded += Name;
438 }
439 continue;
440 }
441 // We get here if it's a function-style macro with arguments.
442 const clang::Token *ResultArgToks;
443 const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
444 if (Args->ArgNeedsPreexpansion(ArgTok, PP))
445 ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
446 ->getPreExpArgument(ArgNo, MI, PP)[0];
447 else
448 ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
449 // If the arg token didn't expand into anything, ignore it.
450 if (ResultArgToks->is(clang::tok::eof))
451 continue;
452 unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
453 // Append the resulting argument expansions.
454 for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
455 const clang::Token &AT = ResultArgToks[ArgumentIndex];
456 clang::IdentifierInfo *II = AT.getIdentifierInfo();
457 if (II == NULL)
458 Expanded += PP.getSpelling(AT); // Not an identifier.
459 else {
460 // It's an identifier. Check for further expansion.
461 std::string Name = II->getName().str();
462 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
463 if (MacroInfo != NULL)
464 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
465 else
466 Expanded += Name;
467 }
468 }
469 }
470 return Expanded;
471}
472
473// We need some operator overloads for string handles.
474bool operator==(const StringHandle &H1, const StringHandle &H2) {
475 const char *S1 = (H1 ? *H1 : "");
476 const char *S2 = (H2 ? *H2 : "");
477 int Diff = strcmp(S1, S2);
478 return Diff == 0;
479}
480bool operator!=(const StringHandle &H1, const StringHandle &H2) {
481 const char *S1 = (H1 ? *H1 : "");
482 const char *S2 = (H2 ? *H2 : "");
483 int Diff = strcmp(S1, S2);
484 return Diff != 0;
485}
486bool operator<(const StringHandle &H1, const StringHandle &H2) {
487 const char *S1 = (H1 ? *H1 : "");
488 const char *S2 = (H2 ? *H2 : "");
489 int Diff = strcmp(S1, S2);
490 return Diff < 0;
491}
492bool operator>(const StringHandle &H1, const StringHandle &H2) {
493 const char *S1 = (H1 ? *H1 : "");
494 const char *S2 = (H2 ? *H2 : "");
495 int Diff = strcmp(S1, S2);
496 return Diff > 0;
497}
498
499// Preprocessor item key.
500//
501// This class represents a location in a source file, for use
502// as a key representing a unique name/file/line/column quadruplet,
503// which in this case is used to identify a macro expansion instance,
504// but could be used for other things as well.
505// The file is a header file handle, the line is a line number,
506// and the column is a column number.
507class PPItemKey {
508public:
509 PPItemKey(clang::Preprocessor &PP, StringHandle Name, HeaderHandle File,
510 clang::SourceLocation Loc)
511 : Name(Name), File(File) {
512 getSourceLocationLineAndColumn(PP, Loc, Line, Column);
513 }
514 PPItemKey(StringHandle Name, HeaderHandle File, int Line, int Column)
515 : Name(Name), File(File), Line(Line), Column(Column) {}
516 PPItemKey(const PPItemKey &Other)
517 : Name(Other.Name), File(Other.File), Line(Other.Line),
518 Column(Other.Column) {}
519 PPItemKey() : File(HeaderHandleInvalid), Line(0), Column(0) {}
520 bool operator==(const PPItemKey &Other) const {
521 if (Name != Other.Name)
522 return false;
523 if (File != Other.File)
524 return false;
525 if (Line != Other.Line)
526 return false;
527 return Column == Other.Column;
528 }
529 bool operator<(const PPItemKey &Other) const {
530 if (Name < Other.Name)
531 return true;
532 else if (Name > Other.Name)
533 return false;
534 if (File < Other.File)
535 return true;
536 else if (File > Other.File)
537 return false;
538 if (Line < Other.Line)
539 return true;
540 else if (Line > Other.Line)
541 return false;
542 return Column < Other.Column;
543 }
544 StringHandle Name;
545 HeaderHandle File;
546 int Line;
547 int Column;
548};
549
550// Header inclusion path.
551class HeaderInclusionPath {
552public:
553 HeaderInclusionPath(std::vector<HeaderHandle> HeaderInclusionPath)
554 : Path(HeaderInclusionPath) {}
555 HeaderInclusionPath(const HeaderInclusionPath &Other) : Path(Other.Path) {}
556 HeaderInclusionPath() {}
557 std::vector<HeaderHandle> Path;
558};
559
560// Macro expansion instance.
561//
562// This class represents an instance of a macro expansion with a
563// unique value. It also stores the unique header inclusion paths
John Thompson7c6e79f32013-07-29 19:07:00 +0000564// for use in telling the user the nested include path to the header.
John Thompson94faa4d2013-07-26 23:56:42 +0000565class MacroExpansionInstance {
566public:
567 MacroExpansionInstance(StringHandle MacroExpanded,
568 PPItemKey &DefinitionLocation,
569 StringHandle DefinitionSourceLine,
570 InclusionPathHandle H)
571 : MacroExpanded(MacroExpanded), DefinitionLocation(DefinitionLocation),
572 DefinitionSourceLine(DefinitionSourceLine) {
573 InclusionPathHandles.push_back(H);
574 }
575 MacroExpansionInstance() {}
576
577 // Check for the presence of a header inclusion path handle entry.
578 // Return false if not found.
579 bool haveInclusionPathHandle(InclusionPathHandle H) {
580 for (std::vector<InclusionPathHandle>::iterator
581 I = InclusionPathHandles.begin(),
582 E = InclusionPathHandles.end();
583 I != E; ++I) {
584 if (*I == H)
585 return true;
586 }
587 return InclusionPathHandleInvalid;
588 }
589 // Add a new header inclusion path entry, if not already present.
590 void addInclusionPathHandle(InclusionPathHandle H) {
591 if (!haveInclusionPathHandle(H))
592 InclusionPathHandles.push_back(H);
593 }
594
595 // A string representing the macro instance after preprocessing.
596 StringHandle MacroExpanded;
597 // A file/line/column triplet representing the macro definition location.
598 PPItemKey DefinitionLocation;
599 // A place to save the macro definition line string.
600 StringHandle DefinitionSourceLine;
601 // The header inclusion path handles for all the instances.
602 std::vector<InclusionPathHandle> InclusionPathHandles;
603};
604
605// Macro expansion instance tracker.
606//
607// This class represents one macro expansion, keyed by a PPItemKey.
608// It stores a string representing the macro reference in the source,
609// and a list of ConditionalExpansionInstances objects representing
John Thompson7c6e79f32013-07-29 19:07:00 +0000610// the unique values the condition expands to in instances of the header.
John Thompson94faa4d2013-07-26 23:56:42 +0000611class MacroExpansionTracker {
612public:
613 MacroExpansionTracker(StringHandle MacroUnexpanded,
614 StringHandle MacroExpanded,
615 StringHandle InstanceSourceLine,
616 PPItemKey &DefinitionLocation,
617 StringHandle DefinitionSourceLine,
618 InclusionPathHandle InclusionPathHandle)
619 : MacroUnexpanded(MacroUnexpanded),
620 InstanceSourceLine(InstanceSourceLine) {
621 addMacroExpansionInstance(MacroExpanded, DefinitionLocation,
622 DefinitionSourceLine, InclusionPathHandle);
623 }
624 MacroExpansionTracker() {}
625
626 // Find a matching macro expansion instance.
627 MacroExpansionInstance *
628 findMacroExpansionInstance(StringHandle MacroExpanded,
629 PPItemKey &DefinitionLocation) {
630 for (std::vector<MacroExpansionInstance>::iterator
631 I = MacroExpansionInstances.begin(),
632 E = MacroExpansionInstances.end();
633 I != E; ++I) {
634 if ((I->MacroExpanded == MacroExpanded) &&
635 (I->DefinitionLocation == DefinitionLocation)) {
636 return &*I; // Found.
637 }
638 }
639 return NULL; // Not found.
640 }
641
642 // Add a macro expansion instance.
643 void addMacroExpansionInstance(StringHandle MacroExpanded,
644 PPItemKey &DefinitionLocation,
645 StringHandle DefinitionSourceLine,
646 InclusionPathHandle InclusionPathHandle) {
647 MacroExpansionInstances.push_back(
648 MacroExpansionInstance(MacroExpanded, DefinitionLocation,
649 DefinitionSourceLine, InclusionPathHandle));
650 }
651
652 // Return true if there is a mismatch.
653 bool hasMismatch() { return MacroExpansionInstances.size() > 1; }
654
655 // A string representing the macro instance without expansion.
656 StringHandle MacroUnexpanded;
657 // A place to save the macro instance source line string.
658 StringHandle InstanceSourceLine;
659 // The macro expansion instances.
660 // If all instances of the macro expansion expand to the same value,
661 // This vector will only have one instance.
662 std::vector<MacroExpansionInstance> MacroExpansionInstances;
663};
664
665// Conditional expansion instance.
666//
John Thompson7c6e79f32013-07-29 19:07:00 +0000667// This class represents an instance of a condition exoression result
668// with a unique value. It also stores the unique header inclusion paths
669// for use in telling the user the nested include path to the header.
John Thompson94faa4d2013-07-26 23:56:42 +0000670class ConditionalExpansionInstance {
671public:
672 ConditionalExpansionInstance(bool ConditionValue, InclusionPathHandle H)
673 : ConditionValue(ConditionValue) {
674 InclusionPathHandles.push_back(H);
675 }
676 ConditionalExpansionInstance() {}
677
678 // Check for the presence of a header inclusion path handle entry.
679 // Return false if not found.
680 bool haveInclusionPathHandle(InclusionPathHandle H) {
681 for (std::vector<InclusionPathHandle>::iterator
682 I = InclusionPathHandles.begin(),
683 E = InclusionPathHandles.end();
684 I != E; ++I) {
685 if (*I == H)
686 return true;
687 }
688 return InclusionPathHandleInvalid;
689 }
690 // Add a new header inclusion path entry, if not already present.
691 void addInclusionPathHandle(InclusionPathHandle H) {
692 if (!haveInclusionPathHandle(H))
693 InclusionPathHandles.push_back(H);
694 }
695
696 // A flag representing the evaluated condition value.
697 bool ConditionValue;
698 // The header inclusion path handles for all the instances.
699 std::vector<InclusionPathHandle> InclusionPathHandles;
700};
701
702// Conditional directive instance tracker.
703//
704// This class represents one conditional directive, keyed by a PPItemKey.
705// It stores a string representing the macro reference in the source,
John Thompson7c6e79f32013-07-29 19:07:00 +0000706// and a list of ConditionExpansionInstance objects representing
707// the unique value the condition expression expands to in instances of
708// the header.
John Thompson94faa4d2013-07-26 23:56:42 +0000709class ConditionalTracker {
710public:
711 ConditionalTracker(clang::tok::PPKeywordKind DirectiveKind,
712 bool ConditionValue, StringHandle ConditionUnexpanded,
713 InclusionPathHandle InclusionPathHandle)
714 : DirectiveKind(DirectiveKind), ConditionUnexpanded(ConditionUnexpanded) {
715 addConditionalExpansionInstance(ConditionValue, InclusionPathHandle);
716 }
717 ConditionalTracker() {}
718
719 // Find a matching condition expansion instance.
720 ConditionalExpansionInstance *
721 findConditionalExpansionInstance(bool ConditionValue) {
722 for (std::vector<ConditionalExpansionInstance>::iterator
723 I = ConditionalExpansionInstances.begin(),
724 E = ConditionalExpansionInstances.end();
725 I != E; ++I) {
726 if (I->ConditionValue == ConditionValue) {
727 return &*I; // Found.
728 }
729 }
730 return NULL; // Not found.
731 }
732
733 // Add a conditional expansion instance.
734 void
735 addConditionalExpansionInstance(bool ConditionValue,
736 InclusionPathHandle InclusionPathHandle) {
737 ConditionalExpansionInstances.push_back(
738 ConditionalExpansionInstance(ConditionValue, InclusionPathHandle));
739 }
740
741 // Return true if there is a mismatch.
742 bool hasMismatch() { return ConditionalExpansionInstances.size() > 1; }
743
744 // The kind of directive.
745 clang::tok::PPKeywordKind DirectiveKind;
746 // A string representing the macro instance without expansion.
747 StringHandle ConditionUnexpanded;
748 // The condition expansion instances.
749 // If all instances of the conditional expression expand to the same value,
750 // This vector will only have one instance.
751 std::vector<ConditionalExpansionInstance> ConditionalExpansionInstances;
752};
753
754// Preprocessor callbacks for modularize.
755//
756// This class derives from the Clang PPCallbacks class to track preprocessor
757// actions, such as changing files and handling preprocessor directives and
758// macro expansions. It has to figure out when a new header file is entered
759// and left, as the provided handler is not particularly clear about it.
760class PreprocessorCallbacks : public clang::PPCallbacks {
761public:
762 PreprocessorCallbacks(PreprocessorTrackerImpl &ppTracker,
763 clang::Preprocessor &PP, llvm::StringRef rootHeaderFile)
764 : PPTracker(ppTracker), PP(PP), RootHeaderFile(rootHeaderFile) {}
765 ~PreprocessorCallbacks() {}
766
767 // Overridden handlers.
768 void FileChanged(clang::SourceLocation Loc,
769 clang::PPCallbacks::FileChangeReason Reason,
770 clang::SrcMgr::CharacteristicKind FileType,
771 clang::FileID PrevFID = clang::FileID());
772 void MacroExpands(const clang::Token &MacroNameTok,
773 const clang::MacroDirective *MD, clang::SourceRange Range,
774 const clang::MacroArgs *Args);
775 void Defined(const clang::Token &MacroNameTok,
776 const clang::MacroDirective *MD, clang::SourceRange Range);
777 void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
778 bool ConditionResult);
779 void Elif(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
780 bool ConditionResult, clang::SourceLocation IfLoc);
781 void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
782 const clang::MacroDirective *MD);
783 void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
784 const clang::MacroDirective *MD);
785
786private:
787 PreprocessorTrackerImpl &PPTracker;
788 clang::Preprocessor &PP;
789 std::string RootHeaderFile;
790};
791
792// Preprocessor macro expansion item map types.
793typedef std::map<PPItemKey, MacroExpansionTracker> MacroExpansionMap;
794typedef std::map<PPItemKey, MacroExpansionTracker>::iterator
795MacroExpansionMapIter;
796
797// Preprocessor conditional expansion item map types.
798typedef std::map<PPItemKey, ConditionalTracker> ConditionalExpansionMap;
799typedef std::map<PPItemKey, ConditionalTracker>::iterator
800ConditionalExpansionMapIter;
801
802// Preprocessor tracker for modularize.
803//
804// This class stores information about all the headers processed in the
805// course of running modularize.
806class PreprocessorTrackerImpl : public PreprocessorTracker {
807public:
808 PreprocessorTrackerImpl()
John Thompson48df0962013-08-05 23:55:14 +0000809 : CurrentInclusionPathHandle(InclusionPathHandleInvalid),
810 InNestedHeader(false) {}
John Thompson94faa4d2013-07-26 23:56:42 +0000811 ~PreprocessorTrackerImpl() {}
812
813 // Handle entering a preprocessing session.
814 void handlePreprocessorEntry(clang::Preprocessor &PP,
815 llvm::StringRef rootHeaderFile) {
John Thompson4ed963a2013-08-07 18:49:47 +0000816 HeadersInThisCompile.clear();
John Thompson94faa4d2013-07-26 23:56:42 +0000817 assert((HeaderStack.size() == 0) && "Header stack should be empty.");
818 pushHeaderHandle(addHeader(rootHeaderFile));
819 PP.addPPCallbacks(new PreprocessorCallbacks(*this, PP, rootHeaderFile));
820 }
821 // Handle exiting a preprocessing session.
822 void handlePreprocessorExit() { HeaderStack.clear(); }
823
824 // Handle entering a header source file.
825 void handleHeaderEntry(clang::Preprocessor &PP, llvm::StringRef HeaderPath) {
826 // Ignore <built-in> and <command-line> to reduce message clutter.
827 if (HeaderPath.startswith("<"))
828 return;
829 HeaderHandle H = addHeader(HeaderPath);
John Thompson4ed963a2013-08-07 18:49:47 +0000830 if (H != getCurrentHeaderHandle())
John Thompson94faa4d2013-07-26 23:56:42 +0000831 pushHeaderHandle(H);
John Thompson4ed963a2013-08-07 18:49:47 +0000832 // Check for nested header.
833 if (!InNestedHeader)
834 InNestedHeader = !HeadersInThisCompile.insert(H);
John Thompson94faa4d2013-07-26 23:56:42 +0000835 }
836 // Handle exiting a header source file.
837 void handleHeaderExit(llvm::StringRef HeaderPath) {
838 // Ignore <built-in> and <command-line> to reduce message clutter.
839 if (HeaderPath.startswith("<"))
840 return;
841 HeaderHandle H = findHeaderHandle(HeaderPath);
842 if (isHeaderHandleInStack(H)) {
843 while ((H != getCurrentHeaderHandle()) && (HeaderStack.size() != 0))
844 popHeaderHandle();
845 }
John Thompson48df0962013-08-05 23:55:14 +0000846 InNestedHeader = false;
John Thompson94faa4d2013-07-26 23:56:42 +0000847 }
848
849 // Lookup/add string.
850 StringHandle addString(llvm::StringRef Str) { return Strings.intern(Str); }
851
852 // Get the handle of a header file entry.
853 // Return HeaderHandleInvalid if not found.
854 HeaderHandle findHeaderHandle(llvm::StringRef HeaderPath) const {
John Thompson48df0962013-08-05 23:55:14 +0000855 std::string CanonicalPath(HeaderPath);
856 std::replace(CanonicalPath.begin(), CanonicalPath.end(), '\\', '/');
John Thompson94faa4d2013-07-26 23:56:42 +0000857 HeaderHandle H = 0;
858 for (std::vector<StringHandle>::const_iterator I = HeaderPaths.begin(),
859 E = HeaderPaths.end();
860 I != E; ++I, ++H) {
John Thompson48df0962013-08-05 23:55:14 +0000861 if (**I == CanonicalPath)
John Thompson94faa4d2013-07-26 23:56:42 +0000862 return H;
863 }
864 return HeaderHandleInvalid;
865 }
866
867 // Add a new header file entry, or return existing handle.
868 // Return the header handle.
869 HeaderHandle addHeader(llvm::StringRef HeaderPath) {
John Thompson48df0962013-08-05 23:55:14 +0000870 std::string CanonicalPath(HeaderPath);
871 std::replace(CanonicalPath.begin(), CanonicalPath.end(), '\\', '/');
872 HeaderHandle H = findHeaderHandle(CanonicalPath);
John Thompson94faa4d2013-07-26 23:56:42 +0000873 if (H == HeaderHandleInvalid) {
874 H = HeaderPaths.size();
John Thompson48df0962013-08-05 23:55:14 +0000875 HeaderPaths.push_back(addString(CanonicalPath));
John Thompson94faa4d2013-07-26 23:56:42 +0000876 }
877 return H;
878 }
879
880 // Return a header file path string given its handle.
881 StringHandle getHeaderFilePath(HeaderHandle H) const {
882 if ((H >= 0) && (H < (HeaderHandle)HeaderPaths.size()))
883 return HeaderPaths[H];
884 return StringHandle();
885 }
886
887 // Returns a handle to the inclusion path.
888 InclusionPathHandle pushHeaderHandle(HeaderHandle H) {
889 HeaderStack.push_back(H);
890 return CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
891 }
892 // Pops the last header handle from the stack;
893 void popHeaderHandle() {
894 // assert((HeaderStack.size() != 0) && "Header stack already empty.");
895 if (HeaderStack.size() != 0) {
896 HeaderStack.pop_back();
897 CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
898 }
899 }
900 // Get the top handle on the header stack.
901 HeaderHandle getCurrentHeaderHandle() const {
902 if (HeaderStack.size() != 0)
903 return HeaderStack.back();
904 return HeaderHandleInvalid;
905 }
906
907 // Check for presence of header handle in the header stack.
908 bool isHeaderHandleInStack(HeaderHandle H) const {
909 for (std::vector<HeaderHandle>::const_iterator I = HeaderStack.begin(),
910 E = HeaderStack.end();
911 I != E; ++I) {
912 if (*I == H)
913 return true;
914 }
915 return false;
916 }
917
918 // Get the handle of a header inclusion path entry.
919 // Return InclusionPathHandleInvalid if not found.
920 InclusionPathHandle
921 findInclusionPathHandle(const std::vector<HeaderHandle> &Path) const {
922 InclusionPathHandle H = 0;
923 for (std::vector<HeaderInclusionPath>::const_iterator
924 I = InclusionPaths.begin(),
925 E = InclusionPaths.end();
926 I != E; ++I, ++H) {
927 if (I->Path == Path)
928 return H;
929 }
930 return HeaderHandleInvalid;
931 }
932 // Add a new header inclusion path entry, or return existing handle.
933 // Return the header inclusion path entry handle.
934 InclusionPathHandle
935 addInclusionPathHandle(const std::vector<HeaderHandle> &Path) {
936 InclusionPathHandle H = findInclusionPathHandle(Path);
937 if (H == HeaderHandleInvalid) {
938 H = InclusionPaths.size();
939 InclusionPaths.push_back(HeaderInclusionPath(Path));
940 }
941 return H;
942 }
943 // Return the current inclusion path handle.
944 InclusionPathHandle getCurrentInclusionPathHandle() const {
945 return CurrentInclusionPathHandle;
946 }
947
948 // Return an inclusion path given its handle.
949 const std::vector<HeaderHandle> &
950 getInclusionPath(InclusionPathHandle H) const {
951 if ((H >= 0) && (H <= (InclusionPathHandle)InclusionPaths.size()))
952 return InclusionPaths[H].Path;
953 static std::vector<HeaderHandle> Empty;
954 return Empty;
955 }
956
957 // Add a macro expansion instance.
958 void addMacroExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
959 clang::SourceLocation InstanceLoc,
960 clang::SourceLocation DefinitionLoc,
961 clang::IdentifierInfo *II,
962 llvm::StringRef MacroUnexpanded,
963 llvm::StringRef MacroExpanded,
964 InclusionPathHandle InclusionPathHandle) {
965 StringHandle MacroName = addString(II->getName());
966 PPItemKey InstanceKey(PP, MacroName, H, InstanceLoc);
967 PPItemKey DefinitionKey(PP, MacroName, H, DefinitionLoc);
968 MacroExpansionMapIter I = MacroExpansions.find(InstanceKey);
John Thompson7c6e79f32013-07-29 19:07:00 +0000969 // If existing instance of expansion not found, add one.
John Thompson94faa4d2013-07-26 23:56:42 +0000970 if (I == MacroExpansions.end()) {
971 std::string InstanceSourceLine =
972 getSourceLocationString(PP, InstanceLoc) + ":\n" +
973 getSourceLine(PP, InstanceLoc) + "\n";
974 std::string DefinitionSourceLine =
975 getSourceLocationString(PP, DefinitionLoc) + ":\n" +
976 getSourceLine(PP, DefinitionLoc) + "\n";
977 MacroExpansions[InstanceKey] = MacroExpansionTracker(
978 addString(MacroUnexpanded), addString(MacroExpanded),
979 addString(InstanceSourceLine), DefinitionKey,
980 addString(DefinitionSourceLine), InclusionPathHandle);
981 } else {
John Thompson7c6e79f32013-07-29 19:07:00 +0000982 // We've seen the macro before. Get its tracker.
John Thompson94faa4d2013-07-26 23:56:42 +0000983 MacroExpansionTracker &CondTracker = I->second;
John Thompson7c6e79f32013-07-29 19:07:00 +0000984 // Look up an existing instance value for the macro.
John Thompson94faa4d2013-07-26 23:56:42 +0000985 MacroExpansionInstance *MacroInfo =
986 CondTracker.findMacroExpansionInstance(addString(MacroExpanded),
987 DefinitionKey);
John Thompson7c6e79f32013-07-29 19:07:00 +0000988 // If found, just add the inclusion path to the instance.
John Thompson94faa4d2013-07-26 23:56:42 +0000989 if (MacroInfo != NULL)
990 MacroInfo->addInclusionPathHandle(InclusionPathHandle);
991 else {
John Thompson7c6e79f32013-07-29 19:07:00 +0000992 // Otherwise add a new instance with the unique value.
John Thompson94faa4d2013-07-26 23:56:42 +0000993 std::string DefinitionSourceLine =
994 getSourceLocationString(PP, DefinitionLoc) + ":\n" +
995 getSourceLine(PP, DefinitionLoc) + "\n";
996 CondTracker.addMacroExpansionInstance(
997 addString(MacroExpanded), DefinitionKey,
998 addString(DefinitionSourceLine), InclusionPathHandle);
999 }
1000 }
1001 }
1002
1003 // Add a conditional expansion instance.
1004 void
1005 addConditionalExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
1006 clang::SourceLocation InstanceLoc,
1007 clang::tok::PPKeywordKind DirectiveKind,
1008 bool ConditionValue,
1009 llvm::StringRef ConditionUnexpanded,
1010 InclusionPathHandle InclusionPathHandle) {
John Thompson48df0962013-08-05 23:55:14 +00001011 // Ignore header guards, assuming the header guard is the only conditional.
1012 if (InNestedHeader)
1013 return;
John Thompson94faa4d2013-07-26 23:56:42 +00001014 StringHandle ConditionUnexpandedHandle(addString(ConditionUnexpanded));
1015 PPItemKey InstanceKey(PP, ConditionUnexpandedHandle, H, InstanceLoc);
1016 ConditionalExpansionMapIter I = ConditionalExpansions.find(InstanceKey);
John Thompson7c6e79f32013-07-29 19:07:00 +00001017 // If existing instance of condition not found, add one.
John Thompson94faa4d2013-07-26 23:56:42 +00001018 if (I == ConditionalExpansions.end()) {
1019 std::string InstanceSourceLine =
1020 getSourceLocationString(PP, InstanceLoc) + ":\n" +
1021 getSourceLine(PP, InstanceLoc) + "\n";
1022 ConditionalExpansions[InstanceKey] =
John Thompson48df0962013-08-05 23:55:14 +00001023 ConditionalTracker(DirectiveKind, ConditionValue,
1024 ConditionUnexpandedHandle,
John Thompson94faa4d2013-07-26 23:56:42 +00001025 InclusionPathHandle);
1026 } else {
John Thompson7c6e79f32013-07-29 19:07:00 +00001027 // We've seen the conditional before. Get its tracker.
John Thompson94faa4d2013-07-26 23:56:42 +00001028 ConditionalTracker &CondTracker = I->second;
John Thompson7c6e79f32013-07-29 19:07:00 +00001029 // Look up an existing instance value for the condition.
John Thompson94faa4d2013-07-26 23:56:42 +00001030 ConditionalExpansionInstance *MacroInfo =
1031 CondTracker.findConditionalExpansionInstance(ConditionValue);
John Thompson7c6e79f32013-07-29 19:07:00 +00001032 // If found, just add the inclusion path to the instance.
John Thompson94faa4d2013-07-26 23:56:42 +00001033 if (MacroInfo != NULL)
1034 MacroInfo->addInclusionPathHandle(InclusionPathHandle);
1035 else {
John Thompson7c6e79f32013-07-29 19:07:00 +00001036 // Otherwise add a new instance with the unique value.
John Thompson94faa4d2013-07-26 23:56:42 +00001037 CondTracker.addConditionalExpansionInstance(ConditionValue,
1038 InclusionPathHandle);
1039 }
1040 }
1041 }
1042
1043 // Report on inconsistent macro instances.
1044 // Returns true if any mismatches.
1045 bool reportInconsistentMacros(llvm::raw_ostream &OS) {
1046 bool ReturnValue = false;
John Thompson7c6e79f32013-07-29 19:07:00 +00001047 // Walk all the macro expansion trackers in the map.
John Thompson94faa4d2013-07-26 23:56:42 +00001048 for (MacroExpansionMapIter I = MacroExpansions.begin(),
1049 E = MacroExpansions.end();
1050 I != E; ++I) {
1051 const PPItemKey &ItemKey = I->first;
1052 MacroExpansionTracker &MacroExpTracker = I->second;
John Thompson7c6e79f32013-07-29 19:07:00 +00001053 // If no mismatch (only one instance value) continue.
John Thompson94faa4d2013-07-26 23:56:42 +00001054 if (!MacroExpTracker.hasMismatch())
1055 continue;
John Thompson7c6e79f32013-07-29 19:07:00 +00001056 // Tell caller we found one or more errors.
John Thompson94faa4d2013-07-26 23:56:42 +00001057 ReturnValue = true;
John Thompson7c6e79f32013-07-29 19:07:00 +00001058 // Start the error message.
John Thompson94faa4d2013-07-26 23:56:42 +00001059 OS << *MacroExpTracker.InstanceSourceLine;
1060 if (ItemKey.Column > 0)
1061 OS << std::string(ItemKey.Column - 1, ' ') << "^\n";
1062 OS << "error: Macro instance '" << *MacroExpTracker.MacroUnexpanded
1063 << "' has different values in this header, depending on how it was "
1064 "included.\n";
John Thompson7c6e79f32013-07-29 19:07:00 +00001065 // Walk all the instances.
John Thompson94faa4d2013-07-26 23:56:42 +00001066 for (std::vector<MacroExpansionInstance>::iterator
1067 IMT = MacroExpTracker.MacroExpansionInstances.begin(),
1068 EMT = MacroExpTracker.MacroExpansionInstances.end();
1069 IMT != EMT; ++IMT) {
1070 MacroExpansionInstance &MacroInfo = *IMT;
1071 OS << " '" << *MacroExpTracker.MacroUnexpanded << "' expanded to: '"
1072 << *MacroInfo.MacroExpanded
1073 << "' with respect to these inclusion paths:\n";
John Thompson7c6e79f32013-07-29 19:07:00 +00001074 // Walk all the inclusion path hierarchies.
John Thompson94faa4d2013-07-26 23:56:42 +00001075 for (std::vector<InclusionPathHandle>::iterator
1076 IIP = MacroInfo.InclusionPathHandles.begin(),
1077 EIP = MacroInfo.InclusionPathHandles.end();
1078 IIP != EIP; ++IIP) {
1079 const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
1080 int Count = (int)ip.size();
1081 for (int Index = 0; Index < Count; ++Index) {
1082 HeaderHandle H = ip[Index];
1083 OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
1084 << "\n";
1085 }
1086 }
1087 // For a macro that wasn't defined, we flag it by using the
1088 // instance location.
1089 // If there is a definition...
1090 if (MacroInfo.DefinitionLocation.Line != ItemKey.Line) {
1091 OS << *MacroInfo.DefinitionSourceLine;
1092 if (MacroInfo.DefinitionLocation.Column > 0)
1093 OS << std::string(MacroInfo.DefinitionLocation.Column - 1, ' ')
1094 << "^\n";
1095 OS << "Macro defined here.\n";
1096 } else
1097 OS << "(no macro definition)"
1098 << "\n";
1099 }
1100 }
1101 return ReturnValue;
1102 }
1103
1104 // Report on inconsistent conditional instances.
1105 // Returns true if any mismatches.
1106 bool reportInconsistentConditionals(llvm::raw_ostream &OS) {
1107 bool ReturnValue = false;
John Thompson7c6e79f32013-07-29 19:07:00 +00001108 // Walk all the conditional trackers in the map.
John Thompson94faa4d2013-07-26 23:56:42 +00001109 for (ConditionalExpansionMapIter I = ConditionalExpansions.begin(),
1110 E = ConditionalExpansions.end();
1111 I != E; ++I) {
1112 const PPItemKey &ItemKey = I->first;
1113 ConditionalTracker &CondTracker = I->second;
1114 if (!CondTracker.hasMismatch())
1115 continue;
John Thompson7c6e79f32013-07-29 19:07:00 +00001116 // Tell caller we found one or more errors.
John Thompson94faa4d2013-07-26 23:56:42 +00001117 ReturnValue = true;
John Thompson7c6e79f32013-07-29 19:07:00 +00001118 // Start the error message.
John Thompson94faa4d2013-07-26 23:56:42 +00001119 OS << *HeaderPaths[ItemKey.File] << ":" << ItemKey.Line << ":"
1120 << ItemKey.Column << "\n";
1121 OS << "#" << getDirectiveSpelling(CondTracker.DirectiveKind) << " "
1122 << *CondTracker.ConditionUnexpanded << "\n";
1123 OS << "^\n";
1124 OS << "error: Conditional expression instance '"
1125 << *CondTracker.ConditionUnexpanded
1126 << "' has different values in this header, depending on how it was "
1127 "included.\n";
John Thompson7c6e79f32013-07-29 19:07:00 +00001128 // Walk all the instances.
John Thompson94faa4d2013-07-26 23:56:42 +00001129 for (std::vector<ConditionalExpansionInstance>::iterator
1130 IMT = CondTracker.ConditionalExpansionInstances.begin(),
1131 EMT = CondTracker.ConditionalExpansionInstances.end();
1132 IMT != EMT; ++IMT) {
1133 ConditionalExpansionInstance &MacroInfo = *IMT;
1134 OS << " '" << *CondTracker.ConditionUnexpanded << "' expanded to: '"
1135 << (MacroInfo.ConditionValue ? "true" : "false")
1136 << "' with respect to these inclusion paths:\n";
John Thompson7c6e79f32013-07-29 19:07:00 +00001137 // Walk all the inclusion path hierarchies.
John Thompson94faa4d2013-07-26 23:56:42 +00001138 for (std::vector<InclusionPathHandle>::iterator
1139 IIP = MacroInfo.InclusionPathHandles.begin(),
1140 EIP = MacroInfo.InclusionPathHandles.end();
1141 IIP != EIP; ++IIP) {
1142 const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
1143 int Count = (int)ip.size();
1144 for (int Index = 0; Index < Count; ++Index) {
1145 HeaderHandle H = ip[Index];
1146 OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
1147 << "\n";
1148 }
1149 }
1150 }
1151 }
1152 return ReturnValue;
1153 }
1154
1155 // Get directive spelling.
1156 static const char *getDirectiveSpelling(clang::tok::PPKeywordKind kind) {
1157 switch (kind) {
1158 case clang::tok::pp_if:
1159 return "if";
1160 case clang::tok::pp_elif:
1161 return "elif";
1162 case clang::tok::pp_ifdef:
1163 return "ifdef";
1164 case clang::tok::pp_ifndef:
1165 return "ifndef";
1166 default:
1167 return "(unknown)";
1168 }
1169 }
1170
1171private:
1172 llvm::StringPool Strings;
1173 std::vector<StringHandle> HeaderPaths;
1174 std::vector<HeaderHandle> HeaderStack;
1175 std::vector<HeaderInclusionPath> InclusionPaths;
1176 InclusionPathHandle CurrentInclusionPathHandle;
John Thompson4ed963a2013-08-07 18:49:47 +00001177 llvm::SmallSet<HeaderHandle, 128> HeadersInThisCompile;
John Thompson94faa4d2013-07-26 23:56:42 +00001178 MacroExpansionMap MacroExpansions;
1179 ConditionalExpansionMap ConditionalExpansions;
John Thompson48df0962013-08-05 23:55:14 +00001180 bool InNestedHeader;
John Thompson94faa4d2013-07-26 23:56:42 +00001181};
1182
1183// PreprocessorTracker functions.
1184
1185// PreprocessorTracker desctructor.
1186PreprocessorTracker::~PreprocessorTracker() {}
1187
1188// Create instance of PreprocessorTracker.
1189PreprocessorTracker *PreprocessorTracker::create() {
1190 return new PreprocessorTrackerImpl();
1191}
1192
1193// Preprocessor callbacks for modularize.
1194
1195// Handle file entry/exit.
1196void PreprocessorCallbacks::FileChanged(
1197 clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason,
1198 clang::SrcMgr::CharacteristicKind FileType, clang::FileID PrevFID) {
1199 switch (Reason) {
1200 case EnterFile:
1201 PPTracker.handleHeaderEntry(PP, getSourceLocationFile(PP, Loc));
1202 break;
1203 case ExitFile:
John Thompson48df0962013-08-05 23:55:14 +00001204 {
1205 const clang::FileEntry *F =
1206 PP.getSourceManager().getFileEntryForID(PrevFID);
1207 if (F != NULL)
1208 PPTracker.handleHeaderExit(F->getName());
1209 }
John Thompson94faa4d2013-07-26 23:56:42 +00001210 break;
1211 case SystemHeaderPragma:
John Thompson94faa4d2013-07-26 23:56:42 +00001212 case RenameFile:
Benjamin Kramerf2576812013-07-27 15:57:46 +00001213 break;
John Thompson94faa4d2013-07-26 23:56:42 +00001214 }
1215}
1216
1217// Handle macro expansion.
1218void PreprocessorCallbacks::MacroExpands(const clang::Token &MacroNameTok,
1219 const clang::MacroDirective *MD,
1220 clang::SourceRange Range,
1221 const clang::MacroArgs *Args) {
1222 clang::SourceLocation Loc = Range.getBegin();
John Thompson91555bd2013-08-09 00:22:20 +00001223 // Ignore macro argument expansions.
1224 if (!Loc.isFileID())
1225 return;
John Thompson94faa4d2013-07-26 23:56:42 +00001226 clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
1227 const clang::MacroInfo *MI = PP.getMacroInfo(II);
1228 std::string MacroName = II->getName().str();
1229 std::string Unexpanded(getMacroUnexpandedString(Range, PP, MacroName, MI));
1230 std::string Expanded(getMacroExpandedString(PP, MacroName, MI, Args));
1231 PPTracker.addMacroExpansionInstance(
1232 PP, PPTracker.getCurrentHeaderHandle(), Loc, MI->getDefinitionLoc(), II,
1233 Unexpanded, Expanded, PPTracker.getCurrentInclusionPathHandle());
1234}
1235
1236void PreprocessorCallbacks::Defined(const clang::Token &MacroNameTok,
1237 const clang::MacroDirective *MD,
1238 clang::SourceRange Range) {
1239 clang::SourceLocation Loc(Range.getBegin());
1240 clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
1241 const clang::MacroInfo *MI = PP.getMacroInfo(II);
1242 std::string MacroName = II->getName().str();
1243 std::string Unexpanded(getSourceString(PP, Range));
1244 PPTracker.addMacroExpansionInstance(
1245 PP, PPTracker.getCurrentHeaderHandle(), Loc,
1246 (MI ? MI->getDefinitionLoc() : Loc), II, Unexpanded,
1247 (MI ? "true" : "false"), PPTracker.getCurrentInclusionPathHandle());
1248}
1249
1250void PreprocessorCallbacks::If(clang::SourceLocation Loc,
1251 clang::SourceRange ConditionRange,
1252 bool ConditionResult) {
1253 std::string Unexpanded(getSourceString(PP, ConditionRange));
1254 PPTracker.addConditionalExpansionInstance(
1255 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_if,
1256 ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
1257}
1258
1259void PreprocessorCallbacks::Elif(clang::SourceLocation Loc,
1260 clang::SourceRange ConditionRange,
1261 bool ConditionResult,
1262 clang::SourceLocation IfLoc) {
1263 std::string Unexpanded(getSourceString(PP, ConditionRange));
1264 PPTracker.addConditionalExpansionInstance(
1265 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_elif,
1266 ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
1267}
1268
1269void PreprocessorCallbacks::Ifdef(clang::SourceLocation Loc,
1270 const clang::Token &MacroNameTok,
1271 const clang::MacroDirective *MD) {
1272 bool IsDefined = (MD != 0);
1273 PPTracker.addConditionalExpansionInstance(
1274 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifdef,
1275 IsDefined, PP.getSpelling(MacroNameTok),
1276 PPTracker.getCurrentInclusionPathHandle());
1277}
1278
1279void PreprocessorCallbacks::Ifndef(clang::SourceLocation Loc,
1280 const clang::Token &MacroNameTok,
1281 const clang::MacroDirective *MD) {
1282 bool IsNotDefined = (MD == 0);
1283 PPTracker.addConditionalExpansionInstance(
1284 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifndef,
1285 IsNotDefined, PP.getSpelling(MacroNameTok),
1286 PPTracker.getCurrentInclusionPathHandle());
1287}
1288} // end namespace Modularize