clang  9.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 llvm::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 llvm::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 llvm::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 llvm::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...
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:328
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:2740
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
__DEVICE__ int max(int __a, int __b)
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