steveire created this revision.
steveire added a reviewer: aaron.ballman.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
steveire requested review of this revision.
Don't match Stmt or Decl nodes not spelled in the source when using
TK_IgnoreUnlessSpelledInSource. This prevents accidental modification
of source code at incorrect locations.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D90984
Files:
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/include/clang/ASTMatchers/ASTMatchersInternal.h
clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -2393,6 +2393,34 @@
M = cxxRecordDecl(hasName("NoSpecialMethods"), has(cxxDestructorDecl()));
EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+
+ M = cxxRecordDecl(hasName("NoSpecialMethods"),
+ hasMethod(cxxConstructorDecl(isCopyConstructor())));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+
+ M = cxxRecordDecl(hasName("NoSpecialMethods"),
+ hasMethod(cxxMethodDecl(isCopyAssignmentOperator())));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+
+ M = cxxRecordDecl(hasName("NoSpecialMethods"),
+ hasMethod(cxxConstructorDecl(isDefaultConstructor())));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+
+ M = cxxRecordDecl(hasName("NoSpecialMethods"),
+ hasMethod(cxxDestructorDecl()));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+ }
+ {
+ // Because the copy-assignment operator is not spelled in the
+ // source (ie, isImplicit()), we don't match it
+ auto M = cxxOperatorCallExpr(
+ callee(cxxMethodDecl(isCopyAssignmentOperator()).bind("callTarget")));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
}
{
// Compiler generates a forStmt to copy the array
@@ -2414,6 +2442,24 @@
EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MDef)));
EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MDef)));
+ auto MBody = cxxMethodDecl(MDecl, hasBody(compoundStmt()));
+
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MBody)));
+ EXPECT_FALSE(
+ matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MBody)));
+
+ auto MIsDefn = cxxMethodDecl(MDecl, isDefinition());
+
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MIsDefn)));
+ EXPECT_FALSE(
+ matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MIsDefn)));
+
+ auto MIsInline = cxxMethodDecl(MDecl, isInline());
+
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, MIsInline)));
+ EXPECT_FALSE(
+ matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, MIsInline)));
+
// The parameter of the defaulted method can still be matched.
auto MParm =
cxxMethodDecl(MDecl, hasParameter(0, parmVarDecl(hasName("other"))));
@@ -2435,6 +2481,21 @@
EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
}
+ {
+ auto M = cxxConstructorDecl(hasName("HasCtorInits"),
+ hasAnyConstructorInitializer(cxxCtorInitializer(
+ forField(hasName("m_nt")))));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+ }
+ {
+ auto M =
+ cxxConstructorDecl(hasName("HasCtorInits"),
+ forEachConstructorInitializer(
+ cxxCtorInitializer(forField(hasName("m_nt")))));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+ }
{
auto M = cxxConstructorDecl(
hasName("HasCtorInits"),
@@ -2563,13 +2624,37 @@
hasDefaultArg(42);
}
)cpp";
+ auto hasDefaultArgCall = [](auto InnerMatcher) {
+ return callExpr(callee(functionDecl(hasName("hasDefaultArg"))),
+ InnerMatcher);
+ };
{
- auto M = callExpr(has(integerLiteral(equals(42))));
+ auto M = hasDefaultArgCall(has(integerLiteral(equals(42))));
EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
}
{
- auto M = callExpr(has(cxxDefaultArgExpr()));
+ auto M = hasDefaultArgCall(has(cxxDefaultArgExpr()));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+ }
+ {
+ auto M = hasDefaultArgCall(argumentCountIs(2));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+ }
+ {
+ auto M = hasDefaultArgCall(argumentCountIs(1));
+ EXPECT_FALSE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+ }
+ {
+ auto M = hasDefaultArgCall(hasArgument(1, cxxDefaultArgExpr()));
+ EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
+ EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
+ }
+ {
+ auto M = hasDefaultArgCall(hasAnyArgument(cxxDefaultArgExpr()));
EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M)));
EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M)));
}
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -665,6 +665,15 @@
return End;
}
+template <typename T, std::enable_if_t<!std::is_base_of<FunctionDecl, T>::value>
+ * = nullptr>
+inline bool isDefaultedHelper(const T *) {
+ return false;
+}
+inline bool isDefaultedHelper(const FunctionDecl *FD) {
+ return FD->isDefaulted();
+}
+
// Metafunction to determine if type T has a member called getDecl.
template <typename Ty>
class has_getDecl {
@@ -932,6 +941,10 @@
/// is \c NULL.
bool matchesDecl(const Decl *Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
+ if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
+ TK_AsIs &&
+ Node->isImplicit())
+ return false;
return Node != nullptr && this->InnerMatcher.matches(
DynTypedNode::create(*Node), Finder, Builder);
}
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -3106,9 +3106,18 @@
/// \c A but not \c B.
AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
InnerMatcher) {
- return matchesFirstInPointerRange(InnerMatcher, Node.method_begin(),
- Node.method_end(), Finder,
- Builder) != Node.method_end();
+ BoundNodesTreeBuilder Result(*Builder);
+ auto MatchIt = matchesFirstInPointerRange(InnerMatcher, Node.method_begin(),
+ Node.method_end(), Finder, &Result);
+ if (MatchIt == Node.method_end())
+ return false;
+
+ if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
+ TK_AsIs &&
+ (*MatchIt)->isImplicit())
+ return false;
+ *Builder = std::move(Result);
+ return true;
}
/// Matches the generated class of lambda expressions.
@@ -4044,7 +4053,17 @@
CallExpr, CXXConstructExpr,
CXXUnresolvedConstructExpr, ObjCMessageExpr),
unsigned, N) {
- return Node.getNumArgs() == N;
+ auto NumArgs = Node.getNumArgs();
+ if (Finder->getASTContext().getParentMapContext().getTraversalKind() ==
+ TK_AsIs)
+ return NumArgs == N;
+ while (NumArgs) {
+ const auto *Arg = Node.getArg(NumArgs - 1);
+ if (!isa<CXXDefaultArgExpr>(Arg))
+ break;
+ --NumArgs;
+ }
+ return NumArgs == N;
}
/// Matches the n'th argument of a call expression or a constructor
@@ -4060,9 +4079,14 @@
CallExpr, CXXConstructExpr,
CXXUnresolvedConstructExpr, ObjCMessageExpr),
unsigned, N, internal::Matcher<Expr>, InnerMatcher) {
- return (N < Node.getNumArgs() &&
- InnerMatcher.matches(
- *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder));
+ if (N >= Node.getNumArgs())
+ return false;
+ const auto *Arg = Node.getArg(N);
+ if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
+ TK_AsIs &&
+ isa<CXXDefaultArgExpr>(Arg))
+ return false;
+ return InnerMatcher.matches(*Arg->IgnoreParenImpCasts(), Finder, Builder);
}
/// Matches the n'th item of an initializer list expression.
@@ -4154,9 +4178,13 @@
/// record matches Foo, hasAnyConstructorInitializer matches foo_(1)
AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer,
internal::Matcher<CXXCtorInitializer>, InnerMatcher) {
- return matchesFirstInPointerRange(InnerMatcher, Node.init_begin(),
- Node.init_end(), Finder,
- Builder) != Node.init_end();
+ auto MatchIt = matchesFirstInPointerRange(InnerMatcher, Node.init_begin(),
+ Node.init_end(), Finder, Builder);
+ if (MatchIt == Node.init_end())
+ return false;
+ return (*MatchIt)->isWritten() ||
+ Finder->getASTContext().getParentMapContext().getTraversalKind() ==
+ TK_AsIs;
}
/// Matches the field declaration of a constructor initializer.
@@ -4280,7 +4308,10 @@
CallExpr, CXXConstructExpr,
CXXUnresolvedConstructExpr, ObjCMessageExpr),
internal::Matcher<Expr>, InnerMatcher) {
+ auto TK = Finder->getASTContext().getParentMapContext().getTraversalKind();
for (const Expr *Arg : Node.arguments()) {
+ if (TK != TK_AsIs && isa<CXXDefaultArgExpr>(Arg))
+ break;
BoundNodesTreeBuilder Result(*Builder);
if (InnerMatcher.matches(*Arg, Finder, &Result)) {
*Builder = std::move(Result);
@@ -4998,6 +5029,10 @@
CXXForRangeStmt,
FunctionDecl),
internal::Matcher<Stmt>, InnerMatcher) {
+ if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
+ TK_AsIs &&
+ isDefaultedHelper(&Node))
+ return false;
const Stmt *const Statement = internal::GetBodyMatcher<NodeType>::get(Node);
return (Statement != nullptr &&
InnerMatcher.matches(*Statement, Finder, Builder));
@@ -5425,6 +5460,12 @@
AST_POLYMORPHIC_SUPPORTED_TYPES(TagDecl, VarDecl,
ObjCMethodDecl,
FunctionDecl)) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(&Node)) {
+ if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
+ TK_AsIs &&
+ FD->isDefaulted())
+ return false;
+ }
return Node.isThisDeclarationADefinition();
}
@@ -6880,6 +6921,10 @@
BoundNodesTreeBuilder Result;
bool Matched = false;
for (const auto *I : Node.inits()) {
+ if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
+ TK_AsIs &&
+ !I->isWritten())
+ continue;
BoundNodesTreeBuilder InitBuilder(*Builder);
if (InnerMatcher.matches(*I, Finder, &InitBuilder)) {
Matched = true;
@@ -7027,9 +7072,14 @@
FunctionDecl)) {
// This is required because the spelling of the function used to determine
// whether inline is specified or not differs between the polymorphic types.
- if (const auto *FD = dyn_cast<FunctionDecl>(&Node))
+ if (const auto *FD = dyn_cast<FunctionDecl>(&Node)) {
+ if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
+ TK_AsIs &&
+ FD->isDefaulted())
+ return false;
+
return FD->isInlineSpecified();
- else if (const auto *NSD = dyn_cast<NamespaceDecl>(&Node))
+ } else if (const auto *NSD = dyn_cast<NamespaceDecl>(&Node))
return NSD->isInline();
llvm_unreachable("Not a valid polymorphic type");
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits