xref: /llvm-project/clang-tools-extra/include-cleaner/unittests/IncludeSpellerTest.cpp (revision 64d9713637ab98e2b65c9c4317a50ddba0ba0dbc)
1 //===--- IncludeSpellerTest.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-include-cleaner/IncludeSpeller.h"
10 #include "clang-include-cleaner/Analysis.h"
11 #include "clang-include-cleaner/Types.h"
12 #include "clang/Lex/Preprocessor.h"
13 #include "clang/Testing/TestAST.h"
14 #include "clang/Tooling/Inclusions/StandardLibrary.h"
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/Path.h"
18 #include "gtest/gtest.h"
19 #include <assert.h>
20 #include <string>
21 namespace clang::include_cleaner {
22 namespace {
23 
24 const char *testRoot() {
25 #ifdef _WIN32
26   return "C:\\include-cleaner-test";
27 #else
28   return "/include-cleaner-test";
29 #endif
30 }
31 
32 std::string testPath(llvm::StringRef File) {
33   assert(llvm::sys::path::is_relative(File) && "FileName should be relative");
34 
35   llvm::SmallString<32> NativeFile = File;
36   llvm::sys::path::native(NativeFile, llvm::sys::path::Style::native);
37   llvm::SmallString<32> Path;
38   llvm::sys::path::append(Path, llvm::sys::path::Style::native, testRoot(),
39                           NativeFile);
40   return std::string(Path.str());
41 }
42 
43 class DummyIncludeSpeller : public IncludeSpeller {
44 public:
45   std::string operator()(const IncludeSpeller::Input &Input) const override {
46     if (Input.H.kind() == Header::Standard)
47       return "<bits/stdc++.h>";
48     if (Input.H.kind() != Header::Physical)
49       return "";
50     llvm::StringRef AbsolutePath = Input.H.resolvedPath();
51     std::string RootWithSeparator{testRoot()};
52     RootWithSeparator += llvm::sys::path::get_separator();
53     if (!AbsolutePath.consume_front(llvm::StringRef{RootWithSeparator}))
54       return "";
55     return "\"" + AbsolutePath.str() + "\"";
56   }
57 };
58 
59 TEST(IncludeSpeller, IsRelativeToTestRoot) {
60   TestInputs Inputs;
61 
62   Inputs.ExtraArgs.push_back("-isystemdir");
63 
64   Inputs.ExtraFiles[testPath("foo.h")] = "";
65   Inputs.ExtraFiles["dir/header.h"] = "";
66   TestAST AST{Inputs};
67 
68   auto &FM = AST.fileManager();
69   auto &HS = AST.preprocessor().getHeaderSearchInfo();
70   const auto *MainFile = AST.sourceManager().getFileEntryForID(
71       AST.sourceManager().getMainFileID());
72 
73   EXPECT_EQ("\"foo.h\"",
74             spellHeader({Header{*FM.getOptionalFileRef(testPath("foo.h"))}, HS,
75                          MainFile}));
76   EXPECT_EQ("<header.h>",
77             spellHeader({Header{*FM.getOptionalFileRef("dir/header.h")}, HS,
78                          MainFile}));
79 }
80 
81 TEST(IncludeSpeller, CanOverrideSystemHeaders) {
82   TestAST AST("");
83   auto &HS = AST.preprocessor().getHeaderSearchInfo();
84   const auto *MainFile = AST.sourceManager().getFileEntryForID(
85       AST.sourceManager().getMainFileID());
86   EXPECT_EQ("<bits/stdc++.h>",
87             spellHeader({Header{*tooling::stdlib::Header::named("<vector>")},
88                          HS, MainFile}));
89 }
90 
91 TEST(IncludeSpeller, RelativeIncludeSearchPath) {
92   TestInputs Inputs;
93 
94   Inputs.WorkingDir = "/root/inner";
95   Inputs.ExtraArgs.push_back("-I..");
96   Inputs.ExtraFiles["/root/foo.h"] = "";
97   TestAST AST{Inputs};
98 
99   auto &FM = AST.fileManager();
100   auto &HS = AST.preprocessor().getHeaderSearchInfo();
101   const auto *MainFile = AST.sourceManager().getFileEntryForID(
102       AST.sourceManager().getMainFileID());
103 
104   EXPECT_EQ("\"foo.h\"",
105             spellHeader(
106                 {Header{*FM.getOptionalFileRef("/root/foo.h")}, HS, MainFile}));
107 }
108 
109 IncludeSpellingStrategy::Add<DummyIncludeSpeller>
110     Speller("dummy", "Dummy Include Speller");
111 
112 } // namespace
113 } // namespace clang::include_cleaner
114