- //===- TypoCorrection.h - Class for typo correction results -----*- C++ -*-===// 
- // 
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 
- // See https://llvm.org/LICENSE.txt for license information. 
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 
- // 
- //===----------------------------------------------------------------------===// 
- // 
- // This file defines the TypoCorrection class, which stores the results of 
- // Sema's typo correction (Sema::CorrectTypo). 
- // 
- //===----------------------------------------------------------------------===// 
-   
- #ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H 
- #define LLVM_CLANG_SEMA_TYPOCORRECTION_H 
-   
- #include "clang/AST/Decl.h" 
- #include "clang/AST/DeclarationName.h" 
- #include "clang/Basic/LLVM.h" 
- #include "clang/Basic/PartialDiagnostic.h" 
- #include "clang/Basic/SourceLocation.h" 
- #include "clang/Sema/DeclSpec.h" 
- #include "llvm/ADT/ArrayRef.h" 
- #include "llvm/ADT/SmallVector.h" 
- #include "llvm/Support/Casting.h" 
- #include <cstddef> 
- #include <limits> 
- #include <string> 
- #include <utility> 
- #include <vector> 
-   
- namespace clang { 
-   
- class DeclContext; 
- class IdentifierInfo; 
- class LangOptions; 
- class MemberExpr; 
- class NestedNameSpecifier; 
- class Sema; 
-   
- /// Simple class containing the result of Sema::CorrectTypo 
- class TypoCorrection { 
- public: 
-   // "Distance" for unusable corrections 
-   static const unsigned InvalidDistance = std::numeric_limits<unsigned>::max(); 
-   
-   // The largest distance still considered valid (larger edit distances are 
-   // mapped to InvalidDistance by getEditDistance). 
-   static const unsigned MaximumDistance = 10000U; 
-   
-   // Relative weightings of the "edit distance" components. The higher the 
-   // weight, the more of a penalty to fitness the component will give (higher 
-   // weights mean greater contribution to the total edit distance, with the 
-   // best correction candidates having the lowest edit distance). 
-   static const unsigned CharDistanceWeight = 100U; 
-   static const unsigned QualifierDistanceWeight = 110U; 
-   static const unsigned CallbackDistanceWeight = 150U; 
-   
-   TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, 
-                  NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0, 
-                  unsigned QualifierDistance = 0) 
-       : CorrectionName(Name), CorrectionNameSpec(NNS), 
-         CharDistance(CharDistance), QualifierDistance(QualifierDistance) { 
-     if (NameDecl) 
-       CorrectionDecls.push_back(NameDecl); 
-   } 
-   
-   TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = nullptr, 
-                  unsigned CharDistance = 0) 
-       : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS), 
-         CharDistance(CharDistance) { 
-     if (Name) 
-       CorrectionDecls.push_back(Name); 
-   } 
-   
-   TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = nullptr, 
-                  unsigned CharDistance = 0) 
-       : CorrectionName(Name), CorrectionNameSpec(NNS), 
-         CharDistance(CharDistance) {} 
-   
-   TypoCorrection() = default; 
-   
-   /// Gets the DeclarationName of the typo correction 
-   DeclarationName getCorrection() const { return CorrectionName; } 
-   
-   IdentifierInfo *getCorrectionAsIdentifierInfo() const { 
-     return CorrectionName.getAsIdentifierInfo(); 
-   } 
-   
-   /// Gets the NestedNameSpecifier needed to use the typo correction 
-   NestedNameSpecifier *getCorrectionSpecifier() const { 
-     return CorrectionNameSpec; 
-   } 
-   
-   void setCorrectionSpecifier(NestedNameSpecifier *NNS) { 
-     CorrectionNameSpec = NNS; 
-     ForceSpecifierReplacement = (NNS != nullptr); 
-   } 
-   
-   void WillReplaceSpecifier(bool ForceReplacement) { 
-     ForceSpecifierReplacement = ForceReplacement; 
-   } 
-   
-   bool WillReplaceSpecifier() const { 
-     return ForceSpecifierReplacement; 
-   } 
-   
-   void setQualifierDistance(unsigned ED) { 
-     QualifierDistance = ED; 
-   } 
-   
-   void setCallbackDistance(unsigned ED) { 
-     CallbackDistance = ED; 
-   } 
-   
-   // Convert the given weighted edit distance to a roughly equivalent number of 
-   // single-character edits (typically for comparison to the length of the 
-   // string being edited). 
-   static unsigned NormalizeEditDistance(unsigned ED) { 
-     if (ED > MaximumDistance) 
-       return InvalidDistance; 
-     return (ED + CharDistanceWeight / 2) / CharDistanceWeight; 
-   } 
-   
-   /// Gets the "edit distance" of the typo correction from the typo. 
-   /// If Normalized is true, scale the distance down by the CharDistanceWeight 
-   /// to return the edit distance in terms of single-character edits. 
-   unsigned getEditDistance(bool Normalized = true) const { 
-     if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance || 
-         CallbackDistance > MaximumDistance) 
-       return InvalidDistance; 
-     unsigned ED = 
-         CharDistance * CharDistanceWeight + 
-         QualifierDistance * QualifierDistanceWeight + 
-         CallbackDistance * CallbackDistanceWeight; 
-     if (ED > MaximumDistance) 
-       return InvalidDistance; 
-     // Half the CharDistanceWeight is added to ED to simulate rounding since 
-     // integer division truncates the value (i.e. round-to-nearest-int instead 
-     // of round-to-zero). 
-     return Normalized ? NormalizeEditDistance(ED) : ED; 
-   } 
-   
-   /// Get the correction declaration found by name lookup (before we 
-   /// looked through using shadow declarations and the like). 
-   NamedDecl *getFoundDecl() const { 
-     return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr; 
-   } 
-   
-   /// Gets the pointer to the declaration of the typo correction 
-   NamedDecl *getCorrectionDecl() const { 
-     auto *D = getFoundDecl(); 
-     return D ? D->getUnderlyingDecl() : nullptr; 
-   } 
-   template <class DeclClass> 
-   DeclClass *getCorrectionDeclAs() const { 
-     return dyn_cast_or_null<DeclClass>(getCorrectionDecl()); 
-   } 
-   
-   /// Clears the list of NamedDecls. 
-   void ClearCorrectionDecls() { 
-     CorrectionDecls.clear(); 
-   } 
-   
-   /// Clears the list of NamedDecls before adding the new one. 
-   void setCorrectionDecl(NamedDecl *CDecl) { 
-     CorrectionDecls.clear(); 
-     addCorrectionDecl(CDecl); 
-   } 
-   
-   /// Clears the list of NamedDecls and adds the given set. 
-   void setCorrectionDecls(ArrayRef<NamedDecl*> Decls) { 
-     CorrectionDecls.clear(); 
-     CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end()); 
-   } 
-   
-   /// Add the given NamedDecl to the list of NamedDecls that are the 
-   /// declarations associated with the DeclarationName of this TypoCorrection 
-   void addCorrectionDecl(NamedDecl *CDecl); 
-   
-   std::string getAsString(const LangOptions &LO) const; 
-   
-   std::string getQuoted(const LangOptions &LO) const { 
-     return "'" + getAsString(LO) + "'"; 
-   } 
-   
-   /// Returns whether this TypoCorrection has a non-empty DeclarationName 
-   explicit operator bool() const { return bool(CorrectionName); } 
-   
-   /// Mark this TypoCorrection as being a keyword. 
-   /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be 
-   /// added to the list of the correction's NamedDecl pointers, NULL is added 
-   /// as the only element in the list to mark this TypoCorrection as a keyword. 
-   void makeKeyword() { 
-     CorrectionDecls.clear(); 
-     CorrectionDecls.push_back(nullptr); 
-     ForceSpecifierReplacement = true; 
-   } 
-   
-   // Check if this TypoCorrection is a keyword by checking if the first 
-   // item in CorrectionDecls is NULL. 
-   bool isKeyword() const { 
-     return !CorrectionDecls.empty() && CorrectionDecls.front() == nullptr; 
-   } 
-   
-   // Check if this TypoCorrection is the given keyword. 
-   template<std::size_t StrLen> 
-   bool isKeyword(const char (&Str)[StrLen]) const { 
-     return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str); 
-   } 
-   
-   // Returns true if the correction either is a keyword or has a known decl. 
-   bool isResolved() const { return !CorrectionDecls.empty(); } 
-   
-   bool isOverloaded() const { 
-     return CorrectionDecls.size() > 1; 
-   } 
-   
-   void setCorrectionRange(CXXScopeSpec *SS, 
-                           const DeclarationNameInfo &TypoName) { 
-     CorrectionRange = TypoName.getSourceRange(); 
-     if (ForceSpecifierReplacement && SS && !SS->isEmpty()) 
-       CorrectionRange.setBegin(SS->getBeginLoc()); 
-   } 
-   
-   SourceRange getCorrectionRange() const { 
-     return CorrectionRange; 
-   } 
-   
-   using decl_iterator = SmallVectorImpl<NamedDecl *>::iterator; 
-   
-   decl_iterator begin() { 
-     return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); 
-   } 
-   
-   decl_iterator end() { return CorrectionDecls.end(); } 
-   
-   using const_decl_iterator = SmallVectorImpl<NamedDecl *>::const_iterator; 
-   
-   const_decl_iterator begin() const { 
-     return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); 
-   } 
-   
-   const_decl_iterator end() const { return CorrectionDecls.end(); } 
-   
-   /// Returns whether this typo correction is correcting to a 
-   /// declaration that was declared in a module that has not been imported. 
-   bool requiresImport() const { return RequiresImport; } 
-   void setRequiresImport(bool Req) { RequiresImport = Req; } 
-   
-   /// Extra diagnostics are printed after the first diagnostic for the typo. 
-   /// This can be used to attach external notes to the diag. 
-   void addExtraDiagnostic(PartialDiagnostic PD) { 
-     ExtraDiagnostics.push_back(std::move(PD)); 
-   } 
-   ArrayRef<PartialDiagnostic> getExtraDiagnostics() const { 
-     return ExtraDiagnostics; 
-   } 
-   
- private: 
-   bool hasCorrectionDecl() const { 
-     return (!isKeyword() && !CorrectionDecls.empty()); 
-   } 
-   
-   // Results. 
-   DeclarationName CorrectionName; 
-   NestedNameSpecifier *CorrectionNameSpec = nullptr; 
-   SmallVector<NamedDecl *, 1> CorrectionDecls; 
-   unsigned CharDistance = 0; 
-   unsigned QualifierDistance = 0; 
-   unsigned CallbackDistance = 0; 
-   SourceRange CorrectionRange; 
-   bool ForceSpecifierReplacement = false; 
-   bool RequiresImport = false; 
-   
-   std::vector<PartialDiagnostic> ExtraDiagnostics; 
- }; 
-   
- /// Base class for callback objects used by Sema::CorrectTypo to check 
- /// the validity of a potential typo correction. 
- class CorrectionCandidateCallback { 
- public: 
-   static const unsigned InvalidDistance = TypoCorrection::InvalidDistance; 
-   
-   explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr, 
-                                        NestedNameSpecifier *TypoNNS = nullptr) 
-       : Typo(Typo), TypoNNS(TypoNNS) {} 
-   
-   virtual ~CorrectionCandidateCallback() = default; 
-   
-   /// Simple predicate used by the default RankCandidate to 
-   /// determine whether to return an edit distance of 0 or InvalidDistance. 
-   /// This can be overridden by validators that only need to determine if a 
-   /// candidate is viable, without ranking potentially viable candidates. 
-   /// Only ValidateCandidate or RankCandidate need to be overridden by a 
-   /// callback wishing to check the viability of correction candidates. 
-   /// The default predicate always returns true if the candidate is not a type 
-   /// name or keyword, true for types if WantTypeSpecifiers is true, and true 
-   /// for keywords if WantTypeSpecifiers, WantExpressionKeywords, 
-   /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true. 
-   virtual bool ValidateCandidate(const TypoCorrection &candidate); 
-   
-   /// Method used by Sema::CorrectTypo to assign an "edit distance" rank 
-   /// to a candidate (where a lower value represents a better candidate), or 
-   /// returning InvalidDistance if the candidate is not at all viable. For 
-   /// validation callbacks that only need to determine if a candidate is viable, 
-   /// the default RankCandidate returns either 0 or InvalidDistance depending 
-   /// whether ValidateCandidate returns true or false. 
-   virtual unsigned RankCandidate(const TypoCorrection &candidate) { 
-     return (!MatchesTypo(candidate) && ValidateCandidate(candidate)) 
-                ? 0 
-                : InvalidDistance; 
-   } 
-   
-   /// Clone this CorrectionCandidateCallback. CorrectionCandidateCallbacks are 
-   /// initially stack-allocated. However in case where delayed typo-correction 
-   /// is done we need to move the callback to storage with a longer lifetime. 
-   /// Every class deriving from CorrectionCandidateCallback must implement 
-   /// this method. 
-   virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0; 
-   
-   void setTypoName(IdentifierInfo *II) { Typo = II; } 
-   void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; } 
-   
-   // Flags for context-dependent keywords. WantFunctionLikeCasts is only 
-   // used/meaningful when WantCXXNamedCasts is false. 
-   // TODO: Expand these to apply to non-keywords or possibly remove them. 
-   bool WantTypeSpecifiers = true; 
-   bool WantExpressionKeywords = true; 
-   bool WantCXXNamedCasts = true; 
-   bool WantFunctionLikeCasts = true; 
-   bool WantRemainingKeywords = true; 
-   bool WantObjCSuper = false; 
-   // Temporary hack for the one case where a CorrectTypoContext enum is used 
-   // when looking up results. 
-   bool IsObjCIvarLookup = false; 
-   bool IsAddressOfOperand = false; 
-   
- protected: 
-   bool MatchesTypo(const TypoCorrection &candidate) { 
-     return Typo && candidate.isResolved() && !candidate.requiresImport() && 
-            candidate.getCorrectionAsIdentifierInfo() == Typo && 
-            // FIXME: This probably does not return true when both 
-            // NestedNameSpecifiers have the same textual representation. 
-            candidate.getCorrectionSpecifier() == TypoNNS; 
-   } 
-   
-   IdentifierInfo *Typo; 
-   NestedNameSpecifier *TypoNNS; 
- }; 
-   
- class DefaultFilterCCC final : public CorrectionCandidateCallback { 
- public: 
-   explicit DefaultFilterCCC(IdentifierInfo *Typo = nullptr, 
-                             NestedNameSpecifier *TypoNNS = nullptr) 
-       : CorrectionCandidateCallback(Typo, TypoNNS) {} 
-   
-   std::unique_ptr<CorrectionCandidateCallback> clone() override { 
-     return std::make_unique<DefaultFilterCCC>(*this); 
-   } 
- }; 
-   
- /// Simple template class for restricting typo correction candidates 
- /// to ones having a single Decl* of the given type. 
- template <class C> 
- class DeclFilterCCC final : public CorrectionCandidateCallback { 
- public: 
-   bool ValidateCandidate(const TypoCorrection &candidate) override { 
-     return candidate.getCorrectionDeclAs<C>(); 
-   } 
-   std::unique_ptr<CorrectionCandidateCallback> clone() override { 
-     return std::make_unique<DeclFilterCCC>(*this); 
-   } 
- }; 
-   
- // Callback class to limit the allowed keywords and to only accept typo 
- // corrections that are keywords or whose decls refer to functions (or template 
- // functions) that accept the given number of arguments. 
- class FunctionCallFilterCCC : public CorrectionCandidateCallback { 
- public: 
-   FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, 
-                         bool HasExplicitTemplateArgs, 
-                         MemberExpr *ME = nullptr); 
-   
-   bool ValidateCandidate(const TypoCorrection &candidate) override; 
-   std::unique_ptr<CorrectionCandidateCallback> clone() override { 
-     return std::make_unique<FunctionCallFilterCCC>(*this); 
-   } 
-   
- private: 
-   unsigned NumArgs; 
-   bool HasExplicitTemplateArgs; 
-   DeclContext *CurContext; 
-   MemberExpr *MemberFn; 
- }; 
-   
- // Callback class that effectively disabled typo correction 
- class NoTypoCorrectionCCC final : public CorrectionCandidateCallback { 
- public: 
-   NoTypoCorrectionCCC() { 
-     WantTypeSpecifiers = false; 
-     WantExpressionKeywords = false; 
-     WantCXXNamedCasts = false; 
-     WantFunctionLikeCasts = false; 
-     WantRemainingKeywords = false; 
-   } 
-   
-   bool ValidateCandidate(const TypoCorrection &candidate) override { 
-     return false; 
-   } 
-   std::unique_ptr<CorrectionCandidateCallback> clone() override { 
-     return std::make_unique<NoTypoCorrectionCCC>(*this); 
-   } 
- }; 
-   
- } // namespace clang 
-   
- #endif // LLVM_CLANG_SEMA_TYPOCORRECTION_H 
-