clang API Documentation

TypoCorrection.h
Go to the documentation of this file.
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