llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Oleksandr T. (a-tarasyuk)

<details>
<summary>Changes</summary>

This patch enhances Clang's diagnosis for unknown attributes by providing typo 
correction suggestions for known attributes.

```cpp
[[gmu::deprected]] // expected-warning {{unknown attribute 'gmu::deprected' 
ignored; did you mean 'gnu::deprecated'?}}
int f1(void) {
  return 0;
}

[[deprected]] // expected-warning {{unknown attribute 'deprected' ignored; did 
you mean 'deprecated'?}}
int f2(void) {
  return 0;
}
```

---

Patch is 30.20 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/140629.diff


20 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+2) 
- (modified) clang/include/clang/Basic/AttributeCommonInfo.h (+5) 
- (modified) clang/include/clang/Basic/Attributes.h (+4) 
- (modified) clang/include/clang/Basic/CMakeLists.txt (+6) 
- (modified) clang/include/clang/Basic/DiagnosticCommonKinds.td (+2) 
- (added) clang/include/clang/Basic/SimpleTypoCorrection.h (+35) 
- (modified) clang/include/clang/Sema/Sema.h (+2) 
- (modified) clang/lib/AST/CommentSema.cpp (+26-71) 
- (modified) clang/lib/Basic/Attributes.cpp (+104-49) 
- (modified) clang/lib/Basic/CMakeLists.txt (+1) 
- (added) clang/lib/Basic/SimpleTypoCorrection.cpp (+52) 
- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+15-3) 
- (modified) clang/lib/Sema/SemaType.cpp (+1-3) 
- (modified) clang/test/Parser/cxx0x-attributes.cpp (+1-1) 
- (modified) clang/test/Sema/attr-c2x.c (+2-2) 
- (modified) clang/test/Sema/unknown-attributes.c (+13-3) 
- (modified) clang/test/SemaCXX/cxx11-gnu-attrs.cpp (+1-1) 
- (modified) clang/utils/TableGen/ClangAttrEmitter.cpp (+27) 
- (modified) clang/utils/TableGen/TableGen.cpp (+6) 
- (modified) clang/utils/TableGen/TableGenBackends.h (+2) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ac9baf229b489..deee00128c1fa 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -561,6 +561,8 @@ Improvements to Clang's diagnostics
 - Fixed a crash when checking a ``__thread``-specified variable declaration
   with a dependent type in C++. (#GH140509)
 
+- Clang now suggests corrections for unknown attribute names.
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h 
b/clang/include/clang/Basic/AttributeCommonInfo.h
index 6db7b53317e7d..b4b8345b4ed40 100644
--- a/clang/include/clang/Basic/AttributeCommonInfo.h
+++ b/clang/include/clang/Basic/AttributeCommonInfo.h
@@ -21,6 +21,8 @@ namespace clang {
 
 class ASTRecordWriter;
 class IdentifierInfo;
+class LangOptions;
+class TargetInfo;
 
 class AttributeCommonInfo {
 public:
@@ -196,6 +198,9 @@ class AttributeCommonInfo {
   /// with surrounding underscores removed as appropriate (e.g.
   /// __gnu__::__attr__ will be normalized to gnu::attr).
   std::string getNormalizedFullName() const;
+  std::optional<std::string>
+  getCorrectedFullName(const TargetInfo &Target,
+                       const LangOptions &LangOpts) const;
   SourceRange getNormalizedRange() const;
 
   bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
diff --git a/clang/include/clang/Basic/Attributes.h 
b/clang/include/clang/Basic/Attributes.h
index 99bb668fe32d0..9cf6fb3d89019 100644
--- a/clang/include/clang/Basic/Attributes.h
+++ b/clang/include/clang/Basic/Attributes.h
@@ -19,6 +19,10 @@ class TargetInfo;
 
 /// Return the version number associated with the attribute if we
 /// recognize and implement the attribute specified by the given information.
+int hasAttribute(AttributeCommonInfo::Syntax Syntax, llvm::StringRef ScopeName,
+                 llvm::StringRef AttrName, const TargetInfo &Target,
+                 const LangOptions &LangOpts, bool CheckPlugins);
+
 int hasAttribute(AttributeCommonInfo::Syntax Syntax,
                  const IdentifierInfo *Scope, const IdentifierInfo *Attr,
                  const TargetInfo &Target, const LangOptions &LangOpts);
diff --git a/clang/include/clang/Basic/CMakeLists.txt 
b/clang/include/clang/Basic/CMakeLists.txt
index 265ea1fc06494..1873878e2e46b 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -79,6 +79,12 @@ clang_tablegen(CXX11AttributeInfo.inc 
-gen-cxx11-attribute-info
   TARGET CXX11AttributeInfo
   )
 
+  clang_tablegen(AttributeSpellingList.inc -gen-attribute-spelling-list
+  -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+  SOURCE Attr.td
+  TARGET AttributeSpellingList
+  )
+
 clang_tablegen(Builtins.inc -gen-clang-builtins
   SOURCE Builtins.td
   TARGET ClangBuiltins)
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td 
b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index e4d94fefbbf3d..0bd8a423c393e 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -181,6 +181,8 @@ def err_opencl_unknown_type_specifier : Error<
 
 def warn_unknown_attribute_ignored : Warning<
   "unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
+def warn_unknown_attribute_ignored_suggestion : Warning<
+  "unknown attribute %0 ignored; did you mean '%1'?">, 
InGroup<UnknownAttributes>;
 def warn_attribute_ignored : Warning<"%0 attribute ignored">,
   InGroup<IgnoredAttributes>;
 def err_keyword_not_supported_on_target : Error<
diff --git a/clang/include/clang/Basic/SimpleTypoCorrection.h 
b/clang/include/clang/Basic/SimpleTypoCorrection.h
new file mode 100644
index 0000000000000..4cd104f79aebe
--- /dev/null
+++ b/clang/include/clang/Basic/SimpleTypoCorrection.h
@@ -0,0 +1,35 @@
+#ifndef LLVM_CLANG_BASIC_SIMPLETYPOCORRECTION_H
+#define LLVM_CLANG_BASIC_SIMPLETYPOCORRECTION_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+
+class IdentifierInfo;
+
+class SimpleTypoCorrection {
+  StringRef BestCandidate;
+  StringRef Typo;
+
+  const unsigned MaxEditDistance;
+  unsigned BestEditDistance;
+  unsigned BestIndex;
+  unsigned NextIndex;
+
+public:
+  explicit SimpleTypoCorrection(StringRef Typo)
+      : BestCandidate(), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
+        BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
+
+  void add(const StringRef Candidate);
+  void add(const char *Candidate);
+  void add(const IdentifierInfo *Candidate);
+
+  std::optional<StringRef> getCorrection() const;
+  bool hasCorrection() const;
+  unsigned getCorrectionIndex() const;
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_BASIC_SIMPLETYPOCORRECTION_H
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5ec67087aeea4..d7a3a81065d33 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5033,6 +5033,8 @@ class Sema final : public SemaBase {
   /// which might be lying around on it.
   void checkUnusedDeclAttributes(Declarator &D);
 
+  void DiagnoseUnknownAttribute(const ParsedAttr &AL);
+
   /// DeclClonePragmaWeak - clone existing decl (maybe definition),
   /// \#pragma weak needs a non-definition decl and source may not have one.
   NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, const IdentifierInfo *II,
diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp
index bd2206bb8a3bc..fb745fc560d2f 100644
--- a/clang/lib/AST/CommentSema.cpp
+++ b/clang/lib/AST/CommentSema.cpp
@@ -13,6 +13,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/Basic/DiagnosticComment.h"
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/SimpleTypoCorrection.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/StringSwitch.h"
@@ -975,69 +976,22 @@ unsigned Sema::resolveParmVarReference(StringRef Name,
   return ParamCommandComment::InvalidParamIndex;
 }
 
-namespace {
-class SimpleTypoCorrector {
-  const NamedDecl *BestDecl;
-
-  StringRef Typo;
-  const unsigned MaxEditDistance;
-
-  unsigned BestEditDistance;
-  unsigned BestIndex;
-  unsigned NextIndex;
-
-public:
-  explicit SimpleTypoCorrector(StringRef Typo)
-      : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
-        BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
-
-  void addDecl(const NamedDecl *ND);
-
-  const NamedDecl *getBestDecl() const {
-    if (BestEditDistance > MaxEditDistance)
-      return nullptr;
-
-    return BestDecl;
-  }
+unsigned
+Sema::correctTypoInParmVarReference(StringRef Typo,
+                                    ArrayRef<const ParmVarDecl *> ParamVars) {
+  SimpleTypoCorrection STC(Typo);
+  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
+    const ParmVarDecl *Param = ParamVars[i];
+    if (!Param)
+      continue;
 
-  unsigned getBestDeclIndex() const {
-    assert(getBestDecl());
-    return BestIndex;
+    STC.add(Param->getIdentifier());
   }
-};
-
-void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
-  unsigned CurrIndex = NextIndex++;
-
-  const IdentifierInfo *II = ND->getIdentifier();
-  if (!II)
-    return;
 
-  StringRef Name = II->getName();
-  unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
-  if (MinPossibleEditDistance > 0 &&
-      Typo.size() / MinPossibleEditDistance < 3)
-    return;
+  if (STC.hasCorrection())
+    return STC.getCorrectionIndex();
 
-  unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
-  if (EditDistance < BestEditDistance) {
-    BestEditDistance = EditDistance;
-    BestDecl = ND;
-    BestIndex = CurrIndex;
-  }
-}
-} // end anonymous namespace
-
-unsigned Sema::correctTypoInParmVarReference(
-                                    StringRef Typo,
-                                    ArrayRef<const ParmVarDecl *> ParamVars) {
-  SimpleTypoCorrector Corrector(Typo);
-  for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
-    Corrector.addDecl(ParamVars[i]);
-  if (Corrector.getBestDecl())
-    return Corrector.getBestDeclIndex();
-  else
-    return ParamCommandComment::InvalidParamIndex;
+  return ParamCommandComment::InvalidParamIndex;
 }
 
 namespace {
@@ -1079,16 +1033,18 @@ bool Sema::resolveTParamReference(
 
 namespace {
 void CorrectTypoInTParamReferenceHelper(
-                            const TemplateParameterList *TemplateParameters,
-                            SimpleTypoCorrector &Corrector) {
+    const TemplateParameterList *TemplateParameters,
+    SimpleTypoCorrection &STC) {
   for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
     const NamedDecl *Param = TemplateParameters->getParam(i);
-    Corrector.addDecl(Param);
+    if (!Param)
+      continue;
+
+    STC.add(Param->getIdentifier());
 
     if (const TemplateTemplateParmDecl *TTP =
             dyn_cast<TemplateTemplateParmDecl>(Param))
-      CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
-                                         Corrector);
+      CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(), STC);
   }
 }
 } // end anonymous namespace
@@ -1096,13 +1052,12 @@ void CorrectTypoInTParamReferenceHelper(
 StringRef Sema::correctTypoInTParamReference(
                             StringRef Typo,
                             const TemplateParameterList *TemplateParameters) {
-  SimpleTypoCorrector Corrector(Typo);
-  CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
-  if (const NamedDecl *ND = Corrector.getBestDecl()) {
-    const IdentifierInfo *II = ND->getIdentifier();
-    assert(II && "SimpleTypoCorrector should not return this decl");
-    return II->getName();
-  }
+  SimpleTypoCorrection STC(Typo);
+  CorrectTypoInTParamReferenceHelper(TemplateParameters, STC);
+
+  if (auto CorrectedTParamReference = STC.getCorrection())
+    return *CorrectedTParamReference;
+
   return StringRef();
 }
 
diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index 8ff5cc54ccc93..0c0a816c78039 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/ParsedAttrInfo.h"
+#include "clang/Basic/SimpleTypoCorrection.h"
 #include "clang/Basic/TargetInfo.h"
 
 #include "llvm/ADT/StringMap.h"
@@ -22,30 +23,37 @@
 
 using namespace clang;
 
-static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name,
-                            StringRef ScopeName, const TargetInfo &Target,
-                            const LangOptions &LangOpts) {
+static StringRef canonicalizeScopeName(StringRef Name) {
+  // Normalize the scope name, but only for gnu and clang attributes.
+  if (Name == "__gnu__")
+    return "gnu";
 
-#include "clang/Basic/AttrHasAttributeImpl.inc"
+  if (Name == "_Clang")
+    return "clang";
 
-  return 0;
+  return Name;
 }
 
-int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
-                        const IdentifierInfo *Scope, const IdentifierInfo 
*Attr,
-                        const TargetInfo &Target, const LangOptions &LangOpts,
-                        bool CheckPlugins) {
-  StringRef Name = Attr->getName();
+static StringRef canonicalizeAttrName(StringRef Name) {
   // Normalize the attribute name, __foo__ becomes foo.
   if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__"))
-    Name = Name.substr(2, Name.size() - 4);
+    return Name.substr(2, Name.size() - 4);
 
-  // Normalize the scope name, but only for gnu and clang attributes.
-  StringRef ScopeName = Scope ? Scope->getName() : "";
-  if (ScopeName == "__gnu__")
-    ScopeName = "gnu";
-  else if (ScopeName == "_Clang")
-    ScopeName = "clang";
+  return Name;
+}
+
+static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name,
+                            StringRef ScopeName, const TargetInfo &Target,
+                            const LangOptions &LangOpts) {
+#include "clang/Basic/AttrHasAttributeImpl.inc"
+  return 0;
+}
+
+int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, StringRef 
ScopeName,
+                        StringRef Name, const TargetInfo &Target,
+                        const LangOptions &LangOpts, bool CheckPlugins) {
+  ScopeName = canonicalizeScopeName(ScopeName);
+  Name = canonicalizeAttrName(Name);
 
   // As a special case, look for the omp::sequence and omp::directive
   // attributes. We support those, but not through the typical attribute
@@ -72,6 +80,14 @@ int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
   return 0;
 }
 
+int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
+                        const IdentifierInfo *Scope, const IdentifierInfo 
*Attr,
+                        const TargetInfo &Target, const LangOptions &LangOpts,
+                        bool CheckPlugins) {
+  return hasAttribute(Syntax, Scope ? Scope->getName() : "", Attr->getName(),
+                      Target, LangOpts, CheckPlugins);
+}
+
 int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
                         const IdentifierInfo *Scope, const IdentifierInfo 
*Attr,
                         const TargetInfo &Target, const LangOptions &LangOpts) 
{
@@ -90,25 +106,25 @@ const char 
*attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
 }
 
 static StringRef
-normalizeAttrScopeName(const IdentifierInfo *Scope,
+normalizeAttrScopeName(StringRef ScopeName,
                        AttributeCommonInfo::Syntax SyntaxUsed) {
-  if (!Scope)
-    return "";
-
-  // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
-  // to be "clang".
-  StringRef ScopeName = Scope->getName();
   if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
-      SyntaxUsed == AttributeCommonInfo::AS_C23) {
-    if (ScopeName == "__gnu__")
-      ScopeName = "gnu";
-    else if (ScopeName == "_Clang")
-      ScopeName = "clang";
-  }
+      SyntaxUsed == AttributeCommonInfo::AS_C23)
+    return canonicalizeScopeName(ScopeName);
+
   return ScopeName;
 }
 
-static StringRef normalizeAttrName(const IdentifierInfo *Name,
+static StringRef
+normalizeAttrScopeName(const IdentifierInfo *ScopeName,
+                       AttributeCommonInfo::Syntax SyntaxUsed) {
+  if (ScopeName)
+    return normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
+
+  return "";
+}
+
+static StringRef normalizeAttrName(StringRef AttrName,
                                    StringRef NormalizedScopeName,
                                    AttributeCommonInfo::Syntax SyntaxUsed) {
   // Normalize the attribute name, __foo__ becomes foo. This is only allowable
@@ -119,10 +135,9 @@ static StringRef normalizeAttrName(const IdentifierInfo 
*Name,
         SyntaxUsed == AttributeCommonInfo::AS_C23) &&
        (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" ||
         NormalizedScopeName == "clang"));
-  StringRef AttrName = Name->getName();
-  if (ShouldNormalize && AttrName.size() >= 4 && AttrName.starts_with("__") &&
-      AttrName.ends_with("__"))
-    AttrName = AttrName.slice(2, AttrName.size() - 2);
+
+  if (ShouldNormalize)
+    return canonicalizeAttrName(AttrName);
 
   return AttrName;
 }
@@ -137,16 +152,11 @@ bool AttributeCommonInfo::isClangScope() const {
 
 #include "clang/Sema/AttrParsedAttrKinds.inc"
 
-static SmallString<64> normalizeName(const IdentifierInfo *Name,
-                                     const IdentifierInfo *Scope,
+static SmallString<64> normalizeName(StringRef AttrName, StringRef ScopeName,
                                      AttributeCommonInfo::Syntax SyntaxUsed) {
-  StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed);
-  StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed);
-
-  std::string StrAttrName = AttrName.str();
-  if (SyntaxUsed == AttributeCommonInfo::AS_HLSLAnnotation)
-    StrAttrName = AttrName.lower();
-
+  std::string StrAttrName = SyntaxUsed == 
AttributeCommonInfo::AS_HLSLAnnotation
+                                ? AttrName.lower()
+                                : AttrName.str();
   SmallString<64> FullName = ScopeName;
   if (!ScopeName.empty()) {
     assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
@@ -154,10 +164,18 @@ static SmallString<64> normalizeName(const IdentifierInfo 
*Name,
     FullName += "::";
   }
   FullName += StrAttrName;
-
   return FullName;
 }
 
+static SmallString<64> normalizeName(const IdentifierInfo *Name,
+                                     const IdentifierInfo *Scope,
+                                     AttributeCommonInfo::Syntax SyntaxUsed) {
+  StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed);
+  StringRef AttrName =
+      normalizeAttrName(Name->getName(), ScopeName, SyntaxUsed);
+  return normalizeName(AttrName, ScopeName, SyntaxUsed);
+}
+
 AttributeCommonInfo::Kind
 AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
                                    const IdentifierInfo *ScopeName,
@@ -167,8 +185,8 @@ AttributeCommonInfo::getParsedKind(const IdentifierInfo 
*Name,
 
 AttributeCommonInfo::AttrArgsInfo
 AttributeCommonInfo::getCXX11AttrArgsInfo(const IdentifierInfo *Name) {
-  StringRef AttrName =
-      normalizeAttrName(Name, /*NormalizedScopeName*/ "", Syntax::AS_CXX11);
+  StringRef AttrName = normalizeAttrName(
+      Name->getName(), /*NormalizedScopeName*/ "", Syntax::AS_CXX11);
 #define CXX11_ATTR_ARGS_INFO
   return llvm::StringSwitch<AttributeCommonInfo::AttrArgsInfo>(AttrName)
 #include "clang/Basic/CXX11AttributeInfo.inc"
@@ -203,10 +221,47 @@ unsigned 
AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
   // attribute spell list index matching code.
   auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
   StringRef ScopeName = normalizeAttrScopeName(getScopeName(), Syntax);
-  StringRef Name = normalizeAttrName(getAttrName(), ScopeName, Syntax);
-
+  StringRef Name =
+      normalizeAttrName(getAttrName()->getName(), ScopeName, Syntax);
   AttributeCommonInfo::Scope ComputedScope =
       getScopeFromNormalizedScopeName(ScopeName);
 
 #include "clang/Sema/AttrSpellingListIndex.inc"
 }
+
+#include "clang/Basic/AttributeSpellingList.inc"
+
+std::optional<std::string>
+AttributeCommonInfo::getCorrectedFullName(const TargetInfo &Target,
+                                          const LangOptions &LangOpts) const {
+  StringRef ScopeName = normalizeAttrScopeName(getScopeName(), getSyntax());
+  if (ScopeName.size() > 0 &&
+      llvm::none_of(AttrScopeSpellingList,
+                    [&](const char *S) { return S == ScopeName; })) {
+    SimpleTypoCorrection STC(ScopeName);
+    for (const auto &Scope : AttrScopeSpellingList)
+      STC.add(Scope);
+
+    if (auto CorrectedScopeName = STC.getCorrection())
+      ScopeName = *CorrectedScopeName;
+  }
+
+  StringRef AttrName =
+      normalizeAttrName(getAttrName()->getName(), ScopeName, getSyntax());
+  if (llvm::none_of(AttrSpellingList,
+                    [&](const char *A) { return A == AttrName; })) {
+    SimpleTypoCorrection STC(AttrName);
+    for (const auto &Attr : AttrSpellingList)
+      STC.add(Attr);
+
+    if (auto CorrectedAttrName = STC.getCorrection())
+      AttrName = *CorrectedAttrName;
+  }
+
+  if (hasAttribute(getSyntax(), ScopeName, AttrName, Target, LangOpts,
+                   /*CheckPlugins=*/true))
+    return static_cast<std::string>(
+        normalizeName(AttrName, ScopeName, getSyntax()));
+
+  return std::nullopt;
+}
diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt
index 0eacf79f5d478..f8a31c890ac4d 100644
--- a/clang/lib/Basic/CMakeLists.txt
+++ b/clang/lib/Basic/CMakeLists.txt
@@ -86,6 +86,7 @@ add_clang_library(clangBasic
   SanitizerSpecialCaseList.cpp
   Sanitizers.cpp
   Sarif.cpp
+  SimpleTypoCorrection.cpp
   SourceLocation.cpp
   SourceManager.cpp
   SourceMgrAdapter.cpp
diff --git a/clang/lib/Basic/SimpleTypoCorrection.cpp 
b/clang/lib/Basic/SimpleTypoCorrection.cpp
new file mode 100644
index 0000000000000..c98b89d9f080d
--- /dev/null
+++ b/clang/lib/Basic/SimpleTypoCorrection.cpp
@@ -0,0 +1,52 @@
+#include "clang/Basic/SimpleTypoCorrection.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang;
+
+void SimpleTypoCorr...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/140629
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to