Skip to content

Conversation

@rniwa
Copy link
Contributor

@rniwa rniwa commented Feb 12, 2025

Added the support for annotating a constructor's argument with [[clang::noescape]].

We explicitly ignore CXXConstructExpr which is visited as a part of CallExpr so that construction of closures like Function, CompletionHandler, etc... don't result in a warning.

…n a constructor

Added the support for annotating a constructor's argument with [[clang::noescape]].

We explicitly ignore CXXConstructExpr which is visited as a part of CallExpr so that
construction of closures like Function, CompletionHandler, etc... don't result in a warning.
@rniwa rniwa requested review from haoNoQ and t-rasmud February 12, 2025 07:44
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:static analyzer labels Feb 12, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 12, 2025

@llvm/pr-subscribers-clang

Author: Ryosuke Niwa (rniwa)

Changes

Added the support for annotating a constructor's argument with [[clang::noescape]].

We explicitly ignore CXXConstructExpr which is visited as a part of CallExpr so that construction of closures like Function, CompletionHandler, etc... don't result in a warning.


Full diff: https://github.com/llvm/llvm-project/pull/126869.diff

2 Files Affected:

  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp (+25-1)
  • (modified) clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp (+4)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
index a56f48c83c660..972364a855eb4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
@@ -41,6 +41,7 @@ class UncountedLambdaCapturesChecker
       const UncountedLambdaCapturesChecker *Checker;
       llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
       llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
+      llvm::DenseSet<const CXXConstructExpr *> ConstructToIgnore;
       QualType ClsType;
 
       explicit LocalVisitor(const UncountedLambdaCapturesChecker *Checker)
@@ -106,6 +107,26 @@ class UncountedLambdaCapturesChecker
         return safeGetName(NsDecl) == "WTF" && safeGetName(Decl) == "switchOn";
       }
 
+      bool VisitCXXConstructExpr(CXXConstructExpr *CE) override {
+        if (ConstructToIgnore.contains(CE))
+          return true;
+        if (auto *Callee = CE->getConstructor()) {
+          unsigned ArgIndex = 0;
+          for (auto *Param : Callee->parameters()) {
+            if (ArgIndex >= CE->getNumArgs())
+              return true;
+            auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
+            if (auto *L = findLambdaInArg(Arg)) {
+              LambdasToIgnore.insert(L);
+              if (!Param->hasAttr<NoEscapeAttr>())
+                Checker->visitLambdaExpr(L, shouldCheckThis());
+            }
+            ++ArgIndex;
+          }
+        }
+        return true;
+      }
+
       bool VisitCallExpr(CallExpr *CE) override {
         checkCalleeLambda(CE);
         if (auto *Callee = CE->getDirectCallee()) {
@@ -143,8 +164,10 @@ class UncountedLambdaCapturesChecker
         auto *CtorArg = CE->getArg(0)->IgnoreParenCasts();
         if (!CtorArg)
           return nullptr;
-        if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg))
+        if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg)) {
+          ConstructToIgnore.insert(CE);
           return Lambda;
+        }
         auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
         if (!DRE)
           return nullptr;
@@ -157,6 +180,7 @@ class UncountedLambdaCapturesChecker
         TempExpr = dyn_cast<CXXBindTemporaryExpr>(Init->IgnoreParenCasts());
         if (!TempExpr)
           return nullptr;
+        ConstructToIgnore.insert(CE);
         return dyn_cast_or_null<LambdaExpr>(TempExpr->getSubExpr());
       }
 
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
index 4f4a960282253..62a8245db99b9 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
@@ -298,7 +298,11 @@ struct RefCountableWithLambdaCapturingThis {
     callLambda([&]() -> RefPtr<RefCountable> {
       return obj->next();
     });
+    WTF::HashMap<int, RefPtr<RefCountable>> anotherMap([&] {
+      return obj->next();
+    });
   }
+
 };
 
 struct NonRefCountableWithLambdaCapturingThis {

@llvmbot
Copy link
Member

llvmbot commented Feb 12, 2025

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Ryosuke Niwa (rniwa)

Changes

Added the support for annotating a constructor's argument with [[clang::noescape]].

We explicitly ignore CXXConstructExpr which is visited as a part of CallExpr so that construction of closures like Function, CompletionHandler, etc... don't result in a warning.


Full diff: https://github.com/llvm/llvm-project/pull/126869.diff

2 Files Affected:

  • (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp (+25-1)
  • (modified) clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp (+4)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
index a56f48c83c660..972364a855eb4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
@@ -41,6 +41,7 @@ class UncountedLambdaCapturesChecker
       const UncountedLambdaCapturesChecker *Checker;
       llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
       llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
+      llvm::DenseSet<const CXXConstructExpr *> ConstructToIgnore;
       QualType ClsType;
 
       explicit LocalVisitor(const UncountedLambdaCapturesChecker *Checker)
@@ -106,6 +107,26 @@ class UncountedLambdaCapturesChecker
         return safeGetName(NsDecl) == "WTF" && safeGetName(Decl) == "switchOn";
       }
 
+      bool VisitCXXConstructExpr(CXXConstructExpr *CE) override {
+        if (ConstructToIgnore.contains(CE))
+          return true;
+        if (auto *Callee = CE->getConstructor()) {
+          unsigned ArgIndex = 0;
+          for (auto *Param : Callee->parameters()) {
+            if (ArgIndex >= CE->getNumArgs())
+              return true;
+            auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
+            if (auto *L = findLambdaInArg(Arg)) {
+              LambdasToIgnore.insert(L);
+              if (!Param->hasAttr<NoEscapeAttr>())
+                Checker->visitLambdaExpr(L, shouldCheckThis());
+            }
+            ++ArgIndex;
+          }
+        }
+        return true;
+      }
+
       bool VisitCallExpr(CallExpr *CE) override {
         checkCalleeLambda(CE);
         if (auto *Callee = CE->getDirectCallee()) {
@@ -143,8 +164,10 @@ class UncountedLambdaCapturesChecker
         auto *CtorArg = CE->getArg(0)->IgnoreParenCasts();
         if (!CtorArg)
           return nullptr;
-        if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg))
+        if (auto *Lambda = dyn_cast<LambdaExpr>(CtorArg)) {
+          ConstructToIgnore.insert(CE);
           return Lambda;
+        }
         auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
         if (!DRE)
           return nullptr;
@@ -157,6 +180,7 @@ class UncountedLambdaCapturesChecker
         TempExpr = dyn_cast<CXXBindTemporaryExpr>(Init->IgnoreParenCasts());
         if (!TempExpr)
           return nullptr;
+        ConstructToIgnore.insert(CE);
         return dyn_cast_or_null<LambdaExpr>(TempExpr->getSubExpr());
       }
 
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
index 4f4a960282253..62a8245db99b9 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
@@ -298,7 +298,11 @@ struct RefCountableWithLambdaCapturingThis {
     callLambda([&]() -> RefPtr<RefCountable> {
       return obj->next();
     });
+    WTF::HashMap<int, RefPtr<RefCountable>> anotherMap([&] {
+      return obj->next();
+    });
   }
+
 };
 
 struct NonRefCountableWithLambdaCapturingThis {

if (ArgIndex >= CE->getNumArgs())
return true;
auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
if (auto *L = findLambdaInArg(Arg)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my understanding: Is the LambdaExpr not covered in VisitLambdaExpr? What's special about the expression being an argument to a constructor?

Copy link
Contributor Author

@rniwa rniwa Feb 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, so we wanna ignore lambda expressions that are passed to [[clang::noescape]] argument. The code in VisitCallExpr and now VisitCXXConstructExpr is there to detect this specific case, and then ignore the argument.

Copy link
Contributor

@t-rasmud t-rasmud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@rniwa
Copy link
Contributor Author

rniwa commented Feb 14, 2025

Thanks for the review!

@rniwa rniwa merged commit da6ac95 into llvm:main Feb 14, 2025
11 checks passed
@rniwa rniwa deleted the support-noescape-on-constructor branch February 14, 2025 21:49
rniwa added a commit to rniwa/llvm-project that referenced this pull request Feb 15, 2025
…n a constructor (llvm#126869)

Added the support for annotating a constructor's argument with
[[clang::noescape]].

We explicitly ignore CXXConstructExpr which is visited as a part of
CallExpr so that construction of closures like Function,
CompletionHandler, etc... don't result in a warning.
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Feb 24, 2025
…n a constructor (llvm#126869)

Added the support for annotating a constructor's argument with
[[clang::noescape]].

We explicitly ignore CXXConstructExpr which is visited as a part of
CallExpr so that construction of closures like Function,
CompletionHandler, etc... don't result in a warning.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:static analyzer clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants