13 #include "clang/Tooling/CompilationDatabase.h" 14 #include "llvm/ADT/Optional.h" 15 #include "llvm/ADT/SmallString.h" 16 #include "llvm/ADT/StringExtras.h" 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/Support/FileSystem.h" 19 #include "llvm/Support/FormatVariadic.h" 20 #include "llvm/Support/MemoryBuffer.h" 21 #include "llvm/Support/Path.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include "gmock/gmock.h" 24 #include "gtest/gtest.h" 31 using ::testing::AllOf;
32 using ::testing::Contains;
33 using ::testing::ElementsAre;
34 using ::testing::EndsWith;
35 using ::testing::HasSubstr;
36 using ::testing::IsEmpty;
38 using ::testing::StartsWith;
39 using ::testing::UnorderedElementsAre;
41 TEST(GlobalCompilationDatabaseTest, FallbackCommand) {
42 DirectoryBasedGlobalCompilationDatabase DB(None);
43 auto Cmd = DB.getFallbackCommand(
testPath(
"foo/bar.cc"));
44 EXPECT_EQ(Cmd.Directory,
testPath(
"foo"));
45 EXPECT_THAT(Cmd.CommandLine,
46 ElementsAre(EndsWith(
"clang"),
testPath(
"foo/bar.cc")));
47 EXPECT_EQ(Cmd.Output,
"");
50 Cmd = DB.getFallbackCommand(
testPath(
"foo/bar.h"));
51 EXPECT_THAT(Cmd.CommandLine,
52 ElementsAre(EndsWith(
"clang"),
"-xobjective-c++-header",
54 Cmd = DB.getFallbackCommand(
testPath(
"foo/bar"));
55 EXPECT_THAT(Cmd.CommandLine,
56 ElementsAre(EndsWith(
"clang"),
"-xobjective-c++-header",
60 static tooling::CompileCommand cmd(llvm::StringRef File, llvm::StringRef Arg) {
61 return tooling::CompileCommand(
testRoot(), File, {
"clang", Arg, File},
"");
64 class OverlayCDBTest :
public ::testing::Test {
65 class BaseCDB :
public GlobalCompilationDatabase {
67 llvm::Optional<tooling::CompileCommand>
68 getCompileCommand(llvm::StringRef File)
const override {
70 return cmd(File,
"-DA=1");
74 tooling::CompileCommand
75 getFallbackCommand(llvm::StringRef File)
const override {
76 return cmd(File,
"-DA=2");
79 llvm::Optional<ProjectInfo> getProjectInfo(
PathRef File)
const override {
85 OverlayCDBTest() :
Base(
llvm::make_unique<BaseCDB>()) {}
86 std::unique_ptr<GlobalCompilationDatabase>
Base;
89 TEST_F(OverlayCDBTest, GetCompileCommand) {
90 OverlayCDB CDB(
Base.get(), {}, std::string(
""));
91 EXPECT_THAT(CDB.getCompileCommand(
testPath(
"foo.cc"))->CommandLine,
92 AllOf(Contains(
testPath(
"foo.cc")), Contains(
"-DA=1")));
95 auto Override = cmd(
testPath(
"foo.cc"),
"-DA=3");
96 CDB.setCompileCommand(
testPath(
"foo.cc"), Override);
97 EXPECT_THAT(CDB.getCompileCommand(
testPath(
"foo.cc"))->CommandLine,
100 CDB.setCompileCommand(
testPath(
"missing.cc"), Override);
101 EXPECT_THAT(CDB.getCompileCommand(
testPath(
"missing.cc"))->CommandLine,
105 TEST_F(OverlayCDBTest, GetFallbackCommand) {
106 OverlayCDB CDB(
Base.get(), {
"-DA=4"});
107 EXPECT_THAT(CDB.getFallbackCommand(
testPath(
"bar.cc")).CommandLine,
108 ElementsAre(
"clang",
"-DA=2",
testPath(
"bar.cc"),
"-DA=4",
109 "-fsyntax-only", StartsWith(
"-resource-dir")));
112 TEST_F(OverlayCDBTest, NoBase) {
113 OverlayCDB CDB(
nullptr, {
"-DA=6"}, std::string(
""));
114 EXPECT_EQ(CDB.getCompileCommand(
testPath(
"bar.cc")),
None);
115 auto Override = cmd(
testPath(
"bar.cc"),
"-DA=5");
116 CDB.setCompileCommand(
testPath(
"bar.cc"), Override);
117 EXPECT_THAT(CDB.getCompileCommand(
testPath(
"bar.cc"))->CommandLine,
120 EXPECT_THAT(CDB.getFallbackCommand(
testPath(
"foo.cc")).CommandLine,
121 ElementsAre(EndsWith(
"clang"),
testPath(
"foo.cc"),
"-DA=6",
125 TEST_F(OverlayCDBTest, Watch) {
126 OverlayCDB Inner(
nullptr);
127 OverlayCDB Outer(&Inner);
129 std::vector<std::vector<std::string>>
Changes;
130 auto Sub = Outer.watch([&](
const std::vector<std::string> &ChangedFiles) {
131 Changes.push_back(ChangedFiles);
134 Inner.setCompileCommand(
"A.cpp", tooling::CompileCommand());
135 Outer.setCompileCommand(
"B.cpp", tooling::CompileCommand());
138 EXPECT_THAT(Changes, ElementsAre(ElementsAre(
"A.cpp"), ElementsAre(
"B.cpp"),
139 ElementsAre(
"A.cpp"), ElementsAre(
"C.cpp")));
142 TEST_F(OverlayCDBTest, Adjustments) {
143 OverlayCDB CDB(
Base.get(), {}, std::string(
""));
144 auto Cmd = CDB.getCompileCommand(
testPath(
"foo.cc")).getValue();
146 Cmd.CommandLine.pop_back();
149 Cmd.CommandLine.push_back(
"-MF");
150 Cmd.CommandLine.push_back(
"random-dependency");
153 Cmd.CommandLine.push_back(
"-Xclang");
154 Cmd.CommandLine.push_back(
"-load");
155 Cmd.CommandLine.push_back(
"-Xclang");
156 Cmd.CommandLine.push_back(
"random-plugin");
158 Cmd.CommandLine.push_back(
"-DA=5");
159 Cmd.CommandLine.push_back(Cmd.Filename);
161 CDB.setCompileCommand(
testPath(
"foo.cc"), Cmd);
163 EXPECT_THAT(CDB.getCompileCommand(
testPath(
"foo.cc"))->CommandLine,
164 AllOf(Contains(
"-fsyntax-only"), Contains(
"-DA=5"),
165 Contains(
testPath(
"foo.cc")), Not(Contains(
"-MF")),
166 Not(Contains(
"random-dependency")),
167 Not(Contains(
"-Xclang")), Not(Contains(
"-load")),
168 Not(Contains(
"random-plugin"))));
171 TEST(GlobalCompilationDatabaseTest, DiscoveryWithNestedCDBs) {
172 const char *
const CDBOuter =
181 "file": "build/gen.cc", 186 "file": "build/gen2.cc", 192 const char *
const CDBInner =
198 "directory": "{0}/build", 204 llvm::SmallString<128> Root;
208 llvm::sys::fs::createUniqueDirectory(
"clangd-cdb-test", Root))
209 <<
"Failed to create unique directory";
213 EXPECT_FALSE(llvm::sys::fs::remove_directories(Root))
214 <<
"Failed to cleanup " << Root;
218 llvm::SmallString<128> AbsPath(Root);
219 llvm::sys::path::append(AbsPath, RelativePath);
221 EXPECT_FALSE(llvm::sys::fs::create_directories(
222 llvm::sys::path::parent_path(AbsPath)))
223 <<
"Failed to create directories for: " << AbsPath;
226 llvm::raw_fd_ostream OS(AbsPath, EC);
227 EXPECT_FALSE(EC) <<
"Failed to open " << AbsPath <<
" for writing";
228 OS << llvm::formatv(Contents.data(),
229 llvm::sys::path::convert_to_slash(Root));
232 EXPECT_FALSE(OS.has_error());
237 FS.registerFile(
"compile_commands.json", CDBOuter);
238 FS.registerFile(
"build/compile_commands.json", CDBInner);
239 llvm::SmallString<128>
File;
244 DirectoryBasedGlobalCompilationDatabase DB(
llvm::None);
245 std::vector<std::string> DiscoveredFiles;
247 DB.watch([&DiscoveredFiles](
const std::vector<std::string>
Changes) {
252 llvm::sys::path::append(File,
"build",
"..",
"a.cc");
253 DB.getCompileCommand(File.str());
254 EXPECT_THAT(DiscoveredFiles, UnorderedElementsAre(AllOf(
255 EndsWith(
"a.cc"), Not(HasSubstr(
"..")))));
256 DiscoveredFiles.clear();
259 llvm::sys::path::append(File,
"build",
"gen.cc");
260 DB.getCompileCommand(File.str());
261 EXPECT_THAT(DiscoveredFiles, UnorderedElementsAre(EndsWith(
"gen.cc")));
266 DirectoryBasedGlobalCompilationDatabase DB(FS.Root.str().str());
267 std::vector<std::string> DiscoveredFiles;
269 DB.watch([&DiscoveredFiles](
const std::vector<std::string>
Changes) {
274 llvm::sys::path::append(File,
"a.cc");
275 DB.getCompileCommand(File.str());
276 EXPECT_THAT(DiscoveredFiles,
277 UnorderedElementsAre(EndsWith(
"a.cc"), EndsWith(
"gen.cc"),
278 EndsWith(
"gen2.cc")));
279 DiscoveredFiles.clear();
282 llvm::sys::path::append(File,
"build",
"gen.cc");
283 DB.getCompileCommand(File.str());
284 EXPECT_THAT(DiscoveredFiles, IsEmpty());
288 TEST(GlobalCompilationDatabaseTest, NonCanonicalFilenames) {
289 OverlayCDB DB(
nullptr);
290 std::vector<std::string> DiscoveredFiles;
292 DB.watch([&DiscoveredFiles](
const std::vector<std::string>
Changes) {
296 llvm::SmallString<128> Root(
testRoot());
297 llvm::sys::path::append(Root,
"build",
"..",
"a.cc");
298 DB.setCompileCommand(Root.str(), tooling::CompileCommand());
299 EXPECT_THAT(DiscoveredFiles, UnorderedElementsAre(
testPath(
"a.cc")));
300 DiscoveredFiles.clear();
303 llvm::sys::path::append(File,
"blabla",
"..",
"a.cc");
305 EXPECT_TRUE(DB.getCompileCommand(File));
306 EXPECT_TRUE(DB.getProjectInfo(File));
Some operations such as code completion produce a set of candidates.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Documents should not be synced at all.
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
TEST(BackgroundQueueTest, Priority)
std::string testPath(PathRef File)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::unique_ptr< GlobalCompilationDatabase > Base