clang-tools 10.0.0

TweakTesting.cpp
Go to the documentation of this file.
1 //===-- TweakTesting.cpp ------------------------------------------------*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "TweakTesting.h"
10
11 #include "Annotations.h"
12 #include "SourceCode.h"
13 #include "TestFS.h"
14 #include "refactor/Tweak.h"
15 #include "clang/Tooling/Core/Replacement.h"
16 #include "llvm/Support/Error.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
19 #include <string>
20
21 namespace clang {
22 namespace clangd {
23 namespace {
24 using Context = TweakTest::CodeContext;
25
26 std::pair<llvm::StringRef, llvm::StringRef> wrapping(Context Ctx) {
27 switch (Ctx) {
28 case TweakTest::File:
29 return {"",""};
30 case TweakTest::Function:
31 return {"void wrapperFunction(){\n", "\n}"};
32 case TweakTest::Expression:
33 return {"auto expressionWrapper(){return\n", "\n;}"};
34 }
35 llvm_unreachable("Unknown TweakTest::CodeContext enum");
36 }
37
38 std::string wrap(Context Ctx, llvm::StringRef Inner) {
39 auto Wrapping = wrapping(Ctx);
40 return (Wrapping.first + Inner + Wrapping.second).str();
41 }
42
43 llvm::StringRef unwrap(Context Ctx, llvm::StringRef Outer) {
44 auto Wrapping = wrapping(Ctx);
45 // Unwrap only if the code matches the expected wrapping.
46 // Don't allow the begin/end wrapping to overlap!
47 if (Outer.startswith(Wrapping.first) && Outer.endswith(Wrapping.second) &&
48 Outer.size() >= Wrapping.first.size() + Wrapping.second.size())
49 return Outer.drop_front(Wrapping.first.size()).drop_back(Wrapping.second.size());
50 return Outer;
51 }
52
53 std::pair<unsigned, unsigned> rangeOrPoint(const Annotations &A) {
54 Range SelectionRng;
55 if (A.points().size() != 0) {
56 assert(A.ranges().size() == 0 &&
57 "both a cursor point and a selection range were specified");
58 SelectionRng = Range{A.point(), A.point()};
59 } else {
60 SelectionRng = A.range();
61 }
62 return {cantFail(positionToOffset(A.code(), SelectionRng.start)),
63 cantFail(positionToOffset(A.code(), SelectionRng.end))};
64 }
65
66 MATCHER_P7(TweakIsAvailable, TweakID, Ctx, Header, ExtraArgs, ExtraFiles, Index,
67 FileName,
68 (TweakID + (negation ? " is unavailable" : " is available")).str()) {
69 std::string WrappedCode = wrap(Ctx, arg);
70 Annotations Input(WrappedCode);
71 auto Selection = rangeOrPoint(Input);
72 TestTU TU;
73 TU.Filename = FileName;
74 TU.HeaderCode = Header;
75 TU.Code = Input.code();
76 TU.ExtraArgs = ExtraArgs;
77 TU.AdditionalFiles = std::move(ExtraFiles);
78 ParsedAST AST = TU.build();
79 Tweak::Selection S(Index, AST, Selection.first, Selection.second);
80 auto PrepareResult = prepareTweak(TweakID, S);
81 if (PrepareResult)
82 return true;
83 llvm::consumeError(PrepareResult.takeError());
84 return false;
85 }
86
87 } // namespace
88
89 std::string TweakTest::apply(llvm::StringRef MarkedCode,
90 llvm::StringMap<std::string> *EditedFiles) const {
91 std::string WrappedCode = wrap(Context, MarkedCode);
92 Annotations Input(WrappedCode);
93 auto Selection = rangeOrPoint(Input);
94
95 TestTU TU;
96 TU.Filename = FileName;
97 TU.HeaderCode = Header;
98 TU.AdditionalFiles = std::move(ExtraFiles);
99 TU.Code = Input.code();
100 TU.ExtraArgs = ExtraArgs;
101 ParsedAST AST = TU.build();
102 Tweak::Selection S(Index.get(), AST, Selection.first, Selection.second);
103
104 auto T = prepareTweak(TweakID, S);
105 if (!T) {
106 llvm::consumeError(T.takeError());
107 return "unavailable";
108 }
109 llvm::Expected<Tweak::Effect> Result = (*T)->apply(S);
110 if (!Result)
111 return "fail: " + llvm::toString(Result.takeError());
112 if (Result->ShowMessage)
113 return "message:\n" + *Result->ShowMessage;
114 if (Result->ApplyEdits.empty())
115 return "no effect";
116
117 std::string EditedMainFile;
118 for (auto &It : Result->ApplyEdits) {
119 auto NewText = It.second.apply();
120 if (!NewText)
121 return "bad edits: " + llvm::toString(NewText.takeError());
122 llvm::StringRef Unwrapped = unwrap(Context, *NewText);
123 if (It.first() == testPath(TU.Filename))
124 EditedMainFile = Unwrapped;
125 else {
126 if (!EditedFiles)
127 ADD_FAILURE() << "There were changes to additional files, but client "
128 "provided a nullptr for EditedFiles.";
129 else
130 EditedFiles->insert_or_assign(It.first(), Unwrapped.str());
131 }
132 }
133 return EditedMainFile;
134 }
135
136 ::testing::Matcher<llvm::StringRef> TweakTest::isAvailable() const {
137 return TweakIsAvailable(llvm::StringRef(TweakID), Context, Header, ExtraArgs,
138 ExtraFiles, Index.get(), FileName);
139 }
140
141 std::vector<std::string> TweakTest::expandCases(llvm::StringRef MarkedCode) {
142 Annotations Test(MarkedCode);
143 llvm::StringRef Code = Test.code();
144 std::vector<std::string> Cases;
145 for (const auto& Point : Test.points()) {
146 size_t Offset = llvm::cantFail(positionToOffset(Code, Point));
147 Cases.push_back((Code.substr(0, Offset) + "^" + Code.substr(Offset)).str());
148 }
149 for (const auto& Range : Test.ranges()) {
150 size_t Begin = llvm::cantFail(positionToOffset(Code, Range.start));
151 size_t End = llvm::cantFail(positionToOffset(Code, Range.end));
152 Cases.push_back((Code.substr(0, Begin) + "[[" +
153 Code.substr(Begin, End - Begin) + "]]" + Code.substr(End))
154 .str());
155 }
156 assert(!Cases.empty() && "No markings in MarkedCode?");
157 return Cases;
158 }
159
160 } // namespace clangd
161 } // namespace clang
clang::clangd::TestTU::build
ParsedAST build() const
Definition: TestTU.cpp:22
Code
std::string Code
Definition: FindTargetTests.cpp:67
clang::clangd::TestTU
Definition: TestTU.h:32
clang::clangd::Range::start
Position start
The range&#39;s start position.
Definition: Protocol.h:158
clang::clangd::TweakTest::ExtraArgs
std::vector< const char * > ExtraArgs
Definition: TweakTesting.h:69
clang::clangd::TestTU::HeaderCode
std::string HeaderCode
Definition: TestTU.h:50
clang::clangd::prepareTweak
llvm::Expected< std::unique_ptr< Tweak > > prepareTweak(StringRef ID, const Tweak::Selection &S)
Definition: Tweak.cpp:77
clang::clangd::TweakTest::isAvailable
::testing::Matcher< llvm::StringRef > isAvailable() const
Definition: TweakTesting.cpp:136
TweakTesting.h
SourceCode.h
clang::clangd::TestTU::Code
std::string Code
Definition: TestTU.h:46
clang::tidy::cppcoreguidelines::toString
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
Definition: SpecialMemberFunctionsCheck.cpp:58
clang::clangd::TweakTest::expandCases
static std::vector< std::string > expandCases(llvm::StringRef MarkedCode)
Definition: TweakTesting.cpp:141
TestFS.h
clang::clangd::TweakTest::apply
std::string apply(llvm::StringRef MarkedCode, llvm::StringMap< std::string > *EditedFiles=nullptr) const
Definition: TweakTesting.cpp:89
clang::clangd::TweakTest::CodeContext
CodeContext
Definition: TweakTesting.h:46
clang::clangd::Annotations::ranges
std::vector< clangd::Range > ranges(llvm::StringRef Name="") const
Definition: Annotations.cpp:41
clang::clangd::TweakTest::Index
std::unique_ptr< const SymbolIndex > Index
Definition: TweakTesting.h:75
clang::clangd::TestTU::ExtraArgs
std::vector< const char * > ExtraArgs
Definition: TestTU.h:57
Tweak.h
Ctx
Context Ctx
Definition: TUScheduler.cpp:237
clang::clangd::Range
Definition: Protocol.h:156
clang::clangd::SymbolOrigin::AST
Annotations.h
clang::clangd::TweakTest::ExtraFiles
llvm::StringMap< std::string > ExtraFiles
Definition: TweakTesting.h:56
clang::clangd::positionToOffset
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
Definition: SourceCode.cpp:155
clang::clangd::testPath
std::string testPath(PathRef File)
Definition: TestFS.cpp:82
clang::clangd::Annotations::points
std::vector< Position > points(llvm::StringRef Name="") const
Definition: Annotations.cpp:19
clang::clangd::TweakTest::Expression
Definition: TweakTesting.h:52
FileName
PathRef FileName
Definition: CodeComplete.cpp:1018
clang::clangd::Context
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition: Context.h:69
clang::clangd::Tweak::Selection
Input to prepare and apply tweaks.
Definition: Tweak.h:49
clang::clangd::ParsedAST
Stores and provides access to parsed AST.
Definition: ParsedAST.h:46
clang::clangd::TweakTest::Header
std::string Header
Definition: TweakTesting.h:64
clang::clangd::detail::wrap
T && wrap(T &&V)
Definition: Logger.h:40
Offset
size_t Offset
Definition: CodeComplete.cpp:1022
clang::clangd::TweakTest::File
Definition: TweakTesting.h:48
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::TweakTest::Function
Definition: TweakTesting.h:50
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
clang::clangd::TweakTest::FileName
llvm::StringRef FileName
Definition: TweakTesting.h:66
clang::clangd::TestTU::Filename
std::string Filename
Definition: TestTU.h:47
clang::clangd::Annotations
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges...
Definition: Annotations.h:23
clang::clangd::ParsedAST::build
static llvm::Optional< ParsedAST > build(std::unique_ptr< clang::CompilerInvocation > CI, llvm::ArrayRef< Diag > CompilerInvocationDiags, std::shared_ptr< const PreambleData > Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, const SymbolIndex *Index, const ParseOptions &Opts)
Attempts to run Clang and store parsed AST.
Definition: ParsedAST.cpp:218
clang::clangd::Range::end
Position end
The range&#39;s end position.
Definition: Protocol.h:161
clang::clangd::TestTU::AdditionalFiles
llvm::StringMap< std::string > AdditionalFiles
Definition: TestTU.h:54
Index
const SymbolIndex * Index
Definition: Dexp.cpp:84