clang-tools 24.0.0git
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 "FindSymbols.h"
10#include "Headers.h"
11#include "RIFF.h"
12#include "index/Serialization.h"
13#include "support/Logger.h"
14#include "clang/Tooling/CompilationDatabase.h"
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
17#include "llvm/Support/Compression.h"
18#include "llvm/Support/Error.h"
19#include "llvm/Support/ScopedPrinter.h"
20#include "gmock/gmock.h"
21#include "gtest/gtest.h"
22#ifdef LLVM_ON_UNIX
23#include <sys/resource.h>
24#endif
25
26using ::testing::ElementsAre;
27using ::testing::Pair;
28using ::testing::UnorderedElementsAre;
29using ::testing::UnorderedElementsAreArray;
30
31namespace clang {
32namespace clangd {
33namespace {
34
35const char *YAML = R"(
36---
37!Symbol
38ID: 057557CEBF6E6B2D
39Name: 'Foo1'
40Scope: 'clang::'
41SymInfo:
42 Kind: Function
43 Lang: Cpp
44CanonicalDeclaration:
45 FileURI: file:///path/foo.h
46 Start:
47 Line: 1
48 Column: 0
49 End:
50 Line: 1
51 Column: 1
52Flags: 129
53Tags: 258
54Documentation: 'Foo doc'
55ReturnType: 'int'
56IncludeHeaders:
57 - Header: 'include1'
58 References: 7
59 Directives: [ Include ]
60 - Header: 'include2'
61 References: 3
62 Directives: [ Import ]
63 - Header: 'include3'
64 References: 2
65 Directives: [ Include, Import ]
66 - Header: 'include4'
67 References: 1
68 Directives: [ ]
69...
70---
71!Symbol
72ID: 057557CEBF6E6B2E
73Name: 'Foo2'
74Scope: 'clang::'
75SymInfo:
76 Kind: Function
77 Lang: Cpp
78CanonicalDeclaration:
79 FileURI: file:///path/bar.h
80 Start:
81 Line: 1
82 Column: 0
83 End:
84 Line: 1
85 Column: 1
86Flags: 2
87Signature: '-sig'
88CompletionSnippetSuffix: '-snippet'
89...
90!Refs
91ID: 057557CEBF6E6B2D
92References:
93 - Kind: 4
94 Location:
95 FileURI: file:///path/foo.cc
96 Start:
97 Line: 5
98 Column: 3
99 End:
100 Line: 5
101 Column: 8
102...
103--- !Relations
104Subject:
105 ID: 6481EE7AF2841756
106Predicate: 0
107Object:
108 ID: 6512AEC512EA3A2D
109...
110--- !Cmd
111Directory: 'testdir'
112CommandLine:
113 - 'cmd1'
114 - 'cmd2'
115...
116--- !Source
117URI: 'file:///path/source1.cpp'
118Flags: 1
119Digest: EED8F5EAF25C453C
120DirectIncludes:
121 - 'file:///path/inc1.h'
122 - 'file:///path/inc2.h'
123...
124)";
125
126MATCHER_P(id, I, "") { return arg.ID == cantFail(SymbolID::fromStr(I)); }
127MATCHER_P(qName, Name, "") { return (arg.Scope + arg.Name).str() == Name; }
128MATCHER_P3(IncludeHeaderWithRefAndDirectives, IncludeHeader, References,
129 SupportedDirectives, "") {
130 return (arg.IncludeHeader == IncludeHeader) &&
131 (arg.References == References) &&
132 (arg.SupportedDirectives == SupportedDirectives);
133}
134
135auto readIndexFile(llvm::StringRef Text) {
137}
138
139TEST(SerializationTest, NoCrashOnEmptyYAML) {
140 EXPECT_TRUE(bool(readIndexFile("")));
141}
142
143TEST(SerializationTest, YAMLConversions) {
144 auto ParsedYAML = readIndexFile(YAML);
145 ASSERT_TRUE(bool(ParsedYAML)) << ParsedYAML.takeError();
146 ASSERT_TRUE(bool(ParsedYAML->Symbols));
147 EXPECT_THAT(
148 *ParsedYAML->Symbols,
149 UnorderedElementsAre(id("057557CEBF6E6B2D"), id("057557CEBF6E6B2E")));
150
151 auto Sym1 = *ParsedYAML->Symbols->find(
152 cantFail(SymbolID::fromStr("057557CEBF6E6B2D")));
153 auto Sym2 = *ParsedYAML->Symbols->find(
154 cantFail(SymbolID::fromStr("057557CEBF6E6B2E")));
155
156 EXPECT_THAT(Sym1, qName("clang::Foo1"));
157 EXPECT_EQ(Sym1.Signature, "");
158 EXPECT_EQ(Sym1.Documentation, "Foo doc");
159 EXPECT_EQ(Sym1.ReturnType, "int");
160 EXPECT_EQ(StringRef(Sym1.CanonicalDeclaration.FileURI), "file:///path/foo.h");
161 EXPECT_EQ(Sym1.Origin, SymbolOrigin::Static);
162 EXPECT_EQ(static_cast<uint8_t>(Sym1.Flags), 129);
163 EXPECT_TRUE(Sym1.Flags & Symbol::IndexedForCodeCompletion);
164 EXPECT_FALSE(Sym1.Flags & Symbol::Deprecated);
165 // Tags: Deprecated (1<<1=2) | Static (1<<8=256) = 258
166 EXPECT_EQ(Sym1.Tags, 258u);
167 EXPECT_TRUE(Sym1.Tags & toSymbolTagBitmask(SymbolTag::Deprecated));
168 EXPECT_TRUE(Sym1.Tags & toSymbolTagBitmask(SymbolTag::Static));
169 EXPECT_THAT(
170 Sym1.IncludeHeaders,
171 UnorderedElementsAre(
172 IncludeHeaderWithRefAndDirectives("include1", 7u, Symbol::Include),
173 IncludeHeaderWithRefAndDirectives("include2", 3u, Symbol::Import),
174 IncludeHeaderWithRefAndDirectives("include3", 2u,
176 IncludeHeaderWithRefAndDirectives("include4", 1u, Symbol::Invalid)));
177
178 EXPECT_THAT(Sym2, qName("clang::Foo2"));
179 EXPECT_EQ(Sym2.Signature, "-sig");
180 EXPECT_EQ(Sym2.ReturnType, "");
181 EXPECT_EQ(llvm::StringRef(Sym2.CanonicalDeclaration.FileURI),
182 "file:///path/bar.h");
183 EXPECT_FALSE(Sym2.Flags & Symbol::IndexedForCodeCompletion);
184 EXPECT_TRUE(Sym2.Flags & Symbol::Deprecated);
185 EXPECT_EQ(Sym2.Tags, 0u); // no Tags in YAML → default zero
186
187 ASSERT_TRUE(bool(ParsedYAML->Refs));
188 EXPECT_THAT(
189 *ParsedYAML->Refs,
190 UnorderedElementsAre(Pair(cantFail(SymbolID::fromStr("057557CEBF6E6B2D")),
191 ::testing::SizeIs(1))));
192 auto Ref1 = ParsedYAML->Refs->begin()->second.front();
193 EXPECT_EQ(Ref1.Kind, RefKind::Reference);
194 EXPECT_EQ(StringRef(Ref1.Location.FileURI), "file:///path/foo.cc");
195
196 SymbolID Base = cantFail(SymbolID::fromStr("6481EE7AF2841756"));
197 SymbolID Derived = cantFail(SymbolID::fromStr("6512AEC512EA3A2D"));
198 ASSERT_TRUE(bool(ParsedYAML->Relations));
199 EXPECT_THAT(
200 *ParsedYAML->Relations,
201 UnorderedElementsAre(Relation{Base, RelationKind::BaseOf, Derived}));
202
203 ASSERT_TRUE(bool(ParsedYAML->Cmd));
204 auto &Cmd = *ParsedYAML->Cmd;
205 ASSERT_EQ(Cmd.Directory, "testdir");
206 EXPECT_THAT(Cmd.CommandLine, ElementsAre("cmd1", "cmd2"));
207
208 ASSERT_TRUE(bool(ParsedYAML->Sources));
209 const auto *URI = "file:///path/source1.cpp";
210 ASSERT_TRUE(ParsedYAML->Sources->count(URI));
211 auto IGNDeserialized = ParsedYAML->Sources->lookup(URI);
212 EXPECT_EQ(llvm::toHex(IGNDeserialized.Digest), "EED8F5EAF25C453C");
213 EXPECT_THAT(IGNDeserialized.DirectIncludes,
214 ElementsAre("file:///path/inc1.h", "file:///path/inc2.h"));
215 EXPECT_EQ(IGNDeserialized.URI, URI);
216 EXPECT_EQ(IGNDeserialized.Flags, IncludeGraphNode::SourceFlag(1));
217}
218
219std::vector<std::string> yamlFromSymbols(const SymbolSlab &Slab) {
220 std::vector<std::string> Result;
221 for (const auto &Sym : Slab)
222 Result.push_back(toYAML(Sym));
223 return Result;
224}
225std::vector<std::string> yamlFromRefs(const RefSlab &Slab) {
226 std::vector<std::string> Result;
227 for (const auto &Refs : Slab)
228 Result.push_back(toYAML(Refs));
229 return Result;
230}
231
232std::vector<std::string> yamlFromRelations(const RelationSlab &Slab) {
233 std::vector<std::string> Result;
234 for (const auto &Rel : Slab)
235 Result.push_back(toYAML(Rel));
236 return Result;
237}
238
239TEST(SerializationTest, BinaryConversions) {
240 auto In = readIndexFile(YAML);
241 EXPECT_TRUE(bool(In)) << In.takeError();
242
243 // Write to binary format, and parse again.
244 IndexFileOut Out(*In);
245 Out.Format = IndexFileFormat::RIFF;
246 std::string Serialized = llvm::to_string(Out);
247
248 auto In2 = readIndexFile(Serialized);
249 ASSERT_TRUE(bool(In2)) << In2.takeError();
250 ASSERT_TRUE(In2->Symbols);
251 ASSERT_TRUE(In2->Refs);
252 ASSERT_TRUE(In2->Relations);
253
254 // Assert the YAML serializations match, for nice comparisons and diffs.
255 EXPECT_THAT(yamlFromSymbols(*In2->Symbols),
256 UnorderedElementsAreArray(yamlFromSymbols(*In->Symbols)));
257 EXPECT_THAT(yamlFromRefs(*In2->Refs),
258 UnorderedElementsAreArray(yamlFromRefs(*In->Refs)));
259 EXPECT_THAT(yamlFromRelations(*In2->Relations),
260 UnorderedElementsAreArray(yamlFromRelations(*In->Relations)));
261}
262
263TEST(SerializationTest, SrcsTest) {
264 auto In = readIndexFile(YAML);
265 EXPECT_TRUE(bool(In)) << In.takeError();
266
267 std::string TestContent("TestContent");
269 IGN.Digest = digest(TestContent);
270 IGN.DirectIncludes = {"inc1", "inc2"};
271 IGN.URI = "URI";
274 IncludeGraph Sources;
275 Sources[IGN.URI] = IGN;
276 // Write to binary format, and parse again.
277 IndexFileOut Out(*In);
278 Out.Format = IndexFileFormat::RIFF;
279 Out.Sources = &Sources;
280 {
281 std::string Serialized = llvm::to_string(Out);
282
283 auto In = readIndexFile(Serialized);
284 ASSERT_TRUE(bool(In)) << In.takeError();
285 ASSERT_TRUE(In->Symbols);
286 ASSERT_TRUE(In->Refs);
287 ASSERT_TRUE(In->Sources);
288 ASSERT_TRUE(In->Sources->count(IGN.URI));
289 // Assert the YAML serializations match, for nice comparisons and diffs.
290 EXPECT_THAT(yamlFromSymbols(*In->Symbols),
291 UnorderedElementsAreArray(yamlFromSymbols(*In->Symbols)));
292 EXPECT_THAT(yamlFromRefs(*In->Refs),
293 UnorderedElementsAreArray(yamlFromRefs(*In->Refs)));
294 auto IGNDeserialized = In->Sources->lookup(IGN.URI);
295 EXPECT_EQ(IGNDeserialized.Digest, IGN.Digest);
296 EXPECT_EQ(IGNDeserialized.DirectIncludes, IGN.DirectIncludes);
297 EXPECT_EQ(IGNDeserialized.URI, IGN.URI);
298 EXPECT_EQ(IGNDeserialized.Flags, IGN.Flags);
299 }
300}
301
302// Verify that Symbol::Tags survive a full YAML -> RIFF -> read roundtrip.
303// This exercises both writeSymbol (new Tags field) and readSymbol.
304TEST(SerializationTest, TagsRoundTrip) {
305 // YAML fixture with a single symbol carrying non-zero Tags.
306 // Deprecated (SymbolTag=1) -> bit 1 -> 1<<1 = 2
307 // Static (SymbolTag=8) -> bit 8 -> 1<<8 = 256
308 // Combined: 258
309 const char *TaggedYAML = R"(
310---
311!Symbol
312ID: AABBCCDDEEFF0011
313Name: 'Tagged'
314Scope: 'ns::'
315SymInfo:
316 Kind: Function
317 Lang: Cpp
318CanonicalDeclaration:
319 FileURI: file:///tmp/tagged.h
320 Start:
321 Line: 0
322 Column: 0
323 End:
324 Line: 0
325 Column: 1
326Flags: 1
327Tags: 258
328...
329)";
330 const SymbolID TaggedID = cantFail(SymbolID::fromStr("AABBCCDDEEFF0011"));
331 const SymbolTags ExpectedTags =
334 constexpr unsigned ExpectedTagMask = 258u;
335 EXPECT_EQ(ExpectedTags, ExpectedTagMask); // bitmask sanity check
336
337 // ── Step 1: YAML deserialization ────────────────────────────────────────
338 auto FromYAML = readIndexFile(TaggedYAML);
339 ASSERT_TRUE(bool(FromYAML)) << FromYAML.takeError();
340 ASSERT_TRUE(bool(FromYAML->Symbols));
341 {
342 auto It = FromYAML->Symbols->find(TaggedID);
343 ASSERT_NE(It, FromYAML->Symbols->end())
344 << "symbol not found after YAML parse";
345 EXPECT_EQ(It->Tags, ExpectedTags)
346 << "Tags lost during YAML deserialization";
347 }
348
349 // ── Step 2: RIFF serialization + deserialization ────────────────────────
350 IndexFileOut Out(*FromYAML);
351 Out.Format = IndexFileFormat::RIFF;
352 std::string Serialized = llvm::to_string(Out);
353
354 auto FromRIFF = readIndexFile(Serialized);
355 ASSERT_TRUE(bool(FromRIFF)) << FromRIFF.takeError();
356 ASSERT_TRUE(bool(FromRIFF->Symbols));
357 {
358 auto It = FromRIFF->Symbols->find(TaggedID);
359 ASSERT_NE(It, FromRIFF->Symbols->end())
360 << "symbol not found after RIFF roundtrip";
361 EXPECT_EQ(It->Tags, ExpectedTags) << "Tags lost during RIFF serialization";
362 // Spot-check individual bits
363 EXPECT_TRUE(It->Tags & toSymbolTagBitmask(SymbolTag::Deprecated));
364 EXPECT_TRUE(It->Tags & toSymbolTagBitmask(SymbolTag::Static));
365 EXPECT_FALSE(It->Tags & toSymbolTagBitmask(SymbolTag::Abstract));
366 }
367
368 // ── Step 3: Symbol with Tags=0 must survive too ─────────────────────────
369 const char *UntaggedYAML = R"(
370---
371!Symbol
372ID: 0000000000000001
373Name: 'Untagged'
374Scope: ''
375SymInfo:
376 Kind: Variable
377 Lang: Cpp
378CanonicalDeclaration:
379 FileURI: file:///tmp/untagged.h
380 Start:
381 Line: 0
382 Column: 0
383 End:
384 Line: 0
385 Column: 1
386Flags: 1
387...
388)";
389 auto FromUntaggedYAML = readIndexFile(UntaggedYAML);
390 ASSERT_TRUE(bool(FromUntaggedYAML)) << FromUntaggedYAML.takeError();
391 ASSERT_TRUE(bool(FromUntaggedYAML->Symbols));
392 IndexFileOut Out2(*FromUntaggedYAML);
393 Out2.Format = IndexFileFormat::RIFF;
394 auto FromUntaggedRIFF = readIndexFile(llvm::to_string(Out2));
395 ASSERT_TRUE(bool(FromUntaggedRIFF)) << FromUntaggedRIFF.takeError();
396 ASSERT_TRUE(bool(FromUntaggedRIFF->Symbols));
397 {
398 const SymbolID UntaggedID = cantFail(SymbolID::fromStr("0000000000000001"));
399 auto It = FromUntaggedRIFF->Symbols->find(UntaggedID);
400 ASSERT_NE(It, FromUntaggedRIFF->Symbols->end());
401 EXPECT_EQ(It->Tags, 0u) << "Tags must be zero for untagged symbol";
402 }
403}
404
405TEST(SerializationTest, CmdlTest) {
406 auto In = readIndexFile(YAML);
407 EXPECT_TRUE(bool(In)) << In.takeError();
408
409 tooling::CompileCommand Cmd;
410 Cmd.Directory = "testdir";
411 Cmd.CommandLine.push_back("cmd1");
412 Cmd.CommandLine.push_back("cmd2");
413 Cmd.Filename = "ignored";
414 Cmd.Heuristic = "ignored";
415 Cmd.Output = "ignored";
416
417 IndexFileOut Out(*In);
418 Out.Format = IndexFileFormat::RIFF;
419 Out.Cmd = &Cmd;
420 {
421 std::string Serialized = llvm::to_string(Out);
422
423 auto In = readIndexFile(Serialized);
424 ASSERT_TRUE(bool(In)) << In.takeError();
425 ASSERT_TRUE(In->Cmd);
426
427 const tooling::CompileCommand &SerializedCmd = *In->Cmd;
428 EXPECT_EQ(SerializedCmd.CommandLine, Cmd.CommandLine);
429 EXPECT_EQ(SerializedCmd.Directory, Cmd.Directory);
430 EXPECT_NE(SerializedCmd.Filename, Cmd.Filename);
431 EXPECT_NE(SerializedCmd.Heuristic, Cmd.Heuristic);
432 EXPECT_NE(SerializedCmd.Output, Cmd.Output);
433 }
434}
435
436// rlimit is part of POSIX. RLIMIT_AS does not exist in OpenBSD.
437// Sanitizers use a lot of address space, so we can't apply strict limits.
438#if LLVM_ON_UNIX && defined(RLIMIT_AS) && !LLVM_ADDRESS_SANITIZER_BUILD && \
439 !LLVM_MEMORY_SANITIZER_BUILD && !LLVM_THREAD_SANITIZER_BUILD
440class ScopedMemoryLimit {
441 struct rlimit OriginalLimit;
442 bool Succeeded = false;
443
444public:
445 ScopedMemoryLimit(rlim_t Bytes) {
446 if (!getrlimit(RLIMIT_AS, &OriginalLimit)) {
447 struct rlimit NewLimit = OriginalLimit;
448 NewLimit.rlim_cur = Bytes;
449 Succeeded = !setrlimit(RLIMIT_AS, &NewLimit);
450 }
451 if (!Succeeded)
452 log("Failed to set rlimit");
453 }
454
455 ~ScopedMemoryLimit() {
456 if (Succeeded)
457 setrlimit(RLIMIT_AS, &OriginalLimit);
458 }
459};
460#else
461class ScopedMemoryLimit {
462public:
463 ScopedMemoryLimit(unsigned Bytes) { log("rlimit unsupported"); }
464};
465#endif
466
467// Test that our deserialization detects invalid array sizes without allocating.
468// If this detection fails, the test should allocate a huge array and crash.
469TEST(SerializationTest, NoCrashOnBadArraySize) {
470 // This test is tricky because we need to construct a subtly invalid file.
471 // First, create a valid serialized file.
472 auto In = readIndexFile(YAML);
473 ASSERT_FALSE(!In) << In.takeError();
474 IndexFileOut Out(*In);
475 Out.Format = IndexFileFormat::RIFF;
476 std::string Serialized = llvm::to_string(Out);
477
478 // Low-level parse it again and find the `srcs` chunk we're going to corrupt.
479 auto Parsed = riff::readFile(Serialized);
480 ASSERT_FALSE(!Parsed) << Parsed.takeError();
481 auto Srcs = llvm::find_if(Parsed->Chunks, [](riff::Chunk C) {
482 return C.ID == riff::fourCC("srcs");
483 });
484 ASSERT_NE(Srcs, Parsed->Chunks.end());
485
486 // Srcs consists of a sequence of IncludeGraphNodes. In our case, just one.
487 // The node has:
488 // - 1 byte: flags (1)
489 // - varint(stringID): URI
490 // - 8 byte: file digest
491 // - varint: DirectIncludes.length
492 // - repeated varint(stringID): DirectIncludes
493 // We want to set DirectIncludes.length to a huge number.
494 // The offset isn't trivial to find, so we use the file digest.
495 std::string FileDigest = llvm::fromHex("EED8F5EAF25C453C");
496 unsigned Pos = Srcs->Data.find_first_of(FileDigest);
497 ASSERT_NE(Pos, StringRef::npos) << "Couldn't locate file digest";
498 Pos += FileDigest.size();
499
500 // Varints are little-endian base-128 numbers, where the top-bit of each byte
501 // indicates whether there are more. ffffffff0f -> 0xffffffff.
502 std::string CorruptSrcs =
503 (Srcs->Data.take_front(Pos) + llvm::fromHex("ffffffff0f") +
504 "some_random_garbage")
505 .str();
506 Srcs->Data = CorruptSrcs;
507
508 // Try to crash rather than hang on large allocation.
509 ScopedMemoryLimit MemLimit(1000 * 1024 * 1024); // 1GB
510
511 std::string CorruptFile = llvm::to_string(*Parsed);
512 auto CorruptParsed = readIndexFile(CorruptFile);
513 ASSERT_TRUE(!CorruptParsed);
514 EXPECT_EQ(llvm::toString(CorruptParsed.takeError()),
515 "malformed or truncated include uri");
516}
517
518// Check we detect invalid string table size size without allocating it first.
519// If this detection fails, the test should allocate a huge array and crash.
520TEST(SerializationTest, NoCrashOnBadStringTableSize) {
521 if (!llvm::compression::zlib::isAvailable()) {
522 log("skipping test, no zlib");
523 return;
524 }
525
526 // First, create a valid serialized file.
527 auto In = readIndexFile(YAML);
528 ASSERT_FALSE(!In) << In.takeError();
529 IndexFileOut Out(*In);
530 Out.Format = IndexFileFormat::RIFF;
531 std::string Serialized = llvm::to_string(Out);
532
533 // Low-level parse it again, we're going to replace the `stri` chunk.
534 auto Parsed = riff::readFile(Serialized);
535 ASSERT_FALSE(!Parsed) << Parsed.takeError();
536 auto Stri = llvm::find_if(Parsed->Chunks, [](riff::Chunk C) {
537 return C.ID == riff::fourCC("stri");
538 });
539 ASSERT_NE(Stri, Parsed->Chunks.end());
540
541 // stri consists of an 8 byte uncompressed-size, and then compressed data.
542 // We'll claim our small amount of data expands to 4GB
543 std::string CorruptStri =
544 (llvm::fromHex("ffffffff") + Stri->Data.drop_front(4)).str();
545 Stri->Data = CorruptStri;
546
547 // Try to crash rather than hang on large allocation.
548 ScopedMemoryLimit MemLimit(1000 * 1024 * 1024); // 1GB
549
550 std::string CorruptFile = llvm::to_string(*Parsed);
551 auto CorruptParsed = readIndexFile(CorruptFile);
552 ASSERT_TRUE(!CorruptParsed);
553 EXPECT_THAT(llvm::toString(CorruptParsed.takeError()),
554 testing::HasSubstr("bytes is implausible"));
555}
556
557} // namespace
558} // namespace clangd
559} // namespace clang
An efficient structure of storing large set of symbol references in memory.
Definition Ref.h:111
static llvm::Expected< SymbolID > fromStr(llvm::StringRef)
Definition SymbolID.cpp:37
An immutable symbol container that stores a set of symbols.
Definition Symbol.h:215
A URI describes the location of a source file.
Definition URI.h:28
llvm::Expected< File > readFile(llvm::StringRef Stream)
Definition RIFF.cpp:48
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data, SymbolOrigin Origin)
uint32_t SymbolTags
A bitmask type representing symbol tags supported by LSP.
Definition Symbol.h:29
FileDigest digest(llvm::StringRef Content)
MATCHER_P(named, N, "")
SymbolTags toSymbolTagBitmask(const SymbolTag ST)
Converts a single SymbolTag to a bitmask.
TEST(BackgroundQueueTest, Priority)
llvm::StringMap< IncludeGraphNode > IncludeGraph
Definition Headers.h:103
void log(const char *Fmt, Ts &&... Vals)
Definition Logger.h:67
std::string toYAML(const Symbol &)
std::array< uint8_t, 8 > FileDigest
Definition SourceCode.h:42
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Represents a relation between two symbols.
Definition Relation.h:32
@ IndexedForCodeCompletion
Whether or not this symbol is meant to be used for the code completion.
Definition Symbol.h:155
@ Deprecated
Indicates if the symbol is deprecated.
Definition Symbol.h:157
@ Include
#include "header.h"
Definition Symbol.h:107
@ Import
#import "header.h"
Definition Symbol.h:109