aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
diff options
context:
space:
mode:
authorFabian Wolff <fabian.wolff@alumni.ethz.ch>2022-04-21 15:18:31 +0200
committerFabian Wolff <fabian.wolff@alumni.ethz.ch>2022-04-21 15:18:31 +0200
commit95d77383f2ba8d3136856b52520d3f73f9bc89e7 (patch)
tree7c0f992e2c7c0b23b289794ea0cc983cdfe4fb6b /clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
parent96e7487013776c26f0a5203b2e4b104b61efcedf (diff)
downloadllvm-95d77383f2ba8d3136856b52520d3f73f9bc89e7.zip
llvm-95d77383f2ba8d3136856b52520d3f73f9bc89e7.tar.gz
llvm-95d77383f2ba8d3136856b52520d3f73f9bc89e7.tar.bz2
[clang-tidy] Fix behavior of `modernize-use-using` with nested structs/unions
Fixes https://github.com/llvm/llvm-project/issues/50334. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D113804
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp55
1 files changed, 41 insertions, 14 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
index a12a056..fa3cfa5 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp
@@ -16,6 +16,10 @@ namespace clang {
namespace tidy {
namespace modernize {
+static constexpr llvm::StringLiteral ParentDeclName = "parent-decl";
+static constexpr llvm::StringLiteral TagDeclName = "tag-decl";
+static constexpr llvm::StringLiteral TypedefName = "typedef";
+
UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
@@ -25,23 +29,45 @@ void UseUsingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
}
void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
- Finder->addMatcher(typedefDecl(unless(isInstantiated())).bind("typedef"),
+ Finder->addMatcher(typedefDecl(unless(isInstantiated()),
+ hasParent(decl().bind(ParentDeclName)))
+ .bind(TypedefName),
this);
- // This matcher used to find tag declarations in source code within typedefs.
- // They appear in the AST just *prior* to the typedefs.
- Finder->addMatcher(tagDecl(unless(isImplicit())).bind("tagdecl"), this);
+
+ // This matcher is used to find tag declarations in source code within
+ // typedefs. They appear in the AST just *prior* to the typedefs.
+ Finder->addMatcher(
+ tagDecl(
+ anyOf(allOf(unless(anyOf(isImplicit(),
+ classTemplateSpecializationDecl())),
+ hasParent(decl().bind(ParentDeclName))),
+ // We want the parent of the ClassTemplateDecl, not the parent
+ // of the specialization.
+ classTemplateSpecializationDecl(hasAncestor(classTemplateDecl(
+ hasParent(decl().bind(ParentDeclName)))))))
+ .bind(TagDeclName),
+ this);
}
void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *ParentDecl = Result.Nodes.getNodeAs<Decl>(ParentDeclName);
+ if (!ParentDecl)
+ return;
+
// Match CXXRecordDecl only to store the range of the last non-implicit full
// declaration, to later check whether it's within the typdef itself.
- const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>("tagdecl");
+ const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(TagDeclName);
if (MatchedTagDecl) {
- LastTagDeclRange = MatchedTagDecl->getSourceRange();
+ // It is not sufficient to just track the last TagDecl that we've seen,
+ // because if one struct or union is nested inside another, the last TagDecl
+ // before the typedef will be the nested one (PR#50990). Therefore, we also
+ // keep track of the parent declaration, so that we can look up the last
+ // TagDecl that is a sibling of the typedef in the AST.
+ LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange();
return;
}
- const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>("typedef");
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>(TypedefName);
if (MatchedDecl->getLocation().isInvalid())
return;
@@ -102,13 +128,14 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
auto Diag = diag(ReplaceRange.getBegin(), UseUsingWarning);
// If typedef contains a full tag declaration, extract its full text.
- if (LastTagDeclRange.isValid() &&
- ReplaceRange.fullyContains(LastTagDeclRange)) {
- bool Invalid;
- Type = std::string(
- Lexer::getSourceText(CharSourceRange::getTokenRange(LastTagDeclRange),
- *Result.SourceManager, getLangOpts(), &Invalid));
- if (Invalid)
+ auto LastTagDeclRange = LastTagDeclRanges.find(ParentDecl);
+ if (LastTagDeclRange != LastTagDeclRanges.end() &&
+ LastTagDeclRange->second.isValid() &&
+ ReplaceRange.fullyContains(LastTagDeclRange->second)) {
+ Type = std::string(Lexer::getSourceText(
+ CharSourceRange::getTokenRange(LastTagDeclRange->second),
+ *Result.SourceManager, getLangOpts()));
+ if (Type.empty())
return;
}