blob: 81f0f1dc5b760cf7b355b29ddec8f1887ac27f07 [file] [log] [blame]
Manuel Klimek3f001342012-05-23 16:29:20 +00001//===- unittest/Tooling/RefactoringTest.cpp - Refactoring unit tests ------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Eric Liu40ef2fb2016-08-01 10:16:37 +000010#include "ReplacementTest.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000011#include "RewriterTestContext.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000012#include "clang/AST/ASTConsumer.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000013#include "clang/AST/ASTContext.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000014#include "clang/AST/DeclCXX.h"
15#include "clang/AST/DeclGroup.h"
16#include "clang/AST/RecursiveASTVisitor.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000017#include "clang/Basic/Diagnostic.h"
Douglas Gregor275e8832012-10-23 22:55:10 +000018#include "clang/Basic/DiagnosticOptions.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000019#include "clang/Basic/FileManager.h"
20#include "clang/Basic/LangOptions.h"
21#include "clang/Basic/SourceManager.h"
Eric Liu4c1ef97a2016-03-29 16:31:53 +000022#include "clang/Format/Format.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000023#include "clang/Frontend/CompilerInstance.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000024#include "clang/Frontend/FrontendAction.h"
25#include "clang/Frontend/TextDiagnosticPrinter.h"
Ted Kremenekcdf81492012-09-01 05:09:24 +000026#include "clang/Rewrite/Core/Rewriter.h"
Chandler Carruth320d9662012-12-04 09:45:34 +000027#include "clang/Tooling/Refactoring.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000028#include "clang/Tooling/Tooling.h"
29#include "llvm/ADT/SmallString.h"
Manuel Klimek3f001342012-05-23 16:29:20 +000030#include "gtest/gtest.h"
31
32namespace clang {
33namespace tooling {
34
Manuel Klimek3f001342012-05-23 16:29:20 +000035TEST_F(ReplacementTest, CanDeleteAllText) {
36 FileID ID = Context.createInMemoryFile("input.cpp", "text");
37 SourceLocation Location = Context.getLocation(ID, 1, 1);
38 Replacement Replace(createReplacement(Location, 4, ""));
39 EXPECT_TRUE(Replace.apply(Context.Rewrite));
40 EXPECT_EQ("", Context.getRewrittenText(ID));
41}
42
43TEST_F(ReplacementTest, CanDeleteAllTextInTextWithNewlines) {
44 FileID ID = Context.createInMemoryFile("input.cpp", "line1\nline2\nline3");
45 SourceLocation Location = Context.getLocation(ID, 1, 1);
46 Replacement Replace(createReplacement(Location, 17, ""));
47 EXPECT_TRUE(Replace.apply(Context.Rewrite));
48 EXPECT_EQ("", Context.getRewrittenText(ID));
49}
50
51TEST_F(ReplacementTest, CanAddText) {
52 FileID ID = Context.createInMemoryFile("input.cpp", "");
53 SourceLocation Location = Context.getLocation(ID, 1, 1);
54 Replacement Replace(createReplacement(Location, 0, "result"));
55 EXPECT_TRUE(Replace.apply(Context.Rewrite));
56 EXPECT_EQ("result", Context.getRewrittenText(ID));
57}
58
59TEST_F(ReplacementTest, CanReplaceTextAtPosition) {
60 FileID ID = Context.createInMemoryFile("input.cpp",
61 "line1\nline2\nline3\nline4");
62 SourceLocation Location = Context.getLocation(ID, 2, 3);
63 Replacement Replace(createReplacement(Location, 12, "x"));
64 EXPECT_TRUE(Replace.apply(Context.Rewrite));
65 EXPECT_EQ("line1\nlixne4", Context.getRewrittenText(ID));
66}
67
68TEST_F(ReplacementTest, CanReplaceTextAtPositionMultipleTimes) {
69 FileID ID = Context.createInMemoryFile("input.cpp",
70 "line1\nline2\nline3\nline4");
71 SourceLocation Location1 = Context.getLocation(ID, 2, 3);
72 Replacement Replace1(createReplacement(Location1, 12, "x\ny\n"));
73 EXPECT_TRUE(Replace1.apply(Context.Rewrite));
74 EXPECT_EQ("line1\nlix\ny\nne4", Context.getRewrittenText(ID));
75
76 // Since the original source has not been modified, the (4, 4) points to the
77 // 'e' in the original content.
78 SourceLocation Location2 = Context.getLocation(ID, 4, 4);
79 Replacement Replace2(createReplacement(Location2, 1, "f"));
80 EXPECT_TRUE(Replace2.apply(Context.Rewrite));
81 EXPECT_EQ("line1\nlix\ny\nnf4", Context.getRewrittenText(ID));
82}
83
84TEST_F(ReplacementTest, ApplyFailsForNonExistentLocation) {
85 Replacement Replace("nonexistent-file.cpp", 0, 1, "");
86 EXPECT_FALSE(Replace.apply(Context.Rewrite));
87}
88
89TEST_F(ReplacementTest, CanRetrivePath) {
90 Replacement Replace("/path/to/file.cpp", 0, 1, "");
91 EXPECT_EQ("/path/to/file.cpp", Replace.getFilePath());
92}
93
94TEST_F(ReplacementTest, ReturnsInvalidPath) {
95 Replacement Replace1(Context.Sources, SourceLocation(), 0, "");
96 EXPECT_TRUE(Replace1.getFilePath().empty());
97
98 Replacement Replace2;
99 EXPECT_TRUE(Replace2.getFilePath().empty());
100}
101
Eric Liu40ef2fb2016-08-01 10:16:37 +0000102TEST_F(ReplacementTest, FailAddReplacements) {
103 Replacements Replaces;
Eric Liu6ef82b62016-09-28 11:02:16 +0000104 Replacement Deletion("x.cc", 0, 10, "3");
105 auto Err = Replaces.add(Deletion);
Eric Liu40ef2fb2016-08-01 10:16:37 +0000106 EXPECT_TRUE(!Err);
107 llvm::consumeError(std::move(Err));
Eric Liu6ef82b62016-09-28 11:02:16 +0000108 Err = Replaces.add(Replacement("x.cc", 0, 2, "a"));
Eric Liu40ef2fb2016-08-01 10:16:37 +0000109 EXPECT_TRUE((bool)Err);
110 llvm::consumeError(std::move(Err));
Eric Liu6ef82b62016-09-28 11:02:16 +0000111 Err = Replaces.add(Replacement("x.cc", 2, 2, "a"));
Eric Liu40ef2fb2016-08-01 10:16:37 +0000112 EXPECT_TRUE((bool)Err);
113 llvm::consumeError(std::move(Err));
114 Err = Replaces.add(Replacement("y.cc", 20, 2, ""));
115 EXPECT_TRUE((bool)Err);
116 llvm::consumeError(std::move(Err));
Eric Liu6ef82b62016-09-28 11:02:16 +0000117 EXPECT_EQ(1u, Replaces.size());
118 EXPECT_EQ(Deletion, *Replaces.begin());
119}
120
121TEST_F(ReplacementTest, DeletionInReplacements) {
122 Replacements Replaces;
123 Replacement R("x.cc", 0, 10, "3");
124 auto Err = Replaces.add(R);
125 EXPECT_TRUE(!Err);
126 llvm::consumeError(std::move(Err));
127 Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
128 EXPECT_TRUE(!Err);
129 llvm::consumeError(std::move(Err));
130 Err = Replaces.add(Replacement("x.cc", 2, 2, ""));
131 EXPECT_TRUE(!Err);
132 llvm::consumeError(std::move(Err));
133 EXPECT_EQ(1u, Replaces.size());
134 EXPECT_EQ(R, *Replaces.begin());
135}
136
137TEST_F(ReplacementTest, OverlappingReplacements) {
138 Replacements Replaces;
139 auto Err = Replaces.add(Replacement("x.cc", 0, 3, "345"));
140 EXPECT_TRUE(!Err);
141 llvm::consumeError(std::move(Err));
142 Err = Replaces.add(Replacement("x.cc", 2, 3, "543"));
143 EXPECT_TRUE(!Err);
144 llvm::consumeError(std::move(Err));
145
146 EXPECT_EQ(1u, Replaces.size());
147 EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
148
149 Err = Replaces.add(Replacement("x.cc", 2, 1, "5"));
150 EXPECT_TRUE(!Err);
151 llvm::consumeError(std::move(Err));
152 EXPECT_EQ(1u, Replaces.size());
153 EXPECT_EQ(Replacement("x.cc", 0, 5, "34543"), *Replaces.begin());
Eric Liu40ef2fb2016-08-01 10:16:37 +0000154}
155
Eric Liu9df9b6f2016-09-19 08:40:42 +0000156TEST_F(ReplacementTest, AddAdjacentInsertionAndReplacement) {
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000157 Replacements Replaces;
158 // Test adding an insertion at the offset of an existing replacement.
159 auto Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
160 EXPECT_TRUE(!Err);
161 llvm::consumeError(std::move(Err));
162 Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000163 EXPECT_TRUE(!Err);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000164 llvm::consumeError(std::move(Err));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000165 EXPECT_EQ(Replaces.size(), 2u);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000166
167 Replaces.clear();
168 // Test overlap with an existing insertion.
169 Err = Replaces.add(Replacement("x.cc", 10, 0, "insert"));
170 EXPECT_TRUE(!Err);
171 llvm::consumeError(std::move(Err));
172 Err = Replaces.add(Replacement("x.cc", 10, 3, "replace"));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000173 EXPECT_TRUE(!Err);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000174 llvm::consumeError(std::move(Err));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000175 EXPECT_EQ(Replaces.size(), 2u);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000176}
177
Eric Liu6ef82b62016-09-28 11:02:16 +0000178TEST_F(ReplacementTest, MergeNewDeletions) {
179 Replacements Replaces;
180 Replacement ContainingReplacement("x.cc", 0, 10, "");
181 auto Err = Replaces.add(ContainingReplacement);
182 EXPECT_TRUE(!Err);
183 llvm::consumeError(std::move(Err));
184
185 Err = Replaces.add(Replacement("x.cc", 5, 3, ""));
186 EXPECT_TRUE(!Err);
187 llvm::consumeError(std::move(Err));
188
189 Err = Replaces.add(Replacement("x.cc", 0, 10, ""));
190 EXPECT_TRUE(!Err);
191 llvm::consumeError(std::move(Err));
192
193 Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
194 EXPECT_TRUE(!Err);
195 llvm::consumeError(std::move(Err));
196
197 EXPECT_EQ(1u, Replaces.size());
198 EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
199}
200
201TEST_F(ReplacementTest, MergeOverlappingButNotAdjacentReplacement) {
202 Replacements Replaces;
203 auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
204 EXPECT_TRUE(!Err);
205 llvm::consumeError(std::move(Err));
206
207 Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
208 EXPECT_TRUE(!Err);
209 llvm::consumeError(std::move(Err));
210
211 Replacement After = Replacement("x.cc", 10, 5, "");
212 Err = Replaces.add(After);
213 EXPECT_TRUE(!Err);
214 llvm::consumeError(std::move(Err));
215
216 Replacement ContainingReplacement("x.cc", 0, 10, "");
217 Err = Replaces.add(ContainingReplacement);
218 EXPECT_TRUE(!Err);
219 llvm::consumeError(std::move(Err));
220
221 EXPECT_EQ(2u, Replaces.size());
222 EXPECT_EQ(*Replaces.begin(), ContainingReplacement);
223 EXPECT_EQ(*(++Replaces.begin()), After);
224}
225
226TEST_F(ReplacementTest, InsertionBeforeMergedDeletions) {
227 Replacements Replaces;
228
229 Replacement Insertion("x.cc", 0, 0, "123");
230 auto Err = Replaces.add(Insertion);
231 EXPECT_TRUE(!Err);
232 llvm::consumeError(std::move(Err));
233
234 Err = Replaces.add(Replacement("x.cc", 5, 5, ""));
235 EXPECT_TRUE(!Err);
236 llvm::consumeError(std::move(Err));
237
238 Replacement Deletion("x.cc", 0, 10, "");
239 Err = Replaces.add(Deletion);
240 EXPECT_TRUE(!Err);
241 llvm::consumeError(std::move(Err));
242
243 EXPECT_EQ(2u, Replaces.size());
244 EXPECT_EQ(*Replaces.begin(), Insertion);
245 EXPECT_EQ(*(++Replaces.begin()), Deletion);
246}
247
248TEST_F(ReplacementTest, MergeOverlappingDeletions) {
249 Replacements Replaces;
250 auto Err = Replaces.add(Replacement("x.cc", 0, 2, ""));
251 EXPECT_TRUE(!Err);
252 llvm::consumeError(std::move(Err));
253
254 Err = Replaces.add(Replacement("x.cc", 0, 5, ""));
255 EXPECT_TRUE(!Err);
256 llvm::consumeError(std::move(Err));
257
258 EXPECT_EQ(1u, Replaces.size());
259 EXPECT_EQ(Replacement("x.cc", 0, 5, ""), *Replaces.begin());
260
261 Err = Replaces.add(Replacement("x.cc", 1, 5, ""));
262 EXPECT_TRUE(!Err);
263 llvm::consumeError(std::move(Err));
264 EXPECT_EQ(1u, Replaces.size());
265 EXPECT_EQ(Replacement("x.cc", 0, 6, ""), *Replaces.begin());
266}
267
268TEST_F(ReplacementTest, FailedMergeExistingDeletions) {
269 Replacements Replaces;
270 Replacement First("x.cc", 0, 2, "");
271 auto Err = Replaces.add(First);
272 EXPECT_TRUE(!Err);
273 llvm::consumeError(std::move(Err));
274
275 Replacement Second("x.cc", 5, 5, "");
276 Err = Replaces.add(Second);
277 EXPECT_TRUE(!Err);
278 llvm::consumeError(std::move(Err));
279
280 Err = Replaces.add(Replacement("x.cc", 1, 10, ""));
281 EXPECT_TRUE(!Err);
282 llvm::consumeError(std::move(Err));
283
284 EXPECT_EQ(1u, Replaces.size());
285 EXPECT_EQ(Replacement("x.cc", 0, 11, ""), *Replaces.begin());
286}
287
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000288TEST_F(ReplacementTest, FailAddRegression) {
289 Replacements Replaces;
290 // Create two replacements, where the second one is an insertion of the empty
291 // string exactly at the end of the first one.
292 auto Err = Replaces.add(Replacement("x.cc", 0, 10, "1"));
293 EXPECT_TRUE(!Err);
294 llvm::consumeError(std::move(Err));
295 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
296 EXPECT_TRUE(!Err);
297 llvm::consumeError(std::move(Err));
298
299 // Make sure we find the overlap with the first entry when inserting a
300 // replacement that ends exactly at the seam of the existing replacements.
301 Err = Replaces.add(Replacement("x.cc", 5, 5, "fail"));
302 EXPECT_TRUE((bool)Err);
303 llvm::consumeError(std::move(Err));
304
305 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
Eric Liu6ef82b62016-09-28 11:02:16 +0000306 EXPECT_TRUE(!Err);
Manuel Klimekdcb910b2016-08-03 14:12:17 +0000307 llvm::consumeError(std::move(Err));
308}
309
Eric Liu9df9b6f2016-09-19 08:40:42 +0000310TEST_F(ReplacementTest, InsertAtOffsetOfReplacement) {
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000311 Replacements Replaces;
312 auto Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
313 EXPECT_TRUE(!Err);
314 llvm::consumeError(std::move(Err));
315 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000316 EXPECT_TRUE(!Err);
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000317 llvm::consumeError(std::move(Err));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000318 EXPECT_EQ(Replaces.size(), 2u);
319
320 Replaces.clear();
321 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
322 EXPECT_TRUE(!Err);
323 llvm::consumeError(std::move(Err));
324 Err = Replaces.add(Replacement("x.cc", 10, 2, ""));
325 EXPECT_TRUE(!Err);
326 llvm::consumeError(std::move(Err));
327 EXPECT_EQ(Replaces.size(), 2u);
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000328}
329
Eric Liu6ef82b62016-09-28 11:02:16 +0000330TEST_F(ReplacementTest, AddInsertAtOtherInsertWhenOderIndependent) {
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000331 Replacements Replaces;
332 auto Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
333 EXPECT_TRUE(!Err);
334 llvm::consumeError(std::move(Err));
335 Err = Replaces.add(Replacement("x.cc", 10, 0, "b"));
336 EXPECT_TRUE((bool)Err);
337 llvm::consumeError(std::move(Err));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000338
339 Replaces.clear();
Eric Liu6ef82b62016-09-28 11:02:16 +0000340 Err = Replaces.add(Replacement("x.cc", 10, 0, "a"));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000341 EXPECT_TRUE(!Err);
342 llvm::consumeError(std::move(Err));
Eric Liu6ef82b62016-09-28 11:02:16 +0000343 Err = Replaces.add(Replacement("x.cc", 10, 0, "aa"));
344 EXPECT_TRUE(!Err);
Eric Liu9df9b6f2016-09-19 08:40:42 +0000345 llvm::consumeError(std::move(Err));
Eric Liu6ef82b62016-09-28 11:02:16 +0000346 EXPECT_EQ(1u, Replaces.size());
347 EXPECT_EQ(Replacement("x.cc", 10, 0, "aaa"), *Replaces.begin());
Eric Liu9df9b6f2016-09-19 08:40:42 +0000348
349 Replaces.clear();
350 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
351 EXPECT_TRUE(!Err);
352 llvm::consumeError(std::move(Err));
353 Err = Replaces.add(Replacement("x.cc", 10, 3, ""));
354 EXPECT_TRUE(!Err);
355 llvm::consumeError(std::move(Err));
356 Err = Replaces.add(Replacement("x.cc", 10, 0, ""));
Eric Liu6ef82b62016-09-28 11:02:16 +0000357 EXPECT_TRUE(!Err);
Eric Liu9df9b6f2016-09-19 08:40:42 +0000358 llvm::consumeError(std::move(Err));
Eric Liu6ef82b62016-09-28 11:02:16 +0000359 EXPECT_EQ(2u, Replaces.size());
360 EXPECT_EQ(Replacement("x.cc", 10, 0, ""), *Replaces.begin());
361 EXPECT_EQ(Replacement("x.cc", 10, 3, ""), *std::next(Replaces.begin()));
Eric Liu9df9b6f2016-09-19 08:40:42 +0000362}
363
364TEST_F(ReplacementTest, InsertBetweenAdjacentReplacements) {
365 Replacements Replaces;
366 auto Err = Replaces.add(Replacement("x.cc", 10, 5, "a"));
367 EXPECT_TRUE(!Err);
368 llvm::consumeError(std::move(Err));
369 Err = Replaces.add(Replacement("x.cc", 8, 2, "a"));
370 EXPECT_TRUE(!Err);
371 llvm::consumeError(std::move(Err));
372 Err = Replaces.add(Replacement("x.cc", 10, 0, "b"));
373 EXPECT_TRUE(!Err);
374 llvm::consumeError(std::move(Err));
Manuel Klimek16c6d0a2016-08-03 15:12:00 +0000375}
376
Manuel Klimek3f001342012-05-23 16:29:20 +0000377TEST_F(ReplacementTest, CanApplyReplacements) {
378 FileID ID = Context.createInMemoryFile("input.cpp",
379 "line1\nline2\nline3\nline4");
Eric Liu40ef2fb2016-08-01 10:16:37 +0000380 Replacements Replaces =
381 toReplacements({Replacement(Context.Sources,
382 Context.getLocation(ID, 2, 1), 5, "replaced"),
383 Replacement(Context.Sources,
384 Context.getLocation(ID, 3, 1), 5, "other")});
Edwin Vane349e1c12013-08-13 17:38:19 +0000385 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
386 EXPECT_EQ("line1\nreplaced\nother\nline4", Context.getRewrittenText(ID));
387}
388
Eric Liu9df9b6f2016-09-19 08:40:42 +0000389// Verifies that replacement/deletion is applied before insertion at the same
390// offset.
391TEST_F(ReplacementTest, InsertAndDelete) {
392 FileID ID = Context.createInMemoryFile("input.cpp",
393 "line1\nline2\nline3\nline4");
394 Replacements Replaces = toReplacements(
395 {Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 6, ""),
396 Replacement(Context.Sources, Context.getLocation(ID, 2, 1), 0,
397 "other\n")});
398 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
399 EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
400}
401
402TEST_F(ReplacementTest, AdjacentReplacements) {
403 FileID ID = Context.createInMemoryFile("input.cpp",
404 "ab");
405 Replacements Replaces = toReplacements(
406 {Replacement(Context.Sources, Context.getLocation(ID, 1, 1), 1, "x"),
407 Replacement(Context.Sources, Context.getLocation(ID, 1, 2), 1, "y")});
408 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
409 EXPECT_EQ("xy", Context.getRewrittenText(ID));
410}
411
Eric Liu6ef82b62016-09-28 11:02:16 +0000412TEST_F(ReplacementTest, AddDuplicateReplacements) {
Manuel Klimek3f001342012-05-23 16:29:20 +0000413 FileID ID = Context.createInMemoryFile("input.cpp",
414 "line1\nline2\nline3\nline4");
Eric Liu40ef2fb2016-08-01 10:16:37 +0000415 auto Replaces = toReplacements({Replacement(
416 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
417
418 auto Err = Replaces.add(Replacement(
419 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced"));
Eric Liu6ef82b62016-09-28 11:02:16 +0000420 EXPECT_TRUE(!Err);
Eric Liu40ef2fb2016-08-01 10:16:37 +0000421 llvm::consumeError(std::move(Err));
422
423 Err = Replaces.add(Replacement(Context.Sources, Context.getLocation(ID, 2, 1),
424 5, "replaced"));
Eric Liu6ef82b62016-09-28 11:02:16 +0000425 EXPECT_TRUE(!Err);
Eric Liu40ef2fb2016-08-01 10:16:37 +0000426 llvm::consumeError(std::move(Err));
427
Manuel Klimek3f001342012-05-23 16:29:20 +0000428 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
429 EXPECT_EQ("line1\nreplaced\nline3\nline4", Context.getRewrittenText(ID));
430}
431
Eric Liu6ef82b62016-09-28 11:02:16 +0000432TEST_F(ReplacementTest, FailOrderDependentReplacements) {
433 FileID ID = Context.createInMemoryFile("input.cpp",
434 "line1\nline2\nline3\nline4");
435 auto Replaces = toReplacements({Replacement(
436 Context.Sources, Context.getLocation(ID, 2, 1), 5, "other")});
437
438 auto Err = Replaces.add(Replacement(
439 Context.Sources, Context.getLocation(ID, 2, 1), 5, "rehto"));
440 EXPECT_TRUE((bool)Err);
441 llvm::consumeError(std::move(Err));
442
443 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
444 EXPECT_EQ("line1\nother\nline3\nline4", Context.getRewrittenText(ID));
445}
446
Eric Liu40ef2fb2016-08-01 10:16:37 +0000447TEST_F(ReplacementTest, InvalidSourceLocationFailsApplyAll) {
448 Replacements Replaces =
449 toReplacements({Replacement(Context.Sources, SourceLocation(), 5, "2")});
450
Manuel Klimek3f001342012-05-23 16:29:20 +0000451 EXPECT_FALSE(applyAllReplacements(Replaces, Context.Rewrite));
Manuel Klimek3f001342012-05-23 16:29:20 +0000452}
453
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000454TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
455 // Column limit is 20.
456 std::string Code1 = "Long *a =\n"
457 " new Long();\n"
458 "long x = 1;";
459 std::string Expected1 = "auto a = new Long();\n"
460 "long x =\n"
461 " 12345678901;";
462 std::string Code2 = "int x = 123;\n"
463 "int y = 0;";
464 std::string Expected2 = "int x =\n"
465 " 1234567890123;\n"
466 "int y = 10;";
Eric Liu40ef2fb2016-08-01 10:16:37 +0000467 StringRef File1 = "format_1.cpp";
468 StringRef File2 = "format_2.cpp";
469 FileID ID1 = Context.createInMemoryFile(File1, Code1);
470 FileID ID2 = Context.createInMemoryFile(File2, Code2);
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000471
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000472 // Scrambled the order of replacements.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000473 std::map<std::string, Replacements> FileToReplaces;
474 FileToReplaces[File1] = toReplacements(
475 {tooling::Replacement(Context.Sources, Context.getLocation(ID1, 1, 1), 6,
476 "auto "),
477 tooling::Replacement(Context.Sources, Context.getLocation(ID1, 3, 10), 1,
478 "12345678901")});
479 FileToReplaces[File2] = toReplacements(
480 {tooling::Replacement(Context.Sources, Context.getLocation(ID2, 1, 12), 0,
481 "4567890123"),
482 tooling::Replacement(Context.Sources, Context.getLocation(ID2, 2, 9), 1,
483 "10")});
484 EXPECT_TRUE(
485 formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite,
486 "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
Eric Liu4c1ef97a2016-03-29 16:31:53 +0000487 EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));
488 EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));
489}
490
Daniel Jasper2a250b82013-05-21 12:21:39 +0000491TEST(ShiftedCodePositionTest, FindsNewCodePosition) {
Eric Liu40ef2fb2016-08-01 10:16:37 +0000492 Replacements Replaces =
493 toReplacements({Replacement("", 0, 1, ""), Replacement("", 4, 3, " ")});
Daniel Jasper2a250b82013-05-21 12:21:39 +0000494 // Assume ' int i;' is turned into 'int i;' and cursor is located at '|'.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000495 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0)); // |int i;
496 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(1)); // |nt i;
497 EXPECT_EQ(1u, Replaces.getShiftedCodePosition(2)); // i|t i;
498 EXPECT_EQ(2u, Replaces.getShiftedCodePosition(3)); // in| i;
499 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(4)); // int| i;
500 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(5)); // int | i;
501 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(6)); // int |i;
502 EXPECT_EQ(4u, Replaces.getShiftedCodePosition(7)); // int |;
503 EXPECT_EQ(5u, Replaces.getShiftedCodePosition(8)); // int i|
Edwin Vane18e503c2013-08-27 15:44:26 +0000504}
505
Daniel Jasper2a250b82013-05-21 12:21:39 +0000506TEST(ShiftedCodePositionTest, FindsNewCodePositionWithInserts) {
Eric Liu40ef2fb2016-08-01 10:16:37 +0000507 Replacements Replaces = toReplacements({Replacement("", 4, 0, "\"\n\"")});
Daniel Jasper2a250b82013-05-21 12:21:39 +0000508 // Assume '"12345678"' is turned into '"1234"\n"5678"'.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000509 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(3)); // "123|5678"
510 EXPECT_EQ(7u, Replaces.getShiftedCodePosition(4)); // "1234|678"
511 EXPECT_EQ(8u, Replaces.getShiftedCodePosition(5)); // "12345|78"
Daniel Jasper3fed9452015-11-23 08:33:48 +0000512}
513
514TEST(ShiftedCodePositionTest, FindsNewCodePositionInReplacedText) {
Daniel Jasper3fed9452015-11-23 08:33:48 +0000515 // Replace the first four characters with "abcd".
Eric Liu40ef2fb2016-08-01 10:16:37 +0000516 auto Replaces = toReplacements({Replacement("", 0, 4, "abcd")});
Daniel Jasper3fed9452015-11-23 08:33:48 +0000517 for (unsigned i = 0; i < 3; ++i)
Eric Liu40ef2fb2016-08-01 10:16:37 +0000518 EXPECT_EQ(i, Replaces.getShiftedCodePosition(i));
519}
520
521TEST(ShiftedCodePositionTest, NoReplacementText) {
522 Replacements Replaces = toReplacements({Replacement("", 0, 42, "")});
523 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(0));
524 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(39));
525 EXPECT_EQ(3u, Replaces.getShiftedCodePosition(45));
526 EXPECT_EQ(0u, Replaces.getShiftedCodePosition(42));
Daniel Jasper2a250b82013-05-21 12:21:39 +0000527}
528
Manuel Klimek3f001342012-05-23 16:29:20 +0000529class FlushRewrittenFilesTest : public ::testing::Test {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000530public:
531 FlushRewrittenFilesTest() {}
Manuel Klimek3f001342012-05-23 16:29:20 +0000532
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000533 ~FlushRewrittenFilesTest() override {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000534 for (llvm::StringMap<std::string>::iterator I = TemporaryFiles.begin(),
535 E = TemporaryFiles.end();
536 I != E; ++I) {
537 llvm::StringRef Name = I->second;
Rafael Espindolac0809172014-06-12 14:02:15 +0000538 std::error_code EC = llvm::sys::fs::remove(Name);
Rafael Espindola641c6a12013-06-26 15:01:50 +0000539 (void)EC;
540 assert(!EC);
541 }
Manuel Klimek3f001342012-05-23 16:29:20 +0000542 }
543
544 FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000545 SmallString<1024> Path;
546 int FD;
Rafael Espindolac0809172014-06-12 14:02:15 +0000547 std::error_code EC = llvm::sys::fs::createTemporaryFile(Name, "", FD, Path);
Rafael Espindola641c6a12013-06-26 15:01:50 +0000548 assert(!EC);
549 (void)EC;
550
551 llvm::raw_fd_ostream OutStream(FD, true);
Manuel Klimek3f001342012-05-23 16:29:20 +0000552 OutStream << Content;
553 OutStream.close();
554 const FileEntry *File = Context.Files.getFile(Path);
Craig Topper416fa342014-06-08 08:38:12 +0000555 assert(File != nullptr);
Rafael Espindola641c6a12013-06-26 15:01:50 +0000556
David Blaikie13156b62014-11-19 03:06:06 +0000557 StringRef Found =
558 TemporaryFiles.insert(std::make_pair(Name, Path.str())).first->second;
Rafael Espindola641c6a12013-06-26 15:01:50 +0000559 assert(Found == Path);
560 (void)Found;
Manuel Klimek3f001342012-05-23 16:29:20 +0000561 return Context.Sources.createFileID(File, SourceLocation(), SrcMgr::C_User);
562 }
563
564 std::string getFileContentFromDisk(llvm::StringRef Name) {
Rafael Espindola641c6a12013-06-26 15:01:50 +0000565 std::string Path = TemporaryFiles.lookup(Name);
566 assert(!Path.empty());
Manuel Klimek3f001342012-05-23 16:29:20 +0000567 // We need to read directly from the FileManager without relaying through
568 // a FileEntry, as otherwise we'd read through an already opened file
569 // descriptor, which might not see the changes made.
570 // FIXME: Figure out whether there is a way to get the SourceManger to
571 // reopen the file.
Benjamin Kramera8857962014-10-26 22:44:13 +0000572 auto FileBuffer = Context.Files.getBufferForFile(Path);
573 return (*FileBuffer)->getBuffer();
Manuel Klimek3f001342012-05-23 16:29:20 +0000574 }
575
Rafael Espindola641c6a12013-06-26 15:01:50 +0000576 llvm::StringMap<std::string> TemporaryFiles;
Manuel Klimek3f001342012-05-23 16:29:20 +0000577 RewriterTestContext Context;
578};
579
580TEST_F(FlushRewrittenFilesTest, StoresChangesOnDisk) {
581 FileID ID = createFile("input.cpp", "line1\nline2\nline3\nline4");
Eric Liu40ef2fb2016-08-01 10:16:37 +0000582 Replacements Replaces = toReplacements({Replacement(
583 Context.Sources, Context.getLocation(ID, 2, 1), 5, "replaced")});
Manuel Klimek3f001342012-05-23 16:29:20 +0000584 EXPECT_TRUE(applyAllReplacements(Replaces, Context.Rewrite));
585 EXPECT_FALSE(Context.Rewrite.overwriteChangedFiles());
586 EXPECT_EQ("line1\nreplaced\nline3\nline4",
587 getFileContentFromDisk("input.cpp"));
588}
589
590namespace {
591template <typename T>
592class TestVisitor : public clang::RecursiveASTVisitor<T> {
593public:
594 bool runOver(StringRef Code) {
595 return runToolOnCode(new TestAction(this), Code);
596 }
597
598protected:
599 clang::SourceManager *SM;
Manuel Klimek94a89232015-06-03 13:10:41 +0000600 clang::ASTContext *Context;
Manuel Klimek3f001342012-05-23 16:29:20 +0000601
602private:
603 class FindConsumer : public clang::ASTConsumer {
604 public:
605 FindConsumer(TestVisitor *Visitor) : Visitor(Visitor) {}
606
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000607 void HandleTranslationUnit(clang::ASTContext &Context) override {
Manuel Klimek3f001342012-05-23 16:29:20 +0000608 Visitor->TraverseDecl(Context.getTranslationUnitDecl());
609 }
610
611 private:
612 TestVisitor *Visitor;
613 };
614
615 class TestAction : public clang::ASTFrontendAction {
616 public:
617 TestAction(TestVisitor *Visitor) : Visitor(Visitor) {}
618
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000619 std::unique_ptr<clang::ASTConsumer>
David Blaikie6beb6aa2014-08-10 19:56:51 +0000620 CreateASTConsumer(clang::CompilerInstance &compiler,
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000621 llvm::StringRef dummy) override {
Manuel Klimek3f001342012-05-23 16:29:20 +0000622 Visitor->SM = &compiler.getSourceManager();
Manuel Klimek94a89232015-06-03 13:10:41 +0000623 Visitor->Context = &compiler.getASTContext();
Manuel Klimek3f001342012-05-23 16:29:20 +0000624 /// TestConsumer will be deleted by the framework calling us.
David Blaikie6beb6aa2014-08-10 19:56:51 +0000625 return llvm::make_unique<FindConsumer>(Visitor);
Manuel Klimek3f001342012-05-23 16:29:20 +0000626 }
627
628 private:
629 TestVisitor *Visitor;
630 };
631};
632} // end namespace
633
634void expectReplacementAt(const Replacement &Replace,
635 StringRef File, unsigned Offset, unsigned Length) {
636 ASSERT_TRUE(Replace.isApplicable());
637 EXPECT_EQ(File, Replace.getFilePath());
638 EXPECT_EQ(Offset, Replace.getOffset());
639 EXPECT_EQ(Length, Replace.getLength());
640}
641
642class ClassDeclXVisitor : public TestVisitor<ClassDeclXVisitor> {
643public:
644 bool VisitCXXRecordDecl(CXXRecordDecl *Record) {
645 if (Record->getName() == "X") {
646 Replace = Replacement(*SM, Record, "");
647 }
648 return true;
649 }
650 Replacement Replace;
651};
652
653TEST(Replacement, CanBeConstructedFromNode) {
654 ClassDeclXVisitor ClassDeclX;
655 EXPECT_TRUE(ClassDeclX.runOver(" class X;"));
656 expectReplacementAt(ClassDeclX.Replace, "input.cc", 5, 7);
657}
658
659TEST(Replacement, ReplacesAtSpellingLocation) {
660 ClassDeclXVisitor ClassDeclX;
661 EXPECT_TRUE(ClassDeclX.runOver("#define A(Y) Y\nA(class X);"));
662 expectReplacementAt(ClassDeclX.Replace, "input.cc", 17, 7);
663}
664
665class CallToFVisitor : public TestVisitor<CallToFVisitor> {
666public:
667 bool VisitCallExpr(CallExpr *Call) {
668 if (Call->getDirectCallee()->getName() == "F") {
669 Replace = Replacement(*SM, Call, "");
670 }
671 return true;
672 }
673 Replacement Replace;
674};
675
676TEST(Replacement, FunctionCall) {
677 CallToFVisitor CallToF;
678 EXPECT_TRUE(CallToF.runOver("void F(); void G() { F(); }"));
679 expectReplacementAt(CallToF.Replace, "input.cc", 21, 3);
680}
681
682TEST(Replacement, TemplatedFunctionCall) {
683 CallToFVisitor CallToF;
684 EXPECT_TRUE(CallToF.runOver(
685 "template <typename T> void F(); void G() { F<int>(); }"));
686 expectReplacementAt(CallToF.Replace, "input.cc", 43, 8);
687}
688
Manuel Klimek94a89232015-06-03 13:10:41 +0000689class NestedNameSpecifierAVisitor
690 : public TestVisitor<NestedNameSpecifierAVisitor> {
691public:
692 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) {
693 if (NNSLoc.getNestedNameSpecifier()) {
694 if (const NamespaceDecl* NS = NNSLoc.getNestedNameSpecifier()->getAsNamespace()) {
695 if (NS->getName() == "a") {
696 Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts());
697 }
698 }
699 }
700 return TestVisitor<NestedNameSpecifierAVisitor>::TraverseNestedNameSpecifierLoc(
701 NNSLoc);
702 }
703 Replacement Replace;
704};
705
706TEST(Replacement, ColonColon) {
707 NestedNameSpecifierAVisitor VisitNNSA;
708 EXPECT_TRUE(VisitNNSA.runOver("namespace a { void f() { ::a::f(); } }"));
709 expectReplacementAt(VisitNNSA.Replace, "input.cc", 25, 5);
710}
711
Manuel Klimekdce23472013-07-19 12:12:36 +0000712TEST(Range, overlaps) {
713 EXPECT_TRUE(Range(10, 10).overlapsWith(Range(0, 11)));
714 EXPECT_TRUE(Range(0, 11).overlapsWith(Range(10, 10)));
715 EXPECT_FALSE(Range(10, 10).overlapsWith(Range(0, 10)));
716 EXPECT_FALSE(Range(0, 10).overlapsWith(Range(10, 10)));
717 EXPECT_TRUE(Range(0, 10).overlapsWith(Range(2, 6)));
Edwin Vanec5148482013-08-13 18:11:16 +0000718 EXPECT_TRUE(Range(2, 6).overlapsWith(Range(0, 10)));
Manuel Klimekdce23472013-07-19 12:12:36 +0000719}
720
721TEST(Range, contains) {
722 EXPECT_TRUE(Range(0, 10).contains(Range(0, 10)));
723 EXPECT_TRUE(Range(0, 10).contains(Range(2, 6)));
724 EXPECT_FALSE(Range(2, 6).contains(Range(0, 10)));
725 EXPECT_FALSE(Range(0, 10).contains(Range(0, 11)));
726}
727
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000728TEST(Range, CalculateRangesOfReplacements) {
729 // Before: aaaabbbbbbz
730 // After : bbbbbbzzzzzzoooooooooooooooo
Eric Liu40ef2fb2016-08-01 10:16:37 +0000731 Replacements Replaces = toReplacements(
732 {Replacement("foo", 0, 4, ""), Replacement("foo", 10, 1, "zzzzzz"),
733 Replacement("foo", 11, 0, "oooooooooooooooo")});
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000734
Eric Liu40ef2fb2016-08-01 10:16:37 +0000735 std::vector<Range> Ranges = Replaces.getAffectedRanges();
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000736
Eric Liu8b636db2016-06-21 17:56:31 +0000737 EXPECT_EQ(2ul, Ranges.size());
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000738 EXPECT_TRUE(Ranges[0].getOffset() == 0);
739 EXPECT_TRUE(Ranges[0].getLength() == 0);
740 EXPECT_TRUE(Ranges[1].getOffset() == 6);
Eric Liu8b636db2016-06-21 17:56:31 +0000741 EXPECT_TRUE(Ranges[1].getLength() == 22);
742}
743
Eric Liu9df9b6f2016-09-19 08:40:42 +0000744TEST(Range, CalculateRangesOfInsertionAroundReplacement) {
745 Replacements Replaces = toReplacements(
746 {Replacement("foo", 0, 2, ""), Replacement("foo", 0, 0, "ba")});
747
748 std::vector<Range> Ranges = Replaces.getAffectedRanges();
749
750 EXPECT_EQ(1ul, Ranges.size());
751 EXPECT_EQ(0u, Ranges[0].getOffset());
752 EXPECT_EQ(2u, Ranges[0].getLength());
753}
754
Eric Liu73337f32016-08-08 13:37:39 +0000755TEST(Range, RangesAfterEmptyReplacements) {
756 std::vector<Range> Ranges = {Range(5, 6), Range(10, 5)};
757 Replacements Replaces;
758 std::vector<Range> Expected = {Range(5, 10)};
759 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
760}
761
Eric Liu8b636db2016-06-21 17:56:31 +0000762TEST(Range, RangesAfterReplacements) {
763 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000764 Replacements Replaces = toReplacements({Replacement("foo", 0, 2, "1234")});
Eric Liu8b636db2016-06-21 17:56:31 +0000765 std::vector<Range> Expected = {Range(0, 4), Range(7, 2), Range(12, 5)};
766 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
767}
768
769TEST(Range, RangesBeforeReplacements) {
770 std::vector<Range> Ranges = {Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000771 Replacements Replaces = toReplacements({Replacement("foo", 20, 2, "1234")});
Eric Liu8b636db2016-06-21 17:56:31 +0000772 std::vector<Range> Expected = {Range(5, 2), Range(10, 5), Range(20, 4)};
773 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
774}
775
776TEST(Range, NotAffectedByReplacements) {
777 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000778 Replacements Replaces = toReplacements({Replacement("foo", 3, 2, "12"),
779 Replacement("foo", 12, 2, "12"),
780 Replacement("foo", 20, 5, "")});
Eric Liu8b636db2016-06-21 17:56:31 +0000781 std::vector<Range> Expected = {Range(0, 2), Range(3, 4), Range(10, 5),
782 Range(20, 0)};
783 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
784}
785
786TEST(Range, RangesWithNonOverlappingReplacements) {
787 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(10, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000788 Replacements Replaces = toReplacements({Replacement("foo", 3, 1, ""),
789 Replacement("foo", 6, 1, "123"),
790 Replacement("foo", 20, 2, "12345")});
Eric Liu8b636db2016-06-21 17:56:31 +0000791 std::vector<Range> Expected = {Range(0, 2), Range(3, 0), Range(4, 4),
792 Range(11, 5), Range(21, 5)};
793 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
794}
795
796TEST(Range, RangesWithOverlappingReplacements) {
797 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5),
798 Range(30, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000799 Replacements Replaces = toReplacements(
800 {Replacement("foo", 1, 3, ""), Replacement("foo", 6, 1, "123"),
801 Replacement("foo", 13, 3, "1"), Replacement("foo", 25, 15, "")});
Eric Liu8b636db2016-06-21 17:56:31 +0000802 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(12, 5),
803 Range(22, 0)};
804 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
805}
806
807TEST(Range, MergeIntoOneRange) {
808 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000809 Replacements Replaces =
810 toReplacements({Replacement("foo", 1, 15, "1234567890")});
Eric Liu8b636db2016-06-21 17:56:31 +0000811 std::vector<Range> Expected = {Range(0, 15)};
812 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
813}
814
815TEST(Range, ReplacementsStartingAtRangeOffsets) {
816 std::vector<Range> Ranges = {Range(0, 2), Range(5, 5), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000817 Replacements Replaces = toReplacements(
818 {Replacement("foo", 0, 2, "12"), Replacement("foo", 5, 1, "123"),
819 Replacement("foo", 7, 4, "12345"), Replacement("foo", 15, 10, "12")});
Eric Liu8b636db2016-06-21 17:56:31 +0000820 std::vector<Range> Expected = {Range(0, 2), Range(5, 9), Range(18, 2)};
821 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
822}
823
824TEST(Range, ReplacementsEndingAtRangeEnds) {
825 std::vector<Range> Ranges = {Range(0, 2), Range(5, 2), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000826 Replacements Replaces = toReplacements(
827 {Replacement("foo", 6, 1, "123"), Replacement("foo", 17, 3, "12")});
Eric Liu8b636db2016-06-21 17:56:31 +0000828 std::vector<Range> Expected = {Range(0, 2), Range(5, 4), Range(17, 4)};
829 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
830}
831
832TEST(Range, AjacentReplacements) {
833 std::vector<Range> Ranges = {Range(0, 0), Range(15, 5)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000834 Replacements Replaces = toReplacements(
835 {Replacement("foo", 1, 2, "123"), Replacement("foo", 12, 3, "1234")});
Eric Liu8b636db2016-06-21 17:56:31 +0000836 std::vector<Range> Expected = {Range(0, 0), Range(1, 3), Range(13, 9)};
837 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
838}
839
840TEST(Range, MergeRangesAfterReplacements) {
841 std::vector<Range> Ranges = {Range(8, 0), Range(5, 2), Range(9, 0), Range(0, 1)};
Eric Liu40ef2fb2016-08-01 10:16:37 +0000842 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, ""),
843 Replacement("foo", 7, 0, "12"),
844 Replacement("foo", 9, 2, "")});
845 std::vector<Range> Expected = {Range(0, 1), Range(2, 4), Range(7, 0),
846 Range(8, 0)};
Eric Liu8b636db2016-06-21 17:56:31 +0000847 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
Manuel Klimekb12e5a52016-03-01 12:37:30 +0000848}
849
Eric Liu40ef2fb2016-08-01 10:16:37 +0000850TEST(Range, ConflictingRangesBeforeReplacements) {
851 std::vector<Range> Ranges = {Range(8, 3), Range(5, 4), Range(9, 1)};
852 Replacements Replaces = toReplacements({Replacement("foo", 1, 3, "")});
853 std::vector<Range> Expected = {Range(1, 0), Range(2, 6)};
854 EXPECT_EQ(Expected, calculateRangesAfterReplacements(Replaces, Ranges));
Edwin Vane938f6882013-08-08 13:31:14 +0000855}
856
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000857class MergeReplacementsTest : public ::testing::Test {
858protected:
859 void mergeAndTestRewrite(StringRef Code, StringRef Intermediate,
860 StringRef Result, const Replacements &First,
861 const Replacements &Second) {
862 // These are mainly to verify the test itself and make it easier to read.
Eric Liu4f8d9942016-07-11 13:53:12 +0000863 auto AfterFirst = applyAllReplacements(Code, First);
864 EXPECT_TRUE(static_cast<bool>(AfterFirst));
865 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
866 EXPECT_TRUE(static_cast<bool>(InSequenceRewrite));
867 EXPECT_EQ(Intermediate, *AfterFirst);
868 EXPECT_EQ(Result, *InSequenceRewrite);
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000869
Eric Liu40ef2fb2016-08-01 10:16:37 +0000870 tooling::Replacements Merged = First.merge(Second);
Eric Liu4f8d9942016-07-11 13:53:12 +0000871 auto MergedRewrite = applyAllReplacements(Code, Merged);
872 EXPECT_TRUE(static_cast<bool>(MergedRewrite));
873 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
874 if (*InSequenceRewrite != *MergedRewrite)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000875 for (tooling::Replacement M : Merged)
876 llvm::errs() << M.getOffset() << " " << M.getLength() << " "
877 << M.getReplacementText() << "\n";
878 }
879 void mergeAndTestRewrite(StringRef Code, const Replacements &First,
880 const Replacements &Second) {
Eric Liu4f8d9942016-07-11 13:53:12 +0000881 auto AfterFirst = applyAllReplacements(Code, First);
882 EXPECT_TRUE(static_cast<bool>(AfterFirst));
883 auto InSequenceRewrite = applyAllReplacements(*AfterFirst, Second);
Eric Liu40ef2fb2016-08-01 10:16:37 +0000884 tooling::Replacements Merged = First.merge(Second);
Eric Liu4f8d9942016-07-11 13:53:12 +0000885 auto MergedRewrite = applyAllReplacements(Code, Merged);
886 EXPECT_TRUE(static_cast<bool>(MergedRewrite));
887 EXPECT_EQ(*InSequenceRewrite, *MergedRewrite);
888 if (*InSequenceRewrite != *MergedRewrite)
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000889 for (tooling::Replacement M : Merged)
890 llvm::errs() << M.getOffset() << " " << M.getLength() << " "
891 << M.getReplacementText() << "\n";
892 }
893};
894
895TEST_F(MergeReplacementsTest, Offsets) {
896 mergeAndTestRewrite("aaa", "aabab", "cacabab",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000897 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
898 toReplacements({{"", 0, 0, "c"}, {"", 1, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000899 mergeAndTestRewrite("aaa", "babaa", "babacac",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000900 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "b"}}),
901 toReplacements({{"", 4, 0, "c"}, {"", 5, 0, "c"}}));
902 mergeAndTestRewrite("aaaa", "aaa", "aac", toReplacements({{"", 1, 1, ""}}),
903 toReplacements({{"", 2, 1, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000904
905 mergeAndTestRewrite("aa", "bbabba", "bbabcba",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000906 toReplacements({{"", 0, 0, "bb"}, {"", 1, 0, "bb"}}),
907 toReplacements({{"", 4, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000908}
909
910TEST_F(MergeReplacementsTest, Concatenations) {
911 // Basic concatenations. It is important to merge these into a single
912 // replacement to ensure the correct order.
Eric Liu40ef2fb2016-08-01 10:16:37 +0000913 {
914 auto First = toReplacements({{"", 0, 0, "a"}});
915 auto Second = toReplacements({{"", 1, 0, "b"}});
916 EXPECT_EQ(toReplacements({{"", 0, 0, "ab"}}), First.merge(Second));
917 }
918 {
919 auto First = toReplacements({{"", 0, 0, "a"}});
920 auto Second = toReplacements({{"", 0, 0, "b"}});
921 EXPECT_EQ(toReplacements({{"", 0, 0, "ba"}}), First.merge(Second));
922 }
923 mergeAndTestRewrite("", "a", "ab", toReplacements({{"", 0, 0, "a"}}),
924 toReplacements({{"", 1, 0, "b"}}));
925 mergeAndTestRewrite("", "a", "ba", toReplacements({{"", 0, 0, "a"}}),
926 toReplacements({{"", 0, 0, "b"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000927}
928
929TEST_F(MergeReplacementsTest, NotChangingLengths) {
Eric Liu40ef2fb2016-08-01 10:16:37 +0000930 mergeAndTestRewrite("aaaa", "abba", "acca",
931 toReplacements({{"", 1, 2, "bb"}}),
932 toReplacements({{"", 1, 2, "cc"}}));
933 mergeAndTestRewrite("aaaa", "abba", "abcc",
934 toReplacements({{"", 1, 2, "bb"}}),
935 toReplacements({{"", 2, 2, "cc"}}));
936 mergeAndTestRewrite("aaaa", "abba", "ccba",
937 toReplacements({{"", 1, 2, "bb"}}),
938 toReplacements({{"", 0, 2, "cc"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000939 mergeAndTestRewrite("aaaaaa", "abbdda", "abccda",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000940 toReplacements({{"", 1, 2, "bb"}, {"", 3, 2, "dd"}}),
941 toReplacements({{"", 2, 2, "cc"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000942}
943
944TEST_F(MergeReplacementsTest, OverlappingRanges) {
945 mergeAndTestRewrite("aaa", "bbd", "bcbcd",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000946 toReplacements({{"", 0, 1, "bb"}, {"", 1, 2, "d"}}),
947 toReplacements({{"", 1, 0, "c"}, {"", 2, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000948
Eric Liu40ef2fb2016-08-01 10:16:37 +0000949 mergeAndTestRewrite("aaaa", "aabbaa", "acccca",
950 toReplacements({{"", 2, 0, "bb"}}),
951 toReplacements({{"", 1, 4, "cccc"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000952 mergeAndTestRewrite("aaaa", "aababa", "acccca",
Eric Liu40ef2fb2016-08-01 10:16:37 +0000953 toReplacements({{"", 2, 0, "b"}, {"", 3, 0, "b"}}),
954 toReplacements({{"", 1, 4, "cccc"}}));
955 mergeAndTestRewrite("aaaaaa", "abbbba", "abba",
956 toReplacements({{"", 1, 4, "bbbb"}}),
957 toReplacements({{"", 2, 2, ""}}));
958 mergeAndTestRewrite("aaaa", "aa", "cc",
959 toReplacements({{"", 1, 1, ""}, {"", 2, 1, ""}}),
960 toReplacements({{"", 0, 2, "cc"}}));
961 mergeAndTestRewrite("aa", "abbba", "abcbcba",
962 toReplacements({{"", 1, 0, "bbb"}}),
963 toReplacements({{"", 2, 0, "c"}, {"", 3, 0, "c"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000964
Eric Liu40ef2fb2016-08-01 10:16:37 +0000965 mergeAndTestRewrite(
966 "aaa", "abbab", "ccdd",
967 toReplacements({{"", 0, 1, ""}, {"", 2, 0, "bb"}, {"", 3, 0, "b"}}),
968 toReplacements({{"", 0, 2, "cc"}, {"", 2, 3, "dd"}}));
969 mergeAndTestRewrite(
970 "aa", "babbab", "ccdd",
971 toReplacements({{"", 0, 0, "b"}, {"", 1, 0, "bb"}, {"", 2, 0, "b"}}),
972 toReplacements({{"", 0, 3, "cc"}, {"", 3, 3, "dd"}}));
Daniel Jasperd89ae9d2015-09-23 08:30:47 +0000973}
974
Eric Liucefe7632016-10-14 09:32:06 +0000975TEST(DeduplicateByFileTest, LeaveLeadingDotDot) {
976 std::map<std::string, Replacements> FileToReplaces;
Eric Liuc45343e2016-10-14 10:10:26 +0000977#if !defined(LLVM_ON_WIN32)
Eric Liucefe7632016-10-14 09:32:06 +0000978 FileToReplaces["../../a/b/.././c.h"] = Replacements();
979 FileToReplaces["../../a/c.h"] = Replacements();
Eric Liuc45343e2016-10-14 10:10:26 +0000980#else
981 FileToReplaces["..\\..\\a\\b\\..\\.\\c.h"] = Replacements();
982 FileToReplaces["..\\..\\a\\c.h"] = Replacements();
983#endif
Eric Liucefe7632016-10-14 09:32:06 +0000984 FileToReplaces = groupReplacementsByFile(FileToReplaces);
985 EXPECT_EQ(1u, FileToReplaces.size());
Eric Liuc45343e2016-10-14 10:10:26 +0000986#if !defined(LLVM_ON_WIN32)
Eric Liucefe7632016-10-14 09:32:06 +0000987 EXPECT_EQ("../../a/c.h", FileToReplaces.begin()->first);
Eric Liuc45343e2016-10-14 10:10:26 +0000988#else
989 EXPECT_EQ("..\\..\\a\\c.h", FileToReplaces.begin()->first);
990#endif
Eric Liucefe7632016-10-14 09:32:06 +0000991}
992
993TEST(DeduplicateByFileTest, RemoveDotSlash) {
994 std::map<std::string, Replacements> FileToReplaces;
Eric Liuc45343e2016-10-14 10:10:26 +0000995#if !defined(LLVM_ON_WIN32)
Eric Liucefe7632016-10-14 09:32:06 +0000996 FileToReplaces["./a/b/.././c.h"] = Replacements();
997 FileToReplaces["a/c.h"] = Replacements();
Eric Liuc45343e2016-10-14 10:10:26 +0000998#else
999 FileToReplaces[".\\a\\b\\..\\.\\c.h"] = Replacements();
1000 FileToReplaces["a\\c.h"] = Replacements();
1001#endif
Eric Liucefe7632016-10-14 09:32:06 +00001002 FileToReplaces = groupReplacementsByFile(FileToReplaces);
1003 EXPECT_EQ(1u, FileToReplaces.size());
Eric Liuc45343e2016-10-14 10:10:26 +00001004#if !defined(LLVM_ON_WIN32)
Eric Liucefe7632016-10-14 09:32:06 +00001005 EXPECT_EQ("a/c.h", FileToReplaces.begin()->first);
Eric Liuc45343e2016-10-14 10:10:26 +00001006#else
1007 EXPECT_EQ("a\\c.h", FileToReplaces.begin()->first);
1008#endif
Eric Liucefe7632016-10-14 09:32:06 +00001009}
1010
Manuel Klimek3f001342012-05-23 16:29:20 +00001011} // end namespace tooling
1012} // end namespace clang