clang 20.0.0git
TypoCorrection.h
Go to the documentation of this file.
1//===- TypoCorrection.h - Class for typo correction results -----*- C++ -*-===//
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// This file defines the TypoCorrection class, which stores the results of
10// Sema's typo correction (Sema::CorrectTypo).
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H
15#define LLVM_CLANG_SEMA_TYPOCORRECTION_H
16
17#include "clang/AST/Decl.h"
19#include "clang/Basic/LLVM.h"
22#include "clang/Sema/DeclSpec.h"
23#include "llvm/ADT/ArrayRef.h"
24#include "llvm/ADT/SmallVector.h"
25#include "llvm/Support/Casting.h"
26#include <cstddef>
27#include <limits>
28#include <string>
29#include <utility>
30#include <vector>
31
32namespace clang {
33
34class DeclContext;
35class IdentifierInfo;
36class LangOptions;
37class MemberExpr;
38class NestedNameSpecifier;
39class Sema;
40
41/// Simple class containing the result of Sema::CorrectTypo
43public:
44 // "Distance" for unusable corrections
45 static const unsigned InvalidDistance = std::numeric_limits<unsigned>::max();
46
47 // The largest distance still considered valid (larger edit distances are
48 // mapped to InvalidDistance by getEditDistance).
49 static const unsigned MaximumDistance = 10000U;
50
51 // Relative weightings of the "edit distance" components. The higher the
52 // weight, the more of a penalty to fitness the component will give (higher
53 // weights mean greater contribution to the total edit distance, with the
54 // best correction candidates having the lowest edit distance).
55 static const unsigned CharDistanceWeight = 100U;
56 static const unsigned QualifierDistanceWeight = 110U;
57 static const unsigned CallbackDistanceWeight = 150U;
58
60 NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0,
61 unsigned QualifierDistance = 0)
62 : CorrectionName(Name), CorrectionNameSpec(NNS),
63 CharDistance(CharDistance), QualifierDistance(QualifierDistance) {
64 if (NameDecl)
65 CorrectionDecls.push_back(NameDecl);
66 }
67
69 unsigned CharDistance = 0)
70 : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
71 CharDistance(CharDistance) {
72 if (Name)
73 CorrectionDecls.push_back(Name);
74 }
75
77 unsigned CharDistance = 0)
78 : CorrectionName(Name), CorrectionNameSpec(NNS),
79 CharDistance(CharDistance) {}
80
81 TypoCorrection() = default;
82
83 /// Gets the DeclarationName of the typo correction
84 DeclarationName getCorrection() const { return CorrectionName; }
85
87 return CorrectionName.getAsIdentifierInfo();
88 }
89
90 /// Gets the NestedNameSpecifier needed to use the typo correction
92 return CorrectionNameSpec;
93 }
94
96 CorrectionNameSpec = NNS;
97 ForceSpecifierReplacement = (NNS != nullptr);
98 }
99
100 void WillReplaceSpecifier(bool ForceReplacement) {
101 ForceSpecifierReplacement = ForceReplacement;
102 }
103
104 bool WillReplaceSpecifier() const {
105 return ForceSpecifierReplacement;
106 }
107
108 void setQualifierDistance(unsigned ED) {
109 QualifierDistance = ED;
110 }
111
112 void setCallbackDistance(unsigned ED) {
113 CallbackDistance = ED;
114 }
115
116 // Convert the given weighted edit distance to a roughly equivalent number of
117 // single-character edits (typically for comparison to the length of the
118 // string being edited).
119 static unsigned NormalizeEditDistance(unsigned ED) {
120 if (ED > MaximumDistance)
121 return InvalidDistance;
122 return (ED + CharDistanceWeight / 2) / CharDistanceWeight;
123 }
124
125 /// Gets the "edit distance" of the typo correction from the typo.
126 /// If Normalized is true, scale the distance down by the CharDistanceWeight
127 /// to return the edit distance in terms of single-character edits.
128 unsigned getEditDistance(bool Normalized = true) const {
129 if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance ||
130 CallbackDistance > MaximumDistance)
131 return InvalidDistance;
132 unsigned ED =
133 CharDistance * CharDistanceWeight +
134 QualifierDistance * QualifierDistanceWeight +
135 CallbackDistance * CallbackDistanceWeight;
136 if (ED > MaximumDistance)
137 return InvalidDistance;
138 // Half the CharDistanceWeight is added to ED to simulate rounding since
139 // integer division truncates the value (i.e. round-to-nearest-int instead
140 // of round-to-zero).
141 return Normalized ? NormalizeEditDistance(ED) : ED;
142 }
143
144 /// Get the correction declaration found by name lookup (before we
145 /// looked through using shadow declarations and the like).
147 return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr;
148 }
149
150 /// Gets the pointer to the declaration of the typo correction
152 auto *D = getFoundDecl();
153 return D ? D->getUnderlyingDecl() : nullptr;
154 }
155 template <class DeclClass>
156 DeclClass *getCorrectionDeclAs() const {
157 return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
158 }
159
160 /// Clears the list of NamedDecls.
162 CorrectionDecls.clear();
163 }
164
165 /// Clears the list of NamedDecls before adding the new one.
167 CorrectionDecls.clear();
168 addCorrectionDecl(CDecl);
169 }
170
171 /// Clears the list of NamedDecls and adds the given set.
173 CorrectionDecls.clear();
174 CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end());
175 }
176
177 /// Add the given NamedDecl to the list of NamedDecls that are the
178 /// declarations associated with the DeclarationName of this TypoCorrection
179 void addCorrectionDecl(NamedDecl *CDecl);
180
181 std::string getAsString(const LangOptions &LO) const;
182
183 std::string getQuoted(const LangOptions &LO) const {
184 return "'" + getAsString(LO) + "'";
185 }
186
187 /// Returns whether this TypoCorrection has a non-empty DeclarationName
188 explicit operator bool() const { return bool(CorrectionName); }
189
190 /// Mark this TypoCorrection as being a keyword.
191 /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
192 /// added to the list of the correction's NamedDecl pointers, NULL is added
193 /// as the only element in the list to mark this TypoCorrection as a keyword.
194 void makeKeyword() {
195 CorrectionDecls.clear();
196 CorrectionDecls.push_back(nullptr);
197 ForceSpecifierReplacement = true;
198 }
199
200 // Check if this TypoCorrection is a keyword by checking if the first
201 // item in CorrectionDecls is NULL.
202 bool isKeyword() const {
203 return !CorrectionDecls.empty() && CorrectionDecls.front() == nullptr;
204 }
205
206 // Check if this TypoCorrection is the given keyword.
207 template<std::size_t StrLen>
208 bool isKeyword(const char (&Str)[StrLen]) const {
210 }
211
212 // Returns true if the correction either is a keyword or has a known decl.
213 bool isResolved() const { return !CorrectionDecls.empty(); }
214
215 bool isOverloaded() const {
216 return CorrectionDecls.size() > 1;
217 }
218
220 const DeclarationNameInfo &TypoName) {
221 CorrectionRange = TypoName.getSourceRange();
222 if (ForceSpecifierReplacement && SS && !SS->isEmpty())
223 CorrectionRange.setBegin(SS->getBeginLoc());
224 }
225
227 return CorrectionRange;
228 }
229
231
233 return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
234 }
235
236 decl_iterator end() { return CorrectionDecls.end(); }
237
239
241 return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
242 }
243
244 const_decl_iterator end() const { return CorrectionDecls.end(); }
245
246 /// Returns whether this typo correction is correcting to a
247 /// declaration that was declared in a module that has not been imported.
248 bool requiresImport() const { return RequiresImport; }
249 void setRequiresImport(bool Req) { RequiresImport = Req; }
250
251 /// Extra diagnostics are printed after the first diagnostic for the typo.
252 /// This can be used to attach external notes to the diag.
254 ExtraDiagnostics.push_back(std::move(PD));
255 }
257 return ExtraDiagnostics;
258 }
259
260private:
261 bool hasCorrectionDecl() const {
262 return (!isKeyword() && !CorrectionDecls.empty());
263 }
264
265 // Results.
266 DeclarationName CorrectionName;
267 NestedNameSpecifier *CorrectionNameSpec = nullptr;
268 SmallVector<NamedDecl *, 1> CorrectionDecls;
269 unsigned CharDistance = 0;
270 unsigned QualifierDistance = 0;
271 unsigned CallbackDistance = 0;
272 SourceRange CorrectionRange;
273 bool ForceSpecifierReplacement = false;
274 bool RequiresImport = false;
275
276 std::vector<PartialDiagnostic> ExtraDiagnostics;
277};
278
279/// Base class for callback objects used by Sema::CorrectTypo to check
280/// the validity of a potential typo correction.
282public:
284
286 NestedNameSpecifier *TypoNNS = nullptr)
287 : Typo(Typo), TypoNNS(TypoNNS) {}
288
289 virtual ~CorrectionCandidateCallback() = default;
290
291 /// Simple predicate used by the default RankCandidate to
292 /// determine whether to return an edit distance of 0 or InvalidDistance.
293 /// This can be overridden by validators that only need to determine if a
294 /// candidate is viable, without ranking potentially viable candidates.
295 /// Only ValidateCandidate or RankCandidate need to be overridden by a
296 /// callback wishing to check the viability of correction candidates.
297 /// The default predicate always returns true if the candidate is not a type
298 /// name or keyword, true for types if WantTypeSpecifiers is true, and true
299 /// for keywords if WantTypeSpecifiers, WantExpressionKeywords,
300 /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true.
301 virtual bool ValidateCandidate(const TypoCorrection &candidate);
302
303 /// Method used by Sema::CorrectTypo to assign an "edit distance" rank
304 /// to a candidate (where a lower value represents a better candidate), or
305 /// returning InvalidDistance if the candidate is not at all viable. For
306 /// validation callbacks that only need to determine if a candidate is viable,
307 /// the default RankCandidate returns either 0 or InvalidDistance depending
308 /// whether ValidateCandidate returns true or false.
309 virtual unsigned RankCandidate(const TypoCorrection &candidate) {
310 return (!MatchesTypo(candidate) && ValidateCandidate(candidate))
311 ? 0
313 }
314
315 /// Clone this CorrectionCandidateCallback. CorrectionCandidateCallbacks are
316 /// initially stack-allocated. However in case where delayed typo-correction
317 /// is done we need to move the callback to storage with a longer lifetime.
318 /// Every class deriving from CorrectionCandidateCallback must implement
319 /// this method.
320 virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0;
321
322 void setTypoName(const IdentifierInfo *II) { Typo = II; }
324
325 // Flags for context-dependent keywords. WantFunctionLikeCasts is only
326 // used/meaningful when WantCXXNamedCasts is false.
327 // TODO: Expand these to apply to non-keywords or possibly remove them.
330 bool WantCXXNamedCasts = true;
333 bool WantObjCSuper = false;
334 // Temporary hack for the one case where a CorrectTypoContext enum is used
335 // when looking up results.
336 bool IsObjCIvarLookup = false;
337 bool IsAddressOfOperand = false;
338
339protected:
340 bool MatchesTypo(const TypoCorrection &candidate) {
341 return Typo && candidate.isResolved() && !candidate.requiresImport() &&
342 candidate.getCorrectionAsIdentifierInfo() == Typo &&
343 // FIXME: This probably does not return true when both
344 // NestedNameSpecifiers have the same textual representation.
345 candidate.getCorrectionSpecifier() == TypoNNS;
346 }
347
350};
351
353public:
354 explicit DefaultFilterCCC(const IdentifierInfo *Typo = nullptr,
355 NestedNameSpecifier *TypoNNS = nullptr)
357
358 std::unique_ptr<CorrectionCandidateCallback> clone() override {
359 return std::make_unique<DefaultFilterCCC>(*this);
360 }
361};
362
363/// Simple template class for restricting typo correction candidates
364/// to ones having a single Decl* of the given type.
365template <class C>
367public:
368 explicit DeclFilterCCC(const IdentifierInfo *Typo = nullptr,
369 NestedNameSpecifier *TypoNNS = nullptr)
371
372 bool ValidateCandidate(const TypoCorrection &candidate) override {
373 return candidate.getCorrectionDeclAs<C>();
374 }
375 std::unique_ptr<CorrectionCandidateCallback> clone() override {
376 return std::make_unique<DeclFilterCCC>(*this);
377 }
378};
379
380// Callback class to limit the allowed keywords and to only accept typo
381// corrections that are keywords or whose decls refer to functions (or template
382// functions) that accept the given number of arguments.
384public:
385 FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
386 bool HasExplicitTemplateArgs,
387 MemberExpr *ME = nullptr);
388
389 bool ValidateCandidate(const TypoCorrection &candidate) override;
390 std::unique_ptr<CorrectionCandidateCallback> clone() override {
391 return std::make_unique<FunctionCallFilterCCC>(*this);
392 }
393
394private:
395 unsigned NumArgs;
396 bool HasExplicitTemplateArgs;
397 DeclContext *CurContext;
398 MemberExpr *MemberFn;
399};
400
401// Callback class that effectively disabled typo correction
403public:
405 WantTypeSpecifiers = false;
407 WantCXXNamedCasts = false;
408 WantFunctionLikeCasts = false;
409 WantRemainingKeywords = false;
410 }
411
412 bool ValidateCandidate(const TypoCorrection &candidate) override {
413 return false;
414 }
415 std::unique_ptr<CorrectionCandidateCallback> clone() override {
416 return std::make_unique<NoTypoCorrectionCCC>(*this);
417 }
418};
419
420} // namespace clang
421
422#endif // LLVM_CLANG_SEMA_TYPOCORRECTION_H
const Decl * D
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Implements a partial diagnostic that can be emitted anwyhere in a DiagnosticBuilder stream.
Defines the clang::SourceLocation class and associated facilities.
Represents a C++ nested-name-specifier or a global scope specifier.
Definition: DeclSpec.h:74
SourceLocation getBeginLoc() const
Definition: DeclSpec.h:84
bool isEmpty() const
No scope specifier.
Definition: DeclSpec.h:208
Base class for callback objects used by Sema::CorrectTypo to check the validity of a potential typo c...
void setTypoName(const IdentifierInfo *II)
virtual unsigned RankCandidate(const TypoCorrection &candidate)
Method used by Sema::CorrectTypo to assign an "edit distance" rank to a candidate (where a lower valu...
virtual bool ValidateCandidate(const TypoCorrection &candidate)
Simple predicate used by the default RankCandidate to determine whether to return an edit distance of...
bool MatchesTypo(const TypoCorrection &candidate)
virtual ~CorrectionCandidateCallback()=default
CorrectionCandidateCallback(const IdentifierInfo *Typo=nullptr, NestedNameSpecifier *TypoNNS=nullptr)
void setTypoNNS(NestedNameSpecifier *NNS)
static const unsigned InvalidDistance
virtual std::unique_ptr< CorrectionCandidateCallback > clone()=0
Clone this CorrectionCandidateCallback.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1436
Simple template class for restricting typo correction candidates to ones having a single Decl* of the...
DeclFilterCCC(const IdentifierInfo *Typo=nullptr, NestedNameSpecifier *TypoNNS=nullptr)
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
bool ValidateCandidate(const TypoCorrection &candidate) override
Simple predicate used by the default RankCandidate to determine whether to return an edit distance of...
The name of a declaration.
IdentifierInfo * getAsIdentifierInfo() const
Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn't...
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
DefaultFilterCCC(const IdentifierInfo *Typo=nullptr, NestedNameSpecifier *TypoNNS=nullptr)
bool ValidateCandidate(const TypoCorrection &candidate) override
Simple predicate used by the default RankCandidate to determine whether to return an edit distance of...
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
One of these records is kept for each identifier that is lexed.
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:476
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3187
This represents a decl that may have a name.
Definition: Decl.h:249
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
bool ValidateCandidate(const TypoCorrection &candidate) override
Simple predicate used by the default RankCandidate to determine whether to return an edit distance of...
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:493
A trivial tuple used to represent a source range.
void setBegin(SourceLocation b)
Simple class containing the result of Sema::CorrectTypo.
IdentifierInfo * getCorrectionAsIdentifierInfo() const
TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0)
TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0, unsigned QualifierDistance=0)
void setCorrectionSpecifier(NestedNameSpecifier *NNS)
ArrayRef< PartialDiagnostic > getExtraDiagnostics() const
static const unsigned InvalidDistance
void addCorrectionDecl(NamedDecl *CDecl)
Add the given NamedDecl to the list of NamedDecls that are the declarations associated with the Decla...
TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0)
void setCorrectionDecls(ArrayRef< NamedDecl * > Decls)
Clears the list of NamedDecls and adds the given set.
std::string getAsString(const LangOptions &LO) const
static const unsigned MaximumDistance
bool requiresImport() const
Returns whether this typo correction is correcting to a declaration that was declared in a module tha...
const_decl_iterator begin() const
void setCorrectionRange(CXXScopeSpec *SS, const DeclarationNameInfo &TypoName)
NamedDecl * getCorrectionDecl() const
Gets the pointer to the declaration of the typo correction.
bool isKeyword(const char(&Str)[StrLen]) const
SourceRange getCorrectionRange() const
void setQualifierDistance(unsigned ED)
void WillReplaceSpecifier(bool ForceReplacement)
decl_iterator end()
void setCallbackDistance(unsigned ED)
decl_iterator begin()
SmallVectorImpl< NamedDecl * >::const_iterator const_decl_iterator
static unsigned NormalizeEditDistance(unsigned ED)
DeclClass * getCorrectionDeclAs() const
const_decl_iterator end() const
DeclarationName getCorrection() const
Gets the DeclarationName of the typo correction.
unsigned getEditDistance(bool Normalized=true) const
Gets the "edit distance" of the typo correction from the typo.
void ClearCorrectionDecls()
Clears the list of NamedDecls.
static const unsigned CallbackDistanceWeight
NestedNameSpecifier * getCorrectionSpecifier() const
Gets the NestedNameSpecifier needed to use the typo correction.
static const unsigned QualifierDistanceWeight
SmallVectorImpl< NamedDecl * >::iterator decl_iterator
void setCorrectionDecl(NamedDecl *CDecl)
Clears the list of NamedDecls before adding the new one.
void setRequiresImport(bool Req)
std::string getQuoted(const LangOptions &LO) const
bool isOverloaded() const
static const unsigned CharDistanceWeight
bool WillReplaceSpecifier() const
NamedDecl * getFoundDecl() const
Get the correction declaration found by name lookup (before we looked through using shadow declaratio...
void addExtraDiagnostic(PartialDiagnostic PD)
Extra diagnostics are printed after the first diagnostic for the typo.
void makeKeyword()
Mark this TypoCorrection as being a keyword.
The JSON file list parser is used to communicate input to InstallAPI.
#define bool
Definition: stdbool.h:24
DeclarationNameInfo - A collector data type for bundling together a DeclarationName and the correspon...
SourceRange getSourceRange() const LLVM_READONLY
getSourceRange - The range of the declaration name.