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