1 //===--- PreprocessorTracker.cpp - Preprocessor tracking -*- C++ -*------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===--------------------------------------------------------------------===//
9 // The Basic Idea (Macro and Conditional Checking)
11 // Basically we install a PPCallbacks-derived object to track preprocessor
12 // activity, namely when a header file is entered/exited, when a macro
13 // is expanded, when "defined" is used, and when #if, #elif, #ifdef,
14 // and #ifndef are used. We save the state of macro and "defined"
15 // expressions in a map, keyed on a name/file/line/column quadruple.
16 // The map entries store the different states (values) that a macro expansion,
17 // "defined" expression, or condition expression has in the course of
18 // processing for the one location in the one header containing it,
19 // plus a list of the nested include stacks for the states. When a macro
20 // or "defined" expression evaluates to the same value, which is the
21 // desired case, only one state is stored. Similarly, for conditional
22 // directives, we save the condition expression states in a separate map.
24 // This information is collected as modularize compiles all the headers
25 // given to it to process. After all the compilations are performed,
26 // a check is performed for any entries in the maps that contain more
27 // than one different state, and for these an output message is generated.
31 // (...)/SubHeader.h:11:5:
34 // error: Macro instance 'SYMBOL' has different values in this header,
35 // depending on how it was included.
36 // 'SYMBOL' expanded to: '1' with respect to these inclusion paths:
39 // (...)/SubHeader.h:3:9:
42 // Macro defined here.
43 // 'SYMBOL' expanded to: '2' with respect to these inclusion paths:
46 // (...)/SubHeader.h:7:9:
49 // Macro defined here.
51 // The Basic Idea ('Extern "C/C++" {}' Or 'namespace {}') With Nested
52 // '#include' Checking)
54 // To check for '#include' directives nested inside 'Extern "C/C++" {}'
55 // or 'namespace {}' blocks, we keep track of the '#include' directives
56 // while running the preprocessor, and later during a walk of the AST
57 // we call a function to check for any '#include' directives inside
58 // an 'Extern "C/C++" {}' or 'namespace {}' block, given its source
61 // Design and Implementation Details (Macro and Conditional Checking)
63 // A PreprocessorTrackerImpl class implements the PreprocessorTracker
64 // interface. It uses a PreprocessorCallbacks class derived from PPCallbacks
65 // to track preprocessor activity, namely entering/exiting a header, macro
66 // expansions, use of "defined" expressions, and #if, #elif, #ifdef, and
67 // #ifndef conditional directives. PreprocessorTrackerImpl stores a map
68 // of MacroExpansionTracker objects keyed on a name/file/line/column
69 // value represented by a light-weight PPItemKey value object. This
70 // is the key top-level data structure tracking the values of macro
71 // expansion instances. Similarly, it stores a map of ConditionalTracker
72 // objects with the same kind of key, for tracking preprocessor conditional
75 // The MacroExpansionTracker object represents one macro reference or use
76 // of a "defined" expression in a header file. It stores a handle to a
77 // string representing the unexpanded macro instance, a handle to a string
78 // representing the unpreprocessed source line containing the unexpanded
79 // macro instance, and a vector of one or more MacroExpansionInstance
82 // The MacroExpansionInstance object represents one or more expansions
83 // of a macro reference, for the case where the macro expands to the same
84 // value. MacroExpansionInstance stores a handle to a string representing
85 // the expanded macro value, a PPItemKey representing the file/line/column
86 // where the macro was defined, a handle to a string representing the source
87 // line containing the macro definition, and a vector of InclusionPathHandle
88 // values that represents the hierarchies of include files for each case
89 // where the particular header containing the macro reference was referenced
92 // In the normal case where a macro instance always expands to the same
93 // value, the MacroExpansionTracker object will only contain one
94 // MacroExpansionInstance representing all the macro expansion instances.
95 // If a case was encountered where a macro instance expands to a value
96 // that is different from that seen before, or the macro was defined in
97 // a different place, a new MacroExpansionInstance object representing
98 // that case will be added to the vector in MacroExpansionTracker. If a
99 // macro instance expands to a value already seen before, the
100 // InclusionPathHandle representing that case's include file hierarchy
101 // will be added to the existing MacroExpansionInstance object.
103 // For checking conditional directives, the ConditionalTracker class
104 // functions similarly to MacroExpansionTracker, but tracks an #if,
105 // #elif, #ifdef, or #ifndef directive in a header file. It stores
106 // a vector of one or two ConditionalExpansionInstance objects,
107 // representing the cases where the conditional expression evaluates
108 // to true or false. This latter object stores the evaluated value
109 // of the condition expression (a bool) and a vector of
110 // InclusionPathHandles.
112 // To reduce the instances of string and object copying, the
113 // PreprocessorTrackerImpl class uses a StringPool to save all stored
114 // strings, and defines a StringHandle type to abstract the references
117 // PreprocessorTrackerImpl also maintains a list representing the unique
118 // headers, which is just a vector of StringHandle's for the header file
119 // paths. A HeaderHandle abstracts a reference to a header, and is simply
120 // the index of the stored header file path.
122 // A HeaderInclusionPath class abstracts a unique hierarchy of header file
123 // inclusions. It simply stores a vector of HeaderHandles ordered from the
124 // top-most header (the one from the header list passed to modularize) down
125 // to the header containing the macro reference. PreprocessorTrackerImpl
126 // stores a vector of these objects. An InclusionPathHandle typedef
127 // abstracts a reference to one of the HeaderInclusionPath objects, and is
128 // simply the index of the stored HeaderInclusionPath object. The
129 // MacroExpansionInstance object stores a vector of these handles so that
130 // the reporting function can display the include hierarchies for the macro
131 // expansion instances represented by that object, to help the user
132 // understand how the header was included. (A future enhancement might
133 // be to associate a line number for the #include directives, but I
134 // think not doing so is good enough for the present.)
136 // A key reason for using these opaque handles was to try to keep all the
137 // internal objects light-weight value objects, in order to reduce string
138 // and object copying overhead, and to abstract this implementation detail.
140 // The key data structures are built up while modularize runs the headers
141 // through the compilation. A PreprocessorTracker instance is created and
142 // passed down to the AST action and consumer objects in modularize. For
143 // each new compilation instance, the consumer calls the
144 // PreprocessorTracker's handleNewPreprocessorEntry function, which sets
145 // up a PreprocessorCallbacks object for the preprocessor. At the end of
146 // the compilation instance, the PreprocessorTracker's
147 // handleNewPreprocessorExit function handles cleaning up with respect
148 // to the preprocessing instance.
150 // The PreprocessorCallbacks object uses an overridden FileChanged callback
151 // to determine when a header is entered and exited (including exiting the
152 // header during #include directives). It calls PreprocessorTracker's
153 // handleHeaderEntry and handleHeaderExit functions upon entering and
154 // exiting a header. These functions manage a stack of header handles
155 // representing by a vector, pushing and popping header handles as headers
156 // are entered and exited. When a HeaderInclusionPath object is created,
157 // it simply copies this stack.
159 // The PreprocessorCallbacks object uses an overridden MacroExpands callback
160 // to track when a macro expansion is performed. It calls a couple of helper
161 // functions to get the unexpanded and expanded macro values as strings, but
162 // then calls PreprocessorTrackerImpl's addMacroExpansionInstance function to
163 // do the rest of the work. The getMacroExpandedString function uses the
164 // preprocessor's getSpelling to convert tokens to strings using the
165 // information passed to the MacroExpands callback, and simply concatenates
166 // them. It makes recursive calls to itself to handle nested macro
167 // definitions, and also handles function-style macros.
169 // PreprocessorTrackerImpl's addMacroExpansionInstance function looks for
170 // an existing MacroExpansionTracker entry in its map of MacroExampleTracker
171 // objects. If none exists, it adds one with one MacroExpansionInstance and
172 // returns. If a MacroExpansionTracker object already exists, it looks for
173 // an existing MacroExpansionInstance object stored in the
174 // MacroExpansionTracker object, one that matches the macro expanded value
175 // and the macro definition location. If a matching MacroExpansionInstance
176 // object is found, it just adds the current HeaderInclusionPath object to
177 // it. If not found, it creates and stores a new MacroExpansionInstance
178 // object. The addMacroExpansionInstance function calls a couple of helper
179 // functions to get the pre-formatted location and source line strings for
180 // the macro reference and the macro definition stored as string handles.
181 // These helper functions use the current source manager from the
182 // preprocessor. This is done in advance at this point in time because the
183 // source manager doesn't exist at the time of the reporting.
185 // For conditional check, the PreprocessorCallbacks class overrides the
186 // PPCallbacks handlers for #if, #elif, #ifdef, and #ifndef. These handlers
187 // call the addConditionalExpansionInstance method of
188 // PreprocessorTrackerImpl. The process is similar to that of macros, but
189 // with some different data and error messages. A lookup is performed for
190 // the conditional, and if a ConditionalTracker object doesn't yet exist for
191 // the conditional, a new one is added, including adding a
192 // ConditionalExpansionInstance object to it to represent the condition
193 // expression state. If a ConditionalTracker for the conditional does
194 // exist, a lookup is made for a ConditionalExpansionInstance object
195 // matching the condition expression state. If one exists, a
196 // HeaderInclusionPath is added to it. Otherwise a new
197 // ConditionalExpansionInstance entry is made. If a ConditionalTracker
198 // has two ConditionalExpansionInstance objects, it means there was a
199 // conflict, meaning the conditional expression evaluated differently in
200 // one or more cases.
202 // After modularize has performed all the compilations, it enters a phase
203 // of error reporting. This new feature adds to this reporting phase calls
204 // to the PreprocessorTracker's reportInconsistentMacros and
205 // reportInconsistentConditionals functions. These functions walk the maps
206 // of MacroExpansionTracker's and ConditionalTracker's respectively. If
207 // any of these objects have more than one MacroExpansionInstance or
208 // ConditionalExpansionInstance objects, it formats and outputs an error
209 // message like the example shown previously, using the stored data.
211 // A potential issue is that there is some overlap between the #if/#elif
212 // conditional and macro reporting. I could disable the #if and #elif,
213 // leaving just the #ifdef and #ifndef, since these don't overlap. Or,
214 // to make clearer the separate reporting phases, I could add an output
215 // message marking the phases.
217 // Design and Implementation Details ('Extern "C/C++" {}' Or
218 // 'namespace {}') With Nested '#include' Checking)
220 // We override the InclusionDirective in PPCallbacks to record information
221 // about each '#include' directive encountered during preprocessing.
222 // We co-opt the PPItemKey class to store the information about each
223 // '#include' directive, including the source file name containing the
224 // directive, the name of the file being included, and the source line
225 // and column of the directive. We store these object in a vector,
226 // after first check to see if an entry already exists.
228 // Later, while the AST is being walked for other checks, we provide
229 // visit handlers for 'extern "C/C++" {}' and 'namespace (name) {}'
230 // blocks, checking to see if any '#include' directives occurred
231 // within the blocks, reporting errors if any found.
235 // We probably should add options to disable any of the checks, in case
236 // there is some problem with them, or the messages get too verbose.
238 // With the map of all the macro and conditional expansion instances,
239 // it might be possible to add to the existing modularize error messages
240 // (the second part referring to definitions being different), attempting
241 // to tie them to the last macro conflict encountered with respect to the
242 // order of the code encountered.
244 //===--------------------------------------------------------------------===//
246 #include "PreprocessorTracker.h"
247 #include "ModularizeUtilities.h"
248 #include "clang/Lex/LexDiagnostic.h"
249 #include "clang/Lex/MacroArgs.h"
250 #include "clang/Lex/PPCallbacks.h"
251 #include "llvm/ADT/SmallSet.h"
252 #include "llvm/ADT/StringSet.h"
253 #include "llvm/Support/raw_ostream.h"
255 namespace Modularize
{
258 typedef llvm::StringRef StringHandle
;
260 typedef int HeaderHandle
;
261 const HeaderHandle HeaderHandleInvalid
= -1;
263 typedef int InclusionPathHandle
;
264 const InclusionPathHandle InclusionPathHandleInvalid
= -1;
266 // Some utility functions.
268 // Get a "file:line:column" source location string.
269 static std::string
getSourceLocationString(clang::Preprocessor
&PP
,
270 clang::SourceLocation Loc
) {
272 return std::string("(none)");
274 return Loc
.printToString(PP
.getSourceManager());
277 // Get just the file name from a source location.
278 static std::string
getSourceLocationFile(clang::Preprocessor
&PP
,
279 clang::SourceLocation Loc
) {
280 std::string
Source(getSourceLocationString(PP
, Loc
));
281 size_t Offset
= Source
.find(':', 2);
282 if (Offset
== std::string::npos
)
284 return Source
.substr(0, Offset
);
287 // Get just the line and column from a source location.
288 static void getSourceLocationLineAndColumn(clang::Preprocessor
&PP
,
289 clang::SourceLocation Loc
, int &Line
,
291 clang::PresumedLoc PLoc
= PP
.getSourceManager().getPresumedLoc(Loc
);
292 if (PLoc
.isInvalid()) {
297 Line
= PLoc
.getLine();
298 Column
= PLoc
.getColumn();
301 // Retrieve source snippet from file image.
302 static std::string
getSourceString(clang::Preprocessor
&PP
,
303 clang::SourceRange Range
) {
304 clang::SourceLocation BeginLoc
= Range
.getBegin();
305 clang::SourceLocation EndLoc
= Range
.getEnd();
306 const char *BeginPtr
= PP
.getSourceManager().getCharacterData(BeginLoc
);
307 const char *EndPtr
= PP
.getSourceManager().getCharacterData(EndLoc
);
308 size_t Length
= EndPtr
- BeginPtr
;
309 return llvm::StringRef(BeginPtr
, Length
).trim().str();
312 // Retrieve source line from file image given a location.
313 static std::string
getSourceLine(clang::Preprocessor
&PP
,
314 clang::SourceLocation Loc
) {
315 llvm::MemoryBufferRef MemBuffer
= PP
.getSourceManager().getBufferOrFake(
316 PP
.getSourceManager().getFileID(Loc
));
317 const char *Buffer
= MemBuffer
.getBufferStart();
318 const char *BufferEnd
= MemBuffer
.getBufferEnd();
319 const char *BeginPtr
= PP
.getSourceManager().getCharacterData(Loc
);
320 const char *EndPtr
= BeginPtr
;
321 while (BeginPtr
> Buffer
) {
322 if (*BeginPtr
== '\n') {
328 while (EndPtr
< BufferEnd
) {
329 if (*EndPtr
== '\n') {
334 size_t Length
= EndPtr
- BeginPtr
;
335 return llvm::StringRef(BeginPtr
, Length
).str();
338 // Retrieve source line from file image given a file ID and line number.
339 static std::string
getSourceLine(clang::Preprocessor
&PP
, clang::FileID FileID
,
341 llvm::MemoryBufferRef MemBuffer
=
342 PP
.getSourceManager().getBufferOrFake(FileID
);
343 const char *Buffer
= MemBuffer
.getBufferStart();
344 const char *BufferEnd
= MemBuffer
.getBufferEnd();
345 const char *BeginPtr
= Buffer
;
346 const char *EndPtr
= BufferEnd
;
351 while (Buffer
< BufferEnd
) {
352 if (*Buffer
== '\n') {
353 if (++LineCounter
== Line
) {
354 BeginPtr
= Buffer
++ + 1;
361 while (Buffer
< BufferEnd
) {
362 if (*Buffer
== '\n') {
368 size_t Length
= EndPtr
- BeginPtr
;
369 return llvm::StringRef(BeginPtr
, Length
).str();
372 // Get the string for the Unexpanded macro instance.
373 // The sourceRange is expected to end at the last token
374 // for the macro instance, which in the case of a function-style
375 // macro will be a ')', but for an object-style macro, it
376 // will be the macro name itself.
377 static std::string
getMacroUnexpandedString(clang::SourceRange Range
,
378 clang::Preprocessor
&PP
,
379 llvm::StringRef MacroName
,
380 const clang::MacroInfo
*MI
) {
381 clang::SourceLocation
BeginLoc(Range
.getBegin());
382 const char *BeginPtr
= PP
.getSourceManager().getCharacterData(BeginLoc
);
384 std::string Unexpanded
;
385 if (MI
->isFunctionLike()) {
386 clang::SourceLocation
EndLoc(Range
.getEnd());
387 const char *EndPtr
= PP
.getSourceManager().getCharacterData(EndLoc
) + 1;
388 Length
= (EndPtr
- BeginPtr
) + 1; // +1 is ')' width.
390 Length
= MacroName
.size();
391 return llvm::StringRef(BeginPtr
, Length
).trim().str();
394 // Get the expansion for a macro instance, given the information
395 // provided by PPCallbacks.
396 // FIXME: This doesn't support function-style macro instances
397 // passed as arguments to another function-style macro. However,
398 // since it still expands the inner arguments, it still
399 // allows modularize to effectively work with respect to macro
400 // consistency checking, although it displays the incorrect
401 // expansion in error messages.
402 static std::string
getMacroExpandedString(clang::Preprocessor
&PP
,
403 llvm::StringRef MacroName
,
404 const clang::MacroInfo
*MI
,
405 const clang::MacroArgs
*Args
) {
406 std::string Expanded
;
407 // Walk over the macro Tokens.
408 for (const auto &T
: MI
->tokens()) {
409 clang::IdentifierInfo
*II
= T
.getIdentifierInfo();
410 int ArgNo
= (II
&& Args
? MI
->getParameterNum(II
) : -1);
412 // This isn't an argument, just add it.
414 Expanded
+= PP
.getSpelling(T
); // Not an identifier.
416 // Token is for an identifier.
417 std::string Name
= II
->getName().str();
418 // Check for nexted macro references.
419 clang::MacroInfo
*MacroInfo
= PP
.getMacroInfo(II
);
420 if (MacroInfo
&& (Name
!= MacroName
))
421 Expanded
+= getMacroExpandedString(PP
, Name
, MacroInfo
, nullptr);
427 // We get here if it's a function-style macro with arguments.
428 const clang::Token
*ResultArgToks
;
429 const clang::Token
*ArgTok
= Args
->getUnexpArgument(ArgNo
);
430 if (Args
->ArgNeedsPreexpansion(ArgTok
, PP
))
431 ResultArgToks
= &(const_cast<clang::MacroArgs
*>(Args
))
432 ->getPreExpArgument(ArgNo
, PP
)[0];
434 ResultArgToks
= ArgTok
; // Use non-preexpanded Tokens.
435 // If the arg token didn't expand into anything, ignore it.
436 if (ResultArgToks
->is(clang::tok::eof
))
438 unsigned NumToks
= clang::MacroArgs::getArgLength(ResultArgToks
);
439 // Append the resulting argument expansions.
440 for (unsigned ArgumentIndex
= 0; ArgumentIndex
< NumToks
; ++ArgumentIndex
) {
441 const clang::Token
&AT
= ResultArgToks
[ArgumentIndex
];
442 clang::IdentifierInfo
*II
= AT
.getIdentifierInfo();
444 Expanded
+= PP
.getSpelling(AT
); // Not an identifier.
446 // It's an identifier. Check for further expansion.
447 std::string Name
= II
->getName().str();
448 clang::MacroInfo
*MacroInfo
= PP
.getMacroInfo(II
);
450 Expanded
+= getMacroExpandedString(PP
, Name
, MacroInfo
, nullptr);
461 // ConditionValueKind strings.
463 ConditionValueKindStrings
[] = {
464 "(not evaluated)", "false", "true"
467 // Preprocessor item key.
469 // This class represents a location in a source file, for use
470 // as a key representing a unique name/file/line/column quadruplet,
471 // which in this case is used to identify a macro expansion instance,
472 // but could be used for other things as well.
473 // The file is a header file handle, the line is a line number,
474 // and the column is a column number.
477 PPItemKey(clang::Preprocessor
&PP
, StringHandle Name
, HeaderHandle File
,
478 clang::SourceLocation Loc
)
479 : Name(Name
), File(File
) {
480 getSourceLocationLineAndColumn(PP
, Loc
, Line
, Column
);
482 PPItemKey(StringHandle Name
, HeaderHandle File
, int Line
, int Column
)
483 : Name(Name
), File(File
), Line(Line
), Column(Column
) {}
484 PPItemKey(const PPItemKey
&Other
)
485 : Name(Other
.Name
), File(Other
.File
), Line(Other
.Line
),
486 Column(Other
.Column
) {}
487 PPItemKey() : File(HeaderHandleInvalid
), Line(0), Column(0) {}
488 bool operator==(const PPItemKey
&Other
) const {
489 if (Name
!= Other
.Name
)
491 if (File
!= Other
.File
)
493 if (Line
!= Other
.Line
)
495 return Column
== Other
.Column
;
497 bool operator<(const PPItemKey
&Other
) const {
498 if (Name
< Other
.Name
)
500 else if (Name
> Other
.Name
)
502 if (File
< Other
.File
)
504 else if (File
> Other
.File
)
506 if (Line
< Other
.Line
)
508 else if (Line
> Other
.Line
)
510 return Column
< Other
.Column
;
518 // Header inclusion path.
519 class HeaderInclusionPath
{
521 HeaderInclusionPath(std::vector
<HeaderHandle
> HeaderInclusionPath
)
522 : Path(HeaderInclusionPath
) {}
523 HeaderInclusionPath(const HeaderInclusionPath
&Other
) : Path(Other
.Path
) {}
524 HeaderInclusionPath() {}
525 std::vector
<HeaderHandle
> Path
;
528 // Macro expansion instance.
530 // This class represents an instance of a macro expansion with a
531 // unique value. It also stores the unique header inclusion paths
532 // for use in telling the user the nested include path to the header.
533 class MacroExpansionInstance
{
535 MacroExpansionInstance(StringHandle MacroExpanded
,
536 PPItemKey
&DefinitionLocation
,
537 StringHandle DefinitionSourceLine
,
538 InclusionPathHandle H
)
539 : MacroExpanded(MacroExpanded
), DefinitionLocation(DefinitionLocation
),
540 DefinitionSourceLine(DefinitionSourceLine
) {
541 InclusionPathHandles
.push_back(H
);
543 MacroExpansionInstance() {}
545 // Check for the presence of a header inclusion path handle entry.
546 // Return false if not found.
547 bool haveInclusionPathHandle(InclusionPathHandle H
) {
548 for (auto I
= InclusionPathHandles
.begin(), E
= InclusionPathHandles
.end();
553 return InclusionPathHandleInvalid
;
555 // Add a new header inclusion path entry, if not already present.
556 void addInclusionPathHandle(InclusionPathHandle H
) {
557 if (!haveInclusionPathHandle(H
))
558 InclusionPathHandles
.push_back(H
);
561 // A string representing the macro instance after preprocessing.
562 StringHandle MacroExpanded
;
563 // A file/line/column triplet representing the macro definition location.
564 PPItemKey DefinitionLocation
;
565 // A place to save the macro definition line string.
566 StringHandle DefinitionSourceLine
;
567 // The header inclusion path handles for all the instances.
568 std::vector
<InclusionPathHandle
> InclusionPathHandles
;
571 // Macro expansion instance tracker.
573 // This class represents one macro expansion, keyed by a PPItemKey.
574 // It stores a string representing the macro reference in the source,
575 // and a list of ConditionalExpansionInstances objects representing
576 // the unique values the condition expands to in instances of the header.
577 class MacroExpansionTracker
{
579 MacroExpansionTracker(StringHandle MacroUnexpanded
,
580 StringHandle MacroExpanded
,
581 StringHandle InstanceSourceLine
,
582 PPItemKey
&DefinitionLocation
,
583 StringHandle DefinitionSourceLine
,
584 InclusionPathHandle InclusionPathHandle
)
585 : MacroUnexpanded(MacroUnexpanded
),
586 InstanceSourceLine(InstanceSourceLine
) {
587 addMacroExpansionInstance(MacroExpanded
, DefinitionLocation
,
588 DefinitionSourceLine
, InclusionPathHandle
);
590 MacroExpansionTracker() {}
592 // Find a matching macro expansion instance.
593 MacroExpansionInstance
*
594 findMacroExpansionInstance(StringHandle MacroExpanded
,
595 PPItemKey
&DefinitionLocation
) {
596 for (auto I
= MacroExpansionInstances
.begin(),
597 E
= MacroExpansionInstances
.end();
599 if ((I
->MacroExpanded
== MacroExpanded
) &&
600 (I
->DefinitionLocation
== DefinitionLocation
)) {
601 return &*I
; // Found.
604 return nullptr; // Not found.
607 // Add a macro expansion instance.
608 void addMacroExpansionInstance(StringHandle MacroExpanded
,
609 PPItemKey
&DefinitionLocation
,
610 StringHandle DefinitionSourceLine
,
611 InclusionPathHandle InclusionPathHandle
) {
612 MacroExpansionInstances
.push_back(
613 MacroExpansionInstance(MacroExpanded
, DefinitionLocation
,
614 DefinitionSourceLine
, InclusionPathHandle
));
617 // Return true if there is a mismatch.
618 bool hasMismatch() { return MacroExpansionInstances
.size() > 1; }
620 // A string representing the macro instance without expansion.
621 StringHandle MacroUnexpanded
;
622 // A place to save the macro instance source line string.
623 StringHandle InstanceSourceLine
;
624 // The macro expansion instances.
625 // If all instances of the macro expansion expand to the same value,
626 // This vector will only have one instance.
627 std::vector
<MacroExpansionInstance
> MacroExpansionInstances
;
630 // Conditional expansion instance.
632 // This class represents an instance of a condition exoression result
633 // with a unique value. It also stores the unique header inclusion paths
634 // for use in telling the user the nested include path to the header.
635 class ConditionalExpansionInstance
{
637 ConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue
, InclusionPathHandle H
)
638 : ConditionValue(ConditionValue
) {
639 InclusionPathHandles
.push_back(H
);
641 ConditionalExpansionInstance() {}
643 // Check for the presence of a header inclusion path handle entry.
644 // Return false if not found.
645 bool haveInclusionPathHandle(InclusionPathHandle H
) {
646 for (auto I
= InclusionPathHandles
.begin(), E
= InclusionPathHandles
.end();
651 return InclusionPathHandleInvalid
;
653 // Add a new header inclusion path entry, if not already present.
654 void addInclusionPathHandle(InclusionPathHandle H
) {
655 if (!haveInclusionPathHandle(H
))
656 InclusionPathHandles
.push_back(H
);
659 // A flag representing the evaluated condition value.
660 clang::PPCallbacks::ConditionValueKind ConditionValue
;
661 // The header inclusion path handles for all the instances.
662 std::vector
<InclusionPathHandle
> InclusionPathHandles
;
665 // Conditional directive instance tracker.
667 // This class represents one conditional directive, keyed by a PPItemKey.
668 // It stores a string representing the macro reference in the source,
669 // and a list of ConditionExpansionInstance objects representing
670 // the unique value the condition expression expands to in instances of
672 class ConditionalTracker
{
674 ConditionalTracker(clang::tok::PPKeywordKind DirectiveKind
,
675 clang::PPCallbacks::ConditionValueKind ConditionValue
,
676 StringHandle ConditionUnexpanded
,
677 InclusionPathHandle InclusionPathHandle
)
678 : DirectiveKind(DirectiveKind
), ConditionUnexpanded(ConditionUnexpanded
) {
679 addConditionalExpansionInstance(ConditionValue
, InclusionPathHandle
);
681 ConditionalTracker() {}
683 // Find a matching condition expansion instance.
684 ConditionalExpansionInstance
*
685 findConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue
) {
686 for (auto I
= ConditionalExpansionInstances
.begin(),
687 E
= ConditionalExpansionInstances
.end();
689 if (I
->ConditionValue
== ConditionValue
) {
690 return &*I
; // Found.
693 return nullptr; // Not found.
696 // Add a conditional expansion instance.
698 addConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue
,
699 InclusionPathHandle InclusionPathHandle
) {
700 ConditionalExpansionInstances
.push_back(
701 ConditionalExpansionInstance(ConditionValue
, InclusionPathHandle
));
704 // Return true if there is a mismatch.
705 bool hasMismatch() { return ConditionalExpansionInstances
.size() > 1; }
707 // The kind of directive.
708 clang::tok::PPKeywordKind DirectiveKind
;
709 // A string representing the macro instance without expansion.
710 StringHandle ConditionUnexpanded
;
711 // The condition expansion instances.
712 // If all instances of the conditional expression expand to the same value,
713 // This vector will only have one instance.
714 std::vector
<ConditionalExpansionInstance
> ConditionalExpansionInstances
;
717 class PreprocessorTrackerImpl
;
719 // Preprocessor callbacks for modularize.
721 // This class derives from the Clang PPCallbacks class to track preprocessor
722 // actions, such as changing files and handling preprocessor directives and
723 // macro expansions. It has to figure out when a new header file is entered
724 // and left, as the provided handler is not particularly clear about it.
725 class PreprocessorCallbacks
: public clang::PPCallbacks
{
727 PreprocessorCallbacks(PreprocessorTrackerImpl
&ppTracker
,
728 clang::Preprocessor
&PP
, llvm::StringRef rootHeaderFile
)
729 : PPTracker(ppTracker
), PP(PP
), RootHeaderFile(rootHeaderFile
) {}
730 ~PreprocessorCallbacks() override
{}
732 // Overridden handlers.
734 InclusionDirective(clang::SourceLocation HashLoc
,
735 const clang::Token
&IncludeTok
, llvm::StringRef FileName
,
736 bool IsAngled
, clang::CharSourceRange FilenameRange
,
737 clang::OptionalFileEntryRef File
,
738 llvm::StringRef SearchPath
, llvm::StringRef RelativePath
,
739 const clang::Module
*SuggestedModule
, bool ModuleImported
,
740 clang::SrcMgr::CharacteristicKind FileType
) override
;
741 void FileChanged(clang::SourceLocation Loc
,
742 clang::PPCallbacks::FileChangeReason Reason
,
743 clang::SrcMgr::CharacteristicKind FileType
,
744 clang::FileID PrevFID
= clang::FileID()) override
;
745 void MacroExpands(const clang::Token
&MacroNameTok
,
746 const clang::MacroDefinition
&MD
, clang::SourceRange Range
,
747 const clang::MacroArgs
*Args
) override
;
748 void Defined(const clang::Token
&MacroNameTok
,
749 const clang::MacroDefinition
&MD
,
750 clang::SourceRange Range
) override
;
751 void If(clang::SourceLocation Loc
, clang::SourceRange ConditionRange
,
752 clang::PPCallbacks::ConditionValueKind ConditionResult
) override
;
753 void Elif(clang::SourceLocation Loc
, clang::SourceRange ConditionRange
,
754 clang::PPCallbacks::ConditionValueKind ConditionResult
,
755 clang::SourceLocation IfLoc
) override
;
756 void Ifdef(clang::SourceLocation Loc
, const clang::Token
&MacroNameTok
,
757 const clang::MacroDefinition
&MD
) override
;
758 void Ifndef(clang::SourceLocation Loc
, const clang::Token
&MacroNameTok
,
759 const clang::MacroDefinition
&MD
) override
;
762 PreprocessorTrackerImpl
&PPTracker
;
763 clang::Preprocessor
&PP
;
764 std::string RootHeaderFile
;
767 // Preprocessor macro expansion item map types.
768 typedef std::map
<PPItemKey
, MacroExpansionTracker
> MacroExpansionMap
;
769 typedef std::map
<PPItemKey
, MacroExpansionTracker
>::iterator
770 MacroExpansionMapIter
;
772 // Preprocessor conditional expansion item map types.
773 typedef std::map
<PPItemKey
, ConditionalTracker
> ConditionalExpansionMap
;
774 typedef std::map
<PPItemKey
, ConditionalTracker
>::iterator
775 ConditionalExpansionMapIter
;
777 // Preprocessor tracker for modularize.
779 // This class stores information about all the headers processed in the
780 // course of running modularize.
781 class PreprocessorTrackerImpl
: public PreprocessorTracker
{
783 PreprocessorTrackerImpl(llvm::SmallVector
<std::string
, 32> &Headers
,
784 bool DoBlockCheckHeaderListOnly
)
785 : BlockCheckHeaderListOnly(DoBlockCheckHeaderListOnly
),
786 CurrentInclusionPathHandle(InclusionPathHandleInvalid
),
787 InNestedHeader(false) {
788 // Use canonical header path representation.
789 for (llvm::ArrayRef
<std::string
>::iterator I
= Headers
.begin(),
792 HeaderList
.push_back(getCanonicalPath(*I
));
796 ~PreprocessorTrackerImpl() override
{}
798 // Handle entering a preprocessing session.
799 void handlePreprocessorEntry(clang::Preprocessor
&PP
,
800 llvm::StringRef rootHeaderFile
) override
{
801 HeadersInThisCompile
.clear();
802 assert((HeaderStack
.size() == 0) && "Header stack should be empty.");
803 pushHeaderHandle(addHeader(rootHeaderFile
));
804 PP
.addPPCallbacks(std::make_unique
<PreprocessorCallbacks
>(*this, PP
,
807 // Handle exiting a preprocessing session.
808 void handlePreprocessorExit() override
{ HeaderStack
.clear(); }
810 // Handle include directive.
811 // This function is called every time an include directive is seen by the
812 // preprocessor, for the purpose of later checking for 'extern "" {}' or
813 // "namespace {}" blocks containing #include directives.
814 void handleIncludeDirective(llvm::StringRef DirectivePath
, int DirectiveLine
,
816 llvm::StringRef TargetPath
) override
{
817 // If it's not a header in the header list, ignore it with respect to
819 if (BlockCheckHeaderListOnly
&& !isHeaderListHeader(TargetPath
))
821 HeaderHandle CurrentHeaderHandle
= findHeaderHandle(DirectivePath
);
822 StringHandle IncludeHeaderHandle
= addString(TargetPath
);
823 for (std::vector
<PPItemKey
>::const_iterator I
= IncludeDirectives
.begin(),
824 E
= IncludeDirectives
.end();
826 // If we already have an entry for this directive, return now.
827 if ((I
->File
== CurrentHeaderHandle
) && (I
->Line
== DirectiveLine
))
830 PPItemKey
IncludeDirectiveItem(IncludeHeaderHandle
, CurrentHeaderHandle
,
831 DirectiveLine
, DirectiveColumn
);
832 IncludeDirectives
.push_back(IncludeDirectiveItem
);
835 // Check for include directives within the given source line range.
836 // Report errors if any found. Returns true if no include directives
838 bool checkForIncludesInBlock(clang::Preprocessor
&PP
,
839 clang::SourceRange BlockSourceRange
,
840 const char *BlockIdentifierMessage
,
841 llvm::raw_ostream
&OS
) override
{
842 clang::SourceLocation BlockStartLoc
= BlockSourceRange
.getBegin();
843 clang::SourceLocation BlockEndLoc
= BlockSourceRange
.getEnd();
844 // Use block location to get FileID of both the include directive
845 // and block statement.
846 clang::FileID FileID
= PP
.getSourceManager().getFileID(BlockStartLoc
);
847 std::string SourcePath
= getSourceLocationFile(PP
, BlockStartLoc
);
848 SourcePath
= ModularizeUtilities::getCanonicalPath(SourcePath
);
849 HeaderHandle SourceHandle
= findHeaderHandle(SourcePath
);
850 if (SourceHandle
== -1)
852 int BlockStartLine
, BlockStartColumn
, BlockEndLine
, BlockEndColumn
;
853 bool returnValue
= true;
854 getSourceLocationLineAndColumn(PP
, BlockStartLoc
, BlockStartLine
,
856 getSourceLocationLineAndColumn(PP
, BlockEndLoc
, BlockEndLine
,
858 for (std::vector
<PPItemKey
>::const_iterator I
= IncludeDirectives
.begin(),
859 E
= IncludeDirectives
.end();
861 // If we find an entry within the block, report an error.
862 if ((I
->File
== SourceHandle
) && (I
->Line
>= BlockStartLine
) &&
863 (I
->Line
< BlockEndLine
)) {
865 OS
<< SourcePath
<< ":" << I
->Line
<< ":" << I
->Column
<< ":\n";
866 OS
<< getSourceLine(PP
, FileID
, I
->Line
) << "\n";
868 OS
<< std::string(I
->Column
- 1, ' ') << "^\n";
869 OS
<< "error: Include directive within " << BlockIdentifierMessage
871 OS
<< SourcePath
<< ":" << BlockStartLine
<< ":" << BlockStartColumn
873 OS
<< getSourceLine(PP
, BlockStartLoc
) << "\n";
874 if (BlockStartColumn
> 0)
875 OS
<< std::string(BlockStartColumn
- 1, ' ') << "^\n";
876 OS
<< "The \"" << BlockIdentifierMessage
<< "\" block is here.\n";
882 // Handle entering a header source file.
883 void handleHeaderEntry(clang::Preprocessor
&PP
, llvm::StringRef HeaderPath
) {
884 // Ignore <built-in> and <command-line> to reduce message clutter.
885 if (HeaderPath
.starts_with("<"))
887 HeaderHandle H
= addHeader(HeaderPath
);
888 if (H
!= getCurrentHeaderHandle())
890 // Check for nested header.
892 InNestedHeader
= !HeadersInThisCompile
.insert(H
).second
;
895 // Handle exiting a header source file.
896 void handleHeaderExit(llvm::StringRef HeaderPath
) {
897 // Ignore <built-in> and <command-line> to reduce message clutter.
898 if (HeaderPath
.starts_with("<"))
900 HeaderHandle H
= findHeaderHandle(HeaderPath
);
902 if (isHeaderHandleInStack(H
)) {
904 TH
= getCurrentHeaderHandle();
906 } while ((TH
!= H
) && (HeaderStack
.size() != 0));
908 InNestedHeader
= false;
911 // Lookup/add string.
912 StringHandle
addString(llvm::StringRef Str
) {
913 return Strings
.insert(Str
).first
->first();
916 // Convert to a canonical path.
917 std::string
getCanonicalPath(llvm::StringRef path
) const {
918 std::string
CanonicalPath(path
);
919 std::replace(CanonicalPath
.begin(), CanonicalPath
.end(), '\\', '/');
920 return CanonicalPath
;
923 // Return true if the given header is in the header list.
924 bool isHeaderListHeader(llvm::StringRef HeaderPath
) const {
925 std::string CanonicalPath
= getCanonicalPath(HeaderPath
);
926 for (llvm::ArrayRef
<std::string
>::iterator I
= HeaderList
.begin(),
927 E
= HeaderList
.end();
929 if (*I
== CanonicalPath
)
935 // Get the handle of a header file entry.
936 // Return HeaderHandleInvalid if not found.
937 HeaderHandle
findHeaderHandle(llvm::StringRef HeaderPath
) const {
938 std::string CanonicalPath
= getCanonicalPath(HeaderPath
);
940 for (auto I
= HeaderPaths
.begin(), E
= HeaderPaths
.end(); I
!= E
;
942 if (*I
== CanonicalPath
)
945 return HeaderHandleInvalid
;
948 // Add a new header file entry, or return existing handle.
949 // Return the header handle.
950 HeaderHandle
addHeader(llvm::StringRef HeaderPath
) {
951 std::string CanonicalPath
= getCanonicalPath(HeaderPath
);
952 HeaderHandle H
= findHeaderHandle(CanonicalPath
);
953 if (H
== HeaderHandleInvalid
) {
954 H
= HeaderPaths
.size();
955 HeaderPaths
.push_back(addString(CanonicalPath
));
960 // Return a header file path string given its handle.
961 StringHandle
getHeaderFilePath(HeaderHandle H
) const {
962 if ((H
>= 0) && (H
< (HeaderHandle
)HeaderPaths
.size()))
963 return HeaderPaths
[H
];
964 return StringHandle();
967 // Returns a handle to the inclusion path.
968 InclusionPathHandle
pushHeaderHandle(HeaderHandle H
) {
969 HeaderStack
.push_back(H
);
970 return CurrentInclusionPathHandle
= addInclusionPathHandle(HeaderStack
);
972 // Pops the last header handle from the stack;
973 void popHeaderHandle() {
974 // assert((HeaderStack.size() != 0) && "Header stack already empty.");
975 if (HeaderStack
.size() != 0) {
976 HeaderStack
.pop_back();
977 CurrentInclusionPathHandle
= addInclusionPathHandle(HeaderStack
);
980 // Get the top handle on the header stack.
981 HeaderHandle
getCurrentHeaderHandle() const {
982 if (HeaderStack
.size() != 0)
983 return HeaderStack
.back();
984 return HeaderHandleInvalid
;
987 // Check for presence of header handle in the header stack.
988 bool isHeaderHandleInStack(HeaderHandle H
) const {
989 return llvm::is_contained(HeaderStack
, H
);
992 // Get the handle of a header inclusion path entry.
993 // Return InclusionPathHandleInvalid if not found.
995 findInclusionPathHandle(const std::vector
<HeaderHandle
> &Path
) const {
996 InclusionPathHandle H
= 0;
997 for (auto I
= InclusionPaths
.begin(), E
= InclusionPaths
.end(); I
!= E
;
1002 return HeaderHandleInvalid
;
1004 // Add a new header inclusion path entry, or return existing handle.
1005 // Return the header inclusion path entry handle.
1007 addInclusionPathHandle(const std::vector
<HeaderHandle
> &Path
) {
1008 InclusionPathHandle H
= findInclusionPathHandle(Path
);
1009 if (H
== HeaderHandleInvalid
) {
1010 H
= InclusionPaths
.size();
1011 InclusionPaths
.push_back(HeaderInclusionPath(Path
));
1015 // Return the current inclusion path handle.
1016 InclusionPathHandle
getCurrentInclusionPathHandle() const {
1017 return CurrentInclusionPathHandle
;
1020 // Return an inclusion path given its handle.
1021 const std::vector
<HeaderHandle
> &
1022 getInclusionPath(InclusionPathHandle H
) const {
1023 if ((H
>= 0) && (H
<= (InclusionPathHandle
)InclusionPaths
.size()))
1024 return InclusionPaths
[H
].Path
;
1025 static std::vector
<HeaderHandle
> Empty
;
1029 // Add a macro expansion instance.
1030 void addMacroExpansionInstance(clang::Preprocessor
&PP
, HeaderHandle H
,
1031 clang::SourceLocation InstanceLoc
,
1032 clang::SourceLocation DefinitionLoc
,
1033 clang::IdentifierInfo
*II
,
1034 llvm::StringRef MacroUnexpanded
,
1035 llvm::StringRef MacroExpanded
,
1036 InclusionPathHandle InclusionPathHandle
) {
1039 StringHandle MacroName
= addString(II
->getName());
1040 PPItemKey
InstanceKey(PP
, MacroName
, H
, InstanceLoc
);
1041 PPItemKey
DefinitionKey(PP
, MacroName
, H
, DefinitionLoc
);
1042 auto I
= MacroExpansions
.find(InstanceKey
);
1043 // If existing instance of expansion not found, add one.
1044 if (I
== MacroExpansions
.end()) {
1045 std::string InstanceSourceLine
=
1046 getSourceLocationString(PP
, InstanceLoc
) + ":\n" +
1047 getSourceLine(PP
, InstanceLoc
) + "\n";
1048 std::string DefinitionSourceLine
=
1049 getSourceLocationString(PP
, DefinitionLoc
) + ":\n" +
1050 getSourceLine(PP
, DefinitionLoc
) + "\n";
1051 MacroExpansions
[InstanceKey
] = MacroExpansionTracker(
1052 addString(MacroUnexpanded
), addString(MacroExpanded
),
1053 addString(InstanceSourceLine
), DefinitionKey
,
1054 addString(DefinitionSourceLine
), InclusionPathHandle
);
1056 // We've seen the macro before. Get its tracker.
1057 MacroExpansionTracker
&CondTracker
= I
->second
;
1058 // Look up an existing instance value for the macro.
1059 MacroExpansionInstance
*MacroInfo
=
1060 CondTracker
.findMacroExpansionInstance(addString(MacroExpanded
),
1062 // If found, just add the inclusion path to the instance.
1064 MacroInfo
->addInclusionPathHandle(InclusionPathHandle
);
1066 // Otherwise add a new instance with the unique value.
1067 std::string DefinitionSourceLine
=
1068 getSourceLocationString(PP
, DefinitionLoc
) + ":\n" +
1069 getSourceLine(PP
, DefinitionLoc
) + "\n";
1070 CondTracker
.addMacroExpansionInstance(
1071 addString(MacroExpanded
), DefinitionKey
,
1072 addString(DefinitionSourceLine
), InclusionPathHandle
);
1077 // Add a conditional expansion instance.
1079 addConditionalExpansionInstance(clang::Preprocessor
&PP
, HeaderHandle H
,
1080 clang::SourceLocation InstanceLoc
,
1081 clang::tok::PPKeywordKind DirectiveKind
,
1082 clang::PPCallbacks::ConditionValueKind ConditionValue
,
1083 llvm::StringRef ConditionUnexpanded
,
1084 InclusionPathHandle InclusionPathHandle
) {
1085 // Ignore header guards, assuming the header guard is the only conditional.
1088 StringHandle
ConditionUnexpandedHandle(addString(ConditionUnexpanded
));
1089 PPItemKey
InstanceKey(PP
, ConditionUnexpandedHandle
, H
, InstanceLoc
);
1090 auto I
= ConditionalExpansions
.find(InstanceKey
);
1091 // If existing instance of condition not found, add one.
1092 if (I
== ConditionalExpansions
.end()) {
1093 std::string InstanceSourceLine
=
1094 getSourceLocationString(PP
, InstanceLoc
) + ":\n" +
1095 getSourceLine(PP
, InstanceLoc
) + "\n";
1096 ConditionalExpansions
[InstanceKey
] =
1097 ConditionalTracker(DirectiveKind
, ConditionValue
,
1098 ConditionUnexpandedHandle
, InclusionPathHandle
);
1100 // We've seen the conditional before. Get its tracker.
1101 ConditionalTracker
&CondTracker
= I
->second
;
1102 // Look up an existing instance value for the condition.
1103 ConditionalExpansionInstance
*MacroInfo
=
1104 CondTracker
.findConditionalExpansionInstance(ConditionValue
);
1105 // If found, just add the inclusion path to the instance.
1107 MacroInfo
->addInclusionPathHandle(InclusionPathHandle
);
1109 // Otherwise add a new instance with the unique value.
1110 CondTracker
.addConditionalExpansionInstance(ConditionValue
,
1111 InclusionPathHandle
);
1116 // Report on inconsistent macro instances.
1117 // Returns true if any mismatches.
1118 bool reportInconsistentMacros(llvm::raw_ostream
&OS
) override
{
1119 bool ReturnValue
= false;
1120 // Walk all the macro expansion trackers in the map.
1121 for (auto I
= MacroExpansions
.begin(), E
= MacroExpansions
.end(); I
!= E
;
1123 const PPItemKey
&ItemKey
= I
->first
;
1124 MacroExpansionTracker
&MacroExpTracker
= I
->second
;
1125 // If no mismatch (only one instance value) continue.
1126 if (!MacroExpTracker
.hasMismatch())
1128 // Tell caller we found one or more errors.
1130 // Start the error message.
1131 OS
<< MacroExpTracker
.InstanceSourceLine
;
1132 if (ItemKey
.Column
> 0)
1133 OS
<< std::string(ItemKey
.Column
- 1, ' ') << "^\n";
1134 OS
<< "error: Macro instance '" << MacroExpTracker
.MacroUnexpanded
1135 << "' has different values in this header, depending on how it was "
1137 // Walk all the instances.
1138 for (auto IMT
= MacroExpTracker
.MacroExpansionInstances
.begin(),
1139 EMT
= MacroExpTracker
.MacroExpansionInstances
.end();
1140 IMT
!= EMT
; ++IMT
) {
1141 MacroExpansionInstance
&MacroInfo
= *IMT
;
1142 OS
<< " '" << MacroExpTracker
.MacroUnexpanded
<< "' expanded to: '"
1143 << MacroInfo
.MacroExpanded
1144 << "' with respect to these inclusion paths:\n";
1145 // Walk all the inclusion path hierarchies.
1146 for (auto IIP
= MacroInfo
.InclusionPathHandles
.begin(),
1147 EIP
= MacroInfo
.InclusionPathHandles
.end();
1148 IIP
!= EIP
; ++IIP
) {
1149 const std::vector
<HeaderHandle
> &ip
= getInclusionPath(*IIP
);
1150 auto Count
= (int)ip
.size();
1151 for (int Index
= 0; Index
< Count
; ++Index
) {
1152 HeaderHandle H
= ip
[Index
];
1153 OS
<< std::string((Index
* 2) + 4, ' ') << getHeaderFilePath(H
)
1157 // For a macro that wasn't defined, we flag it by using the
1158 // instance location.
1159 // If there is a definition...
1160 if (MacroInfo
.DefinitionLocation
.Line
!= ItemKey
.Line
) {
1161 OS
<< MacroInfo
.DefinitionSourceLine
;
1162 if (MacroInfo
.DefinitionLocation
.Column
> 0)
1163 OS
<< std::string(MacroInfo
.DefinitionLocation
.Column
- 1, ' ')
1165 OS
<< "Macro defined here.\n";
1167 OS
<< "(no macro definition)"
1174 // Report on inconsistent conditional instances.
1175 // Returns true if any mismatches.
1176 bool reportInconsistentConditionals(llvm::raw_ostream
&OS
) override
{
1177 bool ReturnValue
= false;
1178 // Walk all the conditional trackers in the map.
1179 for (auto I
= ConditionalExpansions
.begin(),
1180 E
= ConditionalExpansions
.end();
1182 const PPItemKey
&ItemKey
= I
->first
;
1183 ConditionalTracker
&CondTracker
= I
->second
;
1184 if (!CondTracker
.hasMismatch())
1186 // Tell caller we found one or more errors.
1188 // Start the error message.
1189 OS
<< HeaderPaths
[ItemKey
.File
] << ":" << ItemKey
.Line
<< ":"
1190 << ItemKey
.Column
<< "\n";
1191 OS
<< "#" << getDirectiveSpelling(CondTracker
.DirectiveKind
) << " "
1192 << CondTracker
.ConditionUnexpanded
<< "\n";
1194 OS
<< "error: Conditional expression instance '"
1195 << CondTracker
.ConditionUnexpanded
1196 << "' has different values in this header, depending on how it was "
1198 // Walk all the instances.
1199 for (auto IMT
= CondTracker
.ConditionalExpansionInstances
.begin(),
1200 EMT
= CondTracker
.ConditionalExpansionInstances
.end();
1201 IMT
!= EMT
; ++IMT
) {
1202 ConditionalExpansionInstance
&MacroInfo
= *IMT
;
1203 OS
<< " '" << CondTracker
.ConditionUnexpanded
<< "' expanded to: '"
1204 << ConditionValueKindStrings
[MacroInfo
.ConditionValue
]
1205 << "' with respect to these inclusion paths:\n";
1206 // Walk all the inclusion path hierarchies.
1207 for (auto IIP
= MacroInfo
.InclusionPathHandles
.begin(),
1208 EIP
= MacroInfo
.InclusionPathHandles
.end();
1209 IIP
!= EIP
; ++IIP
) {
1210 const std::vector
<HeaderHandle
> &ip
= getInclusionPath(*IIP
);
1211 auto Count
= (int)ip
.size();
1212 for (int Index
= 0; Index
< Count
; ++Index
) {
1213 HeaderHandle H
= ip
[Index
];
1214 OS
<< std::string((Index
* 2) + 4, ' ') << getHeaderFilePath(H
)
1223 // Get directive spelling.
1224 static const char *getDirectiveSpelling(clang::tok::PPKeywordKind kind
) {
1226 case clang::tok::pp_if
:
1228 case clang::tok::pp_elif
:
1230 case clang::tok::pp_ifdef
:
1232 case clang::tok::pp_ifndef
:
1240 llvm::SmallVector
<std::string
, 32> HeaderList
;
1241 // Only do extern, namespace check for headers in HeaderList.
1242 bool BlockCheckHeaderListOnly
;
1243 llvm::StringSet
<> Strings
;
1244 std::vector
<StringHandle
> HeaderPaths
;
1245 std::vector
<HeaderHandle
> HeaderStack
;
1246 std::vector
<HeaderInclusionPath
> InclusionPaths
;
1247 InclusionPathHandle CurrentInclusionPathHandle
;
1248 llvm::SmallSet
<HeaderHandle
, 32> HeadersInThisCompile
;
1249 std::vector
<PPItemKey
> IncludeDirectives
;
1250 MacroExpansionMap MacroExpansions
;
1251 ConditionalExpansionMap ConditionalExpansions
;
1252 bool InNestedHeader
;
1257 // PreprocessorTracker functions.
1259 // PreprocessorTracker destructor.
1260 PreprocessorTracker::~PreprocessorTracker() {}
1262 // Create instance of PreprocessorTracker.
1263 PreprocessorTracker
*PreprocessorTracker::create(
1264 llvm::SmallVector
<std::string
, 32> &Headers
,
1265 bool DoBlockCheckHeaderListOnly
) {
1266 return new PreprocessorTrackerImpl(Headers
, DoBlockCheckHeaderListOnly
);
1269 // Preprocessor callbacks for modularize.
1271 // Handle include directive.
1272 void PreprocessorCallbacks::InclusionDirective(
1273 clang::SourceLocation HashLoc
, const clang::Token
&IncludeTok
,
1274 llvm::StringRef FileName
, bool IsAngled
,
1275 clang::CharSourceRange FilenameRange
, clang::OptionalFileEntryRef File
,
1276 llvm::StringRef SearchPath
, llvm::StringRef RelativePath
,
1277 const clang::Module
*SuggestedModule
, bool ModuleImported
,
1278 clang::SrcMgr::CharacteristicKind FileType
) {
1279 int DirectiveLine
, DirectiveColumn
;
1280 std::string HeaderPath
= getSourceLocationFile(PP
, HashLoc
);
1281 getSourceLocationLineAndColumn(PP
, HashLoc
, DirectiveLine
, DirectiveColumn
);
1282 PPTracker
.handleIncludeDirective(HeaderPath
, DirectiveLine
, DirectiveColumn
,
1286 // Handle file entry/exit.
1287 void PreprocessorCallbacks::FileChanged(
1288 clang::SourceLocation Loc
, clang::PPCallbacks::FileChangeReason Reason
,
1289 clang::SrcMgr::CharacteristicKind FileType
, clang::FileID PrevFID
) {
1292 PPTracker
.handleHeaderEntry(PP
, getSourceLocationFile(PP
, Loc
));
1295 clang::OptionalFileEntryRef F
=
1296 PP
.getSourceManager().getFileEntryRefForID(PrevFID
);
1298 PPTracker
.handleHeaderExit(F
->getName());
1300 case SystemHeaderPragma
:
1306 // Handle macro expansion.
1307 void PreprocessorCallbacks::MacroExpands(const clang::Token
&MacroNameTok
,
1308 const clang::MacroDefinition
&MD
,
1309 clang::SourceRange Range
,
1310 const clang::MacroArgs
*Args
) {
1311 clang::SourceLocation Loc
= Range
.getBegin();
1312 // Ignore macro argument expansions.
1313 if (!Loc
.isFileID())
1315 clang::IdentifierInfo
*II
= MacroNameTok
.getIdentifierInfo();
1316 const clang::MacroInfo
*MI
= MD
.getMacroInfo();
1317 std::string MacroName
= II
->getName().str();
1318 std::string
Unexpanded(getMacroUnexpandedString(Range
, PP
, MacroName
, MI
));
1319 std::string
Expanded(getMacroExpandedString(PP
, MacroName
, MI
, Args
));
1320 PPTracker
.addMacroExpansionInstance(
1321 PP
, PPTracker
.getCurrentHeaderHandle(), Loc
, MI
->getDefinitionLoc(), II
,
1322 Unexpanded
, Expanded
, PPTracker
.getCurrentInclusionPathHandle());
1325 void PreprocessorCallbacks::Defined(const clang::Token
&MacroNameTok
,
1326 const clang::MacroDefinition
&MD
,
1327 clang::SourceRange Range
) {
1328 clang::SourceLocation
Loc(Range
.getBegin());
1329 clang::IdentifierInfo
*II
= MacroNameTok
.getIdentifierInfo();
1330 const clang::MacroInfo
*MI
= MD
.getMacroInfo();
1331 std::string MacroName
= II
->getName().str();
1332 std::string
Unexpanded(getSourceString(PP
, Range
));
1333 PPTracker
.addMacroExpansionInstance(
1334 PP
, PPTracker
.getCurrentHeaderHandle(), Loc
,
1335 (MI
? MI
->getDefinitionLoc() : Loc
), II
, Unexpanded
,
1336 (MI
? "true" : "false"), PPTracker
.getCurrentInclusionPathHandle());
1339 void PreprocessorCallbacks::If(clang::SourceLocation Loc
,
1340 clang::SourceRange ConditionRange
,
1341 clang::PPCallbacks::ConditionValueKind ConditionResult
) {
1342 std::string
Unexpanded(getSourceString(PP
, ConditionRange
));
1343 PPTracker
.addConditionalExpansionInstance(
1344 PP
, PPTracker
.getCurrentHeaderHandle(), Loc
, clang::tok::pp_if
,
1345 ConditionResult
, Unexpanded
, PPTracker
.getCurrentInclusionPathHandle());
1348 void PreprocessorCallbacks::Elif(clang::SourceLocation Loc
,
1349 clang::SourceRange ConditionRange
,
1350 clang::PPCallbacks::ConditionValueKind ConditionResult
,
1351 clang::SourceLocation IfLoc
) {
1352 std::string
Unexpanded(getSourceString(PP
, ConditionRange
));
1353 PPTracker
.addConditionalExpansionInstance(
1354 PP
, PPTracker
.getCurrentHeaderHandle(), Loc
, clang::tok::pp_elif
,
1355 ConditionResult
, Unexpanded
, PPTracker
.getCurrentInclusionPathHandle());
1358 void PreprocessorCallbacks::Ifdef(clang::SourceLocation Loc
,
1359 const clang::Token
&MacroNameTok
,
1360 const clang::MacroDefinition
&MD
) {
1361 clang::PPCallbacks::ConditionValueKind IsDefined
=
1362 (MD
? clang::PPCallbacks::CVK_True
: clang::PPCallbacks::CVK_False
);
1363 PPTracker
.addConditionalExpansionInstance(
1364 PP
, PPTracker
.getCurrentHeaderHandle(), Loc
, clang::tok::pp_ifdef
,
1365 IsDefined
, PP
.getSpelling(MacroNameTok
),
1366 PPTracker
.getCurrentInclusionPathHandle());
1369 void PreprocessorCallbacks::Ifndef(clang::SourceLocation Loc
,
1370 const clang::Token
&MacroNameTok
,
1371 const clang::MacroDefinition
&MD
) {
1372 clang::PPCallbacks::ConditionValueKind IsNotDefined
=
1373 (!MD
? clang::PPCallbacks::CVK_True
: clang::PPCallbacks::CVK_False
);
1374 PPTracker
.addConditionalExpansionInstance(
1375 PP
, PPTracker
.getCurrentHeaderHandle(), Loc
, clang::tok::pp_ifndef
,
1376 IsNotDefined
, PP
.getSpelling(MacroNameTok
),
1377 PPTracker
.getCurrentInclusionPathHandle());
1379 } // end namespace Modularize