Author: Balázs Benics Date: 2026-06-10T09:03:13+01:00 New Revision: a424861be0f82ca8e05dd0ae3fb433805a1fec20
URL: https://github.com/llvm/llvm-project/commit/a424861be0f82ca8e05dd0ae3fb433805a1fec20 DIFF: https://github.com/llvm/llvm-project/commit/a424861be0f82ca8e05dd0ae3fb433805a1fec20.diff LOG: [clang][ssaf] CallGraph extractor should ignore objc callees for now (#202606) Ignoring them is better than crashing/asserting on nullptr derefs. Fixes: rdar://179104950 Added: Modified: clang/include/clang/Analysis/CallGraph.h clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Analysis/CallGraph.h b/clang/include/clang/Analysis/CallGraph.h index 76d1bd1dc9f34..f80790902e6b1 100644 --- a/clang/include/clang/Analysis/CallGraph.h +++ b/clang/include/clang/Analysis/CallGraph.h @@ -194,7 +194,8 @@ class CallGraphNode { Decl *getDecl() const { return FD; } FunctionDecl *getDefinition() const { - return getDecl()->getAsFunction()->getDefinition(); + FunctionDecl *FD = getDecl()->getAsFunction(); + return FD ? FD->getDefinition() : nullptr; } void print(raw_ostream &os) const; diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp index 6e0b0ee8fe834..6dfb66a283674 100644 --- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp +++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp @@ -72,9 +72,13 @@ void CallGraphExtractor::handleCallGraphNode(const ASTContext &Ctx, // never null. assert(CalleeDecl); - // FIXME: `clang::CallGraph` does not consider ObjCMessageExprs as calls. - // Consequently, they don't appear as a Callee. - assert(!isa<ObjCMethodDecl>(CalleeDecl)); + // `clang::CallGraph` resolves ObjCMessageExprs (including property + // dot-syntax) to their ObjCMethodDecls and adds them as callees — see + // `CGBuilder::VisitObjCMessageExpr` in clang/lib/Analysis/CallGraph.cpp. + // ObjC dispatch is dynamic, so recording these as direct callees would be + // misleading; skip them until we model ObjC properly. + if (isa<ObjCMethodDecl>(CalleeDecl)) + continue; // FIXME: `clang::CallGraph` does not create entries for primary templates. assert(!CalleeDecl->isTemplated()); diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp index 39b3cf604857d..183fd7155cfba 100644 --- a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp +++ b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractorTest.cpp @@ -424,6 +424,48 @@ TEST_F(CallGraphExtractorTest, ObjCMessageExprs) { hasSummaryThat(HasNoDirectCallees(), HasNoVirtualCallees())); } +TEST_F(CallGraphExtractorTest, ObjCMessageToLocallyImplementedMethod) { + // When the receiver class is implemented in the same TU, `clang::CallGraph` + // resolves the ObjCMessageExpr (via `lookupPrivateMethod`) to an + // ObjCMethodDecl and adds it as a callee. The extractor must not abort on + // these — ObjC dispatch is dynamic and we don't model it as a direct callee. + runExtractor(R"cpp( + @interface NSObject @end + @interface Inner : NSObject + - (int) val; + @end + @implementation Inner + - (int) val { return 42; } + @end + int caller(Inner *x) { return [x val]; } + )cpp", + {"-x", "objective-c"}); + + ASSERT_THAT_EXPECTED( + findSummary("caller"), + hasSummaryThat(HasNoDirectCallees(), HasNoVirtualCallees())); +} + +TEST_F(CallGraphExtractorTest, ObjCPropertyDotSyntax) { + // Property dot-syntax (`x.val`) desugars to an ObjCMessageExpr to the + // synthesized getter; same dynamic dispatch as bracket syntax. Cover it + // explicitly because real-world hits often come through dot-syntax. + runExtractor(R"cpp( + @interface NSObject @end + @interface Inner : NSObject + @property (readonly) int val; + @end + @implementation Inner + @end + int caller(Inner *x) { return x.val; } + )cpp", + {"-x", "objective-c"}); + + ASSERT_THAT_EXPECTED( + findSummary("caller"), + hasSummaryThat(HasNoDirectCallees(), HasNoVirtualCallees())); +} + TEST_F(CallGraphExtractorTest, DefinitionLocation) { runExtractor(R"cpp( void callee_with_def() {} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
