Skip to content

Commit c1aa5c6

Browse files
committed
[Clang] raise extension warning for unknown namespaced attributes
1 parent deec7fb commit c1aa5c6

File tree

18 files changed

+287
-88
lines changed

18 files changed

+287
-88
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,9 @@ related warnings within the method body.
384384
- Clang now disallows the use of attributes applied before an
385385
``extern template`` declaration (#GH79893).
386386

387+
- Clang now diagnoses unknown attribute namespaces and
388+
provides typo correction for unrecognized namespace and attribute names (#GH120875).
389+
387390
Improvements to Clang's diagnostics
388391
-----------------------------------
389392

clang/include/clang/Basic/AttributeCommonInfo.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616

1717
#include "clang/Basic/SourceLocation.h"
1818
#include "clang/Basic/TokenKinds.h"
19-
2019
namespace clang {
2120

2221
class ASTRecordWriter;
2322
class IdentifierInfo;
23+
class LangOptions;
24+
class TargetInfo;
2425

2526
class AttributeCommonInfo {
2627
public:
@@ -67,7 +68,7 @@ class AttributeCommonInfo {
6768
IgnoredAttribute,
6869
UnknownAttribute,
6970
};
70-
enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, GSL, RISCV };
71+
enum class Scope { NONE, CLANG, GNU, MSVC, OMP, HLSL, GSL, RISCV, UNKNOWN };
7172
enum class AttrArgsInfo {
7273
None,
7374
Optional,
@@ -234,6 +235,12 @@ class AttributeCommonInfo {
234235
return SyntaxUsed == AS_ContextSensitiveKeyword;
235236
}
236237

238+
bool isUnknownScopeName() const;
239+
240+
llvm::StringRef correctScopeTypo() const;
241+
llvm::StringRef correctAttributeTypo(const TargetInfo &Target,
242+
const LangOptions &LangOpts) const;
243+
237244
unsigned getAttributeSpellingListIndex() const {
238245
assert((isAttributeSpellingListCalculated() || AttrName) &&
239246
"Spelling cannot be found");

clang/include/clang/Basic/Attributes.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#define LLVM_CLANG_BASIC_ATTRIBUTES_H
1111

1212
#include "clang/Basic/AttributeCommonInfo.h"
13-
13+
#include "llvm/ADT/StringRef.h"
1414
namespace clang {
1515

1616
class IdentifierInfo;
@@ -19,6 +19,11 @@ class TargetInfo;
1919

2020
/// Return the version number associated with the attribute if we
2121
/// recognize and implement the attribute specified by the given information.
22+
int hasAttribute(AttributeCommonInfo::Syntax Syntax,
23+
const IdentifierInfo *Scope, llvm::StringRef AttrName,
24+
const TargetInfo &Target, const LangOptions &LangOpts,
25+
bool CheckPlugins);
26+
2227
int hasAttribute(AttributeCommonInfo::Syntax Syntax,
2328
const IdentifierInfo *Scope, const IdentifierInfo *Attr,
2429
const TargetInfo &Target, const LangOptions &LangOpts);

clang/include/clang/Basic/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ clang_tablegen(CXX11AttributeInfo.inc -gen-cxx11-attribute-info
7979
TARGET CXX11AttributeInfo
8080
)
8181

82+
clang_tablegen(AttributeSpellingList.inc -gen-attribute-spelling-list
83+
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
84+
SOURCE Attr.td
85+
TARGET AttributeSpellingList
86+
)
87+
8288
clang_tablegen(Builtins.inc -gen-clang-builtins
8389
SOURCE Builtins.td
8490
TARGET ClangBuiltins)

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,16 @@ def err_opencl_unknown_type_specifier : Error<
177177
"%0 does not support the '%1' "
178178
"%select{type qualifier|storage class specifier}2">;
179179

180+
def warn_unknown_attribute_namespace : Warning<
181+
"unknown attribute namespace '%0'; attribute '%0::%1' ignored">,
182+
InGroup<UnknownAttributes>;
183+
def warn_unknown_attribute_namespace_suggestion : Warning<
184+
"unknown attribute namespace '%0'; did you mean '%1'?">,
185+
InGroup<UnknownAttributes>;
180186
def warn_unknown_attribute_ignored : Warning<
181187
"unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
188+
def warn_unknown_attribute_ignored_suggestion : Warning<
189+
"unknown attribute %0 ignored; did you mean '%1'?">, InGroup<UnknownAttributes>;
182190
def warn_attribute_ignored : Warning<"%0 attribute ignored">,
183191
InGroup<IgnoredAttributes>;
184192
def err_keyword_not_supported_on_target : Error<
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef LLVM_CLANG_BASIC_SIMPLETYPOCORRECTOR_H
2+
#define LLVM_CLANG_BASIC_SIMPLETYPOCORRECTOR_H
3+
4+
#include "clang/Basic/LLVM.h"
5+
#include "llvm/ADT/StringRef.h"
6+
7+
namespace clang {
8+
class SimpleTypoCorrector {
9+
StringRef BestCandidate;
10+
StringRef Typo;
11+
12+
const unsigned MaxEditDistance;
13+
unsigned BestEditDistance;
14+
unsigned BestIndex;
15+
unsigned NextIndex;
16+
17+
public:
18+
explicit SimpleTypoCorrector(StringRef Typo)
19+
: BestCandidate(), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
20+
BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
21+
22+
void add(const StringRef Candidate);
23+
void add(const char *Candidate);
24+
25+
bool hasCandidate() const;
26+
StringRef getBestCandidate() const;
27+
unsigned getBestDeclIndex() const;
28+
};
29+
} // namespace clang
30+
31+
#endif // LLVM_CLANG_BASIC_SIMPLETYPOCORRECTOR_H

clang/lib/AST/CommentSema.cpp

Lines changed: 25 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "clang/AST/DeclTemplate.h"
1414
#include "clang/Basic/DiagnosticComment.h"
1515
#include "clang/Basic/LLVM.h"
16+
#include "clang/Basic/SimpleTypoCorrector.h"
1617
#include "clang/Basic/SourceManager.h"
1718
#include "clang/Lex/Preprocessor.h"
1819
#include "llvm/ADT/StringSwitch.h"
@@ -975,69 +976,26 @@ unsigned Sema::resolveParmVarReference(StringRef Name,
975976
return ParamCommandComment::InvalidParamIndex;
976977
}
977978

978-
namespace {
979-
class SimpleTypoCorrector {
980-
const NamedDecl *BestDecl;
981-
982-
StringRef Typo;
983-
const unsigned MaxEditDistance;
984-
985-
unsigned BestEditDistance;
986-
unsigned BestIndex;
987-
unsigned NextIndex;
988-
989-
public:
990-
explicit SimpleTypoCorrector(StringRef Typo)
991-
: BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
992-
BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
993-
994-
void addDecl(const NamedDecl *ND);
995-
996-
const NamedDecl *getBestDecl() const {
997-
if (BestEditDistance > MaxEditDistance)
998-
return nullptr;
999-
1000-
return BestDecl;
1001-
}
1002-
1003-
unsigned getBestDeclIndex() const {
1004-
assert(getBestDecl());
1005-
return BestIndex;
1006-
}
1007-
};
1008-
1009-
void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
1010-
unsigned CurrIndex = NextIndex++;
1011-
1012-
const IdentifierInfo *II = ND->getIdentifier();
1013-
if (!II)
1014-
return;
1015-
1016-
StringRef Name = II->getName();
1017-
unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
1018-
if (MinPossibleEditDistance > 0 &&
1019-
Typo.size() / MinPossibleEditDistance < 3)
1020-
return;
1021-
1022-
unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
1023-
if (EditDistance < BestEditDistance) {
1024-
BestEditDistance = EditDistance;
1025-
BestDecl = ND;
1026-
BestIndex = CurrIndex;
1027-
}
1028-
}
1029-
} // end anonymous namespace
1030-
1031979
unsigned Sema::correctTypoInParmVarReference(
1032980
StringRef Typo,
1033981
ArrayRef<const ParmVarDecl *> ParamVars) {
1034982
SimpleTypoCorrector Corrector(Typo);
1035-
for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
1036-
Corrector.addDecl(ParamVars[i]);
1037-
if (Corrector.getBestDecl())
983+
for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
984+
const ParmVarDecl *Param = ParamVars[i];
985+
if (!Param)
986+
continue;
987+
988+
const IdentifierInfo *II = Param->getIdentifier();
989+
if (!II)
990+
continue;
991+
992+
Corrector.add(II->getName());
993+
}
994+
995+
if (Corrector.hasCandidate())
1038996
return Corrector.getBestDeclIndex();
1039-
else
1040-
return ParamCommandComment::InvalidParamIndex;
997+
998+
return ParamCommandComment::InvalidParamIndex;
1041999
}
10421000

10431001
namespace {
@@ -1083,7 +1041,14 @@ void CorrectTypoInTParamReferenceHelper(
10831041
SimpleTypoCorrector &Corrector) {
10841042
for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
10851043
const NamedDecl *Param = TemplateParameters->getParam(i);
1086-
Corrector.addDecl(Param);
1044+
if (!Param)
1045+
continue;
1046+
1047+
const IdentifierInfo *II = Param->getIdentifier();
1048+
if (!II)
1049+
continue;
1050+
1051+
Corrector.add(II->getName());
10871052

10881053
if (const TemplateTemplateParmDecl *TTP =
10891054
dyn_cast<TemplateTemplateParmDecl>(Param))
@@ -1098,12 +1063,7 @@ StringRef Sema::correctTypoInTParamReference(
10981063
const TemplateParameterList *TemplateParameters) {
10991064
SimpleTypoCorrector Corrector(Typo);
11001065
CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1101-
if (const NamedDecl *ND = Corrector.getBestDecl()) {
1102-
const IdentifierInfo *II = ND->getIdentifier();
1103-
assert(II && "SimpleTypoCorrector should not return this decl");
1104-
return II->getName();
1105-
}
1106-
return StringRef();
1066+
return Corrector.getBestCandidate();
11071067
}
11081068

11091069
InlineCommandRenderKind Sema::getInlineCommandRenderKind(StringRef Name) const {

clang/lib/Basic/Attributes.cpp

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "clang/Basic/IdentifierTable.h"
1616
#include "clang/Basic/LangOptions.h"
1717
#include "clang/Basic/ParsedAttrInfo.h"
18+
#include "clang/Basic/SimpleTypoCorrector.h"
1819
#include "clang/Basic/TargetInfo.h"
1920

2021
#include "llvm/ADT/StringMap.h"
@@ -32,13 +33,13 @@ static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name,
3233
}
3334

3435
int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
35-
const IdentifierInfo *Scope, const IdentifierInfo *Attr,
36+
const IdentifierInfo *Scope, StringRef AttrName,
3637
const TargetInfo &Target, const LangOptions &LangOpts,
3738
bool CheckPlugins) {
38-
StringRef Name = Attr->getName();
3939
// Normalize the attribute name, __foo__ becomes foo.
40-
if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__"))
41-
Name = Name.substr(2, Name.size() - 4);
40+
if (AttrName.size() >= 4 && AttrName.starts_with("__") &&
41+
AttrName.ends_with("__"))
42+
AttrName = AttrName.substr(2, AttrName.size() - 4);
4243

4344
// Normalize the scope name, but only for gnu and clang attributes.
4445
StringRef ScopeName = Scope ? Scope->getName() : "";
@@ -55,23 +56,31 @@ int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
5556
// Other OpenMP attributes (e.g. [[omp::assume]]) are handled via the
5657
// regular attribute parsing machinery.
5758
if (LangOpts.OpenMP && ScopeName == "omp" &&
58-
(Name == "directive" || Name == "sequence"))
59+
(AttrName == "directive" || AttrName == "sequence"))
5960
return 1;
6061

61-
int res = hasAttributeImpl(Syntax, Name, ScopeName, Target, LangOpts);
62+
int res = hasAttributeImpl(Syntax, AttrName, ScopeName, Target, LangOpts);
6263
if (res)
6364
return res;
6465

6566
if (CheckPlugins) {
6667
// Check if any plugin provides this attribute.
6768
for (auto &Ptr : getAttributePluginInstances())
68-
if (Ptr->hasSpelling(Syntax, Name))
69+
if (Ptr->hasSpelling(Syntax, AttrName))
6970
return 1;
7071
}
7172

7273
return 0;
7374
}
7475

76+
int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
77+
const IdentifierInfo *Scope, const IdentifierInfo *Attr,
78+
const TargetInfo &Target, const LangOptions &LangOpts,
79+
bool CheckPlugins) {
80+
return hasAttribute(Syntax, Scope, Attr->getName(), Target, LangOpts,
81+
CheckPlugins);
82+
}
83+
7584
int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
7685
const IdentifierInfo *Scope, const IdentifierInfo *Attr,
7786
const TargetInfo &Target, const LangOptions &LangOpts) {
@@ -191,7 +200,8 @@ getScopeFromNormalizedScopeName(StringRef ScopeName) {
191200
.Case("hlsl", AttributeCommonInfo::Scope::HLSL)
192201
.Case("msvc", AttributeCommonInfo::Scope::MSVC)
193202
.Case("omp", AttributeCommonInfo::Scope::OMP)
194-
.Case("riscv", AttributeCommonInfo::Scope::RISCV);
203+
.Case("riscv", AttributeCommonInfo::Scope::RISCV)
204+
.Default(AttributeCommonInfo::Scope::UNKNOWN);
195205
}
196206

197207
unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
@@ -206,3 +216,35 @@ unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
206216

207217
#include "clang/Sema/AttrSpellingListIndex.inc"
208218
}
219+
220+
bool AttributeCommonInfo::isUnknownScopeName() const {
221+
return getScopeFromNormalizedScopeName(
222+
normalizeAttrScopeName(getScopeName(), getSyntax())) ==
223+
AttributeCommonInfo::Scope::UNKNOWN;
224+
}
225+
226+
#include "clang/Basic/AttributeSpellingList.inc"
227+
228+
StringRef AttributeCommonInfo::correctScopeTypo() const {
229+
SimpleTypoCorrector Corrector(getScopeName()->getName());
230+
231+
for (const auto &ArrtScopeName : AttrScopeSpellingList)
232+
Corrector.add(ArrtScopeName);
233+
234+
return Corrector.getBestCandidate();
235+
}
236+
237+
StringRef
238+
AttributeCommonInfo::correctAttributeTypo(const TargetInfo &Target,
239+
const LangOptions &LangOpts) const {
240+
SimpleTypoCorrector Corrector(getAttrName()->getName());
241+
242+
for (const auto &ArrtName : AttrSpellingList)
243+
Corrector.add(ArrtName);
244+
245+
if (Corrector.hasCandidate() &&
246+
hasAttribute(getSyntax(), getScopeName(), Corrector.getBestCandidate(),
247+
Target, LangOpts, /*CheckPlugins=*/false))
248+
return Corrector.getBestCandidate();
249+
return StringRef();
250+
}

clang/lib/Basic/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ add_clang_library(clangBasic
8686
SanitizerSpecialCaseList.cpp
8787
Sanitizers.cpp
8888
Sarif.cpp
89+
SimpleTypoCorrector.cpp
8990
SourceLocation.cpp
9091
SourceManager.cpp
9192
SourceMgrAdapter.cpp

0 commit comments

Comments
 (0)