17c6e79f3SJohn Thompson //===--- PreprocessorTracker.cpp - Preprocessor tracking -*- C++ -*------===//
294faa4d0SJohn Thompson //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
694faa4d0SJohn Thompson //
77c6e79f3SJohn Thompson //===--------------------------------------------------------------------===//
87c6e79f3SJohn Thompson //
974083926SJohn Thompson // The Basic Idea (Macro and Conditional Checking)
1094faa4d0SJohn Thompson //
1194faa4d0SJohn Thompson // Basically we install a PPCallbacks-derived object to track preprocessor
1294faa4d0SJohn Thompson // activity, namely when a header file is entered/exited, when a macro
137c6e79f3SJohn Thompson // is expanded, when "defined" is used, and when #if, #elif, #ifdef,
147c6e79f3SJohn Thompson // and #ifndef are used.  We save the state of macro and "defined"
1594faa4d0SJohn Thompson // expressions in a map, keyed on a name/file/line/column quadruple.
167c6e79f3SJohn Thompson // The map entries store the different states (values) that a macro expansion,
177c6e79f3SJohn Thompson // "defined" expression, or condition expression has in the course of
1894faa4d0SJohn Thompson // processing for the one location in the one header containing it,
1994faa4d0SJohn Thompson // plus a list of the nested include stacks for the states.  When a macro
207c6e79f3SJohn Thompson // or "defined" expression evaluates to the same value, which is the
2194faa4d0SJohn Thompson // desired case, only one state is stored.  Similarly, for conditional
2294faa4d0SJohn Thompson // directives, we save the condition expression states in a separate map.
2394faa4d0SJohn Thompson //
2494faa4d0SJohn Thompson // This information is collected as modularize compiles all the headers
2594faa4d0SJohn Thompson // given to it to process.  After all the compilations are performed,
267c6e79f3SJohn Thompson // a check is performed for any entries in the maps that contain more
277c6e79f3SJohn Thompson // than one different state, and for these an output message is generated.
287c6e79f3SJohn Thompson //
297c6e79f3SJohn Thompson // For example:
307c6e79f3SJohn Thompson //
317c6e79f3SJohn Thompson //   (...)/SubHeader.h:11:5:
327c6e79f3SJohn Thompson //   #if SYMBOL == 1
337c6e79f3SJohn Thompson //       ^
347c6e79f3SJohn Thompson //   error: Macro instance 'SYMBOL' has different values in this header,
357c6e79f3SJohn Thompson //          depending on how it was included.
367c6e79f3SJohn Thompson //     'SYMBOL' expanded to: '1' with respect to these inclusion paths:
377c6e79f3SJohn Thompson //       (...)/Header1.h
387c6e79f3SJohn Thompson //         (...)/SubHeader.h
397c6e79f3SJohn Thompson //   (...)/SubHeader.h:3:9:
407c6e79f3SJohn Thompson //   #define SYMBOL 1
417c6e79f3SJohn Thompson //             ^
427c6e79f3SJohn Thompson //   Macro defined here.
437c6e79f3SJohn Thompson //     'SYMBOL' expanded to: '2' with respect to these inclusion paths:
447c6e79f3SJohn Thompson //       (...)/Header2.h
457c6e79f3SJohn Thompson //           (...)/SubHeader.h
467c6e79f3SJohn Thompson //   (...)/SubHeader.h:7:9:
477c6e79f3SJohn Thompson //   #define SYMBOL 2
487c6e79f3SJohn Thompson //             ^
497c6e79f3SJohn Thompson //   Macro defined here.
5094faa4d0SJohn Thompson //
5174083926SJohn Thompson // The Basic Idea ('Extern "C/C++" {}' Or 'namespace {}') With Nested
5274083926SJohn Thompson // '#include' Checking)
5374083926SJohn Thompson //
5474083926SJohn Thompson // To check for '#include' directives nested inside 'Extern "C/C++" {}'
5574083926SJohn Thompson // or 'namespace {}' blocks, we keep track of the '#include' directives
5674083926SJohn Thompson // while running the preprocessor, and later during a walk of the AST
57b7ecf1c1SKazuaki Ishizaki // we call a function to check for any '#include' directives inside
5874083926SJohn Thompson // an 'Extern "C/C++" {}' or 'namespace {}' block, given its source
5974083926SJohn Thompson // range.
6074083926SJohn Thompson //
6174083926SJohn Thompson // Design and Implementation Details (Macro and Conditional Checking)
6294faa4d0SJohn Thompson //
6394faa4d0SJohn Thompson // A PreprocessorTrackerImpl class implements the PreprocessorTracker
6494faa4d0SJohn Thompson // interface. It uses a PreprocessorCallbacks class derived from PPCallbacks
6594faa4d0SJohn Thompson // to track preprocessor activity, namely entering/exiting a header, macro
667c6e79f3SJohn Thompson // expansions, use of "defined" expressions, and #if, #elif, #ifdef, and
6794faa4d0SJohn Thompson // #ifndef conditional directives. PreprocessorTrackerImpl stores a map
6894faa4d0SJohn Thompson // of MacroExpansionTracker objects keyed on a name/file/line/column
6994faa4d0SJohn Thompson // value represented by a light-weight PPItemKey value object. This
7094faa4d0SJohn Thompson // is the key top-level data structure tracking the values of macro
7194faa4d0SJohn Thompson // expansion instances.  Similarly, it stores a map of ConditionalTracker
7294faa4d0SJohn Thompson // objects with the same kind of key, for tracking preprocessor conditional
7394faa4d0SJohn Thompson // directives.
7494faa4d0SJohn Thompson //
7594faa4d0SJohn Thompson // The MacroExpansionTracker object represents one macro reference or use
767c6e79f3SJohn Thompson // of a "defined" expression in a header file. It stores a handle to a
7794faa4d0SJohn Thompson // string representing the unexpanded macro instance, a handle to a string
7894faa4d0SJohn Thompson // representing the unpreprocessed source line containing the unexpanded
7994faa4d0SJohn Thompson // macro instance, and a vector of one or more MacroExpansionInstance
8094faa4d0SJohn Thompson // objects.
8194faa4d0SJohn Thompson //
8294faa4d0SJohn Thompson // The MacroExpansionInstance object represents one or more expansions
8394faa4d0SJohn Thompson // of a macro reference, for the case where the macro expands to the same
8494faa4d0SJohn Thompson // value. MacroExpansionInstance stores a handle to a string representing
8594faa4d0SJohn Thompson // the expanded macro value, a PPItemKey representing the file/line/column
8694faa4d0SJohn Thompson // where the macro was defined, a handle to a string representing the source
8794faa4d0SJohn Thompson // line containing the macro definition, and a vector of InclusionPathHandle
8894faa4d0SJohn Thompson // values that represents the hierarchies of include files for each case
8994faa4d0SJohn Thompson // where the particular header containing the macro reference was referenced
9094faa4d0SJohn Thompson // or included.
9194faa4d0SJohn Thompson 
9294faa4d0SJohn Thompson // In the normal case where a macro instance always expands to the same
9394faa4d0SJohn Thompson // value, the MacroExpansionTracker object will only contain one
9494faa4d0SJohn Thompson // MacroExpansionInstance representing all the macro expansion instances.
9594faa4d0SJohn Thompson // If a case was encountered where a macro instance expands to a value
9694faa4d0SJohn Thompson // that is different from that seen before, or the macro was defined in
9794faa4d0SJohn Thompson // a different place, a new MacroExpansionInstance object representing
9894faa4d0SJohn Thompson // that case will be added to the vector in MacroExpansionTracker. If a
9994faa4d0SJohn Thompson // macro instance expands to a value already seen before, the
1007c6e79f3SJohn Thompson // InclusionPathHandle representing that case's include file hierarchy
10194faa4d0SJohn Thompson // will be added to the existing MacroExpansionInstance object.
10294faa4d0SJohn Thompson 
10394faa4d0SJohn Thompson // For checking conditional directives, the ConditionalTracker class
10494faa4d0SJohn Thompson // functions similarly to MacroExpansionTracker, but tracks an #if,
10594faa4d0SJohn Thompson // #elif, #ifdef, or #ifndef directive in a header file.  It stores
10694faa4d0SJohn Thompson // a vector of one or two ConditionalExpansionInstance objects,
10794faa4d0SJohn Thompson // representing the cases where the conditional expression evaluates
10894faa4d0SJohn Thompson // to true or false.  This latter object stores the evaluated value
10994faa4d0SJohn Thompson // of the condition expression (a bool) and a vector of
11094faa4d0SJohn Thompson // InclusionPathHandles.
11194faa4d0SJohn Thompson //
11294faa4d0SJohn Thompson // To reduce the instances of string and object copying, the
11394faa4d0SJohn Thompson // PreprocessorTrackerImpl class uses a StringPool to save all stored
11494faa4d0SJohn Thompson // strings, and defines a StringHandle type to abstract the references
11594faa4d0SJohn Thompson // to the strings.
11694faa4d0SJohn Thompson //
11794faa4d0SJohn Thompson // PreprocessorTrackerImpl also maintains a list representing the unique
1187c6e79f3SJohn Thompson // headers, which is just a vector of StringHandle's for the header file
11994faa4d0SJohn Thompson // paths. A HeaderHandle abstracts a reference to a header, and is simply
12094faa4d0SJohn Thompson // the index of the stored header file path.
12194faa4d0SJohn Thompson //
1227c6e79f3SJohn Thompson // A HeaderInclusionPath class abstracts a unique hierarchy of header file
12394faa4d0SJohn Thompson // inclusions. It simply stores a vector of HeaderHandles ordered from the
12494faa4d0SJohn Thompson // top-most header (the one from the header list passed to modularize) down
12594faa4d0SJohn Thompson // to the header containing the macro reference. PreprocessorTrackerImpl
12694faa4d0SJohn Thompson // stores a vector of these objects. An InclusionPathHandle typedef
12794faa4d0SJohn Thompson // abstracts a reference to one of the HeaderInclusionPath objects, and is
12894faa4d0SJohn Thompson // simply the index of the stored HeaderInclusionPath object. The
1297c6e79f3SJohn Thompson // MacroExpansionInstance object stores a vector of these handles so that
13094faa4d0SJohn Thompson // the reporting function can display the include hierarchies for the macro
13194faa4d0SJohn Thompson // expansion instances represented by that object, to help the user
13294faa4d0SJohn Thompson // understand how the header was included. (A future enhancement might
13394faa4d0SJohn Thompson // be to associate a line number for the #include directives, but I
13494faa4d0SJohn Thompson // think not doing so is good enough for the present.)
13594faa4d0SJohn Thompson //
13694faa4d0SJohn Thompson // A key reason for using these opaque handles was to try to keep all the
13794faa4d0SJohn Thompson // internal objects light-weight value objects, in order to reduce string
13894faa4d0SJohn Thompson // and object copying overhead, and to abstract this implementation detail.
13994faa4d0SJohn Thompson //
14094faa4d0SJohn Thompson // The key data structures are built up while modularize runs the headers
14194faa4d0SJohn Thompson // through the compilation. A PreprocessorTracker instance is created and
14294faa4d0SJohn Thompson // passed down to the AST action and consumer objects in modularize. For
14394faa4d0SJohn Thompson // each new compilation instance, the consumer calls the
1447c6e79f3SJohn Thompson // PreprocessorTracker's handleNewPreprocessorEntry function, which sets
14594faa4d0SJohn Thompson // up a PreprocessorCallbacks object for the preprocessor. At the end of
1467c6e79f3SJohn Thompson // the compilation instance, the PreprocessorTracker's
14794faa4d0SJohn Thompson // handleNewPreprocessorExit function handles cleaning up with respect
14894faa4d0SJohn Thompson // to the preprocessing instance.
14994faa4d0SJohn Thompson //
150dd5571d5SKazuaki Ishizaki // The PreprocessorCallbacks object uses an overridden FileChanged callback
15194faa4d0SJohn Thompson // to determine when a header is entered and exited (including exiting the
1527c6e79f3SJohn Thompson // header during #include directives). It calls PreprocessorTracker's
15394faa4d0SJohn Thompson // handleHeaderEntry and handleHeaderExit functions upon entering and
15494faa4d0SJohn Thompson // exiting a header. These functions manage a stack of header handles
15594faa4d0SJohn Thompson // representing by a vector, pushing and popping header handles as headers
15694faa4d0SJohn Thompson // are entered and exited. When a HeaderInclusionPath object is created,
15794faa4d0SJohn Thompson // it simply copies this stack.
15894faa4d0SJohn Thompson //
15994faa4d0SJohn Thompson // The PreprocessorCallbacks object uses an overridden MacroExpands callback
16094faa4d0SJohn Thompson // to track when a macro expansion is performed. It calls a couple of helper
16194faa4d0SJohn Thompson // functions to get the unexpanded and expanded macro values as strings, but
1627c6e79f3SJohn Thompson // then calls PreprocessorTrackerImpl's addMacroExpansionInstance function to
16394faa4d0SJohn Thompson // do the rest of the work. The getMacroExpandedString function uses the
1647c6e79f3SJohn Thompson // preprocessor's getSpelling to convert tokens to strings using the
16594faa4d0SJohn Thompson // information passed to the MacroExpands callback, and simply concatenates
16694faa4d0SJohn Thompson // them. It makes recursive calls to itself to handle nested macro
16794faa4d0SJohn Thompson // definitions, and also handles function-style macros.
16894faa4d0SJohn Thompson //
1697c6e79f3SJohn Thompson // PreprocessorTrackerImpl's addMacroExpansionInstance function looks for
17094faa4d0SJohn Thompson // an existing MacroExpansionTracker entry in its map of MacroExampleTracker
17194faa4d0SJohn Thompson // objects. If none exists, it adds one with one MacroExpansionInstance and
17294faa4d0SJohn Thompson // returns. If a MacroExpansionTracker object already exists, it looks for
17394faa4d0SJohn Thompson // an existing MacroExpansionInstance object stored in the
17494faa4d0SJohn Thompson // MacroExpansionTracker object, one that matches the macro expanded value
17594faa4d0SJohn Thompson // and the macro definition location. If a matching MacroExpansionInstance
17694faa4d0SJohn Thompson // object is found, it just adds the current HeaderInclusionPath object to
177dd5571d5SKazuaki Ishizaki // it. If not found, it creates and stores a new MacroExpansionInstance
17894faa4d0SJohn Thompson // object. The addMacroExpansionInstance function calls a couple of helper
17994faa4d0SJohn Thompson // functions to get the pre-formatted location and source line strings for
18094faa4d0SJohn Thompson // the macro reference and the macro definition stored as string handles.
18194faa4d0SJohn Thompson // These helper functions use the current source manager from the
18294faa4d0SJohn Thompson // preprocessor. This is done in advance at this point in time because the
1837c6e79f3SJohn Thompson // source manager doesn't exist at the time of the reporting.
18494faa4d0SJohn Thompson //
18594faa4d0SJohn Thompson // For conditional check, the PreprocessorCallbacks class overrides the
18694faa4d0SJohn Thompson // PPCallbacks handlers for #if, #elif, #ifdef, and #ifndef.  These handlers
18794faa4d0SJohn Thompson // call the addConditionalExpansionInstance method of
18894faa4d0SJohn Thompson // PreprocessorTrackerImpl.  The process is similar to that of macros, but
18994faa4d0SJohn Thompson // with some different data and error messages.  A lookup is performed for
1907c6e79f3SJohn Thompson // the conditional, and if a ConditionalTracker object doesn't yet exist for
19194faa4d0SJohn Thompson // the conditional, a new one is added, including adding a
19294faa4d0SJohn Thompson // ConditionalExpansionInstance object to it to represent the condition
19394faa4d0SJohn Thompson // expression state.  If a ConditionalTracker for the conditional does
19494faa4d0SJohn Thompson // exist, a lookup is made for a ConditionalExpansionInstance object
19594faa4d0SJohn Thompson // matching the condition expression state.  If one exists, a
19694faa4d0SJohn Thompson // HeaderInclusionPath is added to it.  Otherwise a new
19794faa4d0SJohn Thompson // ConditionalExpansionInstance  entry is made.  If a ConditionalTracker
19894faa4d0SJohn Thompson // has two ConditionalExpansionInstance objects, it means there was a
19994faa4d0SJohn Thompson // conflict, meaning the conditional expression evaluated differently in
20094faa4d0SJohn Thompson // one or more cases.
20194faa4d0SJohn Thompson //
20294faa4d0SJohn Thompson // After modularize has performed all the compilations, it enters a phase
20394faa4d0SJohn Thompson // of error reporting. This new feature adds to this reporting phase calls
2047c6e79f3SJohn Thompson // to the PreprocessorTracker's reportInconsistentMacros and
20594faa4d0SJohn Thompson // reportInconsistentConditionals functions. These functions walk the maps
2067c6e79f3SJohn Thompson // of MacroExpansionTracker's and ConditionalTracker's respectively. If
20794faa4d0SJohn Thompson // any of these objects have more than one MacroExpansionInstance or
20894faa4d0SJohn Thompson // ConditionalExpansionInstance objects, it formats and outputs an error
20994faa4d0SJohn Thompson // message like the example shown previously, using the stored data.
21094faa4d0SJohn Thompson //
21194faa4d0SJohn Thompson // A potential issue is that there is some overlap between the #if/#elif
21294faa4d0SJohn Thompson // conditional and macro reporting.  I could disable the #if and #elif,
2137c6e79f3SJohn Thompson // leaving just the #ifdef and #ifndef, since these don't overlap.  Or,
21494faa4d0SJohn Thompson // to make clearer the separate reporting phases, I could add an output
21594faa4d0SJohn Thompson // message marking the phases.
21694faa4d0SJohn Thompson //
21774083926SJohn Thompson // Design and Implementation Details ('Extern "C/C++" {}' Or
21874083926SJohn Thompson // 'namespace {}') With Nested '#include' Checking)
21974083926SJohn Thompson //
22074083926SJohn Thompson // We override the InclusionDirective in PPCallbacks to record information
22174083926SJohn Thompson // about each '#include' directive encountered during preprocessing.
22274083926SJohn Thompson // We co-opt the PPItemKey class to store the information about each
22374083926SJohn Thompson // '#include' directive, including the source file name containing the
22474083926SJohn Thompson // directive, the name of the file being included, and the source line
22574083926SJohn Thompson // and column of the directive.  We store these object in a vector,
22674083926SJohn Thompson // after first check to see if an entry already exists.
22774083926SJohn Thompson //
22874083926SJohn Thompson // Later, while the AST is being walked for other checks, we provide
22974083926SJohn Thompson // visit handlers for 'extern "C/C++" {}' and 'namespace (name) {}'
23074083926SJohn Thompson // blocks, checking to see if any '#include' directives occurred
23174083926SJohn Thompson // within the blocks, reporting errors if any found.
23274083926SJohn Thompson //
23394faa4d0SJohn Thompson // Future Directions
23494faa4d0SJohn Thompson //
23594faa4d0SJohn Thompson // We probably should add options to disable any of the checks, in case
23694faa4d0SJohn Thompson // there is some problem with them, or the messages get too verbose.
23794faa4d0SJohn Thompson //
23894faa4d0SJohn Thompson // With the map of all the macro and conditional expansion instances,
23994faa4d0SJohn Thompson // it might be possible to add to the existing modularize error messages
24094faa4d0SJohn Thompson // (the second part referring to definitions being different), attempting
24194faa4d0SJohn Thompson // to tie them to the last macro conflict encountered with respect to the
24294faa4d0SJohn Thompson // order of the code encountered.
24394faa4d0SJohn Thompson //
24494faa4d0SJohn Thompson //===--------------------------------------------------------------------===//
24594faa4d0SJohn Thompson 
24685e6e871SChandler Carruth #include "PreprocessorTracker.h"
24739c9c12bSChris Lattner #include "ModularizeUtilities.h"
24839c9c12bSChris Lattner #include "clang/Lex/LexDiagnostic.h"
24994faa4d0SJohn Thompson #include "clang/Lex/MacroArgs.h"
25094faa4d0SJohn Thompson #include "clang/Lex/PPCallbacks.h"
2514ed963a0SJohn Thompson #include "llvm/ADT/SmallSet.h"
25239c9c12bSChris Lattner #include "llvm/ADT/StringSet.h"
25385e6e871SChandler Carruth #include "llvm/Support/raw_ostream.h"
25494faa4d0SJohn Thompson 
25594faa4d0SJohn Thompson namespace Modularize {
25694faa4d0SJohn Thompson 
25794faa4d0SJohn Thompson // Some handle types
25839c9c12bSChris Lattner typedef llvm::StringRef StringHandle;
25994faa4d0SJohn Thompson 
26094faa4d0SJohn Thompson typedef int HeaderHandle;
26194faa4d0SJohn Thompson const HeaderHandle HeaderHandleInvalid = -1;
26294faa4d0SJohn Thompson 
26394faa4d0SJohn Thompson typedef int InclusionPathHandle;
26494faa4d0SJohn Thompson const InclusionPathHandle InclusionPathHandleInvalid = -1;
26594faa4d0SJohn Thompson 
26694faa4d0SJohn Thompson // Some utility functions.
26794faa4d0SJohn Thompson 
26894faa4d0SJohn Thompson // Get a "file:line:column" source location string.
getSourceLocationString(clang::Preprocessor & PP,clang::SourceLocation Loc)26994faa4d0SJohn Thompson static std::string getSourceLocationString(clang::Preprocessor &PP,
27094faa4d0SJohn Thompson                                            clang::SourceLocation Loc) {
27194faa4d0SJohn Thompson   if (Loc.isInvalid())
27294faa4d0SJohn Thompson     return std::string("(none)");
27394faa4d0SJohn Thompson   else
27494faa4d0SJohn Thompson     return Loc.printToString(PP.getSourceManager());
27594faa4d0SJohn Thompson }
27694faa4d0SJohn Thompson 
27794faa4d0SJohn Thompson // Get just the file name from a source location.
getSourceLocationFile(clang::Preprocessor & PP,clang::SourceLocation Loc)27894faa4d0SJohn Thompson static std::string getSourceLocationFile(clang::Preprocessor &PP,
27994faa4d0SJohn Thompson                                          clang::SourceLocation Loc) {
28094faa4d0SJohn Thompson   std::string Source(getSourceLocationString(PP, Loc));
28194faa4d0SJohn Thompson   size_t Offset = Source.find(':', 2);
28294faa4d0SJohn Thompson   if (Offset == std::string::npos)
28394faa4d0SJohn Thompson     return Source;
28494faa4d0SJohn Thompson   return Source.substr(0, Offset);
28594faa4d0SJohn Thompson }
28694faa4d0SJohn Thompson 
28794faa4d0SJohn Thompson // Get just the line and column from a source location.
getSourceLocationLineAndColumn(clang::Preprocessor & PP,clang::SourceLocation Loc,int & Line,int & Column)28894faa4d0SJohn Thompson static void getSourceLocationLineAndColumn(clang::Preprocessor &PP,
28994faa4d0SJohn Thompson                                            clang::SourceLocation Loc, int &Line,
29094faa4d0SJohn Thompson                                            int &Column) {
29194faa4d0SJohn Thompson   clang::PresumedLoc PLoc = PP.getSourceManager().getPresumedLoc(Loc);
29294faa4d0SJohn Thompson   if (PLoc.isInvalid()) {
29394faa4d0SJohn Thompson     Line = 0;
29494faa4d0SJohn Thompson     Column = 0;
29594faa4d0SJohn Thompson     return;
29694faa4d0SJohn Thompson   }
29794faa4d0SJohn Thompson   Line = PLoc.getLine();
29894faa4d0SJohn Thompson   Column = PLoc.getColumn();
29994faa4d0SJohn Thompson }
30094faa4d0SJohn Thompson 
30194faa4d0SJohn Thompson // Retrieve source snippet from file image.
getSourceString(clang::Preprocessor & PP,clang::SourceRange Range)302e7103712SBenjamin Kramer static std::string getSourceString(clang::Preprocessor &PP,
303e7103712SBenjamin Kramer                                    clang::SourceRange Range) {
30494faa4d0SJohn Thompson   clang::SourceLocation BeginLoc = Range.getBegin();
30594faa4d0SJohn Thompson   clang::SourceLocation EndLoc = Range.getEnd();
30694faa4d0SJohn Thompson   const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
30794faa4d0SJohn Thompson   const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc);
30894faa4d0SJohn Thompson   size_t Length = EndPtr - BeginPtr;
30994faa4d0SJohn Thompson   return llvm::StringRef(BeginPtr, Length).trim().str();
31094faa4d0SJohn Thompson }
31194faa4d0SJohn Thompson 
31274083926SJohn Thompson // Retrieve source line from file image given a location.
getSourceLine(clang::Preprocessor & PP,clang::SourceLocation Loc)313e7103712SBenjamin Kramer static std::string getSourceLine(clang::Preprocessor &PP,
314e7103712SBenjamin Kramer                                  clang::SourceLocation Loc) {
31500651981SDuncan P. N. Exon Smith   llvm::MemoryBufferRef MemBuffer = PP.getSourceManager().getBufferOrFake(
31600651981SDuncan P. N. Exon Smith       PP.getSourceManager().getFileID(Loc));
31700651981SDuncan P. N. Exon Smith   const char *Buffer = MemBuffer.getBufferStart();
31800651981SDuncan P. N. Exon Smith   const char *BufferEnd = MemBuffer.getBufferEnd();
31994faa4d0SJohn Thompson   const char *BeginPtr = PP.getSourceManager().getCharacterData(Loc);
32094faa4d0SJohn Thompson   const char *EndPtr = BeginPtr;
32194faa4d0SJohn Thompson   while (BeginPtr > Buffer) {
32294faa4d0SJohn Thompson     if (*BeginPtr == '\n') {
32394faa4d0SJohn Thompson       BeginPtr++;
32494faa4d0SJohn Thompson       break;
32594faa4d0SJohn Thompson     }
32694faa4d0SJohn Thompson     BeginPtr--;
32794faa4d0SJohn Thompson   }
32894faa4d0SJohn Thompson   while (EndPtr < BufferEnd) {
32994faa4d0SJohn Thompson     if (*EndPtr == '\n') {
33094faa4d0SJohn Thompson       break;
33194faa4d0SJohn Thompson     }
33294faa4d0SJohn Thompson     EndPtr++;
33394faa4d0SJohn Thompson   }
33494faa4d0SJohn Thompson   size_t Length = EndPtr - BeginPtr;
33594faa4d0SJohn Thompson   return llvm::StringRef(BeginPtr, Length).str();
33694faa4d0SJohn Thompson }
33794faa4d0SJohn Thompson 
33874083926SJohn Thompson // Retrieve source line from file image given a file ID and line number.
getSourceLine(clang::Preprocessor & PP,clang::FileID FileID,int Line)339e7103712SBenjamin Kramer static std::string getSourceLine(clang::Preprocessor &PP, clang::FileID FileID,
34074083926SJohn Thompson                                  int Line) {
34100651981SDuncan P. N. Exon Smith   llvm::MemoryBufferRef MemBuffer =
34200651981SDuncan P. N. Exon Smith       PP.getSourceManager().getBufferOrFake(FileID);
34300651981SDuncan P. N. Exon Smith   const char *Buffer = MemBuffer.getBufferStart();
34400651981SDuncan P. N. Exon Smith   const char *BufferEnd = MemBuffer.getBufferEnd();
34574083926SJohn Thompson   const char *BeginPtr = Buffer;
34674083926SJohn Thompson   const char *EndPtr = BufferEnd;
34774083926SJohn Thompson   int LineCounter = 1;
34874083926SJohn Thompson   if (Line == 1)
34974083926SJohn Thompson     BeginPtr = Buffer;
35074083926SJohn Thompson   else {
35174083926SJohn Thompson     while (Buffer < BufferEnd) {
35274083926SJohn Thompson       if (*Buffer == '\n') {
35374083926SJohn Thompson         if (++LineCounter == Line) {
35474083926SJohn Thompson           BeginPtr = Buffer++ + 1;
35574083926SJohn Thompson           break;
35674083926SJohn Thompson         }
35774083926SJohn Thompson       }
35874083926SJohn Thompson       Buffer++;
35974083926SJohn Thompson     }
36074083926SJohn Thompson   }
36174083926SJohn Thompson   while (Buffer < BufferEnd) {
36274083926SJohn Thompson     if (*Buffer == '\n') {
36374083926SJohn Thompson       EndPtr = Buffer;
36474083926SJohn Thompson       break;
36574083926SJohn Thompson     }
36674083926SJohn Thompson     Buffer++;
36774083926SJohn Thompson   }
36874083926SJohn Thompson   size_t Length = EndPtr - BeginPtr;
36974083926SJohn Thompson   return llvm::StringRef(BeginPtr, Length).str();
37074083926SJohn Thompson }
37174083926SJohn Thompson 
37294faa4d0SJohn Thompson // Get the string for the Unexpanded macro instance.
373dd5571d5SKazuaki Ishizaki // The sourceRange is expected to end at the last token
37494faa4d0SJohn Thompson // for the macro instance, which in the case of a function-style
37594faa4d0SJohn Thompson // macro will be a ')', but for an object-style macro, it
37694faa4d0SJohn Thompson // will be the macro name itself.
getMacroUnexpandedString(clang::SourceRange Range,clang::Preprocessor & PP,llvm::StringRef MacroName,const clang::MacroInfo * MI)377e7103712SBenjamin Kramer static std::string getMacroUnexpandedString(clang::SourceRange Range,
37894faa4d0SJohn Thompson                                             clang::Preprocessor &PP,
37994faa4d0SJohn Thompson                                             llvm::StringRef MacroName,
38094faa4d0SJohn Thompson                                             const clang::MacroInfo *MI) {
38194faa4d0SJohn Thompson   clang::SourceLocation BeginLoc(Range.getBegin());
38294faa4d0SJohn Thompson   const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
38394faa4d0SJohn Thompson   size_t Length;
38494faa4d0SJohn Thompson   std::string Unexpanded;
38594faa4d0SJohn Thompson   if (MI->isFunctionLike()) {
38694faa4d0SJohn Thompson     clang::SourceLocation EndLoc(Range.getEnd());
38794faa4d0SJohn Thompson     const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc) + 1;
38894faa4d0SJohn Thompson     Length = (EndPtr - BeginPtr) + 1; // +1 is ')' width.
38994faa4d0SJohn Thompson   } else
39094faa4d0SJohn Thompson     Length = MacroName.size();
39194faa4d0SJohn Thompson   return llvm::StringRef(BeginPtr, Length).trim().str();
39294faa4d0SJohn Thompson }
39394faa4d0SJohn Thompson 
39494faa4d0SJohn Thompson // Get the expansion for a macro instance, given the information
39594faa4d0SJohn Thompson // provided by PPCallbacks.
39691555bdeSJohn Thompson // FIXME: This doesn't support function-style macro instances
39791555bdeSJohn Thompson // passed as arguments to another function-style macro. However,
39891555bdeSJohn Thompson // since it still expands the inner arguments, it still
39991555bdeSJohn Thompson // allows modularize to effectively work with respect to macro
40091555bdeSJohn Thompson // consistency checking, although it displays the incorrect
40191555bdeSJohn Thompson // expansion in error messages.
getMacroExpandedString(clang::Preprocessor & PP,llvm::StringRef MacroName,const clang::MacroInfo * MI,const clang::MacroArgs * Args)402e7103712SBenjamin Kramer static std::string getMacroExpandedString(clang::Preprocessor &PP,
40394faa4d0SJohn Thompson                                           llvm::StringRef MacroName,
40494faa4d0SJohn Thompson                                           const clang::MacroInfo *MI,
40594faa4d0SJohn Thompson                                           const clang::MacroArgs *Args) {
40694faa4d0SJohn Thompson   std::string Expanded;
40794faa4d0SJohn Thompson   // Walk over the macro Tokens.
40889ec7234SDaniel Marjamaki   for (const auto &T : MI->tokens()) {
40989ec7234SDaniel Marjamaki     clang::IdentifierInfo *II = T.getIdentifierInfo();
410cb8e01acSFaisal Vali     int ArgNo = (II && Args ? MI->getParameterNum(II) : -1);
41194faa4d0SJohn Thompson     if (ArgNo == -1) {
41294faa4d0SJohn Thompson       // This isn't an argument, just add it.
413f61be9c9SCraig Topper       if (II == nullptr)
41489ec7234SDaniel Marjamaki         Expanded += PP.getSpelling(T); // Not an identifier.
41594faa4d0SJohn Thompson       else {
41694faa4d0SJohn Thompson         // Token is for an identifier.
41794faa4d0SJohn Thompson         std::string Name = II->getName().str();
41894faa4d0SJohn Thompson         // Check for nexted macro references.
41994faa4d0SJohn Thompson         clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
420fcf3f47dSJohn Thompson         if (MacroInfo && (Name != MacroName))
421f61be9c9SCraig Topper           Expanded += getMacroExpandedString(PP, Name, MacroInfo, nullptr);
42294faa4d0SJohn Thompson         else
42394faa4d0SJohn Thompson           Expanded += Name;
42494faa4d0SJohn Thompson       }
42594faa4d0SJohn Thompson       continue;
42694faa4d0SJohn Thompson     }
42794faa4d0SJohn Thompson     // We get here if it's a function-style macro with arguments.
42894faa4d0SJohn Thompson     const clang::Token *ResultArgToks;
42994faa4d0SJohn Thompson     const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
43094faa4d0SJohn Thompson     if (Args->ArgNeedsPreexpansion(ArgTok, PP))
43194faa4d0SJohn Thompson       ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
432a8e84625SFaisal Vali           ->getPreExpArgument(ArgNo, PP)[0];
43394faa4d0SJohn Thompson     else
43494faa4d0SJohn Thompson       ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
43594faa4d0SJohn Thompson     // If the arg token didn't expand into anything, ignore it.
43694faa4d0SJohn Thompson     if (ResultArgToks->is(clang::tok::eof))
43794faa4d0SJohn Thompson       continue;
43894faa4d0SJohn Thompson     unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
43994faa4d0SJohn Thompson     // Append the resulting argument expansions.
44094faa4d0SJohn Thompson     for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
44194faa4d0SJohn Thompson       const clang::Token &AT = ResultArgToks[ArgumentIndex];
44294faa4d0SJohn Thompson       clang::IdentifierInfo *II = AT.getIdentifierInfo();
443f61be9c9SCraig Topper       if (II == nullptr)
44494faa4d0SJohn Thompson         Expanded += PP.getSpelling(AT); // Not an identifier.
44594faa4d0SJohn Thompson       else {
44694faa4d0SJohn Thompson         // It's an identifier.  Check for further expansion.
44794faa4d0SJohn Thompson         std::string Name = II->getName().str();
44894faa4d0SJohn Thompson         clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
449f61be9c9SCraig Topper         if (MacroInfo)
450f61be9c9SCraig Topper           Expanded += getMacroExpandedString(PP, Name, MacroInfo, nullptr);
45194faa4d0SJohn Thompson         else
45294faa4d0SJohn Thompson           Expanded += Name;
45394faa4d0SJohn Thompson       }
45494faa4d0SJohn Thompson     }
45594faa4d0SJohn Thompson   }
45694faa4d0SJohn Thompson   return Expanded;
45794faa4d0SJohn Thompson }
45894faa4d0SJohn Thompson 
459e7103712SBenjamin Kramer namespace {
46094faa4d0SJohn Thompson 
46187f9fef5SJohn Thompson // ConditionValueKind strings.
46287f9fef5SJohn Thompson const char *
46387f9fef5SJohn Thompson ConditionValueKindStrings[] = {
46487f9fef5SJohn Thompson   "(not evaluated)", "false", "true"
46587f9fef5SJohn Thompson };
46687f9fef5SJohn Thompson 
46794faa4d0SJohn Thompson // Preprocessor item key.
46894faa4d0SJohn Thompson //
46994faa4d0SJohn Thompson // This class represents a location in a source file, for use
47094faa4d0SJohn Thompson // as a key representing a unique name/file/line/column quadruplet,
47194faa4d0SJohn Thompson // which in this case is used to identify a macro expansion instance,
47294faa4d0SJohn Thompson // but could be used for other things as well.
47394faa4d0SJohn Thompson // The file is a header file handle, the line is a line number,
47494faa4d0SJohn Thompson // and the column is a column number.
47594faa4d0SJohn Thompson class PPItemKey {
47694faa4d0SJohn Thompson public:
PPItemKey(clang::Preprocessor & PP,StringHandle Name,HeaderHandle File,clang::SourceLocation Loc)47794faa4d0SJohn Thompson   PPItemKey(clang::Preprocessor &PP, StringHandle Name, HeaderHandle File,
47894faa4d0SJohn Thompson             clang::SourceLocation Loc)
47994faa4d0SJohn Thompson       : Name(Name), File(File) {
48094faa4d0SJohn Thompson     getSourceLocationLineAndColumn(PP, Loc, Line, Column);
48194faa4d0SJohn Thompson   }
PPItemKey(StringHandle Name,HeaderHandle File,int Line,int Column)48294faa4d0SJohn Thompson   PPItemKey(StringHandle Name, HeaderHandle File, int Line, int Column)
48394faa4d0SJohn Thompson       : Name(Name), File(File), Line(Line), Column(Column) {}
PPItemKey(const PPItemKey & Other)48494faa4d0SJohn Thompson   PPItemKey(const PPItemKey &Other)
48594faa4d0SJohn Thompson       : Name(Other.Name), File(Other.File), Line(Other.Line),
48694faa4d0SJohn Thompson         Column(Other.Column) {}
PPItemKey()48794faa4d0SJohn Thompson   PPItemKey() : File(HeaderHandleInvalid), Line(0), Column(0) {}
operator ==(const PPItemKey & Other) const48894faa4d0SJohn Thompson   bool operator==(const PPItemKey &Other) const {
48994faa4d0SJohn Thompson     if (Name != Other.Name)
49094faa4d0SJohn Thompson       return false;
49194faa4d0SJohn Thompson     if (File != Other.File)
49294faa4d0SJohn Thompson       return false;
49394faa4d0SJohn Thompson     if (Line != Other.Line)
49494faa4d0SJohn Thompson       return false;
49594faa4d0SJohn Thompson     return Column == Other.Column;
49694faa4d0SJohn Thompson   }
operator <(const PPItemKey & Other) const49794faa4d0SJohn Thompson   bool operator<(const PPItemKey &Other) const {
49894faa4d0SJohn Thompson     if (Name < Other.Name)
49994faa4d0SJohn Thompson       return true;
50094faa4d0SJohn Thompson     else if (Name > Other.Name)
50194faa4d0SJohn Thompson       return false;
50294faa4d0SJohn Thompson     if (File < Other.File)
50394faa4d0SJohn Thompson       return true;
50494faa4d0SJohn Thompson     else if (File > Other.File)
50594faa4d0SJohn Thompson       return false;
50694faa4d0SJohn Thompson     if (Line < Other.Line)
50794faa4d0SJohn Thompson       return true;
50894faa4d0SJohn Thompson     else if (Line > Other.Line)
50994faa4d0SJohn Thompson       return false;
51094faa4d0SJohn Thompson     return Column < Other.Column;
51194faa4d0SJohn Thompson   }
51294faa4d0SJohn Thompson   StringHandle Name;
51394faa4d0SJohn Thompson   HeaderHandle File;
51494faa4d0SJohn Thompson   int Line;
51594faa4d0SJohn Thompson   int Column;
51694faa4d0SJohn Thompson };
51794faa4d0SJohn Thompson 
51894faa4d0SJohn Thompson // Header inclusion path.
51994faa4d0SJohn Thompson class HeaderInclusionPath {
52094faa4d0SJohn Thompson public:
HeaderInclusionPath(std::vector<HeaderHandle> HeaderInclusionPath)52194faa4d0SJohn Thompson   HeaderInclusionPath(std::vector<HeaderHandle> HeaderInclusionPath)
52294faa4d0SJohn Thompson       : Path(HeaderInclusionPath) {}
HeaderInclusionPath(const HeaderInclusionPath & Other)52394faa4d0SJohn Thompson   HeaderInclusionPath(const HeaderInclusionPath &Other) : Path(Other.Path) {}
HeaderInclusionPath()52494faa4d0SJohn Thompson   HeaderInclusionPath() {}
52594faa4d0SJohn Thompson   std::vector<HeaderHandle> Path;
52694faa4d0SJohn Thompson };
52794faa4d0SJohn Thompson 
52894faa4d0SJohn Thompson // Macro expansion instance.
52994faa4d0SJohn Thompson //
53094faa4d0SJohn Thompson // This class represents an instance of a macro expansion with a
53194faa4d0SJohn Thompson // unique value.  It also stores the unique header inclusion paths
5327c6e79f3SJohn Thompson // for use in telling the user the nested include path to the header.
53394faa4d0SJohn Thompson class MacroExpansionInstance {
53494faa4d0SJohn Thompson public:
MacroExpansionInstance(StringHandle MacroExpanded,PPItemKey & DefinitionLocation,StringHandle DefinitionSourceLine,InclusionPathHandle H)53594faa4d0SJohn Thompson   MacroExpansionInstance(StringHandle MacroExpanded,
53694faa4d0SJohn Thompson                          PPItemKey &DefinitionLocation,
53794faa4d0SJohn Thompson                          StringHandle DefinitionSourceLine,
53894faa4d0SJohn Thompson                          InclusionPathHandle H)
53994faa4d0SJohn Thompson       : MacroExpanded(MacroExpanded), DefinitionLocation(DefinitionLocation),
54094faa4d0SJohn Thompson         DefinitionSourceLine(DefinitionSourceLine) {
54194faa4d0SJohn Thompson     InclusionPathHandles.push_back(H);
54294faa4d0SJohn Thompson   }
MacroExpansionInstance()54394faa4d0SJohn Thompson   MacroExpansionInstance() {}
54494faa4d0SJohn Thompson 
54594faa4d0SJohn Thompson   // Check for the presence of a header inclusion path handle entry.
54694faa4d0SJohn Thompson   // Return false if not found.
haveInclusionPathHandle(InclusionPathHandle H)54794faa4d0SJohn Thompson   bool haveInclusionPathHandle(InclusionPathHandle H) {
54808124b11SPiotr Padlewski     for (auto I = InclusionPathHandles.begin(), E = InclusionPathHandles.end();
54994faa4d0SJohn Thompson          I != E; ++I) {
55094faa4d0SJohn Thompson       if (*I == H)
55194faa4d0SJohn Thompson         return true;
55294faa4d0SJohn Thompson     }
55394faa4d0SJohn Thompson     return InclusionPathHandleInvalid;
55494faa4d0SJohn Thompson   }
55594faa4d0SJohn Thompson   // Add a new header inclusion path entry, if not already present.
addInclusionPathHandle(InclusionPathHandle H)55694faa4d0SJohn Thompson   void addInclusionPathHandle(InclusionPathHandle H) {
55794faa4d0SJohn Thompson     if (!haveInclusionPathHandle(H))
55894faa4d0SJohn Thompson       InclusionPathHandles.push_back(H);
55994faa4d0SJohn Thompson   }
56094faa4d0SJohn Thompson 
56194faa4d0SJohn Thompson   // A string representing the macro instance after preprocessing.
56294faa4d0SJohn Thompson   StringHandle MacroExpanded;
56394faa4d0SJohn Thompson   // A file/line/column triplet representing the macro definition location.
56494faa4d0SJohn Thompson   PPItemKey DefinitionLocation;
56594faa4d0SJohn Thompson   // A place to save the macro definition line string.
56694faa4d0SJohn Thompson   StringHandle DefinitionSourceLine;
56794faa4d0SJohn Thompson   // The header inclusion path handles for all the instances.
56894faa4d0SJohn Thompson   std::vector<InclusionPathHandle> InclusionPathHandles;
56994faa4d0SJohn Thompson };
57094faa4d0SJohn Thompson 
57194faa4d0SJohn Thompson // Macro expansion instance tracker.
57294faa4d0SJohn Thompson //
57394faa4d0SJohn Thompson // This class represents one macro expansion, keyed by a PPItemKey.
57494faa4d0SJohn Thompson // It stores a string representing the macro reference in the source,
57594faa4d0SJohn Thompson // and a list of ConditionalExpansionInstances objects representing
5767c6e79f3SJohn Thompson // the unique values the condition expands to in instances of the header.
57794faa4d0SJohn Thompson class MacroExpansionTracker {
57894faa4d0SJohn Thompson public:
MacroExpansionTracker(StringHandle MacroUnexpanded,StringHandle MacroExpanded,StringHandle InstanceSourceLine,PPItemKey & DefinitionLocation,StringHandle DefinitionSourceLine,InclusionPathHandle InclusionPathHandle)57994faa4d0SJohn Thompson   MacroExpansionTracker(StringHandle MacroUnexpanded,
58094faa4d0SJohn Thompson                         StringHandle MacroExpanded,
58194faa4d0SJohn Thompson                         StringHandle InstanceSourceLine,
58294faa4d0SJohn Thompson                         PPItemKey &DefinitionLocation,
58394faa4d0SJohn Thompson                         StringHandle DefinitionSourceLine,
58494faa4d0SJohn Thompson                         InclusionPathHandle InclusionPathHandle)
58594faa4d0SJohn Thompson       : MacroUnexpanded(MacroUnexpanded),
58694faa4d0SJohn Thompson         InstanceSourceLine(InstanceSourceLine) {
58794faa4d0SJohn Thompson     addMacroExpansionInstance(MacroExpanded, DefinitionLocation,
58894faa4d0SJohn Thompson                               DefinitionSourceLine, InclusionPathHandle);
58994faa4d0SJohn Thompson   }
MacroExpansionTracker()59094faa4d0SJohn Thompson   MacroExpansionTracker() {}
59194faa4d0SJohn Thompson 
59294faa4d0SJohn Thompson   // Find a matching macro expansion instance.
59394faa4d0SJohn Thompson   MacroExpansionInstance *
findMacroExpansionInstance(StringHandle MacroExpanded,PPItemKey & DefinitionLocation)59494faa4d0SJohn Thompson   findMacroExpansionInstance(StringHandle MacroExpanded,
59594faa4d0SJohn Thompson                              PPItemKey &DefinitionLocation) {
59608124b11SPiotr Padlewski     for (auto I = MacroExpansionInstances.begin(),
59794faa4d0SJohn Thompson               E = MacroExpansionInstances.end();
59894faa4d0SJohn Thompson          I != E; ++I) {
59994faa4d0SJohn Thompson       if ((I->MacroExpanded == MacroExpanded) &&
60094faa4d0SJohn Thompson           (I->DefinitionLocation == DefinitionLocation)) {
60194faa4d0SJohn Thompson         return &*I; // Found.
60294faa4d0SJohn Thompson       }
60394faa4d0SJohn Thompson     }
604f61be9c9SCraig Topper     return nullptr; // Not found.
60594faa4d0SJohn Thompson   }
60694faa4d0SJohn Thompson 
60794faa4d0SJohn Thompson   // Add a macro expansion instance.
addMacroExpansionInstance(StringHandle MacroExpanded,PPItemKey & DefinitionLocation,StringHandle DefinitionSourceLine,InclusionPathHandle InclusionPathHandle)60894faa4d0SJohn Thompson   void addMacroExpansionInstance(StringHandle MacroExpanded,
60994faa4d0SJohn Thompson                                  PPItemKey &DefinitionLocation,
61094faa4d0SJohn Thompson                                  StringHandle DefinitionSourceLine,
61194faa4d0SJohn Thompson                                  InclusionPathHandle InclusionPathHandle) {
61294faa4d0SJohn Thompson     MacroExpansionInstances.push_back(
61394faa4d0SJohn Thompson         MacroExpansionInstance(MacroExpanded, DefinitionLocation,
61494faa4d0SJohn Thompson                                DefinitionSourceLine, InclusionPathHandle));
61594faa4d0SJohn Thompson   }
61694faa4d0SJohn Thompson 
61794faa4d0SJohn Thompson   // Return true if there is a mismatch.
hasMismatch()61894faa4d0SJohn Thompson   bool hasMismatch() { return MacroExpansionInstances.size() > 1; }
61994faa4d0SJohn Thompson 
62094faa4d0SJohn Thompson   // A string representing the macro instance without expansion.
62194faa4d0SJohn Thompson   StringHandle MacroUnexpanded;
62294faa4d0SJohn Thompson   // A place to save the macro instance source line string.
62394faa4d0SJohn Thompson   StringHandle InstanceSourceLine;
62494faa4d0SJohn Thompson   // The macro expansion instances.
62594faa4d0SJohn Thompson   // If all instances of the macro expansion expand to the same value,
62694faa4d0SJohn Thompson   // This vector will only have one instance.
62794faa4d0SJohn Thompson   std::vector<MacroExpansionInstance> MacroExpansionInstances;
62894faa4d0SJohn Thompson };
62994faa4d0SJohn Thompson 
63094faa4d0SJohn Thompson // Conditional expansion instance.
63194faa4d0SJohn Thompson //
6327c6e79f3SJohn Thompson // This class represents an instance of a condition exoression result
6337c6e79f3SJohn Thompson // with a unique value.  It also stores the unique header inclusion paths
6347c6e79f3SJohn Thompson // for use in telling the user the nested include path to the header.
63594faa4d0SJohn Thompson class ConditionalExpansionInstance {
63694faa4d0SJohn Thompson public:
ConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue,InclusionPathHandle H)63787f9fef5SJohn Thompson   ConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue, InclusionPathHandle H)
63894faa4d0SJohn Thompson       : ConditionValue(ConditionValue) {
63994faa4d0SJohn Thompson     InclusionPathHandles.push_back(H);
64094faa4d0SJohn Thompson   }
ConditionalExpansionInstance()64194faa4d0SJohn Thompson   ConditionalExpansionInstance() {}
64294faa4d0SJohn Thompson 
64394faa4d0SJohn Thompson   // Check for the presence of a header inclusion path handle entry.
64494faa4d0SJohn Thompson   // Return false if not found.
haveInclusionPathHandle(InclusionPathHandle H)64594faa4d0SJohn Thompson   bool haveInclusionPathHandle(InclusionPathHandle H) {
64608124b11SPiotr Padlewski     for (auto I = InclusionPathHandles.begin(), E = InclusionPathHandles.end();
64794faa4d0SJohn Thompson          I != E; ++I) {
64894faa4d0SJohn Thompson       if (*I == H)
64994faa4d0SJohn Thompson         return true;
65094faa4d0SJohn Thompson     }
65194faa4d0SJohn Thompson     return InclusionPathHandleInvalid;
65294faa4d0SJohn Thompson   }
65394faa4d0SJohn Thompson   // Add a new header inclusion path entry, if not already present.
addInclusionPathHandle(InclusionPathHandle H)65494faa4d0SJohn Thompson   void addInclusionPathHandle(InclusionPathHandle H) {
65594faa4d0SJohn Thompson     if (!haveInclusionPathHandle(H))
65694faa4d0SJohn Thompson       InclusionPathHandles.push_back(H);
65794faa4d0SJohn Thompson   }
65894faa4d0SJohn Thompson 
65994faa4d0SJohn Thompson   // A flag representing the evaluated condition value.
66087f9fef5SJohn Thompson   clang::PPCallbacks::ConditionValueKind ConditionValue;
66194faa4d0SJohn Thompson   // The header inclusion path handles for all the instances.
66294faa4d0SJohn Thompson   std::vector<InclusionPathHandle> InclusionPathHandles;
66394faa4d0SJohn Thompson };
66494faa4d0SJohn Thompson 
66594faa4d0SJohn Thompson // Conditional directive instance tracker.
66694faa4d0SJohn Thompson //
66794faa4d0SJohn Thompson // This class represents one conditional directive, keyed by a PPItemKey.
66894faa4d0SJohn Thompson // It stores a string representing the macro reference in the source,
6697c6e79f3SJohn Thompson // and a list of ConditionExpansionInstance objects representing
6707c6e79f3SJohn Thompson // the unique value the condition expression expands to in instances of
6717c6e79f3SJohn Thompson // the header.
67294faa4d0SJohn Thompson class ConditionalTracker {
67394faa4d0SJohn Thompson public:
ConditionalTracker(clang::tok::PPKeywordKind DirectiveKind,clang::PPCallbacks::ConditionValueKind ConditionValue,StringHandle ConditionUnexpanded,InclusionPathHandle InclusionPathHandle)67494faa4d0SJohn Thompson   ConditionalTracker(clang::tok::PPKeywordKind DirectiveKind,
67587f9fef5SJohn Thompson                      clang::PPCallbacks::ConditionValueKind ConditionValue,
67687f9fef5SJohn Thompson                      StringHandle ConditionUnexpanded,
67794faa4d0SJohn Thompson                      InclusionPathHandle InclusionPathHandle)
67894faa4d0SJohn Thompson       : DirectiveKind(DirectiveKind), ConditionUnexpanded(ConditionUnexpanded) {
67994faa4d0SJohn Thompson     addConditionalExpansionInstance(ConditionValue, InclusionPathHandle);
68094faa4d0SJohn Thompson   }
ConditionalTracker()68194faa4d0SJohn Thompson   ConditionalTracker() {}
68294faa4d0SJohn Thompson 
68394faa4d0SJohn Thompson   // Find a matching condition expansion instance.
68494faa4d0SJohn Thompson   ConditionalExpansionInstance *
findConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue)68587f9fef5SJohn Thompson   findConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue) {
68608124b11SPiotr Padlewski     for (auto I = ConditionalExpansionInstances.begin(),
68794faa4d0SJohn Thompson               E = ConditionalExpansionInstances.end();
68894faa4d0SJohn Thompson          I != E; ++I) {
68994faa4d0SJohn Thompson       if (I->ConditionValue == ConditionValue) {
69094faa4d0SJohn Thompson         return &*I; // Found.
69194faa4d0SJohn Thompson       }
69294faa4d0SJohn Thompson     }
693f61be9c9SCraig Topper     return nullptr; // Not found.
69494faa4d0SJohn Thompson   }
69594faa4d0SJohn Thompson 
69694faa4d0SJohn Thompson   // Add a conditional expansion instance.
69794faa4d0SJohn Thompson   void
addConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue,InclusionPathHandle InclusionPathHandle)69887f9fef5SJohn Thompson   addConditionalExpansionInstance(clang::PPCallbacks::ConditionValueKind ConditionValue,
69994faa4d0SJohn Thompson                                   InclusionPathHandle InclusionPathHandle) {
70094faa4d0SJohn Thompson     ConditionalExpansionInstances.push_back(
70194faa4d0SJohn Thompson         ConditionalExpansionInstance(ConditionValue, InclusionPathHandle));
70294faa4d0SJohn Thompson   }
70394faa4d0SJohn Thompson 
70494faa4d0SJohn Thompson   // Return true if there is a mismatch.
hasMismatch()70594faa4d0SJohn Thompson   bool hasMismatch() { return ConditionalExpansionInstances.size() > 1; }
70694faa4d0SJohn Thompson 
70794faa4d0SJohn Thompson   // The kind of directive.
70894faa4d0SJohn Thompson   clang::tok::PPKeywordKind DirectiveKind;
70994faa4d0SJohn Thompson   // A string representing the macro instance without expansion.
71094faa4d0SJohn Thompson   StringHandle ConditionUnexpanded;
71194faa4d0SJohn Thompson   // The condition expansion instances.
71294faa4d0SJohn Thompson   // If all instances of the conditional expression expand to the same value,
71394faa4d0SJohn Thompson   // This vector will only have one instance.
71494faa4d0SJohn Thompson   std::vector<ConditionalExpansionInstance> ConditionalExpansionInstances;
71594faa4d0SJohn Thompson };
71694faa4d0SJohn Thompson 
717e7103712SBenjamin Kramer class PreprocessorTrackerImpl;
718e7103712SBenjamin Kramer 
71994faa4d0SJohn Thompson // Preprocessor callbacks for modularize.
72094faa4d0SJohn Thompson //
72194faa4d0SJohn Thompson // This class derives from the Clang PPCallbacks class to track preprocessor
72294faa4d0SJohn Thompson // actions, such as changing files and handling preprocessor directives and
72394faa4d0SJohn Thompson // macro expansions.  It has to figure out when a new header file is entered
72494faa4d0SJohn Thompson // and left, as the provided handler is not particularly clear about it.
72594faa4d0SJohn Thompson class PreprocessorCallbacks : public clang::PPCallbacks {
72694faa4d0SJohn Thompson public:
PreprocessorCallbacks(PreprocessorTrackerImpl & ppTracker,clang::Preprocessor & PP,llvm::StringRef rootHeaderFile)72794faa4d0SJohn Thompson   PreprocessorCallbacks(PreprocessorTrackerImpl &ppTracker,
72894faa4d0SJohn Thompson                         clang::Preprocessor &PP, llvm::StringRef rootHeaderFile)
72994faa4d0SJohn Thompson       : PPTracker(ppTracker), PP(PP), RootHeaderFile(rootHeaderFile) {}
~PreprocessorCallbacks()730e04a3da0SDavid Blaikie   ~PreprocessorCallbacks() override {}
73194faa4d0SJohn Thompson 
73294faa4d0SJohn Thompson   // Overridden handlers.
73374083926SJohn Thompson   void InclusionDirective(clang::SourceLocation HashLoc,
73474083926SJohn Thompson                           const clang::Token &IncludeTok,
73574083926SJohn Thompson                           llvm::StringRef FileName, bool IsAngled,
73674083926SJohn Thompson                           clang::CharSourceRange FilenameRange,
737*d79ad2f1SJan Svoboda                           llvm::Optional<clang::FileEntryRef> File,
73874083926SJohn Thompson                           llvm::StringRef SearchPath,
73974083926SJohn Thompson                           llvm::StringRef RelativePath,
740546943f9SJulie Hockett                           const clang::Module *Imported,
741546943f9SJulie Hockett                           clang::SrcMgr::CharacteristicKind FileType) override;
74294faa4d0SJohn Thompson   void FileChanged(clang::SourceLocation Loc,
74394faa4d0SJohn Thompson                    clang::PPCallbacks::FileChangeReason Reason,
74494faa4d0SJohn Thompson                    clang::SrcMgr::CharacteristicKind FileType,
74587638f63SAlexander Kornienko                    clang::FileID PrevFID = clang::FileID()) override;
74694faa4d0SJohn Thompson   void MacroExpands(const clang::Token &MacroNameTok,
74733de8566SRichard Smith                     const clang::MacroDefinition &MD, clang::SourceRange Range,
74887638f63SAlexander Kornienko                     const clang::MacroArgs *Args) override;
74994faa4d0SJohn Thompson   void Defined(const clang::Token &MacroNameTok,
75033de8566SRichard Smith                const clang::MacroDefinition &MD,
75187638f63SAlexander Kornienko                clang::SourceRange Range) override;
75294faa4d0SJohn Thompson   void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
75387638f63SAlexander Kornienko           clang::PPCallbacks::ConditionValueKind ConditionResult) override;
75494faa4d0SJohn Thompson   void Elif(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
75587638f63SAlexander Kornienko             clang::PPCallbacks::ConditionValueKind ConditionResult,
75687638f63SAlexander Kornienko             clang::SourceLocation IfLoc) override;
75794faa4d0SJohn Thompson   void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
75833de8566SRichard Smith              const clang::MacroDefinition &MD) override;
75994faa4d0SJohn Thompson   void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
76033de8566SRichard Smith               const clang::MacroDefinition &MD) override;
76194faa4d0SJohn Thompson 
76294faa4d0SJohn Thompson private:
76394faa4d0SJohn Thompson   PreprocessorTrackerImpl &PPTracker;
76494faa4d0SJohn Thompson   clang::Preprocessor &PP;
76594faa4d0SJohn Thompson   std::string RootHeaderFile;
76694faa4d0SJohn Thompson };
76794faa4d0SJohn Thompson 
76894faa4d0SJohn Thompson // Preprocessor macro expansion item map types.
76994faa4d0SJohn Thompson typedef std::map<PPItemKey, MacroExpansionTracker> MacroExpansionMap;
77094faa4d0SJohn Thompson typedef std::map<PPItemKey, MacroExpansionTracker>::iterator
77194faa4d0SJohn Thompson MacroExpansionMapIter;
77294faa4d0SJohn Thompson 
77394faa4d0SJohn Thompson // Preprocessor conditional expansion item map types.
77494faa4d0SJohn Thompson typedef std::map<PPItemKey, ConditionalTracker> ConditionalExpansionMap;
77594faa4d0SJohn Thompson typedef std::map<PPItemKey, ConditionalTracker>::iterator
77694faa4d0SJohn Thompson ConditionalExpansionMapIter;
77794faa4d0SJohn Thompson 
77894faa4d0SJohn Thompson // Preprocessor tracker for modularize.
77994faa4d0SJohn Thompson //
78094faa4d0SJohn Thompson // This class stores information about all the headers processed in the
78194faa4d0SJohn Thompson // course of running modularize.
78294faa4d0SJohn Thompson class PreprocessorTrackerImpl : public PreprocessorTracker {
78394faa4d0SJohn Thompson public:
PreprocessorTrackerImpl(llvm::SmallVector<std::string,32> & Headers,bool DoBlockCheckHeaderListOnly)784ecd3b04cSJohn Thompson   PreprocessorTrackerImpl(llvm::SmallVector<std::string, 32> &Headers,
785ecd3b04cSJohn Thompson         bool DoBlockCheckHeaderListOnly)
786ecd3b04cSJohn Thompson       : BlockCheckHeaderListOnly(DoBlockCheckHeaderListOnly),
787ecd3b04cSJohn Thompson         CurrentInclusionPathHandle(InclusionPathHandleInvalid),
788ecd3b04cSJohn Thompson         InNestedHeader(false) {
789ecd3b04cSJohn Thompson     // Use canonical header path representation.
790ecd3b04cSJohn Thompson     for (llvm::ArrayRef<std::string>::iterator I = Headers.begin(),
791ecd3b04cSJohn Thompson       E = Headers.end();
792ecd3b04cSJohn Thompson       I != E; ++I) {
793ecd3b04cSJohn Thompson       HeaderList.push_back(getCanonicalPath(*I));
794ecd3b04cSJohn Thompson     }
795ecd3b04cSJohn Thompson   }
796ecd3b04cSJohn Thompson 
~PreprocessorTrackerImpl()797e04a3da0SDavid Blaikie   ~PreprocessorTrackerImpl() override {}
79894faa4d0SJohn Thompson 
79994faa4d0SJohn Thompson   // Handle entering a preprocessing session.
handlePreprocessorEntry(clang::Preprocessor & PP,llvm::StringRef rootHeaderFile)80094faa4d0SJohn Thompson   void handlePreprocessorEntry(clang::Preprocessor &PP,
80187638f63SAlexander Kornienko                                llvm::StringRef rootHeaderFile) override {
8024ed963a0SJohn Thompson     HeadersInThisCompile.clear();
80394faa4d0SJohn Thompson     assert((HeaderStack.size() == 0) && "Header stack should be empty.");
80494faa4d0SJohn Thompson     pushHeaderHandle(addHeader(rootHeaderFile));
8051c705d9cSJonas Devlieghere     PP.addPPCallbacks(std::make_unique<PreprocessorCallbacks>(*this, PP,
806775862a2SCraig Topper                                                                rootHeaderFile));
80794faa4d0SJohn Thompson   }
80894faa4d0SJohn Thompson   // Handle exiting a preprocessing session.
handlePreprocessorExit()80987638f63SAlexander Kornienko   void handlePreprocessorExit() override { HeaderStack.clear(); }
81094faa4d0SJohn Thompson 
81174083926SJohn Thompson   // Handle include directive.
81274083926SJohn Thompson   // This function is called every time an include directive is seen by the
81374083926SJohn Thompson   // preprocessor, for the purpose of later checking for 'extern "" {}' or
81474083926SJohn Thompson   // "namespace {}" blocks containing #include directives.
handleIncludeDirective(llvm::StringRef DirectivePath,int DirectiveLine,int DirectiveColumn,llvm::StringRef TargetPath)81574083926SJohn Thompson   void handleIncludeDirective(llvm::StringRef DirectivePath, int DirectiveLine,
81687638f63SAlexander Kornienko                               int DirectiveColumn,
81787638f63SAlexander Kornienko                               llvm::StringRef TargetPath) override {
818ecd3b04cSJohn Thompson     // If it's not a header in the header list, ignore it with respect to
819ecd3b04cSJohn Thompson     // the check.
8209ea81b00SJohn Thompson     if (BlockCheckHeaderListOnly && !isHeaderListHeader(TargetPath))
821ecd3b04cSJohn Thompson       return;
82274083926SJohn Thompson     HeaderHandle CurrentHeaderHandle = findHeaderHandle(DirectivePath);
82374083926SJohn Thompson     StringHandle IncludeHeaderHandle = addString(TargetPath);
82474083926SJohn Thompson     for (std::vector<PPItemKey>::const_iterator I = IncludeDirectives.begin(),
82574083926SJohn Thompson                                                 E = IncludeDirectives.end();
82674083926SJohn Thompson          I != E; ++I) {
82774083926SJohn Thompson       // If we already have an entry for this directive, return now.
82874083926SJohn Thompson       if ((I->File == CurrentHeaderHandle) && (I->Line == DirectiveLine))
82974083926SJohn Thompson         return;
83074083926SJohn Thompson     }
83174083926SJohn Thompson     PPItemKey IncludeDirectiveItem(IncludeHeaderHandle, CurrentHeaderHandle,
83274083926SJohn Thompson                                    DirectiveLine, DirectiveColumn);
83374083926SJohn Thompson     IncludeDirectives.push_back(IncludeDirectiveItem);
83474083926SJohn Thompson   }
83574083926SJohn Thompson 
83674083926SJohn Thompson   // Check for include directives within the given source line range.
83774083926SJohn Thompson   // Report errors if any found.  Returns true if no include directives
83874083926SJohn Thompson   // found in block.
checkForIncludesInBlock(clang::Preprocessor & PP,clang::SourceRange BlockSourceRange,const char * BlockIdentifierMessage,llvm::raw_ostream & OS)83974083926SJohn Thompson   bool checkForIncludesInBlock(clang::Preprocessor &PP,
84074083926SJohn Thompson                                clang::SourceRange BlockSourceRange,
84174083926SJohn Thompson                                const char *BlockIdentifierMessage,
84287638f63SAlexander Kornienko                                llvm::raw_ostream &OS) override {
84374083926SJohn Thompson     clang::SourceLocation BlockStartLoc = BlockSourceRange.getBegin();
84474083926SJohn Thompson     clang::SourceLocation BlockEndLoc = BlockSourceRange.getEnd();
84574083926SJohn Thompson     // Use block location to get FileID of both the include directive
84674083926SJohn Thompson     // and block statement.
84774083926SJohn Thompson     clang::FileID FileID = PP.getSourceManager().getFileID(BlockStartLoc);
84874083926SJohn Thompson     std::string SourcePath = getSourceLocationFile(PP, BlockStartLoc);
849b70ecf6eSJohn Thompson     SourcePath = ModularizeUtilities::getCanonicalPath(SourcePath);
85074083926SJohn Thompson     HeaderHandle SourceHandle = findHeaderHandle(SourcePath);
851b87fd7dbSJohn Thompson     if (SourceHandle == -1)
852b87fd7dbSJohn Thompson       return true;
85374083926SJohn Thompson     int BlockStartLine, BlockStartColumn, BlockEndLine, BlockEndColumn;
85474083926SJohn Thompson     bool returnValue = true;
85574083926SJohn Thompson     getSourceLocationLineAndColumn(PP, BlockStartLoc, BlockStartLine,
85674083926SJohn Thompson                                    BlockStartColumn);
85774083926SJohn Thompson     getSourceLocationLineAndColumn(PP, BlockEndLoc, BlockEndLine,
85874083926SJohn Thompson                                    BlockEndColumn);
85974083926SJohn Thompson     for (std::vector<PPItemKey>::const_iterator I = IncludeDirectives.begin(),
86074083926SJohn Thompson                                                 E = IncludeDirectives.end();
86174083926SJohn Thompson          I != E; ++I) {
86274083926SJohn Thompson       // If we find an entry within the block, report an error.
86374083926SJohn Thompson       if ((I->File == SourceHandle) && (I->Line >= BlockStartLine) &&
86474083926SJohn Thompson           (I->Line < BlockEndLine)) {
86574083926SJohn Thompson         returnValue = false;
866a2b66875SJohn Thompson         OS << SourcePath << ":" << I->Line << ":" << I->Column << ":\n";
86774083926SJohn Thompson         OS << getSourceLine(PP, FileID, I->Line) << "\n";
86874083926SJohn Thompson         if (I->Column > 0)
86974083926SJohn Thompson           OS << std::string(I->Column - 1, ' ') << "^\n";
87074083926SJohn Thompson         OS << "error: Include directive within " << BlockIdentifierMessage
87174083926SJohn Thompson            << ".\n";
87274083926SJohn Thompson         OS << SourcePath << ":" << BlockStartLine << ":" << BlockStartColumn
873a2b66875SJohn Thompson            << ":\n";
87474083926SJohn Thompson         OS << getSourceLine(PP, BlockStartLoc) << "\n";
87574083926SJohn Thompson         if (BlockStartColumn > 0)
87674083926SJohn Thompson           OS << std::string(BlockStartColumn - 1, ' ') << "^\n";
87774083926SJohn Thompson         OS << "The \"" << BlockIdentifierMessage << "\" block is here.\n";
87874083926SJohn Thompson       }
87974083926SJohn Thompson     }
88074083926SJohn Thompson     return returnValue;
88174083926SJohn Thompson   }
88274083926SJohn Thompson 
88394faa4d0SJohn Thompson   // Handle entering a header source file.
handleHeaderEntry(clang::Preprocessor & PP,llvm::StringRef HeaderPath)88494faa4d0SJohn Thompson   void handleHeaderEntry(clang::Preprocessor &PP, llvm::StringRef HeaderPath) {
88594faa4d0SJohn Thompson     // Ignore <built-in> and <command-line> to reduce message clutter.
88694faa4d0SJohn Thompson     if (HeaderPath.startswith("<"))
88794faa4d0SJohn Thompson       return;
88894faa4d0SJohn Thompson     HeaderHandle H = addHeader(HeaderPath);
8894ed963a0SJohn Thompson     if (H != getCurrentHeaderHandle())
8904ed963a0SJohn Thompson       pushHeaderHandle(H);
89148df096cSJohn Thompson     // Check for nested header.
89248df096cSJohn Thompson     if (!InNestedHeader)
89334318816SDavid Blaikie       InNestedHeader = !HeadersInThisCompile.insert(H).second;
89448df096cSJohn Thompson   }
895ecd3b04cSJohn Thompson 
89694faa4d0SJohn Thompson   // Handle exiting a header source file.
handleHeaderExit(llvm::StringRef HeaderPath)89794faa4d0SJohn Thompson   void handleHeaderExit(llvm::StringRef HeaderPath) {
89894faa4d0SJohn Thompson     // Ignore <built-in> and <command-line> to reduce message clutter.
89994faa4d0SJohn Thompson     if (HeaderPath.startswith("<"))
90094faa4d0SJohn Thompson       return;
90194faa4d0SJohn Thompson     HeaderHandle H = findHeaderHandle(HeaderPath);
902f1828ef3SJohn Thompson     HeaderHandle TH;
90394faa4d0SJohn Thompson     if (isHeaderHandleInStack(H)) {
904f1828ef3SJohn Thompson       do {
905f1828ef3SJohn Thompson         TH = getCurrentHeaderHandle();
90694faa4d0SJohn Thompson         popHeaderHandle();
907f1828ef3SJohn Thompson       } while ((TH != H) && (HeaderStack.size() != 0));
90894faa4d0SJohn Thompson     }
90948df096cSJohn Thompson     InNestedHeader = false;
91094faa4d0SJohn Thompson   }
91194faa4d0SJohn Thompson 
91294faa4d0SJohn Thompson   // Lookup/add string.
addString(llvm::StringRef Str)91339c9c12bSChris Lattner   StringHandle addString(llvm::StringRef Str) {
91439c9c12bSChris Lattner     return Strings.insert(Str).first->first();
91539c9c12bSChris Lattner   }
91694faa4d0SJohn Thompson 
9179724431cSJohn Thompson   // Convert to a canonical path.
getCanonicalPath(llvm::StringRef path) const9189724431cSJohn Thompson   std::string getCanonicalPath(llvm::StringRef path) const {
9199724431cSJohn Thompson     std::string CanonicalPath(path);
9209724431cSJohn Thompson     std::replace(CanonicalPath.begin(), CanonicalPath.end(), '\\', '/');
9219724431cSJohn Thompson     return CanonicalPath;
9229724431cSJohn Thompson   }
9239724431cSJohn Thompson 
924ecd3b04cSJohn Thompson   // Return true if the given header is in the header list.
isHeaderListHeader(llvm::StringRef HeaderPath) const925ecd3b04cSJohn Thompson   bool isHeaderListHeader(llvm::StringRef HeaderPath) const {
926ecd3b04cSJohn Thompson     std::string CanonicalPath = getCanonicalPath(HeaderPath);
927ecd3b04cSJohn Thompson     for (llvm::ArrayRef<std::string>::iterator I = HeaderList.begin(),
928ecd3b04cSJohn Thompson         E = HeaderList.end();
929ecd3b04cSJohn Thompson         I != E; ++I) {
930ecd3b04cSJohn Thompson       if (*I == CanonicalPath)
931ecd3b04cSJohn Thompson         return true;
932ecd3b04cSJohn Thompson     }
933ecd3b04cSJohn Thompson     return false;
934ecd3b04cSJohn Thompson   }
935ecd3b04cSJohn Thompson 
93694faa4d0SJohn Thompson   // Get the handle of a header file entry.
93794faa4d0SJohn Thompson   // Return HeaderHandleInvalid if not found.
findHeaderHandle(llvm::StringRef HeaderPath) const93894faa4d0SJohn Thompson   HeaderHandle findHeaderHandle(llvm::StringRef HeaderPath) const {
9399724431cSJohn Thompson     std::string CanonicalPath = getCanonicalPath(HeaderPath);
94094faa4d0SJohn Thompson     HeaderHandle H = 0;
94108124b11SPiotr Padlewski     for (auto I = HeaderPaths.begin(), E = HeaderPaths.end(); I != E;
94208124b11SPiotr Padlewski          ++I, ++H) {
94339c9c12bSChris Lattner       if (*I == CanonicalPath)
94494faa4d0SJohn Thompson         return H;
94594faa4d0SJohn Thompson     }
94694faa4d0SJohn Thompson     return HeaderHandleInvalid;
94794faa4d0SJohn Thompson   }
94894faa4d0SJohn Thompson 
94994faa4d0SJohn Thompson   // Add a new header file entry, or return existing handle.
95094faa4d0SJohn Thompson   // Return the header handle.
addHeader(llvm::StringRef HeaderPath)95194faa4d0SJohn Thompson   HeaderHandle addHeader(llvm::StringRef HeaderPath) {
9529724431cSJohn Thompson     std::string CanonicalPath = getCanonicalPath(HeaderPath);
95348df096cSJohn Thompson     HeaderHandle H = findHeaderHandle(CanonicalPath);
95494faa4d0SJohn Thompson     if (H == HeaderHandleInvalid) {
95594faa4d0SJohn Thompson       H = HeaderPaths.size();
95648df096cSJohn Thompson       HeaderPaths.push_back(addString(CanonicalPath));
95794faa4d0SJohn Thompson     }
95894faa4d0SJohn Thompson     return H;
95994faa4d0SJohn Thompson   }
96094faa4d0SJohn Thompson 
96194faa4d0SJohn Thompson   // Return a header file path string given its handle.
getHeaderFilePath(HeaderHandle H) const96294faa4d0SJohn Thompson   StringHandle getHeaderFilePath(HeaderHandle H) const {
96394faa4d0SJohn Thompson     if ((H >= 0) && (H < (HeaderHandle)HeaderPaths.size()))
96494faa4d0SJohn Thompson       return HeaderPaths[H];
96594faa4d0SJohn Thompson     return StringHandle();
96694faa4d0SJohn Thompson   }
96794faa4d0SJohn Thompson 
96894faa4d0SJohn Thompson   // Returns a handle to the inclusion path.
pushHeaderHandle(HeaderHandle H)96994faa4d0SJohn Thompson   InclusionPathHandle pushHeaderHandle(HeaderHandle H) {
97094faa4d0SJohn Thompson     HeaderStack.push_back(H);
97194faa4d0SJohn Thompson     return CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
97294faa4d0SJohn Thompson   }
97394faa4d0SJohn Thompson   // Pops the last header handle from the stack;
popHeaderHandle()97494faa4d0SJohn Thompson   void popHeaderHandle() {
97594faa4d0SJohn Thompson     // assert((HeaderStack.size() != 0) && "Header stack already empty.");
97694faa4d0SJohn Thompson     if (HeaderStack.size() != 0) {
97794faa4d0SJohn Thompson       HeaderStack.pop_back();
97894faa4d0SJohn Thompson       CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
97994faa4d0SJohn Thompson     }
98094faa4d0SJohn Thompson   }
98194faa4d0SJohn Thompson   // Get the top handle on the header stack.
getCurrentHeaderHandle() const98294faa4d0SJohn Thompson   HeaderHandle getCurrentHeaderHandle() const {
98394faa4d0SJohn Thompson     if (HeaderStack.size() != 0)
98494faa4d0SJohn Thompson       return HeaderStack.back();
98594faa4d0SJohn Thompson     return HeaderHandleInvalid;
98694faa4d0SJohn Thompson   }
98794faa4d0SJohn Thompson 
98894faa4d0SJohn Thompson   // Check for presence of header handle in the header stack.
isHeaderHandleInStack(HeaderHandle H) const98994faa4d0SJohn Thompson   bool isHeaderHandleInStack(HeaderHandle H) const {
99008124b11SPiotr Padlewski     for (auto I = HeaderStack.begin(), E = HeaderStack.end(); I != E; ++I) {
99194faa4d0SJohn Thompson       if (*I == H)
99294faa4d0SJohn Thompson         return true;
99394faa4d0SJohn Thompson     }
99494faa4d0SJohn Thompson     return false;
99594faa4d0SJohn Thompson   }
99694faa4d0SJohn Thompson 
99794faa4d0SJohn Thompson   // Get the handle of a header inclusion path entry.
99894faa4d0SJohn Thompson   // Return InclusionPathHandleInvalid if not found.
99994faa4d0SJohn Thompson   InclusionPathHandle
findInclusionPathHandle(const std::vector<HeaderHandle> & Path) const100094faa4d0SJohn Thompson   findInclusionPathHandle(const std::vector<HeaderHandle> &Path) const {
100194faa4d0SJohn Thompson     InclusionPathHandle H = 0;
100208124b11SPiotr Padlewski     for (auto I = InclusionPaths.begin(), E = InclusionPaths.end(); I != E;
100308124b11SPiotr Padlewski          ++I, ++H) {
100494faa4d0SJohn Thompson       if (I->Path == Path)
100594faa4d0SJohn Thompson         return H;
100694faa4d0SJohn Thompson     }
100794faa4d0SJohn Thompson     return HeaderHandleInvalid;
100894faa4d0SJohn Thompson   }
100994faa4d0SJohn Thompson   // Add a new header inclusion path entry, or return existing handle.
101094faa4d0SJohn Thompson   // Return the header inclusion path entry handle.
101194faa4d0SJohn Thompson   InclusionPathHandle
addInclusionPathHandle(const std::vector<HeaderHandle> & Path)101294faa4d0SJohn Thompson   addInclusionPathHandle(const std::vector<HeaderHandle> &Path) {
101394faa4d0SJohn Thompson     InclusionPathHandle H = findInclusionPathHandle(Path);
101494faa4d0SJohn Thompson     if (H == HeaderHandleInvalid) {
101594faa4d0SJohn Thompson       H = InclusionPaths.size();
101694faa4d0SJohn Thompson       InclusionPaths.push_back(HeaderInclusionPath(Path));
101794faa4d0SJohn Thompson     }
101894faa4d0SJohn Thompson     return H;
101994faa4d0SJohn Thompson   }
102094faa4d0SJohn Thompson   // Return the current inclusion path handle.
getCurrentInclusionPathHandle() const102194faa4d0SJohn Thompson   InclusionPathHandle getCurrentInclusionPathHandle() const {
102294faa4d0SJohn Thompson     return CurrentInclusionPathHandle;
102394faa4d0SJohn Thompson   }
102494faa4d0SJohn Thompson 
102594faa4d0SJohn Thompson   // Return an inclusion path given its handle.
102694faa4d0SJohn Thompson   const std::vector<HeaderHandle> &
getInclusionPath(InclusionPathHandle H) const102794faa4d0SJohn Thompson   getInclusionPath(InclusionPathHandle H) const {
102894faa4d0SJohn Thompson     if ((H >= 0) && (H <= (InclusionPathHandle)InclusionPaths.size()))
102994faa4d0SJohn Thompson       return InclusionPaths[H].Path;
103094faa4d0SJohn Thompson     static std::vector<HeaderHandle> Empty;
103194faa4d0SJohn Thompson     return Empty;
103294faa4d0SJohn Thompson   }
103394faa4d0SJohn Thompson 
103494faa4d0SJohn Thompson   // Add a macro expansion instance.
addMacroExpansionInstance(clang::Preprocessor & PP,HeaderHandle H,clang::SourceLocation InstanceLoc,clang::SourceLocation DefinitionLoc,clang::IdentifierInfo * II,llvm::StringRef MacroUnexpanded,llvm::StringRef MacroExpanded,InclusionPathHandle InclusionPathHandle)103594faa4d0SJohn Thompson   void addMacroExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
103694faa4d0SJohn Thompson                                  clang::SourceLocation InstanceLoc,
103794faa4d0SJohn Thompson                                  clang::SourceLocation DefinitionLoc,
103894faa4d0SJohn Thompson                                  clang::IdentifierInfo *II,
103994faa4d0SJohn Thompson                                  llvm::StringRef MacroUnexpanded,
104094faa4d0SJohn Thompson                                  llvm::StringRef MacroExpanded,
104194faa4d0SJohn Thompson                                  InclusionPathHandle InclusionPathHandle) {
1042c8d710ccSJohn Thompson     if (InNestedHeader)
1043c8d710ccSJohn Thompson       return;
104494faa4d0SJohn Thompson     StringHandle MacroName = addString(II->getName());
104594faa4d0SJohn Thompson     PPItemKey InstanceKey(PP, MacroName, H, InstanceLoc);
104694faa4d0SJohn Thompson     PPItemKey DefinitionKey(PP, MacroName, H, DefinitionLoc);
104708124b11SPiotr Padlewski     auto I = MacroExpansions.find(InstanceKey);
10487c6e79f3SJohn Thompson     // If existing instance of expansion not found, add one.
104994faa4d0SJohn Thompson     if (I == MacroExpansions.end()) {
105094faa4d0SJohn Thompson       std::string InstanceSourceLine =
105194faa4d0SJohn Thompson           getSourceLocationString(PP, InstanceLoc) + ":\n" +
105294faa4d0SJohn Thompson           getSourceLine(PP, InstanceLoc) + "\n";
105394faa4d0SJohn Thompson       std::string DefinitionSourceLine =
105494faa4d0SJohn Thompson           getSourceLocationString(PP, DefinitionLoc) + ":\n" +
105594faa4d0SJohn Thompson           getSourceLine(PP, DefinitionLoc) + "\n";
105694faa4d0SJohn Thompson       MacroExpansions[InstanceKey] = MacroExpansionTracker(
105794faa4d0SJohn Thompson           addString(MacroUnexpanded), addString(MacroExpanded),
105894faa4d0SJohn Thompson           addString(InstanceSourceLine), DefinitionKey,
105994faa4d0SJohn Thompson           addString(DefinitionSourceLine), InclusionPathHandle);
106094faa4d0SJohn Thompson     } else {
10617c6e79f3SJohn Thompson       // We've seen the macro before.  Get its tracker.
106294faa4d0SJohn Thompson       MacroExpansionTracker &CondTracker = I->second;
10637c6e79f3SJohn Thompson       // Look up an existing instance value for the macro.
106494faa4d0SJohn Thompson       MacroExpansionInstance *MacroInfo =
106594faa4d0SJohn Thompson           CondTracker.findMacroExpansionInstance(addString(MacroExpanded),
106694faa4d0SJohn Thompson                                                  DefinitionKey);
10677c6e79f3SJohn Thompson       // If found, just add the inclusion path to the instance.
1068f61be9c9SCraig Topper       if (MacroInfo)
106994faa4d0SJohn Thompson         MacroInfo->addInclusionPathHandle(InclusionPathHandle);
107094faa4d0SJohn Thompson       else {
10717c6e79f3SJohn Thompson         // Otherwise add a new instance with the unique value.
107294faa4d0SJohn Thompson         std::string DefinitionSourceLine =
107394faa4d0SJohn Thompson             getSourceLocationString(PP, DefinitionLoc) + ":\n" +
107494faa4d0SJohn Thompson             getSourceLine(PP, DefinitionLoc) + "\n";
107594faa4d0SJohn Thompson         CondTracker.addMacroExpansionInstance(
107694faa4d0SJohn Thompson             addString(MacroExpanded), DefinitionKey,
107794faa4d0SJohn Thompson             addString(DefinitionSourceLine), InclusionPathHandle);
107894faa4d0SJohn Thompson       }
107994faa4d0SJohn Thompson     }
108094faa4d0SJohn Thompson   }
108194faa4d0SJohn Thompson 
108294faa4d0SJohn Thompson   // Add a conditional expansion instance.
108394faa4d0SJohn Thompson   void
addConditionalExpansionInstance(clang::Preprocessor & PP,HeaderHandle H,clang::SourceLocation InstanceLoc,clang::tok::PPKeywordKind DirectiveKind,clang::PPCallbacks::ConditionValueKind ConditionValue,llvm::StringRef ConditionUnexpanded,InclusionPathHandle InclusionPathHandle)108494faa4d0SJohn Thompson   addConditionalExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
108594faa4d0SJohn Thompson                                   clang::SourceLocation InstanceLoc,
108694faa4d0SJohn Thompson                                   clang::tok::PPKeywordKind DirectiveKind,
108787f9fef5SJohn Thompson                                   clang::PPCallbacks::ConditionValueKind ConditionValue,
108894faa4d0SJohn Thompson                                   llvm::StringRef ConditionUnexpanded,
108994faa4d0SJohn Thompson                                   InclusionPathHandle InclusionPathHandle) {
109048df096cSJohn Thompson     // Ignore header guards, assuming the header guard is the only conditional.
109148df096cSJohn Thompson     if (InNestedHeader)
109248df096cSJohn Thompson       return;
109394faa4d0SJohn Thompson     StringHandle ConditionUnexpandedHandle(addString(ConditionUnexpanded));
109494faa4d0SJohn Thompson     PPItemKey InstanceKey(PP, ConditionUnexpandedHandle, H, InstanceLoc);
109508124b11SPiotr Padlewski     auto I = ConditionalExpansions.find(InstanceKey);
10967c6e79f3SJohn Thompson     // If existing instance of condition not found, add one.
109794faa4d0SJohn Thompson     if (I == ConditionalExpansions.end()) {
109894faa4d0SJohn Thompson       std::string InstanceSourceLine =
109994faa4d0SJohn Thompson           getSourceLocationString(PP, InstanceLoc) + ":\n" +
110094faa4d0SJohn Thompson           getSourceLine(PP, InstanceLoc) + "\n";
110194faa4d0SJohn Thompson       ConditionalExpansions[InstanceKey] =
110248df096cSJohn Thompson           ConditionalTracker(DirectiveKind, ConditionValue,
1103cc2e291dSJohn Thompson                              ConditionUnexpandedHandle, InclusionPathHandle);
110494faa4d0SJohn Thompson     } else {
11057c6e79f3SJohn Thompson       // We've seen the conditional before.  Get its tracker.
110694faa4d0SJohn Thompson       ConditionalTracker &CondTracker = I->second;
11077c6e79f3SJohn Thompson       // Look up an existing instance value for the condition.
110894faa4d0SJohn Thompson       ConditionalExpansionInstance *MacroInfo =
110994faa4d0SJohn Thompson           CondTracker.findConditionalExpansionInstance(ConditionValue);
11107c6e79f3SJohn Thompson       // If found, just add the inclusion path to the instance.
1111f61be9c9SCraig Topper       if (MacroInfo)
111294faa4d0SJohn Thompson         MacroInfo->addInclusionPathHandle(InclusionPathHandle);
111394faa4d0SJohn Thompson       else {
11147c6e79f3SJohn Thompson         // Otherwise add a new instance with the unique value.
111594faa4d0SJohn Thompson         CondTracker.addConditionalExpansionInstance(ConditionValue,
111694faa4d0SJohn Thompson                                                     InclusionPathHandle);
111794faa4d0SJohn Thompson       }
111894faa4d0SJohn Thompson     }
111994faa4d0SJohn Thompson   }
112094faa4d0SJohn Thompson 
112194faa4d0SJohn Thompson   // Report on inconsistent macro instances.
112294faa4d0SJohn Thompson   // Returns true if any mismatches.
reportInconsistentMacros(llvm::raw_ostream & OS)112387638f63SAlexander Kornienko   bool reportInconsistentMacros(llvm::raw_ostream &OS) override {
112494faa4d0SJohn Thompson     bool ReturnValue = false;
11257c6e79f3SJohn Thompson     // Walk all the macro expansion trackers in the map.
112608124b11SPiotr Padlewski     for (auto I = MacroExpansions.begin(), E = MacroExpansions.end(); I != E;
112708124b11SPiotr Padlewski          ++I) {
112894faa4d0SJohn Thompson       const PPItemKey &ItemKey = I->first;
112994faa4d0SJohn Thompson       MacroExpansionTracker &MacroExpTracker = I->second;
11307c6e79f3SJohn Thompson       // If no mismatch (only one instance value) continue.
113194faa4d0SJohn Thompson       if (!MacroExpTracker.hasMismatch())
113294faa4d0SJohn Thompson         continue;
11337c6e79f3SJohn Thompson       // Tell caller we found one or more errors.
113494faa4d0SJohn Thompson       ReturnValue = true;
11357c6e79f3SJohn Thompson       // Start the error message.
113639c9c12bSChris Lattner       OS << MacroExpTracker.InstanceSourceLine;
113794faa4d0SJohn Thompson       if (ItemKey.Column > 0)
113894faa4d0SJohn Thompson         OS << std::string(ItemKey.Column - 1, ' ') << "^\n";
113939c9c12bSChris Lattner       OS << "error: Macro instance '" << MacroExpTracker.MacroUnexpanded
114094faa4d0SJohn Thompson          << "' has different values in this header, depending on how it was "
114194faa4d0SJohn Thompson             "included.\n";
11427c6e79f3SJohn Thompson       // Walk all the instances.
114308124b11SPiotr Padlewski       for (auto IMT = MacroExpTracker.MacroExpansionInstances.begin(),
114494faa4d0SJohn Thompson                 EMT = MacroExpTracker.MacroExpansionInstances.end();
114594faa4d0SJohn Thompson            IMT != EMT; ++IMT) {
114694faa4d0SJohn Thompson         MacroExpansionInstance &MacroInfo = *IMT;
114739c9c12bSChris Lattner         OS << "  '" << MacroExpTracker.MacroUnexpanded << "' expanded to: '"
114839c9c12bSChris Lattner            << MacroInfo.MacroExpanded
114994faa4d0SJohn Thompson            << "' with respect to these inclusion paths:\n";
11507c6e79f3SJohn Thompson         // Walk all the inclusion path hierarchies.
115108124b11SPiotr Padlewski         for (auto IIP = MacroInfo.InclusionPathHandles.begin(),
115294faa4d0SJohn Thompson                   EIP = MacroInfo.InclusionPathHandles.end();
115394faa4d0SJohn Thompson              IIP != EIP; ++IIP) {
115494faa4d0SJohn Thompson           const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
115508124b11SPiotr Padlewski           auto Count = (int)ip.size();
115694faa4d0SJohn Thompson           for (int Index = 0; Index < Count; ++Index) {
115794faa4d0SJohn Thompson             HeaderHandle H = ip[Index];
115839c9c12bSChris Lattner             OS << std::string((Index * 2) + 4, ' ') << getHeaderFilePath(H)
115994faa4d0SJohn Thompson                << "\n";
116094faa4d0SJohn Thompson           }
116194faa4d0SJohn Thompson         }
116294faa4d0SJohn Thompson         // For a macro that wasn't defined, we flag it by using the
116394faa4d0SJohn Thompson         // instance location.
116494faa4d0SJohn Thompson         // If there is a definition...
116594faa4d0SJohn Thompson         if (MacroInfo.DefinitionLocation.Line != ItemKey.Line) {
116639c9c12bSChris Lattner           OS << MacroInfo.DefinitionSourceLine;
116794faa4d0SJohn Thompson           if (MacroInfo.DefinitionLocation.Column > 0)
116894faa4d0SJohn Thompson             OS << std::string(MacroInfo.DefinitionLocation.Column - 1, ' ')
116994faa4d0SJohn Thompson                << "^\n";
117094faa4d0SJohn Thompson           OS << "Macro defined here.\n";
117194faa4d0SJohn Thompson         } else
117294faa4d0SJohn Thompson           OS << "(no macro definition)"
117394faa4d0SJohn Thompson              << "\n";
117494faa4d0SJohn Thompson       }
117594faa4d0SJohn Thompson     }
117694faa4d0SJohn Thompson     return ReturnValue;
117794faa4d0SJohn Thompson   }
117894faa4d0SJohn Thompson 
117994faa4d0SJohn Thompson   // Report on inconsistent conditional instances.
118094faa4d0SJohn Thompson   // Returns true if any mismatches.
reportInconsistentConditionals(llvm::raw_ostream & OS)118187638f63SAlexander Kornienko   bool reportInconsistentConditionals(llvm::raw_ostream &OS) override {
118294faa4d0SJohn Thompson     bool ReturnValue = false;
11837c6e79f3SJohn Thompson     // Walk all the conditional trackers in the map.
118408124b11SPiotr Padlewski     for (auto I = ConditionalExpansions.begin(),
118594faa4d0SJohn Thompson               E = ConditionalExpansions.end();
118694faa4d0SJohn Thompson          I != E; ++I) {
118794faa4d0SJohn Thompson       const PPItemKey &ItemKey = I->first;
118894faa4d0SJohn Thompson       ConditionalTracker &CondTracker = I->second;
118994faa4d0SJohn Thompson       if (!CondTracker.hasMismatch())
119094faa4d0SJohn Thompson         continue;
11917c6e79f3SJohn Thompson       // Tell caller we found one or more errors.
119294faa4d0SJohn Thompson       ReturnValue = true;
11937c6e79f3SJohn Thompson       // Start the error message.
119439c9c12bSChris Lattner       OS << HeaderPaths[ItemKey.File] << ":" << ItemKey.Line << ":"
119594faa4d0SJohn Thompson          << ItemKey.Column << "\n";
119694faa4d0SJohn Thompson       OS << "#" << getDirectiveSpelling(CondTracker.DirectiveKind) << " "
119739c9c12bSChris Lattner          << CondTracker.ConditionUnexpanded << "\n";
119894faa4d0SJohn Thompson       OS << "^\n";
119994faa4d0SJohn Thompson       OS << "error: Conditional expression instance '"
120039c9c12bSChris Lattner          << CondTracker.ConditionUnexpanded
120194faa4d0SJohn Thompson          << "' has different values in this header, depending on how it was "
120294faa4d0SJohn Thompson             "included.\n";
12037c6e79f3SJohn Thompson       // Walk all the instances.
120408124b11SPiotr Padlewski       for (auto IMT = CondTracker.ConditionalExpansionInstances.begin(),
120594faa4d0SJohn Thompson                 EMT = CondTracker.ConditionalExpansionInstances.end();
120694faa4d0SJohn Thompson            IMT != EMT; ++IMT) {
120794faa4d0SJohn Thompson         ConditionalExpansionInstance &MacroInfo = *IMT;
120839c9c12bSChris Lattner         OS << "  '" << CondTracker.ConditionUnexpanded << "' expanded to: '"
120987f9fef5SJohn Thompson            << ConditionValueKindStrings[MacroInfo.ConditionValue]
121094faa4d0SJohn Thompson            << "' with respect to these inclusion paths:\n";
12117c6e79f3SJohn Thompson         // Walk all the inclusion path hierarchies.
121208124b11SPiotr Padlewski         for (auto IIP = MacroInfo.InclusionPathHandles.begin(),
121394faa4d0SJohn Thompson                   EIP = MacroInfo.InclusionPathHandles.end();
121494faa4d0SJohn Thompson              IIP != EIP; ++IIP) {
121594faa4d0SJohn Thompson           const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
121608124b11SPiotr Padlewski           auto Count = (int)ip.size();
121794faa4d0SJohn Thompson           for (int Index = 0; Index < Count; ++Index) {
121894faa4d0SJohn Thompson             HeaderHandle H = ip[Index];
121939c9c12bSChris Lattner             OS << std::string((Index * 2) + 4, ' ') << getHeaderFilePath(H)
122094faa4d0SJohn Thompson                << "\n";
122194faa4d0SJohn Thompson           }
122294faa4d0SJohn Thompson         }
122394faa4d0SJohn Thompson       }
122494faa4d0SJohn Thompson     }
122594faa4d0SJohn Thompson     return ReturnValue;
122694faa4d0SJohn Thompson   }
122794faa4d0SJohn Thompson 
122894faa4d0SJohn Thompson   // Get directive spelling.
getDirectiveSpelling(clang::tok::PPKeywordKind kind)122994faa4d0SJohn Thompson   static const char *getDirectiveSpelling(clang::tok::PPKeywordKind kind) {
123094faa4d0SJohn Thompson     switch (kind) {
123194faa4d0SJohn Thompson     case clang::tok::pp_if:
123294faa4d0SJohn Thompson       return "if";
123394faa4d0SJohn Thompson     case clang::tok::pp_elif:
123494faa4d0SJohn Thompson       return "elif";
123594faa4d0SJohn Thompson     case clang::tok::pp_ifdef:
123694faa4d0SJohn Thompson       return "ifdef";
123794faa4d0SJohn Thompson     case clang::tok::pp_ifndef:
123894faa4d0SJohn Thompson       return "ifndef";
123994faa4d0SJohn Thompson     default:
124094faa4d0SJohn Thompson       return "(unknown)";
124194faa4d0SJohn Thompson     }
124294faa4d0SJohn Thompson   }
124394faa4d0SJohn Thompson 
124494faa4d0SJohn Thompson private:
1245ecd3b04cSJohn Thompson   llvm::SmallVector<std::string, 32> HeaderList;
1246ecd3b04cSJohn Thompson   // Only do extern, namespace check for headers in HeaderList.
1247ecd3b04cSJohn Thompson   bool BlockCheckHeaderListOnly;
124839c9c12bSChris Lattner   llvm::StringSet<> Strings;
124994faa4d0SJohn Thompson   std::vector<StringHandle> HeaderPaths;
125094faa4d0SJohn Thompson   std::vector<HeaderHandle> HeaderStack;
125194faa4d0SJohn Thompson   std::vector<HeaderInclusionPath> InclusionPaths;
125294faa4d0SJohn Thompson   InclusionPathHandle CurrentInclusionPathHandle;
125348c8426fSMatthias Braun   llvm::SmallSet<HeaderHandle, 32> HeadersInThisCompile;
125474083926SJohn Thompson   std::vector<PPItemKey> IncludeDirectives;
125594faa4d0SJohn Thompson   MacroExpansionMap MacroExpansions;
125694faa4d0SJohn Thompson   ConditionalExpansionMap ConditionalExpansions;
125748df096cSJohn Thompson   bool InNestedHeader;
125894faa4d0SJohn Thompson };
125994faa4d0SJohn Thompson 
1260e7103712SBenjamin Kramer } // namespace
1261e7103712SBenjamin Kramer 
126294faa4d0SJohn Thompson // PreprocessorTracker functions.
126394faa4d0SJohn Thompson 
1264b7ecf1c1SKazuaki Ishizaki // PreprocessorTracker destructor.
~PreprocessorTracker()1265e04a3da0SDavid Blaikie PreprocessorTracker::~PreprocessorTracker() {}
126694faa4d0SJohn Thompson 
126794faa4d0SJohn Thompson // Create instance of PreprocessorTracker.
create(llvm::SmallVector<std::string,32> & Headers,bool DoBlockCheckHeaderListOnly)1268ecd3b04cSJohn Thompson PreprocessorTracker *PreprocessorTracker::create(
1269ecd3b04cSJohn Thompson     llvm::SmallVector<std::string, 32> &Headers,
1270ecd3b04cSJohn Thompson     bool DoBlockCheckHeaderListOnly) {
1271ecd3b04cSJohn Thompson   return new PreprocessorTrackerImpl(Headers, DoBlockCheckHeaderListOnly);
127294faa4d0SJohn Thompson }
127394faa4d0SJohn Thompson 
127494faa4d0SJohn Thompson // Preprocessor callbacks for modularize.
127594faa4d0SJohn Thompson 
127674083926SJohn Thompson // Handle include directive.
InclusionDirective(clang::SourceLocation HashLoc,const clang::Token & IncludeTok,llvm::StringRef FileName,bool IsAngled,clang::CharSourceRange FilenameRange,llvm::Optional<clang::FileEntryRef> File,llvm::StringRef SearchPath,llvm::StringRef RelativePath,const clang::Module * Imported,clang::SrcMgr::CharacteristicKind FileType)127774083926SJohn Thompson void PreprocessorCallbacks::InclusionDirective(
127874083926SJohn Thompson     clang::SourceLocation HashLoc, const clang::Token &IncludeTok,
127974083926SJohn Thompson     llvm::StringRef FileName, bool IsAngled,
1280*d79ad2f1SJan Svoboda     clang::CharSourceRange FilenameRange,
1281*d79ad2f1SJan Svoboda     llvm::Optional<clang::FileEntryRef> File, llvm::StringRef SearchPath,
1282*d79ad2f1SJan Svoboda     llvm::StringRef RelativePath, const clang::Module *Imported,
1283*d79ad2f1SJan Svoboda     clang::SrcMgr::CharacteristicKind FileType) {
128474083926SJohn Thompson   int DirectiveLine, DirectiveColumn;
128574083926SJohn Thompson   std::string HeaderPath = getSourceLocationFile(PP, HashLoc);
128674083926SJohn Thompson   getSourceLocationLineAndColumn(PP, HashLoc, DirectiveLine, DirectiveColumn);
128774083926SJohn Thompson   PPTracker.handleIncludeDirective(HeaderPath, DirectiveLine, DirectiveColumn,
128874083926SJohn Thompson                                    FileName);
128974083926SJohn Thompson }
129074083926SJohn Thompson 
129194faa4d0SJohn Thompson // Handle file entry/exit.
FileChanged(clang::SourceLocation Loc,clang::PPCallbacks::FileChangeReason Reason,clang::SrcMgr::CharacteristicKind FileType,clang::FileID PrevFID)129294faa4d0SJohn Thompson void PreprocessorCallbacks::FileChanged(
129394faa4d0SJohn Thompson     clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason,
129494faa4d0SJohn Thompson     clang::SrcMgr::CharacteristicKind FileType, clang::FileID PrevFID) {
129594faa4d0SJohn Thompson   switch (Reason) {
129694faa4d0SJohn Thompson   case EnterFile:
129794faa4d0SJohn Thompson     PPTracker.handleHeaderEntry(PP, getSourceLocationFile(PP, Loc));
129894faa4d0SJohn Thompson     break;
1299cc2e291dSJohn Thompson   case ExitFile: {
130048df096cSJohn Thompson     const clang::FileEntry *F =
130148df096cSJohn Thompson         PP.getSourceManager().getFileEntryForID(PrevFID);
1302f61be9c9SCraig Topper     if (F)
130348df096cSJohn Thompson       PPTracker.handleHeaderExit(F->getName());
1304cc2e291dSJohn Thompson   } break;
130594faa4d0SJohn Thompson   case SystemHeaderPragma:
130694faa4d0SJohn Thompson   case RenameFile:
1307f2576810SBenjamin Kramer     break;
130894faa4d0SJohn Thompson   }
130994faa4d0SJohn Thompson }
131094faa4d0SJohn Thompson 
131194faa4d0SJohn Thompson // Handle macro expansion.
MacroExpands(const clang::Token & MacroNameTok,const clang::MacroDefinition & MD,clang::SourceRange Range,const clang::MacroArgs * Args)131294faa4d0SJohn Thompson void PreprocessorCallbacks::MacroExpands(const clang::Token &MacroNameTok,
131333de8566SRichard Smith                                          const clang::MacroDefinition &MD,
131494faa4d0SJohn Thompson                                          clang::SourceRange Range,
131594faa4d0SJohn Thompson                                          const clang::MacroArgs *Args) {
131694faa4d0SJohn Thompson   clang::SourceLocation Loc = Range.getBegin();
131791555bdeSJohn Thompson   // Ignore macro argument expansions.
131891555bdeSJohn Thompson   if (!Loc.isFileID())
131991555bdeSJohn Thompson     return;
132094faa4d0SJohn Thompson   clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
132133de8566SRichard Smith   const clang::MacroInfo *MI = MD.getMacroInfo();
132294faa4d0SJohn Thompson   std::string MacroName = II->getName().str();
132394faa4d0SJohn Thompson   std::string Unexpanded(getMacroUnexpandedString(Range, PP, MacroName, MI));
132494faa4d0SJohn Thompson   std::string Expanded(getMacroExpandedString(PP, MacroName, MI, Args));
132594faa4d0SJohn Thompson   PPTracker.addMacroExpansionInstance(
132694faa4d0SJohn Thompson       PP, PPTracker.getCurrentHeaderHandle(), Loc, MI->getDefinitionLoc(), II,
132794faa4d0SJohn Thompson       Unexpanded, Expanded, PPTracker.getCurrentInclusionPathHandle());
132894faa4d0SJohn Thompson }
132994faa4d0SJohn Thompson 
Defined(const clang::Token & MacroNameTok,const clang::MacroDefinition & MD,clang::SourceRange Range)133094faa4d0SJohn Thompson void PreprocessorCallbacks::Defined(const clang::Token &MacroNameTok,
133133de8566SRichard Smith                                     const clang::MacroDefinition &MD,
133294faa4d0SJohn Thompson                                     clang::SourceRange Range) {
133394faa4d0SJohn Thompson   clang::SourceLocation Loc(Range.getBegin());
133494faa4d0SJohn Thompson   clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
133533de8566SRichard Smith   const clang::MacroInfo *MI = MD.getMacroInfo();
133694faa4d0SJohn Thompson   std::string MacroName = II->getName().str();
133794faa4d0SJohn Thompson   std::string Unexpanded(getSourceString(PP, Range));
133894faa4d0SJohn Thompson   PPTracker.addMacroExpansionInstance(
133994faa4d0SJohn Thompson       PP, PPTracker.getCurrentHeaderHandle(), Loc,
134094faa4d0SJohn Thompson       (MI ? MI->getDefinitionLoc() : Loc), II, Unexpanded,
134194faa4d0SJohn Thompson       (MI ? "true" : "false"), PPTracker.getCurrentInclusionPathHandle());
134294faa4d0SJohn Thompson }
134394faa4d0SJohn Thompson 
If(clang::SourceLocation Loc,clang::SourceRange ConditionRange,clang::PPCallbacks::ConditionValueKind ConditionResult)134494faa4d0SJohn Thompson void PreprocessorCallbacks::If(clang::SourceLocation Loc,
134594faa4d0SJohn Thompson                                clang::SourceRange ConditionRange,
134687f9fef5SJohn Thompson                                clang::PPCallbacks::ConditionValueKind ConditionResult) {
134794faa4d0SJohn Thompson   std::string Unexpanded(getSourceString(PP, ConditionRange));
134894faa4d0SJohn Thompson   PPTracker.addConditionalExpansionInstance(
134994faa4d0SJohn Thompson       PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_if,
135094faa4d0SJohn Thompson       ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
135194faa4d0SJohn Thompson }
135294faa4d0SJohn Thompson 
Elif(clang::SourceLocation Loc,clang::SourceRange ConditionRange,clang::PPCallbacks::ConditionValueKind ConditionResult,clang::SourceLocation IfLoc)135394faa4d0SJohn Thompson void PreprocessorCallbacks::Elif(clang::SourceLocation Loc,
135494faa4d0SJohn Thompson                                  clang::SourceRange ConditionRange,
135587f9fef5SJohn Thompson                                  clang::PPCallbacks::ConditionValueKind ConditionResult,
135694faa4d0SJohn Thompson                                  clang::SourceLocation IfLoc) {
135794faa4d0SJohn Thompson   std::string Unexpanded(getSourceString(PP, ConditionRange));
135894faa4d0SJohn Thompson   PPTracker.addConditionalExpansionInstance(
135994faa4d0SJohn Thompson       PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_elif,
136094faa4d0SJohn Thompson       ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
136194faa4d0SJohn Thompson }
136294faa4d0SJohn Thompson 
Ifdef(clang::SourceLocation Loc,const clang::Token & MacroNameTok,const clang::MacroDefinition & MD)136394faa4d0SJohn Thompson void PreprocessorCallbacks::Ifdef(clang::SourceLocation Loc,
136494faa4d0SJohn Thompson                                   const clang::Token &MacroNameTok,
136533de8566SRichard Smith                                   const clang::MacroDefinition &MD) {
136687f9fef5SJohn Thompson   clang::PPCallbacks::ConditionValueKind IsDefined =
1367f61be9c9SCraig Topper     (MD ? clang::PPCallbacks::CVK_True : clang::PPCallbacks::CVK_False );
136894faa4d0SJohn Thompson   PPTracker.addConditionalExpansionInstance(
136994faa4d0SJohn Thompson       PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifdef,
137094faa4d0SJohn Thompson       IsDefined, PP.getSpelling(MacroNameTok),
137194faa4d0SJohn Thompson       PPTracker.getCurrentInclusionPathHandle());
137294faa4d0SJohn Thompson }
137394faa4d0SJohn Thompson 
Ifndef(clang::SourceLocation Loc,const clang::Token & MacroNameTok,const clang::MacroDefinition & MD)137494faa4d0SJohn Thompson void PreprocessorCallbacks::Ifndef(clang::SourceLocation Loc,
137594faa4d0SJohn Thompson                                    const clang::Token &MacroNameTok,
137633de8566SRichard Smith                                    const clang::MacroDefinition &MD) {
137787f9fef5SJohn Thompson   clang::PPCallbacks::ConditionValueKind IsNotDefined =
1378f61be9c9SCraig Topper     (!MD ? clang::PPCallbacks::CVK_True : clang::PPCallbacks::CVK_False );
137994faa4d0SJohn Thompson   PPTracker.addConditionalExpansionInstance(
138094faa4d0SJohn Thompson       PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifndef,
138194faa4d0SJohn Thompson       IsNotDefined, PP.getSpelling(MacroNameTok),
138294faa4d0SJohn Thompson       PPTracker.getCurrentInclusionPathHandle());
138394faa4d0SJohn Thompson }
138494faa4d0SJohn Thompson } // end namespace Modularize
1385