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());
79TEST(HeaderSourceSwitchTest, ModuleInterfaces) {
86 std::optional<Path> PathResult =
88 EXPECT_TRUE(PathResult.has_value());
89 ASSERT_EQ(*PathResult, FooCPPM);
96 EXPECT_TRUE(PathResult.has_value());
97 ASSERT_EQ(*PathResult, Foo2CCM);
100 auto Foo3CXXM =
testPath(
"foo3.cxxm");
104 EXPECT_TRUE(PathResult.has_value());
105 ASSERT_EQ(*PathResult, Foo3CXXM);
107 auto Foo4CPLUSPLUS =
testPath(
"foo4.c++");
108 auto Foo4CPLUSPLUSM =
testPath(
"foo4.c++m");
109 FS.Files[Foo4CPLUSPLUS];
110 FS.Files[Foo4CPLUSPLUSM];
113 EXPECT_TRUE(PathResult.has_value());
114 ASSERT_EQ(*PathResult, Foo4CPLUSPLUSM);
118 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(arg))
119 if (ND->getQualifiedNameAsString() == Name)
124TEST(HeaderSourceSwitchTest, GetLocalDecls) {
139 // Non-indexable symbols
146 auto AST = TU.build();
148 testing::UnorderedElementsAre(
149 declNamed(
"MainF1"), declNamed(
"Foo"), declNamed(
"ns::Foo"),
150 declNamed(
"ns::Foo::method"), declNamed(
"ns::Foo::field")));
153TEST(HeaderSourceSwitchTest, FromHeaderToSource) {
160 Testing.HeaderCode =
"void A_Sym1();";
161 Testing.Filename =
"a.cpp";
162 Testing.Code =
"void A_Sym1() {};";
163 for (
auto &Sym : Testing.headerSymbols())
164 AllSymbols.insert(Sym);
166 Testing.HeaderCode = R
"cpp(
171 Testing.Filename = "b.cpp";
172 Testing.Code = R
"cpp(
176 for (
auto &Sym : Testing.headerSymbols())
177 AllSymbols.insert(Sym);
182 llvm::StringRef HeaderCode;
183 std::optional<std::string> ExpectedSource;
185 {
"// empty, no header found", std::nullopt},
187 // no definition found in the index.
188 void NonDefinition();
203 // a.cpp and b.cpp have same scope, but a.cpp because "a.cpp" < "b.cpp".
210 // We don't have definition in the index, so stay in the header.
215 for (
const auto &Case : TestCases) {
217 TU.Filename =
"TestTU.h";
218 TU.ExtraArgs.push_back(
"-xc++-header");
219 auto HeaderAST = TU.build();
220 EXPECT_EQ(Case.ExpectedSource,
226TEST(HeaderSourceSwitchTest, FromSourceToHeader) {
239 TUForIndex.AdditionalFiles["a.h"] = R
"cpp(
242 TUForIndex.AdditionalFiles["b.h"] = R
"cpp(
246 TUForIndex.Filename = "TestTU.cpp";
247 auto Index = TUForIndex.index();
251 llvm::StringRef SourceCode;
252 std::optional<std::string> ExpectedResult;
254 {
"// empty, no header found", std::nullopt},
256 // symbol not in index, no header found
276 // a.h and b.h have same scope, but a.h wins because "a.h" < "b.h".
282 for (
const auto &Case : TestCases) {
284 TU.Filename =
"Test.cpp";
285 auto AST = TU.build();
286 EXPECT_EQ(Case.ExpectedResult,
292TEST(HeaderSourceSwitchTest, ClangdServerIntegration) {
298 std::string CppPath =
testPath(
"src/lib/test.cpp");
299 std::string HeaderPath =
testPath(
"src/include/test.h");
300 FS.Files[HeaderPath] =
"void foo();";
301 const std::string FileContent = R
"cpp(
305 FS.Files[CppPath] = FileContent;
307 Options.BuildDynamicSymbolIndex =
true;
310 EXPECT_EQ(HeaderPath,
314TEST(HeaderSourceSwitchTest, CaseSensitivity) {
319 TU.HeaderCode = R
"cpp(
320 inline void bar1() {}
321 inline void bar2() {}
325 TU.Filename =
"Source.cpp";
326 TU.HeaderFilename =
"Header.h";
328 auto Index = TU.index();
329 TU.Code = std::move(TU.HeaderCode);
330 TU.HeaderCode.clear();
331 auto AST = TU.build();
336 auto HeaderAbsPath =
testPath(
"HEADER.H");
342#ifdef CLANGD_PATH_CASE_INSENSITIVE
344 llvm::ValueIs(testing::StrCaseEq(
testPath(TU.Filename))));
347 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.
@ Invalid
Sentinel bit pattern. DO NOT USE!
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::string HeaderFilename
static TestTU withCode(llvm::StringRef Code)