[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-14 Thread Artem Dergachev via cfe-commits

https://github.com/haoNoQ closed https://github.com/llvm/llvm-project/pull/81580
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-14 Thread Artem Dergachev via cfe-commits

haoNoQ wrote:

Ok this needs a rebase after the other two PRs landed.

https://github.com/llvm/llvm-project/pull/81580
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread Artem Dergachev via cfe-commits

https://github.com/haoNoQ approved this pull request.

LGTM!

https://github.com/llvm/llvm-project/pull/81580
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread Ryosuke Niwa via cfe-commits


@@ -118,6 +118,26 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
  || FunctionName == "Identifier";
 }
 
+bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
+  assert(F);
+  auto *type = F->getReturnType().getTypePtrOrNull();
+  while (type) {
+if (auto *elaboratedT = dyn_cast(type)) {
+  type = elaboratedT->desugar().getTypePtrOrNull();
+  continue;
+}
+if (auto *specialT = dyn_cast(type)) {

rniwa wrote:

Sounds good. Fixed.

https://github.com/llvm/llvm-project/pull/81580
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread Ryosuke Niwa via cfe-commits

https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81580

>From 24fc75756094d36e72c69805c9d476d8144ed869 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa 
Date: Tue, 13 Feb 2024 00:35:36 -0800
Subject: [PATCH 1/2] [alpha.webkit.UncountedCallArgsChecker] Detect a return
 value of `Ref` & `RefPtr`

This PR makes the checker not emit warning when a function is called with a 
return value
of another function when the return value is of type `Ref` or `RefPtr`.
---
 .../Checkers/WebKit/ASTUtils.cpp  |  6 +
 .../Checkers/WebKit/PtrTypesSemantics.cpp | 20 
 .../Checkers/WebKit/PtrTypesSemantics.h   |  3 +++
 .../call-args-protected-return-value.cpp  | 23 +++
 .../Analysis/Checkers/WebKit/mock-types.h |  1 +
 5 files changed, 53 insertions(+)
 create mode 100644 
clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 4526fac64735bf..b76c0551c77bb0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -19,6 +19,10 @@ namespace clang {
 std::pair
 tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
   while (E) {
+if (auto *tempExpr = dyn_cast(E)) {
+  E = tempExpr->getSubExpr();
+  continue;
+}
 if (auto *cast = dyn_cast(E)) {
   if (StopAtFirstRefCountedObj) {
 if (auto *ConversionFunc =
@@ -62,6 +66,8 @@ tryToFindPtrOrigin(const Expr *E, bool 
StopAtFirstRefCountedObj) {
   E = call->getArg(0);
   continue;
 }
+if (isReturnValueRefCounted(callee))
+  return {E, true};
 
 if (isPtrConversion(callee)) {
   E = call->getArg(0);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index d2b66341058000..70c94dd0e960ab 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -118,6 +118,26 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
  || FunctionName == "Identifier";
 }
 
+bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
+  assert(F);
+  auto *type = F->getReturnType().getTypePtrOrNull();
+  while (type) {
+if (auto *elaboratedT = dyn_cast(type)) {
+  type = elaboratedT->desugar().getTypePtrOrNull();
+  continue;
+}
+if (auto *specialT = dyn_cast(type)) {
+  if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) {
+auto name = decl->getNameAsString();
+return name == "Ref" || name == "RefPtr";
+  }
+  return false;
+}
+return false;
+  }
+  return false;
+}
+
 std::optional isUncounted(const CXXRecordDecl* Class)
 {
   // Keep isRefCounted first as it's cheaper.
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 45b21cc0918443..c2c5b74442ba43 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -50,6 +50,9 @@ std::optional isUncountedPtr(const clang::Type* T);
 /// false if not.
 bool isCtorOfRefCounted(const clang::FunctionDecl *F);
 
+/// \returns true if \p F returns a ref-counted object, false if not.
+bool isReturnValueRefCounted(const clang::FunctionDecl *F);
+
 /// \returns true if \p M is getter of a ref-counted class, false if not.
 std::optional isGetterOfRefCounted(const clang::CXXMethodDecl* Method);
 
diff --git 
a/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp 
b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp
new file mode 100644
index 00..1c4b3df211b1e3
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+class RefCounted {
+public:
+  void ref();
+  void deref();
+};
+
+class Object {
+public:
+  void someFunction(RefCounted&);
+};
+
+RefPtr object();
+RefPtr protectedTargetObject();
+
+void testFunction() {
+  if (RefPtr obj = object())
+obj->someFunction(*protectedTargetObject());
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h 
b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 5f570b8bee8cb8..814e0944145992 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -20,6 +20,7 @@ template  struct RefPtr {
   T *operator->() { return t; }
   T *() { return *t; }
   RefPtr =(T *) { return *this; }
+  operator bool() { return t; }
 };
 
 template  bool operator==(const RefPtr &, const 

[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread Artem Dergachev via cfe-commits


@@ -118,6 +118,26 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
  || FunctionName == "Identifier";
 }
 
+bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
+  assert(F);
+  auto *type = F->getReturnType().getTypePtrOrNull();
+  while (type) {
+if (auto *elaboratedT = dyn_cast(type)) {
+  type = elaboratedT->desugar().getTypePtrOrNull();
+  continue;
+}
+if (auto *specialT = dyn_cast(type)) {

haoNoQ wrote:

`.getTypePtrOrNull()` can be dropped here as well:
```suggestion
  QualType type = F->getReturnType();
  while (!type.isNull()) {
if (auto *elaboratedT = type->getAs()) {
  type = elaboratedT->desugar();
  continue;
}
if (auto *specialT = type->getAs()) {
```

https://github.com/llvm/llvm-project/pull/81580
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread Ryosuke Niwa via cfe-commits

https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81580

>From 24fc75756094d36e72c69805c9d476d8144ed869 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa 
Date: Tue, 13 Feb 2024 00:35:36 -0800
Subject: [PATCH] [alpha.webkit.UncountedCallArgsChecker] Detect a return value
 of `Ref` & `RefPtr`

This PR makes the checker not emit warning when a function is called with a 
return value
of another function when the return value is of type `Ref` or `RefPtr`.
---
 .../Checkers/WebKit/ASTUtils.cpp  |  6 +
 .../Checkers/WebKit/PtrTypesSemantics.cpp | 20 
 .../Checkers/WebKit/PtrTypesSemantics.h   |  3 +++
 .../call-args-protected-return-value.cpp  | 23 +++
 .../Analysis/Checkers/WebKit/mock-types.h |  1 +
 5 files changed, 53 insertions(+)
 create mode 100644 
clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 4526fac64735bf..b76c0551c77bb0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -19,6 +19,10 @@ namespace clang {
 std::pair
 tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
   while (E) {
+if (auto *tempExpr = dyn_cast(E)) {
+  E = tempExpr->getSubExpr();
+  continue;
+}
 if (auto *cast = dyn_cast(E)) {
   if (StopAtFirstRefCountedObj) {
 if (auto *ConversionFunc =
@@ -62,6 +66,8 @@ tryToFindPtrOrigin(const Expr *E, bool 
StopAtFirstRefCountedObj) {
   E = call->getArg(0);
   continue;
 }
+if (isReturnValueRefCounted(callee))
+  return {E, true};
 
 if (isPtrConversion(callee)) {
   E = call->getArg(0);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index d2b66341058000..70c94dd0e960ab 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -118,6 +118,26 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
  || FunctionName == "Identifier";
 }
 
+bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
+  assert(F);
+  auto *type = F->getReturnType().getTypePtrOrNull();
+  while (type) {
+if (auto *elaboratedT = dyn_cast(type)) {
+  type = elaboratedT->desugar().getTypePtrOrNull();
+  continue;
+}
+if (auto *specialT = dyn_cast(type)) {
+  if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) {
+auto name = decl->getNameAsString();
+return name == "Ref" || name == "RefPtr";
+  }
+  return false;
+}
+return false;
+  }
+  return false;
+}
+
 std::optional isUncounted(const CXXRecordDecl* Class)
 {
   // Keep isRefCounted first as it's cheaper.
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 45b21cc0918443..c2c5b74442ba43 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -50,6 +50,9 @@ std::optional isUncountedPtr(const clang::Type* T);
 /// false if not.
 bool isCtorOfRefCounted(const clang::FunctionDecl *F);
 
+/// \returns true if \p F returns a ref-counted object, false if not.
+bool isReturnValueRefCounted(const clang::FunctionDecl *F);
+
 /// \returns true if \p M is getter of a ref-counted class, false if not.
 std::optional isGetterOfRefCounted(const clang::CXXMethodDecl* Method);
 
diff --git 
a/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp 
b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp
new file mode 100644
index 00..1c4b3df211b1e3
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+class RefCounted {
+public:
+  void ref();
+  void deref();
+};
+
+class Object {
+public:
+  void someFunction(RefCounted&);
+};
+
+RefPtr object();
+RefPtr protectedTargetObject();
+
+void testFunction() {
+  if (RefPtr obj = object())
+obj->someFunction(*protectedTargetObject());
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h 
b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 5f570b8bee8cb8..814e0944145992 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -20,6 +20,7 @@ template  struct RefPtr {
   T *operator->() { return t; }
   T *() { return *t; }
   RefPtr =(T *) { return *this; }
+  operator bool() { return t; }
 };
 
 template  bool operator==(const RefPtr &, const 

[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread Ryosuke Niwa via cfe-commits

https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81580

>From 478c7d2c0bb902b829d522fc483e68b8e36489ea Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa 
Date: Tue, 13 Feb 2024 00:35:36 -0800
Subject: [PATCH] [alpha.webkit.UncountedCallArgsChecker] Detect a return value
 of `Ref` & `RefPtr`

This PR makes the checker not emit warning when a function is called with a 
return value
of another function when the return value is of type `Ref` or `RefPtr`.
---
 .../Checkers/WebKit/ASTUtils.cpp  |  6 +
 .../Checkers/WebKit/PtrTypesSemantics.cpp | 20 
 .../Checkers/WebKit/PtrTypesSemantics.h   |  3 +++
 .../call-args-protected-return-value.cpp  | 23 +++
 .../Analysis/Checkers/WebKit/mock-types.h |  1 +
 5 files changed, 53 insertions(+)
 create mode 100644 
clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 4526fac64735bf..b76c0551c77bb0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -19,6 +19,10 @@ namespace clang {
 std::pair
 tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
   while (E) {
+if (auto *tempExpr = dyn_cast(E)) {
+  E = tempExpr->getSubExpr();
+  continue;
+}
 if (auto *cast = dyn_cast(E)) {
   if (StopAtFirstRefCountedObj) {
 if (auto *ConversionFunc =
@@ -62,6 +66,8 @@ tryToFindPtrOrigin(const Expr *E, bool 
StopAtFirstRefCountedObj) {
   E = call->getArg(0);
   continue;
 }
+if (isReturnValueRefCounted(callee))
+  return {E, true};
 
 if (isPtrConversion(callee)) {
   E = call->getArg(0);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index d2b66341058000..377c2b9376c1b9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -118,6 +118,26 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
  || FunctionName == "Identifier";
 }
 
+bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
+  assert(F);
+  auto *type = F->getReturnType().getTypePtrOrNull();
+  while (type) {
+if (auto *elaboratedT = dyn_cast(type)) {
+  type = elaboratedT->desugar().getTypePtrOrNull();
+  continue;  
+}
+if (auto *specialT = dyn_cast(type)) {
+  if (auto* decl = specialT->getTemplateName().getAsTemplateDecl()) {
+auto name = decl->getNameAsString();
+return name == "Ref" || name == "RefPtr";
+  }
+  return false;
+}
+return false;
+  }
+  return false;
+}
+
 std::optional isUncounted(const CXXRecordDecl* Class)
 {
   // Keep isRefCounted first as it's cheaper.
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 45b21cc0918443..c2c5b74442ba43 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -50,6 +50,9 @@ std::optional isUncountedPtr(const clang::Type* T);
 /// false if not.
 bool isCtorOfRefCounted(const clang::FunctionDecl *F);
 
+/// \returns true if \p F returns a ref-counted object, false if not.
+bool isReturnValueRefCounted(const clang::FunctionDecl *F);
+
 /// \returns true if \p M is getter of a ref-counted class, false if not.
 std::optional isGetterOfRefCounted(const clang::CXXMethodDecl* Method);
 
diff --git 
a/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp 
b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp
new file mode 100644
index 00..1c4b3df211b1e3
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+class RefCounted {
+public:
+  void ref();
+  void deref();
+};
+
+class Object {
+public:
+  void someFunction(RefCounted&);
+};
+
+RefPtr object();
+RefPtr protectedTargetObject();
+
+void testFunction() {
+  if (RefPtr obj = object())
+obj->someFunction(*protectedTargetObject());
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h 
b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 5f570b8bee8cb8..814e0944145992 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -20,6 +20,7 @@ template  struct RefPtr {
   T *operator->() { return t; }
   T *() { return *t; }
   RefPtr =(T *) { return *this; }
+  operator bool() { return t; }
 };
 
 template  bool operator==(const RefPtr &, 

[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread Ryosuke Niwa via cfe-commits

https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81580

>From 51fb3aa575c4509d4b4199d16d10e05281f911ac Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa 
Date: Tue, 13 Feb 2024 00:35:36 -0800
Subject: [PATCH] [alpha.webkit.UncountedCallArgsChecker] Detect a return value
 of Ref & RefPtr

This PR makes the checker not emit warning when a function is called with a 
return value
of another function when the return value is of type Ref or RefPtr.
---
 .../Checkers/WebKit/ASTUtils.cpp  |  6 +
 .../Checkers/WebKit/PtrTypesSemantics.cpp | 20 
 .../Checkers/WebKit/PtrTypesSemantics.h   |  3 +++
 .../call-args-protected-return-value.cpp  | 23 +++
 .../Analysis/Checkers/WebKit/mock-types.h |  1 +
 5 files changed, 53 insertions(+)
 create mode 100644 
clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 4526fac64735bf..b76c0551c77bb0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -19,6 +19,10 @@ namespace clang {
 std::pair
 tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
   while (E) {
+if (auto *tempExpr = dyn_cast(E)) {
+  E = tempExpr->getSubExpr();
+  continue;
+}
 if (auto *cast = dyn_cast(E)) {
   if (StopAtFirstRefCountedObj) {
 if (auto *ConversionFunc =
@@ -62,6 +66,8 @@ tryToFindPtrOrigin(const Expr *E, bool 
StopAtFirstRefCountedObj) {
   E = call->getArg(0);
   continue;
 }
+if (isReturnValueRefCounted(callee))
+  return {E, true};
 
 if (isPtrConversion(callee)) {
   E = call->getArg(0);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index d2b66341058000..377c2b9376c1b9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -118,6 +118,26 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
  || FunctionName == "Identifier";
 }
 
+bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
+  assert(F);
+  auto *type = F->getReturnType().getTypePtrOrNull();
+  while (type) {
+if (auto *elaboratedT = dyn_cast(type)) {
+  type = elaboratedT->desugar().getTypePtrOrNull();
+  continue;  
+}
+if (auto *specialT = dyn_cast(type)) {
+  if (auto* decl = specialT->getTemplateName().getAsTemplateDecl()) {
+auto name = decl->getNameAsString();
+return name == "Ref" || name == "RefPtr";
+  }
+  return false;
+}
+return false;
+  }
+  return false;
+}
+
 std::optional isUncounted(const CXXRecordDecl* Class)
 {
   // Keep isRefCounted first as it's cheaper.
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 45b21cc0918443..c2c5b74442ba43 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -50,6 +50,9 @@ std::optional isUncountedPtr(const clang::Type* T);
 /// false if not.
 bool isCtorOfRefCounted(const clang::FunctionDecl *F);
 
+/// \returns true if \p F returns a ref-counted object, false if not.
+bool isReturnValueRefCounted(const clang::FunctionDecl *F);
+
 /// \returns true if \p M is getter of a ref-counted class, false if not.
 std::optional isGetterOfRefCounted(const clang::CXXMethodDecl* Method);
 
diff --git 
a/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp 
b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp
new file mode 100644
index 00..1c4b3df211b1e3
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
+// expected-no-diagnostics
+
+#include "mock-types.h"
+
+class RefCounted {
+public:
+  void ref();
+  void deref();
+};
+
+class Object {
+public:
+  void someFunction(RefCounted&);
+};
+
+RefPtr object();
+RefPtr protectedTargetObject();
+
+void testFunction() {
+  if (RefPtr obj = object())
+obj->someFunction(*protectedTargetObject());
+}
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h 
b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 5f570b8bee8cb8..814e0944145992 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -20,6 +20,7 @@ template  struct RefPtr {
   T *operator->() { return t; }
   T *() { return *t; }
   RefPtr =(T *) { return *this; }
+  operator bool() { return t; }
 };
 
 template  bool operator==(const RefPtr &, const RefPtr 

[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff 535da10842c7309e9eeaf9828cf6bb034fecaf16 
a781c46e5db132e31816efd7bd475d6af157f256 -- 
clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp 
clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp 
clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h 
clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp 
clang/test/Analysis/Checkers/WebKit/mock-types.h 
clang/test/Analysis/Checkers/WebKit/call-args-safe-functions.cpp
``





View the diff from clang-format here.


``diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 9e1035ac13..e9b1a4d09c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -124,10 +124,10 @@ bool isReturnValueRefCounted(const clang::FunctionDecl 
*F) {
   while (type) {
 if (auto *elaboratedT = dyn_cast(type)) {
   type = elaboratedT->desugar().getTypePtrOrNull();
-  continue;  
+  continue;
 }
 if (auto *specialT = dyn_cast(type)) {
-  if (auto* decl = specialT->getTemplateName().getAsTemplateDecl()) {
+  if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) {
 auto name = decl->getNameAsString();
 return name == "Ref" || name == "RefPtr";
   }

``




https://github.com/llvm/llvm-project/pull/81580
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Ryosuke Niwa (rniwa)


Changes

This PR makes the checker not emit warning when a function is called with a 
return value of another function when the return value is of type RefT 
or RefPtrT.

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


7 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp (+6) 
- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
(+23-2) 
- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h (+3) 
- (modified) 
clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp (+6-5) 
- (added) 
clang/test/Analysis/Checkers/WebKit/call-args-protected-return-value.cpp (+23) 
- (renamed) clang/test/Analysis/Checkers/WebKit/call-args-safe-functions.cpp 
(+21) 
- (modified) clang/test/Analysis/Checkers/WebKit/mock-types.h (+1) 


``diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 4526fac64735bf..b76c0551c77bb0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -19,6 +19,10 @@ namespace clang {
 std::pair
 tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
   while (E) {
+if (auto *tempExpr = dyn_cast(E)) {
+  E = tempExpr->getSubExpr();
+  continue;
+}
 if (auto *cast = dyn_cast(E)) {
   if (StopAtFirstRefCountedObj) {
 if (auto *ConversionFunc =
@@ -62,6 +66,8 @@ tryToFindPtrOrigin(const Expr *E, bool 
StopAtFirstRefCountedObj) {
   E = call->getArg(0);
   continue;
 }
+if (isReturnValueRefCounted(callee))
+  return {E, true};
 
 if (isPtrConversion(callee)) {
   E = call->getArg(0);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index d2b66341058000..9e1035ac13ce31 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -118,6 +118,26 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
  || FunctionName == "Identifier";
 }
 
+bool isReturnValueRefCounted(const clang::FunctionDecl *F) {
+  assert(F);
+  auto *type = F->getReturnType().getTypePtrOrNull();
+  while (type) {
+if (auto *elaboratedT = dyn_cast(type)) {
+  type = elaboratedT->desugar().getTypePtrOrNull();
+  continue;  
+}
+if (auto *specialT = dyn_cast(type)) {
+  if (auto* decl = specialT->getTemplateName().getAsTemplateDecl()) {
+auto name = decl->getNameAsString();
+return name == "Ref" || name == "RefPtr";
+  }
+  return false;
+}
+return false;
+  }
+  return false;
+}
+
 std::optional isUncounted(const CXXRecordDecl* Class)
 {
   // Keep isRefCounted first as it's cheaper.
@@ -192,8 +212,9 @@ bool isPtrConversion(const FunctionDecl *F) {
   // FIXME: check # of params == 1
   const auto FunctionName = safeGetName(F);
   if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
-  FunctionName == "dynamicDowncast"
-  || FunctionName == "downcast" || FunctionName == "bitwise_cast")
+  FunctionName == "dynamicDowncast" || FunctionName == "downcast" ||
+  FunctionName == "checkedDowncast" ||
+  FunctionName == "uncheckedDowncast" || FunctionName == "bitwise_cast")
 return true;
 
   return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 45b21cc0918443..c2c5b74442ba43 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -50,6 +50,9 @@ std::optional isUncountedPtr(const clang::Type* T);
 /// false if not.
 bool isCtorOfRefCounted(const clang::FunctionDecl *F);
 
+/// \returns true if \p F returns a ref-counted object, false if not.
+bool isReturnValueRefCounted(const clang::FunctionDecl *F);
+
 /// \returns true if \p M is getter of a ref-counted class, false if not.
 std::optional isGetterOfRefCounted(const clang::CXXMethodDecl* Method);
 
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
index 31ccae8b097b89..cc4585a0b0eeff 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
@@ -148,13 +148,14 @@ class UncountedCallArgsChecker
 
 auto name = safeGetName(Callee);
 if (name == "adoptRef" || name == "getPtr" || name == "WeakPtr" ||
-name == "dynamicDowncast" || name == "downcast" || name == 
"bitwise_cast" ||
-name == "is" || name == "equal" || name == "hash" ||
-name == "isType"
+

[clang] Detect a return value of Ref & RefPtr (PR #81580)

2024-02-13 Thread Ryosuke Niwa via cfe-commits

https://github.com/rniwa created https://github.com/llvm/llvm-project/pull/81580

This PR makes the checker not emit warning when a function is called with a 
return value of another function when the return value is of type Ref or 
RefPtr.

>From 52b6e959d69a96704ec2a403131627049a782352 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa 
Date: Mon, 12 Feb 2024 12:31:37 -0800
Subject: [PATCH 1/2] [alpha.webkit.UncountedCallArgsChecker] Add a few more
 safe functions to call.

Added checkedDowncast, uncheckedDowncast, & toString as safe functions to call.
---
 .../Checkers/WebKit/PtrTypesSemantics.cpp |  5 +++--
 .../WebKit/UncountedCallArgsChecker.cpp   | 11 +-
 ...ncast.cpp => call-args-safe-functions.cpp} | 21 +++
 3 files changed, 30 insertions(+), 7 deletions(-)
 rename clang/test/Analysis/Checkers/WebKit/{call-args-dynamic-downcast.cpp => 
call-args-safe-functions.cpp} (55%)

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index d2b66341058000..c4a78da25438be 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -192,8 +192,9 @@ bool isPtrConversion(const FunctionDecl *F) {
   // FIXME: check # of params == 1
   const auto FunctionName = safeGetName(F);
   if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
-  FunctionName == "dynamicDowncast"
-  || FunctionName == "downcast" || FunctionName == "bitwise_cast")
+  FunctionName == "dynamicDowncast" || FunctionName == "downcast" ||
+  FunctionName == "checkedDowncast" ||
+  FunctionName == "uncheckedDowncast" || FunctionName == "bitwise_cast")
 return true;
 
   return false;
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
index 31ccae8b097b89..cc4585a0b0eeff 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
@@ -148,13 +148,14 @@ class UncountedCallArgsChecker
 
 auto name = safeGetName(Callee);
 if (name == "adoptRef" || name == "getPtr" || name == "WeakPtr" ||
-name == "dynamicDowncast" || name == "downcast" || name == 
"bitwise_cast" ||
-name == "is" || name == "equal" || name == "hash" ||
-name == "isType"
+name == "dynamicDowncast" || name == "downcast" ||
+name == "checkedDowncast" || name == "uncheckedDowncast" ||
+name == "bitwise_cast" || name == "is" || name == "equal" ||
+name == "hash" || name == "isType" ||
 // FIXME: Most/all of these should be implemented via attributes.
-|| name == "equalIgnoringASCIICase" ||
+name == "equalIgnoringASCIICase" ||
 name == "equalIgnoringASCIICaseCommon" ||
-name == "equalIgnoringNullity")
+name == "equalIgnoringNullity" || name == "toString")
   return true;
 
 return false;
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-dynamic-downcast.cpp 
b/clang/test/Analysis/Checkers/WebKit/call-args-safe-functions.cpp
similarity index 55%
rename from clang/test/Analysis/Checkers/WebKit/call-args-dynamic-downcast.cpp
rename to clang/test/Analysis/Checkers/WebKit/call-args-safe-functions.cpp
index 28156623d9a0fd..a87446564870cd 100644
--- a/clang/test/Analysis/Checkers/WebKit/call-args-dynamic-downcast.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-safe-functions.cpp
@@ -23,13 +23,34 @@ class OtherObject {
 Derived* obj();
 };
 
+class String {
+};
+
 template
 inline Target* dynamicDowncast(Source* source)
 {
 return static_cast(source);
 }
 
+template
+inline Target* checkedDowncast(Source* source)
+{
+return static_cast(source);
+}
+
+template
+inline Target* uncheckedDowncast(Source* source)
+{
+return static_cast(source);
+}
+
+template
+String toString(const Types&... values);
+
 void foo(OtherObject* other)
 {
 dynamicDowncast(other->obj());
+checkedDowncast(other->obj());
+uncheckedDowncast(other->obj());
+toString(other->obj());
 }

>From a781c46e5db132e31816efd7bd475d6af157f256 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa 
Date: Tue, 13 Feb 2024 00:35:36 -0800
Subject: [PATCH 2/2] [alpha.webkit.UncountedCallArgsChecker] Detect a return
 value of Ref & RefPtr

This PR makes the checker not emit warning when a function is called with a 
return value
of another function when the return value is of type Ref or RefPtr.
---
 .../Checkers/WebKit/ASTUtils.cpp  |  6 +
 .../Checkers/WebKit/PtrTypesSemantics.cpp | 20 
 .../Checkers/WebKit/PtrTypesSemantics.h   |  3 +++
 .../call-args-protected-return-value.cpp  | 23 +++
 .../Analysis/Checkers/WebKit/mock-types.h |  1 +
 5 files changed, 53 insertions(+)
 create mode 100644