blob: a4bfd8b3b12b0f775d2d08c02585714f567d7fc6 [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.
337std::string getMacroExpandedString(clang::Preprocessor &PP,
338 llvm::StringRef MacroName,
339 const clang::MacroInfo *MI,
340 const clang::MacroArgs *Args) {
341 std::string Expanded;
342 // Walk over the macro Tokens.
343 typedef clang::MacroInfo::tokens_iterator Iter;
344 for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
345 clang::IdentifierInfo *II = I->getIdentifierInfo();
346 int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
347 if (ArgNo == -1) {
348 // This isn't an argument, just add it.
349 if (II == NULL)
350 Expanded += PP.getSpelling((*I)); // Not an identifier.
351 else {
352 // Token is for an identifier.
353 std::string Name = II->getName().str();
354 // Check for nexted macro references.
355 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
356 if (MacroInfo != NULL)
357 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
358 else
359 Expanded += Name;
360 }
361 continue;
362 }
363 // We get here if it's a function-style macro with arguments.
364 const clang::Token *ResultArgToks;
365 const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
366 if (Args->ArgNeedsPreexpansion(ArgTok, PP))
367 ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
368 ->getPreExpArgument(ArgNo, MI, PP)[0];
369 else
370 ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
371 // If the arg token didn't expand into anything, ignore it.
372 if (ResultArgToks->is(clang::tok::eof))
373 continue;
374 unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
375 // Append the resulting argument expansions.
376 for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
377 const clang::Token &AT = ResultArgToks[ArgumentIndex];
378 clang::IdentifierInfo *II = AT.getIdentifierInfo();
379 if (II == NULL)
380 Expanded += PP.getSpelling(AT); // Not an identifier.
381 else {
382 // It's an identifier. Check for further expansion.
383 std::string Name = II->getName().str();
384 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
385 if (MacroInfo != NULL)
386 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
387 else
388 Expanded += Name;
389 }
390 }
391 }
392 return Expanded;
393}
394
395// Get the string representing a vector of Tokens.
396std::string
397getTokensSpellingString(clang::Preprocessor &PP,
398 llvm::SmallVectorImpl<clang::Token> &Tokens) {
399 std::string Expanded;
400 // Walk over the macro Tokens.
401 typedef llvm::SmallVectorImpl<clang::Token>::iterator Iter;
402 for (Iter I = Tokens.begin(), E = Tokens.end(); I != E; ++I)
403 Expanded += PP.getSpelling(*I); // Not an identifier.
404 return llvm::StringRef(Expanded).trim().str();
405}
406
407// Get the expansion for a macro instance, given the information
408// provided by PPCallbacks.
409std::string getExpandedString(clang::Preprocessor &PP,
410 llvm::StringRef MacroName,
411 const clang::MacroInfo *MI,
412 const clang::MacroArgs *Args) {
413 std::string Expanded;
414 // Walk over the macro Tokens.
415 typedef clang::MacroInfo::tokens_iterator Iter;
416 for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
417 clang::IdentifierInfo *II = I->getIdentifierInfo();
418 int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
419 if (ArgNo == -1) {
420 // This isn't an argument, just add it.
421 if (II == NULL)
422 Expanded += PP.getSpelling((*I)); // Not an identifier.
423 else {
424 // Token is for an identifier.
425 std::string Name = II->getName().str();
426 // Check for nexted macro references.
427 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
428 if (MacroInfo != NULL)
429 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
430 else
431 Expanded += Name;
432 }
433 continue;
434 }
435 // We get here if it's a function-style macro with arguments.
436 const clang::Token *ResultArgToks;
437 const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
438 if (Args->ArgNeedsPreexpansion(ArgTok, PP))
439 ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
440 ->getPreExpArgument(ArgNo, MI, PP)[0];
441 else
442 ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
443 // If the arg token didn't expand into anything, ignore it.
444 if (ResultArgToks->is(clang::tok::eof))
445 continue;
446 unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
447 // Append the resulting argument expansions.
448 for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
449 const clang::Token &AT = ResultArgToks[ArgumentIndex];
450 clang::IdentifierInfo *II = AT.getIdentifierInfo();
451 if (II == NULL)
452 Expanded += PP.getSpelling(AT); // Not an identifier.
453 else {
454 // It's an identifier. Check for further expansion.
455 std::string Name = II->getName().str();
456 clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
457 if (MacroInfo != NULL)
458 Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
459 else
460 Expanded += Name;
461 }
462 }
463 }
464 return Expanded;
465}
466
467// We need some operator overloads for string handles.
468bool operator==(const StringHandle &H1, const StringHandle &H2) {
469 const char *S1 = (H1 ? *H1 : "");
470 const char *S2 = (H2 ? *H2 : "");
471 int Diff = strcmp(S1, S2);
472 return Diff == 0;
473}
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}
492
493// Preprocessor item key.
494//
495// This class represents a location in a source file, for use
496// as a key representing a unique name/file/line/column quadruplet,
497// which in this case is used to identify a macro expansion instance,
498// but could be used for other things as well.
499// The file is a header file handle, the line is a line number,
500// and the column is a column number.
501class PPItemKey {
502public:
503 PPItemKey(clang::Preprocessor &PP, StringHandle Name, HeaderHandle File,
504 clang::SourceLocation Loc)
505 : Name(Name), File(File) {
506 getSourceLocationLineAndColumn(PP, Loc, Line, Column);
507 }
508 PPItemKey(StringHandle Name, HeaderHandle File, int Line, int Column)
509 : Name(Name), File(File), Line(Line), Column(Column) {}
510 PPItemKey(const PPItemKey &Other)
511 : Name(Other.Name), File(Other.File), Line(Other.Line),
512 Column(Other.Column) {}
513 PPItemKey() : File(HeaderHandleInvalid), Line(0), Column(0) {}
514 bool operator==(const PPItemKey &Other) const {
515 if (Name != Other.Name)
516 return false;
517 if (File != Other.File)
518 return false;
519 if (Line != Other.Line)
520 return false;
521 return Column == Other.Column;
522 }
523 bool operator<(const PPItemKey &Other) const {
524 if (Name < Other.Name)
525 return true;
526 else if (Name > Other.Name)
527 return false;
528 if (File < Other.File)
529 return true;
530 else if (File > Other.File)
531 return false;
532 if (Line < Other.Line)
533 return true;
534 else if (Line > Other.Line)
535 return false;
536 return Column < Other.Column;
537 }
538 StringHandle Name;
539 HeaderHandle File;
540 int Line;
541 int Column;
542};
543
544// Header inclusion path.
545class HeaderInclusionPath {
546public:
547 HeaderInclusionPath(std::vector<HeaderHandle> HeaderInclusionPath)
548 : Path(HeaderInclusionPath) {}
549 HeaderInclusionPath(const HeaderInclusionPath &Other) : Path(Other.Path) {}
550 HeaderInclusionPath() {}
551 std::vector<HeaderHandle> Path;
552};
553
554// Macro expansion instance.
555//
556// This class represents an instance of a macro expansion with a
557// unique value. It also stores the unique header inclusion paths
John Thompson7c6e79f32013-07-29 19:07:00 +0000558// for use in telling the user the nested include path to the header.
John Thompson94faa4d2013-07-26 23:56:42 +0000559class MacroExpansionInstance {
560public:
561 MacroExpansionInstance(StringHandle MacroExpanded,
562 PPItemKey &DefinitionLocation,
563 StringHandle DefinitionSourceLine,
564 InclusionPathHandle H)
565 : MacroExpanded(MacroExpanded), DefinitionLocation(DefinitionLocation),
566 DefinitionSourceLine(DefinitionSourceLine) {
567 InclusionPathHandles.push_back(H);
568 }
569 MacroExpansionInstance() {}
570
571 // Check for the presence of a header inclusion path handle entry.
572 // Return false if not found.
573 bool haveInclusionPathHandle(InclusionPathHandle H) {
574 for (std::vector<InclusionPathHandle>::iterator
575 I = InclusionPathHandles.begin(),
576 E = InclusionPathHandles.end();
577 I != E; ++I) {
578 if (*I == H)
579 return true;
580 }
581 return InclusionPathHandleInvalid;
582 }
583 // Add a new header inclusion path entry, if not already present.
584 void addInclusionPathHandle(InclusionPathHandle H) {
585 if (!haveInclusionPathHandle(H))
586 InclusionPathHandles.push_back(H);
587 }
588
589 // A string representing the macro instance after preprocessing.
590 StringHandle MacroExpanded;
591 // A file/line/column triplet representing the macro definition location.
592 PPItemKey DefinitionLocation;
593 // A place to save the macro definition line string.
594 StringHandle DefinitionSourceLine;
595 // The header inclusion path handles for all the instances.
596 std::vector<InclusionPathHandle> InclusionPathHandles;
597};
598
599// Macro expansion instance tracker.
600//
601// This class represents one macro expansion, keyed by a PPItemKey.
602// It stores a string representing the macro reference in the source,
603// and a list of ConditionalExpansionInstances objects representing
John Thompson7c6e79f32013-07-29 19:07:00 +0000604// the unique values the condition expands to in instances of the header.
John Thompson94faa4d2013-07-26 23:56:42 +0000605class MacroExpansionTracker {
606public:
607 MacroExpansionTracker(StringHandle MacroUnexpanded,
608 StringHandle MacroExpanded,
609 StringHandle InstanceSourceLine,
610 PPItemKey &DefinitionLocation,
611 StringHandle DefinitionSourceLine,
612 InclusionPathHandle InclusionPathHandle)
613 : MacroUnexpanded(MacroUnexpanded),
614 InstanceSourceLine(InstanceSourceLine) {
615 addMacroExpansionInstance(MacroExpanded, DefinitionLocation,
616 DefinitionSourceLine, InclusionPathHandle);
617 }
618 MacroExpansionTracker() {}
619
620 // Find a matching macro expansion instance.
621 MacroExpansionInstance *
622 findMacroExpansionInstance(StringHandle MacroExpanded,
623 PPItemKey &DefinitionLocation) {
624 for (std::vector<MacroExpansionInstance>::iterator
625 I = MacroExpansionInstances.begin(),
626 E = MacroExpansionInstances.end();
627 I != E; ++I) {
628 if ((I->MacroExpanded == MacroExpanded) &&
629 (I->DefinitionLocation == DefinitionLocation)) {
630 return &*I; // Found.
631 }
632 }
633 return NULL; // Not found.
634 }
635
636 // Add a macro expansion instance.
637 void addMacroExpansionInstance(StringHandle MacroExpanded,
638 PPItemKey &DefinitionLocation,
639 StringHandle DefinitionSourceLine,
640 InclusionPathHandle InclusionPathHandle) {
641 MacroExpansionInstances.push_back(
642 MacroExpansionInstance(MacroExpanded, DefinitionLocation,
643 DefinitionSourceLine, InclusionPathHandle));
644 }
645
646 // Return true if there is a mismatch.
647 bool hasMismatch() { return MacroExpansionInstances.size() > 1; }
648
649 // A string representing the macro instance without expansion.
650 StringHandle MacroUnexpanded;
651 // A place to save the macro instance source line string.
652 StringHandle InstanceSourceLine;
653 // The macro expansion instances.
654 // If all instances of the macro expansion expand to the same value,
655 // This vector will only have one instance.
656 std::vector<MacroExpansionInstance> MacroExpansionInstances;
657};
658
659// Conditional expansion instance.
660//
John Thompson7c6e79f32013-07-29 19:07:00 +0000661// This class represents an instance of a condition exoression result
662// with a unique value. It also stores the unique header inclusion paths
663// for use in telling the user the nested include path to the header.
John Thompson94faa4d2013-07-26 23:56:42 +0000664class ConditionalExpansionInstance {
665public:
666 ConditionalExpansionInstance(bool ConditionValue, InclusionPathHandle H)
667 : ConditionValue(ConditionValue) {
668 InclusionPathHandles.push_back(H);
669 }
670 ConditionalExpansionInstance() {}
671
672 // Check for the presence of a header inclusion path handle entry.
673 // Return false if not found.
674 bool haveInclusionPathHandle(InclusionPathHandle H) {
675 for (std::vector<InclusionPathHandle>::iterator
676 I = InclusionPathHandles.begin(),
677 E = InclusionPathHandles.end();
678 I != E; ++I) {
679 if (*I == H)
680 return true;
681 }
682 return InclusionPathHandleInvalid;
683 }
684 // Add a new header inclusion path entry, if not already present.
685 void addInclusionPathHandle(InclusionPathHandle H) {
686 if (!haveInclusionPathHandle(H))
687 InclusionPathHandles.push_back(H);
688 }
689
690 // A flag representing the evaluated condition value.
691 bool ConditionValue;
692 // The header inclusion path handles for all the instances.
693 std::vector<InclusionPathHandle> InclusionPathHandles;
694};
695
696// Conditional directive instance tracker.
697//
698// This class represents one conditional directive, keyed by a PPItemKey.
699// It stores a string representing the macro reference in the source,
John Thompson7c6e79f32013-07-29 19:07:00 +0000700// and a list of ConditionExpansionInstance objects representing
701// the unique value the condition expression expands to in instances of
702// the header.
John Thompson94faa4d2013-07-26 23:56:42 +0000703class ConditionalTracker {
704public:
705 ConditionalTracker(clang::tok::PPKeywordKind DirectiveKind,
706 bool ConditionValue, StringHandle ConditionUnexpanded,
707 InclusionPathHandle InclusionPathHandle)
708 : DirectiveKind(DirectiveKind), ConditionUnexpanded(ConditionUnexpanded) {
709 addConditionalExpansionInstance(ConditionValue, InclusionPathHandle);
710 }
711 ConditionalTracker() {}
712
713 // Find a matching condition expansion instance.
714 ConditionalExpansionInstance *
715 findConditionalExpansionInstance(bool ConditionValue) {
716 for (std::vector<ConditionalExpansionInstance>::iterator
717 I = ConditionalExpansionInstances.begin(),
718 E = ConditionalExpansionInstances.end();
719 I != E; ++I) {
720 if (I->ConditionValue == ConditionValue) {
721 return &*I; // Found.
722 }
723 }
724 return NULL; // Not found.
725 }
726
727 // Add a conditional expansion instance.
728 void
729 addConditionalExpansionInstance(bool ConditionValue,
730 InclusionPathHandle InclusionPathHandle) {
731 ConditionalExpansionInstances.push_back(
732 ConditionalExpansionInstance(ConditionValue, InclusionPathHandle));
733 }
734
735 // Return true if there is a mismatch.
736 bool hasMismatch() { return ConditionalExpansionInstances.size() > 1; }
737
738 // The kind of directive.
739 clang::tok::PPKeywordKind DirectiveKind;
740 // A string representing the macro instance without expansion.
741 StringHandle ConditionUnexpanded;
742 // The condition expansion instances.
743 // If all instances of the conditional expression expand to the same value,
744 // This vector will only have one instance.
745 std::vector<ConditionalExpansionInstance> ConditionalExpansionInstances;
746};
747
748// Preprocessor callbacks for modularize.
749//
750// This class derives from the Clang PPCallbacks class to track preprocessor
751// actions, such as changing files and handling preprocessor directives and
752// macro expansions. It has to figure out when a new header file is entered
753// and left, as the provided handler is not particularly clear about it.
754class PreprocessorCallbacks : public clang::PPCallbacks {
755public:
756 PreprocessorCallbacks(PreprocessorTrackerImpl &ppTracker,
757 clang::Preprocessor &PP, llvm::StringRef rootHeaderFile)
758 : PPTracker(ppTracker), PP(PP), RootHeaderFile(rootHeaderFile) {}
759 ~PreprocessorCallbacks() {}
760
761 // Overridden handlers.
762 void FileChanged(clang::SourceLocation Loc,
763 clang::PPCallbacks::FileChangeReason Reason,
764 clang::SrcMgr::CharacteristicKind FileType,
765 clang::FileID PrevFID = clang::FileID());
766 void MacroExpands(const clang::Token &MacroNameTok,
767 const clang::MacroDirective *MD, clang::SourceRange Range,
768 const clang::MacroArgs *Args);
769 void Defined(const clang::Token &MacroNameTok,
770 const clang::MacroDirective *MD, clang::SourceRange Range);
771 void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
772 bool ConditionResult);
773 void Elif(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
774 bool ConditionResult, clang::SourceLocation IfLoc);
775 void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
776 const clang::MacroDirective *MD);
777 void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
778 const clang::MacroDirective *MD);
779
780private:
781 PreprocessorTrackerImpl &PPTracker;
782 clang::Preprocessor &PP;
783 std::string RootHeaderFile;
784};
785
786// Preprocessor macro expansion item map types.
787typedef std::map<PPItemKey, MacroExpansionTracker> MacroExpansionMap;
788typedef std::map<PPItemKey, MacroExpansionTracker>::iterator
789MacroExpansionMapIter;
790
791// Preprocessor conditional expansion item map types.
792typedef std::map<PPItemKey, ConditionalTracker> ConditionalExpansionMap;
793typedef std::map<PPItemKey, ConditionalTracker>::iterator
794ConditionalExpansionMapIter;
795
796// Preprocessor tracker for modularize.
797//
798// This class stores information about all the headers processed in the
799// course of running modularize.
800class PreprocessorTrackerImpl : public PreprocessorTracker {
801public:
802 PreprocessorTrackerImpl()
John Thompson48df0962013-08-05 23:55:14 +0000803 : CurrentInclusionPathHandle(InclusionPathHandleInvalid),
804 InNestedHeader(false) {}
John Thompson94faa4d2013-07-26 23:56:42 +0000805 ~PreprocessorTrackerImpl() {}
806
807 // Handle entering a preprocessing session.
808 void handlePreprocessorEntry(clang::Preprocessor &PP,
809 llvm::StringRef rootHeaderFile) {
John Thompson4ed963a2013-08-07 18:49:47 +0000810 HeadersInThisCompile.clear();
John Thompson94faa4d2013-07-26 23:56:42 +0000811 assert((HeaderStack.size() == 0) && "Header stack should be empty.");
812 pushHeaderHandle(addHeader(rootHeaderFile));
813 PP.addPPCallbacks(new PreprocessorCallbacks(*this, PP, rootHeaderFile));
814 }
815 // Handle exiting a preprocessing session.
816 void handlePreprocessorExit() { HeaderStack.clear(); }
817
818 // Handle entering a header source file.
819 void handleHeaderEntry(clang::Preprocessor &PP, llvm::StringRef HeaderPath) {
820 // Ignore <built-in> and <command-line> to reduce message clutter.
821 if (HeaderPath.startswith("<"))
822 return;
823 HeaderHandle H = addHeader(HeaderPath);
John Thompson4ed963a2013-08-07 18:49:47 +0000824 if (H != getCurrentHeaderHandle())
John Thompson94faa4d2013-07-26 23:56:42 +0000825 pushHeaderHandle(H);
John Thompson4ed963a2013-08-07 18:49:47 +0000826 // Check for nested header.
827 if (!InNestedHeader)
828 InNestedHeader = !HeadersInThisCompile.insert(H);
John Thompson94faa4d2013-07-26 23:56:42 +0000829 }
830 // Handle exiting a header source file.
831 void handleHeaderExit(llvm::StringRef HeaderPath) {
832 // Ignore <built-in> and <command-line> to reduce message clutter.
833 if (HeaderPath.startswith("<"))
834 return;
835 HeaderHandle H = findHeaderHandle(HeaderPath);
836 if (isHeaderHandleInStack(H)) {
837 while ((H != getCurrentHeaderHandle()) && (HeaderStack.size() != 0))
838 popHeaderHandle();
839 }
John Thompson48df0962013-08-05 23:55:14 +0000840 InNestedHeader = false;
John Thompson94faa4d2013-07-26 23:56:42 +0000841 }
842
843 // Lookup/add string.
844 StringHandle addString(llvm::StringRef Str) { return Strings.intern(Str); }
845
846 // Get the handle of a header file entry.
847 // Return HeaderHandleInvalid if not found.
848 HeaderHandle findHeaderHandle(llvm::StringRef HeaderPath) const {
John Thompson48df0962013-08-05 23:55:14 +0000849 std::string CanonicalPath(HeaderPath);
850 std::replace(CanonicalPath.begin(), CanonicalPath.end(), '\\', '/');
John Thompson94faa4d2013-07-26 23:56:42 +0000851 HeaderHandle H = 0;
852 for (std::vector<StringHandle>::const_iterator I = HeaderPaths.begin(),
853 E = HeaderPaths.end();
854 I != E; ++I, ++H) {
John Thompson48df0962013-08-05 23:55:14 +0000855 if (**I == CanonicalPath)
John Thompson94faa4d2013-07-26 23:56:42 +0000856 return H;
857 }
858 return HeaderHandleInvalid;
859 }
860
861 // Add a new header file entry, or return existing handle.
862 // Return the header handle.
863 HeaderHandle addHeader(llvm::StringRef HeaderPath) {
John Thompson48df0962013-08-05 23:55:14 +0000864 std::string CanonicalPath(HeaderPath);
865 std::replace(CanonicalPath.begin(), CanonicalPath.end(), '\\', '/');
866 HeaderHandle H = findHeaderHandle(CanonicalPath);
John Thompson94faa4d2013-07-26 23:56:42 +0000867 if (H == HeaderHandleInvalid) {
868 H = HeaderPaths.size();
John Thompson48df0962013-08-05 23:55:14 +0000869 HeaderPaths.push_back(addString(CanonicalPath));
John Thompson94faa4d2013-07-26 23:56:42 +0000870 }
871 return H;
872 }
873
874 // Return a header file path string given its handle.
875 StringHandle getHeaderFilePath(HeaderHandle H) const {
876 if ((H >= 0) && (H < (HeaderHandle)HeaderPaths.size()))
877 return HeaderPaths[H];
878 return StringHandle();
879 }
880
881 // Returns a handle to the inclusion path.
882 InclusionPathHandle pushHeaderHandle(HeaderHandle H) {
883 HeaderStack.push_back(H);
884 return CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
885 }
886 // Pops the last header handle from the stack;
887 void popHeaderHandle() {
888 // assert((HeaderStack.size() != 0) && "Header stack already empty.");
889 if (HeaderStack.size() != 0) {
890 HeaderStack.pop_back();
891 CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
892 }
893 }
894 // Get the top handle on the header stack.
895 HeaderHandle getCurrentHeaderHandle() const {
896 if (HeaderStack.size() != 0)
897 return HeaderStack.back();
898 return HeaderHandleInvalid;
899 }
900
901 // Check for presence of header handle in the header stack.
902 bool isHeaderHandleInStack(HeaderHandle H) const {
903 for (std::vector<HeaderHandle>::const_iterator I = HeaderStack.begin(),
904 E = HeaderStack.end();
905 I != E; ++I) {
906 if (*I == H)
907 return true;
908 }
909 return false;
910 }
911
912 // Get the handle of a header inclusion path entry.
913 // Return InclusionPathHandleInvalid if not found.
914 InclusionPathHandle
915 findInclusionPathHandle(const std::vector<HeaderHandle> &Path) const {
916 InclusionPathHandle H = 0;
917 for (std::vector<HeaderInclusionPath>::const_iterator
918 I = InclusionPaths.begin(),
919 E = InclusionPaths.end();
920 I != E; ++I, ++H) {
921 if (I->Path == Path)
922 return H;
923 }
924 return HeaderHandleInvalid;
925 }
926 // Add a new header inclusion path entry, or return existing handle.
927 // Return the header inclusion path entry handle.
928 InclusionPathHandle
929 addInclusionPathHandle(const std::vector<HeaderHandle> &Path) {
930 InclusionPathHandle H = findInclusionPathHandle(Path);
931 if (H == HeaderHandleInvalid) {
932 H = InclusionPaths.size();
933 InclusionPaths.push_back(HeaderInclusionPath(Path));
934 }
935 return H;
936 }
937 // Return the current inclusion path handle.
938 InclusionPathHandle getCurrentInclusionPathHandle() const {
939 return CurrentInclusionPathHandle;
940 }
941
942 // Return an inclusion path given its handle.
943 const std::vector<HeaderHandle> &
944 getInclusionPath(InclusionPathHandle H) const {
945 if ((H >= 0) && (H <= (InclusionPathHandle)InclusionPaths.size()))
946 return InclusionPaths[H].Path;
947 static std::vector<HeaderHandle> Empty;
948 return Empty;
949 }
950
951 // Add a macro expansion instance.
952 void addMacroExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
953 clang::SourceLocation InstanceLoc,
954 clang::SourceLocation DefinitionLoc,
955 clang::IdentifierInfo *II,
956 llvm::StringRef MacroUnexpanded,
957 llvm::StringRef MacroExpanded,
958 InclusionPathHandle InclusionPathHandle) {
959 StringHandle MacroName = addString(II->getName());
960 PPItemKey InstanceKey(PP, MacroName, H, InstanceLoc);
961 PPItemKey DefinitionKey(PP, MacroName, H, DefinitionLoc);
962 MacroExpansionMapIter I = MacroExpansions.find(InstanceKey);
John Thompson7c6e79f32013-07-29 19:07:00 +0000963 // If existing instance of expansion not found, add one.
John Thompson94faa4d2013-07-26 23:56:42 +0000964 if (I == MacroExpansions.end()) {
965 std::string InstanceSourceLine =
966 getSourceLocationString(PP, InstanceLoc) + ":\n" +
967 getSourceLine(PP, InstanceLoc) + "\n";
968 std::string DefinitionSourceLine =
969 getSourceLocationString(PP, DefinitionLoc) + ":\n" +
970 getSourceLine(PP, DefinitionLoc) + "\n";
971 MacroExpansions[InstanceKey] = MacroExpansionTracker(
972 addString(MacroUnexpanded), addString(MacroExpanded),
973 addString(InstanceSourceLine), DefinitionKey,
974 addString(DefinitionSourceLine), InclusionPathHandle);
975 } else {
John Thompson7c6e79f32013-07-29 19:07:00 +0000976 // We've seen the macro before. Get its tracker.
John Thompson94faa4d2013-07-26 23:56:42 +0000977 MacroExpansionTracker &CondTracker = I->second;
John Thompson7c6e79f32013-07-29 19:07:00 +0000978 // Look up an existing instance value for the macro.
John Thompson94faa4d2013-07-26 23:56:42 +0000979 MacroExpansionInstance *MacroInfo =
980 CondTracker.findMacroExpansionInstance(addString(MacroExpanded),
981 DefinitionKey);
John Thompson7c6e79f32013-07-29 19:07:00 +0000982 // If found, just add the inclusion path to the instance.
John Thompson94faa4d2013-07-26 23:56:42 +0000983 if (MacroInfo != NULL)
984 MacroInfo->addInclusionPathHandle(InclusionPathHandle);
985 else {
John Thompson7c6e79f32013-07-29 19:07:00 +0000986 // Otherwise add a new instance with the unique value.
John Thompson94faa4d2013-07-26 23:56:42 +0000987 std::string DefinitionSourceLine =
988 getSourceLocationString(PP, DefinitionLoc) + ":\n" +
989 getSourceLine(PP, DefinitionLoc) + "\n";
990 CondTracker.addMacroExpansionInstance(
991 addString(MacroExpanded), DefinitionKey,
992 addString(DefinitionSourceLine), InclusionPathHandle);
993 }
994 }
995 }
996
997 // Add a conditional expansion instance.
998 void
999 addConditionalExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
1000 clang::SourceLocation InstanceLoc,
1001 clang::tok::PPKeywordKind DirectiveKind,
1002 bool ConditionValue,
1003 llvm::StringRef ConditionUnexpanded,
1004 InclusionPathHandle InclusionPathHandle) {
John Thompson48df0962013-08-05 23:55:14 +00001005 // Ignore header guards, assuming the header guard is the only conditional.
1006 if (InNestedHeader)
1007 return;
John Thompson94faa4d2013-07-26 23:56:42 +00001008 StringHandle ConditionUnexpandedHandle(addString(ConditionUnexpanded));
1009 PPItemKey InstanceKey(PP, ConditionUnexpandedHandle, H, InstanceLoc);
1010 ConditionalExpansionMapIter I = ConditionalExpansions.find(InstanceKey);
John Thompson7c6e79f32013-07-29 19:07:00 +00001011 // If existing instance of condition not found, add one.
John Thompson94faa4d2013-07-26 23:56:42 +00001012 if (I == ConditionalExpansions.end()) {
1013 std::string InstanceSourceLine =
1014 getSourceLocationString(PP, InstanceLoc) + ":\n" +
1015 getSourceLine(PP, InstanceLoc) + "\n";
1016 ConditionalExpansions[InstanceKey] =
John Thompson48df0962013-08-05 23:55:14 +00001017 ConditionalTracker(DirectiveKind, ConditionValue,
1018 ConditionUnexpandedHandle,
John Thompson94faa4d2013-07-26 23:56:42 +00001019 InclusionPathHandle);
1020 } else {
John Thompson7c6e79f32013-07-29 19:07:00 +00001021 // We've seen the conditional before. Get its tracker.
John Thompson94faa4d2013-07-26 23:56:42 +00001022 ConditionalTracker &CondTracker = I->second;
John Thompson7c6e79f32013-07-29 19:07:00 +00001023 // Look up an existing instance value for the condition.
John Thompson94faa4d2013-07-26 23:56:42 +00001024 ConditionalExpansionInstance *MacroInfo =
1025 CondTracker.findConditionalExpansionInstance(ConditionValue);
John Thompson7c6e79f32013-07-29 19:07:00 +00001026 // If found, just add the inclusion path to the instance.
John Thompson94faa4d2013-07-26 23:56:42 +00001027 if (MacroInfo != NULL)
1028 MacroInfo->addInclusionPathHandle(InclusionPathHandle);
1029 else {
John Thompson7c6e79f32013-07-29 19:07:00 +00001030 // Otherwise add a new instance with the unique value.
John Thompson94faa4d2013-07-26 23:56:42 +00001031 CondTracker.addConditionalExpansionInstance(ConditionValue,
1032 InclusionPathHandle);
1033 }
1034 }
1035 }
1036
1037 // Report on inconsistent macro instances.
1038 // Returns true if any mismatches.
1039 bool reportInconsistentMacros(llvm::raw_ostream &OS) {
1040 bool ReturnValue = false;
John Thompson7c6e79f32013-07-29 19:07:00 +00001041 // Walk all the macro expansion trackers in the map.
John Thompson94faa4d2013-07-26 23:56:42 +00001042 for (MacroExpansionMapIter I = MacroExpansions.begin(),
1043 E = MacroExpansions.end();
1044 I != E; ++I) {
1045 const PPItemKey &ItemKey = I->first;
1046 MacroExpansionTracker &MacroExpTracker = I->second;
John Thompson7c6e79f32013-07-29 19:07:00 +00001047 // If no mismatch (only one instance value) continue.
John Thompson94faa4d2013-07-26 23:56:42 +00001048 if (!MacroExpTracker.hasMismatch())
1049 continue;
John Thompson7c6e79f32013-07-29 19:07:00 +00001050 // Tell caller we found one or more errors.
John Thompson94faa4d2013-07-26 23:56:42 +00001051 ReturnValue = true;
John Thompson7c6e79f32013-07-29 19:07:00 +00001052 // Start the error message.
John Thompson94faa4d2013-07-26 23:56:42 +00001053 OS << *MacroExpTracker.InstanceSourceLine;
1054 if (ItemKey.Column > 0)
1055 OS << std::string(ItemKey.Column - 1, ' ') << "^\n";
1056 OS << "error: Macro instance '" << *MacroExpTracker.MacroUnexpanded
1057 << "' has different values in this header, depending on how it was "
1058 "included.\n";
John Thompson7c6e79f32013-07-29 19:07:00 +00001059 // Walk all the instances.
John Thompson94faa4d2013-07-26 23:56:42 +00001060 for (std::vector<MacroExpansionInstance>::iterator
1061 IMT = MacroExpTracker.MacroExpansionInstances.begin(),
1062 EMT = MacroExpTracker.MacroExpansionInstances.end();
1063 IMT != EMT; ++IMT) {
1064 MacroExpansionInstance &MacroInfo = *IMT;
1065 OS << " '" << *MacroExpTracker.MacroUnexpanded << "' expanded to: '"
1066 << *MacroInfo.MacroExpanded
1067 << "' with respect to these inclusion paths:\n";
John Thompson7c6e79f32013-07-29 19:07:00 +00001068 // Walk all the inclusion path hierarchies.
John Thompson94faa4d2013-07-26 23:56:42 +00001069 for (std::vector<InclusionPathHandle>::iterator
1070 IIP = MacroInfo.InclusionPathHandles.begin(),
1071 EIP = MacroInfo.InclusionPathHandles.end();
1072 IIP != EIP; ++IIP) {
1073 const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
1074 int Count = (int)ip.size();
1075 for (int Index = 0; Index < Count; ++Index) {
1076 HeaderHandle H = ip[Index];
1077 OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
1078 << "\n";
1079 }
1080 }
1081 // For a macro that wasn't defined, we flag it by using the
1082 // instance location.
1083 // If there is a definition...
1084 if (MacroInfo.DefinitionLocation.Line != ItemKey.Line) {
1085 OS << *MacroInfo.DefinitionSourceLine;
1086 if (MacroInfo.DefinitionLocation.Column > 0)
1087 OS << std::string(MacroInfo.DefinitionLocation.Column - 1, ' ')
1088 << "^\n";
1089 OS << "Macro defined here.\n";
1090 } else
1091 OS << "(no macro definition)"
1092 << "\n";
1093 }
1094 }
1095 return ReturnValue;
1096 }
1097
1098 // Report on inconsistent conditional instances.
1099 // Returns true if any mismatches.
1100 bool reportInconsistentConditionals(llvm::raw_ostream &OS) {
1101 bool ReturnValue = false;
John Thompson7c6e79f32013-07-29 19:07:00 +00001102 // Walk all the conditional trackers in the map.
John Thompson94faa4d2013-07-26 23:56:42 +00001103 for (ConditionalExpansionMapIter I = ConditionalExpansions.begin(),
1104 E = ConditionalExpansions.end();
1105 I != E; ++I) {
1106 const PPItemKey &ItemKey = I->first;
1107 ConditionalTracker &CondTracker = I->second;
1108 if (!CondTracker.hasMismatch())
1109 continue;
John Thompson7c6e79f32013-07-29 19:07:00 +00001110 // Tell caller we found one or more errors.
John Thompson94faa4d2013-07-26 23:56:42 +00001111 ReturnValue = true;
John Thompson7c6e79f32013-07-29 19:07:00 +00001112 // Start the error message.
John Thompson94faa4d2013-07-26 23:56:42 +00001113 OS << *HeaderPaths[ItemKey.File] << ":" << ItemKey.Line << ":"
1114 << ItemKey.Column << "\n";
1115 OS << "#" << getDirectiveSpelling(CondTracker.DirectiveKind) << " "
1116 << *CondTracker.ConditionUnexpanded << "\n";
1117 OS << "^\n";
1118 OS << "error: Conditional expression instance '"
1119 << *CondTracker.ConditionUnexpanded
1120 << "' has different values in this header, depending on how it was "
1121 "included.\n";
John Thompson7c6e79f32013-07-29 19:07:00 +00001122 // Walk all the instances.
John Thompson94faa4d2013-07-26 23:56:42 +00001123 for (std::vector<ConditionalExpansionInstance>::iterator
1124 IMT = CondTracker.ConditionalExpansionInstances.begin(),
1125 EMT = CondTracker.ConditionalExpansionInstances.end();
1126 IMT != EMT; ++IMT) {
1127 ConditionalExpansionInstance &MacroInfo = *IMT;
1128 OS << " '" << *CondTracker.ConditionUnexpanded << "' expanded to: '"
1129 << (MacroInfo.ConditionValue ? "true" : "false")
1130 << "' with respect to these inclusion paths:\n";
John Thompson7c6e79f32013-07-29 19:07:00 +00001131 // Walk all the inclusion path hierarchies.
John Thompson94faa4d2013-07-26 23:56:42 +00001132 for (std::vector<InclusionPathHandle>::iterator
1133 IIP = MacroInfo.InclusionPathHandles.begin(),
1134 EIP = MacroInfo.InclusionPathHandles.end();
1135 IIP != EIP; ++IIP) {
1136 const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
1137 int Count = (int)ip.size();
1138 for (int Index = 0; Index < Count; ++Index) {
1139 HeaderHandle H = ip[Index];
1140 OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
1141 << "\n";
1142 }
1143 }
1144 }
1145 }
1146 return ReturnValue;
1147 }
1148
1149 // Get directive spelling.
1150 static const char *getDirectiveSpelling(clang::tok::PPKeywordKind kind) {
1151 switch (kind) {
1152 case clang::tok::pp_if:
1153 return "if";
1154 case clang::tok::pp_elif:
1155 return "elif";
1156 case clang::tok::pp_ifdef:
1157 return "ifdef";
1158 case clang::tok::pp_ifndef:
1159 return "ifndef";
1160 default:
1161 return "(unknown)";
1162 }
1163 }
1164
1165private:
1166 llvm::StringPool Strings;
1167 std::vector<StringHandle> HeaderPaths;
1168 std::vector<HeaderHandle> HeaderStack;
1169 std::vector<HeaderInclusionPath> InclusionPaths;
1170 InclusionPathHandle CurrentInclusionPathHandle;
John Thompson4ed963a2013-08-07 18:49:47 +00001171 llvm::SmallSet<HeaderHandle, 128> HeadersInThisCompile;
John Thompson94faa4d2013-07-26 23:56:42 +00001172 MacroExpansionMap MacroExpansions;
1173 ConditionalExpansionMap ConditionalExpansions;
John Thompson48df0962013-08-05 23:55:14 +00001174 bool InNestedHeader;
John Thompson94faa4d2013-07-26 23:56:42 +00001175};
1176
1177// PreprocessorTracker functions.
1178
1179// PreprocessorTracker desctructor.
1180PreprocessorTracker::~PreprocessorTracker() {}
1181
1182// Create instance of PreprocessorTracker.
1183PreprocessorTracker *PreprocessorTracker::create() {
1184 return new PreprocessorTrackerImpl();
1185}
1186
1187// Preprocessor callbacks for modularize.
1188
1189// Handle file entry/exit.
1190void PreprocessorCallbacks::FileChanged(
1191 clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason,
1192 clang::SrcMgr::CharacteristicKind FileType, clang::FileID PrevFID) {
1193 switch (Reason) {
1194 case EnterFile:
1195 PPTracker.handleHeaderEntry(PP, getSourceLocationFile(PP, Loc));
1196 break;
1197 case ExitFile:
John Thompson48df0962013-08-05 23:55:14 +00001198 {
1199 const clang::FileEntry *F =
1200 PP.getSourceManager().getFileEntryForID(PrevFID);
1201 if (F != NULL)
1202 PPTracker.handleHeaderExit(F->getName());
1203 }
John Thompson94faa4d2013-07-26 23:56:42 +00001204 break;
1205 case SystemHeaderPragma:
John Thompson94faa4d2013-07-26 23:56:42 +00001206 case RenameFile:
Benjamin Kramerf2576812013-07-27 15:57:46 +00001207 break;
John Thompson94faa4d2013-07-26 23:56:42 +00001208 }
1209}
1210
1211// Handle macro expansion.
1212void PreprocessorCallbacks::MacroExpands(const clang::Token &MacroNameTok,
1213 const clang::MacroDirective *MD,
1214 clang::SourceRange Range,
1215 const clang::MacroArgs *Args) {
1216 clang::SourceLocation Loc = Range.getBegin();
1217 clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
1218 const clang::MacroInfo *MI = PP.getMacroInfo(II);
1219 std::string MacroName = II->getName().str();
1220 std::string Unexpanded(getMacroUnexpandedString(Range, PP, MacroName, MI));
1221 std::string Expanded(getMacroExpandedString(PP, MacroName, MI, Args));
1222 PPTracker.addMacroExpansionInstance(
1223 PP, PPTracker.getCurrentHeaderHandle(), Loc, MI->getDefinitionLoc(), II,
1224 Unexpanded, Expanded, PPTracker.getCurrentInclusionPathHandle());
1225}
1226
1227void PreprocessorCallbacks::Defined(const clang::Token &MacroNameTok,
1228 const clang::MacroDirective *MD,
1229 clang::SourceRange Range) {
1230 clang::SourceLocation Loc(Range.getBegin());
1231 clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
1232 const clang::MacroInfo *MI = PP.getMacroInfo(II);
1233 std::string MacroName = II->getName().str();
1234 std::string Unexpanded(getSourceString(PP, Range));
1235 PPTracker.addMacroExpansionInstance(
1236 PP, PPTracker.getCurrentHeaderHandle(), Loc,
1237 (MI ? MI->getDefinitionLoc() : Loc), II, Unexpanded,
1238 (MI ? "true" : "false"), PPTracker.getCurrentInclusionPathHandle());
1239}
1240
1241void PreprocessorCallbacks::If(clang::SourceLocation Loc,
1242 clang::SourceRange ConditionRange,
1243 bool ConditionResult) {
1244 std::string Unexpanded(getSourceString(PP, ConditionRange));
1245 PPTracker.addConditionalExpansionInstance(
1246 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_if,
1247 ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
1248}
1249
1250void PreprocessorCallbacks::Elif(clang::SourceLocation Loc,
1251 clang::SourceRange ConditionRange,
1252 bool ConditionResult,
1253 clang::SourceLocation IfLoc) {
1254 std::string Unexpanded(getSourceString(PP, ConditionRange));
1255 PPTracker.addConditionalExpansionInstance(
1256 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_elif,
1257 ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
1258}
1259
1260void PreprocessorCallbacks::Ifdef(clang::SourceLocation Loc,
1261 const clang::Token &MacroNameTok,
1262 const clang::MacroDirective *MD) {
1263 bool IsDefined = (MD != 0);
1264 PPTracker.addConditionalExpansionInstance(
1265 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifdef,
1266 IsDefined, PP.getSpelling(MacroNameTok),
1267 PPTracker.getCurrentInclusionPathHandle());
1268}
1269
1270void PreprocessorCallbacks::Ifndef(clang::SourceLocation Loc,
1271 const clang::Token &MacroNameTok,
1272 const clang::MacroDirective *MD) {
1273 bool IsNotDefined = (MD == 0);
1274 PPTracker.addConditionalExpansionInstance(
1275 PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifndef,
1276 IsNotDefined, PP.getSpelling(MacroNameTok),
1277 PPTracker.getCurrentInclusionPathHandle());
1278}
1279} // end namespace Modularize