16#include "llvm/Testing/Support/SupportHelpers.h"
17#include "gmock/gmock.h"
18#include "gtest/gtest.h"
25TEST(HeaderSourceSwitchTest, FileHeuristic) {
34 std::optional<Path> PathResult =
36 EXPECT_TRUE(PathResult.has_value());
37 ASSERT_EQ(*PathResult, FooH);
40 EXPECT_TRUE(PathResult.has_value());
41 ASSERT_EQ(*PathResult, FooCpp);
51 EXPECT_TRUE(PathResult.has_value());
52 ASSERT_EQ(*PathResult, FooHH);
60 EXPECT_TRUE(PathResult.has_value());
61 ASSERT_EQ(*PathResult, Foo2HH);
70 EXPECT_TRUE(PathResult.has_value());
71 ASSERT_EQ(*PathResult, Foo3HXX);
76 EXPECT_FALSE(PathResult.has_value());
80 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(arg))
81 if (ND->getQualifiedNameAsString() ==
Name)
86TEST(HeaderSourceSwitchTest, GetLocalDecls) {
88 TU.HeaderCode = R
"cpp(
101 // Non-indexable symbols
108 auto AST = TU.build();
110 testing::UnorderedElementsAre(
111 declNamed(
"MainF1"), declNamed(
"Foo"), declNamed(
"ns::Foo"),
112 declNamed(
"ns::Foo::method"), declNamed(
"ns::Foo::field")));
115TEST(HeaderSourceSwitchTest, FromHeaderToSource) {
119 SymbolSlab::Builder AllSymbols;
121 Testing.HeaderFilename =
"TestTU.h";
122 Testing.HeaderCode =
"void A_Sym1();";
123 Testing.Filename =
"a.cpp";
124 Testing.Code =
"void A_Sym1() {};";
125 for (
auto &Sym : Testing.headerSymbols())
126 AllSymbols.insert(Sym);
128 Testing.HeaderCode = R
"cpp(
133 Testing.Filename = "b.cpp";
134 Testing.Code = R
"cpp(
138 for (
auto &Sym : Testing.headerSymbols())
139 AllSymbols.insert(Sym);
144 llvm::StringRef HeaderCode;
145 std::optional<std::string> ExpectedSource;
147 {
"// empty, no header found", std::nullopt},
149 // no definition found in the index.
150 void NonDefinition();
165 // a.cpp and b.cpp have same scope, but a.cpp because "a.cpp" < "b.cpp".
172 // We don't have definition in the index, so stay in the header.
177 for (
const auto &Case : TestCases) {
179 TU.Filename =
"TestTU.h";
180 TU.ExtraArgs.push_back(
"-xc++-header");
181 auto HeaderAST = TU.build();
182 EXPECT_EQ(Case.ExpectedSource,
188TEST(HeaderSourceSwitchTest, FromSourceToHeader) {
201 TUForIndex.AdditionalFiles["a.h"] = R
"cpp(
204 TUForIndex.AdditionalFiles["b.h"] = R
"cpp(
208 TUForIndex.Filename = "TestTU.cpp";
209 auto Index = TUForIndex.index();
213 llvm::StringRef SourceCode;
214 std::optional<std::string> ExpectedResult;
216 {
"// empty, no header found", std::nullopt},
218 // symbol not in index, no header found
238 // a.h and b.h have same scope, but a.h wins because "a.h" < "b.h".
244 for (
const auto &Case : TestCases) {
246 TU.Filename =
"Test.cpp";
247 auto AST = TU.build();
248 EXPECT_EQ(Case.ExpectedResult,
254TEST(HeaderSourceSwitchTest, ClangdServerIntegration) {
255 MockCompilationDatabase CDB;
256 CDB.ExtraClangFlags = {
"-I" +
260 std::string CppPath =
testPath(
"src/lib/test.cpp");
261 std::string HeaderPath =
testPath(
"src/include/test.h");
262 FS.Files[HeaderPath] =
"void foo();";
263 const std::string FileContent = R
"cpp(
267 FS.Files[CppPath] = FileContent;
269 Options.BuildDynamicSymbolIndex =
true;
270 ClangdServer Server(CDB, FS, Options);
272 EXPECT_EQ(HeaderPath,
276TEST(HeaderSourceSwitchTest, CaseSensitivity) {
281 TU.HeaderCode = R
"cpp(
282 inline void bar1() {}
283 inline void bar2() {}
287 TU.Filename =
"Source.cpp";
288 TU.HeaderFilename =
"Header.h";
290 auto Index = TU.index();
291 TU.Code = std::move(TU.HeaderCode);
292 TU.HeaderCode.clear();
293 auto AST = TU.build();
298 auto HeaderAbsPath =
testPath(
"HEADER.H");
304#ifdef CLANGD_PATH_CASE_INSENSITIVE
306 llvm::ValueIs(testing::StrCaseEq(
testPath(TU.Filename))));
309 llvm::ValueIs(testing::StrCaseEq(
testPath(TU.HeaderFilename))));
llvm::SmallString< 256U > Name
static Options optsForTest()
static std::unique_ptr< SymbolIndex > build(SymbolSlab Symbols, RefSlab Refs, RelationSlab Relations)
Builds an index from slabs. The index takes ownership of the data.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > view(std::nullopt_t CWD) const
Obtain a vfs::FileSystem with an arbitrary initial working directory.
llvm::Expected< std::optional< clangd::Path > > runSwitchHeaderSource(ClangdServer &Server, PathRef File)
std::vector< const Decl * > getIndexableLocalDecls(ParsedAST &AST)
Returns all indexable decls that are present in the main file of the AST.
std::string testPath(PathRef File, llvm::sys::path::Style Style)
TEST(BackgroundQueueTest, Priority)
void runAddDocument(ClangdServer &Server, PathRef File, llvm::StringRef Contents, llvm::StringRef Version, WantDiagnostics WantDiags, bool ForceRebuild)
std::optional< Path > getCorrespondingHeaderOrSource(PathRef OriginalFile, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS)
Given a header file, returns the best matching source file, and vice visa.
@ Invalid
Sentinel bit pattern. DO NOT USE!
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static TestTU withCode(llvm::StringRef Code)