[clang-tools-extra] r187228 - Added new feature for checking macro and preprocessor conditional consistency.
John Thompson
John.Thompson.JTSoftware at gmail.com
Fri Jul 26 11:16:22 PDT 2013
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
More information about the cfe-commits
mailing list