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() << getIndent(1) << "When included or nested in these top-level headers:\n"; + ModularizeTopHeaderVectorIterator thIter = headerInstance->getTopHeadersBegin(); + ModularizeTopHeaderVectorIterator thEnd = headerInstance->getTopHeadersEnd(); + for (; thIter != thEnd; ++thIter) { + errs() << getIndent(2) << *thIter << "\n"; + } + errs() << getIndent(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() << getIndent(level) << Name << ":\n"; + errs() << getIndent(level + 1) << "instance count: " + << getHeaderInstanceCount() << "\n"; + + errs() << getIndent(level + 1) << "instances: \n"; + ModularizeHeaderInstanceVectorIterator hiIter = getHeaderInstancesBegin(); + ModularizeHeaderInstanceVectorIterator hiEnd = getHeaderInstancesEnd(); + int hiIndex; + for (hiIndex = 0; hiIter != hiEnd; ++hiIter, ++hiIndex) { + ModularizeHeaderInstance *headerInstance = (*hiIter); + errs() << getIndent(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,67 @@ +//===- 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; +}; + +// Collections for users of this typs. +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() << getIndent(level) << "top headers:\n"; + + ModularizeTopHeaderVectorIterator thIter = getTopHeadersBegin(); + ModularizeTopHeaderVectorIterator thEnd = getTopHeadersEnd(); + for (; thIter != thEnd; ++thIter) { + errs() << getIndent(level + 1) << *thIter << "\n"; + } + + errs() << getIndent(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,89 @@ +//===--- 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" + +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 stream, suitable for a message. +void ModularizePPDirective::print(raw_ostream &OS, + int level, std::string fileName) { + const char *directiveSpelling = getDirectiveSpelling(DirectiveKind); + OS << getIndent(level) << fileName << ":" << LineNumber << ":1: #" + << directiveSpelling << " " << UnconvertedConditional << " (#" << + directiveSpelling << " " << ConvertedConditional << ")\n"; +} + +// Print this directive to a string, suitable for a message. +std::string ModularizePPDirective::printToString( + int level, std::string fileName) { + std::string S; + llvm::raw_string_ostream OS(S); + print(OS, level, fileName); + return OS.str(); +} + +// Display useful information about this object for debugging. +void ModularizePPDirective::dump(int level, const char *fileName) { + if (fileName == NULL) + fileName = "line"; + print(errs(), level, fileName); +} + +// Get directive spelling. +const char *ModularizePPDirective::getDirectiveSpelling( + ModularizePPDirectiveKind kind) { + const char *directiveString; + switch (kind) { + 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; + } + return directiveString; +} + +} Index: modularize/ModularizePPCallbacks.cpp =================================================================== --- modularize/ModularizePPCallbacks.cpp (revision 0) +++ modularize/ModularizePPCallbacks.cpp (revision 0) @@ -0,0 +1,328 @@ +//===--- 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; + +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() { +} + +void ModularizePPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { + std::string locgetFileName(getSourceLocationFile(Loc)); + ModularizeHeaderFile *mhf = NULL; + std::string *fileName = NULL; + switch (Reason) { + case EnterFile: + fileName = &locgetFileName; + break; + case ExitFile: + if (PrevFID.isInvalid()) + fileName = &TopFile; + else + fileName = &locgetFileName; + 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; +} + +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); + } +} + +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); +} + +void ModularizePPCallbacks::If(SourceLocation Loc, SourceRange ConditionRange) { + std::string unconvertedConditional(getSourceSnippet(ConditionRange)); + std::string convertedConditional(getMacroSubstitutedString(unconvertedConditional)); + unsigned lineNumber = getSourceLocationLineNumber(Loc); + if (CurrentHeaderFile->getLastLineNumber() < lineNumber) { + ModularizePPDirective directive( + MPPD_If, lineNumber, + unconvertedConditional, convertedConditional); + CurrentHeaderFile->addDirective(directive); + } +} + +void ModularizePPCallbacks::Elif(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) { + std::string unconvertedConditional(getSourceSnippet(ConditionRange)); + std::string convertedConditional(getMacroSubstitutedString(unconvertedConditional)); + unsigned lineNumber = getSourceLocationLineNumber(Loc); + if (CurrentHeaderFile->getLastLineNumber() < lineNumber) { + ModularizePPDirective directive( + MPPD_ElIf, getSourceLocationLineNumber(Loc), + unconvertedConditional, convertedConditional); + CurrentHeaderFile->addDirective(directive); + } +} + +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 = getSourceLocationLineNumber(Loc); + if (CurrentHeaderFile->getLastLineNumber() < lineNumber) { + ModularizePPDirective directive( + MPPD_IfDef, getSourceLocationLineNumber(Loc), + unconvertedConditional, convertedConditional); + CurrentHeaderFile->addDirective(directive); + } +} + +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 = getSourceLocationLineNumber(Loc); + if (CurrentHeaderFile->getLastLineNumber() < lineNumber) { + ModularizePPDirective directive( + MPPD_IfNDef, getSourceLocationLineNumber(Loc), + unconvertedConditional, convertedConditional); + CurrentHeaderFile->addDirective(directive); + } +} + +// Some utility functions. + +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; +} + +// 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; +} + +std::string ModularizePPCallbacks::getSourceLocationString(SourceLocation Loc) { + if (Loc.isInvalid()) + return std::string("(none)"); + else + return Loc.printToString(PP.getSourceManager()); +} + +std::string ModularizePPCallbacks::getSourceLocationFile(SourceLocation Loc) { + std::string source(getSourceLocationString(Loc)); + int offset = source.find(':', 2); + if (offset < 0) + return source; + return source.substr(0, offset); +} + +unsigned ModularizePPCallbacks::getSourceLocationLineNumber(SourceLocation Loc) { + return PP.getSourceManager().getPresumedLineNumber(Loc); +} + +// Retrieve source snippet from file image. +std::string ModularizePPCallbacks::getSourceSnippet(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. However, it's somewhat +// problematic in that it could interfere with the preprocessor +// and lexor state, and call the MacroExpanded handlers again. +// So for now, we stick with this simple function, to be extend +// to support function-style macros. +std::string ModularizePPCallbacks::getMacroSubstitutedString(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 = getMacroSubstitutedString(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); +} + +} 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() << getIndent(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,88 @@ +//===--- 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 stream. + void print(raw_ostream &OS, int level, std::string fileName); + + // 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); + + // Get directive spelling. + static const char *getDirectiveSpelling(ModularizePPDirectiveKind kind); +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,90 @@ +//===--- 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; + +/// \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(); + + // Overidden handlers. + void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID = FileID()); + void EndOfMainFile(); + void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD, + SourceRange Range, const MacroArgs *Args); + void If(SourceLocation Loc, SourceRange ConditionRange); + void Elif(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc); + void Ifdef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDirective *MD); + void Ifndef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDirective *MD); +private: + // Local accessors. + ModularizeHeaderFile *getHeaderFile(const std::string& name); + void addHeaderFile(ModularizeHeaderFile *headerFile); + + // 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); + + // Local utilities. + std::string getSourceLocationString(SourceLocation Loc); + std::string getSourceLocationFile(SourceLocation Loc); + unsigned getSourceLocationLineNumber(SourceLocation Loc); + // Retrieve source snippet from file image. + std::string getSourceSnippet(SourceRange sourceRange); + // Do macro substitutions in a string. + std::string getMacroSubstitutedString(std::string str); + +private: + // Local data. + ModularizeMasterHeaderTracker &MasterHeaderTracker; + std::string TopFile; + Preprocessor &PP; + ModularizeHeaderFile *RootHeaderFile; + ModularizeHeaderFile *CurrentHeaderFile; + ModularizeHeaderFileMap HeaderFileMap; + ModularizeSymbolMap Symbols; + +}; + +} // 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() << getIndent(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