blob: d21afbb274dfe7b1d333f8ea50ce76e17bc92325 [file] [log] [blame]
Manuel Klimekd00d6f12015-08-11 11:37:48 +00001//===---- IncludeInserterTest.cpp - clang-tidy ----------------------------===//
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
Alexander Kornienko5f252ca2015-08-14 14:31:31 +000010#include "../clang-tidy/utils/IncludeInserter.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +000011#include "clang/Lex/Preprocessor.h"
12#include "clang/Frontend/CompilerInstance.h"
13#include "ClangTidyTest.h"
14#include "gtest/gtest.h"
15
Manuel Klimeke8c8d882015-08-11 14:21:26 +000016// FIXME: Canonicalize paths correctly on windows.
17// Currently, adding virtual files will canonicalize the paths before
18// storing the virtual entries.
19// When resolving virtual entries in the FileManager, the paths (for
20// example coming from a #include directive) are not canonicalized
21// to native paths; thus, the virtual file is not found.
22// This needs to be fixed in the FileManager before we can make
23// clang-tidy tests work.
24#if !defined(_WIN32)
25
Manuel Klimekd00d6f12015-08-11 11:37:48 +000026namespace clang {
27namespace tidy {
28namespace {
29
30class IncludeInserterCheckBase : public ClangTidyCheck {
31public:
Manuel Klimek46e82c32015-08-11 12:59:22 +000032 IncludeInserterCheckBase(StringRef CheckName, ClangTidyContext *Context)
33 : ClangTidyCheck(CheckName, Context) {}
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000034
Manuel Klimekd00d6f12015-08-11 11:37:48 +000035 void registerPPCallbacks(CompilerInstance &Compiler) override {
36 Inserter.reset(new IncludeInserter(Compiler.getSourceManager(),
37 Compiler.getLangOpts(),
38 IncludeSorter::IS_Google));
39 Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
40 }
41
42 void registerMatchers(ast_matchers::MatchFinder *Finder) override {
43 Finder->addMatcher(ast_matchers::declStmt().bind("stmt"), this);
44 }
45
46 void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000047 auto Diag = diag(Result.Nodes.getStmtAs<DeclStmt>("stmt")->getLocStart(),
48 "foo, bar");
49 for (StringRef header : HeadersToInclude()) {
50 auto Fixit = Inserter->CreateIncludeInsertion(
51 Result.SourceManager->getMainFileID(), header, IsAngledInclude());
52 if (Fixit) {
53 Diag << *Fixit;
54 }
Manuel Klimekd00d6f12015-08-11 11:37:48 +000055 }
Manuel Klimekd00d6f12015-08-11 11:37:48 +000056 }
57
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000058 virtual std::vector<StringRef> HeadersToInclude() const = 0;
Manuel Klimekd00d6f12015-08-11 11:37:48 +000059 virtual bool IsAngledInclude() const = 0;
60
61 std::unique_ptr<IncludeInserter> Inserter;
62};
63
64class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase {
65public:
Manuel Klimek46e82c32015-08-11 12:59:22 +000066 NonSystemHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
67 : IncludeInserterCheckBase(CheckName, Context) {}
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000068
69 std::vector<StringRef> HeadersToInclude() const override {
70 return {"path/to/header.h"};
71 }
72 bool IsAngledInclude() const override { return false; }
73};
74
75class MultipleHeaderInserterCheck : public IncludeInserterCheckBase {
76public:
77 MultipleHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
78 : IncludeInserterCheckBase(CheckName, Context) {}
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000079
80 std::vector<StringRef> HeadersToInclude() const override {
81 return {"path/to/header.h", "path/to/header2.h", "path/to/header.h"};
82 }
Manuel Klimekd00d6f12015-08-11 11:37:48 +000083 bool IsAngledInclude() const override { return false; }
84};
85
Alexander Kornienko8cc024e2015-08-14 12:33:25 +000086class CSystemIncludeInserterCheck : public IncludeInserterCheckBase {
87public:
Alexander Kornienko078ab132015-08-14 13:23:55 +000088 CSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
89 : IncludeInserterCheckBase(CheckName, Context) {}
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000090
91 std::vector<StringRef> HeadersToInclude() const override {
92 return {"stdlib.h"};
93 }
Alexander Kornienko8cc024e2015-08-14 12:33:25 +000094 bool IsAngledInclude() const override { return true; }
95};
96
Manuel Klimekd00d6f12015-08-11 11:37:48 +000097class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {
98public:
Manuel Klimek46e82c32015-08-11 12:59:22 +000099 CXXSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
100 : IncludeInserterCheckBase(CheckName, Context) {}
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000101
102 std::vector<StringRef> HeadersToInclude() const override { return {"set"}; }
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000103 bool IsAngledInclude() const override { return true; }
104};
105
106template <typename Check>
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000107std::string runCheckOnCode(StringRef Code, StringRef Filename) {
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000108 std::vector<ClangTidyError> Errors;
109 return test::runCheckOnCode<Check>(Code, &Errors, Filename, None,
110 ClangTidyOptions(),
111 {// Main file include
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000112 {"clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000113 "insert_includes_test_header.h",
114 "\n"},
115 // Non system headers
116 {"path/to/a/header.h", "\n"},
117 {"path/to/z/header.h", "\n"},
118 {"path/to/header.h", "\n"},
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000119 {"path/to/header2.h", "\n"},
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000120 // Fake system headers.
121 {"stdlib.h", "\n"},
122 {"unistd.h", "\n"},
123 {"list", "\n"},
124 {"map", "\n"},
125 {"set", "\n"},
126 {"vector", "\n"}});
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000127}
128
129TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) {
130 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000131#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000132
133#include <list>
134#include <map>
135
136#include "path/to/a/header.h"
137
138void foo() {
139 int a = 0;
140})";
141 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000142#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000143
144#include <list>
145#include <map>
146
147#include "path/to/a/header.h"
148#include "path/to/header.h"
149
150void foo() {
151 int a = 0;
152})";
153
154 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000155 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000156 "insert_includes_test_input2.cc"));
157}
158
159TEST(IncludeInserterTest, InsertMultipleIncludesAndDeduplicate) {
160 const char *PreCode = R"(
161#include "clang_tidy/tests/insert_includes_test_header.h"
162
163#include <list>
164#include <map>
165
166#include "path/to/a/header.h"
167
168void foo() {
169 int a = 0;
170})";
171 const char *PostCode = R"(
172#include "clang_tidy/tests/insert_includes_test_header.h"
173
174#include <list>
175#include <map>
176
177#include "path/to/a/header.h"
178#include "path/to/header.h"
179#include "path/to/header2.h"
180
181void foo() {
182 int a = 0;
183})";
184
185 EXPECT_EQ(PostCode, runCheckOnCode<MultipleHeaderInserterCheck>(
186 PreCode, "clang_tidy/tests/"
187 "insert_includes_test_input2.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000188}
189
190TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) {
191 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000192#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000193
194#include <list>
195#include <map>
196
197#include "path/to/z/header.h"
198
199void foo() {
200 int a = 0;
201})";
202 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000203#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000204
205#include <list>
206#include <map>
207
208#include "path/to/header.h"
209#include "path/to/z/header.h"
210
211void foo() {
212 int a = 0;
213})";
214
215 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000216 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000217 "insert_includes_test_input2.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000218}
219
220TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) {
221 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000222#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000223
224#include <list>
225#include <map>
226
227#include "path/to/a/header.h"
228#include "path/to/z/header.h"
229
230void foo() {
231 int a = 0;
232})";
233 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000234#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000235
236#include <list>
237#include <map>
238
239#include "path/to/a/header.h"
240#include "path/to/header.h"
241#include "path/to/z/header.h"
242
243void foo() {
244 int a = 0;
245})";
246
247 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000248 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000249 "insert_includes_test_input2.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000250}
251
252TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) {
253 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000254#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000255
256#include <list>
257#include <map>
258
259#include "path/to/a/header.h"
260#include "path/to/header.h"
261#include "path/to/z/header.h"
262
263void foo() {
264 int a = 0;
265})";
266 EXPECT_EQ(PreCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000267 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000268 "insert_includes_test_input2.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000269}
270
271TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) {
272 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000273#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000274
275#include <list>
276#include <map>
277
278void foo() {
279 int a = 0;
280})";
281 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000282#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000283
284#include <list>
285#include <map>
286
287#include "path/to/header.h"
288
289void foo() {
290 int a = 0;
291})";
292
293 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000294 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000295 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000296}
297
298TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {
299 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000300#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000301
302void foo() {
303 int a = 0;
304})";
305 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000306#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000307
308#include "path/to/header.h"
309
310void foo() {
311 int a = 0;
312})";
313
314 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000315 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000316 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000317}
318
319TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) {
320 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000321#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000322
323#include <list>
324#include <map>
325
326#include "path/to/a/header.h"
327
328void foo() {
329 int a = 0;
330})";
331 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000332#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000333
334#include <list>
335#include <map>
336#include <set>
337
338#include "path/to/a/header.h"
339
340void foo() {
341 int a = 0;
342})";
343
344 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000345 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000346 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000347}
348
349TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) {
350 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000351#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000352
353#include <vector>
354
355#include "path/to/a/header.h"
356
357void foo() {
358 int a = 0;
359})";
360 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000361#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000362
363#include <set>
364#include <vector>
365
366#include "path/to/a/header.h"
367
368void foo() {
369 int a = 0;
370})";
371
372 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000373 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000374 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000375}
376
377TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) {
378 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000379#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000380
381#include <map>
382#include <vector>
383
384#include "path/to/a/header.h"
385
386void foo() {
387 int a = 0;
388})";
389 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000390#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000391
392#include <map>
393#include <set>
394#include <vector>
395
396#include "path/to/a/header.h"
397
398void foo() {
399 int a = 0;
400})";
401
402 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000403 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000404 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000405}
406
407TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) {
408 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000409#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000410
411#include "path/to/a/header.h"
412
413void foo() {
414 int a = 0;
415})";
416 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000417#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000418
419#include <set>
420
421#include "path/to/a/header.h"
422
423void foo() {
424 int a = 0;
425})";
426
427 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000428 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000429 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000430}
431
432TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) {
433 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000434#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000435
436#include <stdlib.h>
437
438#include "path/to/a/header.h"
439
440void foo() {
441 int a = 0;
442})";
443 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000444#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000445
446#include <stdlib.h>
447
448#include <set>
449
450#include "path/to/a/header.h"
451
452void foo() {
453 int a = 0;
454})";
455
456 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000457 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000458 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000459}
460
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000461TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) {
462 const char *PreCode = R"(
463#include "path/to/a/header.h"
464
465void foo() {
466 int a = 0;
467})";
468 const char *PostCode = R"(
469#include <set>
470
471#include "path/to/a/header.h"
472
473void foo() {
474 int a = 0;
475})";
476
477 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
478 PreCode, "devtools/cymbal/clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000479 "insert_includes_test_header.cc"));
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000480}
481
482TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) {
483 const char *PreCode = R"(
484#include <set>
485
486#include "path/to/a/header.h"
487
488void foo() {
489 int a = 0;
490})";
491 const char *PostCode = R"(
492#include <stdlib.h>
493
494#include <set>
495
496#include "path/to/a/header.h"
497
498void foo() {
499 int a = 0;
500})";
501
502 EXPECT_EQ(PostCode, runCheckOnCode<CSystemIncludeInserterCheck>(
503 PreCode, "devtools/cymbal/clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000504 "insert_includes_test_header.cc"));
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000505}
506
507TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) {
508 const char *PreCode = R"(
509void foo() {
510 int a = 0;
511})";
512 const char *PostCode = R"(#include <set>
513
514
515void foo() {
516 int a = 0;
517})";
518
519 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
520 PreCode, "devtools/cymbal/clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000521 "insert_includes_test_header.cc"));
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000522}
523
Eugene Zelenko7da47b82016-01-26 22:32:24 +0000524} // anonymous namespace
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000525} // namespace tidy
526} // namespace clang
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000527
Alexander Kornienko078ab132015-08-14 13:23:55 +0000528#endif