From fd056b6d07d7171c99c9388fa474c61b1cafc999 Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aaron@aaronballman.com> Date: Fri, 29 Jan 2016 17:03:11 +0000 Subject: [PATCH] Extend hasType narrowing matcher for TypedefDecls, add functionProtoType matcher for FunctionProtoType nodes, extend parameterCountIs to FunctionProtoType nodes. Patch by Richard Thomson git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@259210 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LibASTMatchersReference.html | 72 ++++++++++++++++--- include/clang/ASTMatchers/ASTMatchers.h | 36 ++++++++-- .../clang/ASTMatchers/ASTMatchersInternal.h | 11 +++ lib/ASTMatchers/Dynamic/Registry.cpp | 1 + unittests/ASTMatchers/ASTMatchersTest.cpp | 26 ++++++- 5 files changed, 132 insertions(+), 14 deletions(-) diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 75deea40e13..93408e5776e 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -1308,6 +1308,18 @@ c and d. </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('functionProtoType0')"><a name="functionProtoType0Anchor">functionProtoType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionProtoType.html">FunctionProtoType</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="functionProtoType0"><pre>Matches FunctionProtoType nodes. + +Given + int (*f)(int); + void g(); +functionProtoType() + matches "int (*f)(int)" and the type of "g" in C++ mode. + In C mode, "g" is not matched because it does not contain a prototype. +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td><td class="name" onclick="toggle('functionType0')"><a name="functionType0Anchor">functionType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionType.html">FunctionType</a>>...</td></tr> <tr><td colspan="4" class="doc" id="functionType0"><pre>Matches FunctionType nodes. @@ -2335,13 +2347,40 @@ compiled in C mode. <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>></td><td class="name" onclick="toggle('parameterCountIs0')"><a name="parameterCountIs0Anchor">parameterCountIs</a></td><td>unsigned N</td></tr> -<tr><td colspan="4" class="doc" id="parameterCountIs0"><pre>Matches FunctionDecls that have a specific parameter count. +<tr><td colspan="4" class="doc" id="parameterCountIs0"><pre>Matches FunctionDecls and FunctionProtoTypes that have a +specific parameter count. + +Given + void f(int i) {} + void g(int i, int j) {} + void h(int i, int j); + void j(int i); + void k(int x, int y, int z, ...); +functionDecl(parameterCountIs(2)) + matches void g(int i, int j) {} +functionProtoType(parameterCountIs(2)) + matches void h(int i, int j) +functionProtoType(parameterCountIs(3)) + matches void k(int x, int y, int z, ...); +</pre></td></tr> + + +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionProtoType.html">FunctionProtoType</a>></td><td class="name" onclick="toggle('parameterCountIs1')"><a name="parameterCountIs1Anchor">parameterCountIs</a></td><td>unsigned N</td></tr> +<tr><td colspan="4" class="doc" id="parameterCountIs1"><pre>Matches FunctionDecls and FunctionProtoTypes that have a +specific parameter count. Given void f(int i) {} void g(int i, int j) {} + void h(int i, int j); + void j(int i); + void k(int x, int y, int z, ...); functionDecl(parameterCountIs(2)) - matches g(int i, int j) {} + matches void g(int i, int j) {} +functionProtoType(parameterCountIs(2)) + matches void h(int i, int j) +functionProtoType(parameterCountIs(3)) + matches void k(int x, int y, int z, ...); </pre></td></tr> @@ -3995,8 +4034,8 @@ actual casts "explicit" casts.) </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('hasType2')"><a name="hasType2Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="hasType2"><pre>Overloaded to match the declaration of the expression's or value +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>></td><td class="name" onclick="toggle('hasType3')"><a name="hasType3Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasType3"><pre>Overloaded to match the declaration of the expression's or value declaration's type. In case of a value declaration (for example a variable declaration), @@ -4020,8 +4059,10 @@ matcher. Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) + and U (matcher = typedefDecl(hasType(asString("int"))) class X {}; void y(X &x) { x; X z; } + typedef int U; </pre></td></tr> @@ -4796,6 +4837,19 @@ Usable as: Any Matcher </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefDecl.html">TypedefDecl</a>></td><td class="name" onclick="toggle('hasType1')"><a name="hasType1Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasType1"><pre>Matches if the expression's or declaration's type matches a type +matcher. + +Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) + and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) + and U (matcher = typedefDecl(hasType(asString("int"))) + class X {}; + void y(X &x) { x; X z; } + typedef int U; +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>></td><td class="name" onclick="toggle('hasDeclaration1')"><a name="hasDeclaration1Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasDeclaration1"><pre>Matches a node if the declaration associated with that node matches the given matcher. @@ -4881,8 +4935,8 @@ usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(functionDecl()))) matches using X::b but not using X::a </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType3')"><a name="hasType3Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="hasType3"><pre>Overloaded to match the declaration of the expression's or value +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType4')"><a name="hasType4Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasType4"><pre>Overloaded to match the declaration of the expression's or value declaration's type. In case of a value declaration (for example a variable declaration), @@ -4900,14 +4954,16 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr. </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType1')"><a name="hasType1Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="hasType1"><pre>Matches if the expression's or declaration's type matches a type +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>></td><td class="name" onclick="toggle('hasType2')"><a name="hasType2Anchor">hasType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasType2"><pre>Matches if the expression's or declaration's type matches a type matcher. Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) + and U (matcher = typedefDecl(hasType(asString("int"))) class X {}; void y(X &x) { x; X z; } + typedef int U; </pre></td></tr> diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index c74b4bce9d0..ea81028a7f6 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -2298,14 +2298,17 @@ AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher, /// /// Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X"))))) /// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X"))))) +/// and U (matcher = typedefDecl(hasType(asString("int"))) /// \code /// class X {}; /// void y(X &x) { x; X z; } +/// typedef int U; /// \endcode AST_POLYMORPHIC_MATCHER_P_OVERLOAD( - hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, ValueDecl), + hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, TypedefDecl, ValueDecl), internal::Matcher<QualType>, InnerMatcher, 0) { - return InnerMatcher.matches(Node.getType(), Finder, Builder); + return InnerMatcher.matches(internal::getUnderlyingType<NodeType>(Node), + Finder, Builder); } /// \brief Overloaded to match the declaration of the expression's or value @@ -2951,16 +2954,27 @@ AST_MATCHER_P(FunctionDecl, hasAnyParameter, Node.param_end(), Finder, Builder); } -/// \brief Matches \c FunctionDecls that have a specific parameter count. +/// \brief Matches \c FunctionDecls and \c FunctionProtoTypes that have a +/// specific parameter count. /// /// Given /// \code /// void f(int i) {} /// void g(int i, int j) {} +/// void h(int i, int j); +/// void j(int i); +/// void k(int x, int y, int z, ...); /// \endcode /// functionDecl(parameterCountIs(2)) -/// matches g(int i, int j) {} -AST_MATCHER_P(FunctionDecl, parameterCountIs, unsigned, N) { +/// matches void g(int i, int j) {} +/// functionProtoType(parameterCountIs(2)) +/// matches void h(int i, int j) +/// functionProtoType(parameterCountIs(3)) +/// matches void k(int x, int y, int z, ...); +AST_POLYMORPHIC_MATCHER_P(parameterCountIs, + AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, + FunctionProtoType), + unsigned, N) { return Node.getNumParams() == N; } @@ -4099,6 +4113,18 @@ AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType, /// matches "int (*f)(int)" and the type of "g". AST_TYPE_MATCHER(FunctionType, functionType); +/// \brief Matches \c FunctionProtoType nodes. +/// +/// Given +/// \code +/// int (*f)(int); +/// void g(); +/// \endcode +/// functionProtoType() +/// matches "int (*f)(int)" and the type of "g" in C++ mode. +/// In C mode, "g" is not matched because it does not contain a prototype. +AST_TYPE_MATCHER(FunctionProtoType, functionProtoType); + /// \brief Matches \c ParenType nodes. /// /// Given diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index 2b3fa6ea9c0..ca0b49137ec 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -60,6 +60,17 @@ class BoundNodes; namespace internal { +/// \brief Unifies obtaining the underlying type of a regular node through +/// `getType` and a TypedefNameDecl node through `getUnderlyingType`. +template <typename NodeType> +inline QualType getUnderlyingType(const NodeType &Node) { + return Node.getType(); +} + +template <> inline QualType getUnderlyingType(const TypedefDecl &Node) { + return Node.getUnderlyingType(); +} + /// \brief Internal version of BoundNodes. Holds all the bound nodes. class BoundNodesMap { public: diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 6aee48416de..df4f29d0f0a 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -182,6 +182,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(forStmt); REGISTER_MATCHER(friendDecl); REGISTER_MATCHER(functionDecl); + REGISTER_MATCHER(functionProtoType); REGISTER_MATCHER(functionTemplateDecl); REGISTER_MATCHER(functionType); REGISTER_MATCHER(gotoStmt); diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index 7fd933718fa..073f2c50938 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -1091,6 +1091,16 @@ TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) { notMatches("class X {}; void y() { X *x; }", varDecl(hasType(ClassX)))); } +TEST(HasType, MatchesTypedefDecl) { + EXPECT_TRUE(matches("typedef int X;", typedefDecl(hasType(asString("int"))))); + EXPECT_TRUE(matches("typedef const int T;", + typedefDecl(hasType(asString("const int"))))); + EXPECT_TRUE(notMatches("typedef const int T;", + typedefDecl(hasType(asString("int"))))); + EXPECT_TRUE(matches("typedef int foo; typedef foo bar;", + typedefDecl(hasType(asString("foo")), hasName("bar")))); +} + TEST(HasTypeLoc, MatchesDeclaratorDecls) { EXPECT_TRUE(matches("int x;", varDecl(hasName("x"), hasTypeLoc(loc(asString("int")))))); @@ -1563,6 +1573,9 @@ TEST(Function, MatchesFunctionDeclarations) { functionDecl(isVariadic()))); EXPECT_TRUE(notMatches("void f();", functionDecl(isVariadic()))); EXPECT_TRUE(notMatchesC("void f();", functionDecl(isVariadic()))); + EXPECT_TRUE(matches("void f(...);", functionDecl(parameterCountIs(0)))); + EXPECT_TRUE(matchesC("void f();", functionDecl(parameterCountIs(0)))); + EXPECT_TRUE(matches("void f(int, ...);", functionDecl(parameterCountIs(1)))); } TEST(FunctionTemplate, MatchesFunctionTemplateDeclarations) { @@ -1719,6 +1732,7 @@ TEST(Matcher, ParameterCount) { EXPECT_TRUE(matches("class X { void f(int i) {} };", Function1Arg)); EXPECT_TRUE(notMatches("void f() {}", Function1Arg)); EXPECT_TRUE(notMatches("void f(int i, int j, int k) {}", Function1Arg)); + EXPECT_TRUE(matches("void f(int i, ...) {};", Function1Arg)); } TEST(Matcher, References) { @@ -4447,6 +4461,15 @@ TEST(TypeMatching, MatchesFunctionTypes) { EXPECT_TRUE(matches("void f(int i) {}", functionType())); } +TEST(TypeMatching, MatchesFunctionProtoTypes) { + EXPECT_TRUE(matches("int (*f)(int);", functionProtoType())); + EXPECT_TRUE(matches("void f(int i);", functionProtoType())); + EXPECT_TRUE(matches("void f();", functionProtoType(parameterCountIs(0)))); + EXPECT_TRUE(notMatchesC("void f();", functionProtoType())); + EXPECT_TRUE( + matchesC("void f(void);", functionProtoType(parameterCountIs(0)))); +} + TEST(TypeMatching, MatchesParenType) { EXPECT_TRUE( matches("int (*array)[4];", varDecl(hasType(pointsTo(parenType()))))); @@ -5148,7 +5171,8 @@ TEST(IsInlineMatcher, IsInline) { namespaceDecl(isInline(), hasName("m")))); } -// FIXME: Figure out how to specify paths so the following tests pass on Windows. +// FIXME: Figure out how to specify paths so the following tests pass on +// Windows. #ifndef LLVM_ON_WIN32 TEST(Matcher, IsExpansionInMainFileMatcher) { -- GitLab