clang-tools 8.0.0

Merge.cpp
Go to the documentation of this file.
1 //===--- Merge.cpp -----------------------------------------------*- C++-*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "Merge.h"
11 #include "Logger.h"
12 #include "Trace.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/StringSet.h"
15 #include "llvm/Support/raw_ostream.h"
16
17 namespace clang {
18 namespace clangd {
19
20 // FIXME: Deleted symbols in dirty files are still returned (from Static).
21 // To identify these eliminate these, we should:
22 // - find the generating file from each Symbol which is Static-only
23 // - ask Dynamic if it has that file (needs new SymbolIndex method)
24 // - if so, drop the Symbol.
25 bool MergedIndex::fuzzyFind(
26 const FuzzyFindRequest &Req,
27 llvm::function_ref<void(const Symbol &)> Callback) const {
28 // We can't step through both sources in parallel. So:
29 // 1) query all dynamic symbols, slurping results into a slab
30 // 2) query the static symbols, for each one:
31 // a) if it's not in the dynamic slab, yield it directly
32 // b) if it's in the dynamic slab, merge it and yield the result
33 // 3) now yield all the dynamic symbols we haven't processed.
34 trace::Span Tracer("MergedIndex fuzzyFind");
35 bool More = false; // We'll be incomplete if either source was.
36 SymbolSlab::Builder DynB;
37 unsigned DynamicCount = 0;
38 unsigned StaticCount = 0;
39 unsigned MergedCount = 0;
40 More |= Dynamic->fuzzyFind(Req, [&](const Symbol &S) {
41 ++DynamicCount;
42 DynB.insert(S);
43 });
44 SymbolSlab Dyn = std::move(DynB).build();
45
46 llvm::DenseSet<SymbolID> SeenDynamicSymbols;
47 More |= Static->fuzzyFind(Req, [&](const Symbol &S) {
48 auto DynS = Dyn.find(S.ID);
49 ++StaticCount;
50 if (DynS == Dyn.end())
51 return Callback(S);
52 ++MergedCount;
53 SeenDynamicSymbols.insert(S.ID);
54 Callback(mergeSymbol(*DynS, S));
55 });
56 SPAN_ATTACH(Tracer, "dynamic", DynamicCount);
57 SPAN_ATTACH(Tracer, "static", StaticCount);
58 SPAN_ATTACH(Tracer, "merged", MergedCount);
59 for (const Symbol &S : Dyn)
60 if (!SeenDynamicSymbols.count(S.ID))
61 Callback(S);
62 return More;
63 }
64
65 void MergedIndex::lookup(
66 const LookupRequest &Req,
67 llvm::function_ref<void(const Symbol &)> Callback) const {
68 trace::Span Tracer("MergedIndex lookup");
69 SymbolSlab::Builder B;
70
71 Dynamic->lookup(Req, [&](const Symbol &S) { B.insert(S); });
72
73 auto RemainingIDs = Req.IDs;
74 Static->lookup(Req, [&](const Symbol &S) {
75 const Symbol *Sym = B.find(S.ID);
76 RemainingIDs.erase(S.ID);
77 if (!Sym)
78 Callback(S);
79 else
80 Callback(mergeSymbol(*Sym, S));
81 });
82 for (const auto &ID : RemainingIDs)
83 if (const Symbol *Sym = B.find(ID))
84 Callback(*Sym);
85 }
86
87 void MergedIndex::refs(const RefsRequest &Req,
88 llvm::function_ref<void(const Ref &)> Callback) const {
89 trace::Span Tracer("MergedIndex refs");
90 uint32_t Remaining =
91 Req.Limit.getValueOr(std::numeric_limits<uint32_t>::max());
92 // We don't want duplicated refs from the static/dynamic indexes,
93 // and we can't reliably duplicate them because offsets may differ slightly.
94 // We consider the dynamic index authoritative and report all its refs,
95 // and only report static index refs from other files.
96 //
97 // FIXME: The heuristic fails if the dynamic index contains a file, but all
98 // refs were removed (we will report stale ones from the static index).
99 // Ultimately we should explicit check which index has the file instead.
100 llvm::StringSet<> DynamicIndexFileURIs;
101 Dynamic->refs(Req, [&](const Ref &O) {
102 DynamicIndexFileURIs.insert(O.Location.FileURI);
103 Callback(O);
104 --Remaining;
105 });
106 assert(Remaining >= 0);
107 if (Remaining == 0)
108 return;
109 // We return less than Req.Limit if static index returns more refs for dirty
110 // files.
111 Static->refs(Req, [&](const Ref &O) {
112 if (Remaining > 0 && !DynamicIndexFileURIs.count(O.Location.FileURI)) {
113 --Remaining;
114 Callback(O);
115 }
116 });
117 }
118
119 Symbol mergeSymbol(const Symbol &L, const Symbol &R) {
120 assert(L.ID == R.ID);
121 // We prefer information from TUs that saw the definition.
122 // Classes: this is the def itself. Functions: hopefully the header decl.
123 // If both did (or both didn't), continue to prefer L over R.
124 bool PreferR = R.Definition && !L.Definition;
125 // Merge include headers only if both have definitions or both have no
126 // definition; otherwise, only accumulate references of common includes.
127 assert(L.Definition.FileURI && R.Definition.FileURI);
128 bool MergeIncludes =
129 bool(*L.Definition.FileURI) == bool(*R.Definition.FileURI);
130 Symbol S = PreferR ? R : L; // The target symbol we're merging into.
131 const Symbol &O = PreferR ? L : R; // The "other" less-preferred symbol.
132
133 // For each optional field, fill it from O if missing in S.
134 // (It might be missing in O too, but that's a no-op).
135 if (!S.Definition)
136 S.Definition = O.Definition;
137 if (!S.CanonicalDeclaration)
138 S.CanonicalDeclaration = O.CanonicalDeclaration;
139 S.References += O.References;
140 if (S.Signature == "")
141 S.Signature = O.Signature;
142 if (S.CompletionSnippetSuffix == "")
143 S.CompletionSnippetSuffix = O.CompletionSnippetSuffix;
144 if (S.Documentation == "")
145 S.Documentation = O.Documentation;
146 if (S.ReturnType == "")
147 S.ReturnType = O.ReturnType;
148 if (S.Type == "")
149 S.Type = O.Type;
150 for (const auto &OI : O.IncludeHeaders) {
151 bool Found = false;
152 for (auto &SI : S.IncludeHeaders) {
153 if (SI.IncludeHeader == OI.IncludeHeader) {
154 Found = true;
155 SI.References += OI.References;
156 break;
157 }
158 }
159 if (!Found && MergeIncludes)
160 S.IncludeHeaders.emplace_back(OI.IncludeHeader, OI.References);
161 }
162
163 S.Origin |= O.Origin | SymbolOrigin::Merge;
164 S.Flags |= O.Flags;
165 return S;
166 }
167
168 } // namespace clangd
169 } // namespace clang
clang::clangd::SymbolIndex::lookup
virtual void lookup(const LookupRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Looks up symbols with any of the given symbol IDs and applies Callback on each matched symbol...
clang::clangd::SymbolSlab
Definition: Index.h:292
Trace.h
clang::clangd::SymbolSlab::Builder::find
const Symbol * find(const SymbolID &ID)
Definition: Index.h:323
clang::clangd::SymbolSlab::find
const_iterator find(const SymbolID &SymID) const
Definition: Index.cpp:77
clang::clangd::LookupRequest::IDs
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:473
clang::clangd::Ref
Definition: Index.h:373
clang::clangd::SymbolIndex::fuzzyFind
virtual bool fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Matches symbols in the index fuzzily and applies Callback on each matched symbol before returning...
clang::clangd::DuplicateHandling::Merge
clang::clangd::RefsRequest
Definition: Index.h:476
clang::clangd::SymbolSlab::Builder::insert
void insert(const Symbol &S)
Definition: Index.cpp:91
clang::clangd::Callback
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:29
clang::clangd::FuzzyFindRequest
Definition: Index.h:436
clang::clangd::Symbol::References
unsigned References
Definition: Index.h:183
clang::clangd::SymbolSlab::Builder
Definition: Index.h:314
clang::clangd::Symbol::ID
SymbolID ID
Definition: Index.h:162
clang::clangd::Symbol::Definition
SymbolLocation Definition
Definition: Index.h:171
clang::clangd::MergedIndex::lookup
void lookup(const LookupRequest &, llvm::function_ref< void(const Symbol &)>) const override
Looks up symbols with any of the given symbol IDs and applies Callback on each matched symbol...
Definition: Merge.cpp:65
clang::clangd::Symbol::IncludeHeaders
llvm::SmallVector< IncludeHeaderWithReferences, 1 > IncludeHeaders
One Symbol can potentially be incuded via different headers.
Definition: Index.h:231
clang::clangd::Symbol::Flags
SymbolFlag Flags
Definition: Index.h:248
clang::clangd::Symbol::Signature
llvm::StringRef Signature
A brief description of the symbol that can be appended in the completion candidate list...
Definition: Index.h:189
clang::clangd::Ref::Location
SymbolLocation Location
Definition: Index.h:375
clang::clangd::Symbol::Documentation
llvm::StringRef Documentation
Documentation including comment for the symbol declaration.
Definition: Index.h:196
clang::clangd::Symbol::CanonicalDeclaration
SymbolLocation CanonicalDeclaration
Definition: Index.h:180
clang::clangd::mergeSymbol
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
Definition: Merge.cpp:119
clang::clangd::SymbolIndex::refs
virtual void refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
Logger.h
Merge.h
clang::clangd::Symbol
Definition: Index.h:160
clang::clangd::LookupRequest
Definition: Index.h:472
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
clang::clangd::RefsRequest::Limit
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition: Index.h:482
clang::clangd::MergedIndex::refs
void refs(const RefsRequest &, llvm::function_ref< void(const Ref &)>) const override
Finds all occurrences (e.g.
Definition: Merge.cpp:87
clang::clangd::Symbol::CompletionSnippetSuffix
llvm::StringRef CompletionSnippetSuffix
What to insert when completing this symbol, after the symbol name.
Definition: Index.h:194
clang::clangd::SymbolSlab::end
const_iterator end() const
Definition: Index.h:301
clang::clangd::MergedIndex::fuzzyFind
bool fuzzyFind(const FuzzyFindRequest &, llvm::function_ref< void(const Symbol &)>) const override
Matches symbols in the index fuzzily and applies Callback on each matched symbol before returning...
Definition: Merge.cpp:25
clang::clangd::Symbol::Type
llvm::StringRef Type
Raw representation of the OpaqueType of the symbol, used for scoring purposes.
Definition: Index.h:205
clang::clangd::Symbol::Origin
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.
Definition: Index.h:185
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:83
clang::clangd::SymbolLocation::FileURI
const char * FileURI
Definition: Index.h:72
clang::clangd::Symbol::ReturnType
llvm::StringRef ReturnType
Type when this symbol is used in an expression.
Definition: Index.h:200
SPAN_ATTACH
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Definition: Trace.h:99