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());
82 EXPECT_TRUE(PathResult.has_value());
83 ASSERT_EQ(*PathResult, FooHpp);
92 EXPECT_TRUE(PathResult.has_value());
93 ASSERT_EQ(*PathResult, BarHh);
96TEST(HeaderSourceSwitchTest, ModuleInterfaces) {
100 auto FooCPPM =
testPath(
"foo.cppm");
103 std::optional<Path> PathResult =
105 EXPECT_TRUE(PathResult.has_value());
106 ASSERT_EQ(*PathResult, FooCPPM);
108 auto Foo2CPP =
testPath(
"foo2.cpp");
109 auto Foo2CCM =
testPath(
"foo2.ccm");
113 EXPECT_TRUE(PathResult.has_value());
114 ASSERT_EQ(*PathResult, Foo2CCM);
116 auto Foo3CXX =
testPath(
"foo3.cxx");
117 auto Foo3CXXM =
testPath(
"foo3.cxxm");
121 EXPECT_TRUE(PathResult.has_value());
122 ASSERT_EQ(*PathResult, Foo3CXXM);
124 auto Foo4CPLUSPLUS =
testPath(
"foo4.c++");
125 auto Foo4CPLUSPLUSM =
testPath(
"foo4.c++m");
126 FS.Files[Foo4CPLUSPLUS];
127 FS.Files[Foo4CPLUSPLUSM];
130 EXPECT_TRUE(PathResult.has_value());
131 ASSERT_EQ(*PathResult, Foo4CPLUSPLUSM);
135 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(arg))
136 if (ND->getQualifiedNameAsString() == Name)
141TEST(HeaderSourceSwitchTest, GetLocalDecls) {
156 // Non-indexable symbols
163 auto AST = TU.build();
165 testing::UnorderedElementsAre(
166 declNamed(
"MainF1"), declNamed(
"Foo"), declNamed(
"ns::Foo"),
167 declNamed(
"ns::Foo::method"), declNamed(
"ns::Foo::field")));
170TEST(HeaderSourceSwitchTest, FromHeaderToSource) {
177 Testing.HeaderCode =
"void A_Sym1();";
178 Testing.Filename =
"a.cpp";
179 Testing.Code =
"void A_Sym1() {};";
180 for (
auto &Sym : Testing.headerSymbols())
181 AllSymbols.insert(Sym);
183 Testing.HeaderCode = R
"cpp(
188 Testing.Filename = "b.cpp";
189 Testing.Code = R
"cpp(
193 for (
auto &Sym : Testing.headerSymbols())
194 AllSymbols.insert(Sym);
199 llvm::StringRef HeaderCode;
200 std::optional<std::string> ExpectedSource;
202 {
"// empty, no header found", std::nullopt},
204 // no definition found in the index.
205 void NonDefinition();
220 // a.cpp and b.cpp have same scope, but a.cpp because "a.cpp" < "b.cpp".
227 // We don't have definition in the index, so stay in the header.
232 for (
const auto &Case : TestCases) {
234 TU.Filename =
"TestTU.h";
235 TU.ExtraArgs.push_back(
"-xc++-header");
236 auto HeaderAST = TU.build();
237 EXPECT_EQ(Case.ExpectedSource,
243TEST(HeaderSourceSwitchTest, FromSourceToHeader) {
256 TUForIndex.AdditionalFiles["a.h"] = R
"cpp(
259 TUForIndex.AdditionalFiles["b.h"] = R
"cpp(
263 TUForIndex.Filename = "TestTU.cpp";
264 auto Index = TUForIndex.index();
268 llvm::StringRef SourceCode;
269 std::optional<std::string> ExpectedResult;
271 {
"// empty, no header found", std::nullopt},
273 // symbol not in index, no header found
293 // a.h and b.h have same scope, but a.h wins because "a.h" < "b.h".
299 for (
const auto &Case : TestCases) {
301 TU.Filename =
"Test.cpp";
302 auto AST = TU.build();
303 EXPECT_EQ(Case.ExpectedResult,
309TEST(HeaderSourceSwitchTest, ClangdServerIntegration) {
315 std::string CppPath =
testPath(
"src/lib/test.cpp");
316 std::string HeaderPath =
testPath(
"src/include/test.h");
317 FS.Files[HeaderPath] =
"void foo();";
318 const std::string FileContent = R
"cpp(
322 FS.Files[CppPath] = FileContent;
324 Options.BuildDynamicSymbolIndex =
true;
327 EXPECT_EQ(HeaderPath,
331TEST(HeaderSourceSwitchTest, CaseSensitivity) {
336 TU.HeaderCode = R
"cpp(
337 inline void bar1() {}
338 inline void bar2() {}
342 TU.Filename =
"Source.cpp";
343 TU.HeaderFilename =
"Header.h";
345 auto Index = TU.index();
346 TU.Code = std::move(TU.HeaderCode);
347 TU.HeaderCode.clear();
348 auto AST = TU.build();
353 auto HeaderAbsPath =
testPath(
"HEADER.H");
359#ifdef CLANGD_PATH_CASE_INSENSITIVE
361 llvm::ValueIs(testing::StrCaseEq(
testPath(TU.Filename))));
364 llvm::ValueIs(testing::StrCaseEq(
testPath(TU.HeaderFilename))));
Manages a collection of source files and derived data (ASTs, indexes), and provides language-aware fe...
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.
std::vector< std::string > ExtraClangFlags
SymbolSlab::Builder is a mutable container that can 'freeze' to SymbolSlab.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
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.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::string HeaderFilename
static TestTU withCode(llvm::StringRef Code)