blob: eb55830019c0a92fb65ceeace577bbfe9822ca4f [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) {}
Manuel Klimekd00d6f12015-08-11 11:37:48 +000034 void registerPPCallbacks(CompilerInstance &Compiler) override {
35 Inserter.reset(new IncludeInserter(Compiler.getSourceManager(),
36 Compiler.getLangOpts(),
37 IncludeSorter::IS_Google));
38 Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
39 }
40
41 void registerMatchers(ast_matchers::MatchFinder *Finder) override {
42 Finder->addMatcher(ast_matchers::declStmt().bind("stmt"), this);
43 }
44
45 void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
46 auto Fixit =
47 Inserter->CreateIncludeInsertion(Result.SourceManager->getMainFileID(),
48 HeaderToInclude(), IsAngledInclude());
49 if (Fixit) {
50 diag(Result.Nodes.getStmtAs<DeclStmt>("stmt")->getLocStart(), "foo, bar")
51 << *Fixit;
52 }
53 // Second include should yield no Fixit.
54 Fixit =
55 Inserter->CreateIncludeInsertion(Result.SourceManager->getMainFileID(),
56 HeaderToInclude(), IsAngledInclude());
57 EXPECT_FALSE(Fixit);
58 }
59
60 virtual StringRef HeaderToInclude() const = 0;
61 virtual bool IsAngledInclude() const = 0;
62
63 std::unique_ptr<IncludeInserter> Inserter;
64};
65
66class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase {
67public:
Manuel Klimek46e82c32015-08-11 12:59:22 +000068 NonSystemHeaderInserterCheck(StringRef CheckName, ClangTidyContext *Context)
69 : IncludeInserterCheckBase(CheckName, Context) {}
Manuel Klimekd00d6f12015-08-11 11:37:48 +000070 StringRef HeaderToInclude() const override { return "path/to/header.h"; }
71 bool IsAngledInclude() const override { return false; }
72};
73
Alexander Kornienko8cc024e2015-08-14 12:33:25 +000074class CSystemIncludeInserterCheck : public IncludeInserterCheckBase {
75public:
Alexander Kornienko078ab132015-08-14 13:23:55 +000076 CSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
77 : IncludeInserterCheckBase(CheckName, Context) {}
Alexander Kornienko8cc024e2015-08-14 12:33:25 +000078 StringRef HeaderToInclude() const override { return "stdlib.h"; }
79 bool IsAngledInclude() const override { return true; }
80};
81
Manuel Klimekd00d6f12015-08-11 11:37:48 +000082class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {
83public:
Manuel Klimek46e82c32015-08-11 12:59:22 +000084 CXXSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
85 : IncludeInserterCheckBase(CheckName, Context) {}
Manuel Klimekd00d6f12015-08-11 11:37:48 +000086 StringRef HeaderToInclude() const override { return "set"; }
87 bool IsAngledInclude() const override { return true; }
88};
89
90template <typename Check>
91std::string runCheckOnCode(StringRef Code, StringRef Filename,
92 size_t NumWarningsExpected) {
93 std::vector<ClangTidyError> Errors;
94 return test::runCheckOnCode<Check>(Code, &Errors, Filename, None,
95 ClangTidyOptions(),
96 {// Main file include
Manuel Klimeke8c8d882015-08-11 14:21:26 +000097 {"clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +000098 "insert_includes_test_header.h",
99 "\n"},
100 // Non system headers
101 {"path/to/a/header.h", "\n"},
102 {"path/to/z/header.h", "\n"},
103 {"path/to/header.h", "\n"},
104 // Fake system headers.
105 {"stdlib.h", "\n"},
106 {"unistd.h", "\n"},
107 {"list", "\n"},
108 {"map", "\n"},
109 {"set", "\n"},
110 {"vector", "\n"}});
111 EXPECT_EQ(NumWarningsExpected, Errors.size());
112}
113
114TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) {
115 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000116#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000117
118#include <list>
119#include <map>
120
121#include "path/to/a/header.h"
122
123void foo() {
124 int a = 0;
125})";
126 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000127#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000128
129#include <list>
130#include <map>
131
132#include "path/to/a/header.h"
133#include "path/to/header.h"
134
135void foo() {
136 int a = 0;
137})";
138
139 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000140 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000141 "insert_includes_test_input2.cc",
142 1));
143}
144
145TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) {
146 const char *PreCode = 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/z/header.h"
153
154void foo() {
155 int a = 0;
156})";
157 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000158#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000159
160#include <list>
161#include <map>
162
163#include "path/to/header.h"
164#include "path/to/z/header.h"
165
166void foo() {
167 int a = 0;
168})";
169
170 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000171 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000172 "insert_includes_test_input2.cc",
173 1));
174}
175
176TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) {
177 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000178#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000179
180#include <list>
181#include <map>
182
183#include "path/to/a/header.h"
184#include "path/to/z/header.h"
185
186void foo() {
187 int a = 0;
188})";
189 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000190#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000191
192#include <list>
193#include <map>
194
195#include "path/to/a/header.h"
196#include "path/to/header.h"
197#include "path/to/z/header.h"
198
199void foo() {
200 int a = 0;
201})";
202
203 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000204 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000205 "insert_includes_test_input2.cc",
206 1));
207}
208
209TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) {
210 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000211#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000212
213#include <list>
214#include <map>
215
216#include "path/to/a/header.h"
217#include "path/to/header.h"
218#include "path/to/z/header.h"
219
220void foo() {
221 int a = 0;
222})";
223 EXPECT_EQ(PreCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000224 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000225 "insert_includes_test_input2.cc",
226 0));
227}
228
229TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) {
230 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000231#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000232
233#include <list>
234#include <map>
235
236void foo() {
237 int a = 0;
238})";
239 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000240#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000241
242#include <list>
243#include <map>
244
245#include "path/to/header.h"
246
247void foo() {
248 int a = 0;
249})";
250
251 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000252 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000253 "insert_includes_test_header.cc",
254 1));
255}
256
257TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {
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
261void foo() {
262 int a = 0;
263})";
264 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000265#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000266
267#include "path/to/header.h"
268
269void foo() {
270 int a = 0;
271})";
272
273 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000274 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000275 "insert_includes_test_header.cc",
276 1));
277}
278
279TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) {
280 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000281#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000282
283#include <list>
284#include <map>
285
286#include "path/to/a/header.h"
287
288void foo() {
289 int a = 0;
290})";
291 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000292#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000293
294#include <list>
295#include <map>
296#include <set>
297
298#include "path/to/a/header.h"
299
300void foo() {
301 int a = 0;
302})";
303
304 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000305 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000306 "insert_includes_test_header.cc",
307 1));
308}
309
310TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) {
311 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000312#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000313
314#include <vector>
315
316#include "path/to/a/header.h"
317
318void foo() {
319 int a = 0;
320})";
321 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000322#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000323
324#include <set>
325#include <vector>
326
327#include "path/to/a/header.h"
328
329void foo() {
330 int a = 0;
331})";
332
333 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000334 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000335 "insert_includes_test_header.cc",
336 1));
337}
338
339TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) {
340 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000341#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000342
343#include <map>
344#include <vector>
345
346#include "path/to/a/header.h"
347
348void foo() {
349 int a = 0;
350})";
351 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000352#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000353
354#include <map>
355#include <set>
356#include <vector>
357
358#include "path/to/a/header.h"
359
360void foo() {
361 int a = 0;
362})";
363
364 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000365 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000366 "insert_includes_test_header.cc",
367 1));
368}
369
370TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) {
371 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000372#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000373
374#include "path/to/a/header.h"
375
376void foo() {
377 int a = 0;
378})";
379 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000380#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000381
382#include <set>
383
384#include "path/to/a/header.h"
385
386void foo() {
387 int a = 0;
388})";
389
390 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000391 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000392 "insert_includes_test_header.cc",
393 1));
394}
395
396TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) {
397 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000398#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000399
400#include <stdlib.h>
401
402#include "path/to/a/header.h"
403
404void foo() {
405 int a = 0;
406})";
407 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000408#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000409
410#include <stdlib.h>
411
412#include <set>
413
414#include "path/to/a/header.h"
415
416void foo() {
417 int a = 0;
418})";
419
420 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000421 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000422 "insert_includes_test_header.cc",
423 1));
424}
425
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000426TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) {
427 const char *PreCode = R"(
428#include "path/to/a/header.h"
429
430void foo() {
431 int a = 0;
432})";
433 const char *PostCode = R"(
434#include <set>
435
436#include "path/to/a/header.h"
437
438void foo() {
439 int a = 0;
440})";
441
442 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
443 PreCode, "devtools/cymbal/clang_tidy/tests/"
444 "insert_includes_test_header.cc",
445 1));
446}
447
448TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) {
449 const char *PreCode = R"(
450#include <set>
451
452#include "path/to/a/header.h"
453
454void foo() {
455 int a = 0;
456})";
457 const char *PostCode = R"(
458#include <stdlib.h>
459
460#include <set>
461
462#include "path/to/a/header.h"
463
464void foo() {
465 int a = 0;
466})";
467
468 EXPECT_EQ(PostCode, runCheckOnCode<CSystemIncludeInserterCheck>(
469 PreCode, "devtools/cymbal/clang_tidy/tests/"
470 "insert_includes_test_header.cc",
471 1));
472}
473
474TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) {
475 const char *PreCode = R"(
476void foo() {
477 int a = 0;
478})";
479 const char *PostCode = R"(#include <set>
480
481
482void foo() {
483 int a = 0;
484})";
485
486 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
487 PreCode, "devtools/cymbal/clang_tidy/tests/"
488 "insert_includes_test_header.cc",
489 1));
490}
491
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000492} // namespace
493} // namespace tidy
494} // namespace clang
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000495
Alexander Kornienko078ab132015-08-14 13:23:55 +0000496#endif