114 lines · cpp
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-exception6//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>21namespace clang::include_cleaner {22namespace {23 24const char *testRoot() {25#ifdef _WIN3226 return "C:\\include-cleaner-test";27#else28 return "/include-cleaner-test";29#endif30}31 32std::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 43class DummyIncludeSpeller : public IncludeSpeller {44public: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 59TEST(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 81TEST(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 91TEST(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 109IncludeSpellingStrategy::Add<DummyIncludeSpeller>110 Speller("dummy", "Dummy Include Speller");111 112} // namespace113} // namespace clang::include_cleaner114