clang-tools  11.0.0
MarshallingTests.cpp
Go to the documentation of this file.
1 //===--- MarshallingTests.cpp ------------------------------------*- C++-*-===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "../TestTU.h"
10 #include "TestFS.h"
11 #include "index/Index.h"
12 #include "index/Ref.h"
13 #include "index/Serialization.h"
14 #include "index/Symbol.h"
15 #include "index/SymbolID.h"
17 #include "clang/Index/IndexSymbol.h"
18 #include "llvm/ADT/SmallString.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/Path.h"
21 #include "llvm/Support/StringSaver.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include <cstring>
25 
26 namespace clang {
27 namespace clangd {
28 namespace remote {
29 namespace {
30 
31 using llvm::sys::path::convert_to_slash;
32 
33 const char *testPathURI(llvm::StringRef Path,
34  llvm::UniqueStringSaver &Strings) {
35  auto URI = URI::createFile(testPath(Path));
36  return Strings.save(URI.toString()).begin();
37 }
38 
39 TEST(RemoteMarshallingTest, URITranslation) {
40  llvm::BumpPtrAllocator Arena;
41  llvm::UniqueStringSaver Strings(Arena);
42  clangd::Ref Original;
43  Original.Location.FileURI =
44  testPathURI("remote/machine/projects/llvm-project/clang-tools-extra/"
45  "clangd/unittests/remote/MarshallingTests.cpp",
46  Strings);
47  auto Serialized =
48  toProtobuf(Original, testPath("remote/machine/projects/llvm-project/"));
49  EXPECT_EQ(Serialized.location().file_path(),
50  "clang-tools-extra/clangd/unittests/remote/MarshallingTests.cpp");
51  const std::string LocalIndexPrefix = testPath("local/machine/project/");
52  auto Deserialized = fromProtobuf(Serialized, &Strings,
53  testPath("home/my-projects/llvm-project/"));
54  EXPECT_TRUE(Deserialized);
55  EXPECT_EQ(Deserialized->Location.FileURI,
56  testPathURI("home/my-projects/llvm-project/clang-tools-extra/"
57  "clangd/unittests/remote/MarshallingTests.cpp",
58  Strings));
59 
60  clangd::Ref WithInvalidURI;
61  // Invalid URI results in empty path.
62  WithInvalidURI.Location.FileURI = "This is not a URI";
63  Serialized = toProtobuf(WithInvalidURI, testPath("home/"));
64  EXPECT_EQ(Serialized.location().file_path(), "");
65 
66  // Can not use URIs with scheme different from "file".
67  auto UnittestURI =
68  URI::create(testPath("project/lib/HelloWorld.cpp"), "unittest");
69  EXPECT_TRUE(bool(UnittestURI));
70  WithInvalidURI.Location.FileURI =
71  Strings.save(UnittestURI->toString()).begin();
72  Serialized = toProtobuf(WithInvalidURI, testPath("project/lib/"));
73  EXPECT_EQ(Serialized.location().file_path(), "");
74 
75  Ref WithAbsolutePath;
76  *WithAbsolutePath.mutable_location()->mutable_file_path() =
77  "/usr/local/user/home/HelloWorld.cpp";
78  Deserialized = fromProtobuf(WithAbsolutePath, &Strings, LocalIndexPrefix);
79  // Paths transmitted over the wire can not be absolute, they have to be
80  // relative.
81  EXPECT_FALSE(Deserialized);
82 }
83 
84 TEST(RemoteMarshallingTest, SymbolSerialization) {
85  clangd::Symbol Sym;
86 
87  auto ID = SymbolID::fromStr("057557CEBF6E6B2D");
88  EXPECT_TRUE(bool(ID));
89  Sym.ID = *ID;
90 
92  Info.Kind = index::SymbolKind::Function;
93  Info.SubKind = index::SymbolSubKind::AccessorGetter;
94  Info.Lang = index::SymbolLanguage::CXX;
95  Info.Properties = static_cast<index::SymbolPropertySet>(
96  index::SymbolProperty::TemplateSpecialization);
97  Sym.SymInfo = Info;
98 
99  llvm::BumpPtrAllocator Arena;
100  llvm::UniqueStringSaver Strings(Arena);
101 
102  Sym.Name = Strings.save("Foo");
103  Sym.Scope = Strings.save("llvm::foo::bar::");
104 
105  clangd::SymbolLocation Location;
106  Location.Start.setLine(1);
107  Location.Start.setColumn(15);
108  Location.End.setLine(3);
109  Location.End.setColumn(121);
110  Location.FileURI = testPathURI("home/Definition.cpp", Strings);
111  Sym.Definition = Location;
112 
113  Location.Start.setLine(42);
114  Location.Start.setColumn(31);
115  Location.End.setLine(20);
116  Location.End.setColumn(400);
117  Location.FileURI = testPathURI("home/Declaration.h", Strings);
118  Sym.CanonicalDeclaration = Location;
119 
120  Sym.References = 9000;
121  Sym.Origin = clangd::SymbolOrigin::Static;
122  Sym.Signature = Strings.save("(int X, char Y, Type T)");
123  Sym.TemplateSpecializationArgs = Strings.save("<int, char, bool, Type>");
124  Sym.CompletionSnippetSuffix =
125  Strings.save("({1: int X}, {2: char Y}, {3: Type T})");
126  Sym.Documentation = Strings.save("This is my amazing Foo constructor!");
127  Sym.ReturnType = Strings.save("Foo");
128 
129  Sym.Flags = clangd::Symbol::SymbolFlag::IndexedForCodeCompletion;
130 
131  // Check that symbols are exactly the same if the path to indexed project is
132  // the same on indexing machine and the client.
133  auto Serialized = toProtobuf(Sym, testPath("home/"));
134  auto Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
135  EXPECT_TRUE(Deserialized);
136  EXPECT_EQ(toYAML(Sym), toYAML(*Deserialized));
137  // Serialized paths are relative and have UNIX slashes.
138  EXPECT_EQ(convert_to_slash(Serialized.definition().file_path(),
139  llvm::sys::path::Style::posix),
140  Serialized.definition().file_path());
141  EXPECT_TRUE(
142  llvm::sys::path::is_relative(Serialized.definition().file_path()));
143 
144  // Fail with an invalid URI.
145  Location.FileURI = "Not A URI";
146  Sym.Definition = Location;
147  Serialized = toProtobuf(Sym, testPath("home/"));
148  Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
149  EXPECT_FALSE(Deserialized);
150 
151  // Schemes other than "file" can not be used.
152  auto UnittestURI = URI::create(testPath("home/SomePath.h"), "unittest");
153  EXPECT_TRUE(bool(UnittestURI));
154  Location.FileURI = Strings.save(UnittestURI->toString()).begin();
155  Sym.Definition = Location;
156  Serialized = toProtobuf(Sym, testPath("home/"));
157  Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
158  EXPECT_FALSE(Deserialized);
159 
160  // Passing root that is not prefix of the original file path.
161  Location.FileURI = testPathURI("home/File.h", Strings);
162  Sym.Definition = Location;
163  // Check that the symbol is valid and passing the correct path works.
164  Serialized = toProtobuf(Sym, testPath("home/"));
165  Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
166  EXPECT_TRUE(Deserialized);
167  EXPECT_EQ(Deserialized->Definition.FileURI,
168  testPathURI("home/File.h", Strings));
169  // Fail with a wrong root.
170  Serialized = toProtobuf(Sym, testPath("nothome/"));
171  Deserialized = fromProtobuf(Serialized, &Strings, testPath("home/"));
172  EXPECT_FALSE(Deserialized);
173 }
174 
175 TEST(RemoteMarshallingTest, RefSerialization) {
176  clangd::Ref Ref;
178 
179  llvm::BumpPtrAllocator Arena;
180  llvm::UniqueStringSaver Strings(Arena);
181 
182  clangd::SymbolLocation Location;
183  Location.Start.setLine(124);
184  Location.Start.setColumn(21);
185  Location.End.setLine(3213);
186  Location.End.setColumn(541);
187  Location.FileURI = testPathURI(
188  "llvm-project/llvm/clang-tools-extra/clangd/Protocol.h", Strings);
189  Ref.Location = Location;
190 
191  auto Serialized = toProtobuf(Ref, testPath("llvm-project/"));
192  auto Deserialized =
193  fromProtobuf(Serialized, &Strings, testPath("llvm-project/"));
194  EXPECT_TRUE(Deserialized);
195  EXPECT_EQ(toYAML(Ref), toYAML(*Deserialized));
196 }
197 
198 TEST(RemoteMarshallingTest, IncludeHeaderURIs) {
199  llvm::BumpPtrAllocator Arena;
200  llvm::UniqueStringSaver Strings(Arena);
201 
202  llvm::SmallVector<clangd::Symbol::IncludeHeaderWithReferences, 1>
203  ValidHeaders;
204  clangd::Symbol::IncludeHeaderWithReferences Header;
205  Header.IncludeHeader = Strings.save(
206  URI::createFile("/usr/local/user/home/project/Header.h").toString());
207  Header.References = 21;
208  ValidHeaders.push_back(Header);
209  Header.IncludeHeader = Strings.save("<iostream>");
210  Header.References = 100;
211  ValidHeaders.push_back(Header);
212  Header.IncludeHeader = Strings.save("\"cstdio\"");
213  Header.References = 200;
214  ValidHeaders.push_back(Header);
215 
216  llvm::SmallVector<clangd::Symbol::IncludeHeaderWithReferences, 1>
217  InvalidHeaders;
218  // This is an absolute path to a header: can not be transmitted over the wire.
219  Header.IncludeHeader = Strings.save(testPath("project/include/Common.h"));
220  Header.References = 42;
221  InvalidHeaders.push_back(Header);
222  // This is not a valid header: can not be transmitted over the wire;
223  Header.IncludeHeader = Strings.save("NotAHeader");
224  Header.References = 5;
225  InvalidHeaders.push_back(Header);
226 
227  clangd::Symbol Sym;
228  // Fill in definition and declaration, Symbool will be invalid otherwise.
229  clangd::SymbolLocation Location;
230  Location.Start.setLine(1);
231  Location.Start.setColumn(2);
232  Location.End.setLine(3);
233  Location.End.setColumn(4);
234  Location.FileURI = testPathURI("File.h", Strings);
235  Sym.Definition = Location;
236  Sym.CanonicalDeclaration = Location;
237 
238  // Try to serialize all headers but only valid ones will end up in Protobuf
239  // message.
240  auto AllHeaders = ValidHeaders;
241  AllHeaders.insert(AllHeaders.end(), InvalidHeaders.begin(),
242  InvalidHeaders.end());
243  Sym.IncludeHeaders = AllHeaders;
244 
245  auto Serialized = toProtobuf(Sym, convert_to_slash("/"));
246  EXPECT_EQ(static_cast<size_t>(Serialized.headers_size()),
247  ValidHeaders.size());
248  auto Deserialized = fromProtobuf(Serialized, &Strings, convert_to_slash("/"));
249  EXPECT_TRUE(Deserialized);
250 
251  Sym.IncludeHeaders = ValidHeaders;
252  EXPECT_EQ(toYAML(Sym), toYAML(*Deserialized));
253 }
254 
255 TEST(RemoteMarshallingTest, FuzzyFindRequestSerialization) {
256  clangd::FuzzyFindRequest Request;
257  Request.ProximityPaths = {testPath("remote/Header.h"),
258  testPath("remote/subdir/OtherHeader.h"),
259  testPath("notremote/File.h"), "Not a Path."};
260  auto Serialized = toProtobuf(Request, testPath("remote/"));
261  EXPECT_EQ(Serialized.proximity_paths_size(), 2);
262  auto Deserialized = fromProtobuf(&Serialized, testPath("home/"));
263  EXPECT_THAT(Deserialized.ProximityPaths,
264  testing::ElementsAre(testPath("home/Header.h"),
265  testPath("home/subdir/OtherHeader.h")));
266 }
267 
268 TEST(RemoteMarshallingTest, RelativePathToURITranslation) {
269  EXPECT_TRUE(relativePathToURI("lib/File.cpp", testPath("home/project/")));
270  // RelativePath can not be absolute.
271  EXPECT_FALSE(relativePathToURI("/lib/File.cpp", testPath("home/project/")));
272  // IndexRoot has to be absolute path.
273  EXPECT_FALSE(relativePathToURI("lib/File.cpp", "home/project/"));
274 }
275 
276 TEST(RemoteMarshallingTest, URIToRelativePathTranslation) {
277  llvm::BumpPtrAllocator Arena;
278  llvm::UniqueStringSaver Strings(Arena);
279  EXPECT_TRUE(
280  uriToRelativePath(testPathURI("home/project/lib/File.cpp", Strings),
281  testPath("home/project/")));
282  // IndexRoot has to be absolute path.
283  EXPECT_FALSE(uriToRelativePath(
284  testPathURI("home/project/lib/File.cpp", Strings), "home/project/"));
285  // IndexRoot has to be be a prefix of the file path.
286  EXPECT_FALSE(
287  uriToRelativePath(testPathURI("home/project/lib/File.cpp", Strings),
288  testPath("home/other/project/")));
289 }
290 
291 } // namespace
292 } // namespace remote
293 } // namespace clangd
294 } // namespace clang
SymbolID.h
clang::clangd::TEST
TEST(BackgroundQueueTest, Priority)
Definition: BackgroundIndexTests.cpp:704
clang::clangd::testPath
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:82
clang::clangd::RefKind::Declaration
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
Location
Definition: Modularize.cpp:383
Index.h
clang::clangd::URI::create
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
Definition: URI.cpp:196
Marshalling.h
clang::clangd::remote::fromProtobuf
clangd::FuzzyFindRequest fromProtobuf(const FuzzyFindRequest *Request, llvm::StringRef IndexRoot)
Definition: Marshalling.cpp:126
clang::clangd::remote::relativePathToURI
llvm::Optional< std::string > relativePathToURI(llvm::StringRef RelativePath, llvm::StringRef IndexRoot)
Translates RelativePath into the absolute path and builds URI for the user machine.
Definition: Marshalling.cpp:289
clang::clangd::SymbolOrigin::Static
clang::clangd::toYAML
std::string toYAML(const Symbol &)
Definition: YAMLSerialization.cpp:487
TestFS.h
clang::clangd::remote::toProtobuf
LookupRequest toProtobuf(const clangd::LookupRequest &From)
Definition: Marshalling.cpp:208
clang::clangd::remote::uriToRelativePath
llvm::Optional< std::string > uriToRelativePath(llvm::StringRef URI, llvm::StringRef IndexRoot)
Translates a URI from the server's backing index to a relative path suitable to send over the wire to...
Definition: Marshalling.cpp:313
clang::clangd::toString
static const char * toString(OffsetEncoding OE)
Definition: Protocol.cpp:1170
Serialization.h
Symbol.h
clang::clangd::RefKind::Spelled
Info
FunctionInfo Info
Definition: FunctionSizeCheck.cpp:120
Strings
std::vector< llvm::StringRef > Strings
Definition: Serialization.cpp:195
Ref.h
clang::clangd::SymbolID::fromStr
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition: SymbolID.cpp:35
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
Arena
llvm::BumpPtrAllocator Arena
Definition: Serialization.cpp:194
SymbolInfo
clang::find_all_symbols::SymbolInfo SymbolInfo
Definition: FindAllSymbolsMain.cpp:38
clang::clangd::URI::createFile
static URI createFile(llvm::StringRef AbsolutePath)
This creates a file:// URI for AbsolutePath. The path must be absolute.
Definition: URI.cpp:225