clang  8.0.0svn
TypoCorrection.h
Go to the documentation of this file.
1 //===- TypoCorrection.h - Class for typo correction results -----*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the TypoCorrection class, which stores the results of
11 // Sema's typo correction (Sema::CorrectTypo).
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H
16 #define LLVM_CLANG_SEMA_TYPOCORRECTION_H
17 
18 #include "clang/AST/Decl.h"
20 #include "clang/Basic/LLVM.h"
23 #include "clang/Sema/DeclSpec.h"
24 #include "llvm/ADT/ArrayRef.h"
25 #include "llvm/ADT/SmallVector.h"
26 #include "llvm/Support/Casting.h"
27 #include <cstddef>
28 #include <limits>
29 #include <string>
30 #include <utility>
31 #include <vector>
32 
33 namespace clang {
34 
35 class DeclContext;
36 class IdentifierInfo;
37 class LangOptions;
38 class MemberExpr;
39 class NestedNameSpecifier;
40 class Sema;
41 
42 /// Simple class containing the result of Sema::CorrectTypo
44 public:
45  // "Distance" for unusable corrections
47 
48  // The largest distance still considered valid (larger edit distances are
49  // mapped to InvalidDistance by getEditDistance).
50  static const unsigned MaximumDistance = 10000U;
51 
52  // Relative weightings of the "edit distance" components. The higher the
53  // weight, the more of a penalty to fitness the component will give (higher
54  // weights mean greater contribution to the total edit distance, with the
55  // best correction candidates having the lowest edit distance).
56  static const unsigned CharDistanceWeight = 100U;
57  static const unsigned QualifierDistanceWeight = 110U;
58  static const unsigned CallbackDistanceWeight = 150U;
59 
60  TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
61  NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0,
62  unsigned QualifierDistance = 0)
63  : CorrectionName(Name), CorrectionNameSpec(NNS),
64  CharDistance(CharDistance), QualifierDistance(QualifierDistance) {
65  if (NameDecl)
66  CorrectionDecls.push_back(NameDecl);
67  }
68 
70  unsigned CharDistance = 0)
71  : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
72  CharDistance(CharDistance) {
73  if (Name)
74  CorrectionDecls.push_back(Name);
75  }
76 
78  unsigned CharDistance = 0)
79  : CorrectionName(Name), CorrectionNameSpec(NNS),
80  CharDistance(CharDistance) {}
81 
82  TypoCorrection() = default;
83 
84  /// Gets the DeclarationName of the typo correction
85  DeclarationName getCorrection() const { return CorrectionName; }
86 
88  return CorrectionName.getAsIdentifierInfo();
89  }
90 
91  /// Gets the NestedNameSpecifier needed to use the typo correction
93  return CorrectionNameSpec;
94  }
95 
97  CorrectionNameSpec = NNS;
98  ForceSpecifierReplacement = (NNS != nullptr);
99  }
100 
101  void WillReplaceSpecifier(bool ForceReplacement) {
102  ForceSpecifierReplacement = ForceReplacement;
103  }
104 
105  bool WillReplaceSpecifier() const {
106  return ForceSpecifierReplacement;
107  }
108 
109  void setQualifierDistance(unsigned ED) {
110  QualifierDistance = ED;
111  }
112 
113  void setCallbackDistance(unsigned ED) {
114  CallbackDistance = ED;
115  }
116 
117  // Convert the given weighted edit distance to a roughly equivalent number of
118  // single-character edits (typically for comparison to the length of the
119  // string being edited).
120  static unsigned NormalizeEditDistance(unsigned ED) {
121  if (ED > MaximumDistance)
122  return InvalidDistance;
123  return (ED + CharDistanceWeight / 2) / CharDistanceWeight;
124  }
125 
126  /// Gets the "edit distance" of the typo correction from the typo.
127  /// If Normalized is true, scale the distance down by the CharDistanceWeight
128  /// to return the edit distance in terms of single-character edits.
129  unsigned getEditDistance(bool Normalized = true) const {
130  if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance ||
131  CallbackDistance > MaximumDistance)
132  return InvalidDistance;
133  unsigned ED =
134  CharDistance * CharDistanceWeight +
135  QualifierDistance * QualifierDistanceWeight +
136  CallbackDistance * CallbackDistanceWeight;
137  if (ED > MaximumDistance)
138  return InvalidDistance;
139  // Half the CharDistanceWeight is added to ED to simulate rounding since
140  // integer division truncates the value (i.e. round-to-nearest-int instead
141  // of round-to-zero).
142  return Normalized ? NormalizeEditDistance(ED) : ED;
143  }
144 
145  /// Get the correction declaration found by name lookup (before we
146  /// looked through using shadow declarations and the like).
148  return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr;
149  }
150 
151  /// Gets the pointer to the declaration of the typo correction
153  auto *D = getFoundDecl();
154  return D ? D->getUnderlyingDecl() : nullptr;
155  }
156  template <class DeclClass>
157  DeclClass *getCorrectionDeclAs() const {
158  return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
159  }
160 
161  /// Clears the list of NamedDecls.
163  CorrectionDecls.clear();
164  }
165 
166  /// Clears the list of NamedDecls before adding the new one.
168  CorrectionDecls.clear();
169  addCorrectionDecl(CDecl);
170  }
171 
172  /// Clears the list of NamedDecls and adds the given set.
174  CorrectionDecls.clear();
175  CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end());
176  }
177 
178  /// Add the given NamedDecl to the list of NamedDecls that are the
179  /// declarations associated with the DeclarationName of this TypoCorrection
180  void addCorrectionDecl(NamedDecl *CDecl);
181 
182  std::string getAsString(const LangOptions &LO) const;
183 
184  std::string getQuoted(const LangOptions &LO) const {
185  return "'" + getAsString(LO) + "'";
186  }
187 
188  /// Returns whether this TypoCorrection has a non-empty DeclarationName
189  explicit operator bool() const { return bool(CorrectionName); }
190 
191  /// Mark this TypoCorrection as being a keyword.
192  /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
193  /// added to the list of the correction's NamedDecl pointers, NULL is added
194  /// as the only element in the list to mark this TypoCorrection as a keyword.
195  void makeKeyword() {
196  CorrectionDecls.clear();
197  CorrectionDecls.push_back(nullptr);
198  ForceSpecifierReplacement = true;
199  }
200 
201  // Check if this TypoCorrection is a keyword by checking if the first
202  // item in CorrectionDecls is NULL.
203  bool isKeyword() const {
204  return !CorrectionDecls.empty() && CorrectionDecls.front() == nullptr;
205  }
206 
207  // Check if this TypoCorrection is the given keyword.
208  template<std::size_t StrLen>
209  bool isKeyword(const char (&Str)[StrLen]) const {
210  return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str);
211  }
212 
213  // Returns true if the correction either is a keyword or has a known decl.
214  bool isResolved() const { return !CorrectionDecls.empty(); }
215 
216  bool isOverloaded() const {
217  return CorrectionDecls.size() > 1;
218  }
219 
221  const DeclarationNameInfo &TypoName) {
222  CorrectionRange = TypoName.getSourceRange();
223  if (ForceSpecifierReplacement && SS && !SS->isEmpty())
224  CorrectionRange.setBegin(SS->getBeginLoc());
225  }
226 
228  return CorrectionRange;
229  }
230 
232 
234  return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
235  }
236 
237  decl_iterator end() { return CorrectionDecls.end(); }
238 
240 
242  return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
243  }
244 
245  const_decl_iterator end() const { return CorrectionDecls.end(); }
246 
247  /// Returns whether this typo correction is correcting to a
248  /// declaration that was declared in a module that has not been imported.
249  bool requiresImport() const { return RequiresImport; }
250  void setRequiresImport(bool Req) { RequiresImport = Req; }
251 
252  /// Extra diagnostics are printed after the first diagnostic for the typo.
253  /// This can be used to attach external notes to the diag.
255  ExtraDiagnostics.push_back(std::move(PD));
256  }
258  return ExtraDiagnostics;
259  }
260 
261 private:
262  bool hasCorrectionDecl() const {
263  return (!isKeyword() && !CorrectionDecls.empty());
264  }
265 
266  // Results.
267  DeclarationName CorrectionName;
268  NestedNameSpecifier *CorrectionNameSpec = nullptr;
269  SmallVector<NamedDecl *, 1> CorrectionDecls;
270  unsigned CharDistance = 0;
271  unsigned QualifierDistance = 0;
272  unsigned CallbackDistance = 0;
273  SourceRange CorrectionRange;
274  bool ForceSpecifierReplacement = false;
275  bool RequiresImport = false;
276 
277  std::vector<PartialDiagnostic> ExtraDiagnostics;
278 };
279 
280 /// Base class for callback objects used by Sema::CorrectTypo to check
281 /// the validity of a potential typo correction.
283 public:
284  static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
285 
286  explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr,
287  NestedNameSpecifier *TypoNNS = nullptr)
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
313  : InvalidDistance;
314  }
315 
316  void setTypoName(IdentifierInfo *II) { Typo = II; }
317  void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
318 
319  // Flags for context-dependent keywords. WantFunctionLikeCasts is only
320  // used/meaningful when WantCXXNamedCasts is false.
321  // TODO: Expand these to apply to non-keywords or possibly remove them.
322  bool WantTypeSpecifiers = true;
323  bool WantExpressionKeywords = true;
324  bool WantCXXNamedCasts = true;
325  bool WantFunctionLikeCasts = true;
326  bool WantRemainingKeywords = true;
327  bool WantObjCSuper = false;
328  // Temporary hack for the one case where a CorrectTypoContext enum is used
329  // when looking up results.
330  bool IsObjCIvarLookup = false;
331  bool IsAddressOfOperand = false;
332 
333 protected:
334  bool MatchesTypo(const TypoCorrection &candidate) {
335  return Typo && candidate.isResolved() && !candidate.requiresImport() &&
336  candidate.getCorrectionAsIdentifierInfo() == Typo &&
337  // FIXME: This probably does not return true when both
338  // NestedNameSpecifiers have the same textual representation.
339  candidate.getCorrectionSpecifier() == TypoNNS;
340  }
341 
344 };
345 
346 /// Simple template class for restricting typo correction candidates
347 /// to ones having a single Decl* of the given type.
348 template <class C>
350 public:
351  bool ValidateCandidate(const TypoCorrection &candidate) override {
352  return candidate.getCorrectionDeclAs<C>();
353  }
354 };
355 
356 // Callback class to limit the allowed keywords and to only accept typo
357 // corrections that are keywords or whose decls refer to functions (or template
358 // functions) that accept the given number of arguments.
360 public:
361  FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
362  bool HasExplicitTemplateArgs,
363  MemberExpr *ME = nullptr);
364 
365  bool ValidateCandidate(const TypoCorrection &candidate) override;
366 
367 private:
368  unsigned NumArgs;
369  bool HasExplicitTemplateArgs;
370  DeclContext *CurContext;
371  MemberExpr *MemberFn;
372 };
373 
374 // Callback class that effectively disabled typo correction
376 public:
378  WantTypeSpecifiers = false;
379  WantExpressionKeywords = false;
380  WantCXXNamedCasts = false;
381  WantFunctionLikeCasts = false;
382  WantRemainingKeywords = false;
383  }
384 
385  bool ValidateCandidate(const TypoCorrection &candidate) override {
386  return false;
387  }
388 };
389 
390 } // namespace clang
391 
392 #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
decl_iterator begin()
void makeKeyword()
Mark this TypoCorrection as being a keyword.
void setCorrectionSpecifier(NestedNameSpecifier *NNS)
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:50
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:278
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:31
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
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:1261
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
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:2467
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)
ArrayRef< PartialDiagnostic > getExtraDiagnostics() const