Index: test/modularize/Inputs/InconsistentSubHeader.h =================================================================== --- test/modularize/Inputs/InconsistentSubHeader.h (revision 183718) +++ test/modularize/Inputs/InconsistentSubHeader.h (working copy) @@ -1,8 +1,8 @@ // Set up so TypeInt only defined during InconsistentHeader1.h include. -#ifdef SYMBOL1 +#if defined(SYMBOL1) && !defined(SYMBOL) #define SYMBOL 1 #endif -#ifdef SYMBOL2 +#if defined(SYMBOL2) && !defined(SYMBOL) #define SYMBOL 2 #endif Index: test/modularize/ProblemsInconsistent.modularize =================================================================== --- test/modularize/ProblemsInconsistent.modularize (revision 183718) +++ test/modularize/ProblemsInconsistent.modularize (working copy) @@ -6,7 +6,16 @@ # 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 dependening on how it was included +# CHECK-NEXT:warning: The instances of header {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h have different contents after preprocessing: +# CHECK-NEXT: When included or nested in these top-level headers: +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader1.h +# CHECK-NEXT: This preprocessor directive is mismatched (the parentheses show the condition after macro substitution): +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:9:1: #if SYMBOL == 1 (#if 1 == 1) +# CHECK-NEXT: When included or nested in these top-level headers: +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentHeader2.h +# CHECK-NEXT: This preprocessor directive is mismatched (the parentheses show the condition after macro substitution): +# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}InconsistentSubHeader.h:9:1: #if SYMBOL == 1 (#if 2 == 1) +# 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 Index: modularize/ModularizeHeaderTracker.cpp =================================================================== --- modularize/ModularizeHeaderTracker.cpp (revision 0) +++ modularize/ModularizeHeaderTracker.cpp (revision 0) @@ -0,0 +1,134 @@ +//==- ModularizeHeaderTracker.cpp - Represents header instances -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModularizeHeaderTracker.h" +#include "ModularizeUtilities.h" +#include "llvm/Support/raw_ostream.h" + +namespace Modularize { +using namespace llvm; +using namespace clang; + +ModularizeHeaderTracker::ModularizeHeaderTracker( + std::string& name, ModularizeHeaderFile *headerFile, + std::string topHeader) : + Name(name) { + ModularizeHeaderInstance *headerInstance = new ModularizeHeaderInstance( + headerFile, topHeader); + AddHeaderInstance(headerInstance); +} + +ModularizeHeaderTracker::~ModularizeHeaderTracker() { +} + +// Process a header snapshot. +// If the snapshot differs, add a new header instance. +void ModularizeHeaderTracker::AddHeaderFile( + ModularizeHeaderFile *headerFile, std::string topHeader) { + ModularizeHeaderInstanceVectorIterator iter = HeaderInstances.begin(); + ModularizeHeaderInstanceVectorIterator EI = HeaderInstances.end(); + for (; iter != EI; ++iter) { + ModularizeHeaderFile *existingHeader = (*iter)->GetHeaderFile(); + if (existingHeader->Match(headerFile)) { + (*iter)->AddTopHeader(topHeader); + return; + } + } + ModularizeHeaderInstance *newInstance = new ModularizeHeaderInstance( + headerFile, topHeader); + AddHeaderInstance(newInstance); +} + +// Add a header instance. +void ModularizeHeaderTracker::AddHeaderInstance( + ModularizeHeaderInstance *headerInstance) { + HeaderInstances.push_back(headerInstance); +} + +// Report instances where header snapshots differ. +// Returns true if no errors, i.e. no differing snapshots. +bool ModularizeHeaderTracker::Report() { + int headerInstanceIndex; + int headerInstanceCount = GetHeaderInstanceCount(); + ModularizeHeaderInstance *headerInstance; + ModularizeHeaderInstance *headerInstance0; + ModularizeHeaderFile *headerFile; + ModularizeHeaderFile *headerFile0; + int directiveIndex; + ModularizePPDirective *directive; + ModularizePPDirective *directive0; + bool mismatch; + if (GetHeaderInstanceCount() > 1) { + int directiveCount = 0x7fffffff; // Big number. + ModularizeHeaderInstanceVectorIterator hiIter = GetHeaderInstancesBegin(); + ModularizeHeaderInstanceVectorIterator hiEnd = GetHeaderInstancesEnd(); + // Get the number of instances which is least. + for (; hiIter != hiEnd; ++hiIter) { + headerInstance = (*hiIter); + headerFile = headerInstance->GetHeaderFile(); + if (headerFile->GetDirectiveCount() < directiveCount) + directiveCount = headerFile->GetDirectiveCount(); + } + for (directiveIndex = 0; directiveIndex < directiveCount; + directiveIndex++) { + headerInstance0 = GetHeaderInstance(0); + headerFile0 = headerInstance0->GetHeaderFile(); + directive0 = &headerFile0->GetDirective(directiveIndex); + mismatch = false; + for (headerInstanceIndex = 1; headerInstanceIndex < headerInstanceCount; + headerInstanceIndex++) { + headerInstance = GetHeaderInstance(headerInstanceIndex); + headerFile = headerInstance->GetHeaderFile(); + directive = &headerFile->GetDirective(directiveIndex); + if (!directive->Match(directive0)) + mismatch = true; + } + if (mismatch) { + errs() << "warning: The instances of header " << Name << " have different contents after preprocessing:\n"; + for (headerInstanceIndex = 0; headerInstanceIndex < headerInstanceCount; + headerInstanceIndex++) { + headerInstance = GetHeaderInstance(headerInstanceIndex); + headerFile = headerInstance->GetHeaderFile(); + errs() << Indent(1) << "When included or nested in these top-level headers:\n"; + ModularizeTopHeaderVectorIterator thIter = headerInstance->GetTopHeadersBegin(); + ModularizeTopHeaderVectorIterator thEnd = headerInstance->GetTopHeadersEnd(); + for (; thIter != thEnd; ++thIter) { + errs() << Indent(2) << *thIter << "\n"; + } + errs() << Indent(1) << "This preprocessor directive is mismatched (the parentheses show the condition after macro substitution):\n"; + directive = &headerFile->GetDirective(directiveIndex); + directive->Dump(2, Name.c_str()); + } + break; // Stop here, because the blocks might be different after this. + } + } + return false; // There was a mismatch. + } + return true; // No mismatch. +} + +// Display the information for debugging. +void ModularizeHeaderTracker::Dump(int level) { + errs() << Indent(level) << Name << ":\n"; + errs() << Indent(level + 1) << "instance count: " + << GetHeaderInstanceCount() << "\n"; + + errs() << Indent(level + 1) << "instances: \n"; + ModularizeHeaderInstanceVectorIterator hiIter = GetHeaderInstancesBegin(); + ModularizeHeaderInstanceVectorIterator hiEnd = GetHeaderInstancesEnd(); + int hiIndex; + for (hiIndex = 0; hiIter != hiEnd; ++hiIter, ++hiIndex) { + ModularizeHeaderInstance *headerInstance = (*hiIter); + errs() << Indent(level + 2) << "instance: " << hiIndex << "\n"; + headerInstance->Dump(level + 3); + } +} + +} + Index: modularize/ModularizeHeaderTracker.h =================================================================== --- modularize/ModularizeHeaderTracker.h (revision 0) +++ modularize/ModularizeHeaderTracker.h (revision 0) @@ -0,0 +1,66 @@ +//===- ModularizeHeaderTracker.h - Represents header instances -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines a class to store header instance snapshot information +/// for one header file. +/// +//===----------------------------------------------------------------------===// + +#ifndef MODULARIZEHEADERTRACKER_H +#define MODULARIZEHEADERTRACKER_H + +#include "ModularizeHeaderInstance.h" + +namespace Modularize { + using namespace clang; + using namespace llvm; + +/// \brief This class stores the header snapshot instances for a particular +/// header. +class ModularizeHeaderTracker { +public: + ModularizeHeaderTracker(std::string& name, ModularizeHeaderFile *headerFile, + std::string topHeader); + ~ModularizeHeaderTracker(); + + // Header name accessors. + std::string& GetName() { return Name; } + void SetName(std::string name) { Name = name; }; + + // Process a header snapshot. + // If the snapshot differs, add a new header instance. + void AddHeaderFile(ModularizeHeaderFile *headerFile, std::string topHeader); + // Add a header instance. + void AddHeaderInstance(ModularizeHeaderInstance *headerInstance); + // Get instance count. > 1 means there were mismatches. + int GetHeaderInstanceCount() { return HeaderInstances.size(); } + // Get header instance vector. + ModularizeHeaderInstanceVector &GetHeaderInstances() { return HeaderInstances; } + ModularizeHeaderInstanceVectorIterator GetHeaderInstancesBegin() { return HeaderInstances.begin(); } + ModularizeHeaderInstanceVectorIterator GetHeaderInstancesEnd() { return HeaderInstances.end(); } + ModularizeHeaderInstance *GetHeaderInstance(int index) { return HeaderInstances[index]; } + + // Report instances where header snapshots differ. + // Returns true if no errors, i.e. no differing snapshots. + bool Report(); + // Display the information for debugging. + void Dump(int level = 0); + +private: + std::string Name; + ModularizeHeaderInstanceVector HeaderInstances; +}; + +typedef StringMap ModularizeHeaderTrackerMap; +typedef ModularizeHeaderTrackerMap::iterator ModularizeHeaderTrackerMapIterator; + +} // end namespace clang + +#endif Index: modularize/ModularizeHeaderInstance.cpp =================================================================== --- modularize/ModularizeHeaderInstance.cpp (revision 0) +++ modularize/ModularizeHeaderInstance.cpp (revision 0) @@ -0,0 +1,56 @@ +//==- ModularizeHeaderInstance.cpp - Stores header instance info -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModularizeHeaderInstance.h" +#include "ModularizeUtilities.h" +#include "llvm/Support/raw_ostream.h" +#include "clang/Basic/SourceManager.h" + +namespace Modularize { +using namespace llvm; +using namespace clang; + +ModularizeHeaderInstance::ModularizeHeaderInstance( + ModularizeHeaderFile *HeaderFile, std::string topHeader) : + HeaderFile(HeaderFile) { + TopHeaders.push_back(topHeader); +} + +ModularizeHeaderInstance::~ModularizeHeaderInstance() { +} + +bool ModularizeHeaderInstance::HasTopHeader(std::string topHeader) { + ModularizeTopHeaderVectorIterator iter = TopHeaders.begin(); + ModularizeTopHeaderVectorIterator end = TopHeaders.begin(); + for (; iter != end; ++iter) { + if (*iter == topHeader) + return true; + } + return false; +} + +// Display the information for debugging. +void ModularizeHeaderInstance::Dump(int level) { + errs() << Indent(level) << "top headers:\n"; + + ModularizeTopHeaderVectorIterator thIter = GetTopHeadersBegin(); + ModularizeTopHeaderVectorIterator thEnd = GetTopHeadersEnd(); + for (; thIter != thEnd; ++thIter) { + errs() << Indent(level + 1) << *thIter << "\n"; + } + + errs() << Indent(level) << "preprocessor directives: \n"; + ModularizePPDirectiveVectorIterator dIter = HeaderFile->GetDirectivesBegin(); + ModularizePPDirectiveVectorIterator dEnd = HeaderFile->GetDirectivesEnd(); + for (; dIter != dEnd; ++dIter) { + (*dIter).Dump(level + 1, HeaderFile->GetName().c_str()); + } +} + +} Index: modularize/ModularizePPDirective.cpp =================================================================== --- modularize/ModularizePPDirective.cpp (revision 0) +++ modularize/ModularizePPDirective.cpp (revision 0) @@ -0,0 +1,96 @@ +//===--- ModularizePPDirective.cpp - Represents a PP directive --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModularizePPDirective.h" +#include "ModularizeUtilities.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/raw_ostream.h" +#include + +#if _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. +# define snprintf _snprintf_s +#elif _MSC_VER +# define snprintf _snprintf +#endif + +namespace Modularize { +using namespace llvm; +using namespace clang; + +ModularizePPDirective::ModularizePPDirective( + ModularizePPDirectiveKind directiveKind, unsigned lineNumber, + std::string unconvertedConditional, std::string convertedConditional) : + DirectiveKind(directiveKind), + LineNumber(lineNumber), + UnconvertedConditional(unconvertedConditional), + ConvertedConditional(convertedConditional) { +} + +ModularizePPDirective::~ModularizePPDirective() { +} + +// Return true if this directive matches another. +// (It compares the converted conditionals.) +bool ModularizePPDirective::Match(ModularizePPDirective *other) { + if (ConvertedConditional == other->GetConvertedConditional()) { + return true; + } + return false; +} + +// Print this directive to a string suitable for a message. +// FIXME: The following was to avoid the apparent portability +// problems with snprintf. Perhaps there was a better way +// with just std::string or other string utilities I don't +// know about, but the following has fewer allocations. +std::string ModularizePPDirective::PrintToString( + int level, std::string fileName) { + char buffer[1024]; + char lineBuffer[80]; + snprintf(lineBuffer, sizeof(lineBuffer) - 1, ":%d:1", LineNumber); + strncpy(buffer, Indent(level).c_str(), sizeof(buffer) - 1); + strncat(buffer, fileName.c_str(), sizeof(buffer) - 1); + strncat(buffer, lineBuffer, sizeof(buffer) - 1); + strncat(buffer, ": ", sizeof(buffer) - 1); + const char *directiveString; + switch (DirectiveKind) { + case MPPD_If: + directiveString = "#if "; + break; + case MPPD_ElIf: + directiveString = "#elif "; + break; + case MPPD_IfDef: + directiveString = "#ifdef "; + break; + case MPPD_IfNDef: + directiveString = "#ifndef "; + break; + default: + directiveString = "#unknown "; + break; + } + strncat(buffer, directiveString, sizeof(buffer) - 1); + strncat(buffer, UnconvertedConditional.c_str(), sizeof(buffer) - 1); + strncat(buffer, " (", sizeof(buffer) - 1); + strncat(buffer, directiveString, sizeof(buffer) - 1); + strncat(buffer, ConvertedConditional.c_str(), sizeof(buffer) - 1); + strncat(buffer, ")\n", sizeof(buffer) - 1); + buffer[sizeof(buffer) - 1] = '\0'; + return std::string(buffer); +} + +// Display the information for debugging. +void ModularizePPDirective::Dump(int level, const char *fileName) { + if (fileName == NULL) + fileName = "line"; + errs() << PrintToString(level, fileName); +} + +} Index: modularize/Modularize.cpp =================================================================== --- modularize/Modularize.cpp (revision 183718) +++ modularize/Modularize.cpp (working copy) @@ -39,7 +39,23 @@ // (file):(row):(column) // (file):(row):(column) // -// error: header '(file)' has different contents dependening on how it was +// The following message might appear if preprocessor conditional directives +// resolve differently. +// +// warning: The instances of header (file) have different contents after +// preprocessing: +// When included or nested in these top-level headers: +// (file list) +// This preprocessor directive is mismatched (the parentheses show the +// condition after macro substitution): +// (file):(line):1: #if SYMBOL == 1 (#if 1 == 1) +// When included or nested in these top-level headers: +// (file list) +// This preprocessor directive is mismatched (the parentheses show the +// condition after macro substitution): +// (file):(line):1: #if SYMBOL == 1 (#if 2 == 1) +// +// error: header '(file)' has different contents depending on how it was // included // // The latter might be followed by messages like the following: @@ -53,20 +69,20 @@ // // Some ideas: // -// 1. Try to figure out the preprocessor conditional directives that -// contribute to problems. -// -// 2. Check for correct and consistent usage of extern "C" {} and other +// 1. Check for correct and consistent usage of extern "C" {} and other // directives. Warn about #include inside extern "C" {}. // -// 3. What else? +// 2. What else? // -// General clean-up and refactoring: +// General clean-up, refactoring, and fixing: // // 1. The Location class seems to be something that we might // want to design to be applicable to a wider range of tools, and stick it // somewhere into Tooling/ in mainline // +// 2. The header preprocessing instance checking has some limitations that +// need to be address. It currently can only handle non-function-like macros. +// //===----------------------------------------------------------------------===// #include "clang/AST/ASTConsumer.h" @@ -90,11 +106,32 @@ #include #include #include +#include "ModularizeMasterHeaderTracker.h" +#include "ModularizePPCallbacks.h" using namespace clang::tooling; using namespace clang; using namespace llvm; +using namespace Modularize; +// Option to specify a prefix to be prepended to the header names. +cl::opt HeaderPrefix( + "prefix", cl::init(""), + cl::desc( + "Prepend header file paths with this prefix." + " If not specified," + " the files are considered to be relative to the header list file.")); + +// Fixme: This option doesn't seem to work. +// Option to disable the header preprocessing check. +cl::opt NoPreprocessingCheck( + "no-preprocessing-check", + cl::desc( + "If this option is specified, no header preprocessing check" + " will be performed. This is a fallback in case there are problems" + " with the checking itself."), + cl::init(false)); + // Option to specify a file name for a list of header files to check. cl::opt ListFileName(cl::Positional, @@ -104,14 +141,6 @@ cl::list CC1Arguments( cl::ConsumeAfter, cl::desc("...")); -// Option to specify a prefix to be prepended to the header names. -cl::opt HeaderPrefix( - "prefix", cl::init(""), - cl::desc( - "Prepend header file paths with this prefix." - " If not specified," - " the files are considered to be relative to the header list file.")); - // Read the header list file and collect the header file names. error_code GetHeaderFileNames(SmallVectorImpl &headerFileNames, StringRef listFileName, StringRef headerPrefix) { @@ -380,8 +409,14 @@ class CollectEntitiesConsumer : public ASTConsumer { public: - CollectEntitiesConsumer(EntityMap &Entities, Preprocessor &PP) - : Entities(Entities), PP(PP) {} + CollectEntitiesConsumer( + EntityMap &Entities, + ModularizeMasterHeaderTracker &masterHeaderTracker, + Preprocessor &PP, StringRef InFile) + : Entities(Entities), MasterHeaderTracker(masterHeaderTracker), PP(PP) { + if (!masterHeaderTracker.IsDisabled()) + PP.addPPCallbacks(new ModularizePPCallbacks(PP, InFile, masterHeaderTracker)); + } virtual void HandleTranslationUnit(ASTContext &Ctx) { SourceManager &SM = Ctx.getSourceManager(); @@ -406,30 +441,39 @@ } private: EntityMap &Entities; + ModularizeMasterHeaderTracker &MasterHeaderTracker; Preprocessor &PP; }; class CollectEntitiesAction : public SyntaxOnlyAction { public: - CollectEntitiesAction(EntityMap &Entities) : Entities(Entities) {} + CollectEntitiesAction( + EntityMap &Entities, ModularizeMasterHeaderTracker &masterHeaderTracker) + : Entities(Entities), MasterHeaderTracker(masterHeaderTracker) {} protected: virtual clang::ASTConsumer * CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { - return new CollectEntitiesConsumer(Entities, CI.getPreprocessor()); + return new CollectEntitiesConsumer( + Entities, MasterHeaderTracker, CI.getPreprocessor(), InFile); } private: EntityMap &Entities; + ModularizeMasterHeaderTracker &MasterHeaderTracker; }; class ModularizeFrontendActionFactory : public FrontendActionFactory { public: - ModularizeFrontendActionFactory(EntityMap &Entities) : Entities(Entities) {} + ModularizeFrontendActionFactory( + EntityMap &Entities, + ModularizeMasterHeaderTracker &masterHeaderTracker) + : Entities(Entities), MasterHeaderTracker(masterHeaderTracker) {} virtual CollectEntitiesAction *create() { - return new CollectEntitiesAction(Entities); + return new CollectEntitiesAction(Entities, MasterHeaderTracker); } private: EntityMap &Entities; + ModularizeMasterHeaderTracker &MasterHeaderTracker; }; int main(int argc, const char **argv) { @@ -458,10 +502,14 @@ Compilations.reset( new FixedCompilationDatabase(Twine(PathBuf), CC1Arguments)); + // Create the master header tracker. + ModularizeMasterHeaderTracker MasterHeaderTracker(NoPreprocessingCheck); + // 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, MasterHeaderTracker)); // Create a place to save duplicate entity locations, separate bins per kind. typedef SmallVector LocationArray; @@ -509,6 +557,10 @@ } } + // Report on header preprocessing mismatches. + if (!MasterHeaderTracker.Report()) + 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 @@ -524,7 +576,7 @@ HadErrors = 1; errs() << "error: header '" << H->first->getName() - << "' has different contents dependening 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 " << H->second[I].Loc.Line << ":" Index: modularize/ModularizePPCallbacks.cpp =================================================================== --- modularize/ModularizePPCallbacks.cpp (revision 0) +++ modularize/ModularizePPCallbacks.cpp (revision 0) @@ -0,0 +1,711 @@ +//===--- PPCallbacks.cpp - Callbacks for Preprocessor actions ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModularizePPCallbacks.h" +#include "ModularizeUtilities.h" +#include "llvm/Support/raw_ostream.h" +#include "clang/Basic/SourceManager.h" +#include +#include +#include + +namespace Modularize { +using namespace llvm; +using namespace clang; + +// FIXME: This class doesn't need to override all the handlers. + +// Set to 1 to enable tracing messages. +// FIXME: Take out the tracing when it will no longer be needed. +#define MPPC_TRACE 0 + +ModularizePPCallbacks::ModularizePPCallbacks(Preprocessor& pp, StringRef topFile, + ModularizeMasterHeaderTracker &masterHeaderTracker) : + MasterHeaderTracker(masterHeaderTracker), + TopFile(topFile.str()), + PP(pp), + RootHeaderFile(NULL), + CurrentHeaderFile(NULL) { + ModularizeHeaderFile *mhf = new ModularizeHeaderFile(topFile.str(), PP); + AddHeaderFile(mhf); + CurrentHeaderFile = mhf; + RootHeaderFile = mhf; +} + +ModularizePPCallbacks::~ModularizePPCallbacks() { +#if MPPC_TRACE + Trace("~ModularizePPCallbacks called.\n"); +#endif +} + +/// \brief Callback invoked whenever a source file is entered or exited. +/// +/// \param Loc Indicates the new location. +/// \param PrevFID the file that was exited if \p Reason is ExitFile. +void ModularizePPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { + std::string locFileName(SourceLocationFile(Loc)); +#if MPPC_TRACE + std::string prevFileName(FileName(PrevFID)); + std::string locString(SourceLocationStr(Loc)); + Trace(Loc, "FileChanged(%s, %s, %s, %s) called.\n", + locString.c_str(), FileChangeReasonStr(Reason), CharacteristicKindStr(FileType), + prevFileName.c_str()); +#endif + ModularizeHeaderFile *mhf = NULL; + std::string *fileName = NULL; + switch (Reason) { + case EnterFile: + fileName = &locFileName; + break; + case ExitFile: + if (PrevFID.isInvalid()) + fileName = &TopFile; + else + fileName = &locFileName; + break; + case SystemHeaderPragma: + return; + case RenameFile: + return; + default: + return; + } + if (fileName == NULL) + return; + mhf = GetHeaderFile(*fileName); + if (mhf == NULL) { + mhf = new ModularizeHeaderFile(*fileName, PP); + AddHeaderFile(mhf); + CurrentHeaderFile = mhf; + if (!RootHeaderFile) + RootHeaderFile = mhf; + } + else + CurrentHeaderFile = mhf; +} + +/// \brief Callback invoked whenever a source file is skipped as the result +/// of header guard optimization. +/// +/// \param ParentFile The file that \#included the skipped file. +/// +/// \param FilenameTok The token in ParentFile that indicates the +/// skipped file. +void ModularizePPCallbacks::FileSkipped(const FileEntry &ParentFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) { +#if MPPC_TRACE + Trace(FilenameTok, "FileSkipped called.\n"); +#endif +} + +/// \brief Callback invoked whenever an inclusion directive results in a +/// file-not-found error. +/// +/// \param FileName The name of the file being included, as written in the +/// source code. +/// +/// \param RecoveryPath If this client indicates that it can recover from +/// this missing file, the client should set this as an additional header +/// search patch. +/// +/// \returns true to indicate that the preprocessor should attempt to recover +/// by adding \p RecoveryPath as a header search path. +bool ModularizePPCallbacks::FileNotFound(StringRef FileName, + SmallVectorImpl &RecoveryPath) { +#if MPPC_TRACE + Trace("FileNotFound(%s) called.\n", FileName.str().c_str()); +#endif + return false; +} + +/// \brief Callback invoked whenever an inclusion directive of +/// any kind (\c \#include, \c \#import, etc.) has been processed, regardless +/// of whether the inclusion will actually result in an inclusion. +/// +/// \param HashLoc The location of the '#' that starts the inclusion +/// directive. +/// +/// \param IncludeTok The token that indicates the kind of inclusion +/// directive, e.g., 'include' or 'import'. +/// +/// \param FileName The name of the file being included, as written in the +/// source code. +/// +/// \param IsAngled Whether the file name was enclosed in angle brackets; +/// otherwise, it was enclosed in quotes. +/// +/// \param FilenameRange The character range of the quotes or angle brackets +/// for the written file name. +/// +/// \param File The actual file that may be included by this inclusion +/// directive. +/// +/// \param SearchPath Contains the search path which was used to find the file +/// in the file system. If the file was found via an absolute include path, +/// SearchPath will be empty. For framework includes, the SearchPath and +/// RelativePath will be split up. For example, if an include of "Some/Some.h" +/// is found via the framework path +/// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be +/// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be +/// "Some.h". +/// +/// \param RelativePath The path relative to SearchPath, at which the include +/// file was found. This is equal to FileName except for framework includes. +/// +/// \param Imported The module, whenever an inclusion directive was +/// automatically turned into a module import or null otherwise. +/// +void ModularizePPCallbacks::InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported) { + std::string fileName(File->getName()); +#if 0 // Can result in mismatched files. + ModularizeHeaderFile *mhf = NULL; + mhf = GetHeaderFile(fileName); + if (mhf == NULL) { + mhf = new ModularizeHeaderFile(fileName, PP); + AddHeaderFile(mhf); + CurrentHeaderFile = mhf; + if (!RootHeaderFile) + RootHeaderFile = mhf; + } + else + CurrentHeaderFile = mhf; +#endif +#if MPPC_TRACE + Trace(IncludeTok, "InclusionDirective(%s) called.\n", fileName.c_str()); +#endif +} + +/// \brief Callback invoked whenever there was an explicit module-import +/// syntax. +/// +/// \param ImportLoc The location of import directive token. +/// +/// \param Path The identifiers (and their locations) of the module +/// "path", e.g., "std.vector" would be split into "std" and "vector". +/// +/// \param Imported The imported module; can be null if importing failed. +/// +void ModularizePPCallbacks::moduleImport(SourceLocation ImportLoc, + ModuleIdPath Path, + const Module *Imported) { +#if MPPC_TRACE + Trace(ImportLoc, "moduleImport() called.\n"); +#endif +} + +/// \brief Callback invoked when the end of the main file is reached. +/// +/// No subsequent callbacks will be made. +void ModularizePPCallbacks::EndOfMainFile() { + // Add all the header snapshots to the master header file tracker. + ModularizeHeaderFileMapIterator iter = HeaderFileMap.begin(); + ModularizeHeaderFileMapIterator end = HeaderFileMap.end(); + for (; iter != end; ++iter) { + MasterHeaderTracker.AddHeaderFile((*iter).second, TopFile); + } +#if MPPC_TRACE + Trace("EndOfMainFile() called.\n"); +#endif +} + +/// \brief Callback invoked when a \#ident or \#sccs directive is read. +/// \param Loc The location of the directive. +/// \param str The text of the directive. +/// +void ModularizePPCallbacks::Ident(SourceLocation Loc, const std::string &str) { +#if MPPC_TRACE + Trace(Loc, "Ident() called.\n"); +#endif +} + +/// \brief Callback invoked when a \#pragma comment directive is read. +void ModularizePPCallbacks::PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + const std::string &Str) { +#if MPPC_TRACE + Trace(Loc, "PragmaComment() called.\n"); +#endif +} + +/// \brief Callback invoked when a \#pragma clang __debug directive is read. +/// \param Loc The location of the debug directive. +/// \param DebugType The identifier following __debug. +void ModularizePPCallbacks::PragmaDebug(SourceLocation Loc, StringRef DebugType) { +#if MPPC_TRACE + Trace(Loc, "PragmaDebug() called.\n"); +#endif +} + +/// \brief Callback invoked when a \#pragma message directive is read. +/// \param Loc The location of the message directive. +/// \param Namespace The namespace of the message directive. +/// \param Kind The type of the message directive. +/// \param Str The text of the message directive. +void ModularizePPCallbacks::PragmaMessage(SourceLocation Loc, StringRef Namespace, + PragmaMessageKind Kind, StringRef Str) { +#if MPPC_TRACE + Trace(Loc, "PragmaMessage() called.\n"); +#endif +} + +/// \brief Callback invoked when a \#pragma gcc dianostic push directive +/// is read. +void ModularizePPCallbacks::PragmaDiagnosticPush(SourceLocation Loc, + StringRef Namespace) { +#if MPPC_TRACE + Trace(Loc, "PragmaDiagnosticPush() called.\n"); +#endif +} + +/// \brief Callback invoked when a \#pragma gcc dianostic pop directive +/// is read. +void ModularizePPCallbacks::PragmaDiagnosticPop(SourceLocation Loc, + StringRef Namespace) { +#if MPPC_TRACE + Trace(Loc, "PragmaDiagnosticPop() called.\n"); +#endif +} + +/// \brief Callback invoked when a \#pragma gcc dianostic directive is read. +void ModularizePPCallbacks::PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Mapping mapping, StringRef Str) { +#if MPPC_TRACE + Trace(Loc, "PragmaDiagnostic() called.\n"); +#endif +} + +/// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a +/// macro invocation is found. +void ModularizePPCallbacks::MacroExpands(const Token &MacroNameTok, const MacroDirective *MD, + SourceRange Range, const MacroArgs *Args) { + std::string macroName = MacroNameTok.getIdentifierInfo()->getName().str(); + std::string value; + const MacroInfo *MI = PP.getMacroInfo(MacroNameTok.getIdentifierInfo()); + MacroInfo::tokens_iterator I = MI->tokens_begin(); + MacroInfo::tokens_iterator E = MI->tokens_end(); + for (; I != E; ++I) + value += PP.getSpelling((*I)); + AddSymbol(macroName, value); +#if MPPC_TRACE + Trace(MacroNameTok, "MacroExpands(%s) called: ", macroName.c_str()); + for (I = MI->tokens_begin(); I != E; ++I) { + Trace(" '%s'", PP.getSpelling((*I)).c_str()); + } + Trace("\n"); +#endif +} + +/// \brief Hook called whenever a macro definition is seen. +void ModularizePPCallbacks::MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { +#if MPPC_TRACE + std::string macroName = + MacroNameTok.getIdentifierInfo()->getName().str(); + Trace(MacroNameTok, "MacroDefined(%s) called: ", macroName.c_str()); + const MacroInfo *MI = PP.getMacroInfo(MacroNameTok.getIdentifierInfo()); + MacroInfo::tokens_iterator I = MI->tokens_begin(); + MacroInfo::tokens_iterator E = MI->tokens_end(); + for (; I != E; ++I) { + Trace(" '%s'", PP.getSpelling((*I)).c_str()); + } + Trace("\n"); +#endif +} + +/// \brief Hook called whenever a macro \#undef is seen. +/// +/// MD is released immediately following this callback. +void ModularizePPCallbacks::MacroUndefined(const Token &MacroNameTok, + const MacroDirective *MD) { +#if MPPC_TRACE + std::string macroName = + MacroNameTok.getIdentifierInfo()->getName().str(); + Trace(MacroNameTok, "MacroUndefined(%s) called.\n", macroName.c_str()); +#endif +} + +/// \brief Hook called whenever the 'defined' operator is seen. +/// \param MD The MacroDirective if the name was a macro, null otherwise. +void ModularizePPCallbacks::Defined(const Token &MacroNameTok, const MacroDirective *MD) { +#if MPPC_TRACE + std::string macroName = + MacroNameTok.getIdentifierInfo()->getName().str(); + Trace(MacroNameTok, "Defined(%s) called.\n", macroName.c_str()); +#endif +} + +/// \brief Hook called when a source range is skipped. +/// \param Range The SourceRange that was skipped. The range begins at the +/// \#if/\#else directive and ends after the \#endif/\#else directive. +void ModularizePPCallbacks::SourceRangeSkipped(SourceRange Range) { +#if MPPC_TRACE + Trace(Range.getBegin(), "SourceRangeSkipped() called.\n"); +#endif +} + +/// \brief Hook called whenever an \#if is seen. +/// \param Loc the source location of the directive. +/// \param ConditionRange The SourceRange of the expression being tested. +/// +// FIXME: better to pass in a list (or tree!) of Tokens. +void ModularizePPCallbacks::If(SourceLocation Loc, SourceRange ConditionRange) { + std::string unconvertedConditional(SourceSnippet(ConditionRange)); + std::string convertedConditional(DoMacroSubstitutions(unconvertedConditional)); + unsigned lineNumber = SourceLocationLineNumber(Loc); + if (CurrentHeaderFile->GetLastLineNumber() < lineNumber) { + ModularizePPDirective directive( + MPPD_If, lineNumber, + unconvertedConditional, convertedConditional); + CurrentHeaderFile->AddDirective(directive); + } +#if MPPC_TRACE + Trace(Loc, "If(%s (%s)) called.\n", + unconvertedConditional.c_str(), convertedConditional.c_str()); + Trace("CurrentHeaderFile.Name = %s\n", CurrentHeaderFile->GetName().c_str()); +#endif +} + +/// \brief Hook called whenever an \#elif is seen. +/// \param Loc the source location of the directive. +/// \param ConditionRange The SourceRange of the expression being tested. +/// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. +// FIXME: better to pass in a list (or tree!) of Tokens. +void ModularizePPCallbacks::Elif(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) { + std::string unconvertedConditional(SourceSnippet(ConditionRange)); + std::string convertedConditional(DoMacroSubstitutions(unconvertedConditional)); + unsigned lineNumber = SourceLocationLineNumber(Loc); + if (CurrentHeaderFile->GetLastLineNumber() < lineNumber) { + ModularizePPDirective directive( + MPPD_ElIf, SourceLocationLineNumber(Loc), + unconvertedConditional, convertedConditional); + CurrentHeaderFile->AddDirective(directive); + } +#if MPPC_TRACE + Trace(Loc, "Elif(%s (%s)) called.\n", + unconvertedConditional.c_str(), convertedConditional.c_str()); + Trace("CurrentHeaderFile.Name = %s\n", CurrentHeaderFile->GetName().c_str()); +#endif +} + +/// \brief Hook called whenever an \#ifdef is seen. +/// \param Loc the source location of the directive. +/// \param MacroNameTok Information on the token being tested. +/// \param MD The MacroDirective if the name was a macro, null otherwise. +void ModularizePPCallbacks::Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDirective *MD) { + std::string macroName = MacroNameTok.getIdentifierInfo()->getName().str(); + std::string unconvertedConditional(macroName); + std::string convertedConditional( + macroName + (MD ? " (defined)" : " (not defined)")); + unsigned lineNumber = SourceLocationLineNumber(Loc); + if (CurrentHeaderFile->GetLastLineNumber() < lineNumber) { + ModularizePPDirective directive( + MPPD_IfDef, SourceLocationLineNumber(Loc), + unconvertedConditional, convertedConditional); + CurrentHeaderFile->AddDirective(directive); + } +#if MPPC_TRACE + Trace(Loc, "Ifdef(%s, %s) called.\n", + macroName.c_str(), (MD ? " (defined)" : " (not defined)")); + Trace("CurrentHeaderFile.Name = %s\n", CurrentHeaderFile->GetName().c_str()); +#endif +} + +/// \brief Hook called whenever an \#ifndef is seen. +/// \param Loc the source location of the directive. +/// \param MacroNameTok Information on the token being tested. +/// \param MD The MacroDirective if the name was a macro, null otherwise. +void ModularizePPCallbacks::Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDirective *MD) { + std::string macroName = MacroNameTok.getIdentifierInfo()->getName().str(); + std::string unconvertedConditional(macroName); + std::string convertedConditional( + macroName + (MD ? " (defined)" : " (not defined)")); + unsigned lineNumber = SourceLocationLineNumber(Loc); + if (CurrentHeaderFile->GetLastLineNumber() < lineNumber) { + ModularizePPDirective directive( + MPPD_IfNDef, SourceLocationLineNumber(Loc), + unconvertedConditional, convertedConditional); + CurrentHeaderFile->AddDirective(directive); + } +#if MPPC_TRACE + Trace(Loc, "Ifndef(%s, %s) called.\n", + macroName.c_str(), (MD ? " (defined)" : " (not defined)")); + Trace("CurrentHeaderFile.Name = %s\n", CurrentHeaderFile->GetName().c_str()); +#endif +} + +/// \brief Hook called whenever an \#else is seen. +/// \param Loc the source location of the directive. +/// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. +void ModularizePPCallbacks::Else(SourceLocation Loc, SourceLocation IfLoc) { +#if MPPC_TRACE + Trace(Loc, "Else() called.\n"); +#endif +} + +/// \brief Hook called whenever an \#endif is seen. +/// \param Loc the source location of the directive. +/// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. +void ModularizePPCallbacks::Endif(SourceLocation Loc, SourceLocation IfLoc) { +#if MPPC_TRACE + Trace(Loc, "Endif() called.\n"); +#endif +} + +// Some utility functions. + +std::string ModularizePPCallbacks::SourceLocationStr(SourceLocation Loc) { + if (Loc.isInvalid()) + return std::string("(none)"); + else + return Loc.printToString(PP.getSourceManager()); +} + +std::string ModularizePPCallbacks::SourceLocationFile(SourceLocation Loc) { + std::string source(SourceLocationStr(Loc)); + int offset = source.find(':', 2); + if (offset < 0) + return source; + return source.substr(0, offset); +} + +unsigned ModularizePPCallbacks::SourceLocationLineNumber(SourceLocation Loc) { + return PP.getSourceManager().getPresumedLineNumber(Loc); +} + +std::string ModularizePPCallbacks::FileName(FileID fileID) { + return SourceLocationFile(PP.getSourceManager().getLocForStartOfFile(fileID)); +} + +ModularizeHeaderFile *ModularizePPCallbacks::GetHeaderFile(const std::string& name) { + ModularizeHeaderFileMap::iterator iter = HeaderFileMap.find(name); + if (iter != HeaderFileMap.end()) + return iter->second; + return NULL; +} + +void ModularizePPCallbacks::AddHeaderFile(ModularizeHeaderFile *headerFile) { + HeaderFileMap[headerFile->GetName()] = headerFile; +} + +const char *ModularizePPCallbacks::FileChangeReasonStr(FileChangeReason reason) { + switch (reason) { + case EnterFile: + return "EnterFile"; + case ExitFile: + return "ExitFile"; + case SystemHeaderPragma: + return "SystemHeaderPragma"; + case RenameFile: + return "RenameFile"; + default: + return "(unknown)"; + } +} + +const char *ModularizePPCallbacks::CharacteristicKindStr(SrcMgr::CharacteristicKind fileType) { + using namespace SrcMgr; + switch (fileType) { + case C_User: + return "C_User"; + case C_System: + return "C_System"; + case C_ExternCSystem: + return "C_ExternCSystem"; + default: + return "(unknown)"; + } +} + +// Retrieve source snippet from file image. +std::string ModularizePPCallbacks::SourceSnippet(SourceRange sourceRange) { + SourceLocation bLoc(sourceRange.getBegin()); + SourceLocation eLoc(sourceRange.getEnd()); + + // Decompose the locations into FID/Offset pairs. + std::pair bLocInfo = PP.getSourceManager().getDecomposedLoc(bLoc); + std::pair eLocInfo = PP.getSourceManager().getDecomposedLoc(eLoc); + FileID FID = bLocInfo.first; + unsigned bFileOffset = bLocInfo.second; + unsigned eFileOffset = eLocInfo.second; + unsigned length = eFileOffset - bFileOffset; + + // Get information about the buffer it points into. + bool Invalid = false; + const char *BufStart = PP.getSourceManager().getBufferData(FID, &Invalid).data(); + if (Invalid) + return std::string(); + + // Rewind from the current position to the start of the line. + const char *bPtr = BufStart + bFileOffset; + + // Trim snippet. + while ((*bPtr <= ' ') && (length != 0)) { + bPtr++; + length--; + } + + while ((length != 0) && (bPtr[length - 1] <= ' ')) + length--; + + std::string returnValue(bPtr, length); + + return returnValue; +} + +// Do macro substitutions in a string. +// FIXME: Note that this is very simple parser, such that it doesn't +// support things like function-style macros, macros with string +// or character literals, and defined(). +// FIXME: There probably should be a function in the Preprocessor +// class that will lex a string, do substitutions, and return either +// a token list or a converted string. +std::string ModularizePPCallbacks::DoMacroSubstitutions(std::string str) { + enum LexMode { + LM_Top, + LM_Symbol + } lexMode = LM_Top; + char output[1024]; + size_t outputLength = 0; + char token[256]; + size_t tokenLength = 0; + std::string symbolValue; + size_t symbolLength; + size_t length = str.length(); + size_t index; + char c = '\0'; + for (index = 0; index <= length; index++) { + if (index < length) + c = str[index]; + else + c = '\0'; +restart: + switch (lexMode) { + case LM_Top: + tokenLength = 0; + if (isalpha(c) || (c == '_')) { + lexMode = LM_Symbol; + goto restart; + } + else { + if (outputLength < sizeof(output) + 1) + output[outputLength++] = c; + } + break; + case LM_Symbol: + if (isalpha(c) || (c == '_') || isdigit(c)) { + if (tokenLength < sizeof(token) - 1) + token[tokenLength++] = c; + } + else { + token[tokenLength] = '\0'; + if (GetSymbol(token, symbolValue)) { + // Recursively do substitutions on macro value. + symbolValue = DoMacroSubstitutions(symbolValue); + symbolLength = symbolValue.length(); + if (outputLength + symbolLength < sizeof(output) - 1) { + strcpy(output + outputLength, symbolValue.c_str()); + outputLength += symbolLength; + } + else { + strncpy(output + outputLength, symbolValue.c_str(), sizeof(output) - outputLength - 1); + outputLength = sizeof(output) - 1; + output[sizeof(output) - 1] = '\0'; + } + } + else { + if (outputLength + tokenLength < sizeof(output) - 1) { + strcpy(output + outputLength, token); + outputLength += tokenLength; + } + else { + strncpy(output + outputLength, token, sizeof(output) - outputLength - 1); + outputLength = sizeof(output) - 1; + output[sizeof(output) - 1] = '\0'; + } + } + lexMode = LM_Top; + goto restart; + } + break; + } + } + output[outputLength] = '\0'; + return std::string(output); +} + +// Add a symbol definition. If the symbol already exists, +// its value is replaced. +void ModularizePPCallbacks::AddSymbol(std::string name, std::string value) { + Symbols[name] = value; +} + +// Get symbol value. Return empty string if not defined. +std::string ModularizePPCallbacks::GetSymbol(std::string name) { + ModularizeSymbolMapIterator iter = Symbols.find(name); + if (iter != Symbols.end()) + return (*iter).second; + return std::string(); +} + +// Get symbol value. Return true if found. +bool ModularizePPCallbacks::GetSymbol(std::string name, std::string &value) { + ModularizeSymbolMapIterator iter = Symbols.find(name); + if (iter != Symbols.end()) { + value = (*iter).second; + return true; + } + return false; +} + +void ModularizePPCallbacks::Trace(const char *format, ...) { + char buffer[1024]; + va_list args; + va_start(args, format); + vsnprintf(buffer, sizeof(buffer) - 1, format, args); + errs() << buffer; + va_end(args); +} + +void ModularizePPCallbacks::Trace( + SourceLocation Loc, const char *format, ...) { + char buffer[1024]; + va_list args; + va_start(args, format); + errs() << SourceLocationStr(Loc) << ": "; + vsnprintf(buffer, sizeof(buffer) - 1, format, args); + errs() << buffer; + va_end(args); +} + +/// \brief Outputs a trace string with a location from a token. +void ModularizePPCallbacks::Trace(const Token &Token, const char *format, ...) { + char buffer[1024]; + va_list args; + va_start(args, format); + errs() << SourceLocationStr(Token.getLocation()) << ": "; + vsnprintf(buffer, sizeof(buffer) - 1, format, args); + errs() << buffer; + va_end(args); +} + +} + Index: modularize/ModularizeMasterHeaderTracker.cpp =================================================================== --- modularize/ModularizeMasterHeaderTracker.cpp (revision 0) +++ modularize/ModularizeMasterHeaderTracker.cpp (revision 0) @@ -0,0 +1,79 @@ +//==- ModularizeMasterHeaderTracker.cpp - Stores header trackers -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModularizeMasterHeaderTracker.h" +#include "ModularizeUtilities.h" +#include "llvm/Support/raw_ostream.h" +#include "clang/Basic/SourceManager.h" + +namespace Modularize { +using namespace llvm; +using namespace clang; + +ModularizeMasterHeaderTracker::ModularizeMasterHeaderTracker(bool disabled) + : Disabled(disabled) { +} + +ModularizeMasterHeaderTracker::~ModularizeMasterHeaderTracker() { +} + +// Find an existing header tracker. +// Returns NULL if not found.. +ModularizeHeaderTracker *ModularizeMasterHeaderTracker::GetHeaderTracker( + std::string headerName) { + ModularizeHeaderTrackerMap::iterator iter = HeaderTrackers.find(headerName); + if (iter != HeaderTrackers.end()) + return iter->second; + return NULL; +} + +// Process a header snapshot. +// If the header has be seen before, and the snapshot differs, add a new +// header instance. +void ModularizeMasterHeaderTracker::AddHeaderFile( + ModularizeHeaderFile *headerFile, std::string topHeader) { + ModularizeHeaderTracker *headerTracker = GetHeaderTracker( + headerFile->GetName()); + if (headerTracker != NULL) + headerTracker->AddHeaderFile(headerFile, topHeader); + else { + headerTracker = new ModularizeHeaderTracker( + headerFile->GetName(), headerFile, topHeader); + HeaderTrackers[headerTracker->GetName()] = headerTracker; + } +} + +// Report instances where header snapshots differ. +// Returns true if no errors, i.e. no differing snapshots. +bool ModularizeMasterHeaderTracker::Report() { + if (Disabled) + return true; + bool returnValue = true; + ModularizeHeaderTrackerMapIterator iter = HeaderTrackers.begin(); + ModularizeHeaderTrackerMapIterator end = HeaderTrackers.end(); + for (; iter != end; ++iter) { + ModularizeHeaderTracker *headerTracker = (*iter).second; + if (!headerTracker->Report()) + returnValue = false; + } + return returnValue; +} + +// Display the information for debugging. +void ModularizeMasterHeaderTracker::Dump(int level) { + errs() << Indent(level) << "The headers:\n"; + ModularizeHeaderTrackerMapIterator iter = HeaderTrackers.begin(); + ModularizeHeaderTrackerMapIterator end = HeaderTrackers.end(); + for (; iter != end; ++iter) { + ModularizeHeaderTracker *headerTracker = (*iter).second; + headerTracker->Dump(level + 1); + } +} + +} Index: modularize/ModularizeHeaderInstance.h =================================================================== --- modularize/ModularizeHeaderInstance.h (revision 0) +++ modularize/ModularizeHeaderInstance.h (revision 0) @@ -0,0 +1,63 @@ +//===- ModularizeHeaderInstance.h - Stores header instance info-*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines a class to store information about a set of instances of a +/// header being used where the conditional directives are equivalent. +/// +//===----------------------------------------------------------------------===// + +#ifndef MODULARIZEHEADERINSTANCE_H +#define MODULARIZEHEADERINSTANCE_H + +#include "ModularizeHeaderFile.h" + +namespace Modularize { + using namespace clang; + using namespace llvm; + +typedef std::vector ModularizeTopHeaderVector; +typedef ModularizeTopHeaderVector::iterator ModularizeTopHeaderVectorIterator; + +/// \brief This class stores information about a set of instances of a +/// header being used where the conditional directives are equivalent. +class ModularizeHeaderInstance { +public: + ModularizeHeaderInstance(ModularizeHeaderFile *HeaderFile, std::string topHeader); + ~ModularizeHeaderInstance(); + + // Header file accessors. + ModularizeHeaderFile *GetHeaderFile() { return HeaderFile; } + void SetHeaderFile(ModularizeHeaderFile *headerFile) { HeaderFile = headerFile; }; + + // Top headers (the files directly passed to modularize) accessors. + ModularizeTopHeaderVector &GetTopHeaders() { return TopHeaders; } + ModularizeTopHeaderVectorIterator GetTopHeadersBegin() { return TopHeaders.begin(); } + ModularizeTopHeaderVectorIterator GetTopHeadersEnd() { return TopHeaders.end(); } + bool HasTopHeader(std::string topHeader); + void AddTopHeader(std::string topHeader) { TopHeaders.push_back(topHeader); }; + + // Display the information for debugging. + void Dump(int level = 0); +private: + // This points to the object containing a unique snapshot of the + // representations of the header preprocessor directives. + ModularizeHeaderFile *HeaderFile; + // This vector contains the names of the top-level headers that + // contained the above unique snapshot. + ModularizeTopHeaderVector TopHeaders; +}; + +// Collections for users of this typs. +typedef std::vector ModularizeHeaderInstanceVector; +typedef ModularizeHeaderInstanceVector::iterator ModularizeHeaderInstanceVectorIterator; + +} // end namespace clang + +#endif Index: modularize/ModularizePPDirective.h =================================================================== --- modularize/ModularizePPDirective.h (revision 0) +++ modularize/ModularizePPDirective.h (revision 0) @@ -0,0 +1,82 @@ +//===--- ModularizePPDirective.h - Represents a PP directive ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines a class to store information about one preprocessor directive +/// that modularize might be interested in. +/// +//===----------------------------------------------------------------------===// + +#ifndef MODULARIZEPPDIRECTIVE_H +#define MODULARIZEPPDIRECTIVE_H + +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/SourceLocation.h" +#include + +namespace Modularize { + using namespace clang; + using namespace llvm; + +// Represents a preprocessor directive kind. +enum ModularizePPDirectiveKind { + MPPD_If, + MPPD_ElIf, + MPPD_IfDef, + MPPD_IfNDef +}; + +/// \brief This class stores information about one preprocessor directive +/// that modularize might be interested in. +class ModularizePPDirective { +public: + ModularizePPDirective( + ModularizePPDirectiveKind directiveKind, unsigned lineNumber, + std::string unconvertedConditional, std::string convertedConditional); + ~ModularizePPDirective(); + + // Source location string accessors. + unsigned GetLineNumber() { return LineNumber; } + void SetLineNumber(unsigned value) { LineNumber = value; }; + + // Unconverted conditional accessors. + std::string& GetUnconvertedConditional() { return UnconvertedConditional; } + void SetUnconvertedConditional(std::string value) { UnconvertedConditional = value; }; + + // Converted conditional accessors. + std::string& GetConvertedConditional() { return ConvertedConditional; } + void SetConvertedConditional(std::string value) { ConvertedConditional = value; }; + + // Return true if this directive matches another. + // (It compares the converted conditionals.) + bool Match(ModularizePPDirective *other); + + // Print this directive to a string suitable for a message. + std::string PrintToString(int level, std::string fileName); + + // Display the information for debugging. + void Dump(int level = 0, const char *fileName = NULL); +private: + // The kind of directive. + ModularizePPDirectiveKind DirectiveKind; + // Presumed line number for direcive. + unsigned LineNumber; + // Raw value representation of conditional. + std::string UnconvertedConditional; + // The conditional with macro substitutions done. + std::string ConvertedConditional; +}; + +// Collections for users of this typs. +typedef std::vector ModularizePPDirectiveVector; +typedef ModularizePPDirectiveVector::iterator ModularizePPDirectiveVectorIterator; + +} // end namespace clang + +#endif Index: modularize/ModularizePPCallbacks.h =================================================================== --- modularize/ModularizePPCallbacks.h (revision 0) +++ modularize/ModularizePPCallbacks.h (revision 0) @@ -0,0 +1,282 @@ +//===--- ModularizePPCallbacks.h - Callbacks for Modularize PP -*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Implements the PPCallbacks interface for modularize. +/// +//===----------------------------------------------------------------------===// + +#ifndef MODULARIZEPPCALLBACKS_H +#define MODULARIZEPPCALLBACKS_H + +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/SourceLocation.h" +#include "ModularizeHeaderFile.h" +#include "ModularizeMasterHeaderTracker.h" + +namespace Modularize { + using namespace clang; + using namespace llvm; + +typedef StringMap ModularizeSymbolMap; +typedef ModularizeSymbolMap::iterator ModularizeSymbolMapIterator; + +// FIXME: This class doesn't need to override all the handlers. + +/// \brief This class provides callback implementations to grab information +/// about preprocessor directives encountered. +class ModularizePPCallbacks : public PPCallbacks { +public: + ModularizePPCallbacks(Preprocessor &pp, StringRef topFile, + ModularizeMasterHeaderTracker &masterHeaderTracker); + ~ModularizePPCallbacks(); + + /// \brief Callback invoked whenever a source file is entered or exited. + /// + /// \param Loc Indicates the new location. + /// \param PrevFID the file that was exited if \p Reason is ExitFile. + void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID = FileID()); + + /// \brief Callback invoked whenever a source file is skipped as the result + /// of header guard optimization. + /// + /// \param ParentFile The file that \#included the skipped file. + /// + /// \param FilenameTok The token in ParentFile that indicates the + /// skipped file. + void FileSkipped(const FileEntry &ParentFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType); + + /// \brief Callback invoked whenever an inclusion directive results in a + /// file-not-found error. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param RecoveryPath If this client indicates that it can recover from + /// this missing file, the client should set this as an additional header + /// search patch. + /// + /// \returns true to indicate that the preprocessor should attempt to recover + /// by adding \p RecoveryPath as a header search path. + bool FileNotFound(StringRef FileName, + SmallVectorImpl &RecoveryPath); + + /// \brief Callback invoked whenever an inclusion directive of + /// any kind (\c \#include, \c \#import, etc.) has been processed, regardless + /// of whether the inclusion will actually result in an inclusion. + /// + /// \param HashLoc The location of the '#' that starts the inclusion + /// directive. + /// + /// \param IncludeTok The token that indicates the kind of inclusion + /// directive, e.g., 'include' or 'import'. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param IsAngled Whether the file name was enclosed in angle brackets; + /// otherwise, it was enclosed in quotes. + /// + /// \param FilenameRange The character range of the quotes or angle brackets + /// for the written file name. + /// + /// \param File The actual file that may be included by this inclusion + /// directive. + /// + /// \param SearchPath Contains the search path which was used to find the file + /// in the file system. If the file was found via an absolute include path, + /// SearchPath will be empty. For framework includes, the SearchPath and + /// RelativePath will be split up. For example, if an include of "Some/Some.h" + /// is found via the framework path + /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be + /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be + /// "Some.h". + /// + /// \param RelativePath The path relative to SearchPath, at which the include + /// file was found. This is equal to FileName except for framework includes. + /// + /// \param Imported The module, whenever an inclusion directive was + /// automatically turned into a module import or null otherwise. + /// + void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported); + + /// \brief Callback invoked whenever there was an explicit module-import + /// syntax. + /// + /// \param ImportLoc The location of import directive token. + /// + /// \param Path The identifiers (and their locations) of the module + /// "path", e.g., "std.vector" would be split into "std" and "vector". + /// + /// \param Imported The imported module; can be null if importing failed. + /// + void moduleImport(SourceLocation ImportLoc, + ModuleIdPath Path, + const Module *Imported); + + /// \brief Callback invoked when the end of the main file is reached. + /// + /// No subsequent callbacks will be made. + void EndOfMainFile(); + + /// \brief Callback invoked when a \#ident or \#sccs directive is read. + /// \param Loc The location of the directive. + /// \param str The text of the directive. + /// + void Ident(SourceLocation Loc, const std::string &str); + + /// \brief Callback invoked when a \#pragma comment directive is read. + void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + const std::string &Str); + + /// \brief Callback invoked when a \#pragma clang __debug directive is read. + /// \param Loc The location of the debug directive. + /// \param DebugType The identifier following __debug. + void PragmaDebug(SourceLocation Loc, StringRef DebugType); + + /// \brief Callback invoked when a \#pragma message directive is read. + /// \param Loc The location of the message directive. + /// \param Namespace The namespace of the message directive. + /// \param Kind The type of the message directive. + /// \param Str The text of the message directive. + void PragmaMessage(SourceLocation Loc, StringRef Namespace, + PragmaMessageKind Kind, StringRef Str); + + /// \brief Callback invoked when a \#pragma gcc dianostic push directive + /// is read. + void PragmaDiagnosticPush(SourceLocation Loc, + StringRef Namespace); + + /// \brief Callback invoked when a \#pragma gcc dianostic pop directive + /// is read. + void PragmaDiagnosticPop(SourceLocation Loc, + StringRef Namespace); + + /// \brief Callback invoked when a \#pragma gcc dianostic directive is read. + void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Mapping mapping, StringRef Str); + + /// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a + /// macro invocation is found. + void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD, + SourceRange Range, const MacroArgs *Args); + + /// \brief Hook called whenever a macro definition is seen. + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD); + + /// \brief Hook called whenever a macro \#undef is seen. + /// + /// MD is released immediately following this callback. + void MacroUndefined(const Token &MacroNameTok, + const MacroDirective *MD); + + /// \brief Hook called whenever the 'defined' operator is seen. + /// \param MD The MacroDirective if the name was a macro, null otherwise. + void Defined(const Token &MacroNameTok, const MacroDirective *MD); + + /// \brief Hook called when a source range is skipped. + /// \param Range The SourceRange that was skipped. The range begins at the + /// \#if/\#else directive and ends after the \#endif/\#else directive. + void SourceRangeSkipped(SourceRange Range); + + /// \brief Hook called whenever an \#if is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// + // FIXME: better to pass in a list (or tree!) of Tokens. + void If(SourceLocation Loc, SourceRange ConditionRange); + + /// \brief Hook called whenever an \#elif is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + // FIXME: better to pass in a list (or tree!) of Tokens. + void Elif(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc); + + /// \brief Hook called whenever an \#ifdef is seen. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDirective if the name was a macro, null otherwise. + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDirective *MD); + + /// \brief Hook called whenever an \#ifndef is seen. + /// \param Loc the source location of the directive. + /// \param MacroNameTok Information on the token being tested. + /// \param MD The MacroDirective if the name was a macro, null otherwise. + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDirective *MD); + + /// \brief Hook called whenever an \#else is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + void Else(SourceLocation Loc, SourceLocation IfLoc); + + /// \brief Hook called whenever an \#endif is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive. + void Endif(SourceLocation Loc, SourceLocation IfLoc); +private: + ModularizeMasterHeaderTracker &MasterHeaderTracker; + std::string TopFile; + Preprocessor &PP; + ModularizeHeaderFile *RootHeaderFile; + ModularizeHeaderFile *CurrentHeaderFile; + ModularizeHeaderFileMap HeaderFileMap; + ModularizeSymbolMap Symbols; + + /// \brief Lookup header. + ModularizeHeaderFile *GetHeaderFile(const std::string& name); + void AddHeaderFile(ModularizeHeaderFile *headerFile); + std::string SourceLocationStr(SourceLocation Loc); + std::string SourceLocationFile(SourceLocation Loc); + unsigned SourceLocationLineNumber(SourceLocation Loc); + std::string FileName(FileID fileID); + const char *FileChangeReasonStr(FileChangeReason reason); + const char *CharacteristicKindStr(SrcMgr::CharacteristicKind fileType); + // Retrieve source snippet from file image. + std::string SourceSnippet(SourceRange sourceRange); + // Do macro substitutions in a string. + std::string DoMacroSubstitutions(std::string str); + + // Get symbol map. + ModularizeSymbolMap &GetSymbols() { return Symbols; } + // Add a symbol definition. If the symbol already exists, + // its value is replaced. + void AddSymbol(std::string name, std::string value); + // Get symbol value. Return empty string if not defined. + std::string GetSymbol(std::string name); + // Get symbol value. Return true if found. + bool GetSymbol(std::string name, std::string &value); + + /// \brief Outputs a trace string. + void Trace(const char *format, ...); + /// \brief Outputs a trace string with a location. + void Trace(SourceLocation Loc, const char *format, ...); + /// \brief Outputs a trace string with a location from a token. + void Trace(const Token &Token, const char *format, ...); +}; + +} // end namespace clang + +#endif Index: modularize/ModularizeMasterHeaderTracker.h =================================================================== --- modularize/ModularizeMasterHeaderTracker.h (revision 0) +++ modularize/ModularizeMasterHeaderTracker.h (revision 0) @@ -0,0 +1,60 @@ +//===- ModularizeMasterHeaderTracker.h - Stores header trackers -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines a class to store all the header trackers, for use in finding +/// header instance differences. +/// +//===----------------------------------------------------------------------===// + +#ifndef MODULARIZEMASTERHEADERTRACKER_H +#define MODULARIZEMASTERHEADERTRACKER_H + +#include "ModularizeHeaderFile.h" +#include "ModularizeHeaderTracker.h" + +namespace Modularize { + using namespace clang; + using namespace llvm; + +/// \brief This class stores all the header trackers, for use in finding +/// header instance differences. +class ModularizeMasterHeaderTracker { +public: + ModularizeMasterHeaderTracker(bool disabled); + ~ModularizeMasterHeaderTracker(); + + // Return true if header preprocessing checking is disabled. + bool IsDisabled() { return Disabled; } + + // Return the map of all the header trackers. + ModularizeHeaderTrackerMap& GetHeaderTrackers() { return HeaderTrackers; } + // Find an existing header tracker. + // Returns NULL if not found.. + ModularizeHeaderTracker *GetHeaderTracker(std::string headerName); + // Process a header snapshot. + // If the header has be seen before, and the snapshot differs, add a new + // header instance. + void AddHeaderFile(ModularizeHeaderFile *headerFile, std::string topHeader); + + // Report instances where header snapshots differ. + // Returns true if no errors, i.e. no differing snapshots. + bool Report(); + // Display the information for debugging. + void Dump(int level = 0); +private: + // Set to true if header preprocessing checking is disabled. + bool Disabled; + // This map contains an entry for each header file encountered. + ModularizeHeaderTrackerMap HeaderTrackers; +}; + +} // end namespace clang + +#endif Index: modularize/ModularizeHeaderFile.cpp =================================================================== --- modularize/ModularizeHeaderFile.cpp (revision 0) +++ modularize/ModularizeHeaderFile.cpp (revision 0) @@ -0,0 +1,63 @@ +//===--- ModularizeHeaderFile.cpp - Callbacks for Preprocessor actions ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ModularizeHeaderFile.h" +#include "ModularizeUtilities.h" +#include "llvm/Support/raw_ostream.h" +#include "clang/Basic/SourceManager.h" + +namespace Modularize { +using namespace llvm; +using namespace clang; + +ModularizeHeaderFile::ModularizeHeaderFile(std::string name, Preprocessor& pp) : + Name(name) { +} + +ModularizeHeaderFile::~ModularizeHeaderFile() { +} + +// Get highest line-numbered directive. +unsigned ModularizeHeaderFile::GetLastLineNumber() { + if (Directives.size() == 0) + return 0; + return Directives[Directives.size() - 1].GetLineNumber(); +} + +// Return true if this snapshot matches the other snapshot. +bool ModularizeHeaderFile::Match(ModularizeHeaderFile *other) { + bool returnValue = true; + // Walk conditional directives. If the condition + // (after macro substitutions) is not the same, + // return false, meaning the header file snapshot doesn't match. + ModularizePPDirectiveVectorIterator thisIter = GetDirectivesBegin(); + ModularizePPDirectiveVectorIterator thisEnd = GetDirectivesEnd(); + ModularizePPDirectiveVectorIterator otherIter = other->GetDirectivesBegin(); + ModularizePPDirectiveVectorIterator otherEnd = other->GetDirectivesEnd(); + for (; (thisIter != thisEnd) && (otherIter != otherEnd); + ++thisIter, ++ otherIter) { + if (!(*thisIter).Match(&(*otherIter))) { + returnValue = false; + break; + } + } + return returnValue; +} + +// Display the information for debugging. +void ModularizeHeaderFile::Dump(int level) { + errs() << Indent(level) << "preprocessor directives:\n"; + ModularizePPDirectiveVectorIterator dIter = GetDirectivesBegin(); + ModularizePPDirectiveVectorIterator dEnd = GetDirectivesEnd(); + for (; dIter != dEnd; ++dIter) { + (*dIter).Dump(level + 1, Name.c_str()); + } +} + +} Index: modularize/ModularizeHeaderFile.h =================================================================== --- modularize/ModularizeHeaderFile.h (revision 0) +++ modularize/ModularizeHeaderFile.h (revision 0) @@ -0,0 +1,75 @@ +//===--- ModularizeHeaderFile.h - Stores PP directives ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Defines a class to store information about preprocessor directives +/// encountered in a header file which might be relevant to finding modules-related +/// problems. +/// +//===----------------------------------------------------------------------===// + +#ifndef MODULARIZEHEADERFILE_H +#define MODULARIZEHEADERFILE_H + +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringMap.h" +#include "ModularizePPDirective.h" +#include + +namespace Modularize { + using namespace clang; + using namespace llvm; + +/// \brief This class stores information about preprocessor directives +/// encountered in a header file which might be relevant to finding +/// modules-related problems. +class ModularizeHeaderFile { +public: + ModularizeHeaderFile(std::string name, Preprocessor &pp); + ~ModularizeHeaderFile(); + + // Name accessors. + std::string& GetName() { return Name; } + void SetName(std::string name) { Name = name; }; + + // Preprocessor directive accessors. + ModularizePPDirectiveVector &GetDirectives() { return Directives; } + int GetDirectiveCount() { return Directives.size(); } + ModularizePPDirectiveVectorIterator GetDirectivesBegin() + { return Directives.begin(); } + ModularizePPDirectiveVectorIterator GetDirectivesEnd() + { return Directives.end(); } + ModularizePPDirective &GetDirective(int index) { return Directives[index]; } + void AddDirective(ModularizePPDirective &directive) + { Directives.push_back(directive); }; + + // Get highest line-numbered directive. + unsigned GetLastLineNumber(); + + // Return true if this snapshot matches the other snapshot. + bool Match(ModularizeHeaderFile *other); + + // Display the information for debugging. + void Dump(int level = 0); +private: + // The full path name of the header file. + std::string Name; + // The array of preprocessor directives in the file, limited + // to the kinds modularize is interested in. + ModularizePPDirectiveVector Directives; +}; + +// Collections for users of this typs. +typedef StringMap ModularizeHeaderFileMap; +typedef ModularizeHeaderFileMap::iterator ModularizeHeaderFileMapIterator; + +} // end namespace clang + +#endif Index: modularize/CMakeLists.txt =================================================================== --- modularize/CMakeLists.txt (revision 183718) +++ modularize/CMakeLists.txt (working copy) @@ -7,6 +7,13 @@ add_clang_executable(modularize Modularize.cpp + ModularizeHeaderFile.cpp + ModularizeHeaderInstance.cpp + ModularizeHeaderTracker.cpp + ModularizeMasterHeaderTracker.cpp + ModularizePPCallbacks.cpp + ModularizePPDirective.cpp + ModularizeUtilities.cpp ) target_link_libraries(modularize