clang  6.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/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 Get the correction declaration found by name lookup (before we
133  /// looked through using shadow declarations and the like).
135  return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr;
136  }
137 
138  /// \brief Gets the pointer to the declaration of the typo correction
140  auto *D = getFoundDecl();
141  return D ? D->getUnderlyingDecl() : nullptr;
142  }
143  template <class DeclClass>
144  DeclClass *getCorrectionDeclAs() const {
145  return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
146  }
147 
148  /// \brief Clears the list of NamedDecls.
150  CorrectionDecls.clear();
151  }
152 
153  /// \brief Clears the list of NamedDecls before adding the new one.
155  CorrectionDecls.clear();
156  addCorrectionDecl(CDecl);
157  }
158 
159  /// \brief Clears the list of NamedDecls and adds the given set.
161  CorrectionDecls.clear();
162  CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end());
163  }
164 
165  /// \brief Add the given NamedDecl to the list of NamedDecls that are the
166  /// declarations associated with the DeclarationName of this TypoCorrection
167  void addCorrectionDecl(NamedDecl *CDecl);
168 
169  std::string getAsString(const LangOptions &LO) const;
170  std::string getQuoted(const LangOptions &LO) const {
171  return "'" + getAsString(LO) + "'";
172  }
173 
174  /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName
175  explicit operator bool() const { return bool(CorrectionName); }
176 
177  /// \brief Mark this TypoCorrection as being a keyword.
178  /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
179  /// added to the list of the correction's NamedDecl pointers, NULL is added
180  /// as the only element in the list to mark this TypoCorrection as a keyword.
181  void makeKeyword() {
182  CorrectionDecls.clear();
183  CorrectionDecls.push_back(nullptr);
184  ForceSpecifierReplacement = true;
185  }
186 
187  // Check if this TypoCorrection is a keyword by checking if the first
188  // item in CorrectionDecls is NULL.
189  bool isKeyword() const {
190  return !CorrectionDecls.empty() && CorrectionDecls.front() == nullptr;
191  }
192 
193  // Check if this TypoCorrection is the given keyword.
194  template<std::size_t StrLen>
195  bool isKeyword(const char (&Str)[StrLen]) const {
196  return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str);
197  }
198 
199  // Returns true if the correction either is a keyword or has a known decl.
200  bool isResolved() const { return !CorrectionDecls.empty(); }
201 
202  bool isOverloaded() const {
203  return CorrectionDecls.size() > 1;
204  }
205 
207  const DeclarationNameInfo &TypoName) {
208  CorrectionRange = TypoName.getSourceRange();
209  if (ForceSpecifierReplacement && SS && !SS->isEmpty())
210  CorrectionRange.setBegin(SS->getBeginLoc());
211  }
212 
214  return CorrectionRange;
215  }
216 
218  decl_iterator begin() {
219  return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
220  }
221  decl_iterator end() { return CorrectionDecls.end(); }
223  const_decl_iterator begin() const {
224  return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
225  }
226  const_decl_iterator end() const { return CorrectionDecls.end(); }
227 
228  /// \brief Returns whether this typo correction is correcting to a
229  /// declaration that was declared in a module that has not been imported.
230  bool requiresImport() const { return RequiresImport; }
231  void setRequiresImport(bool Req) { RequiresImport = Req; }
232 
233  /// Extra diagnostics are printed after the first diagnostic for the typo.
234  /// This can be used to attach external notes to the diag.
236  ExtraDiagnostics.push_back(std::move(PD));
237  }
239  return ExtraDiagnostics;
240  }
241 
242 private:
243  bool hasCorrectionDecl() const {
244  return (!isKeyword() && !CorrectionDecls.empty());
245  }
246 
247  // Results.
248  DeclarationName CorrectionName;
249  NestedNameSpecifier *CorrectionNameSpec;
250  SmallVector<NamedDecl *, 1> CorrectionDecls;
251  unsigned CharDistance;
252  unsigned QualifierDistance;
253  unsigned CallbackDistance;
254  SourceRange CorrectionRange;
255  bool ForceSpecifierReplacement;
256  bool RequiresImport;
257 
258  std::vector<PartialDiagnostic> ExtraDiagnostics;
259 };
260 
261 /// @brief Base class for callback objects used by Sema::CorrectTypo to check
262 /// the validity of a potential typo correction.
264 public:
265  static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
266 
267  explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr,
268  NestedNameSpecifier *TypoNNS = nullptr)
269  : WantTypeSpecifiers(true), WantExpressionKeywords(true),
270  WantCXXNamedCasts(true), WantFunctionLikeCasts(true),
271  WantRemainingKeywords(true), WantObjCSuper(false),
272  IsObjCIvarLookup(false), IsAddressOfOperand(false), Typo(Typo),
273  TypoNNS(TypoNNS) {}
274 
276 
277  /// \brief Simple predicate used by the default RankCandidate to
278  /// determine whether to return an edit distance of 0 or InvalidDistance.
279  /// This can be overrided by validators that only need to determine if a
280  /// candidate is viable, without ranking potentially viable candidates.
281  /// Only ValidateCandidate or RankCandidate need to be overriden by a
282  /// callback wishing to check the viability of correction candidates.
283  /// The default predicate always returns true if the candidate is not a type
284  /// name or keyword, true for types if WantTypeSpecifiers is true, and true
285  /// for keywords if WantTypeSpecifiers, WantExpressionKeywords,
286  /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true.
287  virtual bool ValidateCandidate(const TypoCorrection &candidate);
288 
289  /// \brief Method used by Sema::CorrectTypo to assign an "edit distance" rank
290  /// to a candidate (where a lower value represents a better candidate), or
291  /// returning InvalidDistance if the candidate is not at all viable. For
292  /// validation callbacks that only need to determine if a candidate is viable,
293  /// the default RankCandidate returns either 0 or InvalidDistance depending
294  /// whether ValidateCandidate returns true or false.
295  virtual unsigned RankCandidate(const TypoCorrection &candidate) {
296  return (!MatchesTypo(candidate) && ValidateCandidate(candidate))
297  ? 0
298  : InvalidDistance;
299  }
300 
301  void setTypoName(IdentifierInfo *II) { Typo = II; }
302  void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
303 
304  // Flags for context-dependent keywords. WantFunctionLikeCasts is only
305  // used/meaningful when WantCXXNamedCasts is false.
306  // TODO: Expand these to apply to non-keywords or possibly remove them.
313  // Temporary hack for the one case where a CorrectTypoContext enum is used
314  // when looking up results.
317 
318 protected:
319  bool MatchesTypo(const TypoCorrection &candidate) {
320  return Typo && candidate.isResolved() && !candidate.requiresImport() &&
321  candidate.getCorrectionAsIdentifierInfo() == Typo &&
322  // FIXME: This probably does not return true when both
323  // NestedNameSpecifiers have the same textual representation.
324  candidate.getCorrectionSpecifier() == TypoNNS;
325  }
326 
329 };
330 
331 /// @brief Simple template class for restricting typo correction candidates
332 /// to ones having a single Decl* of the given type.
333 template <class C>
335 public:
336  bool ValidateCandidate(const TypoCorrection &candidate) override {
337  return candidate.getCorrectionDeclAs<C>();
338  }
339 };
340 
341 // @brief Callback class to limit the allowed keywords and to only accept typo
342 // corrections that are keywords or whose decls refer to functions (or template
343 // functions) that accept the given number of arguments.
345 public:
346  FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
347  bool HasExplicitTemplateArgs,
348  MemberExpr *ME = nullptr);
349 
350  bool ValidateCandidate(const TypoCorrection &candidate) override;
351 
352  private:
353  unsigned NumArgs;
354  bool HasExplicitTemplateArgs;
355  DeclContext *CurContext;
356  MemberExpr *MemberFn;
357 };
358 
359 // @brief Callback class that effectively disabled typo correction
361 public:
363  WantTypeSpecifiers = false;
364  WantExpressionKeywords = false;
365  WantCXXNamedCasts = false;
366  WantFunctionLikeCasts = false;
367  WantRemainingKeywords = false;
368  }
369 
370  bool ValidateCandidate(const TypoCorrection &candidate) override {
371  return false;
372  }
373 };
374 
375 }
376 
377 #endif
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
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:48
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)
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
SmallVectorImpl< NamedDecl * >::const_iterator const_decl_iterator
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:274
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
getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in this declaration name, or NULL if this declaration name isn&#39;t a simple identifier.
CorrectionCandidateCallback(IdentifierInfo *Typo=nullptr, NestedNameSpecifier *TypoNNS=nullptr)
static const unsigned CharDistanceWeight
#define false
Definition: stdbool.h:33
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:1252
NamedDecl * getCorrectionDecl() const
Gets the pointer to the declaration of the typo correction.
DeclarationName - 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...
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:2387
void setCorrectionDecls(ArrayRef< NamedDecl *> Decls)
Clears the list of NamedDecls and adds the given set.
const_decl_iterator begin() const
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
#define true
Definition: stdbool.h:32
TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=nullptr, unsigned CharDistance=0)
A trivial tuple used to represent a source range.
NamedDecl - This represents a decl with a name.
Definition: Decl.h:245
void WillReplaceSpecifier(bool ForceReplacement)
ArrayRef< PartialDiagnostic > getExtraDiagnostics() const