diff options
-rw-r--r-- | include/clang/Lex/Lexer.h | 6 | ||||
-rw-r--r-- | lib/Lex/Lexer.cpp | 42 | ||||
-rw-r--r-- | unittests/Lex/LexerTest.cpp | 5 |
3 files changed, 53 insertions, 0 deletions
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h index eb8ad347d6..a935718e6f 100644 --- a/include/clang/Lex/Lexer.h +++ b/include/clang/Lex/Lexer.h @@ -339,6 +339,12 @@ public: const SourceManager &SM, const LangOptions &LangOpts); + /// \brief Returns a string for the source that the range encompasses. + static StringRef getSourceText(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts, + bool *Invalid = 0); + /// \brief Retrieve the name of the immediate macro expansion. /// /// This routine starts from a source location, and finds the name of the macro diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 1a469bef48..12cb76722b 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -813,6 +813,9 @@ CharSourceRange Lexer::makeFileCharRange(SourceRange TokenRange, // Break down the source locations. std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(Begin); + if (beginInfo.first.isInvalid()) + return CharSourceRange(); + unsigned EndOffs; if (!SM.isInFileID(End, beginInfo.first, &EndOffs) || beginInfo.second > EndOffs) @@ -821,6 +824,45 @@ CharSourceRange Lexer::makeFileCharRange(SourceRange TokenRange, return CharSourceRange::getCharRange(Begin, End); } +StringRef Lexer::getSourceText(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts, + bool *Invalid) { + if (Range.isTokenRange()) + Range = makeFileCharRange(Range.getAsRange(), SM, LangOpts); + + if (Range.isInvalid() || + Range.getBegin().isMacroID() || Range.getEnd().isMacroID()) { + if (Invalid) *Invalid = true; + return StringRef(); + } + + // Break down the source location. + std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(Range.getBegin()); + if (beginInfo.first.isInvalid()) { + if (Invalid) *Invalid = true; + return StringRef(); + } + + unsigned EndOffs; + if (!SM.isInFileID(Range.getEnd(), beginInfo.first, &EndOffs) || + beginInfo.second > EndOffs) { + if (Invalid) *Invalid = true; + return StringRef(); + } + + // Try to the load the file buffer. + bool invalidTemp = false; + StringRef file = SM.getBufferData(beginInfo.first, &invalidTemp); + if (invalidTemp) { + if (Invalid) *Invalid = true; + return StringRef(); + } + + if (Invalid) *Invalid = false; + return file.substr(beginInfo.second, EndOffs - beginInfo.second); +} + StringRef Lexer::getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts) { diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp index 05478eef9f..fecdb7fc05 100644 --- a/unittests/Lex/LexerTest.cpp +++ b/unittests/Lex/LexerTest.cpp @@ -114,6 +114,11 @@ TEST_F(LexerTest, LexAPI) { EXPECT_EQ(range.getAsRange(), SourceRange(macroRange.getBegin(), macroRange.getEnd().getLocWithOffset(1))); + + StringRef text = Lexer::getSourceText( + CharSourceRange::getTokenRange(SourceRange(lsqrLoc, rsqrLoc)), + SourceMgr, LangOpts); + EXPECT_EQ(text, "M(foo)"); } } // anonymous namespace |