diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 35efa2ca4aa93..32db3fe5740ed 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -361,6 +361,8 @@ Fixed Point Support in Clang AST Matchers ------------ +- Ensure ``isDerivedFrom`` matches the correct base in case more than one alias exists. + clang-format ------------ diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index 3d01a70395a9b..e9ec7eff1e0ab 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -1287,6 +1287,27 @@ class MatchASTVisitor : public RecursiveASTVisitor, auto Aliases = TypeAliases.find(CanonicalType); if (Aliases == TypeAliases.end()) return false; + + if (const auto *ElaboratedTypeNode = + llvm::dyn_cast(TypeNode)) { + if (ElaboratedTypeNode->isSugared() && Aliases->second.size() > 1) { + const auto &DesugaredTypeName = + ElaboratedTypeNode->desugar().getAsString(); + + for (const TypedefNameDecl *Alias : Aliases->second) { + if (Alias->getName() != DesugaredTypeName) { + continue; + } + + BoundNodesTreeBuilder Result(*Builder); + if (Matcher.matches(*Alias, this, &Result)) { + *Builder = std::move(Result); + return true; + } + } + } + } + for (const TypedefNameDecl *Alias : Aliases->second) { BoundNodesTreeBuilder Result(*Builder); if (Matcher.matches(*Alias, this, &Result)) { diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index 5e1c12ba26d87..4e6baedae2be5 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1167,6 +1167,23 @@ TEST_P(ASTMatchersTest, IsDerivedFrom_EmptyName) { EXPECT_TRUE(notMatches(Code, cxxRecordDecl(isSameOrDerivedFrom("")))); } +TEST_P(ASTMatchersTest, IsDerivedFrom_ElaboratedType) { + if (!GetParam().isCXX()) { + return; + } + + DeclarationMatcher IsDerivenFromBase = + cxxRecordDecl(isDerivedFrom(decl().bind("typedef"))); + + EXPECT_TRUE(matchAndVerifyResultTrue( + "struct AnInterface {};" + "typedef AnInterface UnusedTypedef;" + "typedef AnInterface Base;" + "class AClass : public Base {};", + IsDerivenFromBase, + std::make_unique>("typedef", "Base"))); +} + TEST_P(ASTMatchersTest, IsDerivedFrom_ObjC) { DeclarationMatcher IsDerivedFromX = objcInterfaceDecl(isDerivedFrom("X")); EXPECT_TRUE(