blob: 8801e3e1bb67ead39f2a5335a829c9bdad9fb67c [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
10#include "../clang-tidy/IncludeInserter.h"
11#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:
76 using IncludeInserterCheckBase::IncludeInserterCheckBase;
77 StringRef HeaderToInclude() const override { return "stdlib.h"; }
78 bool IsAngledInclude() const override { return true; }
79};
80
Manuel Klimekd00d6f12015-08-11 11:37:48 +000081class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {
82public:
Manuel Klimek46e82c32015-08-11 12:59:22 +000083 CXXSystemIncludeInserterCheck(StringRef CheckName, ClangTidyContext *Context)
84 : IncludeInserterCheckBase(CheckName, Context) {}
Manuel Klimekd00d6f12015-08-11 11:37:48 +000085 StringRef HeaderToInclude() const override { return "set"; }
86 bool IsAngledInclude() const override { return true; }
87};
88
89template <typename Check>
90std::string runCheckOnCode(StringRef Code, StringRef Filename,
91 size_t NumWarningsExpected) {
92 std::vector<ClangTidyError> Errors;
93 return test::runCheckOnCode<Check>(Code, &Errors, Filename, None,
94 ClangTidyOptions(),
95 {// Main file include
Manuel Klimeke8c8d882015-08-11 14:21:26 +000096 {"clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +000097 "insert_includes_test_header.h",
98 "\n"},
99 // Non system headers
100 {"path/to/a/header.h", "\n"},
101 {"path/to/z/header.h", "\n"},
102 {"path/to/header.h", "\n"},
103 // Fake system headers.
104 {"stdlib.h", "\n"},
105 {"unistd.h", "\n"},
106 {"list", "\n"},
107 {"map", "\n"},
108 {"set", "\n"},
109 {"vector", "\n"}});
110 EXPECT_EQ(NumWarningsExpected, Errors.size());
111}
112
113TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) {
114 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000115#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000116
117#include <list>
118#include <map>
119
120#include "path/to/a/header.h"
121
122void foo() {
123 int a = 0;
124})";
125 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000126#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000127
128#include <list>
129#include <map>
130
131#include "path/to/a/header.h"
132#include "path/to/header.h"
133
134void foo() {
135 int a = 0;
136})";
137
138 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000139 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000140 "insert_includes_test_input2.cc",
141 1));
142}
143
144TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) {
145 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000146#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000147
148#include <list>
149#include <map>
150
151#include "path/to/z/header.h"
152
153void foo() {
154 int a = 0;
155})";
156 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000157#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000158
159#include <list>
160#include <map>
161
162#include "path/to/header.h"
163#include "path/to/z/header.h"
164
165void foo() {
166 int a = 0;
167})";
168
169 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000170 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000171 "insert_includes_test_input2.cc",
172 1));
173}
174
175TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) {
176 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000177#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000178
179#include <list>
180#include <map>
181
182#include "path/to/a/header.h"
183#include "path/to/z/header.h"
184
185void foo() {
186 int a = 0;
187})";
188 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000189#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000190
191#include <list>
192#include <map>
193
194#include "path/to/a/header.h"
195#include "path/to/header.h"
196#include "path/to/z/header.h"
197
198void foo() {
199 int a = 0;
200})";
201
202 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000203 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000204 "insert_includes_test_input2.cc",
205 1));
206}
207
208TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) {
209 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000210#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000211
212#include <list>
213#include <map>
214
215#include "path/to/a/header.h"
216#include "path/to/header.h"
217#include "path/to/z/header.h"
218
219void foo() {
220 int a = 0;
221})";
222 EXPECT_EQ(PreCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000223 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000224 "insert_includes_test_input2.cc",
225 0));
226}
227
228TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) {
229 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000230#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000231
232#include <list>
233#include <map>
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/header.h"
245
246void foo() {
247 int a = 0;
248})";
249
250 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000251 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000252 "insert_includes_test_header.cc",
253 1));
254}
255
256TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {
257 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000258#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000259
260void foo() {
261 int a = 0;
262})";
263 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000264#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000265
266#include "path/to/header.h"
267
268void foo() {
269 int a = 0;
270})";
271
272 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000273 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000274 "insert_includes_test_header.cc",
275 1));
276}
277
278TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) {
279 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000280#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000281
282#include <list>
283#include <map>
284
285#include "path/to/a/header.h"
286
287void foo() {
288 int a = 0;
289})";
290 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000291#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000292
293#include <list>
294#include <map>
295#include <set>
296
297#include "path/to/a/header.h"
298
299void foo() {
300 int a = 0;
301})";
302
303 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000304 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000305 "insert_includes_test_header.cc",
306 1));
307}
308
309TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) {
310 const char *PreCode = 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 <vector>
314
315#include "path/to/a/header.h"
316
317void foo() {
318 int a = 0;
319})";
320 const char *PostCode = 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 <set>
324#include <vector>
325
326#include "path/to/a/header.h"
327
328void foo() {
329 int a = 0;
330})";
331
332 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000333 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000334 "insert_includes_test_header.cc",
335 1));
336}
337
338TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) {
339 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000340#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000341
342#include <map>
343#include <vector>
344
345#include "path/to/a/header.h"
346
347void foo() {
348 int a = 0;
349})";
350 const char *PostCode = 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 <map>
354#include <set>
355#include <vector>
356
357#include "path/to/a/header.h"
358
359void foo() {
360 int a = 0;
361})";
362
363 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000364 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000365 "insert_includes_test_header.cc",
366 1));
367}
368
369TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) {
370 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000371#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000372
373#include "path/to/a/header.h"
374
375void foo() {
376 int a = 0;
377})";
378 const char *PostCode = 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 <set>
382
383#include "path/to/a/header.h"
384
385void foo() {
386 int a = 0;
387})";
388
389 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000390 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000391 "insert_includes_test_header.cc",
392 1));
393}
394
395TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) {
396 const char *PreCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000397#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000398
399#include <stdlib.h>
400
401#include "path/to/a/header.h"
402
403void foo() {
404 int a = 0;
405})";
406 const char *PostCode = R"(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000407#include "clang_tidy/tests/insert_includes_test_header.h"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000408
409#include <stdlib.h>
410
411#include <set>
412
413#include "path/to/a/header.h"
414
415void foo() {
416 int a = 0;
417})";
418
419 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000420 PreCode, "clang_tidy/tests/"
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000421 "insert_includes_test_header.cc",
422 1));
423}
424
Alexander Kornienko8cc024e2015-08-14 12:33:25 +0000425TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeNonSystemInclude) {
426 const char *PreCode = R"(
427#include "path/to/a/header.h"
428
429void foo() {
430 int a = 0;
431})";
432 const char *PostCode = R"(
433#include <set>
434
435#include "path/to/a/header.h"
436
437void foo() {
438 int a = 0;
439})";
440
441 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
442 PreCode, "devtools/cymbal/clang_tidy/tests/"
443 "insert_includes_test_header.cc",
444 1));
445}
446
447TEST(IncludeInserterTest, InsertCSystemIncludeBeforeCXXSystemInclude) {
448 const char *PreCode = R"(
449#include <set>
450
451#include "path/to/a/header.h"
452
453void foo() {
454 int a = 0;
455})";
456 const char *PostCode = R"(
457#include <stdlib.h>
458
459#include <set>
460
461#include "path/to/a/header.h"
462
463void foo() {
464 int a = 0;
465})";
466
467 EXPECT_EQ(PostCode, runCheckOnCode<CSystemIncludeInserterCheck>(
468 PreCode, "devtools/cymbal/clang_tidy/tests/"
469 "insert_includes_test_header.cc",
470 1));
471}
472
473TEST(IncludeInserterTest, InsertIncludeIfThereWasNoneBefore) {
474 const char *PreCode = R"(
475void foo() {
476 int a = 0;
477})";
478 const char *PostCode = R"(#include <set>
479
480
481void foo() {
482 int a = 0;
483})";
484
485 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
486 PreCode, "devtools/cymbal/clang_tidy/tests/"
487 "insert_includes_test_header.cc",
488 1));
489}
490
Manuel Klimekd00d6f12015-08-11 11:37:48 +0000491} // namespace
492} // namespace tidy
493} // namespace clang
Manuel Klimeke8c8d882015-08-11 14:21:26 +0000494
495#endif