clang API Documentation
00001 //===--- TypoCorrection.h - Class for typo correction results ---*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines the TypoCorrection class, which stores the results of 00011 // Sema's typo correction (Sema::CorrectTypo). 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H 00016 #define LLVM_CLANG_SEMA_TYPOCORRECTION_H 00017 00018 #include "clang/AST/DeclCXX.h" 00019 #include "llvm/ADT/SmallVector.h" 00020 00021 namespace clang { 00022 00023 /// @brief Simple class containing the result of Sema::CorrectTypo 00024 class TypoCorrection { 00025 public: 00026 // "Distance" for unusable corrections 00027 static const unsigned InvalidDistance = ~0U; 00028 // The largest distance still considered valid (larger edit distances are 00029 // mapped to InvalidDistance by getEditDistance). 00030 static const unsigned MaximumDistance = 10000U; 00031 00032 // Relative weightings of the "edit distance" components. The higher the 00033 // weight, the more of a penalty to fitness the component will give (higher 00034 // weights mean greater contribution to the total edit distance, with the 00035 // best correction candidates having the lowest edit distance). 00036 static const unsigned CharDistanceWeight = 100U; 00037 static const unsigned QualifierDistanceWeight = 110U; 00038 static const unsigned CallbackDistanceWeight = 150U; 00039 00040 TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, 00041 NestedNameSpecifier *NNS=0, unsigned CharDistance=0, 00042 unsigned QualifierDistance=0) 00043 : CorrectionName(Name), CorrectionNameSpec(NNS), 00044 CharDistance(CharDistance), QualifierDistance(QualifierDistance), 00045 CallbackDistance(0) { 00046 if (NameDecl) 00047 CorrectionDecls.push_back(NameDecl); 00048 } 00049 00050 TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=0, 00051 unsigned CharDistance=0) 00052 : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS), 00053 CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) { 00054 if (Name) 00055 CorrectionDecls.push_back(Name); 00056 } 00057 00058 TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=0, 00059 unsigned CharDistance=0) 00060 : CorrectionName(Name), CorrectionNameSpec(NNS), 00061 CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {} 00062 00063 TypoCorrection() 00064 : CorrectionNameSpec(0), CharDistance(0), QualifierDistance(0), 00065 CallbackDistance(0) {} 00066 00067 /// \brief Gets the DeclarationName of the typo correction 00068 DeclarationName getCorrection() const { return CorrectionName; } 00069 IdentifierInfo* getCorrectionAsIdentifierInfo() const { 00070 return CorrectionName.getAsIdentifierInfo(); 00071 } 00072 00073 /// \brief Gets the NestedNameSpecifier needed to use the typo correction 00074 NestedNameSpecifier* getCorrectionSpecifier() const { 00075 return CorrectionNameSpec; 00076 } 00077 void setCorrectionSpecifier(NestedNameSpecifier* NNS) { 00078 CorrectionNameSpec = NNS; 00079 } 00080 00081 void setQualifierDistance(unsigned ED) { 00082 QualifierDistance = ED; 00083 } 00084 00085 void setCallbackDistance(unsigned ED) { 00086 CallbackDistance = ED; 00087 } 00088 00089 // Convert the given weighted edit distance to a roughly equivalent number of 00090 // single-character edits (typically for comparison to the length of the 00091 // string being edited). 00092 static unsigned NormalizeEditDistance(unsigned ED) { 00093 if (ED > MaximumDistance) 00094 return InvalidDistance; 00095 return (ED + CharDistanceWeight / 2) / CharDistanceWeight; 00096 } 00097 00098 /// \brief Gets the "edit distance" of the typo correction from the typo. 00099 /// If Normalized is true, scale the distance down by the CharDistanceWeight 00100 /// to return the edit distance in terms of single-character edits. 00101 unsigned getEditDistance(bool Normalized = true) const { 00102 if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance || 00103 CallbackDistance > MaximumDistance) 00104 return InvalidDistance; 00105 unsigned ED = 00106 CharDistance * CharDistanceWeight + 00107 QualifierDistance * QualifierDistanceWeight + 00108 CallbackDistance * CallbackDistanceWeight; 00109 if (ED > MaximumDistance) 00110 return InvalidDistance; 00111 // Half the CharDistanceWeight is added to ED to simulate rounding since 00112 // integer division truncates the value (i.e. round-to-nearest-int instead 00113 // of round-to-zero). 00114 return Normalized ? NormalizeEditDistance(ED) : ED; 00115 } 00116 00117 /// \brief Gets the pointer to the declaration of the typo correction 00118 NamedDecl* getCorrectionDecl() const { 00119 return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : 0; 00120 } 00121 template <class DeclClass> 00122 DeclClass *getCorrectionDeclAs() const { 00123 return dyn_cast_or_null<DeclClass>(getCorrectionDecl()); 00124 } 00125 00126 /// \brief Clears the list of NamedDecls before adding the new one. 00127 void setCorrectionDecl(NamedDecl *CDecl) { 00128 CorrectionDecls.clear(); 00129 addCorrectionDecl(CDecl); 00130 } 00131 00132 /// \brief Add the given NamedDecl to the list of NamedDecls that are the 00133 /// declarations associated with the DeclarationName of this TypoCorrection 00134 void addCorrectionDecl(NamedDecl *CDecl); 00135 00136 std::string getAsString(const LangOptions &LO) const; 00137 std::string getQuoted(const LangOptions &LO) const { 00138 return "'" + getAsString(LO) + "'"; 00139 } 00140 00141 /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName 00142 operator bool() const { return bool(CorrectionName); } 00143 00144 /// \brief Mark this TypoCorrection as being a keyword. 00145 /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be 00146 /// added to the list of the correction's NamedDecl pointers, NULL is added 00147 /// as the only element in the list to mark this TypoCorrection as a keyword. 00148 void makeKeyword() { 00149 CorrectionDecls.clear(); 00150 CorrectionDecls.push_back(0); 00151 } 00152 00153 // Check if this TypoCorrection is a keyword by checking if the first 00154 // item in CorrectionDecls is NULL. 00155 bool isKeyword() const { 00156 return !CorrectionDecls.empty() && 00157 CorrectionDecls.front() == 0; 00158 } 00159 00160 // Check if this TypoCorrection is the given keyword. 00161 template<std::size_t StrLen> 00162 bool isKeyword(const char (&Str)[StrLen]) const { 00163 return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str); 00164 } 00165 00166 // Returns true if the correction either is a keyword or has a known decl. 00167 bool isResolved() const { return !CorrectionDecls.empty(); } 00168 00169 bool isOverloaded() const { 00170 return CorrectionDecls.size() > 1; 00171 } 00172 00173 typedef llvm::SmallVector<NamedDecl*, 1>::iterator decl_iterator; 00174 decl_iterator begin() { 00175 return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); 00176 } 00177 decl_iterator end() { return CorrectionDecls.end(); } 00178 typedef llvm::SmallVector<NamedDecl*, 1>::const_iterator const_decl_iterator; 00179 const_decl_iterator begin() const { 00180 return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); 00181 } 00182 const_decl_iterator end() const { return CorrectionDecls.end(); } 00183 00184 private: 00185 bool hasCorrectionDecl() const { 00186 return (!isKeyword() && !CorrectionDecls.empty()); 00187 } 00188 00189 // Results. 00190 DeclarationName CorrectionName; 00191 NestedNameSpecifier *CorrectionNameSpec; 00192 llvm::SmallVector<NamedDecl*, 1> CorrectionDecls; 00193 unsigned CharDistance; 00194 unsigned QualifierDistance; 00195 unsigned CallbackDistance; 00196 }; 00197 00198 /// @brief Base class for callback objects used by Sema::CorrectTypo to check 00199 /// the validity of a potential typo correction. 00200 class CorrectionCandidateCallback { 00201 public: 00202 static const unsigned InvalidDistance = TypoCorrection::InvalidDistance; 00203 00204 CorrectionCandidateCallback() 00205 : WantTypeSpecifiers(true), WantExpressionKeywords(true), 00206 WantCXXNamedCasts(true), WantRemainingKeywords(true), 00207 WantObjCSuper(false), 00208 IsObjCIvarLookup(false) {} 00209 00210 virtual ~CorrectionCandidateCallback() {} 00211 00212 /// \brief Simple predicate used by the default RankCandidate to 00213 /// determine whether to return an edit distance of 0 or InvalidDistance. 00214 /// This can be overrided by validators that only need to determine if a 00215 /// candidate is viable, without ranking potentially viable candidates. 00216 /// Only ValidateCandidate or RankCandidate need to be overriden by a 00217 /// callback wishing to check the viability of correction candidates. 00218 virtual bool ValidateCandidate(const TypoCorrection &candidate) { 00219 return true; 00220 } 00221 00222 /// \brief Method used by Sema::CorrectTypo to assign an "edit distance" rank 00223 /// to a candidate (where a lower value represents a better candidate), or 00224 /// returning InvalidDistance if the candidate is not at all viable. For 00225 /// validation callbacks that only need to determine if a candidate is viable, 00226 /// the default RankCandidate returns either 0 or InvalidDistance depending 00227 /// whether ValidateCandidate returns true or false. 00228 virtual unsigned RankCandidate(const TypoCorrection &candidate) { 00229 return ValidateCandidate(candidate) ? 0 : InvalidDistance; 00230 } 00231 00232 // Flags for context-dependent keywords. 00233 // TODO: Expand these to apply to non-keywords or possibly remove them. 00234 bool WantTypeSpecifiers; 00235 bool WantExpressionKeywords; 00236 bool WantCXXNamedCasts; 00237 bool WantRemainingKeywords; 00238 bool WantObjCSuper; 00239 // Temporary hack for the one case where a CorrectTypoContext enum is used 00240 // when looking up results. 00241 bool IsObjCIvarLookup; 00242 }; 00243 00244 /// @brief Simple template class for restricting typo correction candidates 00245 /// to ones having a single Decl* of the given type. 00246 template <class C> 00247 class DeclFilterCCC : public CorrectionCandidateCallback { 00248 public: 00249 virtual bool ValidateCandidate(const TypoCorrection &candidate) { 00250 return candidate.getCorrectionDeclAs<C>(); 00251 } 00252 }; 00253 00254 } 00255 00256 #endif