clang  19.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 
32 namespace clang {
33 
34 class DeclContext;
35 class IdentifierInfo;
36 class LangOptions;
37 class MemberExpr;
38 class NestedNameSpecifier;
39 class Sema;
40 
41 /// Simple class containing the result of Sema::CorrectTypo
43 public:
44  // "Distance" for unusable corrections
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 
59  TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
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 {
209  return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str);
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 
260 private:
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.
282 public:
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
312  : InvalidDistance;
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; }
323  void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
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.
328  bool WantTypeSpecifiers = true;
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 
339 protected:
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 
353 public:
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.
365 template <class C>
367 public:
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.
384 public:
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 
394 private:
395  unsigned NumArgs;
396  bool HasExplicitTemplateArgs;
397  DeclContext *CurContext;
398  MemberExpr *MemberFn;
399 };
400 
401 // Callback class that effectively disabled typo correction
403 public:
405  WantTypeSpecifiers = false;
406  WantExpressionKeywords = 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
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.
__DEVICE__ int max(int __a, int __b)
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)
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.
The name of a declaration.
IdentifierInfo * getAsIdentifierInfo() const
Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn't...
DefaultFilterCCC(const IdentifierInfo *Typo=nullptr, NestedNameSpecifier *TypoNNS=nullptr)
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
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...
FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, bool HasExplicitTemplateArgs, MemberExpr *ME=nullptr)
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:482
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3224
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:462
A trivial tuple used to represent a source range.
void setBegin(SourceLocation b)
Simple class containing the result of Sema::CorrectTypo.
TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0)
ArrayRef< PartialDiagnostic > getExtraDiagnostics() const
TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0, unsigned QualifierDistance=0)
void setCorrectionSpecifier(NestedNameSpecifier *NNS)
NamedDecl * getCorrectionDecl() const
Gets the pointer to the declaration of the typo correction.
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...
DeclClass * getCorrectionDeclAs() const
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
IdentifierInfo * getCorrectionAsIdentifierInfo() 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)
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)
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
NamedDecl * getFoundDecl() const
Get the correction declaration found by name lookup (before we looked through using shadow declaratio...
SmallVectorImpl< NamedDecl * >::iterator decl_iterator
void setCorrectionDecl(NamedDecl *CDecl)
Clears the list of NamedDecls before adding the new one.
void setRequiresImport(bool Req)
NestedNameSpecifier * getCorrectionSpecifier() const
Gets the NestedNameSpecifier needed to use the typo correction.
std::string getQuoted(const LangOptions &LO) const
bool isOverloaded() const
static const unsigned CharDistanceWeight
bool WillReplaceSpecifier() const
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.