xref: /llvm-project/clang/unittests/Tooling/HeaderAnalysisTest.cpp (revision b0abc9dd44271815b3ae1ad5d009a1ca83e0fdca)
1 //===- unittest/Tooling/HeaderAnalysisTest.cpp ----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Tooling/Inclusions/HeaderAnalysis.h"
10 #include "clang/Lex/Preprocessor.h"
11 #include "clang/Testing/TestAST.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 
15 namespace clang {
16 namespace tooling {
17 namespace {
18 using testing::Eq;
19 
TEST(HeaderAnalysisTest,IsSelfContained)20 TEST(HeaderAnalysisTest, IsSelfContained) {
21   TestInputs Inputs;
22   Inputs.Code = R"cpp(
23   #include "headerguard.h"
24   #include "pragmaonce.h"
25   #import "imported.h"
26 
27   #include "bad.h"
28   #include "unguarded.h"
29   )cpp";
30 
31   Inputs.ExtraFiles["headerguard.h"] = R"cpp(
32   #ifndef HEADER_H
33   #define HEADER_H
34 
35   #endif HEADER_H
36   )cpp";
37   Inputs.ExtraFiles["pragmaonce.h"] = R"cpp(
38   #pragma once
39   )cpp";
40   Inputs.ExtraFiles["imported.h"] = "";
41 
42   Inputs.ExtraFiles["unguarded.h"] = "";
43   Inputs.ExtraFiles["bad.h"] = R"cpp(
44   #pragma once
45 
46   #if defined(INSIDE_H)
47   #error "Only ... can be included directly"
48   #endif
49   )cpp";
50 
51   TestAST AST(Inputs);
52   const auto &SM = AST.sourceManager();
53   auto &FM = SM.getFileManager();
54   auto &HI = AST.preprocessor().getHeaderSearchInfo();
55   EXPECT_TRUE(
56       isSelfContainedHeader(*FM.getOptionalFileRef("headerguard.h"), SM, HI));
57   EXPECT_TRUE(
58       isSelfContainedHeader(*FM.getOptionalFileRef("pragmaonce.h"), SM, HI));
59   EXPECT_TRUE(
60       isSelfContainedHeader(*FM.getOptionalFileRef("imported.h"), SM, HI));
61   EXPECT_TRUE(isSelfContainedHeader(
62       *SM.getFileEntryRefForID(SM.getMainFileID()), SM, HI));
63 
64   EXPECT_FALSE(
65       isSelfContainedHeader(*FM.getOptionalFileRef("unguarded.h"), SM, HI));
66   EXPECT_FALSE(isSelfContainedHeader(*FM.getOptionalFileRef("bad.h"), SM, HI));
67 }
68 
TEST(HeaderAnalysisTest,CodeContainsImports)69 TEST(HeaderAnalysisTest, CodeContainsImports) {
70   EXPECT_TRUE(codeContainsImports(R"cpp(
71   #include "foo.h"
72   #import "NSFoo.h"
73 
74   int main() {
75     foo();
76   }
77   )cpp"));
78 
79   EXPECT_TRUE(codeContainsImports(R"cpp(
80   #include "foo.h"
81 
82   int main() {
83     foo();
84   }
85 
86   #import "NSFoo.h"
87   )cpp"));
88 
89   EXPECT_FALSE(codeContainsImports(R"cpp(
90   #include "foo.h"
91 
92   int main() {
93     foo();
94   }
95   )cpp"));
96 }
97 
TEST(HeaderAnalysisTest,ParseIWYUPragma)98 TEST(HeaderAnalysisTest, ParseIWYUPragma) {
99   EXPECT_THAT(parseIWYUPragma("// IWYU pragma: keep"), Eq("keep"));
100   EXPECT_THAT(parseIWYUPragma("// IWYU pragma:   keep  me\netc"),
101               Eq("keep  me"));
102   EXPECT_THAT(parseIWYUPragma("/* IWYU pragma: keep */"), Eq("keep"));
103   EXPECT_EQ(parseIWYUPragma("//  IWYU pragma: keep"), std::nullopt)
104       << "Prefix is sensitive to whitespace";
105   EXPECT_EQ(parseIWYUPragma("// IWYU pragma:keep"), std::nullopt)
106       << "Prefix is sensitive to whitespace";
107   EXPECT_EQ(parseIWYUPragma("/\n* IWYU pragma: keep */"), std::nullopt)
108       << "Must start with /* or //";
109 }
110 
111 } // namespace
112 } // namespace tooling
113 } // namespace clang
114