annotate clang-tools-extra/clangd/Quality.h @ 236:c4bab56944e8 llvm-original

LLVM 16
author kono
date Wed, 09 Nov 2022 17:45:10 +0900
parents 79ff65ed7e25
children 1f2b6ac9f198
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===--- Quality.h - Ranking alternatives for ambiguous queries --*- C++-*-===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 ///
anatofuz
parents:
diff changeset
9 /// Some operations such as code completion produce a set of candidates.
anatofuz
parents:
diff changeset
10 /// Usually the user can choose between them, but we should put the best options
anatofuz
parents:
diff changeset
11 /// at the top (they're easier to select, and more likely to be seen).
anatofuz
parents:
diff changeset
12 ///
anatofuz
parents:
diff changeset
13 /// This file defines building blocks for ranking candidates.
anatofuz
parents:
diff changeset
14 /// It's used by the features directly and also in the implementation of
anatofuz
parents:
diff changeset
15 /// indexes, as indexes also need to heuristically limit their results.
anatofuz
parents:
diff changeset
16 ///
anatofuz
parents:
diff changeset
17 /// The facilities here are:
anatofuz
parents:
diff changeset
18 /// - retrieving scoring signals from e.g. indexes, AST, CodeCompletionString
anatofuz
parents:
diff changeset
19 /// These are structured in a way that they can be debugged, and are fairly
anatofuz
parents:
diff changeset
20 /// consistent regardless of the source.
anatofuz
parents:
diff changeset
21 /// - compute scores from scoring signals. These are suitable for sorting.
anatofuz
parents:
diff changeset
22 /// - sorting utilities like the TopN container.
anatofuz
parents:
diff changeset
23 /// These could be split up further to isolate dependencies if we care.
anatofuz
parents:
diff changeset
24 ///
anatofuz
parents:
diff changeset
25 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
26
anatofuz
parents:
diff changeset
27 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_QUALITY_H
anatofuz
parents:
diff changeset
28 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_QUALITY_H
anatofuz
parents:
diff changeset
29
anatofuz
parents:
diff changeset
30 #include "FileDistance.h"
anatofuz
parents:
diff changeset
31 #include "clang/Sema/CodeCompleteConsumer.h"
anatofuz
parents:
diff changeset
32 #include "llvm/ADT/StringRef.h"
anatofuz
parents:
diff changeset
33 #include "llvm/ADT/StringSet.h"
anatofuz
parents:
diff changeset
34 #include <algorithm>
anatofuz
parents:
diff changeset
35 #include <functional>
anatofuz
parents:
diff changeset
36 #include <vector>
anatofuz
parents:
diff changeset
37
anatofuz
parents:
diff changeset
38 namespace llvm {
anatofuz
parents:
diff changeset
39 class raw_ostream;
anatofuz
parents:
diff changeset
40 } // namespace llvm
anatofuz
parents:
diff changeset
41
anatofuz
parents:
diff changeset
42 namespace clang {
anatofuz
parents:
diff changeset
43 class CodeCompletionResult;
anatofuz
parents:
diff changeset
44
anatofuz
parents:
diff changeset
45 namespace clangd {
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
46 struct ASTSignals;
150
anatofuz
parents:
diff changeset
47 struct Symbol;
anatofuz
parents:
diff changeset
48 class URIDistance;
anatofuz
parents:
diff changeset
49
anatofuz
parents:
diff changeset
50 // Signals structs are designed to be aggregated from 0 or more sources.
anatofuz
parents:
diff changeset
51 // A default instance has neutral signals, and sources are merged into it.
anatofuz
parents:
diff changeset
52 // They can be dumped for debugging, and evaluate()d into a score.
anatofuz
parents:
diff changeset
53
anatofuz
parents:
diff changeset
54 /// Attributes of a symbol that affect how much we like it.
anatofuz
parents:
diff changeset
55 struct SymbolQualitySignals {
anatofuz
parents:
diff changeset
56 bool Deprecated = false;
anatofuz
parents:
diff changeset
57 bool ReservedName = false; // __foo, _Foo are usually implementation details.
anatofuz
parents:
diff changeset
58 // FIXME: make these findable once user types _.
anatofuz
parents:
diff changeset
59 bool ImplementationDetail = false;
anatofuz
parents:
diff changeset
60 unsigned References = 0;
anatofuz
parents:
diff changeset
61
anatofuz
parents:
diff changeset
62 enum SymbolCategory {
anatofuz
parents:
diff changeset
63 Unknown = 0,
anatofuz
parents:
diff changeset
64 Variable,
anatofuz
parents:
diff changeset
65 Macro,
anatofuz
parents:
diff changeset
66 Type,
anatofuz
parents:
diff changeset
67 Function,
anatofuz
parents:
diff changeset
68 Constructor,
anatofuz
parents:
diff changeset
69 Destructor,
anatofuz
parents:
diff changeset
70 Namespace,
anatofuz
parents:
diff changeset
71 Keyword,
anatofuz
parents:
diff changeset
72 Operator,
anatofuz
parents:
diff changeset
73 } Category = Unknown;
anatofuz
parents:
diff changeset
74
anatofuz
parents:
diff changeset
75 void merge(const CodeCompletionResult &SemaCCResult);
anatofuz
parents:
diff changeset
76 void merge(const Symbol &IndexResult);
anatofuz
parents:
diff changeset
77
anatofuz
parents:
diff changeset
78 // Condense these signals down to a single number, higher is better.
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
79 float evaluateHeuristics() const;
150
anatofuz
parents:
diff changeset
80 };
anatofuz
parents:
diff changeset
81 llvm::raw_ostream &operator<<(llvm::raw_ostream &,
anatofuz
parents:
diff changeset
82 const SymbolQualitySignals &);
anatofuz
parents:
diff changeset
83
anatofuz
parents:
diff changeset
84 /// Attributes of a symbol-query pair that affect how much we like it.
anatofuz
parents:
diff changeset
85 struct SymbolRelevanceSignals {
anatofuz
parents:
diff changeset
86 /// The name of the symbol (for ContextWords). Must be explicitly assigned.
anatofuz
parents:
diff changeset
87 llvm::StringRef Name;
anatofuz
parents:
diff changeset
88 /// 0-1+ fuzzy-match score for unqualified name. Must be explicitly assigned.
anatofuz
parents:
diff changeset
89 float NameMatch = 1;
anatofuz
parents:
diff changeset
90 /// Lowercase words relevant to the context (e.g. near the completion point).
anatofuz
parents:
diff changeset
91 llvm::StringSet<>* ContextWords = nullptr;
anatofuz
parents:
diff changeset
92 bool Forbidden = false; // Unavailable (e.g const) or inaccessible (private).
anatofuz
parents:
diff changeset
93 /// Whether fixits needs to be applied for that completion or not.
anatofuz
parents:
diff changeset
94 bool NeedsFixIts = false;
anatofuz
parents:
diff changeset
95 bool InBaseClass = false; // A member from base class of the accessed class.
anatofuz
parents:
diff changeset
96
anatofuz
parents:
diff changeset
97 URIDistance *FileProximityMatch = nullptr;
anatofuz
parents:
diff changeset
98 /// These are used to calculate proximity between the index symbol and the
anatofuz
parents:
diff changeset
99 /// query.
anatofuz
parents:
diff changeset
100 llvm::StringRef SymbolURI;
anatofuz
parents:
diff changeset
101 /// FIXME: unify with index proximity score - signals should be
anatofuz
parents:
diff changeset
102 /// source-independent.
anatofuz
parents:
diff changeset
103 /// Proximity between best declaration and the query. [0-1], 1 is closest.
anatofuz
parents:
diff changeset
104 float SemaFileProximityScore = 0;
anatofuz
parents:
diff changeset
105
anatofuz
parents:
diff changeset
106 // Scope proximity is only considered (both index and sema) when this is set.
anatofuz
parents:
diff changeset
107 ScopeDistance *ScopeProximityMatch = nullptr;
anatofuz
parents:
diff changeset
108 llvm::Optional<llvm::StringRef> SymbolScope;
anatofuz
parents:
diff changeset
109 // A symbol from sema should be accessible from the current scope.
anatofuz
parents:
diff changeset
110 bool SemaSaysInScope = false;
anatofuz
parents:
diff changeset
111
anatofuz
parents:
diff changeset
112 // An approximate measure of where we expect the symbol to be used.
anatofuz
parents:
diff changeset
113 enum AccessibleScope {
anatofuz
parents:
diff changeset
114 FunctionScope,
anatofuz
parents:
diff changeset
115 ClassScope,
anatofuz
parents:
diff changeset
116 FileScope,
anatofuz
parents:
diff changeset
117 GlobalScope,
anatofuz
parents:
diff changeset
118 } Scope = GlobalScope;
anatofuz
parents:
diff changeset
119
anatofuz
parents:
diff changeset
120 enum QueryType {
anatofuz
parents:
diff changeset
121 CodeComplete,
anatofuz
parents:
diff changeset
122 Generic,
anatofuz
parents:
diff changeset
123 } Query = Generic;
anatofuz
parents:
diff changeset
124
anatofuz
parents:
diff changeset
125 CodeCompletionContext::Kind Context = CodeCompletionContext::CCC_Other;
anatofuz
parents:
diff changeset
126
anatofuz
parents:
diff changeset
127 // Whether symbol is an instance member of a class.
anatofuz
parents:
diff changeset
128 bool IsInstanceMember = false;
anatofuz
parents:
diff changeset
129
anatofuz
parents:
diff changeset
130 // Whether clang provided a preferred type in the completion context.
anatofuz
parents:
diff changeset
131 bool HadContextType = false;
anatofuz
parents:
diff changeset
132 // Whether a source completion item or a symbol had a type information.
anatofuz
parents:
diff changeset
133 bool HadSymbolType = false;
anatofuz
parents:
diff changeset
134 // Whether the item matches the type expected in the completion context.
anatofuz
parents:
diff changeset
135 bool TypeMatchesPreferred = false;
anatofuz
parents:
diff changeset
136
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
137 /// Length of the unqualified partial name of Symbol typed in
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
138 /// CompletionPrefix.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
139 unsigned FilterLength = 0;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
140
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
141 const ASTSignals *MainFileSignals = nullptr;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
142 /// Number of references to the candidate in the main file.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
143 unsigned MainFileRefs = 0;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
144 /// Number of unique symbols in the main file which belongs to candidate's
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
145 /// namespace. This indicates how relevant the namespace is in the current
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
146 /// file.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
147 unsigned ScopeRefsInFile = 0;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
148
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
149 /// Set of derived signals computed by calculateDerivedSignals(). Must not be
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
150 /// set explicitly.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
151 struct DerivedSignals {
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
152 /// Whether Name contains some word from context.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
153 bool NameMatchesContext = false;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
154 /// Min distance between SymbolURI and all the headers included by the TU.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
155 unsigned FileProximityDistance = FileDistance::Unreachable;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
156 /// Min distance between SymbolScope and all the available scopes.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
157 unsigned ScopeProximityDistance = FileDistance::Unreachable;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
158 };
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
159
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
160 DerivedSignals calculateDerivedSignals() const;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
161
150
anatofuz
parents:
diff changeset
162 void merge(const CodeCompletionResult &SemaResult);
anatofuz
parents:
diff changeset
163 void merge(const Symbol &IndexResult);
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
164 void computeASTSignals(const CodeCompletionResult &SemaResult);
150
anatofuz
parents:
diff changeset
165
anatofuz
parents:
diff changeset
166 // Condense these signals down to a single number, higher is better.
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
167 float evaluateHeuristics() const;
150
anatofuz
parents:
diff changeset
168 };
anatofuz
parents:
diff changeset
169 llvm::raw_ostream &operator<<(llvm::raw_ostream &,
anatofuz
parents:
diff changeset
170 const SymbolRelevanceSignals &);
anatofuz
parents:
diff changeset
171
anatofuz
parents:
diff changeset
172 /// Combine symbol quality and relevance into a single score.
anatofuz
parents:
diff changeset
173 float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance);
anatofuz
parents:
diff changeset
174
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
175 /// Same semantics as CodeComplete::Score. Quality score and Relevance score
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
176 /// have been removed since DecisionForest cannot assign individual scores to
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
177 /// Quality and Relevance signals.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
178 struct DecisionForestScores {
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
179 float Total = 0.f;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
180 float ExcludingName = 0.f;
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
181 };
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
182
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
183 DecisionForestScores
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
184 evaluateDecisionForest(const SymbolQualitySignals &Quality,
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
185 const SymbolRelevanceSignals &Relevance, float Base);
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
186
150
anatofuz
parents:
diff changeset
187 /// TopN<T> is a lossy container that preserves only the "best" N elements.
anatofuz
parents:
diff changeset
188 template <typename T, typename Compare = std::greater<T>> class TopN {
anatofuz
parents:
diff changeset
189 public:
anatofuz
parents:
diff changeset
190 using value_type = T;
anatofuz
parents:
diff changeset
191 TopN(size_t N, Compare Greater = Compare())
anatofuz
parents:
diff changeset
192 : N(N), Greater(std::move(Greater)) {}
anatofuz
parents:
diff changeset
193
anatofuz
parents:
diff changeset
194 // Adds a candidate to the set.
anatofuz
parents:
diff changeset
195 // Returns true if a candidate was dropped to get back under N.
anatofuz
parents:
diff changeset
196 bool push(value_type &&V) {
anatofuz
parents:
diff changeset
197 bool Dropped = false;
anatofuz
parents:
diff changeset
198 if (Heap.size() >= N) {
anatofuz
parents:
diff changeset
199 Dropped = true;
anatofuz
parents:
diff changeset
200 if (N > 0 && Greater(V, Heap.front())) {
anatofuz
parents:
diff changeset
201 std::pop_heap(Heap.begin(), Heap.end(), Greater);
anatofuz
parents:
diff changeset
202 Heap.back() = std::move(V);
anatofuz
parents:
diff changeset
203 std::push_heap(Heap.begin(), Heap.end(), Greater);
anatofuz
parents:
diff changeset
204 }
anatofuz
parents:
diff changeset
205 } else {
anatofuz
parents:
diff changeset
206 Heap.push_back(std::move(V));
anatofuz
parents:
diff changeset
207 std::push_heap(Heap.begin(), Heap.end(), Greater);
anatofuz
parents:
diff changeset
208 }
anatofuz
parents:
diff changeset
209 assert(Heap.size() <= N);
anatofuz
parents:
diff changeset
210 assert(std::is_heap(Heap.begin(), Heap.end(), Greater));
anatofuz
parents:
diff changeset
211 return Dropped;
anatofuz
parents:
diff changeset
212 }
anatofuz
parents:
diff changeset
213
anatofuz
parents:
diff changeset
214 // Returns candidates from best to worst.
anatofuz
parents:
diff changeset
215 std::vector<value_type> items() && {
anatofuz
parents:
diff changeset
216 std::sort_heap(Heap.begin(), Heap.end(), Greater);
anatofuz
parents:
diff changeset
217 assert(Heap.size() <= N);
anatofuz
parents:
diff changeset
218 return std::move(Heap);
anatofuz
parents:
diff changeset
219 }
anatofuz
parents:
diff changeset
220
anatofuz
parents:
diff changeset
221 private:
anatofuz
parents:
diff changeset
222 const size_t N;
anatofuz
parents:
diff changeset
223 std::vector<value_type> Heap; // Min-heap, comparator is Greater.
anatofuz
parents:
diff changeset
224 Compare Greater;
anatofuz
parents:
diff changeset
225 };
anatofuz
parents:
diff changeset
226
anatofuz
parents:
diff changeset
227 /// Returns a string that sorts in the same order as (-Score, Tiebreak), for
anatofuz
parents:
diff changeset
228 /// LSP. (The highest score compares smallest so it sorts at the top).
anatofuz
parents:
diff changeset
229 std::string sortText(float Score, llvm::StringRef Tiebreak = "");
anatofuz
parents:
diff changeset
230
anatofuz
parents:
diff changeset
231 struct SignatureQualitySignals {
anatofuz
parents:
diff changeset
232 uint32_t NumberOfParameters = 0;
anatofuz
parents:
diff changeset
233 uint32_t NumberOfOptionalParameters = 0;
anatofuz
parents:
diff changeset
234 CodeCompleteConsumer::OverloadCandidate::CandidateKind Kind =
anatofuz
parents:
diff changeset
235 CodeCompleteConsumer::OverloadCandidate::CandidateKind::CK_Function;
anatofuz
parents:
diff changeset
236 };
anatofuz
parents:
diff changeset
237 llvm::raw_ostream &operator<<(llvm::raw_ostream &,
anatofuz
parents:
diff changeset
238 const SignatureQualitySignals &);
anatofuz
parents:
diff changeset
239
anatofuz
parents:
diff changeset
240 } // namespace clangd
anatofuz
parents:
diff changeset
241 } // namespace clang
anatofuz
parents:
diff changeset
242
anatofuz
parents:
diff changeset
243 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_QUALITY_H