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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits