blob: 72b5fc31ced9f662ce5cbb89bbc73577ec6e3b99 [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
16namespace clang {
17namespace tidy {
18namespace {
19
20class IncludeInserterCheckBase : public ClangTidyCheck {
21public:
22 using ClangTidyCheck::ClangTidyCheck;
23 void registerPPCallbacks(CompilerInstance &Compiler) override {
24 Inserter.reset(new IncludeInserter(Compiler.getSourceManager(),
25 Compiler.getLangOpts(),
26 IncludeSorter::IS_Google));
27 Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
28 }
29
30 void registerMatchers(ast_matchers::MatchFinder *Finder) override {
31 Finder->addMatcher(ast_matchers::declStmt().bind("stmt"), this);
32 }
33
34 void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
35 auto Fixit =
36 Inserter->CreateIncludeInsertion(Result.SourceManager->getMainFileID(),
37 HeaderToInclude(), IsAngledInclude());
38 if (Fixit) {
39 diag(Result.Nodes.getStmtAs<DeclStmt>("stmt")->getLocStart(), "foo, bar")
40 << *Fixit;
41 }
42 // Second include should yield no Fixit.
43 Fixit =
44 Inserter->CreateIncludeInsertion(Result.SourceManager->getMainFileID(),
45 HeaderToInclude(), IsAngledInclude());
46 EXPECT_FALSE(Fixit);
47 }
48
49 virtual StringRef HeaderToInclude() const = 0;
50 virtual bool IsAngledInclude() const = 0;
51
52 std::unique_ptr<IncludeInserter> Inserter;
53};
54
55class NonSystemHeaderInserterCheck : public IncludeInserterCheckBase {
56public:
57 using IncludeInserterCheckBase::IncludeInserterCheckBase;
58 StringRef HeaderToInclude() const override { return "path/to/header.h"; }
59 bool IsAngledInclude() const override { return false; }
60};
61
62class CXXSystemIncludeInserterCheck : public IncludeInserterCheckBase {
63public:
64 using IncludeInserterCheckBase::IncludeInserterCheckBase;
65 StringRef HeaderToInclude() const override { return "set"; }
66 bool IsAngledInclude() const override { return true; }
67};
68
69template <typename Check>
70std::string runCheckOnCode(StringRef Code, StringRef Filename,
71 size_t NumWarningsExpected) {
72 std::vector<ClangTidyError> Errors;
73 return test::runCheckOnCode<Check>(Code, &Errors, Filename, None,
74 ClangTidyOptions(),
75 {// Main file include
76 {"devtools/cymbal/clang_tidy/tests/"
77 "insert_includes_test_header.h",
78 "\n"},
79 // Non system headers
80 {"path/to/a/header.h", "\n"},
81 {"path/to/z/header.h", "\n"},
82 {"path/to/header.h", "\n"},
83 // Fake system headers.
84 {"stdlib.h", "\n"},
85 {"unistd.h", "\n"},
86 {"list", "\n"},
87 {"map", "\n"},
88 {"set", "\n"},
89 {"vector", "\n"}});
90 EXPECT_EQ(NumWarningsExpected, Errors.size());
91}
92
93TEST(IncludeInserterTest, InsertAfterLastNonSystemInclude) {
94 const char *PreCode = R"(
95#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
96
97#include <list>
98#include <map>
99
100#include "path/to/a/header.h"
101
102void foo() {
103 int a = 0;
104})";
105 const char *PostCode = R"(
106#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
107
108#include <list>
109#include <map>
110
111#include "path/to/a/header.h"
112#include "path/to/header.h"
113
114void foo() {
115 int a = 0;
116})";
117
118 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
119 PreCode, "devtools/cymbal/clang_tidy/tests/"
120 "insert_includes_test_input2.cc",
121 1));
122}
123
124TEST(IncludeInserterTest, InsertBeforeFirstNonSystemInclude) {
125 const char *PreCode = R"(
126#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
127
128#include <list>
129#include <map>
130
131#include "path/to/z/header.h"
132
133void foo() {
134 int a = 0;
135})";
136 const char *PostCode = R"(
137#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
138
139#include <list>
140#include <map>
141
142#include "path/to/header.h"
143#include "path/to/z/header.h"
144
145void foo() {
146 int a = 0;
147})";
148
149 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
150 PreCode, "devtools/cymbal/clang_tidy/tests/"
151 "insert_includes_test_input2.cc",
152 1));
153}
154
155TEST(IncludeInserterTest, InsertBetweenNonSystemIncludes) {
156 const char *PreCode = R"(
157#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
158
159#include <list>
160#include <map>
161
162#include "path/to/a/header.h"
163#include "path/to/z/header.h"
164
165void foo() {
166 int a = 0;
167})";
168 const char *PostCode = R"(
169#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
170
171#include <list>
172#include <map>
173
174#include "path/to/a/header.h"
175#include "path/to/header.h"
176#include "path/to/z/header.h"
177
178void foo() {
179 int a = 0;
180})";
181
182 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
183 PreCode, "devtools/cymbal/clang_tidy/tests/"
184 "insert_includes_test_input2.cc",
185 1));
186}
187
188TEST(IncludeInserterTest, NonSystemIncludeAlreadyIncluded) {
189 const char *PreCode = R"(
190#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
191
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 EXPECT_EQ(PreCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
203 PreCode, "devtools/cymbal/clang_tidy/tests/"
204 "insert_includes_test_input2.cc",
205 0));
206}
207
208TEST(IncludeInserterTest, InsertNonSystemIncludeAfterLastCXXSystemInclude) {
209 const char *PreCode = R"(
210#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
211
212#include <list>
213#include <map>
214
215void foo() {
216 int a = 0;
217})";
218 const char *PostCode = R"(
219#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
220
221#include <list>
222#include <map>
223
224#include "path/to/header.h"
225
226void foo() {
227 int a = 0;
228})";
229
230 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
231 PreCode, "devtools/cymbal/clang_tidy/tests/"
232 "insert_includes_test_header.cc",
233 1));
234}
235
236TEST(IncludeInserterTest, InsertNonSystemIncludeAfterMainFileInclude) {
237 const char *PreCode = R"(
238#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
239
240void foo() {
241 int a = 0;
242})";
243 const char *PostCode = R"(
244#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
245
246#include "path/to/header.h"
247
248void foo() {
249 int a = 0;
250})";
251
252 EXPECT_EQ(PostCode, runCheckOnCode<NonSystemHeaderInserterCheck>(
253 PreCode, "devtools/cymbal/clang_tidy/tests/"
254 "insert_includes_test_header.cc",
255 1));
256}
257
258TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterLastCXXSystemInclude) {
259 const char *PreCode = R"(
260#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
261
262#include <list>
263#include <map>
264
265#include "path/to/a/header.h"
266
267void foo() {
268 int a = 0;
269})";
270 const char *PostCode = R"(
271#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
272
273#include <list>
274#include <map>
275#include <set>
276
277#include "path/to/a/header.h"
278
279void foo() {
280 int a = 0;
281})";
282
283 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
284 PreCode, "devtools/cymbal/clang_tidy/tests/"
285 "insert_includes_test_header.cc",
286 1));
287}
288
289TEST(IncludeInserterTest, InsertCXXSystemIncludeBeforeFirstCXXSystemInclude) {
290 const char *PreCode = R"(
291#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
292
293#include <vector>
294
295#include "path/to/a/header.h"
296
297void foo() {
298 int a = 0;
299})";
300 const char *PostCode = R"(
301#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
302
303#include <set>
304#include <vector>
305
306#include "path/to/a/header.h"
307
308void foo() {
309 int a = 0;
310})";
311
312 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
313 PreCode, "devtools/cymbal/clang_tidy/tests/"
314 "insert_includes_test_header.cc",
315 1));
316}
317
318TEST(IncludeInserterTest, InsertCXXSystemIncludeBetweenCXXSystemIncludes) {
319 const char *PreCode = R"(
320#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
321
322#include <map>
323#include <vector>
324
325#include "path/to/a/header.h"
326
327void foo() {
328 int a = 0;
329})";
330 const char *PostCode = R"(
331#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
332
333#include <map>
334#include <set>
335#include <vector>
336
337#include "path/to/a/header.h"
338
339void foo() {
340 int a = 0;
341})";
342
343 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
344 PreCode, "devtools/cymbal/clang_tidy/tests/"
345 "insert_includes_test_header.cc",
346 1));
347}
348
349TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterMainFileInclude) {
350 const char *PreCode = R"(
351#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
352
353#include "path/to/a/header.h"
354
355void foo() {
356 int a = 0;
357})";
358 const char *PostCode = R"(
359#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
360
361#include <set>
362
363#include "path/to/a/header.h"
364
365void foo() {
366 int a = 0;
367})";
368
369 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
370 PreCode, "devtools/cymbal/clang_tidy/tests/"
371 "insert_includes_test_header.cc",
372 1));
373}
374
375TEST(IncludeInserterTest, InsertCXXSystemIncludeAfterCSystemInclude) {
376 const char *PreCode = R"(
377#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
378
379#include <stdlib.h>
380
381#include "path/to/a/header.h"
382
383void foo() {
384 int a = 0;
385})";
386 const char *PostCode = R"(
387#include "devtools/cymbal/clang_tidy/tests/insert_includes_test_header.h"
388
389#include <stdlib.h>
390
391#include <set>
392
393#include "path/to/a/header.h"
394
395void foo() {
396 int a = 0;
397})";
398
399 EXPECT_EQ(PostCode, runCheckOnCode<CXXSystemIncludeInserterCheck>(
400 PreCode, "devtools/cymbal/clang_tidy/tests/"
401 "insert_includes_test_header.cc",
402 1));
403}
404
405} // namespace
406} // namespace tidy
407} // namespace clang