clang  3.7.0
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/DeclCXX.h"
19 #include "clang/Sema/DeclSpec.h"
20 #include "clang/Sema/Ownership.h"
21 #include "llvm/ADT/SmallVector.h"
22 
23 namespace clang {
24 
25 /// @brief Simple class containing the result of Sema::CorrectTypo
27 public:
28  // "Distance" for unusable corrections
29  static const unsigned InvalidDistance = ~0U;
30  // The largest distance still considered valid (larger edit distances are
31  // mapped to InvalidDistance by getEditDistance).
32  static const unsigned MaximumDistance = 10000U;
33 
34  // Relative weightings of the "edit distance" components. The higher the
35  // weight, the more of a penalty to fitness the component will give (higher
36  // weights mean greater contribution to the total edit distance, with the
37  // best correction candidates having the lowest edit distance).
38  static const unsigned CharDistanceWeight = 100U;
39  static const unsigned QualifierDistanceWeight = 110U;
40  static const unsigned CallbackDistanceWeight = 150U;
41 
42  TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
43  NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0,
44  unsigned QualifierDistance = 0)
45  : CorrectionName(Name), CorrectionNameSpec(NNS),
46  CharDistance(CharDistance), QualifierDistance(QualifierDistance),
47  CallbackDistance(0), ForceSpecifierReplacement(false),
48  RequiresImport(false) {
49  if (NameDecl)
50  CorrectionDecls.push_back(NameDecl);
51  }
52 
54  unsigned CharDistance = 0)
55  : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
56  CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0),
57  ForceSpecifierReplacement(false), RequiresImport(false) {
58  if (Name)
59  CorrectionDecls.push_back(Name);
60  }
61 
63  unsigned CharDistance = 0)
64  : CorrectionName(Name), CorrectionNameSpec(NNS),
65  CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0),
66  ForceSpecifierReplacement(false), RequiresImport(false) {}
67 
69  : CorrectionNameSpec(nullptr), CharDistance(0), QualifierDistance(0),
70  CallbackDistance(0), ForceSpecifierReplacement(false),
71  RequiresImport(false) {}
72 
73  /// \brief Gets the DeclarationName of the typo correction
74  DeclarationName getCorrection() const { return CorrectionName; }
76  return CorrectionName.getAsIdentifierInfo();
77  }
78 
79  /// \brief Gets the NestedNameSpecifier needed to use the typo correction
81  return CorrectionNameSpec;
82  }
84  CorrectionNameSpec = NNS;
85  ForceSpecifierReplacement = (NNS != nullptr);
86  }
87 
88  void WillReplaceSpecifier(bool ForceReplacement) {
89  ForceSpecifierReplacement = ForceReplacement;
90  }
91 
92  bool WillReplaceSpecifier() const {
93  return ForceSpecifierReplacement;
94  }
95 
96  void setQualifierDistance(unsigned ED) {
97  QualifierDistance = ED;
98  }
99 
100  void setCallbackDistance(unsigned ED) {
101  CallbackDistance = ED;
102  }
103 
104  // Convert the given weighted edit distance to a roughly equivalent number of
105  // single-character edits (typically for comparison to the length of the
106  // string being edited).
107  static unsigned NormalizeEditDistance(unsigned ED) {
108  if (ED > MaximumDistance)
109  return InvalidDistance;
110  return (ED + CharDistanceWeight / 2) / CharDistanceWeight;
111  }
112 
113  /// \brief Gets the "edit distance" of the typo correction from the typo.
114  /// If Normalized is true, scale the distance down by the CharDistanceWeight
115  /// to return the edit distance in terms of single-character edits.
116  unsigned getEditDistance(bool Normalized = true) const {
117  if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance ||
118  CallbackDistance > MaximumDistance)
119  return InvalidDistance;
120  unsigned ED =
121  CharDistance * CharDistanceWeight +
122  QualifierDistance * QualifierDistanceWeight +
123  CallbackDistance * CallbackDistanceWeight;
124  if (ED > MaximumDistance)
125  return InvalidDistance;
126  // Half the CharDistanceWeight is added to ED to simulate rounding since
127  // integer division truncates the value (i.e. round-to-nearest-int instead
128  // of round-to-zero).
129  return Normalized ? NormalizeEditDistance(ED) : ED;
130  }
131 
132  /// \brief Gets the pointer to the declaration of the typo correction
134  return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr;
135  }
136  template <class DeclClass>
137  DeclClass *getCorrectionDeclAs() const {
138  return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
139  }
140 
141  /// \brief Clears the list of NamedDecls.
143  CorrectionDecls.clear();
144  }
145 
146  /// \brief Clears the list of NamedDecls before adding the new one.
148  CorrectionDecls.clear();
149  addCorrectionDecl(CDecl);
150  }
151 
152  /// \brief Clears the list of NamedDecls and adds the given set.
154  CorrectionDecls.clear();
155  CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end());
156  }
157 
158  /// \brief Add the given NamedDecl to the list of NamedDecls that are the
159  /// declarations associated with the DeclarationName of this TypoCorrection
160  void addCorrectionDecl(NamedDecl *CDecl);
161 
162  std::string getAsString(const LangOptions &LO) const;
163  std::string getQuoted(const LangOptions &LO) const {
164  return "'" + getAsString(LO) + "'";
165  }
166 
167  /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName
168  explicit operator bool() const { return bool(CorrectionName); }
169 
170  /// \brief Mark this TypoCorrection as being a keyword.
171  /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
172  /// added to the list of the correction's NamedDecl pointers, NULL is added
173  /// as the only element in the list to mark this TypoCorrection as a keyword.
174  void makeKeyword() {
175  CorrectionDecls.clear();
176  CorrectionDecls.push_back(nullptr);
177  ForceSpecifierReplacement = true;
178  }
179 
180  // Check if this TypoCorrection is a keyword by checking if the first
181  // item in CorrectionDecls is NULL.
182  bool isKeyword() const {
183  return !CorrectionDecls.empty() &&
184  CorrectionDecls.front() == nullptr;
185  }
186 
187  // Check if this TypoCorrection is the given keyword.
188  template<std::size_t StrLen>
189  bool isKeyword(const char (&Str)[StrLen]) const {
190  return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str);
191  }
192 
193  // Returns true if the correction either is a keyword or has a known decl.
194  bool isResolved() const { return !CorrectionDecls.empty(); }
195 
196  bool isOverloaded() const {
197  return CorrectionDecls.size() > 1;
198  }
199 
201  const DeclarationNameInfo &TypoName) {
202  CorrectionRange = TypoName.getSourceRange();
203  if (ForceSpecifierReplacement && SS && !SS->isEmpty())
204  CorrectionRange.setBegin(SS->getBeginLoc());
205  }
206 
208  return CorrectionRange;
209  }
210 
213  return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
214  }
215  decl_iterator end() { return CorrectionDecls.end(); }
218  return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
219  }
220  const_decl_iterator end() const { return CorrectionDecls.end(); }
221 
222  /// \brief Returns whether this typo correction is correcting to a
223  /// declaration that was declared in a module that has not been imported.
224  bool requiresImport() const { return RequiresImport; }
225  void setRequiresImport(bool Req) { RequiresImport = Req; }
226 
227 private:
228  bool hasCorrectionDecl() const {
229  return (!isKeyword() && !CorrectionDecls.empty());
230  }
231 
232  // Results.
233  DeclarationName CorrectionName;
234  NestedNameSpecifier *CorrectionNameSpec;
235  SmallVector<NamedDecl *, 1> CorrectionDecls;
236  unsigned CharDistance;
237  unsigned QualifierDistance;
238  unsigned CallbackDistance;
239  SourceRange CorrectionRange;
240  bool ForceSpecifierReplacement;
241  bool RequiresImport;
242 };
243 
244 /// @brief Base class for callback objects used by Sema::CorrectTypo to check
245 /// the validity of a potential typo correction.
247 public:
249 
251  NestedNameSpecifier *TypoNNS = nullptr)
256  TypoNNS(TypoNNS) {}
257 
259 
260  /// \brief Simple predicate used by the default RankCandidate to
261  /// determine whether to return an edit distance of 0 or InvalidDistance.
262  /// This can be overrided by validators that only need to determine if a
263  /// candidate is viable, without ranking potentially viable candidates.
264  /// Only ValidateCandidate or RankCandidate need to be overriden by a
265  /// callback wishing to check the viability of correction candidates.
266  /// The default predicate always returns true if the candidate is not a type
267  /// name or keyword, true for types if WantTypeSpecifiers is true, and true
268  /// for keywords if WantTypeSpecifiers, WantExpressionKeywords,
269  /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true.
270  virtual bool ValidateCandidate(const TypoCorrection &candidate);
271 
272  /// \brief Method used by Sema::CorrectTypo to assign an "edit distance" rank
273  /// to a candidate (where a lower value represents a better candidate), or
274  /// returning InvalidDistance if the candidate is not at all viable. For
275  /// validation callbacks that only need to determine if a candidate is viable,
276  /// the default RankCandidate returns either 0 or InvalidDistance depending
277  /// whether ValidateCandidate returns true or false.
278  virtual unsigned RankCandidate(const TypoCorrection &candidate) {
279  return (!MatchesTypo(candidate) && ValidateCandidate(candidate))
280  ? 0
281  : InvalidDistance;
282  }
283 
284  void setTypoName(IdentifierInfo *II) { Typo = II; }
285  void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
286 
287  // Flags for context-dependent keywords. WantFunctionLikeCasts is only
288  // used/meaningful when WantCXXNamedCasts is false.
289  // TODO: Expand these to apply to non-keywords or possibly remove them.
296  // Temporary hack for the one case where a CorrectTypoContext enum is used
297  // when looking up results.
300 
301 protected:
302  bool MatchesTypo(const TypoCorrection &candidate) {
303  return Typo && candidate.isResolved() && !candidate.requiresImport() &&
304  candidate.getCorrectionAsIdentifierInfo() == Typo &&
305  // FIXME: This probably does not return true when both
306  // NestedNameSpecifiers have the same textual representation.
307  candidate.getCorrectionSpecifier() == TypoNNS;
308  }
309 
312 };
313 
314 /// @brief Simple template class for restricting typo correction candidates
315 /// to ones having a single Decl* of the given type.
316 template <class C>
318 public:
319  bool ValidateCandidate(const TypoCorrection &candidate) override {
320  return candidate.getCorrectionDeclAs<C>();
321  }
322 };
323 
324 // @brief Callback class to limit the allowed keywords and to only accept typo
325 // corrections that are keywords or whose decls refer to functions (or template
326 // functions) that accept the given number of arguments.
328 public:
329  FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
330  bool HasExplicitTemplateArgs,
331  MemberExpr *ME = nullptr);
332 
333  bool ValidateCandidate(const TypoCorrection &candidate) override;
334 
335  private:
336  unsigned NumArgs;
337  bool HasExplicitTemplateArgs;
338  DeclContext *CurContext;
339  MemberExpr *MemberFn;
340 };
341 
342 // @brief Callback class that effectively disabled typo correction
344 public:
346  WantTypeSpecifiers = false;
347  WantExpressionKeywords = false;
348  WantCXXNamedCasts = false;
349  WantFunctionLikeCasts = false;
350  WantRemainingKeywords = false;
351  }
352 
353  bool ValidateCandidate(const TypoCorrection &candidate) override {
354  return false;
355  }
356 };
357 
358 }
359 
360 #endif
void setTypoName(IdentifierInfo *II)
FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, bool HasExplicitTemplateArgs, MemberExpr *ME=nullptr)
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...
IdentifierInfo * getAsIdentifierInfo() const
decl_iterator begin()
void makeKeyword()
Mark this TypoCorrection as being a keyword. Since addCorrectionDeclsand setCorrectionDecl don't allo...
void setCorrectionSpecifier(NestedNameSpecifier *NNS)
static const unsigned InvalidDistance
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...
bool isEmpty() const
No scope specifier.
Definition: DeclSpec.h:194
void setCorrectionDecl(NamedDecl *CDecl)
Clears the list of NamedDecls before adding the new one.
TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0)
IdentifierInfo * getCorrectionAsIdentifierInfo() const
Base class for callback objects used by Sema::CorrectTypo to check the validity of a potential typo c...
static const unsigned MaximumDistance
bool isOverloaded() const
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:48
void setCallbackDistance(unsigned ED)
bool isKeyword(const char(&Str)[StrLen]) const
void setQualifierDistance(unsigned ED)
bool ValidateCandidate(const TypoCorrection &candidate) override
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)
static unsigned NormalizeEditDistance(unsigned ED)
std::string getQuoted(const LangOptions &LO) const
Represents a C++ nested-name-specifier or a global scope specifier.
Definition: DeclSpec.h:68
bool WillReplaceSpecifier() const
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
SmallVectorImpl< NamedDecl * >::const_iterator const_decl_iterator
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:258
virtual bool ValidateCandidate(const TypoCorrection &candidate)
Simple predicate used by the default RankCandidate to determine whether to return an edit distance of...
NestedNameSpecifier * getCorrectionSpecifier() const
Gets the NestedNameSpecifier needed to use the typo correction.
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
CorrectionCandidateCallback(IdentifierInfo *Typo=nullptr, NestedNameSpecifier *TypoNNS=nullptr)
unsigned getEditDistance(bool Normalized=true) const
Gets the "edit distance" of the typo correction from the typo. If Normalized is true, scale the distance down by the CharDistanceWeight to return the edit distance in terms of single-character edits.
static const unsigned CharDistanceWeight
#define false
Definition: stdbool.h:33
void setCorrectionDecls(ArrayRef< NamedDecl * > Decls)
Clears the list of NamedDecls and adds the given set.
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)
SourceLocation getBeginLoc() const
Definition: DeclSpec.h:77
static const unsigned QualifierDistanceWeight
bool isStr(const char(&Str)[StrLen]) const
Return true if this is the identifier for the specified string.
bool isResolved() const
const_decl_iterator begin() const
DeclClass * getCorrectionDeclAs() const
DeclarationName getCorrection() const
Gets the DeclarationName of the typo correction.
bool isKeyword() const
NamedDecl * getCorrectionDecl() const
Gets the pointer to the declaration of the typo correction.
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...
std::string getAsString(const LangOptions &LO) const
SourceRange getCorrectionRange() const
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
void ClearCorrectionDecls()
Clears the list of NamedDecls.
void setCorrectionRange(CXXScopeSpec *SS, const DeclarationNameInfo &TypoName)
SmallVectorImpl< NamedDecl * >::iterator decl_iterator
decl_iterator end()
static const unsigned CallbackDistanceWeight
const_decl_iterator end() const
#define true
Definition: stdbool.h:32
TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0)
A trivial tuple used to represent a source range.
bool requiresImport() const
Returns whether this typo correction is correcting to a declaration that was declared in a module tha...
void WillReplaceSpecifier(bool ForceReplacement)