diff --git a/clang-tools-extra/clangd/unittests/tweaks/AddUsingTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/AddUsingTests.cpp --- a/clang-tools-extra/clangd/unittests/tweaks/AddUsingTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/AddUsingTests.cpp @@ -102,7 +102,7 @@ #include "test.hpp" namespace { void fun() { - ^o^n^e^:^:^t^w^o^:^:^f^f(); + ^one::two::ff(); } })cpp", R"cpp( @@ -120,7 +120,7 @@ #include "test.hpp" namespace { void fun() { - ::on^e::t^wo::c^c inst; + ::one::t^wo::cc inst; } })cpp", R"cpp( @@ -138,7 +138,7 @@ #include "test.hpp" void fun() { - on^e::t^wo::e^e inst; + one::two::e^e inst; })cpp", R"cpp( #include "test.hpp" @@ -185,7 +185,7 @@ using one::two::ff; void fun() { - o^ne::o^o(); + o^ne::oo(); } })cpp", R"cpp( @@ -469,8 +469,7 @@ )cpp"}}; llvm::StringMap EditedFiles; for (const auto &Case : Cases) { - for (const auto &SubCase : expandCases(Case.TestSource)) { - ExtraFiles["test.hpp"] = R"cpp( + ExtraFiles["test.hpp"] = R"cpp( namespace one { void oo() {} namespace two { @@ -485,8 +484,7 @@ using uu = two::cc; template struct vec {}; })cpp"; - EXPECT_EQ(apply(SubCase, &EditedFiles), Case.ExpectedSource); - } + EXPECT_EQ(apply(Case.TestSource, &EditedFiles), Case.ExpectedSource); } } diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.h b/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.h --- a/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.h +++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.h @@ -9,9 +9,11 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_TWEAKS_TWEAKTESTING_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_TWEAKS_TWEAKTESTING_H +#include "ParsedAST.h" #include "index/Index.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Testing/Support/Annotations.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include @@ -89,14 +91,13 @@ std::string apply(llvm::StringRef MarkedCode, llvm::StringMap *EditedFiles = nullptr) const; - // Accepts a code snippet with many ranges (or points) marked, and returns a - // list of snippets with one range marked each. - // Primarily used from EXPECT_AVAILABLE/EXPECT_UNAVAILABLE macro. - static std::vector expandCases(llvm::StringRef MarkedCode); - - // Returns a matcher that accepts marked code snippets where the tweak is - // available at the marked range. - ::testing::Matcher isAvailable() const; + // Helpers for EXPECT_AVAILABLE/EXPECT_UNAVAILABLE macros. + using WrappedAST = std::pair; + WrappedAST build(llvm::StringRef) const; + bool isAvailable(WrappedAST &, llvm::Annotations::Range) const; + // Return code re-decorated with a single point/range. + static std::string decorate(llvm::StringRef, unsigned); + static std::string decorate(llvm::StringRef, llvm::Annotations::Range); }; MATCHER_P2(FileWithContents, FileName, Contents, "") { @@ -109,18 +110,18 @@ TweakID##Test() : TweakTest(#TweakID) {} \ } -#define EXPECT_AVAILABLE(MarkedCode) \ - do { \ - for (const auto &Case : expandCases(MarkedCode)) \ - EXPECT_THAT(Case, ::clang::clangd::TweakTest::isAvailable()); \ - } while (0) - -#define EXPECT_UNAVAILABLE(MarkedCode) \ +#define EXPECT_AVAILABLE_(MarkedCode, Available) \ do { \ - for (const auto &Case : expandCases(MarkedCode)) \ - EXPECT_THAT(Case, \ - ::testing::Not(::clang::clangd::TweakTest::isAvailable())); \ + llvm::Annotations A{llvm::StringRef(MarkedCode)}; \ + auto AST = build(A.code()); \ + assert(!A.points().empty() || !A.ranges().empty()); \ + for (const auto &P : A.points()) \ + EXPECT_EQ(Available, isAvailable(AST, {P, P})) << decorate(A.code(), P); \ + for (const auto &R : A.ranges()) \ + EXPECT_EQ(Available, isAvailable(AST, R)) << decorate(A.code(), R); \ } while (0) +#define EXPECT_AVAILABLE(MarkedCode) EXPECT_AVAILABLE_(MarkedCode, true) +#define EXPECT_UNAVAILABLE(MarkedCode) EXPECT_AVAILABLE_(MarkedCode, false) } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp --- a/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTesting.cpp @@ -8,7 +8,6 @@ #include "TweakTesting.h" -#include "Annotations.h" #include "SourceCode.h" #include "TestTU.h" #include "refactor/Tweak.h" @@ -50,31 +49,25 @@ return Outer; } -std::pair rangeOrPoint(const Annotations &A) { - Range SelectionRng; +llvm::Annotations::Range rangeOrPoint(const llvm::Annotations &A) { if (A.points().size() != 0) { assert(A.ranges().size() == 0 && "both a cursor point and a selection range were specified"); - SelectionRng = Range{A.point(), A.point()}; - } else { - SelectionRng = A.range(); + return {A.point(), A.point()}; } - return {cantFail(positionToOffset(A.code(), SelectionRng.start)), - cantFail(positionToOffset(A.code(), SelectionRng.end))}; + return A.range(); } // Prepare and apply the specified tweak based on the selection in Input. // Returns None if and only if prepare() failed. llvm::Optional> -applyTweak(ParsedAST &AST, const Annotations &Input, StringRef TweakID, +applyTweak(ParsedAST &AST, llvm::Annotations::Range Range, StringRef TweakID, const SymbolIndex *Index, llvm::vfs::FileSystem *FS) { - auto Range = rangeOrPoint(Input); llvm::Optional> Result; - SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Range.first, - Range.second, [&](SelectionTree ST) { - Tweak::Selection S(Index, AST, Range.first, - Range.second, std::move(ST), - FS); + SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Range.Begin, + Range.End, [&](SelectionTree ST) { + Tweak::Selection S(Index, AST, Range.Begin, + Range.End, std::move(ST), FS); if (auto T = prepareTweak(TweakID, S, nullptr)) { Result = (*T)->apply(S); return true; @@ -86,33 +79,12 @@ return Result; } -MATCHER_P7(TweakIsAvailable, TweakID, Ctx, Header, ExtraArgs, ExtraFiles, Index, - FileName, - (TweakID + (negation ? " is unavailable" : " is available")).str()) { - std::string WrappedCode = wrap(Ctx, arg); - Annotations Input(WrappedCode); - TestTU TU; - TU.Filename = std::string(FileName); - TU.HeaderCode = Header; - TU.Code = std::string(Input.code()); - TU.ExtraArgs = ExtraArgs; - TU.AdditionalFiles = std::move(ExtraFiles); - ParsedAST AST = TU.build(); - auto Result = applyTweak( - AST, Input, TweakID, Index, - &AST.getSourceManager().getFileManager().getVirtualFileSystem()); - // We only care if prepare() succeeded, but must handle Errors. - if (Result && !*Result) - consumeError(Result->takeError()); - return Result.hasValue(); -} - } // namespace std::string TweakTest::apply(llvm::StringRef MarkedCode, llvm::StringMap *EditedFiles) const { std::string WrappedCode = wrap(Context, MarkedCode); - Annotations Input(WrappedCode); + llvm::Annotations Input(WrappedCode); TestTU TU; TU.Filename = std::string(FileName); TU.HeaderCode = Header; @@ -122,7 +94,7 @@ ParsedAST AST = TU.build(); auto Result = applyTweak( - AST, Input, TweakID, Index.get(), + AST, rangeOrPoint(Input), TweakID, Index.get(), &AST.getSourceManager().getFileManager().getVirtualFileSystem()); if (!Result) return "unavailable"; @@ -153,28 +125,39 @@ return EditedMainFile; } -::testing::Matcher TweakTest::isAvailable() const { - return TweakIsAvailable(llvm::StringRef(TweakID), Context, Header, ExtraArgs, - ExtraFiles, Index.get(), FileName); +bool TweakTest::isAvailable(WrappedAST &AST, + llvm::Annotations::Range Range) const { + // Adjust range for wrapping offset. + Range.Begin += AST.second; + Range.End += AST.second; + auto Result = applyTweak( + AST.first, Range, TweakID, Index.get(), + &AST.first.getSourceManager().getFileManager().getVirtualFileSystem()); + // We only care if prepare() succeeded, but must handle Errors. + if (Result && !*Result) + consumeError(Result->takeError()); + return Result.hasValue(); } -std::vector TweakTest::expandCases(llvm::StringRef MarkedCode) { - Annotations Test(MarkedCode); - llvm::StringRef Code = Test.code(); - std::vector Cases; - for (const auto &Point : Test.points()) { - size_t Offset = llvm::cantFail(positionToOffset(Code, Point)); - Cases.push_back((Code.substr(0, Offset) + "^" + Code.substr(Offset)).str()); - } - for (const auto &Range : Test.ranges()) { - size_t Begin = llvm::cantFail(positionToOffset(Code, Range.start)); - size_t End = llvm::cantFail(positionToOffset(Code, Range.end)); - Cases.push_back((Code.substr(0, Begin) + "[[" + - Code.substr(Begin, End - Begin) + "]]" + Code.substr(End)) - .str()); - } - assert(!Cases.empty() && "No markings in MarkedCode?"); - return Cases; +TweakTest::WrappedAST TweakTest::build(llvm::StringRef Code) const { + TestTU TU; + TU.Filename = std::string(FileName); + TU.HeaderCode = Header; + TU.Code = wrap(Context, Code); + TU.ExtraArgs = ExtraArgs; + TU.AdditionalFiles = std::move(ExtraFiles); + return {TU.build(), wrapping(Context).first.size()}; +} + +std::string TweakTest::decorate(llvm::StringRef Code, unsigned Point) { + return (Code.substr(0, Point) + "^" + Code.substr(Point)).str(); +} + +std::string TweakTest::decorate(llvm::StringRef Code, + llvm::Annotations::Range Range) { + return (Code.substr(0, Range.Begin) + "[[" + + Code.substr(Range.Begin, Range.End) + "]]" + Code.substr(Range.End)) + .str(); } } // namespace clangd