Skip to content

Commit 765c075

Browse files
rniwagithub-actions[bot]
authored andcommitted
Automerge: [alpha.webkit.ForwardDeclChecker] Ignore unary operator when detecting a parameter (#160994)
This PR updates the forward declaration checker so that unary operator & and * will be ignored for the purpose of determining if a given function argument is also a function argument of the caller / call-site.
2 parents 305eb7f + e61e625 commit 765c075

File tree

5 files changed

+145
-16
lines changed

5 files changed

+145
-16
lines changed

clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,18 +263,43 @@ class ForwardDeclChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
263263
void visitCallArg(const Expr *Arg, const ParmVarDecl *Param,
264264
const Decl *DeclWithIssue) const {
265265
auto *ArgExpr = Arg->IgnoreParenCasts();
266-
if (auto *InnerCE = dyn_cast<CallExpr>(Arg)) {
267-
auto *InnerCallee = InnerCE->getDirectCallee();
268-
if (InnerCallee && InnerCallee->isInStdNamespace() &&
269-
safeGetName(InnerCallee) == "move" && InnerCE->getNumArgs() == 1) {
270-
ArgExpr = InnerCE->getArg(0);
271-
if (ArgExpr)
272-
ArgExpr = ArgExpr->IgnoreParenCasts();
266+
while (ArgExpr) {
267+
ArgExpr = ArgExpr->IgnoreParenCasts();
268+
if (auto *InnerCE = dyn_cast<CallExpr>(ArgExpr)) {
269+
auto *InnerCallee = InnerCE->getDirectCallee();
270+
if (InnerCallee && InnerCallee->isInStdNamespace() &&
271+
safeGetName(InnerCallee) == "move" && InnerCE->getNumArgs() == 1) {
272+
ArgExpr = InnerCE->getArg(0);
273+
continue;
274+
}
275+
}
276+
if (auto *UO = dyn_cast<UnaryOperator>(ArgExpr)) {
277+
auto OpCode = UO->getOpcode();
278+
if (OpCode == UO_Deref || OpCode == UO_AddrOf) {
279+
ArgExpr = UO->getSubExpr();
280+
continue;
281+
}
273282
}
283+
break;
274284
}
285+
286+
if (auto *MemberCallExpr = dyn_cast<CXXMemberCallExpr>(ArgExpr)) {
287+
if (isOwnerPtrType(MemberCallExpr->getObjectType()))
288+
return;
289+
}
290+
291+
if (auto *OpCE = dyn_cast<CXXOperatorCallExpr>(ArgExpr)) {
292+
auto *Method = dyn_cast_or_null<CXXMethodDecl>(OpCE->getDirectCallee());
293+
if (Method && isOwnerPtr(safeGetName(Method->getParent()))) {
294+
if (OpCE->getOperator() == OO_Star && OpCE->getNumArgs() == 1)
295+
return;
296+
}
297+
}
298+
275299
if (isNullPtr(ArgExpr) || isa<IntegerLiteral>(ArgExpr) ||
276300
isa<CXXDefaultArgExpr>(ArgExpr))
277301
return;
302+
278303
if (auto *DRE = dyn_cast<DeclRefExpr>(ArgExpr)) {
279304
if (auto *ValDecl = DRE->getDecl()) {
280305
if (isa<ParmVarDecl>(ValDecl))

clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ bool isCheckedPtr(const std::string &Name) {
138138
return Name == "CheckedPtr" || Name == "CheckedRef";
139139
}
140140

141+
bool isOwnerPtr(const std::string &Name) {
142+
return isRefType(Name) || isCheckedPtr(Name) || Name == "unique_ptr" ||
143+
Name == "UniqueRef" || Name == "LazyUniqueRef";
144+
}
145+
141146
bool isSmartPtrClass(const std::string &Name) {
142147
return isRefType(Name) || isCheckedPtr(Name) || isRetainPtrOrOSPtr(Name) ||
143148
Name == "WeakPtr" || Name == "WeakPtrFactory" ||
@@ -206,10 +211,7 @@ bool isRetainPtrOrOSPtrType(const clang::QualType T) {
206211
}
207212

208213
bool isOwnerPtrType(const clang::QualType T) {
209-
return isPtrOfType(T, [](auto Name) {
210-
return isRefType(Name) || isCheckedPtr(Name) || Name == "unique_ptr" ||
211-
Name == "UniqueRef" || Name == "LazyUniqueRef";
212-
});
214+
return isPtrOfType(T, [](auto Name) { return isOwnerPtr(Name); });
213215
}
214216

215217
std::optional<bool> isUncounted(const QualType T) {

clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ bool isCheckedPtr(const std::string &Name);
143143
/// \returns true if \p Name is RetainPtr or its variant, false if not.
144144
bool isRetainPtrOrOSPtr(const std::string &Name);
145145

146+
/// \returns true if \p Name is an owning smar pointer such as Ref, CheckedPtr,
147+
/// and unique_ptr.
148+
bool isOwnerPtr(const std::string &Name);
149+
146150
/// \returns true if \p Name is a smart pointer type name, false if not.
147151
bool isSmartPtrClass(const std::string &Name);
148152

clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
Obj* provide_obj_ptr();
1313
void receive_obj_ptr(Obj* p = nullptr);
14+
void receive_obj_ref(Obj&);
15+
void receive_obj_rref(Obj&&);
1416
sqlite3* open_db();
1517
void close_db(sqlite3*);
1618

@@ -38,6 +40,16 @@
3840
return obj;
3941
}
4042

43+
void opaque_call_arg(Obj* obj, Obj&& otherObj, const RefPtr<Obj>& safeObj, WeakPtr<Obj> weakObj, std::unique_ptr<Obj>& uniqObj) {
44+
receive_obj_ref(*obj);
45+
receive_obj_ptr(&*obj);
46+
receive_obj_rref(std::move(otherObj));
47+
receive_obj_ref(*safeObj.get());
48+
receive_obj_ptr(weakObj.get());
49+
// expected-warning@-1{{Call argument for parameter 'p' uses a forward declared type 'Obj *'}}
50+
receive_obj_ref(*uniqObj);
51+
}
52+
4153
Obj&& provide_obj_rval();
4254
void receive_obj_rval(Obj&& p);
4355

clang/test/Analysis/Checkers/WebKit/mock-types.h

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,23 @@ namespace std {
2525
template <typename T>
2626
class unique_ptr {
2727
private:
28-
T *t;
28+
void *t;
2929

3030
public:
3131
unique_ptr() : t(nullptr) { }
3232
unique_ptr(T *t) : t(t) { }
3333
~unique_ptr() {
3434
if (t)
35-
delete t;
35+
delete static_cast<T*>(t);
3636
}
3737
template <typename U> unique_ptr(unique_ptr<U>&& u)
3838
: t(u.t)
3939
{
4040
u.t = nullptr;
4141
}
42-
T *get() const { return t; }
43-
T *operator->() const { return t; }
44-
T &operator*() const { return *t; }
42+
T *get() const { return static_cast<T*>(t); }
43+
T *operator->() const { return get(); }
44+
T &operator*() const { return *get(); }
4545
unique_ptr &operator=(T *) { return *this; }
4646
explicit operator bool() const { return !!t; }
4747
};
@@ -313,4 +313,90 @@ class UniqueRef {
313313
UniqueRef &operator=(T &) { return *this; }
314314
};
315315

316+
class WeakPtrImpl {
317+
private:
318+
void* ptr { nullptr };
319+
mutable unsigned m_refCount { 0 };
320+
321+
template <typename U> friend class CanMakeWeakPtr;
322+
template <typename U> friend class WeakPtr;
323+
324+
public:
325+
template <typename T>
326+
static Ref<WeakPtrImpl> create(T& t)
327+
{
328+
return adoptRef(*new WeakPtrImpl(t));
329+
}
330+
331+
void ref() const { m_refCount++; }
332+
void deref() const {
333+
m_refCount--;
334+
if (!m_refCount)
335+
delete const_cast<WeakPtrImpl*>(this);
336+
}
337+
338+
template <typename T>
339+
T* get() { return static_cast<T*>(ptr); }
340+
operator bool() const { return !!ptr; }
341+
void clear() { ptr = nullptr; }
342+
343+
private:
344+
template <typename T>
345+
WeakPtrImpl(T* t)
346+
: ptr(static_cast<void*>(t))
347+
{ }
348+
};
349+
350+
template <typename T>
351+
class CanMakeWeakPtr {
352+
private:
353+
RefPtr<WeakPtrImpl> impl;
354+
355+
template <typename U> friend class CanMakeWeakPtr;
356+
template <typename U> friend class WeakPtr;
357+
358+
Ref<WeakPtrImpl> createWeakPtrImpl() {
359+
if (!impl)
360+
impl = WeakPtrImpl::create(static_cast<T>(*this));
361+
return *impl;
362+
}
363+
364+
public:
365+
~CanMakeWeakPtr() {
366+
if (!impl)
367+
return;
368+
impl->clear();
369+
impl = nullptr;
370+
}
371+
};
372+
373+
template <typename T>
374+
class WeakPtr {
375+
private:
376+
RefPtr<WeakPtrImpl> impl;
377+
378+
public:
379+
WeakPtr(T& t) {
380+
*this = t;
381+
}
382+
WeakPtr(T* t) {
383+
*this = t;
384+
}
385+
386+
template <typename U>
387+
WeakPtr<T> operator=(U& obj) {
388+
impl = obj.createWeakPtrImpl();
389+
}
390+
391+
template <typename U>
392+
WeakPtr<T> operator=(U* obj) {
393+
impl = obj ? obj->createWeakPtrImpl() : nullptr;
394+
}
395+
396+
T* get() {
397+
return impl ? impl->get<T>() : nullptr;
398+
}
399+
400+
};
401+
316402
#endif

0 commit comments

Comments
 (0)