1 //===--- IncludeSpellerTest.cpp--------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
21 namespace clang::include_cleaner
{
24 const char *testRoot() {
26 return "C:\\include-cleaner-test";
28 return "/include-cleaner-test";
32 std::string
testPath(llvm::StringRef File
) {
33 assert(llvm::sys::path::is_relative(File
) && "FileName should be relative");
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(),
40 return std::string(Path
.str());
43 class DummyIncludeSpeller
: public IncludeSpeller
{
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
)
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
}))
55 return "\"" + AbsolutePath
.str() + "\"";
59 TEST(IncludeSpeller
, IsRelativeToTestRoot
) {
62 Inputs
.ExtraArgs
.push_back("-isystemdir");
64 Inputs
.ExtraFiles
[testPath("foo.h")] = "";
65 Inputs
.ExtraFiles
["dir/header.h"] = "";
68 auto &FM
= AST
.fileManager();
69 auto &HS
= AST
.preprocessor().getHeaderSearchInfo();
70 const auto *MainFile
= AST
.sourceManager().getFileEntryForID(
71 AST
.sourceManager().getMainFileID());
73 EXPECT_EQ("\"foo.h\"",
74 spellHeader({Header
{*FM
.getOptionalFileRef(testPath("foo.h"))}, HS
,
76 EXPECT_EQ("<header.h>",
77 spellHeader({Header
{*FM
.getOptionalFileRef("dir/header.h")}, HS
,
81 TEST(IncludeSpeller
, CanOverrideSystemHeaders
) {
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>")},
91 TEST(IncludeSpeller
, RelativeIncludeSearchPath
) {
94 Inputs
.WorkingDir
= "/root/inner";
95 Inputs
.ExtraArgs
.push_back("-I..");
96 Inputs
.ExtraFiles
["/root/foo.h"] = "";
99 auto &FM
= AST
.fileManager();
100 auto &HS
= AST
.preprocessor().getHeaderSearchInfo();
101 const auto *MainFile
= AST
.sourceManager().getFileEntryForID(
102 AST
.sourceManager().getMainFileID());
104 EXPECT_EQ("\"foo.h\"",
106 {Header
{*FM
.getOptionalFileRef("/root/foo.h")}, HS
, MainFile
}));
109 IncludeSpellingStrategy::Add
<DummyIncludeSpeller
>
110 Speller("dummy", "Dummy Include Speller");
113 } // namespace clang::include_cleaner