Index: include/clang/Basic/SourceLocation.h =================================================================== --- include/clang/Basic/SourceLocation.h +++ include/clang/Basic/SourceLocation.h @@ -220,6 +220,10 @@ bool operator!=(const SourceRange &X) const { return B != X.B || E != X.E; } + + void print(raw_ostream &OS, const SourceManager &SM) const; + std::string printToString(const SourceManager &SM) const; + void dump(const SourceManager &SM) const; }; /// Represents a character-granular source range. Index: lib/Basic/SourceLocation.cpp =================================================================== --- lib/Basic/SourceLocation.cpp +++ lib/Basic/SourceLocation.cpp @@ -80,6 +80,60 @@ llvm::errs() << '\n'; } +LLVM_DUMP_METHOD void SourceRange::dump(const SourceManager &SM) const { + print(llvm::errs(), SM); + llvm::errs() << '\n'; +} + +static PresumedLoc printDifference(raw_ostream &OS, const SourceManager &SM, SourceLocation Loc, PresumedLoc Previous) +{ + if (Loc.isFileID()) { + + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + if (PLoc.isInvalid()) { + OS << ""; + return Previous; + } + + if (Previous.isInvalid() || strcmp(PLoc.getFilename(), Previous.getFilename()) != 0) { + OS << PLoc.getFilename() << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); + } else if (Previous.isInvalid() || PLoc.getLine() != Previous.getLine()) { + OS << "line" << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); + } else { + OS << "col" << ':' << PLoc.getColumn(); + } + return PLoc; + } + auto printedLoc = printDifference(OS, SM, SM.getExpansionLoc(Loc), Previous); + + OS << " '; + return printedLoc; +} + +void SourceRange::print(raw_ostream &OS, const SourceManager &SM) const { + + OS << '<'; + auto printedLoc = printDifference(OS, SM, B, {}); + if (B != E) { + OS << ", "; + printDifference(OS, SM, E, printedLoc); + } + OS << '>'; +} + +LLVM_DUMP_METHOD std::string +SourceRange::printToString(const SourceManager &SM) const { + std::string S; + llvm::raw_string_ostream OS(S); + print(OS, SM); + return OS.str(); +} + //===----------------------------------------------------------------------===// // FullSourceLoc //===----------------------------------------------------------------------===// Index: unittests/Basic/SourceManagerTest.cpp =================================================================== --- unittests/Basic/SourceManagerTest.cpp +++ unittests/Basic/SourceManagerTest.cpp @@ -155,6 +155,52 @@ EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, nullptr)); } +TEST_F(SourceManagerTest, locationPrintTest) { + const char *header = + "#define IDENTITY(x) x\n"; + + const char *Source = + "int x;\n" + "include \"test-header.h\"\n" + "IDENTITY(int y);\n" + "int z;"; + + std::unique_ptr HeaderBuf = + llvm::MemoryBuffer::getMemBuffer(header); + std::unique_ptr Buf = + llvm::MemoryBuffer::getMemBuffer(Source); + + const FileEntry *sourceFile = FileMgr.getVirtualFile("/mainFile.cpp", + Buf->getBufferSize(), 0); + SourceMgr.overrideFileContents(sourceFile, std::move(Buf)); + + const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", + HeaderBuf->getBufferSize(), 0); + SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); + + FileID MainFileID = SourceMgr.getOrCreateFileID(sourceFile, SrcMgr::C_User); + SourceMgr.setMainFileID(MainFileID); + + auto beginLoc = SourceMgr.getLocForStartOfFile(MainFileID); + auto endLoc = SourceMgr.getLocForEndOfFile(MainFileID); + + auto beginEOLLoc = SourceMgr.translateLineCol(MainFileID, 1, 7); + + // TODO: How do I get a loc in another file? + auto headerLoc = SourceMgr.getSpellingLoc(SourceMgr.translateLineCol(MainFileID, 3, 5)); + + EXPECT_EQ(beginLoc.printToString(SourceMgr), "/mainFile.cpp:1:1"); + EXPECT_EQ(endLoc.printToString(SourceMgr), "/mainFile.cpp:4:7"); + + EXPECT_EQ(beginEOLLoc.printToString(SourceMgr), "/mainFile.cpp:1:7"); + EXPECT_EQ(headerLoc.printToString(SourceMgr), "TODO"); + + EXPECT_EQ(SourceRange(beginLoc, beginLoc).printToString(SourceMgr), ""); + EXPECT_EQ(SourceRange(beginLoc, beginEOLLoc).printToString(SourceMgr), ""); + EXPECT_EQ(SourceRange(beginLoc, endLoc).printToString(SourceMgr), ""); + EXPECT_EQ(SourceRange(beginLoc, headerLoc).printToString(SourceMgr), ""); +} + #if defined(LLVM_ON_UNIX) TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {