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.
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.
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 
66  const LookupRequest &Req,
67  llvm::function_ref<void(const Symbol &)> Callback) const {
68  trace::Span Tracer("MergedIndex lookup");
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 
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)
139  S.References += O.References;
140  if (S.Signature == "")
141  S.Signature = O.Signature;
142  if (S.CompletionSnippetSuffix == "")
144  if (S.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 
164  S.Flags |= O.Flags;
165  return S;
166 }
167 
168 } // namespace clangd
169 } // namespace clang
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...
const Symbol * find(const SymbolID &ID)
Definition: Index.h:323
const_iterator find(const SymbolID &SymID) const
Definition: Index.cpp:77
llvm::DenseSet< SymbolID > IDs
Definition: Index.h:473
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...
void insert(const Symbol &S)
Definition: Index.cpp:91
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:29
unsigned References
Definition: Index.h:183
SymbolLocation Definition
Definition: Index.h:171
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
llvm::SmallVector< IncludeHeaderWithReferences, 1 > IncludeHeaders
One Symbol can potentially be incuded via different headers.
Definition: Index.h:231
SymbolFlag Flags
Definition: Index.h:248
llvm::StringRef Signature
A brief description of the symbol that can be appended in the completion candidate list...
Definition: Index.h:189
SymbolLocation Location
Definition: Index.h:375
llvm::StringRef Documentation
Documentation including comment for the symbol declaration.
Definition: Index.h:196
SymbolLocation CanonicalDeclaration
Definition: Index.h:180
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
Definition: Merge.cpp:119
virtual void refs(const RefsRequest &Req, llvm::function_ref< void(const Ref &)> Callback) const =0
Finds all occurrences (e.g.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< uint32_t > Limit
If set, limit the number of refers returned from the index.
Definition: Index.h:482
void refs(const RefsRequest &, llvm::function_ref< void(const Ref &)>) const override
Finds all occurrences (e.g.
Definition: Merge.cpp:87
llvm::StringRef CompletionSnippetSuffix
What to insert when completing this symbol, after the symbol name.
Definition: Index.h:194
const_iterator end() const
Definition: Index.h:301
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
llvm::StringRef Type
Raw representation of the OpaqueType of the symbol, used for scoring purposes.
Definition: Index.h:205
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.
Definition: Index.h:185
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:83
const char * FileURI
Definition: Index.h:72
llvm::StringRef ReturnType
Type when this symbol is used in an expression.
Definition: Index.h:200
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Definition: Trace.h:99