[Rewrite] Extend to further accept CharSourceRange

Some Rewrite functions are already overloaded to accept
CharSourceRange, and this extends others in the same manner.  I'm
calling these in code that's not ready to upstream, but I figure they
might be useful to others in the meantime.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D61467

llvm-svn: 365258
This commit is contained in:
Joel E. Denny 2019-07-06 02:55:06 +00:00
parent a2ca358291
commit adeb5ac2d6
4 changed files with 105 additions and 4 deletions

View File

@ -84,7 +84,16 @@ public:
/// in different buffers, this returns an empty string.
///
/// Note that this method is not particularly efficient.
std::string getRewrittenText(SourceRange Range) const;
std::string getRewrittenText(CharSourceRange Range) const;
/// getRewrittenText - Return the rewritten form of the text in the specified
/// range. If the start or end of the range was unrewritable or if they are
/// in different buffers, this returns an empty string.
///
/// Note that this method is not particularly efficient.
std::string getRewrittenText(SourceRange Range) const {
return getRewrittenText(CharSourceRange::getTokenRange(Range));
}
/// InsertText - Insert the specified string at the specified location in the
/// original buffer. This method returns true (and does nothing) if the input
@ -138,6 +147,13 @@ public:
bool ReplaceText(SourceLocation Start, unsigned OrigLength,
StringRef NewStr);
/// ReplaceText - This method replaces a range of characters in the input
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.
bool ReplaceText(CharSourceRange range, StringRef NewStr) {
return ReplaceText(range.getBegin(), getRangeSize(range), NewStr);
}
/// ReplaceText - This method replaces a range of characters in the input
/// buffer with a new string. This is effectively a combined "remove/insert"
/// operation.

View File

@ -170,7 +170,7 @@ int Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const {
/// in different buffers, this returns an empty string.
///
/// Note that this method is not particularly efficient.
std::string Rewriter::getRewrittenText(SourceRange Range) const {
std::string Rewriter::getRewrittenText(CharSourceRange Range) const {
if (!isRewritable(Range.getBegin()) ||
!isRewritable(Range.getEnd()))
return {};
@ -193,7 +193,9 @@ std::string Rewriter::getRewrittenText(SourceRange Range) const {
// Adjust the end offset to the end of the last token, instead of being the
// start of the last token.
EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
if (Range.isTokenRange())
EndOff +=
Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
return std::string(Ptr, Ptr+EndOff-StartOff);
}
@ -203,7 +205,8 @@ std::string Rewriter::getRewrittenText(SourceRange Range) const {
// Adjust the end offset to the end of the last token, instead of being the
// start of the last token.
EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
if (Range.isTokenRange())
EndOff += Lexer::MeasureTokenLength(Range.getEnd(), *SourceMgr, *LangOpts);
// Advance the iterators to the right spot, yay for linear time algorithms.
RewriteBuffer::iterator Start = RB.begin();

View File

@ -4,8 +4,10 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(RewriteTests
RewriteBufferTest.cpp
RewriterTest.cpp
)
clang_target_link_libraries(RewriteTests
PRIVATE
clangRewrite
clangTooling
)

View File

@ -0,0 +1,80 @@
//===- unittests/Rewrite/RewriterTest.cpp - Rewriter tests ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
using namespace clang;
namespace {
struct RangeTypeTest {
std::unique_ptr<ASTUnit> AST;
Rewriter Rewrite;
SourceLocation FileStart;
CharSourceRange CRange; // covers exact char range
CharSourceRange TRange; // extends CRange to whole tokens
SourceRange SRange; // different type but behaves like TRange
SourceLocation makeLoc(int Off) { return FileStart.getLocWithOffset(Off); }
CharSourceRange makeCharRange(int StartOff, int EndOff) {
return CharSourceRange::getCharRange(makeLoc(StartOff), makeLoc(EndOff));
}
RangeTypeTest(StringRef Code, int StartOff, int EndOff) {
AST = tooling::buildASTFromCode(Code);
ASTContext &C = AST->getASTContext();
Rewrite = Rewriter(C.getSourceManager(), C.getLangOpts());
FileStart = AST->getStartOfMainFileID();
CRange = makeCharRange(StartOff, EndOff);
SRange = CRange.getAsRange();
TRange = CharSourceRange::getTokenRange(SRange);
}
};
TEST(Rewriter, GetRewrittenTextRangeTypes) {
// Check that correct text is retrieved for each range type. Check again
// after a modification. Ranges remain in terms of the original text but
// include the new text.
StringRef Code = "int main() { return 0; }";
// get char range ^~~ = "ret"
// get token range ^~~+++ = "return"
// get source range ^~~+++ = "return"
// insert "x" ^
// get char range ^~~ = "xret"
// get token range ^~~+++ = "xreturn"
// get source range ^~~+++ = "xreturn"
RangeTypeTest T(Code, 13, 16);
EXPECT_EQ(T.Rewrite.getRewrittenText(T.CRange), "ret");
EXPECT_EQ(T.Rewrite.getRewrittenText(T.TRange), "return");
EXPECT_EQ(T.Rewrite.getRewrittenText(T.SRange), "return");
T.Rewrite.InsertText(T.makeLoc(13), "x");
EXPECT_EQ(T.Rewrite.getRewrittenText(T.CRange), "xret");
EXPECT_EQ(T.Rewrite.getRewrittenText(T.TRange), "xreturn");
EXPECT_EQ(T.Rewrite.getRewrittenText(T.SRange), "xreturn");
}
TEST(Rewriter, ReplaceTextRangeTypes) {
// Check that correct text is replaced for each range type. Ranges remain in
// terms of the original text but include the new text.
StringRef Code = "int main(int argc, char *argv[]) { return argc; }";
// replace char range with "foo" ^~
// get ^~~~~ = "foogc;"
// replace token range with "bar" ^~++
// get ^~~~~ = "bar;"
// replace source range with "0" ^~++
// get ^~~~~ = "0;"
RangeTypeTest T(Code, 42, 44);
T.Rewrite.ReplaceText(T.CRange, "foo");
EXPECT_EQ(T.Rewrite.getRewrittenText(T.makeCharRange(42, 47)), "foogc;");
T.Rewrite.ReplaceText(T.TRange, "bar");
EXPECT_EQ(T.Rewrite.getRewrittenText(T.makeCharRange(42, 47)), "bar;");
T.Rewrite.ReplaceText(T.SRange, "0");
EXPECT_EQ(T.Rewrite.getRewrittenText(T.makeCharRange(42, 47)), "0;");
}
} // anonymous namespace