File: Merge.cpp

package info (click to toggle)
llvm-toolchain-7 1%3A7.0.1-8%2Bdeb10u2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 734,616 kB
  • sloc: cpp: 3,776,926; ansic: 633,271; asm: 350,301; python: 142,716; objc: 107,612; sh: 22,626; lisp: 11,056; perl: 7,999; pascal: 6,742; ml: 5,537; awk: 3,536; makefile: 2,557; cs: 2,027; xml: 841; javascript: 518; ruby: 156
file content (128 lines) | stat: -rw-r--r-- 4,594 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//===--- Merge.h ------------------------------------------------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
#include "Merge.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
namespace clangd {
namespace {
using namespace llvm;

class MergedIndex : public SymbolIndex {
 public:
   MergedIndex(const SymbolIndex *Dynamic, const SymbolIndex *Static)
       : Dynamic(Dynamic), Static(Static) {}

   // FIXME: Deleted symbols in dirty files are still returned (from Static).
   //        To identify these eliminate these, we should:
   //          - find the generating file from each Symbol which is Static-only
   //          - ask Dynamic if it has that file (needs new SymbolIndex method)
   //          - if so, drop the Symbol.
   bool fuzzyFind(const FuzzyFindRequest &Req,
                  function_ref<void(const Symbol &)> Callback) const override {
     // We can't step through both sources in parallel. So:
     //  1) query all dynamic symbols, slurping results into a slab
     //  2) query the static symbols, for each one:
     //    a) if it's not in the dynamic slab, yield it directly
     //    b) if it's in the dynamic slab, merge it and yield the result
     //  3) now yield all the dynamic symbols we haven't processed.
     bool More = false; // We'll be incomplete if either source was.
     SymbolSlab::Builder DynB;
     More |= Dynamic->fuzzyFind(Req, [&](const Symbol &S) { DynB.insert(S); });
     SymbolSlab Dyn = std::move(DynB).build();

     DenseSet<SymbolID> SeenDynamicSymbols;
     Symbol::Details Scratch;
     More |= Static->fuzzyFind(Req, [&](const Symbol &S) {
       auto DynS = Dyn.find(S.ID);
       if (DynS == Dyn.end())
         return Callback(S);
       SeenDynamicSymbols.insert(S.ID);
       Callback(mergeSymbol(*DynS, S, &Scratch));
     });
     for (const Symbol &S : Dyn)
       if (!SeenDynamicSymbols.count(S.ID))
         Callback(S);
     return More;
  }

  void
  lookup(const LookupRequest &Req,
         llvm::function_ref<void(const Symbol &)> Callback) const override {
    SymbolSlab::Builder B;

    Dynamic->lookup(Req, [&](const Symbol &S) { B.insert(S); });

    auto RemainingIDs = Req.IDs;
    Symbol::Details Scratch;
    Static->lookup(Req, [&](const Symbol &S) {
      const Symbol *Sym = B.find(S.ID);
      RemainingIDs.erase(S.ID);
      if (!Sym)
        Callback(S);
      else
        Callback(mergeSymbol(*Sym, S, &Scratch));
    });
    for (const auto &ID : RemainingIDs)
      if (const Symbol *Sym = B.find(ID))
        Callback(*Sym);
  }

private:
  const SymbolIndex *Dynamic, *Static;
};
} // namespace

Symbol
mergeSymbol(const Symbol &L, const Symbol &R, Symbol::Details *Scratch) {
  assert(L.ID == R.ID);
  // We prefer information from TUs that saw the definition.
  // Classes: this is the def itself. Functions: hopefully the header decl.
  // If both did (or both didn't), continue to prefer L over R.
  bool PreferR = R.Definition && !L.Definition;
  Symbol S = PreferR ? R : L;        // The target symbol we're merging into.
  const Symbol &O = PreferR ? L : R; // The "other" less-preferred symbol.

  // For each optional field, fill it from O if missing in S.
  // (It might be missing in O too, but that's a no-op).
  if (!S.Definition)
    S.Definition = O.Definition;
  if (!S.CanonicalDeclaration)
    S.CanonicalDeclaration = O.CanonicalDeclaration;
  S.References += O.References;
  if (S.Signature == "")
    S.Signature = O.Signature;
  if (S.CompletionSnippetSuffix == "")
    S.CompletionSnippetSuffix = O.CompletionSnippetSuffix;

  if (O.Detail) {
    if (S.Detail) {
      // Copy into scratch space so we can merge.
      *Scratch = *S.Detail;
      if (Scratch->Documentation == "")
        Scratch->Documentation = O.Detail->Documentation;
      if (Scratch->ReturnType == "")
        Scratch->ReturnType = O.Detail->ReturnType;
      if (Scratch->IncludeHeader == "")
        Scratch->IncludeHeader = O.Detail->IncludeHeader;
      S.Detail = Scratch;
    } else
      S.Detail = O.Detail;
  }

  S.Origin |= O.Origin | SymbolOrigin::Merge;
  return S;
}

std::unique_ptr<SymbolIndex> mergeIndex(const SymbolIndex *Dynamic,
                                        const SymbolIndex *Static) {
  return llvm::make_unique<MergedIndex>(Dynamic, Static);
}
} // namespace clangd
} // namespace clang