]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/include/clang/Sema/TypoCorrection.h
MFC r244628:
[FreeBSD/stable/9.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 "llvm/ADT/SmallVector.h"
20
21 namespace clang {
22
23 /// @brief Simple class containing the result of Sema::CorrectTypo
24 class TypoCorrection {
25 public:
26   // "Distance" for unusable corrections
27   static const unsigned InvalidDistance = ~0U;
28   // The largest distance still considered valid (larger edit distances are
29   // mapped to InvalidDistance by getEditDistance).
30   static const unsigned MaximumDistance = 10000U;
31
32   // Relative weightings of the "edit distance" components. The higher the
33   // weight, the more of a penalty to fitness the component will give (higher
34   // weights mean greater contribution to the total edit distance, with the
35   // best correction candidates having the lowest edit distance).
36   static const unsigned CharDistanceWeight = 100U;
37   static const unsigned QualifierDistanceWeight = 110U;
38   static const unsigned CallbackDistanceWeight = 150U;
39
40   TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
41                  NestedNameSpecifier *NNS=0, unsigned CharDistance=0,
42                  unsigned QualifierDistance=0)
43       : CorrectionName(Name), CorrectionNameSpec(NNS),
44       CharDistance(CharDistance), QualifierDistance(QualifierDistance),
45       CallbackDistance(0) {
46     if (NameDecl)
47       CorrectionDecls.push_back(NameDecl);
48   }
49
50   TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=0,
51                  unsigned CharDistance=0)
52       : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
53       CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {
54     if (Name)
55       CorrectionDecls.push_back(Name);
56   }
57
58   TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=0,
59                  unsigned CharDistance=0)
60       : CorrectionName(Name), CorrectionNameSpec(NNS),
61       CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {}
62
63   TypoCorrection()
64       : CorrectionNameSpec(0), CharDistance(0), QualifierDistance(0),
65       CallbackDistance(0) {}
66
67   /// \brief Gets the DeclarationName of the typo correction
68   DeclarationName getCorrection() const { return CorrectionName; }
69   IdentifierInfo* getCorrectionAsIdentifierInfo() const {
70     return CorrectionName.getAsIdentifierInfo();
71   }
72
73   /// \brief Gets the NestedNameSpecifier needed to use the typo correction
74   NestedNameSpecifier* getCorrectionSpecifier() const {
75     return CorrectionNameSpec;
76   }
77   void setCorrectionSpecifier(NestedNameSpecifier* NNS) {
78     CorrectionNameSpec = NNS;
79   }
80
81   void setQualifierDistance(unsigned ED) {
82     QualifierDistance = ED;
83   }
84
85   void setCallbackDistance(unsigned ED) {
86     CallbackDistance = ED;
87   }
88
89   // Convert the given weighted edit distance to a roughly equivalent number of
90   // single-character edits (typically for comparison to the length of the
91   // string being edited).
92   static unsigned NormalizeEditDistance(unsigned ED) {
93     if (ED > MaximumDistance)
94       return InvalidDistance;
95     return (ED + CharDistanceWeight / 2) / CharDistanceWeight;
96   }
97
98   /// \brief Gets the "edit distance" of the typo correction from the typo.
99   /// If Normalized is true, scale the distance down by the CharDistanceWeight
100   /// to return the edit distance in terms of single-character edits.
101   unsigned getEditDistance(bool Normalized = true) const {
102     if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance ||
103         CallbackDistance > MaximumDistance)
104       return InvalidDistance;
105     unsigned ED =
106         CharDistance * CharDistanceWeight +
107         QualifierDistance * QualifierDistanceWeight +
108         CallbackDistance * CallbackDistanceWeight;
109     if (ED > MaximumDistance)
110       return InvalidDistance;
111     // Half the CharDistanceWeight is added to ED to simulate rounding since
112     // integer division truncates the value (i.e. round-to-nearest-int instead
113     // of round-to-zero).
114     return Normalized ? NormalizeEditDistance(ED) : ED;
115   }
116
117   /// \brief Gets the pointer to the declaration of the typo correction
118   NamedDecl* getCorrectionDecl() const {
119     return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : 0;
120   }
121   template <class DeclClass>
122   DeclClass *getCorrectionDeclAs() const {
123     return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
124   }
125   
126   /// \brief Clears the list of NamedDecls before adding the new one.
127   void setCorrectionDecl(NamedDecl *CDecl) {
128     CorrectionDecls.clear();
129     addCorrectionDecl(CDecl);
130   }
131
132   /// \brief Add the given NamedDecl to the list of NamedDecls that are the
133   /// declarations associated with the DeclarationName of this TypoCorrection
134   void addCorrectionDecl(NamedDecl *CDecl);
135
136   std::string getAsString(const LangOptions &LO) const;
137   std::string getQuoted(const LangOptions &LO) const {
138     return "'" + getAsString(LO) + "'";
139   }
140
141   /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName
142   operator bool() const { return bool(CorrectionName); }
143
144   /// \brief Mark this TypoCorrection as being a keyword.
145   /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
146   /// added to the list of the correction's NamedDecl pointers, NULL is added
147   /// as the only element in the list to mark this TypoCorrection as a keyword.
148   void makeKeyword() {
149     CorrectionDecls.clear();
150     CorrectionDecls.push_back(0);
151   }
152
153   // Check if this TypoCorrection is a keyword by checking if the first
154   // item in CorrectionDecls is NULL.
155   bool isKeyword() const {
156     return !CorrectionDecls.empty() &&
157         CorrectionDecls.front() == 0;
158   }
159
160   // Check if this TypoCorrection is the given keyword.
161   template<std::size_t StrLen>
162   bool isKeyword(const char (&Str)[StrLen]) const {
163     return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str);
164   }
165
166   // Returns true if the correction either is a keyword or has a known decl.
167   bool isResolved() const { return !CorrectionDecls.empty(); }
168
169   bool isOverloaded() const {
170     return CorrectionDecls.size() > 1;
171   }
172
173   void setCorrectionRange(CXXScopeSpec* SS,
174                           const DeclarationNameInfo &TypoName) {
175     CorrectionRange.setBegin(CorrectionNameSpec && SS ? SS->getBeginLoc()
176                                                       : TypoName.getLoc());
177     CorrectionRange.setEnd(TypoName.getLoc());
178   }
179
180   SourceRange getCorrectionRange() const {
181     return CorrectionRange;
182   }
183
184   typedef llvm::SmallVector<NamedDecl*, 1>::iterator decl_iterator;
185   decl_iterator begin() {
186     return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
187   }
188   decl_iterator end() { return CorrectionDecls.end(); }
189   typedef llvm::SmallVector<NamedDecl*, 1>::const_iterator const_decl_iterator;
190   const_decl_iterator begin() const {
191     return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
192   }
193   const_decl_iterator end() const { return CorrectionDecls.end(); }
194
195 private:
196   bool hasCorrectionDecl() const {
197     return (!isKeyword() && !CorrectionDecls.empty());
198   }
199
200   // Results.
201   DeclarationName CorrectionName;
202   NestedNameSpecifier *CorrectionNameSpec;
203   llvm::SmallVector<NamedDecl*, 1> CorrectionDecls;
204   unsigned CharDistance;
205   unsigned QualifierDistance;
206   unsigned CallbackDistance;
207   SourceRange CorrectionRange;
208 };
209
210 /// @brief Base class for callback objects used by Sema::CorrectTypo to check
211 /// the validity of a potential typo correction.
212 class CorrectionCandidateCallback {
213  public:
214   static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
215
216   CorrectionCandidateCallback()
217       : WantTypeSpecifiers(true), WantExpressionKeywords(true),
218         WantCXXNamedCasts(true), WantRemainingKeywords(true),
219         WantObjCSuper(false),
220         IsObjCIvarLookup(false) {}
221
222   virtual ~CorrectionCandidateCallback() {}
223
224   /// \brief Simple predicate used by the default RankCandidate to
225   /// determine whether to return an edit distance of 0 or InvalidDistance.
226   /// This can be overrided by validators that only need to determine if a
227   /// candidate is viable, without ranking potentially viable candidates.
228   /// Only ValidateCandidate or RankCandidate need to be overriden by a
229   /// callback wishing to check the viability of correction candidates.
230   virtual bool ValidateCandidate(const TypoCorrection &candidate) {
231     return true;
232   }
233
234   /// \brief Method used by Sema::CorrectTypo to assign an "edit distance" rank
235   /// to a candidate (where a lower value represents a better candidate), or
236   /// returning InvalidDistance if the candidate is not at all viable. For
237   /// validation callbacks that only need to determine if a candidate is viable,
238   /// the default RankCandidate returns either 0 or InvalidDistance depending
239   /// whether ValidateCandidate returns true or false.
240   virtual unsigned RankCandidate(const TypoCorrection &candidate) {
241     return ValidateCandidate(candidate) ? 0 : InvalidDistance;
242   }
243
244   // Flags for context-dependent keywords.
245   // TODO: Expand these to apply to non-keywords or possibly remove them.
246   bool WantTypeSpecifiers;
247   bool WantExpressionKeywords;
248   bool WantCXXNamedCasts;
249   bool WantRemainingKeywords;
250   bool WantObjCSuper;
251   // Temporary hack for the one case where a CorrectTypoContext enum is used
252   // when looking up results.
253   bool IsObjCIvarLookup;
254 };
255
256 /// @brief Simple template class for restricting typo correction candidates
257 /// to ones having a single Decl* of the given type.
258 template <class C>
259 class DeclFilterCCC : public CorrectionCandidateCallback {
260  public:
261   virtual bool ValidateCandidate(const TypoCorrection &candidate) {
262     return candidate.getCorrectionDeclAs<C>();
263   }
264 };
265
266 }
267
268 #endif