clang  10.0.0svn
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:
283  static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
284 
285  explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr,
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(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;
329  bool WantExpressionKeywords = true;
330  bool WantCXXNamedCasts = true;
331  bool WantFunctionLikeCasts = true;
332  bool WantRemainingKeywords = 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(IdentifierInfo *Typo = nullptr,
355  NestedNameSpecifier *TypoNNS = nullptr)
356  : CorrectionCandidateCallback(Typo, TypoNNS) {}
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  bool ValidateCandidate(const TypoCorrection &candidate) override {
369  return candidate.getCorrectionDeclAs<C>();
370  }
371  std::unique_ptr<CorrectionCandidateCallback> clone() override {
372  return std::make_unique<DeclFilterCCC>(*this);
373  }
374 };
375 
376 // Callback class to limit the allowed keywords and to only accept typo
377 // corrections that are keywords or whose decls refer to functions (or template
378 // functions) that accept the given number of arguments.
380 public:
381  FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
382  bool HasExplicitTemplateArgs,
383  MemberExpr *ME = nullptr);
384 
385  bool ValidateCandidate(const TypoCorrection &candidate) override;
386  std::unique_ptr<CorrectionCandidateCallback> clone() override {
387  return std::make_unique<FunctionCallFilterCCC>(*this);
388  }
389 
390 private:
391  unsigned NumArgs;
392  bool HasExplicitTemplateArgs;
393  DeclContext *CurContext;
394  MemberExpr *MemberFn;
395 };
396 
397 // Callback class that effectively disabled typo correction
399 public:
401  WantTypeSpecifiers = false;
402  WantExpressionKeywords = false;
403  WantCXXNamedCasts = false;
404  WantFunctionLikeCasts = false;
405  WantRemainingKeywords = false;
406  }
407 
408  bool ValidateCandidate(const TypoCorrection &candidate) override {
409  return false;
410  }
411  std::unique_ptr<CorrectionCandidateCallback> clone() override {
412  return std::make_unique<NoTypoCorrectionCCC>(*this);
413  }
414 };
415 
416 } // namespace clang
417 
418 #endif // LLVM_CLANG_SEMA_TYPOCORRECTION_H
void setTypoName(IdentifierInfo *II)
SourceRange getCorrectionRange() const
Simple class containing the result of Sema::CorrectTypo.
virtual unsigned RankCandidate(const TypoCorrection &candidate)
Method used by Sema::CorrectTypo to assign an "edit distance" rank to a candidate (where a lower valu...
bool isEmpty() const
No scope specifier.
Definition: DeclSpec.h:189
SmallVectorImpl< NamedDecl * >::const_iterator const_decl_iterator
SmallVectorImpl< NamedDecl * >::iterator decl_iterator
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
decl_iterator begin()
void makeKeyword()
Mark this TypoCorrection as being a keyword.
void setCorrectionSpecifier(NestedNameSpecifier *NNS)
DefaultFilterCCC(IdentifierInfo *Typo=nullptr, NestedNameSpecifier *TypoNNS=nullptr)
NestedNameSpecifier * getCorrectionSpecifier() const
Gets the NestedNameSpecifier needed to use the typo correction.
DeclClass * getCorrectionDeclAs() const
bool isOverloaded() const
void setBegin(SourceLocation b)
bool ValidateCandidate(const TypoCorrection &candidate) override
Simple predicate used by the default RankCandidate to determine whether to return an edit distance of...
void setCorrectionDecl(NamedDecl *CDecl)
Clears the list of NamedDecls before adding the new one.
One of these records is kept for each identifier that is lexed.
TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0)
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
std::string getQuoted(const LangOptions &LO) const
DeclarationName getCorrection() const
Gets the DeclarationName of the typo correction.
Base class for callback objects used by Sema::CorrectTypo to check the validity of a potential typo c...
static const unsigned MaximumDistance
void addCorrectionDecl(NamedDecl *CDecl)
Add the given NamedDecl to the list of NamedDecls that are the declarations associated with the Decla...
__DEVICE__ int max(int __a, int __b)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
bool requiresImport() const
Returns whether this typo correction is correcting to a declaration that was declared in a module tha...
void setCallbackDistance(unsigned ED)
void setQualifierDistance(unsigned ED)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
bool MatchesTypo(const TypoCorrection &candidate)
void setTypoNNS(NestedNameSpecifier *NNS)
static unsigned NormalizeEditDistance(unsigned ED)
Represents a C++ nested-name-specifier or a global scope specifier.
Definition: DeclSpec.h:63
bool ValidateCandidate(const TypoCorrection &candidate) override
Simple predicate used by the default RankCandidate to determine whether to return an edit distance of...
static const unsigned InvalidDistance
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:331
NamedDecl * getFoundDecl() const
Get the correction declaration found by name lookup (before we looked through using shadow declaratio...
unsigned getEditDistance(bool Normalized=true) const
Gets the "edit distance" of the typo correction from the typo.
std::string getAsString(const LangOptions &LO) const
void addExtraDiagnostic(PartialDiagnostic PD)
Extra diagnostics are printed after the first diagnostic for the typo.
This file defines the classes used to store parsed information about declaration-specifiers and decla...
void setRequiresImport(bool Req)
#define bool
Definition: stdbool.h:15
SourceLocation getBeginLoc() const
Definition: DeclSpec.h:72
IdentifierInfo * getAsIdentifierInfo() const
Retrieve the IdentifierInfo * stored in this declaration name, or null if this declaration name isn&#39;t...
CorrectionCandidateCallback(IdentifierInfo *Typo=nullptr, NestedNameSpecifier *TypoNNS=nullptr)
static const unsigned CharDistanceWeight
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0, unsigned QualifierDistance=0)
const_decl_iterator end() const
static const unsigned QualifierDistanceWeight
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
Dataflow Directional Tag Classes.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1271
NamedDecl * getCorrectionDecl() const
Gets the pointer to the declaration of the typo correction.
The name of a declaration.
bool isKeyword(const char(&Str)[StrLen]) const
DeclarationNameInfo - A collector data type for bundling together a DeclarationName and the correspnd...
bool WillReplaceSpecifier() const
IdentifierInfo * getCorrectionAsIdentifierInfo() const
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
SourceRange getSourceRange() const LLVM_READONLY
getSourceRange - The range of the declaration name.
Simple template class for restricting typo correction candidates to ones having a single Decl* of the...
Implements a partial diagnostic that can be emitted anwyhere in a DiagnosticBuilder stream...
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:2811
void setCorrectionDecls(ArrayRef< NamedDecl *> Decls)
Clears the list of NamedDecls and adds the given set.
Defines the clang::SourceLocation class and associated facilities.
const_decl_iterator begin() const
void ClearCorrectionDecls()
Clears the list of NamedDecls.
void setCorrectionRange(CXXScopeSpec *SS, const DeclarationNameInfo &TypoName)
decl_iterator end()
static const unsigned CallbackDistanceWeight
TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0)
A trivial tuple used to represent a source range.
This represents a decl that may have a name.
Definition: Decl.h:248
void WillReplaceSpecifier(bool ForceReplacement)
std::unique_ptr< CorrectionCandidateCallback > clone() override
Clone this CorrectionCandidateCallback.
ArrayRef< PartialDiagnostic > getExtraDiagnostics() const