https://github.com/iitianpushkar updated https://github.com/llvm/llvm-project/pull/212934
>From 62527613ff6e8b141fdf7c73a1c56201999a9b4c Mon Sep 17 00:00:00 2001 From: iitianpushkar <[email protected]> Date: Thu, 30 Jul 2026 11:24:26 +0530 Subject: [PATCH 1/3] Added arg accessors to AnyCall --- clang/include/clang/Analysis/AnyCall.h | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/clang/include/clang/Analysis/AnyCall.h b/clang/include/clang/Analysis/AnyCall.h index 3e95366c98595..b6b80b6c56d3f 100644 --- a/clang/include/clang/Analysis/AnyCall.h +++ b/clang/include/clang/Analysis/AnyCall.h @@ -162,6 +162,41 @@ class AnyCall { size_t param_size() const { return parameters().size(); } bool param_empty() const { return parameters().empty(); } + /// \returns actual arguments for expression-backed calls. + ArrayRef<const Expr *> arguments() const { + if (!E) + return {}; + + switch (K) { + case Function: + case Block: { + const auto *CE = cast<CallExpr>(E); + return {CE->getArgs(), CE->getNumArgs()}; + } + case ObjCMethod: { + const auto *ME = cast<ObjCMessageExpr>(E); + return {ME->getArgs(), ME->getNumArgs()}; + } + case Constructor: { + const auto *CE = cast<CXXConstructExpr>(E); + return {CE->getArgs(), CE->getNumArgs()}; + } + case Destructor: + case InheritedConstructor: + case Allocator: + case Deallocator: + return {}; + } + llvm_unreachable("Unknown AnyCall::Kind"); + } + + using arg_const_iterator = ArrayRef<const Expr *>::const_iterator; + arg_const_iterator arg_begin() const { return arguments().begin(); } + arg_const_iterator arg_end() const { return arguments().end(); } + size_t arg_size() const { return arguments().size(); } + bool arg_empty() const { return arguments().empty(); } + const Expr *getArg(unsigned I) const { return arguments()[I]; } + QualType getReturnType(ASTContext &Ctx) const { switch (K) { case Function: >From af97b67165d6a65c593d7f7ff6d4aeefbfd68a09 Mon Sep 17 00:00:00 2001 From: iitianpushkar <[email protected]> Date: Fri, 31 Jul 2026 10:27:22 +0530 Subject: [PATCH 2/3] added test for AnyCall argument accesssor --- clang/include/clang/Analysis/AnyCall.h | 4 +- clang/unittests/Analysis/AnyCallTest.cpp | 274 +++++++++++++++++++++++ clang/unittests/Analysis/CMakeLists.txt | 1 + 3 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 clang/unittests/Analysis/AnyCallTest.cpp diff --git a/clang/include/clang/Analysis/AnyCall.h b/clang/include/clang/Analysis/AnyCall.h index b6b80b6c56d3f..65975de78d94a 100644 --- a/clang/include/clang/Analysis/AnyCall.h +++ b/clang/include/clang/Analysis/AnyCall.h @@ -162,7 +162,9 @@ class AnyCall { size_t param_size() const { return parameters().size(); } bool param_empty() const { return parameters().empty(); } - /// \returns actual arguments for expression-backed calls. + /// \returns actual arguments for expression-backed calls, or an empty range + /// for declaration-backed calls and call kinds with implicit or synthesized + /// argument lists, such as allocators and destructors. ArrayRef<const Expr *> arguments() const { if (!E) return {}; diff --git a/clang/unittests/Analysis/AnyCallTest.cpp b/clang/unittests/Analysis/AnyCallTest.cpp new file mode 100644 index 0000000000000..f71453fd9b5fc --- /dev/null +++ b/clang/unittests/Analysis/AnyCallTest.cpp @@ -0,0 +1,274 @@ +//===- AnyCallTest.cpp - AnyCall unit tests ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/AnyCall.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" +#include <initializer_list> +#include <memory> +#include <string> +#include <vector> + +namespace clang { +namespace { + +using namespace ast_matchers; + +std::unique_ptr<ASTUnit> buildAST(llvm::StringRef Code, + std::vector<std::string> Args = { + "-fsyntax-only", "-std=c++17"}) { + return tooling::buildASTFromCodeWithArgs(Code, Args); +} + +const IntegerLiteral *asIntegerLiteral(const Expr *E) { + return dyn_cast<IntegerLiteral>(E->IgnoreImplicit()); +} + +void expectIntegerArguments(const AnyCall &Call, + std::initializer_list<int> Expected) { + ASSERT_EQ(Call.arg_size(), Expected.size()); + EXPECT_FALSE(Call.arg_empty()); + + unsigned Index = 0; + for (int ExpectedValue : Expected) { + const auto *Arg = asIntegerLiteral(Call.getArg(Index)); + ASSERT_NE(Arg, nullptr); + EXPECT_EQ(Arg->getValue(), ExpectedValue); + ++Index; + } +} + +void expectNoArguments(const AnyCall &Call) { + EXPECT_TRUE(Call.arg_empty()); + EXPECT_EQ(Call.arg_size(), 0u); + EXPECT_EQ(Call.arg_begin(), Call.arg_end()); +} + +TEST(AnyCallTest, ExposesFunctionParameters) { + auto AST = buildAST(R"cpp( + void callee(int first, int second); + )cpp"); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *Callee = selectFirst<FunctionDecl>( + "callee", match(functionDecl(hasName("callee")).bind("callee"), Ctx)); + ASSERT_NE(Callee, nullptr); + + AnyCall Call(Callee); + EXPECT_FALSE(Call.param_empty()); + ASSERT_EQ(Call.param_size(), 2u); + EXPECT_EQ(Call.parameters()[0], Callee->getParamDecl(0)); + EXPECT_EQ(*Call.param_begin(), Callee->getParamDecl(0)); +} + +TEST(AnyCallTest, ExposesFunctionCallArguments) { + auto AST = buildAST(R"cpp( + void callee(int, int); + void target() { callee(1, 2); } + )cpp"); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *CE = selectFirst<CallExpr>( + "call", + match(callExpr(callee(functionDecl(hasName("callee")))).bind("call"), + Ctx)); + ASSERT_NE(CE, nullptr); + + AnyCall Call(CE); + expectIntegerArguments(Call, {1, 2}); + EXPECT_EQ(Call.arguments()[0], CE->getArg(0)); + EXPECT_EQ(*Call.arg_begin(), CE->getArg(0)); +} + +TEST(AnyCallTest, ExposesBlockCallArguments) { + auto AST = buildAST(R"cpp( + void target() { + void (^block)(int, int) = ^(int, int) {}; + block(3, 4); + } + )cpp", + {"-fsyntax-only", "-std=c++17", "-fblocks"}); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *CE = selectFirst<CallExpr>( + "call", match(callExpr(callee(expr(hasType(blockPointerType()))), + argumentCountIs(2)) + .bind("call"), + Ctx)); + ASSERT_NE(CE, nullptr); + + AnyCall Call(CE); + EXPECT_EQ(Call.getKind(), AnyCall::Block); + expectIntegerArguments(Call, {3, 4}); + EXPECT_EQ(Call.arguments()[0], CE->getArg(0)); + EXPECT_EQ(*Call.arg_begin(), CE->getArg(0)); +} + +TEST(AnyCallTest, ExposesObjCMethodArguments) { + auto AST = buildAST(R"objc( + @interface Receiver + - (void)method:(int)x second:(int)y; + @end + + void target(Receiver *R) { + [R method:5 second:6]; + } + )objc", + {"-fsyntax-only", "-x", "objective-c++", "-std=c++17"}); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *ME = selectFirst<ObjCMessageExpr>( + "message", + match(objcMessageExpr(callee(objcMethodDecl(hasName("method:second:"))), + argumentCountIs(2)) + .bind("message"), + Ctx)); + ASSERT_NE(ME, nullptr); + + AnyCall Call(ME); + EXPECT_EQ(Call.getKind(), AnyCall::ObjCMethod); + expectIntegerArguments(Call, {5, 6}); + EXPECT_EQ(Call.arguments()[0], ME->getArg(0)); + EXPECT_EQ(*Call.arg_begin(), ME->getArg(0)); +} + +TEST(AnyCallTest, ExposesConstructorArguments) { + auto AST = buildAST(R"cpp( + struct Widget { + Widget(int, int); + }; + void target() { Widget W(3, 4); } + )cpp"); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *CtorExpr = selectFirst<CXXConstructExpr>( + "ctor", match(cxxConstructExpr(hasDeclaration(cxxConstructorDecl( + ofClass(hasName("Widget")))), + argumentCountIs(2)) + .bind("ctor"), + Ctx)); + ASSERT_NE(CtorExpr, nullptr); + + AnyCall Call(CtorExpr); + expectIntegerArguments(Call, {3, 4}); + EXPECT_EQ(Call.arguments()[0], CtorExpr->getArg(0)); + EXPECT_EQ(*Call.arg_begin(), CtorExpr->getArg(0)); +} + +TEST(AnyCallTest, AllocatorCallsHaveNoArguments) { + auto AST = buildAST(R"cpp( + void target() { + int *P = new int(5); + } + )cpp"); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *NE = + selectFirst<CXXNewExpr>("new", match(cxxNewExpr().bind("new"), Ctx)); + ASSERT_NE(NE, nullptr); + + AnyCall Call(NE); + EXPECT_EQ(Call.getKind(), AnyCall::Allocator); + expectNoArguments(Call); +} + +TEST(AnyCallTest, DeallocatorCallsHaveNoArguments) { + auto AST = buildAST(R"cpp( + void target(int *P) { + delete P; + } + )cpp"); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *DE = selectFirst<CXXDeleteExpr>( + "delete", match(cxxDeleteExpr().bind("delete"), Ctx)); + ASSERT_NE(DE, nullptr); + + AnyCall Call(DE); + EXPECT_EQ(Call.getKind(), AnyCall::Deallocator); + expectNoArguments(Call); +} + +TEST(AnyCallTest, InheritedConstructorCallsHaveNoArguments) { + auto AST = buildAST(R"cpp( + struct Base { + Base(int) {} + }; + struct Derived : Base { + using Base::Base; + }; + + Derived D = Derived(0); + )cpp", + {"-fsyntax-only", "-std=c++20"}); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *InheritedCtorInit = selectFirst<CXXInheritedCtorInitExpr>( + "init", + match(cxxConstructorDecl(hasAnyConstructorInitializer( + cxxCtorInitializer(withInitializer(expr().bind("init"))))), + Ctx)); + ASSERT_NE(InheritedCtorInit, nullptr); + + AnyCall Call(InheritedCtorInit); + EXPECT_EQ(Call.getKind(), AnyCall::InheritedConstructor); + expectNoArguments(Call); +} + +TEST(AnyCallTest, DestructorDeclarationsHaveNoArguments) { + auto AST = buildAST(R"cpp( + struct Widget { + ~Widget(); + }; + )cpp"); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *Destructor = selectFirst<CXXDestructorDecl>( + "destructor", + match(cxxDestructorDecl(ofClass(hasName("Widget"))).bind("destructor"), + Ctx)); + ASSERT_NE(Destructor, nullptr); + + AnyCall Call(Destructor); + EXPECT_EQ(Call.getKind(), AnyCall::Destructor); + expectNoArguments(Call); +} + +TEST(AnyCallTest, DeclarationBackedCallsHaveNoArguments) { + auto AST = buildAST(R"cpp( + void callee(int first, int second); + )cpp"); + ASTContext &Ctx = AST->getASTContext(); + ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); + + const auto *Callee = selectFirst<FunctionDecl>( + "callee", match(functionDecl(hasName("callee")).bind("callee"), Ctx)); + ASSERT_NE(Callee, nullptr); + + AnyCall Call(Callee); + EXPECT_EQ(Call.getKind(), AnyCall::Function); + expectNoArguments(Call); +} + +} // namespace +} // namespace clang diff --git a/clang/unittests/Analysis/CMakeLists.txt b/clang/unittests/Analysis/CMakeLists.txt index cb7cc1bd0062e..33164d1f2f9f1 100644 --- a/clang/unittests/Analysis/CMakeLists.txt +++ b/clang/unittests/Analysis/CMakeLists.txt @@ -1,4 +1,5 @@ add_clang_unittest(ClangAnalysisTests + AnyCallTest.cpp CFGBackEdgesTest.cpp CFGDominatorTree.cpp CFGTest.cpp >From 46dc33cdf1b54d3dec75e0c393cc33019983f60b Mon Sep 17 00:00:00 2001 From: iitianpushkar <[email protected]> Date: Fri, 31 Jul 2026 16:34:16 +0530 Subject: [PATCH 3/3] refactored code in AnyCallTest.cpp --- clang/unittests/Analysis/AnyCallTest.cpp | 36 ++++++------------------ 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/clang/unittests/Analysis/AnyCallTest.cpp b/clang/unittests/Analysis/AnyCallTest.cpp index f71453fd9b5fc..425e10a3bd54c 100644 --- a/clang/unittests/Analysis/AnyCallTest.cpp +++ b/clang/unittests/Analysis/AnyCallTest.cpp @@ -39,6 +39,8 @@ void expectIntegerArguments(const AnyCall &Call, std::initializer_list<int> Expected) { ASSERT_EQ(Call.arg_size(), Expected.size()); EXPECT_FALSE(Call.arg_empty()); + EXPECT_EQ(Call.arguments()[0], Call.getArg(0)); + EXPECT_EQ(*Call.arg_begin(), Call.getArg(0)); unsigned Index = 0; for (int ExpectedValue : Expected) { @@ -55,27 +57,9 @@ void expectNoArguments(const AnyCall &Call) { EXPECT_EQ(Call.arg_begin(), Call.arg_end()); } -TEST(AnyCallTest, ExposesFunctionParameters) { +TEST(AnyCallTest, ExposesFunctionParametersAndArguments) { auto AST = buildAST(R"cpp( void callee(int first, int second); - )cpp"); - ASTContext &Ctx = AST->getASTContext(); - ASSERT_EQ(Ctx.getDiagnostics().getClient()->getNumErrors(), 0U); - - const auto *Callee = selectFirst<FunctionDecl>( - "callee", match(functionDecl(hasName("callee")).bind("callee"), Ctx)); - ASSERT_NE(Callee, nullptr); - - AnyCall Call(Callee); - EXPECT_FALSE(Call.param_empty()); - ASSERT_EQ(Call.param_size(), 2u); - EXPECT_EQ(Call.parameters()[0], Callee->getParamDecl(0)); - EXPECT_EQ(*Call.param_begin(), Callee->getParamDecl(0)); -} - -TEST(AnyCallTest, ExposesFunctionCallArguments) { - auto AST = buildAST(R"cpp( - void callee(int, int); void target() { callee(1, 2); } )cpp"); ASTContext &Ctx = AST->getASTContext(); @@ -88,9 +72,13 @@ TEST(AnyCallTest, ExposesFunctionCallArguments) { ASSERT_NE(CE, nullptr); AnyCall Call(CE); + const auto *Callee = cast<FunctionDecl>(Call.getDecl()); + EXPECT_FALSE(Call.param_empty()); + ASSERT_EQ(Call.param_size(), 2u); + EXPECT_EQ(Call.parameters()[0], Callee->getParamDecl(0)); + EXPECT_EQ(*Call.param_begin(), Callee->getParamDecl(0)); + expectIntegerArguments(Call, {1, 2}); - EXPECT_EQ(Call.arguments()[0], CE->getArg(0)); - EXPECT_EQ(*Call.arg_begin(), CE->getArg(0)); } TEST(AnyCallTest, ExposesBlockCallArguments) { @@ -114,8 +102,6 @@ TEST(AnyCallTest, ExposesBlockCallArguments) { AnyCall Call(CE); EXPECT_EQ(Call.getKind(), AnyCall::Block); expectIntegerArguments(Call, {3, 4}); - EXPECT_EQ(Call.arguments()[0], CE->getArg(0)); - EXPECT_EQ(*Call.arg_begin(), CE->getArg(0)); } TEST(AnyCallTest, ExposesObjCMethodArguments) { @@ -143,8 +129,6 @@ TEST(AnyCallTest, ExposesObjCMethodArguments) { AnyCall Call(ME); EXPECT_EQ(Call.getKind(), AnyCall::ObjCMethod); expectIntegerArguments(Call, {5, 6}); - EXPECT_EQ(Call.arguments()[0], ME->getArg(0)); - EXPECT_EQ(*Call.arg_begin(), ME->getArg(0)); } TEST(AnyCallTest, ExposesConstructorArguments) { @@ -167,8 +151,6 @@ TEST(AnyCallTest, ExposesConstructorArguments) { AnyCall Call(CtorExpr); expectIntegerArguments(Call, {3, 4}); - EXPECT_EQ(Call.arguments()[0], CtorExpr->getArg(0)); - EXPECT_EQ(*Call.arg_begin(), CtorExpr->getArg(0)); } TEST(AnyCallTest, AllocatorCallsHaveNoArguments) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
