[ASTMatchers] Fix traversal matchers with explicit and defaulted methods

Differential Revision: https://reviews.llvm.org/D94030
This commit is contained in:
Stephen Kelly 2020-12-26 16:22:32 +00:00
parent 3d5b18a3fd
commit 7e4f53f748
4 changed files with 78 additions and 15 deletions

View File

@ -5490,6 +5490,9 @@ AST_MATCHER(FunctionDecl, isVariadic) {
/// \endcode
AST_MATCHER_P(CXXMethodDecl, ofClass,
internal::Matcher<CXXRecordDecl>, InnerMatcher) {
ASTChildrenNotSpelledInSourceScope RAII(Finder, false);
const CXXRecordDecl *Parent = Node.getParent();
return (Parent != nullptr &&
InnerMatcher.matches(*Parent, Finder, Builder));
@ -7037,6 +7040,9 @@ AST_MATCHER_P(FunctionDecl, hasExplicitSpecifier, internal::Matcher<Expr>,
ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(&Node);
if (!ES.getExpr())
return false;
ASTChildrenNotSpelledInSourceScope RAII(Finder, false);
return InnerMatcher.matches(*ES.getExpr(), Finder, Builder);
}

View File

@ -742,6 +742,24 @@ protected:
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) = 0;
private:
friend struct ASTChildrenNotSpelledInSourceScope;
virtual bool isMatchingChildrenNotSpelledInSource() const = 0;
virtual void setMatchingChildrenNotSpelledInSource(bool Set) = 0;
};
struct ASTChildrenNotSpelledInSourceScope {
ASTChildrenNotSpelledInSourceScope(ASTMatchFinder *V, bool B)
: MV(V), MB(V->isMatchingChildrenNotSpelledInSource()) {
V->setMatchingChildrenNotSpelledInSource(B);
}
~ASTChildrenNotSpelledInSourceScope() {
MV->setMatchingChildrenNotSpelledInSource(MB);
}
private:
ASTMatchFinder *MV;
bool MB;
};
/// Specialization of the conversion functions for QualType.

View File

@ -666,6 +666,13 @@ public:
bool IsMatchingInASTNodeNotSpelledInSource() const override {
return TraversingASTNodeNotSpelledInSource;
}
bool isMatchingChildrenNotSpelledInSource() const override {
return TraversingASTChildrenNotSpelledInSource;
}
void setMatchingChildrenNotSpelledInSource(bool Set) override {
TraversingASTChildrenNotSpelledInSource = Set;
}
bool IsMatchingInASTNodeNotAsIs() const override {
return TraversingASTNodeNotAsIs;
}
@ -719,20 +726,6 @@ private:
bool MB;
};
struct ASTChildrenNotSpelledInSource {
ASTChildrenNotSpelledInSource(MatchASTVisitor *V, bool B)
: MV(V), MB(V->TraversingASTChildrenNotSpelledInSource) {
V->TraversingASTChildrenNotSpelledInSource = B;
}
~ASTChildrenNotSpelledInSource() {
MV->TraversingASTChildrenNotSpelledInSource = MB;
}
private:
MatchASTVisitor *MV;
bool MB;
};
class TimeBucketRegion {
public:
TimeBucketRegion() : Bucket(nullptr) {}
@ -1168,7 +1161,7 @@ bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
}
ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
ASTChildrenNotSpelledInSource RAII2(this, ScopedChildren);
ASTChildrenNotSpelledInSourceScope RAII2(this, ScopedChildren);
match(*DeclNode);
return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);

View File

@ -2706,6 +2706,52 @@ void callDefaultArg()
EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
}
Code = R"cpp(
struct A
{
~A();
private:
int i;
};
A::~A() = default;
)cpp";
{
auto M = cxxDestructorDecl(isDefaulted(),
ofClass(cxxRecordDecl(has(fieldDecl()))));
EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
}
Code = R"cpp(
struct S
{
static constexpr bool getTrue() { return true; }
};
struct A
{
explicit(S::getTrue()) A();
};
A::A() = default;
)cpp";
{
EXPECT_TRUE(matchesConditionally(
Code,
traverse(TK_AsIs,
cxxConstructorDecl(
isDefaulted(),
hasExplicitSpecifier(expr(ignoringImplicit(
callExpr(has(ignoringImplicit(declRefExpr())))))))),
true, {"-std=c++20"}));
EXPECT_TRUE(matchesConditionally(
Code,
traverse(TK_IgnoreUnlessSpelledInSource,
cxxConstructorDecl(
isDefaulted(),
hasExplicitSpecifier(callExpr(has(declRefExpr()))))),
true, {"-std=c++20"}));
}
}
template <typename MatcherT>