diff --git a/clang/Driver/RewriteTest.cpp b/clang/Driver/RewriteTest.cpp index 103610248ad0..5b27f55190f6 100644 --- a/clang/Driver/RewriteTest.cpp +++ b/clang/Driver/RewriteTest.cpp @@ -21,17 +21,22 @@ using namespace clang; namespace { class RewriteTest : public ASTConsumer { + Rewriter Rewrite; SourceManager *SM; unsigned MainFileID; + SourceLocation LastIncLoc; public: void Initialize(ASTContext &Context, unsigned mainFileID) { SM = &Context.SourceMgr; MainFileID = mainFileID; + Rewrite.setSourceMgr(Context.SourceMgr); } virtual void HandleTopLevelDecl(Decl *D); - + void HandleDeclInMainFile(Decl *D); + void RewriteInclude(SourceLocation Loc); + ~RewriteTest(); }; } @@ -39,19 +44,53 @@ namespace { ASTConsumer *clang::CreateCodeRewriterTest() { return new RewriteTest(); } void RewriteTest::HandleTopLevelDecl(Decl *D) { - // Nothing to do here yet. -#if 0 - if (NamedDecl *ND = dyn_cast(D)) - if (ND->getName()) - printf("%s\n", ND->getName()); -#endif + // Two cases: either the decl could be in the main file, or it could be in a + // #included file. If the former, rewrite it now. If the later, check to see + // if we rewrote the #include/#import. + SourceLocation Loc = D->getLocation(); + Loc = SM->getLogicalLoc(Loc); + + // If this is for a builtin, ignore it. + if (Loc.isInvalid()) return; + + if (SM->getDecomposedFileLoc(Loc).first == MainFileID) + return HandleDeclInMainFile(D); + + RewriteInclude(Loc); +} + +void RewriteTest::RewriteInclude(SourceLocation Loc) { + // Rip up the #include stack to the main file. + SourceLocation IncLoc = Loc, NextLoc = Loc; + do { + IncLoc = Loc; + Loc = SM->getLogicalLoc(NextLoc); + NextLoc = SM->getIncludeLoc(Loc); + } while (!NextLoc.isInvalid()); + + // Loc is now the location of the #include filename "foo" or . + // IncLoc indicates the header that was included if it is useful. + IncLoc = SM->getLogicalLoc(IncLoc); + if (SM->getDecomposedFileLoc(Loc).first != MainFileID || + Loc == LastIncLoc) + return; + LastIncLoc = Loc; + + unsigned IncCol = SM->getColumnNumber(Loc); + SourceLocation LineStartLoc = Loc.getFileLocWithOffset(-IncCol+1); + + // Replace the #import with #include. + Rewrite.ReplaceText(LineStartLoc, IncCol-1, "#include ", strlen("#include ")); +} + +/// HandleDeclInMainFile - This is called for each top-level decl defined in the +/// main file of the input. +void RewriteTest::HandleDeclInMainFile(Decl *D) { + // Nothing yet. } - RewriteTest::~RewriteTest() { - Rewriter Rewrite(*SM); - // Get the top-level buffer that this corresponds to. std::pair MainBuf = SM->getBufferData(MainFileID); const char *MainBufStart = MainBuf.first; diff --git a/clang/Rewrite/Rewriter.cpp b/clang/Rewrite/Rewriter.cpp index 5f935c328113..3c618de585b3 100644 --- a/clang/Rewrite/Rewriter.cpp +++ b/clang/Rewrite/Rewriter.cpp @@ -143,7 +143,7 @@ void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, unsigned Rewriter::getLocationOffsetAndFileID(SourceLocation Loc, unsigned &FileID) const { - std::pair V = SourceMgr.getDecomposedFileLoc(Loc); + std::pair V = SourceMgr->getDecomposedFileLoc(Loc); FileID = V.first; return V.second; } @@ -158,7 +158,7 @@ RewriteBuffer &Rewriter::getEditBuffer(unsigned FileID) { return I->second; I = RewriteBuffers.insert(I, std::make_pair(FileID, RewriteBuffer())); - std::pair MB = SourceMgr.getBufferData(FileID); + std::pair MB = SourceMgr->getBufferData(FileID); I->second.Initialize(MB.first, MB.second); return I->second; diff --git a/clang/clang.xcodeproj/project.pbxproj b/clang/clang.xcodeproj/project.pbxproj index 75d938806b00..33627a1f29da 100644 --- a/clang/clang.xcodeproj/project.pbxproj +++ b/clang/clang.xcodeproj/project.pbxproj @@ -238,7 +238,7 @@ 84AF36A00CB17A3B00C820A5 /* DeclObjC.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DeclObjC.h; path = clang/AST/DeclObjC.h; sourceTree = ""; }; 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = ""; }; 84D9A88B0C1A581300AC7ABC /* AttributeList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = AttributeList.h; path = clang/Parse/AttributeList.h; sourceTree = ""; }; - 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; }; + 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = clang; sourceTree = BUILT_PRODUCTS_DIR; }; DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = ""; }; DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = Parse/ParseExprCXX.cpp; sourceTree = ""; }; DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = ""; }; diff --git a/clang/include/clang/Basic/SourceLocation.h b/clang/include/clang/Basic/SourceLocation.h index 420d5012f0c7..1ebb0ff3f859 100644 --- a/clang/include/clang/Basic/SourceLocation.h +++ b/clang/include/clang/Basic/SourceLocation.h @@ -30,7 +30,9 @@ public: MacroIDBits = 20, MacroPhysOffsBits = 9, - MacroLogOffBits = 2 + MacroLogOffBits = 2, + + ChunkSize = (1 << FilePosBits) }; SourceLocation() : ID(0) {} // 0 is an invalid FileID. @@ -42,9 +44,9 @@ public: SourceLocation L; // If a FilePos is larger than (1<= (1 << FilePosBits)) { + if (FilePos >= ChunkSize) { FileID += FilePos >> FilePosBits; - FilePos &= (1 << FilePosBits)-1; + FilePos &= ChunkSize-1; } // FIXME: Find a way to handle out of FileID bits! Maybe MaxFileID is an @@ -98,7 +100,7 @@ public: /// SourceManager::getFilePos. This method will be incorrect for large files. unsigned getRawFilePos() const { assert(isFileID() && "can't get the file id of a non-file sloc!"); - return ID & ((1 << FilePosBits)-1); + return ID & (ChunkSize-1); } unsigned getMacroID() const { @@ -122,7 +124,14 @@ public: /// getFileLocWithOffset - Return a source location with the specified offset /// from this file SourceLocation. SourceLocation getFileLocWithOffset(int Offset) const { - return getFileLoc(getFileID(), getRawFilePos()+Offset); + unsigned FileID = getFileID(); + Offset += getRawFilePos(); + // Handle negative offsets correctly. + while (Offset < 0) { + --FileID; + Offset += ChunkSize; + } + return getFileLoc(FileID, Offset); } /// getRawEncoding - When a SourceLocation itself cannot be used, this returns diff --git a/clang/include/clang/Rewrite/Rewriter.h b/clang/include/clang/Rewrite/Rewriter.h index 24c7f1c8f3db..6e8c2084c64f 100644 --- a/clang/include/clang/Rewrite/Rewriter.h +++ b/clang/include/clang/Rewrite/Rewriter.h @@ -107,11 +107,14 @@ private: // Methods only usable by Rewriter. /// job is to dispatch high-level requests to the low-level RewriteBuffers that /// are involved. class Rewriter { - SourceManager &SourceMgr; + SourceManager *SourceMgr; std::map RewriteBuffers; public: - explicit Rewriter(SourceManager &SM) : SourceMgr(SM) {} + explicit Rewriter(SourceManager &SM) : SourceMgr(&SM) {} + explicit Rewriter() : SourceMgr(0) {} + + void setSourceMgr(SourceManager &SM) { SourceMgr = &SM; } /// isRewritable - Return true if this location is a raw file location, which /// is rewritable. Locations from macros, etc are not rewritable.