clang-tools  11.0.0
SerializationTests.cpp
Go to the documentation of this file.
1 //===-- SerializationTests.cpp - Binary and YAML serialization unit tests -===//
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 "Headers.h"
10 #include "index/Index.h"
11 #include "index/Serialization.h"
12 #include "clang/Tooling/CompilationDatabase.h"
13 #include "llvm/Support/ScopedPrinter.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16 
17 using ::testing::_;
18 using ::testing::AllOf;
19 using ::testing::ElementsAre;
20 using ::testing::Pair;
21 using ::testing::UnorderedElementsAre;
22 using ::testing::UnorderedElementsAreArray;
23 
24 namespace clang {
25 namespace clangd {
26 namespace {
27 
28 const char *YAML = R"(
29 ---
30 !Symbol
31 ID: 057557CEBF6E6B2D
32 Name: 'Foo1'
33 Scope: 'clang::'
34 SymInfo:
35  Kind: Function
36  Lang: Cpp
37 CanonicalDeclaration:
38  FileURI: file:///path/foo.h
39  Start:
40  Line: 1
41  Column: 0
42  End:
43  Line: 1
44  Column: 1
45 Origin: 128
46 Flags: 129
47 Documentation: 'Foo doc'
48 ReturnType: 'int'
49 IncludeHeaders:
50  - Header: 'include1'
51  References: 7
52  - Header: 'include2'
53  References: 3
54 ...
55 ---
56 !Symbol
57 ID: 057557CEBF6E6B2E
58 Name: 'Foo2'
59 Scope: 'clang::'
60 SymInfo:
61  Kind: Function
62  Lang: Cpp
63 CanonicalDeclaration:
64  FileURI: file:///path/bar.h
65  Start:
66  Line: 1
67  Column: 0
68  End:
69  Line: 1
70  Column: 1
71 Flags: 2
72 Signature: '-sig'
73 CompletionSnippetSuffix: '-snippet'
74 ...
75 !Refs
76 ID: 057557CEBF6E6B2D
77 References:
78  - Kind: 4
79  Location:
80  FileURI: file:///path/foo.cc
81  Start:
82  Line: 5
83  Column: 3
84  End:
85  Line: 5
86  Column: 8
87 ...
88 --- !Relations
89 Subject:
90  ID: 6481EE7AF2841756
91 Predicate: 0
92 Object:
93  ID: 6512AEC512EA3A2D
94 ...
95 --- !Cmd
96 Directory: 'testdir'
97 CommandLine:
98  - 'cmd1'
99  - 'cmd2'
100 ...
101 --- !Source
102 URI: 'file:///path/source1.cpp'
103 Flags: 1
104 Digest: EED8F5EAF25C453C
105 DirectIncludes:
106  - 'file:///path/inc1.h'
107  - 'file:///path/inc2.h'
108 ...
109 )";
110 
111 MATCHER_P(ID, I, "") { return arg.ID == cantFail(SymbolID::fromStr(I)); }
112 MATCHER_P(QName, Name, "") { return (arg.Scope + arg.Name).str() == Name; }
113 MATCHER_P2(IncludeHeaderWithRef, IncludeHeader, References, "") {
114  return (arg.IncludeHeader == IncludeHeader) && (arg.References == References);
115 }
116 
117 TEST(SerializationTest, NoCrashOnEmptyYAML) {
118  EXPECT_TRUE(bool(readIndexFile("")));
119 }
120 
121 TEST(SerializationTest, YAMLConversions) {
122  auto ParsedYAML = readIndexFile(YAML);
123  ASSERT_TRUE(bool(ParsedYAML)) << ParsedYAML.takeError();
124  ASSERT_TRUE(bool(ParsedYAML->Symbols));
125  EXPECT_THAT(
126  *ParsedYAML->Symbols,
127  UnorderedElementsAre(ID("057557CEBF6E6B2D"), ID("057557CEBF6E6B2E")));
128 
129  auto Sym1 = *ParsedYAML->Symbols->find(
130  cantFail(SymbolID::fromStr("057557CEBF6E6B2D")));
131  auto Sym2 = *ParsedYAML->Symbols->find(
132  cantFail(SymbolID::fromStr("057557CEBF6E6B2E")));
133 
134  EXPECT_THAT(Sym1, QName("clang::Foo1"));
135  EXPECT_EQ(Sym1.Signature, "");
136  EXPECT_EQ(Sym1.Documentation, "Foo doc");
137  EXPECT_EQ(Sym1.ReturnType, "int");
138  EXPECT_EQ(StringRef(Sym1.CanonicalDeclaration.FileURI), "file:///path/foo.h");
139  EXPECT_EQ(Sym1.Origin, static_cast<SymbolOrigin>(1 << 7));
140  EXPECT_EQ(static_cast<uint8_t>(Sym1.Flags), 129);
141  EXPECT_TRUE(Sym1.Flags & Symbol::IndexedForCodeCompletion);
142  EXPECT_FALSE(Sym1.Flags & Symbol::Deprecated);
143  EXPECT_THAT(Sym1.IncludeHeaders,
144  UnorderedElementsAre(IncludeHeaderWithRef("include1", 7u),
145  IncludeHeaderWithRef("include2", 3u)));
146 
147  EXPECT_THAT(Sym2, QName("clang::Foo2"));
148  EXPECT_EQ(Sym2.Signature, "-sig");
149  EXPECT_EQ(Sym2.ReturnType, "");
150  EXPECT_EQ(llvm::StringRef(Sym2.CanonicalDeclaration.FileURI),
151  "file:///path/bar.h");
152  EXPECT_FALSE(Sym2.Flags & Symbol::IndexedForCodeCompletion);
153  EXPECT_TRUE(Sym2.Flags & Symbol::Deprecated);
154 
155  ASSERT_TRUE(bool(ParsedYAML->Refs));
156  EXPECT_THAT(
157  *ParsedYAML->Refs,
158  UnorderedElementsAre(Pair(cantFail(SymbolID::fromStr("057557CEBF6E6B2D")),
159  ::testing::SizeIs(1))));
160  auto Ref1 = ParsedYAML->Refs->begin()->second.front();
161  EXPECT_EQ(Ref1.Kind, RefKind::Reference);
162  EXPECT_EQ(StringRef(Ref1.Location.FileURI), "file:///path/foo.cc");
163 
164  SymbolID Base = cantFail(SymbolID::fromStr("6481EE7AF2841756"));
165  SymbolID Derived = cantFail(SymbolID::fromStr("6512AEC512EA3A2D"));
166  ASSERT_TRUE(bool(ParsedYAML->Relations));
167  EXPECT_THAT(
168  *ParsedYAML->Relations,
169  UnorderedElementsAre(Relation{Base, RelationKind::BaseOf, Derived}));
170 
171  ASSERT_TRUE(bool(ParsedYAML->Cmd));
172  auto &Cmd = *ParsedYAML->Cmd;
173  ASSERT_EQ(Cmd.Directory, "testdir");
174  EXPECT_THAT(Cmd.CommandLine, ElementsAre("cmd1", "cmd2"));
175 
176  ASSERT_TRUE(bool(ParsedYAML->Sources));
177  const auto *URI = "file:///path/source1.cpp";
178  ASSERT_TRUE(ParsedYAML->Sources->count(URI));
179  auto IGNDeserialized = ParsedYAML->Sources->lookup(URI);
180  EXPECT_EQ(llvm::toHex(IGNDeserialized.Digest), "EED8F5EAF25C453C");
181  EXPECT_THAT(IGNDeserialized.DirectIncludes,
182  ElementsAre("file:///path/inc1.h", "file:///path/inc2.h"));
183  EXPECT_EQ(IGNDeserialized.URI, URI);
184  EXPECT_EQ(IGNDeserialized.Flags, IncludeGraphNode::SourceFlag(1));
185 }
186 
187 std::vector<std::string> YAMLFromSymbols(const SymbolSlab &Slab) {
188  std::vector<std::string> Result;
189  for (const auto &Sym : Slab)
190  Result.push_back(toYAML(Sym));
191  return Result;
192 }
193 std::vector<std::string> YAMLFromRefs(const RefSlab &Slab) {
194  std::vector<std::string> Result;
195  for (const auto &Refs : Slab)
196  Result.push_back(toYAML(Refs));
197  return Result;
198 }
199 
200 std::vector<std::string> YAMLFromRelations(const RelationSlab &Slab) {
201  std::vector<std::string> Result;
202  for (const auto &Rel : Slab)
203  Result.push_back(toYAML(Rel));
204  return Result;
205 }
206 
207 TEST(SerializationTest, BinaryConversions) {
208  auto In = readIndexFile(YAML);
209  EXPECT_TRUE(bool(In)) << In.takeError();
210 
211  // Write to binary format, and parse again.
212  IndexFileOut Out(*In);
213  Out.Format = IndexFileFormat::RIFF;
214  std::string Serialized = llvm::to_string(Out);
215 
216  auto In2 = readIndexFile(Serialized);
217  ASSERT_TRUE(bool(In2)) << In.takeError();
218  ASSERT_TRUE(In2->Symbols);
219  ASSERT_TRUE(In2->Refs);
220  ASSERT_TRUE(In2->Relations);
221 
222  // Assert the YAML serializations match, for nice comparisons and diffs.
223  EXPECT_THAT(YAMLFromSymbols(*In2->Symbols),
224  UnorderedElementsAreArray(YAMLFromSymbols(*In->Symbols)));
225  EXPECT_THAT(YAMLFromRefs(*In2->Refs),
226  UnorderedElementsAreArray(YAMLFromRefs(*In->Refs)));
227  EXPECT_THAT(YAMLFromRelations(*In2->Relations),
228  UnorderedElementsAreArray(YAMLFromRelations(*In->Relations)));
229 }
230 
231 TEST(SerializationTest, SrcsTest) {
232  auto In = readIndexFile(YAML);
233  EXPECT_TRUE(bool(In)) << In.takeError();
234 
235  std::string TestContent("TestContent");
236  IncludeGraphNode IGN;
237  IGN.Digest = digest(TestContent);
238  IGN.DirectIncludes = {"inc1", "inc2"};
239  IGN.URI = "URI";
242  IncludeGraph Sources;
243  Sources[IGN.URI] = IGN;
244  // Write to binary format, and parse again.
245  IndexFileOut Out(*In);
246  Out.Format = IndexFileFormat::RIFF;
247  Out.Sources = &Sources;
248  {
249  std::string Serialized = llvm::to_string(Out);
250 
251  auto In = readIndexFile(Serialized);
252  ASSERT_TRUE(bool(In)) << In.takeError();
253  ASSERT_TRUE(In->Symbols);
254  ASSERT_TRUE(In->Refs);
255  ASSERT_TRUE(In->Sources);
256  ASSERT_TRUE(In->Sources->count(IGN.URI));
257  // Assert the YAML serializations match, for nice comparisons and diffs.
258  EXPECT_THAT(YAMLFromSymbols(*In->Symbols),
259  UnorderedElementsAreArray(YAMLFromSymbols(*In->Symbols)));
260  EXPECT_THAT(YAMLFromRefs(*In->Refs),
261  UnorderedElementsAreArray(YAMLFromRefs(*In->Refs)));
262  auto IGNDeserialized = In->Sources->lookup(IGN.URI);
263  EXPECT_EQ(IGNDeserialized.Digest, IGN.Digest);
264  EXPECT_EQ(IGNDeserialized.DirectIncludes, IGN.DirectIncludes);
265  EXPECT_EQ(IGNDeserialized.URI, IGN.URI);
266  EXPECT_EQ(IGNDeserialized.Flags, IGN.Flags);
267  }
268 }
269 
270 TEST(SerializationTest, CmdlTest) {
271  auto In = readIndexFile(YAML);
272  EXPECT_TRUE(bool(In)) << In.takeError();
273 
274  tooling::CompileCommand Cmd;
275  Cmd.Directory = "testdir";
276  Cmd.CommandLine.push_back("cmd1");
277  Cmd.CommandLine.push_back("cmd2");
278  Cmd.Filename = "ignored";
279  Cmd.Heuristic = "ignored";
280  Cmd.Output = "ignored";
281 
282  IndexFileOut Out(*In);
283  Out.Format = IndexFileFormat::RIFF;
284  Out.Cmd = &Cmd;
285  {
286  std::string Serialized = llvm::to_string(Out);
287 
288  auto In = readIndexFile(Serialized);
289  ASSERT_TRUE(bool(In)) << In.takeError();
290  ASSERT_TRUE(In->Cmd);
291 
292  const tooling::CompileCommand &SerializedCmd = In->Cmd.getValue();
293  EXPECT_EQ(SerializedCmd.CommandLine, Cmd.CommandLine);
294  EXPECT_EQ(SerializedCmd.Directory, Cmd.Directory);
295  EXPECT_NE(SerializedCmd.Filename, Cmd.Filename);
296  EXPECT_NE(SerializedCmd.Heuristic, Cmd.Heuristic);
297  EXPECT_NE(SerializedCmd.Output, Cmd.Output);
298  }
299 }
300 } // namespace
301 } // namespace clangd
302 } // namespace clang
clang::clangd::IndexFileFormat::YAML
clang::clangd::Symbol::IndexedForCodeCompletion
Whether or not this symbol is meant to be used for the code completion.
Definition: Symbol.h:119
Base
std::unique_ptr< GlobalCompilationDatabase > Base
Definition: GlobalCompilationDatabaseTests.cpp:85
clang::clangd::TEST
TEST(BackgroundQueueTest, Priority)
Definition: BackgroundIndexTests.cpp:704
Headers.h
References
unsigned References
Definition: CodeComplete.cpp:161
clang::clangd::RelationKind::BaseOf
clang::clangd::digest
FileDigest digest(llvm::StringRef Content)
Definition: SourceCode.cpp:560
Refs
RefSlab Refs
Definition: SymbolCollectorTests.cpp:296
clang::clangd::IndexFileFormat::RIFF
Index.h
clang::clangd::Symbol::Deprecated
Indicates if the symbol is deprecated.
Definition: Symbol.h:121
clang::clangd::IncludeGraphNode::SourceFlag::IsTU
clang::clangd::readIndexFile
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data)
Definition: Serialization.cpp:657
clang::clangd::toYAML
std::string toYAML(const Symbol &)
Definition: YAMLSerialization.cpp:487
clang::clangd::IncludeGraphNode::SourceFlag
SourceFlag
Definition: Headers.h:69
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::clangd::RefKind::Reference
Serialization.h
clang::doc::SymbolID
std::array< uint8_t, 20 > SymbolID
Definition: Representation.h:30
clang::clangd::IncludeGraphNode::SourceFlag::HadErrors
clang::clangd::MATCHER_P
MATCHER_P(Named, N, "")
Definition: BackgroundIndexTests.cpp:29
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
clang::clangd::IncludeGraph
llvm::StringMap< IncludeGraphNode > IncludeGraph
Definition: Headers.h:86
Out
CompiledFragmentImpl & Out
Definition: ConfigCompile.cpp:70