mikecrowe created this revision. mikecrowe added a reviewer: PiotrZSL. Herald added a project: All. mikecrowe requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. mikecrowe added inline comments.
================ Comment at: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp:1671 + notMatches("void x(int, int = 1) { x(0); }", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + EXPECT_TRUE( ---------------- I'm not sure if this is the best way to trigger testing of the ignoring default argument path in the implementation of `argumentCountAtLeast`, but it does seem to work. I added explicit `TK_AsIs` to the tests above to make it clear that they are not testing that path. This will be used by the modernize-use-std-print clang-tidy check and related checks later. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D153716 Files: clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1640,6 +1640,95 @@ cxxConversionDecl(isExplicit()))); } +TEST_P(ASTMatchersTest, ArgumentCountAtLeast_CallExpr) { + StatementMatcher Call2PlusArgs = callExpr(argumentCountAtLeast(2)); + + EXPECT_TRUE(notMatches("void x(void) { x(); }", Call2PlusArgs)); + EXPECT_TRUE(notMatches("void x(int) { x(0); }", Call2PlusArgs)); + EXPECT_TRUE(matches("void x(int, int) { x(0, 0); }", Call2PlusArgs)); + EXPECT_TRUE(matches("void x(int, int, int) { x(0, 0, 0); }", Call2PlusArgs)); + + if (!GetParam().isCXX()) { + return; + } + + EXPECT_TRUE( + notMatches("void x(int = 1) { x(); }", traverse(TK_AsIs, Call2PlusArgs))); + EXPECT_TRUE(matches("void x(int, int = 1) { x(0); }", + traverse(TK_AsIs, Call2PlusArgs))); + EXPECT_TRUE(matches("void x(int, int = 1, int = 1) { x(0); }", + traverse(TK_AsIs, Call2PlusArgs))); + EXPECT_TRUE(matches("void x(int, int, int = 1) { x(0, 0); }", + traverse(TK_AsIs, Call2PlusArgs))); + EXPECT_TRUE(matches("void x(int, int, int, int = 1) { x(0, 0, 0); }", + traverse(TK_AsIs, Call2PlusArgs))); + + EXPECT_TRUE( + notMatches("void x(int = 1) { x(); }", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + EXPECT_TRUE( + notMatches("void x(int, int = 1) { x(0); }", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + EXPECT_TRUE( + notMatches("void x(int, int = 1, int = 1) { x(0); }", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + EXPECT_TRUE(matches("void x(int, int, int = 1) { x(0, 0); }", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + EXPECT_TRUE(matches("void x(int, int, int, int = 1) { x(0, 0, 0); }", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); +} + +TEST_P(ASTMatchersTest, ArgumentCountAtLeast_CallExpr_CXX) { + if (!GetParam().isCXX()) { + return; + } + + StatementMatcher Call2PlusArgs = callExpr(argumentCountAtLeast(2)); + EXPECT_TRUE(notMatches("class X { void x() { x(); } };", Call2PlusArgs)); + EXPECT_TRUE(notMatches("class X { void x(int) { x(0); } };", Call2PlusArgs)); + EXPECT_TRUE( + matches("class X { void x(int, int) { x(0, 0); } };", Call2PlusArgs)); + EXPECT_TRUE(matches("class X { void x(int, int, int) { x(0, 0, 0); } };", + Call2PlusArgs)); + + EXPECT_TRUE(notMatches("class X { void x(int = 1) { x(0); } };", + traverse(TK_AsIs, Call2PlusArgs))); + EXPECT_TRUE(matches("class X { void x(int, int = 1) { x(0); } };", + traverse(TK_AsIs, Call2PlusArgs))); + EXPECT_TRUE(matches("class X { void x(int, int = 1, int = 1) { x(0); } };", + traverse(TK_AsIs, Call2PlusArgs))); + EXPECT_TRUE(matches("class X { void x(int, int, int = 1) { x(0, 0); } };", + traverse(TK_AsIs, Call2PlusArgs))); + EXPECT_TRUE( + matches("class X { void x(int, int, int, int = 1) { x(0, 0, 0); } };", + traverse(TK_AsIs, Call2PlusArgs))); + + EXPECT_TRUE( + notMatches("class X { void x(int = 1) { x(0); } };", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + EXPECT_TRUE( + notMatches("class X { void x(int, int = 1) { x(0); } };", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + EXPECT_TRUE( + notMatches("class X { void x(int, int = 1, int = 1) { x(0); } };", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + EXPECT_TRUE(matches("class X { void x(int, int, int = 1) { x(0, 0); } };", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + EXPECT_TRUE( + matches("class X { void x(int, int, int, int = 1) { x(0, 0, 0); } };", + traverse(TK_IgnoreUnlessSpelledInSource, Call2PlusArgs))); + + EXPECT_TRUE( + notMatches("class X { static void x() { x(); } };", Call2PlusArgs)); + EXPECT_TRUE( + notMatches("class X { static void x(int) { x(0); } };", Call2PlusArgs)); + EXPECT_TRUE(matches("class X { static void x(int, int) { x(0, 0); } };", + Call2PlusArgs)); + EXPECT_TRUE( + matches("class X { static void x(int, int, int) { x(0, 0, 0); } };", + Call2PlusArgs)); +} + TEST_P(ASTMatchersTest, ArgumentCountIs_CallExpr) { StatementMatcher Call1Arg = callExpr(argumentCountIs(1)); Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4430,6 +4430,33 @@ return NumArgs == N; } +/// Checks that a call expression or a constructor call expression has at least +/// the specified number of arguments (including absent default arguments). +/// +/// Example matches f(0, 0) and g(0, 0, 0) +/// (matcher = callExpr(argumentCountAtLeast(2))) +/// \code +/// void f(int x, int y); +/// void g(int x, int y, int z); +/// f(0, 0); +/// g(0, 0, 0); +/// \endcode +AST_POLYMORPHIC_MATCHER_P(argumentCountAtLeast, + AST_POLYMORPHIC_SUPPORTED_TYPES( + CallExpr, CXXConstructExpr, + CXXUnresolvedConstructExpr, ObjCMessageExpr), + unsigned, N) { + unsigned NumArgs = Node.getNumArgs(); + if (!Finder->isTraversalIgnoringImplicitNodes()) + return NumArgs >= N; + while (NumArgs) { + if (!isa<CXXDefaultArgExpr>(Node.getArg(NumArgs - 1))) + break; + --NumArgs; + } + return NumArgs >= N; +} + /// Matches the n'th argument of a call expression or a constructor /// call expression. /// Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -3036,6 +3036,18 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('argumentCountAtLeast1')"><a name="argumentCountAtLeast1Anchor">argumentCountAtLeast</a></td><td>unsigned N</td></tr> +<tr><td colspan="4" class="doc" id="argumentCountAtLeast1"><pre>Checks that a call expression or a constructor call expression has +at least the specified number of arguments (including absent default arguments). + +Example matches f(0, 0) and g(0, 0, 0) (matcher = callExpr(argumentCountAtLeast(2))) + void f(int x, int y); + void g(int x, int y, int z); + f(0, 0); + g(0, 0, 0); +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>></td><td class="name" onclick="toggle('argumentCountIs1')"><a name="argumentCountIs1Anchor">argumentCountIs</a></td><td>unsigned N</td></tr> <tr><td colspan="4" class="doc" id="argumentCountIs1"><pre>Checks that a call expression or a constructor call expression has a specific number of arguments (including absent default arguments). @@ -3693,6 +3705,18 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>></td><td class="name" onclick="toggle('argumentCountAtLeast2')"><a name="argumentCountAtLeast2Anchor">argumentCountAtLeast</a></td><td>unsigned N</td></tr> +<tr><td colspan="4" class="doc" id="argumentCountAtLeast2"><pre>Checks that a call expression or a constructor call expression has +at least the specified number of arguments (including absent default arguments). + +Example matches f(0, 0) and g(0, 0, 0) (matcher = callExpr(argumentCountAtLeast(2))) + void f(int x, int y); + void g(int x, int y, int z); + f(0, 0); + g(0, 0, 0); +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>></td><td class="name" onclick="toggle('argumentCountIs2')"><a name="argumentCountIs2Anchor">argumentCountIs</a></td><td>unsigned N</td></tr> <tr><td colspan="4" class="doc" id="argumentCountIs2"><pre>Checks that a call expression or a constructor call expression has a specific number of arguments (including absent default arguments). @@ -3703,6 +3727,18 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('argumentCountAtLeast0')"><a name="argumentCountAtLeast0Anchor">argumentCountAtLeast</a></td><td>unsigned N</td></tr> +<tr><td colspan="4" class="doc" id="argumentCountAtLeast0"><pre>Checks that a call expression or a constructor call expression has +at least the specified number of arguments (including absent default arguments). + +Example matches f(0, 0) and g(0, 0, 0) (matcher = callExpr(argumentCountAtLeast(2))) + void f(int x, int y); + void g(int x, int y, int z); + f(0, 0); + g(0, 0, 0); +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('argumentCountIs0')"><a name="argumentCountIs0Anchor">argumentCountIs</a></td><td>unsigned N</td></tr> <tr><td colspan="4" class="doc" id="argumentCountIs0"><pre>Checks that a call expression or a constructor call expression has a specific number of arguments (including absent default arguments). @@ -4860,6 +4896,18 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('argumentCountAtLeast3')"><a name="argumentCountAtLeast3Anchor">argumentCountAtLeast</a></td><td>unsigned N</td></tr> +<tr><td colspan="4" class="doc" id="argumentCountAtLeast3"><pre>Checks that a call expression or a constructor call expression has +at least the specified number of arguments (including absent default arguments). + +Example matches f(0, 0) and g(0, 0, 0) (matcher = callExpr(argumentCountAtLeast(2))) + void f(int x, int y); + void g(int x, int y, int z); + f(0, 0); + g(0, 0, 0); +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('argumentCountIs3')"><a name="argumentCountIs3Anchor">argumentCountIs</a></td><td>unsigned N</td></tr> <tr><td colspan="4" class="doc" id="argumentCountIs3"><pre>Checks that a call expression or a constructor call expression has a specific number of arguments (including absent default arguments).
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits