blob: 2267897d03509929e0871248e8cde21253b0009d [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 virtual ~IncludeInserterCheckBase() {}
35
Manuel Klimekd00d6f12015-08-11 11:37:48 +000036 void registerPPCallbacks(CompilerInstance &Compiler) override {
37 Inserter.reset(new IncludeInserter(Compiler.getSourceManager(),
38 Compiler.getLangOpts(),
39 IncludeSorter::IS_Google));
40 Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
41 }
42
43 void registerMatchers(ast_matchers::MatchFinder *Finder) override {
44 Finder->addMatcher(ast_matchers::declStmt().bind("stmt"), this);
45 }
46
47 void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000048 auto Diag = diag(Result.Nodes.getStmtAs<DeclStmt>("stmt")->getLocStart(),
49 "foo, bar");
50 for (StringRef header : HeadersToInclude()) {
51 auto Fixit = Inserter->CreateIncludeInsertion(
52 Result.SourceManager->getMainFileID(), header, IsAngledInclude());
53 if (Fixit) {
54 Diag << *Fixit;
55 }
Manuel Klimekd00d6f12015-08-11 11:37:48 +000056 }
Manuel Klimekd00d6f12015-08-11 11:37:48 +000057 }
58
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000059 virtual std::vector<StringRef> HeadersToInclude() const = 0;
Manuel Klimekd00d6f12015-08-11 11:37:48 +000060 virtual bool IsAngledInclude() const = 0;
61
62 std::unique_ptr<IncludeInserter> Inserter;
63};
64
65class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase {
66public:
Manuel Klimek46e82c32015-08-11 12:59:22 +000067 NonSystemHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
68 : IncludeInserterCheckBase(CheckName, Context) {}
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000069 virtual ~NonSystemHeaderInserterCheck() {}
70
71 std::vector<StringRef> HeadersToInclude() const override {
72 return {"path/to/header.h"};
73 }
74 bool IsAngledInclude() const override { return false; }
75};
76
77class MultipleHeaderInserterCheck : public IncludeInserterCheckBase {
78public:
79 MultipleHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
80 : IncludeInserterCheckBase(CheckName, Context) {}
81 virtual ~MultipleHeaderInserterCheck() {}
82
83 std::vector<StringRef> HeadersToInclude() const override {
84 return {"path/to/header.h", "path/to/header2.h", "path/to/header.h"};
85 }
Manuel Klimekd00d6f12015-08-11 11:37:48 +000086 bool IsAngledInclude() const override { return false; }
87};
88
Alexander Kornienko8cc024e2015-08-14 12:33:25 +000089class CSystemIncludeInserterCheck : public IncludeInserterCheckBase {
90public:
Alexander Kornienko078ab132015-08-14 13:23:55 +000091 CSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
92 : IncludeInserterCheckBase(CheckName, Context) {}
Daniel Jasperd30dc3f2015-08-19 21:02:27 +000093 virtual ~CSystemIncludeInserterCheck() {}
94
95 std::vector<StringRef> HeadersToInclude() const override {
96 return {"stdlib.h"};
97 }
Alexander Kornienko8cc024e2015-08-14 12:33:25 +000098 bool IsAngledInclude() const override { return true; }
99};
100
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000101class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {
102public:
Manuel Klimek46e82c32015-08-11 12:59:22 +0000103 CXXSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
104 : IncludeInserterCheckBase(CheckName, Context) {}
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000105 virtual ~CXXSystemIncludeInserterCheck() {}
106
107 std::vector<StringRef> HeadersToInclude() const override { return {"set"}; }
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000108 bool IsAngledInclude() const override { return true; }
109};
110
111template <typename Check>
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000112std::string runCheckOnCode(StringRef Code, StringRef Filename) {
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000113 std::vector<ClangTidyError> Errors;
114 return test::runCheckOnCode<Check>(Code, &Errors, Filename, None,
115 ClangTidyOptions(),
116 {// Main file include
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000117 {"clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000118 "insert_includes_test_header.h",
119 "\n"},
120 // Non system headers
121 {"path/to/a/header.h", "\n"},
122 {"path/to/z/header.h", "\n"},
123 {"path/to/header.h", "\n"},
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000124 {"path/to/header2.h", "\n"},
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000125 // Fake system headers.
126 {"stdlib.h", "\n"},
127 {"unistd.h", "\n"},
128 {"list", "\n"},
129 {"map", "\n"},
130 {"set", "\n"},
131 {"vector", "\n"}});
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000132}
133
134TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) {
135 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000136#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000137
138#include <list>
139#include <map>
140
141#include "path/to/a/header.h"
142
143void foo() {
144 int a = 0;
145})";
146 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000147#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000148
149#include <list>
150#include <map>
151
152#include "path/to/a/header.h"
153#include "path/to/header.h"
154
155void foo() {
156 int a = 0;
157})";
158
159 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000160 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000161 "insert_includes_test_input2.cc"));
162}
163
164TEST(IncludeInserterTest, InsertMultipleIncludesAndDeduplicate) {
165 const char *PreCode = R"(
166#include "clang_tidy/tests/insert_includes_test_header.h"
167
168#include <list>
169#include <map>
170
171#include "path/to/a/header.h"
172
173void foo() {
174 int a = 0;
175})";
176 const char *PostCode = R"(
177#include "clang_tidy/tests/insert_includes_test_header.h"
178
179#include <list>
180#include <map>
181
182#include "path/to/a/header.h"
183#include "path/to/header.h"
184#include "path/to/header2.h"
185
186void foo() {
187 int a = 0;
188})";
189
190 EXPECT_EQ(PostCode, runCheckOnCode<MultipleHeaderInserterCheck>(
191 PreCode, "clang_tidy/tests/"
192 "insert_includes_test_input2.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000193}
194
195TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) {
196 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000197#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000198
199#include <list>
200#include <map>
201
202#include "path/to/z/header.h"
203
204void foo() {
205 int a = 0;
206})";
207 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000208#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000209
210#include <list>
211#include <map>
212
213#include "path/to/header.h"
214#include "path/to/z/header.h"
215
216void foo() {
217 int a = 0;
218})";
219
220 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000221 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000222 "insert_includes_test_input2.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000223}
224
225TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) {
226 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000227#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000228
229#include <list>
230#include <map>
231
232#include "path/to/a/header.h"
233#include "path/to/z/header.h"
234
235void foo() {
236 int a = 0;
237})";
238 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000239#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000240
241#include <list>
242#include <map>
243
244#include "path/to/a/header.h"
245#include "path/to/header.h"
246#include "path/to/z/header.h"
247
248void foo() {
249 int a = 0;
250})";
251
252 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000253 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000254 "insert_includes_test_input2.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000255}
256
257TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) {
258 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000259#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000260
261#include <list>
262#include <map>
263
264#include "path/to/a/header.h"
265#include "path/to/header.h"
266#include "path/to/z/header.h"
267
268void foo() {
269 int a = 0;
270})";
271 EXPECT_EQ(PreCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000272 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000273 "insert_includes_test_input2.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000274}
275
276TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) {
277 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000278#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000279
280#include <list>
281#include <map>
282
283void foo() {
284 int a = 0;
285})";
286 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000287#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000288
289#include <list>
290#include <map>
291
292#include "path/to/header.h"
293
294void foo() {
295 int a = 0;
296})";
297
298 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000299 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000300 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000301}
302
303TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {
304 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000305#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000306
307void foo() {
308 int a = 0;
309})";
310 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000311#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000312
313#include "path/to/header.h"
314
315void foo() {
316 int a = 0;
317})";
318
319 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000320 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000321 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000322}
323
324TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) {
325 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000326#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000327
328#include <list>
329#include <map>
330
331#include "path/to/a/header.h"
332
333void foo() {
334 int a = 0;
335})";
336 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000337#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000338
339#include <list>
340#include <map>
341#include <set>
342
343#include "path/to/a/header.h"
344
345void foo() {
346 int a = 0;
347})";
348
349 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000350 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000351 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000352}
353
354TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) {
355 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000356#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000357
358#include <vector>
359
360#include "path/to/a/header.h"
361
362void foo() {
363 int a = 0;
364})";
365 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000366#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000367
368#include <set>
369#include <vector>
370
371#include "path/to/a/header.h"
372
373void foo() {
374 int a = 0;
375})";
376
377 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000378 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000379 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000380}
381
382TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) {
383 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000384#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000385
386#include <map>
387#include <vector>
388
389#include "path/to/a/header.h"
390
391void foo() {
392 int a = 0;
393})";
394 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000395#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000396
397#include <map>
398#include <set>
399#include <vector>
400
401#include "path/to/a/header.h"
402
403void foo() {
404 int a = 0;
405})";
406
407 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000408 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000409 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000410}
411
412TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) {
413 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000414#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000415
416#include "path/to/a/header.h"
417
418void foo() {
419 int a = 0;
420})";
421 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000422#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000423
424#include <set>
425
426#include "path/to/a/header.h"
427
428void foo() {
429 int a = 0;
430})";
431
432 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000433 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000434 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000435}
436
437TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) {
438 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000439#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000440
441#include <stdlib.h>
442
443#include "path/to/a/header.h"
444
445void foo() {
446 int a = 0;
447})";
448 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000449#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000450
451#include <stdlib.h>
452
453#include <set>
454
455#include "path/to/a/header.h"
456
457void foo() {
458 int a = 0;
459})";
460
461 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000462 PreCode, "clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000463 "insert_includes_test_header.cc"));
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000464}
465
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000466TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) {
467 const char *PreCode = R"(
468#include "path/to/a/header.h"
469
470void foo() {
471 int a = 0;
472})";
473 const char *PostCode = R"(
474#include <set>
475
476#include "path/to/a/header.h"
477
478void foo() {
479 int a = 0;
480})";
481
482 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
483 PreCode, "devtools/cymbal/clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000484 "insert_includes_test_header.cc"));
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000485}
486
487TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) {
488 const char *PreCode = R"(
489#include <set>
490
491#include "path/to/a/header.h"
492
493void foo() {
494 int a = 0;
495})";
496 const char *PostCode = R"(
497#include <stdlib.h>
498
499#include <set>
500
501#include "path/to/a/header.h"
502
503void foo() {
504 int a = 0;
505})";
506
507 EXPECT_EQ(PostCode, runCheckOnCode<CSystemIncludeInserterCheck>(
508 PreCode, "devtools/cymbal/clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000509 "insert_includes_test_header.cc"));
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000510}
511
512TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) {
513 const char *PreCode = R"(
514void foo() {
515 int a = 0;
516})";
517 const char *PostCode = R"(#include <set>
518
519
520void foo() {
521 int a = 0;
522})";
523
524 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
525 PreCode, "devtools/cymbal/clang_tidy/tests/"
Daniel Jasperd30dc3f2015-08-19 21:02:27 +0000526 "insert_includes_test_header.cc"));
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000527}
528
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000529} // namespace
530} // namespace tidy
531} // namespace clang
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000532
Alexander Kornienko078ab132015-08-14 13:23:55 +0000533#endif