clang 22.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 = std::nullopt,
61 unsigned CharDistance = 0, unsigned QualifierDistance = 0)
62 : CorrectionName(Name), CorrectionNameSpec(NNS),
63 CharDistance(CharDistance), QualifierDistance(QualifierDistance) {
64 if (NameDecl)
65 CorrectionDecls.push_back(NameDecl);
66 }
67
68 TypoCorrection(NamedDecl *Name, NestedNameSpecifier NNS = std::nullopt,
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;
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 = std::nullopt;
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 const IdentifierInfo *Typo = nullptr,
287 NestedNameSpecifier TypoNNS = std::nullopt)
288 : Typo(Typo), TypoNNS(TypoNNS) {}
289
290 virtual ~CorrectionCandidateCallback() = default;
291
292 /// Simple predicate used by the default RankCandidate to
293 /// determine whether to return an edit distance of 0 or InvalidDistance.
294 /// This can be overridden by validators that only need to determine if a
295 /// candidate is viable, without ranking potentially viable candidates.
296 /// Only ValidateCandidate or RankCandidate need to be overridden by a
297 /// callback wishing to check the viability of correction candidates.
298 /// The default predicate always returns true if the candidate is not a type
299 /// name or keyword, true for types if WantTypeSpecifiers is true, and true
300 /// for keywords if WantTypeSpecifiers, WantExpressionKeywords,
301 /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true.
302 virtual bool ValidateCandidate(const TypoCorrection &candidate);
303
304 /// Method used by Sema::CorrectTypo to assign an "edit distance" rank
305 /// to a candidate (where a lower value represents a better candidate), or
306 /// returning InvalidDistance if the candidate is not at all viable. For
307 /// validation callbacks that only need to determine if a candidate is viable,
308 /// the default RankCandidate returns either 0 or InvalidDistance depending
309 /// whether ValidateCandidate returns true or false.
310 virtual unsigned RankCandidate(const TypoCorrection &candidate) {
311 return (!MatchesTypo(candidate) && ValidateCandidate(candidate))
312 ? 0
314 }
315
316 /// Clone this CorrectionCandidateCallback. CorrectionCandidateCallbacks are
317 /// initially stack-allocated. However in case where delayed typo-correction
318 /// is done we need to move the callback to storage with a longer lifetime.
319 /// Every class deriving from CorrectionCandidateCallback must implement
320 /// this method.
321 virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0;
322
323 void setTypoName(const IdentifierInfo *II) { Typo = II; }
325
326 // Flags for context-dependent keywords. WantFunctionLikeCasts is only
327 // used/meaningful when WantCXXNamedCasts is false.
328 // TODO: Expand these to apply to non-keywords or possibly remove them.
331 bool WantCXXNamedCasts = true;
334 bool WantObjCSuper = false;
335 // Temporary hack for the one case where a CorrectTypoContext enum is used
336 // when looking up results.
337 bool IsObjCIvarLookup = false;
338 bool IsAddressOfOperand = false;
339
340protected:
341 bool MatchesTypo(const TypoCorrection &candidate) {
342 return Typo && candidate.isResolved() && !candidate.requiresImport() &&
343 candidate.getCorrectionAsIdentifierInfo() == Typo &&
344 // FIXME: This probably does not return true when both
345 // NestedNameSpecifiers have the same textual representation.
346 candidate.getCorrectionSpecifier() == TypoNNS;
347 }
348
351};
352
354public:
355 explicit DefaultFilterCCC(const IdentifierInfo *Typo = nullptr,
356 NestedNameSpecifier TypoNNS = std::nullopt)
358
359 std::unique_ptr<CorrectionCandidateCallback> clone() override {
360 return std::make_unique<DefaultFilterCCC>(*this);
361 }
362};
363
364/// Simple template class for restricting typo correction candidates
365/// to ones having a single Decl* of the given type.
366template <class C>
368public:
369 explicit DeclFilterCCC(const IdentifierInfo *Typo = nullptr,
370 NestedNameSpecifier TypoNNS = std::nullopt)
372
373 bool ValidateCandidate(const TypoCorrection &candidate) override {
374 return candidate.getCorrectionDeclAs<C>();
375 }
376 std::unique_ptr<CorrectionCandidateCallback> clone() override {
377 return std::make_unique<DeclFilterCCC>(*this);
378 }
379};
380
381// Callback class to limit the allowed keywords and to only accept typo
382// corrections that are keywords or whose decls refer to functions (or template
383// functions) that accept the given number of arguments.
385public:
386 FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
387 bool HasExplicitTemplateArgs,
388 MemberExpr *ME = nullptr);
389
390 bool ValidateCandidate(const TypoCorrection &candidate) override;
391 std::unique_ptr<CorrectionCandidateCallback> clone() override {
392 return std::make_unique<FunctionCallFilterCCC>(*this);
393 }
394
395private:
396 unsigned NumArgs;
397 bool HasExplicitTemplateArgs;
398 DeclContext *CurContext;
399 MemberExpr *MemberFn;
400};
401
402// Callback class that effectively disabled typo correction
404public:
406 WantTypeSpecifiers = false;
408 WantCXXNamedCasts = false;
409 WantFunctionLikeCasts = false;
410 WantRemainingKeywords = false;
411 }
412
413 bool ValidateCandidate(const TypoCorrection &candidate) override {
414 return false;
415 }
416 std::unique_ptr<CorrectionCandidateCallback> clone() override {
417 return std::make_unique<NoTypoCorrectionCCC>(*this);
418 }
419};
420
421} // namespace clang
422
423#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:73
SourceLocation getBeginLoc() const
Definition: DeclSpec.h:83
bool isEmpty() const
No scope specifier.
Definition: DeclSpec.h:178
Base class for callback objects used by Sema::CorrectTypo to check the validity of a potential typo c...
CorrectionCandidateCallback(const IdentifierInfo *Typo=nullptr, NestedNameSpecifier TypoNNS=std::nullopt)
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)
void setTypoNNS(NestedNameSpecifier NNS)
virtual ~CorrectionCandidateCallback()=default
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:1449
Simple template class for restricting typo correction candidates to ones having a single Decl* of the...
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
DeclFilterCCC(const IdentifierInfo *Typo=nullptr, NestedNameSpecifier TypoNNS=std::nullopt)
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=std::nullopt)
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:434
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3300
This represents a decl that may have a name.
Definition: Decl.h:273
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:850
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=std::nullopt, unsigned CharDistance=0)
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...
void setCorrectionSpecifier(NestedNameSpecifier NNS)
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)
TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, NestedNameSpecifier NNS=std::nullopt, unsigned CharDistance=0, unsigned QualifierDistance=0)
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
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)
TypoCorrection(NamedDecl *Name, NestedNameSpecifier NNS=std::nullopt, unsigned CharDistance=0)
std::string getQuoted(const LangOptions &LO) const
bool isOverloaded() const
static const unsigned CharDistanceWeight
bool WillReplaceSpecifier() const
NestedNameSpecifier getCorrectionSpecifier() const
Gets the NestedNameSpecifier needed to use the typo correction.
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.
#define bool
Definition: gpuintrin.h:32
The JSON file list parser is used to communicate input to InstallAPI.
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.