[clang-tools-extra] r187228 - Added new feature for checking macro and preprocessor conditional consistency.

Rafael EspĂ­ndola rafael.espindola at gmail.com
Fri Jul 26 12:25:43 PDT 2013


This broke some bots and I reverted it for now.

On 26 July 2013 14:16, John Thompson <John.Thompson.JTSoftware at gmail.com> wrote:
> Author: jtsoftware
> Date: Fri Jul 26 13:16:22 2013
> New Revision: 187228
>
> URL: http://llvm.org/viewvc/llvm-project?rev=187228&view=rev
> Log:
> Added new feature for checking macro and preprocessor conditional consistency.
>
> Added:
>     clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp
>     clang-tools-extra/trunk/modularize/PreprocessorTracker.h
> Modified:
>     clang-tools-extra/trunk/modularize/CMakeLists.txt
>     clang-tools-extra/trunk/modularize/Modularize.cpp
>     clang-tools-extra/trunk/test/modularize/Inputs/InconsistentSubHeader.h
>     clang-tools-extra/trunk/test/modularize/ProblemsInconsistent.modularize
>
> Modified: clang-tools-extra/trunk/modularize/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/modularize/CMakeLists.txt?rev=187228&r1=187227&r2=187228&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/modularize/CMakeLists.txt (original)
> +++ clang-tools-extra/trunk/modularize/CMakeLists.txt Fri Jul 26 13:16:22 2013
> @@ -7,6 +7,7 @@ set(LLVM_LINK_COMPONENTS
>
>  add_clang_executable(modularize
>    Modularize.cpp
> +  PreprocessorTracker.cpp
>    )
>
>  target_link_libraries(modularize
>
> Modified: clang-tools-extra/trunk/modularize/Modularize.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/modularize/Modularize.cpp?rev=187228&r1=187227&r2=187228&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/modularize/Modularize.cpp (original)
> +++ clang-tools-extra/trunk/modularize/Modularize.cpp Fri Jul 26 13:16:22 2013
> @@ -90,10 +90,12 @@
>  #include <iterator>
>  #include <string>
>  #include <vector>
> +#include "PreprocessorTracker.h"
>
>  using namespace clang::tooling;
>  using namespace clang;
>  using namespace llvm;
> +using namespace Modularize;
>
>  // Option to specify a file name for a list of header files to check.
>  cl::opt<std::string>
> @@ -382,8 +384,14 @@ private:
>
>  class CollectEntitiesConsumer : public ASTConsumer {
>  public:
> -  CollectEntitiesConsumer(EntityMap &Entities, Preprocessor &PP)
> -      : Entities(Entities), PP(PP) {}
> +  CollectEntitiesConsumer(EntityMap &Entities,
> +                          PreprocessorTracker &preprocessorTracker,
> +                          Preprocessor &PP, StringRef InFile)
> +      : Entities(Entities), PPTracker(preprocessorTracker), PP(PP) {
> +    PPTracker.handlePreprocessorEntry(PP, InFile);
> +  }
> +
> +  ~CollectEntitiesConsumer() { PPTracker.handlePreprocessorExit(); }
>
>    virtual void HandleTranslationUnit(ASTContext &Ctx) {
>      SourceManager &SM = Ctx.getSourceManager();
> @@ -409,33 +417,41 @@ public:
>
>  private:
>    EntityMap &Entities;
> +  PreprocessorTracker &PPTracker;
>    Preprocessor &PP;
>  };
>
>  class CollectEntitiesAction : public SyntaxOnlyAction {
>  public:
> -  CollectEntitiesAction(EntityMap &Entities) : Entities(Entities) {}
> +  CollectEntitiesAction(EntityMap &Entities,
> +                        PreprocessorTracker &preprocessorTracker)
> +      : Entities(Entities), PPTracker(preprocessorTracker) {}
>
>  protected:
>    virtual clang::ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
>                                                  StringRef InFile) {
> -    return new CollectEntitiesConsumer(Entities, CI.getPreprocessor());
> +    return new CollectEntitiesConsumer(Entities, PPTracker,
> +                                       CI.getPreprocessor(), InFile);
>    }
>
>  private:
>    EntityMap &Entities;
> +  PreprocessorTracker &PPTracker;
>  };
>
>  class ModularizeFrontendActionFactory : public FrontendActionFactory {
>  public:
> -  ModularizeFrontendActionFactory(EntityMap &Entities) : Entities(Entities) {}
> +  ModularizeFrontendActionFactory(EntityMap &Entities,
> +                                  PreprocessorTracker &preprocessorTracker)
> +      : Entities(Entities), PPTracker(preprocessorTracker) {}
>
>    virtual CollectEntitiesAction *create() {
> -    return new CollectEntitiesAction(Entities);
> +    return new CollectEntitiesAction(Entities, PPTracker);
>    }
>
>  private:
>    EntityMap &Entities;
> +  PreprocessorTracker &PPTracker;
>  };
>
>  int main(int argc, const char **argv) {
> @@ -464,10 +480,14 @@ int main(int argc, const char **argv) {
>    Compilations.reset(
>        new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments));
>
> +  // Create preprocessor tracker, to watch for macro and conditional problems.
> +  OwningPtr<PreprocessorTracker> PPTracker(PreprocessorTracker::create());
> +
>    // Parse all of the headers, detecting duplicates.
>    EntityMap Entities;
>    ClangTool Tool(*Compilations, Headers);
> -  int HadErrors = Tool.run(new ModularizeFrontendActionFactory(Entities));
> +  int HadErrors =
> +      Tool.run(new ModularizeFrontendActionFactory(Entities, *PPTracker));
>
>    // Create a place to save duplicate entity locations, separate bins per kind.
>    typedef SmallVector<Location, 8> LocationArray;
> @@ -515,6 +535,16 @@ int main(int argc, const char **argv) {
>      }
>    }
>
> +  // Complain about macro instance in header files that differ based on how
> +  // they are included.
> +  if (PPTracker->reportInconsistentMacros(errs()))
> +    HadErrors = 1;
> +
> +  // Complain about preprocessor conditional directives in header files that
> +  // differ based on how they are included.
> +  if (PPTracker->reportInconsistentConditionals(errs()))
> +    HadErrors = 1;
> +
>    // Complain about any headers that have contents that differ based on how
>    // they are included.
>    // FIXME: Could we provide information about which preprocessor conditionals
> @@ -530,7 +560,7 @@ int main(int argc, const char **argv) {
>
>      HadErrors = 1;
>      errs() << "error: header '" << H->first->getName()
> -           << "' has different contents depending on how it was included\n";
> +           << "' has different contents depending on how it was included.\n";
>      for (unsigned I = 0, N = H->second.size(); I != N; ++I) {
>        errs() << "note: '" << H->second[I].Name << "' in "
>               << H->second[I].Loc.File->getName() << " at "
>
> Added: clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp?rev=187228&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp (added)
> +++ clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp Fri Jul 26 13:16:22 2013
> @@ -0,0 +1,1036 @@
> +//=- PreprocessorTracker.cpp - Preprocessor tracking -*- C++ -*-=//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===--------------------------------------------------------------------===//
> +
> +#include "clang/Lex/LexDiagnostic.h"
> +#include "clang/Lex/MacroArgs.h"
> +#include "clang/Lex/PPCallbacks.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "llvm/Support/StringPool.h"
> +#include "PreprocessorTracker.h"
> +
> +namespace Modularize {
> +
> +// Forwards.
> +class PreprocessorTrackerImpl;
> +
> +// Some handle types
> +
> +// String handle.
> +typedef llvm::PooledStringPtr StringHandle;
> +
> +// Header handle.
> +typedef int HeaderHandle;
> +const HeaderHandle HeaderHandleInvalid = -1;
> +
> +// Header inclusion path handle.
> +typedef int InclusionPathHandle;
> +const InclusionPathHandle InclusionPathHandleInvalid = -1;
> +
> +// Some utility functions.
> +
> +// Get a "file:line:column" source location string.
> +static std::string getSourceLocationString(clang::Preprocessor &PP,
> +                                           clang::SourceLocation Loc) {
> +  if (Loc.isInvalid())
> +    return std::string("(none)");
> +  else
> +    return Loc.printToString(PP.getSourceManager());
> +}
> +
> +// Get just the file name from a source location.
> +static std::string getSourceLocationFile(clang::Preprocessor &PP,
> +                                         clang::SourceLocation Loc) {
> +  std::string Source(getSourceLocationString(PP, Loc));
> +  size_t Offset = Source.find(':', 2);
> +  if (Offset == std::string::npos)
> +    return Source;
> +  return Source.substr(0, Offset);
> +}
> +
> +// Get just the line and column from a source location.
> +static void getSourceLocationLineAndColumn(clang::Preprocessor &PP,
> +                                           clang::SourceLocation Loc, int &Line,
> +                                           int &Column) {
> +  clang::PresumedLoc PLoc = PP.getSourceManager().getPresumedLoc(Loc);
> +  if (PLoc.isInvalid()) {
> +    Line = 0;
> +    Column = 0;
> +    return;
> +  }
> +  Line = PLoc.getLine();
> +  Column = PLoc.getColumn();
> +}
> +
> +// Retrieve source snippet from file image.
> +std::string getSourceString(clang::Preprocessor &PP, clang::SourceRange Range) {
> +  clang::SourceLocation BeginLoc = Range.getBegin();
> +  clang::SourceLocation EndLoc = Range.getEnd();
> +  const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
> +  const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc);
> +  size_t Length = EndPtr - BeginPtr;
> +  return llvm::StringRef(BeginPtr, Length).trim().str();
> +}
> +
> +// Retrieve source line from file image.
> +std::string getSourceLine(clang::Preprocessor &PP, clang::SourceLocation Loc) {
> +  const llvm::MemoryBuffer *MemBuffer =
> +      PP.getSourceManager().getBuffer(PP.getSourceManager().getFileID(Loc));
> +  const char *Buffer = MemBuffer->getBufferStart();
> +  const char *BufferEnd = MemBuffer->getBufferEnd();
> +  const char *BeginPtr = PP.getSourceManager().getCharacterData(Loc);
> +  const char *EndPtr = BeginPtr;
> +  while (BeginPtr > Buffer) {
> +    if (*BeginPtr == '\n') {
> +      BeginPtr++;
> +      break;
> +    }
> +    BeginPtr--;
> +  }
> +  while (EndPtr < BufferEnd) {
> +    if (*EndPtr == '\n') {
> +      break;
> +    }
> +    EndPtr++;
> +  }
> +  size_t Length = EndPtr - BeginPtr;
> +  return llvm::StringRef(BeginPtr, Length).str();
> +}
> +
> +// Get the string for the Unexpanded macro instance.
> +// The soureRange is expected to end at the last token
> +// for the macro instance, which in the case of a function-style
> +// macro will be a ')', but for an object-style macro, it
> +// will be the macro name itself.
> +std::string getMacroUnexpandedString(clang::SourceRange Range,
> +                                     clang::Preprocessor &PP,
> +                                     llvm::StringRef MacroName,
> +                                     const clang::MacroInfo *MI) {
> +  clang::SourceLocation BeginLoc(Range.getBegin());
> +  const char *BeginPtr = PP.getSourceManager().getCharacterData(BeginLoc);
> +  size_t Length;
> +  std::string Unexpanded;
> +  if (MI->isFunctionLike()) {
> +    clang::SourceLocation EndLoc(Range.getEnd());
> +    const char *EndPtr = PP.getSourceManager().getCharacterData(EndLoc) + 1;
> +    Length = (EndPtr - BeginPtr) + 1; // +1 is ')' width.
> +  } else
> +    Length = MacroName.size();
> +  return llvm::StringRef(BeginPtr, Length).trim().str();
> +}
> +
> +// Get the expansion for a macro instance, given the information
> +// provided by PPCallbacks.
> +std::string getMacroExpandedString(clang::Preprocessor &PP,
> +                                   llvm::StringRef MacroName,
> +                                   const clang::MacroInfo *MI,
> +                                   const clang::MacroArgs *Args) {
> +  std::string Expanded;
> +  // Walk over the macro Tokens.
> +  typedef clang::MacroInfo::tokens_iterator Iter;
> +  for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
> +    clang::IdentifierInfo *II = I->getIdentifierInfo();
> +    int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
> +    if (ArgNo == -1) {
> +      // This isn't an argument, just add it.
> +      if (II == NULL)
> +        Expanded += PP.getSpelling((*I)); // Not an identifier.
> +      else {
> +        // Token is for an identifier.
> +        std::string Name = II->getName().str();
> +        // Check for nexted macro references.
> +        clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
> +        if (MacroInfo != NULL)
> +          Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
> +        else
> +          Expanded += Name;
> +      }
> +      continue;
> +    }
> +    // We get here if it's a function-style macro with arguments.
> +    const clang::Token *ResultArgToks;
> +    const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
> +    if (Args->ArgNeedsPreexpansion(ArgTok, PP))
> +      ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
> +          ->getPreExpArgument(ArgNo, MI, PP)[0];
> +    else
> +      ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
> +    // If the arg token didn't expand into anything, ignore it.
> +    if (ResultArgToks->is(clang::tok::eof))
> +      continue;
> +    unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
> +    // Append the resulting argument expansions.
> +    for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
> +      const clang::Token &AT = ResultArgToks[ArgumentIndex];
> +      clang::IdentifierInfo *II = AT.getIdentifierInfo();
> +      if (II == NULL)
> +        Expanded += PP.getSpelling(AT); // Not an identifier.
> +      else {
> +        // It's an identifier.  Check for further expansion.
> +        std::string Name = II->getName().str();
> +        clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
> +        if (MacroInfo != NULL)
> +          Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
> +        else
> +          Expanded += Name;
> +      }
> +    }
> +  }
> +  return Expanded;
> +}
> +
> +// Get the string representing a vector of Tokens.
> +std::string
> +getTokensSpellingString(clang::Preprocessor &PP,
> +                        llvm::SmallVectorImpl<clang::Token> &Tokens) {
> +  std::string Expanded;
> +  // Walk over the macro Tokens.
> +  typedef llvm::SmallVectorImpl<clang::Token>::iterator Iter;
> +  for (Iter I = Tokens.begin(), E = Tokens.end(); I != E; ++I)
> +    Expanded += PP.getSpelling(*I); // Not an identifier.
> +  return llvm::StringRef(Expanded).trim().str();
> +}
> +
> +// Get the expansion for a macro instance, given the information
> +// provided by PPCallbacks.
> +std::string getExpandedString(clang::Preprocessor &PP,
> +                              llvm::StringRef MacroName,
> +                              const clang::MacroInfo *MI,
> +                              const clang::MacroArgs *Args) {
> +  std::string Expanded;
> +  // Walk over the macro Tokens.
> +  typedef clang::MacroInfo::tokens_iterator Iter;
> +  for (Iter I = MI->tokens_begin(), E = MI->tokens_end(); I != E; ++I) {
> +    clang::IdentifierInfo *II = I->getIdentifierInfo();
> +    int ArgNo = (II && Args ? MI->getArgumentNum(II) : -1);
> +    if (ArgNo == -1) {
> +      // This isn't an argument, just add it.
> +      if (II == NULL)
> +        Expanded += PP.getSpelling((*I)); // Not an identifier.
> +      else {
> +        // Token is for an identifier.
> +        std::string Name = II->getName().str();
> +        // Check for nexted macro references.
> +        clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
> +        if (MacroInfo != NULL)
> +          Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
> +        else
> +          Expanded += Name;
> +      }
> +      continue;
> +    }
> +    // We get here if it's a function-style macro with arguments.
> +    const clang::Token *ResultArgToks;
> +    const clang::Token *ArgTok = Args->getUnexpArgument(ArgNo);
> +    if (Args->ArgNeedsPreexpansion(ArgTok, PP))
> +      ResultArgToks = &(const_cast<clang::MacroArgs *>(Args))
> +          ->getPreExpArgument(ArgNo, MI, PP)[0];
> +    else
> +      ResultArgToks = ArgTok; // Use non-preexpanded Tokens.
> +    // If the arg token didn't expand into anything, ignore it.
> +    if (ResultArgToks->is(clang::tok::eof))
> +      continue;
> +    unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
> +    // Append the resulting argument expansions.
> +    for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
> +      const clang::Token &AT = ResultArgToks[ArgumentIndex];
> +      clang::IdentifierInfo *II = AT.getIdentifierInfo();
> +      if (II == NULL)
> +        Expanded += PP.getSpelling(AT); // Not an identifier.
> +      else {
> +        // It's an identifier.  Check for further expansion.
> +        std::string Name = II->getName().str();
> +        clang::MacroInfo *MacroInfo = PP.getMacroInfo(II);
> +        if (MacroInfo != NULL)
> +          Expanded += getMacroExpandedString(PP, Name, MacroInfo, NULL);
> +        else
> +          Expanded += Name;
> +      }
> +    }
> +  }
> +  return Expanded;
> +}
> +
> +// We need some operator overloads for string handles.
> +bool operator==(const StringHandle &H1, const StringHandle &H2) {
> +  const char *S1 = (H1 ? *H1 : "");
> +  const char *S2 = (H2 ? *H2 : "");
> +  int Diff = strcmp(S1, S2);
> +  return Diff == 0;
> +}
> +bool operator!=(const StringHandle &H1, const StringHandle &H2) {
> +  const char *S1 = (H1 ? *H1 : "");
> +  const char *S2 = (H2 ? *H2 : "");
> +  int Diff = strcmp(S1, S2);
> +  return Diff != 0;
> +}
> +bool operator<(const StringHandle &H1, const StringHandle &H2) {
> +  const char *S1 = (H1 ? *H1 : "");
> +  const char *S2 = (H2 ? *H2 : "");
> +  int Diff = strcmp(S1, S2);
> +  return Diff < 0;
> +}
> +bool operator>(const StringHandle &H1, const StringHandle &H2) {
> +  const char *S1 = (H1 ? *H1 : "");
> +  const char *S2 = (H2 ? *H2 : "");
> +  int Diff = strcmp(S1, S2);
> +  return Diff > 0;
> +}
> +
> +// Preprocessor item key.
> +//
> +// This class represents a location in a source file, for use
> +// as a key representing a unique name/file/line/column quadruplet,
> +// which in this case is used to identify a macro expansion instance,
> +// but could be used for other things as well.
> +// The file is a header file handle, the line is a line number,
> +// and the column is a column number.
> +class PPItemKey {
> +public:
> +  PPItemKey(clang::Preprocessor &PP, StringHandle Name, HeaderHandle File,
> +            clang::SourceLocation Loc)
> +      : Name(Name), File(File) {
> +    getSourceLocationLineAndColumn(PP, Loc, Line, Column);
> +  }
> +  PPItemKey(StringHandle Name, HeaderHandle File, int Line, int Column)
> +      : Name(Name), File(File), Line(Line), Column(Column) {}
> +  PPItemKey(const PPItemKey &Other)
> +      : Name(Other.Name), File(Other.File), Line(Other.Line),
> +        Column(Other.Column) {}
> +  PPItemKey() : File(HeaderHandleInvalid), Line(0), Column(0) {}
> +  bool operator==(const PPItemKey &Other) const {
> +    if (Name != Other.Name)
> +      return false;
> +    if (File != Other.File)
> +      return false;
> +    if (Line != Other.Line)
> +      return false;
> +    return Column == Other.Column;
> +  }
> +  bool operator<(const PPItemKey &Other) const {
> +    if (Name < Other.Name)
> +      return true;
> +    else if (Name > Other.Name)
> +      return false;
> +    if (File < Other.File)
> +      return true;
> +    else if (File > Other.File)
> +      return false;
> +    if (Line < Other.Line)
> +      return true;
> +    else if (Line > Other.Line)
> +      return false;
> +    return Column < Other.Column;
> +  }
> +  StringHandle Name;
> +  HeaderHandle File;
> +  int Line;
> +  int Column;
> +};
> +
> +// Header inclusion path.
> +class HeaderInclusionPath {
> +public:
> +  HeaderInclusionPath(std::vector<HeaderHandle> HeaderInclusionPath)
> +      : Path(HeaderInclusionPath) {}
> +  HeaderInclusionPath(const HeaderInclusionPath &Other) : Path(Other.Path) {}
> +  HeaderInclusionPath() {}
> +  std::vector<HeaderHandle> Path;
> +};
> +
> +// Macro expansion instance.
> +//
> +// This class represents an instance of a macro expansion with a
> +// unique value.  It also stores the unique header inclusion paths
> +// for use in telling the user the nested include path f
> +class MacroExpansionInstance {
> +public:
> +  MacroExpansionInstance(StringHandle MacroExpanded,
> +                         PPItemKey &DefinitionLocation,
> +                         StringHandle DefinitionSourceLine,
> +                         InclusionPathHandle H)
> +      : MacroExpanded(MacroExpanded), DefinitionLocation(DefinitionLocation),
> +        DefinitionSourceLine(DefinitionSourceLine) {
> +    InclusionPathHandles.push_back(H);
> +  }
> +  MacroExpansionInstance() {}
> +
> +  // Check for the presence of a header inclusion path handle entry.
> +  // Return false if not found.
> +  bool haveInclusionPathHandle(InclusionPathHandle H) {
> +    for (std::vector<InclusionPathHandle>::iterator
> +             I = InclusionPathHandles.begin(),
> +             E = InclusionPathHandles.end();
> +         I != E; ++I) {
> +      if (*I == H)
> +        return true;
> +    }
> +    return InclusionPathHandleInvalid;
> +  }
> +  // Add a new header inclusion path entry, if not already present.
> +  void addInclusionPathHandle(InclusionPathHandle H) {
> +    if (!haveInclusionPathHandle(H))
> +      InclusionPathHandles.push_back(H);
> +  }
> +
> +  // A string representing the macro instance after preprocessing.
> +  StringHandle MacroExpanded;
> +  // A file/line/column triplet representing the macro definition location.
> +  PPItemKey DefinitionLocation;
> +  // A place to save the macro definition line string.
> +  StringHandle DefinitionSourceLine;
> +  // The header inclusion path handles for all the instances.
> +  std::vector<InclusionPathHandle> InclusionPathHandles;
> +};
> +
> +// Macro expansion instance tracker.
> +//
> +// This class represents one macro expansion, keyed by a PPItemKey.
> +// It stores a string representing the macro reference in the source,
> +// and a list of ConditionalExpansionInstances objects representing
> +// the unique value the condition expands to in instances of the header.
> +class MacroExpansionTracker {
> +public:
> +  MacroExpansionTracker(StringHandle MacroUnexpanded,
> +                        StringHandle MacroExpanded,
> +                        StringHandle InstanceSourceLine,
> +                        PPItemKey &DefinitionLocation,
> +                        StringHandle DefinitionSourceLine,
> +                        InclusionPathHandle InclusionPathHandle)
> +      : MacroUnexpanded(MacroUnexpanded),
> +        InstanceSourceLine(InstanceSourceLine) {
> +    addMacroExpansionInstance(MacroExpanded, DefinitionLocation,
> +                              DefinitionSourceLine, InclusionPathHandle);
> +  }
> +  MacroExpansionTracker() {}
> +
> +  // Find a matching macro expansion instance.
> +  MacroExpansionInstance *
> +  findMacroExpansionInstance(StringHandle MacroExpanded,
> +                             PPItemKey &DefinitionLocation) {
> +    for (std::vector<MacroExpansionInstance>::iterator
> +             I = MacroExpansionInstances.begin(),
> +             E = MacroExpansionInstances.end();
> +         I != E; ++I) {
> +      if ((I->MacroExpanded == MacroExpanded) &&
> +          (I->DefinitionLocation == DefinitionLocation)) {
> +        return &*I; // Found.
> +      }
> +    }
> +    return NULL; // Not found.
> +  }
> +
> +  // Add a macro expansion instance.
> +  void addMacroExpansionInstance(StringHandle MacroExpanded,
> +                                 PPItemKey &DefinitionLocation,
> +                                 StringHandle DefinitionSourceLine,
> +                                 InclusionPathHandle InclusionPathHandle) {
> +    MacroExpansionInstances.push_back(
> +        MacroExpansionInstance(MacroExpanded, DefinitionLocation,
> +                               DefinitionSourceLine, InclusionPathHandle));
> +  }
> +
> +  // Return true if there is a mismatch.
> +  bool hasMismatch() { return MacroExpansionInstances.size() > 1; }
> +
> +  // A string representing the macro instance without expansion.
> +  StringHandle MacroUnexpanded;
> +  // A place to save the macro instance source line string.
> +  StringHandle InstanceSourceLine;
> +  // The macro expansion instances.
> +  // If all instances of the macro expansion expand to the same value,
> +  // This vector will only have one instance.
> +  std::vector<MacroExpansionInstance> MacroExpansionInstances;
> +};
> +
> +// Conditional expansion instance.
> +//
> +// This class represents an instance of a macro expansion with a
> +// unique value.  It also stores the unique header inclusion paths
> +// for use in telling the user the nested include path f
> +class ConditionalExpansionInstance {
> +public:
> +  ConditionalExpansionInstance(bool ConditionValue, InclusionPathHandle H)
> +      : ConditionValue(ConditionValue) {
> +    InclusionPathHandles.push_back(H);
> +  }
> +  ConditionalExpansionInstance() {}
> +
> +  // Check for the presence of a header inclusion path handle entry.
> +  // Return false if not found.
> +  bool haveInclusionPathHandle(InclusionPathHandle H) {
> +    for (std::vector<InclusionPathHandle>::iterator
> +             I = InclusionPathHandles.begin(),
> +             E = InclusionPathHandles.end();
> +         I != E; ++I) {
> +      if (*I == H)
> +        return true;
> +    }
> +    return InclusionPathHandleInvalid;
> +  }
> +  // Add a new header inclusion path entry, if not already present.
> +  void addInclusionPathHandle(InclusionPathHandle H) {
> +    if (!haveInclusionPathHandle(H))
> +      InclusionPathHandles.push_back(H);
> +  }
> +
> +  // A flag representing the evaluated condition value.
> +  bool ConditionValue;
> +  // The header inclusion path handles for all the instances.
> +  std::vector<InclusionPathHandle> InclusionPathHandles;
> +};
> +
> +// Conditional directive instance tracker.
> +//
> +// This class represents one conditional directive, keyed by a PPItemKey.
> +// It stores a string representing the macro reference in the source,
> +// and a list of MacroExpansionInstance objects representing
> +// the unique value the macro expands to in instances of the header.
> +class ConditionalTracker {
> +public:
> +  ConditionalTracker(clang::tok::PPKeywordKind DirectiveKind,
> +                     bool ConditionValue, StringHandle ConditionUnexpanded,
> +                     InclusionPathHandle InclusionPathHandle)
> +      : DirectiveKind(DirectiveKind), ConditionUnexpanded(ConditionUnexpanded) {
> +    addConditionalExpansionInstance(ConditionValue, InclusionPathHandle);
> +  }
> +  ConditionalTracker() {}
> +
> +  // Find a matching condition expansion instance.
> +  ConditionalExpansionInstance *
> +  findConditionalExpansionInstance(bool ConditionValue) {
> +    for (std::vector<ConditionalExpansionInstance>::iterator
> +             I = ConditionalExpansionInstances.begin(),
> +             E = ConditionalExpansionInstances.end();
> +         I != E; ++I) {
> +      if (I->ConditionValue == ConditionValue) {
> +        return &*I; // Found.
> +      }
> +    }
> +    return NULL; // Not found.
> +  }
> +
> +  // Add a conditional expansion instance.
> +  void
> +  addConditionalExpansionInstance(bool ConditionValue,
> +                                  InclusionPathHandle InclusionPathHandle) {
> +    ConditionalExpansionInstances.push_back(
> +        ConditionalExpansionInstance(ConditionValue, InclusionPathHandle));
> +  }
> +
> +  // Return true if there is a mismatch.
> +  bool hasMismatch() { return ConditionalExpansionInstances.size() > 1; }
> +
> +  // The kind of directive.
> +  clang::tok::PPKeywordKind DirectiveKind;
> +  // A string representing the macro instance without expansion.
> +  StringHandle ConditionUnexpanded;
> +  // The condition expansion instances.
> +  // If all instances of the conditional expression expand to the same value,
> +  // This vector will only have one instance.
> +  std::vector<ConditionalExpansionInstance> ConditionalExpansionInstances;
> +};
> +
> +// Preprocessor callbacks for modularize.
> +//
> +// This class derives from the Clang PPCallbacks class to track preprocessor
> +// actions, such as changing files and handling preprocessor directives and
> +// macro expansions.  It has to figure out when a new header file is entered
> +// and left, as the provided handler is not particularly clear about it.
> +class PreprocessorCallbacks : public clang::PPCallbacks {
> +public:
> +  PreprocessorCallbacks(PreprocessorTrackerImpl &ppTracker,
> +                        clang::Preprocessor &PP, llvm::StringRef rootHeaderFile)
> +      : PPTracker(ppTracker), PP(PP), RootHeaderFile(rootHeaderFile) {}
> +  ~PreprocessorCallbacks() {}
> +
> +  // Overidden handlers.
> +  void FileChanged(clang::SourceLocation Loc,
> +                   clang::PPCallbacks::FileChangeReason Reason,
> +                   clang::SrcMgr::CharacteristicKind FileType,
> +                   clang::FileID PrevFID = clang::FileID());
> +  void MacroExpands(const clang::Token &MacroNameTok,
> +                    const clang::MacroDirective *MD, clang::SourceRange Range,
> +                    const clang::MacroArgs *Args);
> +  void Defined(const clang::Token &MacroNameTok,
> +               const clang::MacroDirective *MD, clang::SourceRange Range);
> +  void If(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
> +          bool ConditionResult);
> +  void Elif(clang::SourceLocation Loc, clang::SourceRange ConditionRange,
> +            bool ConditionResult, clang::SourceLocation IfLoc);
> +  void Ifdef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
> +             const clang::MacroDirective *MD);
> +  void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
> +              const clang::MacroDirective *MD);
> +
> +private:
> +  PreprocessorTrackerImpl &PPTracker;
> +  clang::Preprocessor &PP;
> +  std::string RootHeaderFile;
> +};
> +
> +// Preprocessor macro expansion item map types.
> +typedef std::map<PPItemKey, MacroExpansionTracker> MacroExpansionMap;
> +typedef std::map<PPItemKey, MacroExpansionTracker>::iterator
> +MacroExpansionMapIter;
> +
> +// Preprocessor conditional expansion item map types.
> +typedef std::map<PPItemKey, ConditionalTracker> ConditionalExpansionMap;
> +typedef std::map<PPItemKey, ConditionalTracker>::iterator
> +ConditionalExpansionMapIter;
> +
> +// Preprocessor tracker for modularize.
> +//
> +// This class stores information about all the headers processed in the
> +// course of running modularize.
> +class PreprocessorTrackerImpl : public PreprocessorTracker {
> +public:
> +  PreprocessorTrackerImpl()
> +      : CurrentInclusionPathHandle(InclusionPathHandleInvalid) {}
> +  ~PreprocessorTrackerImpl() {}
> +
> +  // Handle entering a preprocessing session.
> +  void handlePreprocessorEntry(clang::Preprocessor &PP,
> +                               llvm::StringRef rootHeaderFile) {
> +    assert((HeaderStack.size() == 0) && "Header stack should be empty.");
> +    pushHeaderHandle(addHeader(rootHeaderFile));
> +    PP.addPPCallbacks(new PreprocessorCallbacks(*this, PP, rootHeaderFile));
> +  }
> +  // Handle exiting a preprocessing session.
> +  void handlePreprocessorExit() { HeaderStack.clear(); }
> +
> +  // Handle entering a header source file.
> +  void handleHeaderEntry(clang::Preprocessor &PP, llvm::StringRef HeaderPath) {
> +    // Ignore <built-in> and <command-line> to reduce message clutter.
> +    if (HeaderPath.startswith("<"))
> +      return;
> +    HeaderHandle H = addHeader(HeaderPath);
> +    if (H != getCurrentHeaderHandle())
> +      pushHeaderHandle(H);
> +  }
> +  // Handle exiting a header source file.
> +  void handleHeaderExit(llvm::StringRef HeaderPath) {
> +    // Ignore <built-in> and <command-line> to reduce message clutter.
> +    if (HeaderPath.startswith("<"))
> +      return;
> +    HeaderHandle H = findHeaderHandle(HeaderPath);
> +    if (isHeaderHandleInStack(H)) {
> +      while ((H != getCurrentHeaderHandle()) && (HeaderStack.size() != 0))
> +        popHeaderHandle();
> +    }
> +  }
> +
> +  // Lookup/add string.
> +  StringHandle addString(llvm::StringRef Str) { return Strings.intern(Str); }
> +
> +  // Get the handle of a header file entry.
> +  // Return HeaderHandleInvalid if not found.
> +  HeaderHandle findHeaderHandle(llvm::StringRef HeaderPath) const {
> +    HeaderHandle H = 0;
> +    for (std::vector<StringHandle>::const_iterator I = HeaderPaths.begin(),
> +                                                   E = HeaderPaths.end();
> +         I != E; ++I, ++H) {
> +      if (**I == HeaderPath)
> +        return H;
> +    }
> +    return HeaderHandleInvalid;
> +  }
> +
> +  // Add a new header file entry, or return existing handle.
> +  // Return the header handle.
> +  HeaderHandle addHeader(llvm::StringRef HeaderPath) {
> +    std::string canonicalPath(HeaderPath);
> +    std::replace(canonicalPath.begin(), canonicalPath.end(), '\\', '/');
> +    HeaderHandle H = findHeaderHandle(canonicalPath);
> +    if (H == HeaderHandleInvalid) {
> +      H = HeaderPaths.size();
> +      HeaderPaths.push_back(addString(canonicalPath));
> +    }
> +    return H;
> +  }
> +
> +  // Return a header file path string given its handle.
> +  StringHandle getHeaderFilePath(HeaderHandle H) const {
> +    if ((H >= 0) && (H < (HeaderHandle)HeaderPaths.size()))
> +      return HeaderPaths[H];
> +    return StringHandle();
> +  }
> +
> +  // Returns a handle to the inclusion path.
> +  InclusionPathHandle pushHeaderHandle(HeaderHandle H) {
> +    HeaderStack.push_back(H);
> +    return CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
> +  }
> +  // Pops the last header handle from the stack;
> +  void popHeaderHandle() {
> +    // assert((HeaderStack.size() != 0) && "Header stack already empty.");
> +    if (HeaderStack.size() != 0) {
> +      HeaderStack.pop_back();
> +      CurrentInclusionPathHandle = addInclusionPathHandle(HeaderStack);
> +    }
> +  }
> +  // Get the top handle on the header stack.
> +  HeaderHandle getCurrentHeaderHandle() const {
> +    if (HeaderStack.size() != 0)
> +      return HeaderStack.back();
> +    return HeaderHandleInvalid;
> +  }
> +
> +  // Check for presence of header handle in the header stack.
> +  bool isHeaderHandleInStack(HeaderHandle H) const {
> +    for (std::vector<HeaderHandle>::const_iterator I = HeaderStack.begin(),
> +                                                   E = HeaderStack.end();
> +         I != E; ++I) {
> +      if (*I == H)
> +        return true;
> +    }
> +    return false;
> +  }
> +
> +  // Get the handle of a header inclusion path entry.
> +  // Return InclusionPathHandleInvalid if not found.
> +  InclusionPathHandle
> +  findInclusionPathHandle(const std::vector<HeaderHandle> &Path) const {
> +    InclusionPathHandle H = 0;
> +    for (std::vector<HeaderInclusionPath>::const_iterator
> +             I = InclusionPaths.begin(),
> +             E = InclusionPaths.end();
> +         I != E; ++I, ++H) {
> +      if (I->Path == Path)
> +        return H;
> +    }
> +    return HeaderHandleInvalid;
> +  }
> +  // Add a new header inclusion path entry, or return existing handle.
> +  // Return the header inclusion path entry handle.
> +  InclusionPathHandle
> +  addInclusionPathHandle(const std::vector<HeaderHandle> &Path) {
> +    InclusionPathHandle H = findInclusionPathHandle(Path);
> +    if (H == HeaderHandleInvalid) {
> +      H = InclusionPaths.size();
> +      InclusionPaths.push_back(HeaderInclusionPath(Path));
> +    }
> +    return H;
> +  }
> +  // Return the current inclusion path handle.
> +  InclusionPathHandle getCurrentInclusionPathHandle() const {
> +    return CurrentInclusionPathHandle;
> +  }
> +
> +  // Return an inclusion path given its handle.
> +  const std::vector<HeaderHandle> &
> +  getInclusionPath(InclusionPathHandle H) const {
> +    if ((H >= 0) && (H <= (InclusionPathHandle)InclusionPaths.size()))
> +      return InclusionPaths[H].Path;
> +    static std::vector<HeaderHandle> Empty;
> +    return Empty;
> +  }
> +
> +  // Add a macro expansion instance.
> +  void addMacroExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
> +                                 clang::SourceLocation InstanceLoc,
> +                                 clang::SourceLocation DefinitionLoc,
> +                                 clang::IdentifierInfo *II,
> +                                 llvm::StringRef MacroUnexpanded,
> +                                 llvm::StringRef MacroExpanded,
> +                                 InclusionPathHandle InclusionPathHandle) {
> +    StringHandle MacroName = addString(II->getName());
> +    PPItemKey instanceKey(PP, MacroName, H, InstanceLoc);
> +    PPItemKey definitionKey(PP, MacroName, H, DefinitionLoc);
> +    MacroExpansionMapIter I = MacroExpansions.find(instanceKey);
> +    if (I == MacroExpansions.end()) {
> +      std::string instanceSourceLine =
> +          getSourceLocationString(PP, InstanceLoc) + ":\n" +
> +          getSourceLine(PP, InstanceLoc) + "\n";
> +      std::string definitionSourceLine =
> +          getSourceLocationString(PP, DefinitionLoc) + ":\n" +
> +          getSourceLine(PP, DefinitionLoc) + "\n";
> +      MacroExpansions[instanceKey] = MacroExpansionTracker(
> +          addString(MacroUnexpanded), addString(MacroExpanded),
> +          addString(instanceSourceLine), definitionKey,
> +          addString(definitionSourceLine), InclusionPathHandle);
> +    } else {
> +      MacroExpansionTracker &CondTracker = I->second;
> +      MacroExpansionInstance *MacroInfo =
> +          CondTracker.findMacroExpansionInstance(addString(MacroExpanded),
> +                                                 definitionKey);
> +      if (MacroInfo != NULL)
> +        MacroInfo->addInclusionPathHandle(InclusionPathHandle);
> +      else {
> +        std::string definitionSourceLine =
> +            getSourceLocationString(PP, DefinitionLoc) + ":\n" +
> +            getSourceLine(PP, DefinitionLoc) + "\n";
> +        CondTracker.addMacroExpansionInstance(
> +            addString(MacroExpanded), definitionKey,
> +            addString(definitionSourceLine), InclusionPathHandle);
> +      }
> +    }
> +  }
> +
> +  // Add a conditional expansion instance.
> +  void
> +  addConditionalExpansionInstance(clang::Preprocessor &PP, HeaderHandle H,
> +                                  clang::SourceLocation InstanceLoc,
> +                                  clang::tok::PPKeywordKind DirectiveKind,
> +                                  bool ConditionValue,
> +                                  llvm::StringRef ConditionUnexpanded,
> +                                  InclusionPathHandle InclusionPathHandle) {
> +    StringHandle conditionUnexpanded(addString(ConditionUnexpanded));
> +    PPItemKey instanceKey(PP, conditionUnexpanded, H, InstanceLoc);
> +    ConditionalExpansionMapIter I = ConditionalExpansions.find(instanceKey);
> +    if (I == ConditionalExpansions.end()) {
> +      std::string instanceSourceLine =
> +          getSourceLocationString(PP, InstanceLoc) + ":\n" +
> +          getSourceLine(PP, InstanceLoc) + "\n";
> +      ConditionalExpansions[instanceKey] =
> +          ConditionalTracker(DirectiveKind, ConditionValue, conditionUnexpanded,
> +                             InclusionPathHandle);
> +    } else {
> +      ConditionalTracker &CondTracker = I->second;
> +      ConditionalExpansionInstance *MacroInfo =
> +          CondTracker.findConditionalExpansionInstance(ConditionValue);
> +      if (MacroInfo != NULL)
> +        MacroInfo->addInclusionPathHandle(InclusionPathHandle);
> +      else {
> +        CondTracker.addConditionalExpansionInstance(ConditionValue,
> +                                                    InclusionPathHandle);
> +      }
> +    }
> +  }
> +
> +  // Report on inconsistent macro instances.
> +  // Returns true if any mismatches.
> +  bool reportInconsistentMacros(llvm::raw_ostream &OS) {
> +    bool returnValue = false;
> +    for (MacroExpansionMapIter I = MacroExpansions.begin(),
> +                               E = MacroExpansions.end();
> +         I != E; ++I) {
> +      const PPItemKey &ItemKey = I->first;
> +      MacroExpansionTracker &MacroExpTracker = I->second;
> +      if (!MacroExpTracker.hasMismatch())
> +        continue;
> +      returnValue = true;
> +      OS << *MacroExpTracker.InstanceSourceLine;
> +      if (ItemKey.Column > 0)
> +        OS << std::string(ItemKey.Column - 1, ' ') << "^\n";
> +      OS << "error: Macro instance '" << *MacroExpTracker.MacroUnexpanded
> +         << "' has different values in this header, depending on how it was "
> +            "included.\n";
> +      for (std::vector<MacroExpansionInstance>::iterator
> +               IMT = MacroExpTracker.MacroExpansionInstances.begin(),
> +               EMT = MacroExpTracker.MacroExpansionInstances.end();
> +           IMT != EMT; ++IMT) {
> +        MacroExpansionInstance &MacroInfo = *IMT;
> +        OS << "  '" << *MacroExpTracker.MacroUnexpanded << "' Expanded to: '"
> +           << *MacroInfo.MacroExpanded
> +           << "' with respect to these inclusion paths:\n";
> +        for (std::vector<InclusionPathHandle>::iterator
> +                 IIP = MacroInfo.InclusionPathHandles.begin(),
> +                 EIP = MacroInfo.InclusionPathHandles.end();
> +             IIP != EIP; ++IIP) {
> +          const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
> +          int Count = (int)ip.size();
> +          for (int Index = 0; Index < Count; ++Index) {
> +            HeaderHandle H = ip[Index];
> +            OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
> +               << "\n";
> +          }
> +        }
> +        // For a macro that wasn't defined, we flag it by using the
> +        // instance location.
> +        // If there is a definition...
> +        if (MacroInfo.DefinitionLocation.Line != ItemKey.Line) {
> +          OS << *MacroInfo.DefinitionSourceLine;
> +          if (MacroInfo.DefinitionLocation.Column > 0)
> +            OS << std::string(MacroInfo.DefinitionLocation.Column - 1, ' ')
> +               << "^\n";
> +          OS << "Macro defined here.\n";
> +        } else
> +          OS << "(no macro definition)"
> +             << "\n";
> +      }
> +    }
> +    return returnValue;
> +  }
> +
> +  // Report on inconsistent conditional instances.
> +  // Returns true if any mismatches.
> +  bool reportInconsistentConditionals(llvm::raw_ostream &OS) {
> +    bool returnValue = false;
> +    for (ConditionalExpansionMapIter I = ConditionalExpansions.begin(),
> +                                     E = ConditionalExpansions.end();
> +         I != E; ++I) {
> +      const PPItemKey &ItemKey = I->first;
> +      ConditionalTracker &CondTracker = I->second;
> +      if (!CondTracker.hasMismatch())
> +        continue;
> +      returnValue = true;
> +      OS << *HeaderPaths[ItemKey.File] << ":" << ItemKey.Line << ":"
> +         << ItemKey.Column << "\n";
> +      OS << "#" << getDirectiveSpelling(CondTracker.DirectiveKind) << " "
> +         << *CondTracker.ConditionUnexpanded << "\n";
> +      OS << "^\n";
> +      OS << "error: Conditional expression instance '"
> +         << *CondTracker.ConditionUnexpanded
> +         << "' has different values in this header, depending on how it was "
> +            "included.\n";
> +      for (std::vector<ConditionalExpansionInstance>::iterator
> +               IMT = CondTracker.ConditionalExpansionInstances.begin(),
> +               EMT = CondTracker.ConditionalExpansionInstances.end();
> +           IMT != EMT; ++IMT) {
> +        ConditionalExpansionInstance &MacroInfo = *IMT;
> +        OS << "  '" << *CondTracker.ConditionUnexpanded << "' Expanded to: '"
> +           << (MacroInfo.ConditionValue ? "true" : "false")
> +           << "' with respect to these inclusion paths:\n";
> +        for (std::vector<InclusionPathHandle>::iterator
> +                 IIP = MacroInfo.InclusionPathHandles.begin(),
> +                 EIP = MacroInfo.InclusionPathHandles.end();
> +             IIP != EIP; ++IIP) {
> +          const std::vector<HeaderHandle> &ip = getInclusionPath(*IIP);
> +          int Count = (int)ip.size();
> +          for (int Index = 0; Index < Count; ++Index) {
> +            HeaderHandle H = ip[Index];
> +            OS << std::string((Index * 2) + 4, ' ') << *getHeaderFilePath(H)
> +               << "\n";
> +          }
> +        }
> +      }
> +    }
> +    return returnValue;
> +  }
> +
> +  // Get directive spelling.
> +  static const char *getDirectiveSpelling(clang::tok::PPKeywordKind kind) {
> +    switch (kind) {
> +    case clang::tok::pp_if:
> +      return "if";
> +    case clang::tok::pp_elif:
> +      return "elif";
> +    case clang::tok::pp_ifdef:
> +      return "ifdef";
> +    case clang::tok::pp_ifndef:
> +      return "ifndef";
> +    default:
> +      return "(unknown)";
> +    }
> +  }
> +
> +private:
> +  llvm::StringPool Strings;
> +  std::vector<StringHandle> HeaderPaths;
> +  std::vector<HeaderHandle> HeaderStack;
> +  std::vector<HeaderInclusionPath> InclusionPaths;
> +  InclusionPathHandle CurrentInclusionPathHandle;
> +  MacroExpansionMap MacroExpansions;
> +  ConditionalExpansionMap ConditionalExpansions;
> +};
> +
> +// PreprocessorTracker functions.
> +
> +// PreprocessorTracker desctructor.
> +PreprocessorTracker::~PreprocessorTracker() {}
> +
> +// Create instance of PreprocessorTracker.
> +PreprocessorTracker *PreprocessorTracker::create() {
> +  return new PreprocessorTrackerImpl();
> +}
> +
> +// Preprocessor callbacks for modularize.
> +
> +// Handle file entry/exit.
> +void PreprocessorCallbacks::FileChanged(
> +    clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason,
> +    clang::SrcMgr::CharacteristicKind FileType, clang::FileID PrevFID) {
> +  switch (Reason) {
> +  case EnterFile:
> +    PPTracker.handleHeaderEntry(PP, getSourceLocationFile(PP, Loc));
> +    break;
> +  case ExitFile:
> +    if (PrevFID.isInvalid())
> +      PPTracker.handleHeaderExit(RootHeaderFile);
> +    else
> +      PPTracker.handleHeaderExit(getSourceLocationFile(PP, Loc));
> +    break;
> +  case SystemHeaderPragma:
> +    return;
> +  case RenameFile:
> +    return;
> +  default:
> +    return;
> +  }
> +}
> +
> +// Handle macro expansion.
> +void PreprocessorCallbacks::MacroExpands(const clang::Token &MacroNameTok,
> +                                         const clang::MacroDirective *MD,
> +                                         clang::SourceRange Range,
> +                                         const clang::MacroArgs *Args) {
> +  clang::SourceLocation Loc = Range.getBegin();
> +  clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
> +  const clang::MacroInfo *MI = PP.getMacroInfo(II);
> +  std::string MacroName = II->getName().str();
> +  std::string Unexpanded(getMacroUnexpandedString(Range, PP, MacroName, MI));
> +  std::string Expanded(getMacroExpandedString(PP, MacroName, MI, Args));
> +  PPTracker.addMacroExpansionInstance(
> +      PP, PPTracker.getCurrentHeaderHandle(), Loc, MI->getDefinitionLoc(), II,
> +      Unexpanded, Expanded, PPTracker.getCurrentInclusionPathHandle());
> +}
> +
> +void PreprocessorCallbacks::Defined(const clang::Token &MacroNameTok,
> +                                    const clang::MacroDirective *MD,
> +                                    clang::SourceRange Range) {
> +  clang::SourceLocation Loc(Range.getBegin());
> +  clang::IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
> +  const clang::MacroInfo *MI = PP.getMacroInfo(II);
> +  std::string MacroName = II->getName().str();
> +  std::string Unexpanded(getSourceString(PP, Range));
> +  PPTracker.addMacroExpansionInstance(
> +      PP, PPTracker.getCurrentHeaderHandle(), Loc,
> +      (MI ? MI->getDefinitionLoc() : Loc), II, Unexpanded,
> +      (MI ? "true" : "false"), PPTracker.getCurrentInclusionPathHandle());
> +}
> +
> +void PreprocessorCallbacks::If(clang::SourceLocation Loc,
> +                               clang::SourceRange ConditionRange,
> +                               bool ConditionResult) {
> +  std::string Unexpanded(getSourceString(PP, ConditionRange));
> +  PPTracker.addConditionalExpansionInstance(
> +      PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_if,
> +      ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
> +}
> +
> +void PreprocessorCallbacks::Elif(clang::SourceLocation Loc,
> +                                 clang::SourceRange ConditionRange,
> +                                 bool ConditionResult,
> +                                 clang::SourceLocation IfLoc) {
> +  std::string Unexpanded(getSourceString(PP, ConditionRange));
> +  PPTracker.addConditionalExpansionInstance(
> +      PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_elif,
> +      ConditionResult, Unexpanded, PPTracker.getCurrentInclusionPathHandle());
> +}
> +
> +void PreprocessorCallbacks::Ifdef(clang::SourceLocation Loc,
> +                                  const clang::Token &MacroNameTok,
> +                                  const clang::MacroDirective *MD) {
> +  bool IsDefined = (MD != 0);
> +  PPTracker.addConditionalExpansionInstance(
> +      PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifdef,
> +      IsDefined, PP.getSpelling(MacroNameTok),
> +      PPTracker.getCurrentInclusionPathHandle());
> +}
> +
> +void PreprocessorCallbacks::Ifndef(clang::SourceLocation Loc,
> +                                   const clang::Token &MacroNameTok,
> +                                   const clang::MacroDirective *MD) {
> +  bool IsNotDefined = (MD == 0);
> +  PPTracker.addConditionalExpansionInstance(
> +      PP, PPTracker.getCurrentHeaderHandle(), Loc, clang::tok::pp_ifndef,
> +      IsNotDefined, PP.getSpelling(MacroNameTok),
> +      PPTracker.getCurrentInclusionPathHandle());
> +}
> +} // end namespace Modularize
>
> Added: clang-tools-extra/trunk/modularize/PreprocessorTracker.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/modularize/PreprocessorTracker.h?rev=187228&view=auto
> ==============================================================================
> --- clang-tools-extra/trunk/modularize/PreprocessorTracker.h (added)
> +++ clang-tools-extra/trunk/modularize/PreprocessorTracker.h Fri Jul 26 13:16:22 2013
> @@ -0,0 +1,53 @@
> +//===- PreprocessorTracker.h - Tracks preprocessor activities -*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===--------------------------------------------------------------------===//
> +///
> +/// \file
> +/// \brief Track preprocessor activities for modularize.
> +///
> +//===--------------------------------------------------------------------===//
> +
> +#ifndef MODULARIZE_PREPROCESSOR_TRACKER_H
> +#define MODULARIZE_PREPROCESSOR_TRACKER_H
> +
> +#include "clang/Lex/Preprocessor.h"
> +
> +namespace Modularize {
> +
> +// Preprocessor tracker for modularize.
> +//
> +// This class stores information about all the headers processed in the
> +// course of running modularize.
> +class PreprocessorTracker {
> +public:
> +  virtual ~PreprocessorTracker();
> +
> +  // Handle entering a preprocessing session.
> +  // (Called after a Preprocessor object is created, but before preprocessing.)
> +  virtual void handlePreprocessorEntry(clang::Preprocessor &PP,
> +                                       llvm::StringRef RootHeaderFile) = 0;
> +  // Handle exiting a preprocessing session.
> +  // (Called after preprocessing is complete, but before the Preprocessor
> +  // object is destroyed.)
> +  virtual void handlePreprocessorExit() = 0;
> +
> +  // Report on inconsistent macro instances.
> +  // Returns true if any mismatches.
> +  virtual bool reportInconsistentMacros(llvm::raw_ostream &OS) = 0;
> +
> +  // Report on inconsistent conditional directive instances.
> +  // Returns true if any mismatches.
> +  virtual bool reportInconsistentConditionals(llvm::raw_ostream &OS) = 0;
> +
> +  // Create instance of PreprocessorTracker.
> +  static PreprocessorTracker *create();
> +};
> +
> +} // end namespace Modularize
> +
> +#endif
>
> Modified: clang-tools-extra/trunk/test/modularize/Inputs/InconsistentSubHeader.h
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/modularize/Inputs/InconsistentSubHeader.h?rev=187228&r1=187227&r2=187228&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/test/modularize/Inputs/InconsistentSubHeader.h (original)
> +++ clang-tools-extra/trunk/test/modularize/Inputs/InconsistentSubHeader.h Fri Jul 26 13:16:22 2013
> @@ -1,11 +1,18 @@
>  // Set up so TypeInt only defined during InconsistentHeader1.h include.
>  #ifdef SYMBOL1
>  #define SYMBOL 1
> +#define FUNC_STYLE(a, b) a || b
>  #endif
>  #ifdef SYMBOL2
>  #define SYMBOL 2
> +#define FUNC_STYLE(a, b) a &&b
>  #endif
>
>  #if SYMBOL == 1
>  typedef int TypeInt;
>  #endif
> +
> +int var = FUNC_STYLE(1, 0);
> +
> +#if defined(SYMBOL1)
> +#endif
>
> Modified: clang-tools-extra/trunk/test/modularize/ProblemsInconsistent.modularize
> URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/modularize/ProblemsInconsistent.modularize?rev=187228&r1=187227&r2=187228&view=diff
> ==============================================================================
> --- clang-tools-extra/trunk/test/modularize/ProblemsInconsistent.modularize (original)
> +++ clang-tools-extra/trunk/test/modularize/ProblemsInconsistent.modularize Fri Jul 26 13:16:22 2013
> @@ -4,9 +4,105 @@ Inputs/InconsistentHeader1.h
>  Inputs/InconsistentHeader2.h
>
>  # CHECK: error: macro 'SYMBOL' defined at multiple locations:
> -# CHECK-NEXT:    {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:3:9
> -# CHECK-NEXT:    {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:6:9
> -# CHECK-NEXT: error: header '{{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h' has different contents depending on how it was included
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:3:9
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:7:9
> +# CHECK-NEXT: error: macro 'FUNC_STYLE' defined at multiple locations:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:4:9
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:8:9
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:15:11:
> +# CHECK-NEXT: int var = FUNC_STYLE(1, 0);
> +# CHECK-NEXT:           ^
> +# CHECK-NEXT: error: Macro instance 'FUNC_STYLE(1, 0);' has different values in this header, depending on how it was included.
> +# CHECK-NEXT:   'FUNC_STYLE(1, 0);' expanded to: '1||0' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:4:9:
> +# CHECK-NEXT: #define FUNC_STYLE(a, b) a || b
> +# CHECK-NEXT:         ^
> +# CHECK-NEXT: Macro defined here.
> +# CHECK-NEXT:   'FUNC_STYLE(1, 0);' expanded to: '1&&0' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:8:9:
> +# CHECK-NEXT: #define FUNC_STYLE(a, b) a &&b
> +# CHECK-NEXT:         ^
> +# CHECK-NEXT: Macro defined here.
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:11:5:
> +# CHECK-NEXT: #if SYMBOL == 1
> +# CHECK-NEXT:     ^
> +# CHECK-NEXT: error: Macro instance 'SYMBOL' has different values in this header, depending on how it was included.
> +# CHECK-NEXT:   'SYMBOL' expanded to: '1' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:3:9:
> +# CHECK-NEXT: #define SYMBOL 1
> +# CHECK-NEXT:         ^
> +# CHECK-NEXT: Macro defined here.
> +# CHECK-NEXT:   'SYMBOL' expanded to: '2' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:7:9:
> +# CHECK-NEXT: #define SYMBOL 2
> +# CHECK-NEXT:         ^
> +# CHECK-NEXT: Macro defined here.
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:17:5:
> +# CHECK-NEXT: #if defined(SYMBOL1)
> +# CHECK-NEXT:     ^
> +# CHECK-NEXT: error: Macro instance 'defined(SYMBOL1)' has different values in this header, depending on how it was included.
> +# CHECK-NEXT:   'defined(SYMBOL1)' expanded to: 'true' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h:3:9:
> +# CHECK-NEXT: #define SYMBOL1 1
> +# CHECK-NEXT:         ^
> +# CHECK-NEXT: Macro defined here.
> +# CHECK-NEXT:   'defined(SYMBOL1)' expanded to: 'false' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: (no macro definition)
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:11:2
> +# CHECK-NEXT: #if SYMBOL == 1
> +# CHECK-NEXT: ^
> +# CHECK-NEXT: error: Conditional expression instance 'SYMBOL == 1' has different values in this header, depending on how it was included.
> +# CHECK-NEXT:   'SYMBOL == 1' expanded to: 'true' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT:   'SYMBOL == 1' expanded to: 'false' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:2:2
> +# CHECK-NEXT: #ifdef SYMBOL1
> +# CHECK-NEXT: ^
> +# CHECK-NEXT: error: Conditional expression instance 'SYMBOL1' has different values in this header, depending on how it was included.
> +# CHECK-NEXT:   'SYMBOL1' expanded to: 'true' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT:   'SYMBOL1' expanded to: 'false' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:6:2
> +# CHECK-NEXT: #ifdef SYMBOL2
> +# CHECK-NEXT: ^
> +# CHECK-NEXT: error: Conditional expression instance 'SYMBOL2' has different values in this header, depending on how it was included.
> +# CHECK-NEXT:   'SYMBOL2' expanded to: 'false' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT:   'SYMBOL2' expanded to: 'true' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:17:2
> +# CHECK-NEXT: #if defined(SYMBOL1)
> +# CHECK-NEXT: ^
> +# CHECK-NEXT: error: Conditional expression instance 'defined(SYMBOL1)' has different values in this header, depending on how it was included.
> +# CHECK-NEXT:   'defined(SYMBOL1)' expanded to: 'true' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT:   'defined(SYMBOL1)' expanded to: 'false' with respect to these inclusion paths:
> +# CHECK-NEXT:     {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h
> +# CHECK-NEXT:       {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h
> +# CHECK-NEXT: error: header '{{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h' has different contents depending on how it was included.
>  # CHECK-NEXT: note: 'SYMBOL' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 3:9 not always provided
> -# CHECK-NEXT: note: 'SYMBOL' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 6:9 not always provided
> -# CHECK-NEXT: note: 'TypeInt' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 10:13 not always provided
> +# CHECK-NEXT: note: 'FUNC_STYLE' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 4:9 not always provided
> +# CHECK-NEXT: note: 'SYMBOL' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 7:9 not always provided
> +# CHECK-NEXT: note: 'FUNC_STYLE' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 8:9 not always provided
> +# CHECK-NEXT: note: 'TypeInt' in {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h at 12:13 not always provided
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list