[clang] Detect a return value of Ref & RefPtr (PR #81580)
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)
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)
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)
@@ -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)
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)
@@ -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)
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)
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)
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)
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)
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)
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