https://github.com/dmaclach updated https://github.com/llvm/llvm-project/pull/216201
>From 23010f10d8c513f542a78b59e7d41a5f6e2e9152 Mon Sep 17 00:00:00 2001 From: Dave MacLachlan <[email protected]> Date: Thu, 13 Aug 2026 15:23:11 -0700 Subject: [PATCH 1/2] [include-cleaner] Support Objective-C literals and boxed expressions in WalkAST This change adds AST visitors for ObjCBoxedExpr, ObjCArrayLiteral, ObjCDictionaryLiteral, and ObjCStringLiteral. This ensures that the underlying class interfaces (such as NSNumber, NSArray, NSDictionary, and NSString) and any associated categories used for these literals are correctly reported as referenced. Unit tests are included to verify the new behavior. --- .../include-cleaner/lib/WalkAST.cpp | 28 +++++++ .../include-cleaner/unittests/WalkASTTest.cpp | 73 +++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index 17e7bd6ed683f..976e998e1d45f 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -622,6 +622,34 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> { } return true; } + + void ReportObjCMethodDecl(SourceLocation Loc, ObjCMethodDecl *Method) { + if (!Method) + return; + report(Loc, Method->getClassInterface(), RefType::Implicit); + report(Loc, dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())); + } + + bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) { + ReportObjCMethodDecl(E->getBeginLoc(), E->getBoxingMethod()); + return true; + } + + bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) { + ReportObjCMethodDecl(E->getBeginLoc(), E->getArrayWithObjectsMethod()); + return true; + } + + bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { + ReportObjCMethodDecl(E->getBeginLoc(), E->getDictWithObjectsMethod()); + return true; + } + + bool VisitObjCStringLiteral(ObjCStringLiteral *E) { + if (const auto *ObjCPtr = E->getType()->getAs<ObjCObjectPointerType>()) + report(E->getBeginLoc(), ObjCPtr->getInterfaceDecl(), RefType::Implicit); + return true; + } }; } // namespace diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index ace55ea7aa23f..71bc455ca00ed 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -1250,6 +1250,7 @@ TEST(WalkAST, ObjCTollFreeBridgeCStyleCast) { {"-x", "objective-c"}); } + TEST(WalkAST, ObjCBridgedCastExprToProtocol) { // Note this test case is handled by TraverseObjCProtocolLoc instead of // VisitCastExpr. @@ -1545,5 +1546,77 @@ TEST(WalkAST, ObjCEncodeExpr) { {"-x", "objective-c"}); } +TEST(WalkAST, ObjCBoxedExprInt) { + testWalk(R"objc( + @interface $implicit^NSNumber + + (id)numberWithInt:(int)val; + @end + )objc", + R"objc( + void test() { + id x = ^@42; + } + )objc", + {"-x", "objective-c"}); +} + + +TEST(WalkAST, ObjCBoxedExprCategory) { + testWalk(R"objc( + @interface $implicit^NSNumber + @end + @interface $explicit^NSNumber (CustomCategory) + + (id)numberWithInt:(int)val; + @end + )objc", + R"objc( + void test() { + id x = ^@42; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCArrayLiteral) { + testWalk(R"objc( + @interface $implicit^NSArray + + (id)arrayWithObjects:(const id *)objects count:(unsigned long)cnt; + @end + )objc", + R"objc( + void test(id a, id b) { + id arr = ^@[a, b]; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCDictionaryLiteral) { + testWalk(R"objc( + @interface $implicit^NSDictionary + + (id)dictionaryWithObjects:(const id *)objects forKeys:(const id *)keys count:(unsigned long)cnt; + @end + )objc", + R"objc( + void test(id k, id v) { + id dict = ^@{k: v}; + } + )objc", + {"-x", "objective-c"}); +} + +TEST(WalkAST, ObjCStringLiteral) { + testWalk(R"objc( + @interface $implicit^NSString + @end + )objc", + R"objc( + void test() { + id s = ^@"hello"; + } + )objc", + {"-x", "objective-c"}); +} + } // namespace } // namespace clang::include_cleaner >From 90228f581f914f637e43076f6c51b5464349ba29 Mon Sep 17 00:00:00 2001 From: Dave MacLachlan <[email protected]> Date: Mon, 24 Aug 2026 10:23:14 -0700 Subject: [PATCH 2/2] Cleaned up based on comments - Changed references to explicit - Removed unneeded references for categories - Added test for Boxed C Structures --- .../include-cleaner/lib/WalkAST.cpp | 16 +++++------ .../include-cleaner/unittests/WalkASTTest.cpp | 27 ++++++++++--------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index 976e998e1d45f..5449411371e60 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -623,31 +623,31 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> { return true; } - void ReportObjCMethodDecl(SourceLocation Loc, ObjCMethodDecl *Method) { + void reportObjCLiteralMethod(SourceLocation Loc, ObjCMethodDecl *Method) { if (!Method) return; - report(Loc, Method->getClassInterface(), RefType::Implicit); - report(Loc, dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())); + report(Loc, Method->getClassInterface()); } bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) { - ReportObjCMethodDecl(E->getBeginLoc(), E->getBoxingMethod()); + // Handles NSNumber literals and NSValue literals. + reportObjCLiteralMethod(E->getBeginLoc(), E->getBoxingMethod()); return true; } bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) { - ReportObjCMethodDecl(E->getBeginLoc(), E->getArrayWithObjectsMethod()); + reportObjCLiteralMethod(E->getBeginLoc(), E->getArrayWithObjectsMethod()); return true; } bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { - ReportObjCMethodDecl(E->getBeginLoc(), E->getDictWithObjectsMethod()); + reportObjCLiteralMethod(E->getBeginLoc(), E->getDictWithObjectsMethod()); return true; } bool VisitObjCStringLiteral(ObjCStringLiteral *E) { - if (const auto *ObjCPtr = E->getType()->getAs<ObjCObjectPointerType>()) - report(E->getBeginLoc(), ObjCPtr->getInterfaceDecl(), RefType::Implicit); + report(E->getBeginLoc(), + E->getType()->getAs<ObjCObjectPointerType>()->getInterfaceDecl()); return true; } }; diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index 71bc455ca00ed..bcc1df3f618e4 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -1548,7 +1548,7 @@ TEST(WalkAST, ObjCEncodeExpr) { TEST(WalkAST, ObjCBoxedExprInt) { testWalk(R"objc( - @interface $implicit^NSNumber + @interface $explicit^NSNumber + (id)numberWithInt:(int)val; @end )objc", @@ -1560,18 +1560,19 @@ TEST(WalkAST, ObjCBoxedExprInt) { {"-x", "objective-c"}); } - -TEST(WalkAST, ObjCBoxedExprCategory) { +TEST(WalkAST, ObjCBoxedExprStruct) { testWalk(R"objc( - @interface $implicit^NSNumber - @end - @interface $explicit^NSNumber (CustomCategory) - + (id)numberWithInt:(int)val; + struct __attribute__((objc_boxable)) Point { + int x, y; + }; + @interface $explicit^NSValue + + (id)valueWithBytes:(const void *)bytes objCType:(const char *)type; @end )objc", R"objc( void test() { - id x = ^@42; + struct Point p = {1, 2}; + id x = ^@(p); } )objc", {"-x", "objective-c"}); @@ -1579,7 +1580,7 @@ TEST(WalkAST, ObjCBoxedExprCategory) { TEST(WalkAST, ObjCArrayLiteral) { testWalk(R"objc( - @interface $implicit^NSArray + @interface $explicit^NSArray + (id)arrayWithObjects:(const id *)objects count:(unsigned long)cnt; @end )objc", @@ -1593,8 +1594,10 @@ TEST(WalkAST, ObjCArrayLiteral) { TEST(WalkAST, ObjCDictionaryLiteral) { testWalk(R"objc( - @interface $implicit^NSDictionary - + (id)dictionaryWithObjects:(const id *)objects forKeys:(const id *)keys count:(unsigned long)cnt; + @interface $explicit^NSDictionary + + (id)dictionaryWithObjects:(const id *)objects + forKeys:(const id *)keys + count:(unsigned long)cnt; @end )objc", R"objc( @@ -1607,7 +1610,7 @@ TEST(WalkAST, ObjCDictionaryLiteral) { TEST(WalkAST, ObjCStringLiteral) { testWalk(R"objc( - @interface $implicit^NSString + @interface $explicit^NSString @end )objc", R"objc( _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
