File indexing completed on 2026-05-10 08:37:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H
0015 #define LLVM_CLANG_SEMA_TYPOCORRECTION_H
0016
0017 #include "clang/AST/Decl.h"
0018 #include "clang/AST/DeclarationName.h"
0019 #include "clang/Basic/LLVM.h"
0020 #include "clang/Basic/PartialDiagnostic.h"
0021 #include "clang/Basic/SourceLocation.h"
0022 #include "clang/Sema/DeclSpec.h"
0023 #include "llvm/ADT/ArrayRef.h"
0024 #include "llvm/ADT/SmallVector.h"
0025 #include "llvm/Support/Casting.h"
0026 #include <cstddef>
0027 #include <limits>
0028 #include <string>
0029 #include <utility>
0030 #include <vector>
0031
0032 namespace clang {
0033
0034 class DeclContext;
0035 class IdentifierInfo;
0036 class LangOptions;
0037 class MemberExpr;
0038 class NestedNameSpecifier;
0039 class Sema;
0040
0041
0042 class TypoCorrection {
0043 public:
0044
0045 static const unsigned InvalidDistance = std::numeric_limits<unsigned>::max();
0046
0047
0048
0049 static const unsigned MaximumDistance = 10000U;
0050
0051
0052
0053
0054
0055 static const unsigned CharDistanceWeight = 100U;
0056 static const unsigned QualifierDistanceWeight = 110U;
0057 static const unsigned CallbackDistanceWeight = 150U;
0058
0059 TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
0060 NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0,
0061 unsigned QualifierDistance = 0)
0062 : CorrectionName(Name), CorrectionNameSpec(NNS),
0063 CharDistance(CharDistance), QualifierDistance(QualifierDistance) {
0064 if (NameDecl)
0065 CorrectionDecls.push_back(NameDecl);
0066 }
0067
0068 TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = nullptr,
0069 unsigned CharDistance = 0)
0070 : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
0071 CharDistance(CharDistance) {
0072 if (Name)
0073 CorrectionDecls.push_back(Name);
0074 }
0075
0076 TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = nullptr,
0077 unsigned CharDistance = 0)
0078 : CorrectionName(Name), CorrectionNameSpec(NNS),
0079 CharDistance(CharDistance) {}
0080
0081 TypoCorrection() = default;
0082
0083
0084 DeclarationName getCorrection() const { return CorrectionName; }
0085
0086 IdentifierInfo *getCorrectionAsIdentifierInfo() const {
0087 return CorrectionName.getAsIdentifierInfo();
0088 }
0089
0090
0091 NestedNameSpecifier *getCorrectionSpecifier() const {
0092 return CorrectionNameSpec;
0093 }
0094
0095 void setCorrectionSpecifier(NestedNameSpecifier *NNS) {
0096 CorrectionNameSpec = NNS;
0097 ForceSpecifierReplacement = (NNS != nullptr);
0098 }
0099
0100 void WillReplaceSpecifier(bool ForceReplacement) {
0101 ForceSpecifierReplacement = ForceReplacement;
0102 }
0103
0104 bool WillReplaceSpecifier() const {
0105 return ForceSpecifierReplacement;
0106 }
0107
0108 void setQualifierDistance(unsigned ED) {
0109 QualifierDistance = ED;
0110 }
0111
0112 void setCallbackDistance(unsigned ED) {
0113 CallbackDistance = ED;
0114 }
0115
0116
0117
0118
0119 static unsigned NormalizeEditDistance(unsigned ED) {
0120 if (ED > MaximumDistance)
0121 return InvalidDistance;
0122 return (ED + CharDistanceWeight / 2) / CharDistanceWeight;
0123 }
0124
0125
0126
0127
0128 unsigned getEditDistance(bool Normalized = true) const {
0129 if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance ||
0130 CallbackDistance > MaximumDistance)
0131 return InvalidDistance;
0132 unsigned ED =
0133 CharDistance * CharDistanceWeight +
0134 QualifierDistance * QualifierDistanceWeight +
0135 CallbackDistance * CallbackDistanceWeight;
0136 if (ED > MaximumDistance)
0137 return InvalidDistance;
0138
0139
0140
0141 return Normalized ? NormalizeEditDistance(ED) : ED;
0142 }
0143
0144
0145
0146 NamedDecl *getFoundDecl() const {
0147 return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr;
0148 }
0149
0150
0151 NamedDecl *getCorrectionDecl() const {
0152 auto *D = getFoundDecl();
0153 return D ? D->getUnderlyingDecl() : nullptr;
0154 }
0155 template <class DeclClass>
0156 DeclClass *getCorrectionDeclAs() const {
0157 return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
0158 }
0159
0160
0161 void ClearCorrectionDecls() {
0162 CorrectionDecls.clear();
0163 }
0164
0165
0166 void setCorrectionDecl(NamedDecl *CDecl) {
0167 CorrectionDecls.clear();
0168 addCorrectionDecl(CDecl);
0169 }
0170
0171
0172 void setCorrectionDecls(ArrayRef<NamedDecl*> Decls) {
0173 CorrectionDecls.clear();
0174 CorrectionDecls.insert(CorrectionDecls.begin(), Decls.begin(), Decls.end());
0175 }
0176
0177
0178
0179 void addCorrectionDecl(NamedDecl *CDecl);
0180
0181 std::string getAsString(const LangOptions &LO) const;
0182
0183 std::string getQuoted(const LangOptions &LO) const {
0184 return "'" + getAsString(LO) + "'";
0185 }
0186
0187
0188 explicit operator bool() const { return bool(CorrectionName); }
0189
0190
0191
0192
0193
0194 void makeKeyword() {
0195 CorrectionDecls.clear();
0196 CorrectionDecls.push_back(nullptr);
0197 ForceSpecifierReplacement = true;
0198 }
0199
0200
0201
0202 bool isKeyword() const {
0203 return !CorrectionDecls.empty() && CorrectionDecls.front() == nullptr;
0204 }
0205
0206
0207 template<std::size_t StrLen>
0208 bool isKeyword(const char (&Str)[StrLen]) const {
0209 return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str);
0210 }
0211
0212
0213 bool isResolved() const { return !CorrectionDecls.empty(); }
0214
0215 bool isOverloaded() const {
0216 return CorrectionDecls.size() > 1;
0217 }
0218
0219 void setCorrectionRange(CXXScopeSpec *SS,
0220 const DeclarationNameInfo &TypoName) {
0221 CorrectionRange = TypoName.getSourceRange();
0222 if (ForceSpecifierReplacement && SS && !SS->isEmpty())
0223 CorrectionRange.setBegin(SS->getBeginLoc());
0224 }
0225
0226 SourceRange getCorrectionRange() const {
0227 return CorrectionRange;
0228 }
0229
0230 using decl_iterator = SmallVectorImpl<NamedDecl *>::iterator;
0231
0232 decl_iterator begin() {
0233 return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
0234 }
0235
0236 decl_iterator end() { return CorrectionDecls.end(); }
0237
0238 using const_decl_iterator = SmallVectorImpl<NamedDecl *>::const_iterator;
0239
0240 const_decl_iterator begin() const {
0241 return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
0242 }
0243
0244 const_decl_iterator end() const { return CorrectionDecls.end(); }
0245
0246
0247
0248 bool requiresImport() const { return RequiresImport; }
0249 void setRequiresImport(bool Req) { RequiresImport = Req; }
0250
0251
0252
0253 void addExtraDiagnostic(PartialDiagnostic PD) {
0254 ExtraDiagnostics.push_back(std::move(PD));
0255 }
0256 ArrayRef<PartialDiagnostic> getExtraDiagnostics() const {
0257 return ExtraDiagnostics;
0258 }
0259
0260 private:
0261 bool hasCorrectionDecl() const {
0262 return (!isKeyword() && !CorrectionDecls.empty());
0263 }
0264
0265
0266 DeclarationName CorrectionName;
0267 NestedNameSpecifier *CorrectionNameSpec = nullptr;
0268 SmallVector<NamedDecl *, 1> CorrectionDecls;
0269 unsigned CharDistance = 0;
0270 unsigned QualifierDistance = 0;
0271 unsigned CallbackDistance = 0;
0272 SourceRange CorrectionRange;
0273 bool ForceSpecifierReplacement = false;
0274 bool RequiresImport = false;
0275
0276 std::vector<PartialDiagnostic> ExtraDiagnostics;
0277 };
0278
0279
0280
0281 class CorrectionCandidateCallback {
0282 public:
0283 static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
0284
0285 explicit CorrectionCandidateCallback(const IdentifierInfo *Typo = nullptr,
0286 NestedNameSpecifier *TypoNNS = nullptr)
0287 : Typo(Typo), TypoNNS(TypoNNS) {}
0288
0289 virtual ~CorrectionCandidateCallback() = default;
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301 virtual bool ValidateCandidate(const TypoCorrection &candidate);
0302
0303
0304
0305
0306
0307
0308
0309 virtual unsigned RankCandidate(const TypoCorrection &candidate) {
0310 return (!MatchesTypo(candidate) && ValidateCandidate(candidate))
0311 ? 0
0312 : InvalidDistance;
0313 }
0314
0315
0316
0317
0318
0319
0320 virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0;
0321
0322 void setTypoName(const IdentifierInfo *II) { Typo = II; }
0323 void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
0324
0325
0326
0327
0328 bool WantTypeSpecifiers = true;
0329 bool WantExpressionKeywords = true;
0330 bool WantCXXNamedCasts = true;
0331 bool WantFunctionLikeCasts = true;
0332 bool WantRemainingKeywords = true;
0333 bool WantObjCSuper = false;
0334
0335
0336 bool IsObjCIvarLookup = false;
0337 bool IsAddressOfOperand = false;
0338
0339 protected:
0340 bool MatchesTypo(const TypoCorrection &candidate) {
0341 return Typo && candidate.isResolved() && !candidate.requiresImport() &&
0342 candidate.getCorrectionAsIdentifierInfo() == Typo &&
0343
0344
0345 candidate.getCorrectionSpecifier() == TypoNNS;
0346 }
0347
0348 const IdentifierInfo *Typo;
0349 NestedNameSpecifier *TypoNNS;
0350 };
0351
0352 class DefaultFilterCCC final : public CorrectionCandidateCallback {
0353 public:
0354 explicit DefaultFilterCCC(const IdentifierInfo *Typo = nullptr,
0355 NestedNameSpecifier *TypoNNS = nullptr)
0356 : CorrectionCandidateCallback(Typo, TypoNNS) {}
0357
0358 std::unique_ptr<CorrectionCandidateCallback> clone() override {
0359 return std::make_unique<DefaultFilterCCC>(*this);
0360 }
0361 };
0362
0363
0364
0365 template <class C>
0366 class DeclFilterCCC final : public CorrectionCandidateCallback {
0367 public:
0368 explicit DeclFilterCCC(const IdentifierInfo *Typo = nullptr,
0369 NestedNameSpecifier *TypoNNS = nullptr)
0370 : CorrectionCandidateCallback(Typo, TypoNNS) {}
0371
0372 bool ValidateCandidate(const TypoCorrection &candidate) override {
0373 return candidate.getCorrectionDeclAs<C>();
0374 }
0375 std::unique_ptr<CorrectionCandidateCallback> clone() override {
0376 return std::make_unique<DeclFilterCCC>(*this);
0377 }
0378 };
0379
0380
0381
0382
0383 class FunctionCallFilterCCC : public CorrectionCandidateCallback {
0384 public:
0385 FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
0386 bool HasExplicitTemplateArgs,
0387 MemberExpr *ME = nullptr);
0388
0389 bool ValidateCandidate(const TypoCorrection &candidate) override;
0390 std::unique_ptr<CorrectionCandidateCallback> clone() override {
0391 return std::make_unique<FunctionCallFilterCCC>(*this);
0392 }
0393
0394 private:
0395 unsigned NumArgs;
0396 bool HasExplicitTemplateArgs;
0397 DeclContext *CurContext;
0398 MemberExpr *MemberFn;
0399 };
0400
0401
0402 class NoTypoCorrectionCCC final : public CorrectionCandidateCallback {
0403 public:
0404 NoTypoCorrectionCCC() {
0405 WantTypeSpecifiers = false;
0406 WantExpressionKeywords = false;
0407 WantCXXNamedCasts = false;
0408 WantFunctionLikeCasts = false;
0409 WantRemainingKeywords = false;
0410 }
0411
0412 bool ValidateCandidate(const TypoCorrection &candidate) override {
0413 return false;
0414 }
0415 std::unique_ptr<CorrectionCandidateCallback> clone() override {
0416 return std::make_unique<NoTypoCorrectionCCC>(*this);
0417 }
0418 };
0419
0420 }
0421
0422 #endif