]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/clang/include/clang/Sema/TypoCorrection.h
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / llvm / tools / clang / include / clang / Sema / TypoCorrection.h
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 "llvm/ADT/SmallVector.h"
21
22 namespace clang {
23
24 /// @brief Simple class containing the result of Sema::CorrectTypo
25 class TypoCorrection {
26 public:
27   // "Distance" for unusable corrections
28   static const unsigned InvalidDistance = ~0U;
29   // The largest distance still considered valid (larger edit distances are
30   // mapped to InvalidDistance by getEditDistance).
31   static const unsigned MaximumDistance = 10000U;
32
33   // Relative weightings of the "edit distance" components. The higher the
34   // weight, the more of a penalty to fitness the component will give (higher
35   // weights mean greater contribution to the total edit distance, with the
36   // best correction candidates having the lowest edit distance).
37   static const unsigned CharDistanceWeight = 100U;
38   static const unsigned QualifierDistanceWeight = 110U;
39   static const unsigned CallbackDistanceWeight = 150U;
40
41   TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
42                  NestedNameSpecifier *NNS = 0, unsigned CharDistance = 0,
43                  unsigned QualifierDistance = 0)
44       : CorrectionName(Name), CorrectionNameSpec(NNS),
45         CharDistance(CharDistance), QualifierDistance(QualifierDistance),
46         CallbackDistance(0), ForceSpecifierReplacement(false),
47         RequiresImport(false) {
48     if (NameDecl)
49       CorrectionDecls.push_back(NameDecl);
50   }
51
52   TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = 0,
53                  unsigned CharDistance = 0)
54       : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
55         CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0),
56         ForceSpecifierReplacement(false), RequiresImport(false) {
57     if (Name)
58       CorrectionDecls.push_back(Name);
59   }
60
61   TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = 0,
62                  unsigned CharDistance = 0)
63       : CorrectionName(Name), CorrectionNameSpec(NNS),
64         CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0),
65         ForceSpecifierReplacement(false), RequiresImport(false) {}
66
67   TypoCorrection()
68       : CorrectionNameSpec(0), CharDistance(0), QualifierDistance(0),
69         CallbackDistance(0), ForceSpecifierReplacement(false),
70         RequiresImport(false) {}
71
72   /// \brief Gets the DeclarationName of the typo correction
73   DeclarationName getCorrection() const { return CorrectionName; }
74   IdentifierInfo* getCorrectionAsIdentifierInfo() const {
75     return CorrectionName.getAsIdentifierInfo();
76   }
77
78   /// \brief Gets the NestedNameSpecifier needed to use the typo correction
79   NestedNameSpecifier* getCorrectionSpecifier() const {
80     return CorrectionNameSpec;
81   }
82   void setCorrectionSpecifier(NestedNameSpecifier* NNS) {
83     CorrectionNameSpec = NNS;
84     ForceSpecifierReplacement = (NNS != 0);
85   }
86
87   void WillReplaceSpecifier(bool ForceReplacement) {
88     ForceSpecifierReplacement = ForceReplacement;
89   }
90
91   bool WillReplaceSpecifier() const {
92     return ForceSpecifierReplacement;
93   }
94
95   void setQualifierDistance(unsigned ED) {
96     QualifierDistance = ED;
97   }
98
99   void setCallbackDistance(unsigned ED) {
100     CallbackDistance = ED;
101   }
102
103   // Convert the given weighted edit distance to a roughly equivalent number of
104   // single-character edits (typically for comparison to the length of the
105   // string being edited).
106   static unsigned NormalizeEditDistance(unsigned ED) {
107     if (ED > MaximumDistance)
108       return InvalidDistance;
109     return (ED + CharDistanceWeight / 2) / CharDistanceWeight;
110   }
111
112   /// \brief Gets the "edit distance" of the typo correction from the typo.
113   /// If Normalized is true, scale the distance down by the CharDistanceWeight
114   /// to return the edit distance in terms of single-character edits.
115   unsigned getEditDistance(bool Normalized = true) const {
116     if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance ||
117         CallbackDistance > MaximumDistance)
118       return InvalidDistance;
119     unsigned ED =
120         CharDistance * CharDistanceWeight +
121         QualifierDistance * QualifierDistanceWeight +
122         CallbackDistance * CallbackDistanceWeight;
123     if (ED > MaximumDistance)
124       return InvalidDistance;
125     // Half the CharDistanceWeight is added to ED to simulate rounding since
126     // integer division truncates the value (i.e. round-to-nearest-int instead
127     // of round-to-zero).
128     return Normalized ? NormalizeEditDistance(ED) : ED;
129   }
130
131   /// \brief Gets the pointer to the declaration of the typo correction
132   NamedDecl *getCorrectionDecl() const {
133     return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : 0;
134   }
135   template <class DeclClass>
136   DeclClass *getCorrectionDeclAs() const {
137     return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
138   }
139
140   /// \brief Clears the list of NamedDecls.
141   void ClearCorrectionDecls() {
142     CorrectionDecls.clear();
143   }
144
145   /// \brief Clears the list of NamedDecls before adding the new one.
146   void setCorrectionDecl(NamedDecl *CDecl) {
147     CorrectionDecls.clear();
148     addCorrectionDecl(CDecl);
149   }
150
151   /// \brief Clears the list of NamedDecls and adds the given set.
152   void setCorrectionDecls(ArrayRef<NamedDecl*> Decls) {
153     CorrectionDecls.clear();
154     CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end());
155   }
156
157   /// \brief Add the given NamedDecl to the list of NamedDecls that are the
158   /// declarations associated with the DeclarationName of this TypoCorrection
159   void addCorrectionDecl(NamedDecl *CDecl);
160
161   std::string getAsString(const LangOptions &LO) const;
162   std::string getQuoted(const LangOptions &LO) const {
163     return "'" + getAsString(LO) + "'";
164   }
165
166   /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName
167   LLVM_EXPLICIT operator bool() const { return bool(CorrectionName); }
168
169   /// \brief Mark this TypoCorrection as being a keyword.
170   /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
171   /// added to the list of the correction's NamedDecl pointers, NULL is added
172   /// as the only element in the list to mark this TypoCorrection as a keyword.
173   void makeKeyword() {
174     CorrectionDecls.clear();
175     CorrectionDecls.push_back(0);
176     ForceSpecifierReplacement = true;
177   }
178
179   // Check if this TypoCorrection is a keyword by checking if the first
180   // item in CorrectionDecls is NULL.
181   bool isKeyword() const {
182     return !CorrectionDecls.empty() &&
183         CorrectionDecls.front() == 0;
184   }
185
186   // Check if this TypoCorrection is the given keyword.
187   template<std::size_t StrLen>
188   bool isKeyword(const char (&Str)[StrLen]) const {
189     return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str);
190   }
191
192   // Returns true if the correction either is a keyword or has a known decl.
193   bool isResolved() const { return !CorrectionDecls.empty(); }
194
195   bool isOverloaded() const {
196     return CorrectionDecls.size() > 1;
197   }
198
199   void setCorrectionRange(CXXScopeSpec *SS,
200                           const DeclarationNameInfo &TypoName) {
201     CorrectionRange.setBegin(ForceSpecifierReplacement && SS && !SS->isEmpty()
202                                  ? SS->getBeginLoc()
203                                  : TypoName.getLoc());
204     CorrectionRange.setEnd(TypoName.getLoc());
205   }
206
207   SourceRange getCorrectionRange() const {
208     return CorrectionRange;
209   }
210
211   typedef SmallVectorImpl<NamedDecl *>::iterator decl_iterator;
212   decl_iterator begin() {
213     return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
214   }
215   decl_iterator end() { return CorrectionDecls.end(); }
216   typedef SmallVectorImpl<NamedDecl *>::const_iterator const_decl_iterator;
217   const_decl_iterator begin() const {
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.
246 class CorrectionCandidateCallback {
247 public:
248   static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
249
250   CorrectionCandidateCallback()
251       : WantTypeSpecifiers(true), WantExpressionKeywords(true),
252         WantCXXNamedCasts(true), WantRemainingKeywords(true),
253         WantObjCSuper(false),
254         IsObjCIvarLookup(false) {}
255
256   virtual ~CorrectionCandidateCallback() {}
257
258   /// \brief Simple predicate used by the default RankCandidate to
259   /// determine whether to return an edit distance of 0 or InvalidDistance.
260   /// This can be overrided by validators that only need to determine if a
261   /// candidate is viable, without ranking potentially viable candidates.
262   /// Only ValidateCandidate or RankCandidate need to be overriden by a
263   /// callback wishing to check the viability of correction candidates.
264   /// The default predicate always returns true if the candidate is not a type
265   /// name or keyword, true for types if WantTypeSpecifiers is true, and true
266   /// for keywords if WantTypeSpecifiers, WantExpressionKeywords,
267   /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true.
268   virtual bool ValidateCandidate(const TypoCorrection &candidate);
269
270   /// \brief Method used by Sema::CorrectTypo to assign an "edit distance" rank
271   /// to a candidate (where a lower value represents a better candidate), or
272   /// returning InvalidDistance if the candidate is not at all viable. For
273   /// validation callbacks that only need to determine if a candidate is viable,
274   /// the default RankCandidate returns either 0 or InvalidDistance depending
275   /// whether ValidateCandidate returns true or false.
276   virtual unsigned RankCandidate(const TypoCorrection &candidate) {
277     return ValidateCandidate(candidate) ? 0 : InvalidDistance;
278   }
279
280   // Flags for context-dependent keywords.
281   // TODO: Expand these to apply to non-keywords or possibly remove them.
282   bool WantTypeSpecifiers;
283   bool WantExpressionKeywords;
284   bool WantCXXNamedCasts;
285   bool WantRemainingKeywords;
286   bool WantObjCSuper;
287   // Temporary hack for the one case where a CorrectTypoContext enum is used
288   // when looking up results.
289   bool IsObjCIvarLookup;
290 };
291
292 /// @brief Simple template class for restricting typo correction candidates
293 /// to ones having a single Decl* of the given type.
294 template <class C>
295 class DeclFilterCCC : public CorrectionCandidateCallback {
296 public:
297   virtual bool ValidateCandidate(const TypoCorrection &candidate) {
298     return candidate.getCorrectionDeclAs<C>();
299   }
300 };
301
302 // @brief Callback class to limit the allowed keywords and to only accept typo
303 // corrections that are keywords or whose decls refer to functions (or template
304 // functions) that accept the given number of arguments.
305 class FunctionCallFilterCCC : public CorrectionCandidateCallback {
306 public:
307   FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
308                         bool HasExplicitTemplateArgs);
309
310   virtual bool ValidateCandidate(const TypoCorrection &candidate);
311
312  private:
313   unsigned NumArgs;
314   bool HasExplicitTemplateArgs;
315 };
316
317 // @brief Callback class that effectively disabled typo correction
318 class NoTypoCorrectionCCC : public CorrectionCandidateCallback {
319 public:
320   NoTypoCorrectionCCC() {
321     WantTypeSpecifiers = false;
322     WantExpressionKeywords = false;
323     WantCXXNamedCasts = false;
324     WantRemainingKeywords = false;
325   }
326
327   virtual bool ValidateCandidate(const TypoCorrection &candidate) {
328     return false;
329   }
330 };
331
332 }
333
334 #endif