Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ bool isRefType(const std::string &Name) {
}

bool isRetainPtr(const std::string &Name) {
return Name == "RetainPtr" || Name == "RetainPtrArc";
return Name == "RetainPtr" || Name == "RetainPtrArc" ||
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Maybe rename isRetainPtr to indicate its new functionality.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to isRetainPtrOrOSPtr.

Name == "OSObjectPtr" || Name == "OSObjectPtrArc";
}

bool isCheckedPtr(const std::string &Name) {
Expand Down Expand Up @@ -170,7 +171,8 @@ bool isCtorOfRetainPtr(const clang::FunctionDecl *F) {
const std::string &FunctionName = safeGetName(F);
return FunctionName == "RetainPtr" || FunctionName == "adoptNS" ||
FunctionName == "adoptCF" || FunctionName == "retainPtr" ||
FunctionName == "RetainPtrArc" || FunctionName == "adoptNSArc";
FunctionName == "RetainPtrArc" || FunctionName == "adoptNSArc" ||
FunctionName == "adoptOSObject" || FunctionName == "adoptOSObjectArc";
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Same as above - rename function to reflect the new functionality.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to isCtorOfRetainPtrOrOSPtr

}

bool isCtorOfSafePtr(const clang::FunctionDecl *F) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,11 @@ class RawPtrRefMemberChecker
auto *Desugared = PointeeType->getUnqualifiedDesugaredType();
if (!Desugared)
return nullptr;
auto *ObjCType = dyn_cast<ObjCInterfaceType>(Desugared);
if (!ObjCType)
return nullptr;
return ObjCType->getDecl();
if (auto *ObjCType = dyn_cast<ObjCInterfaceType>(Desugared))
return ObjCType->getDecl();
if (auto *ObjCType = dyn_cast<ObjCObjectType>(Desugared))
return ObjCType->getInterface();
return nullptr;
}

void visitObjCDecl(const ObjCContainerDecl *CD) const {
Expand Down Expand Up @@ -369,7 +370,7 @@ class NoUnretainedMemberChecker final : public RawPtrRefMemberChecker {
const char *typeName() const final { return "retainable type"; }

const char *invariant() const final {
return "member variables must be a RetainPtr";
return "member variables must be a RetainPtr or OSObjectPtr";
}

PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ class RetainPtrCtorAdoptChecker
}

bool isAdoptFnName(const std::string &Name) const {
return isAdoptNS(Name) || Name == "adoptCF" || Name == "adoptCFArc";
return isAdoptNS(Name) || Name == "adoptCF" || Name == "adoptCFArc" ||
Name == "adoptOSObject" || Name == "adoptOSObjectArc";
}

bool isAdoptNS(const std::string &Name) const {
Expand Down
14 changes: 0 additions & 14 deletions clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,6 @@

#include "mock-types.h"

namespace std {

template <typename T> struct remove_reference {
typedef T type;
};

template <typename T> struct remove_reference<T&> {
typedef T type;
};

template<typename T> typename remove_reference<T>::type&& move(T&& t);

} // namespace std

RefCountableAndCheckable* makeObj();
CheckedRef<RefCountableAndCheckable> makeObjChecked();
void someFunction(RefCountableAndCheckable*);
Expand Down
14 changes: 0 additions & 14 deletions clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,6 @@
#include "objc-mock-types.h"
#include "mock-system-header.h"

namespace std {

template <typename T> struct remove_reference {
typedef T type;
};

template <typename T> struct remove_reference<T&> {
typedef T type;
};

template<typename T> typename remove_reference<T>::type&& move(T&& t);

} // namespace std

typedef struct OpaqueJSString * JSStringRef;

class Obj;
Expand Down
19 changes: 19 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/mock-types.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
#ifndef std_move
#define std_move

namespace std {

template <typename T> struct remove_reference {
typedef T type;
};

template <typename T> struct remove_reference<T&> {
typedef T type;
};

template<typename T> typename remove_reference<T>::type&& move(T&& t);

}

#endif

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice job refactoring our common code!

#ifndef mock_types_1103988513531
#define mock_types_1103988513531

Expand Down
165 changes: 165 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
#ifndef std_move
#define std_move

namespace std {

template <typename T> struct remove_reference {
typedef T type;
};

template <typename T> struct remove_reference<T&> {
typedef T type;
};

template<typename T> typename remove_reference<T>::type&& move(T&& t);

}

#endif

@class NSString;
@class NSArray;
@class NSMutableArray;
Expand Down Expand Up @@ -157,6 +176,39 @@ __attribute__((objc_root_class))
- (void)doMoreWork:(OtherObj *)other;
@end

@protocol OS_dispatch_queue
@end

typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;

@protocol OS_dispatch_queue_attr
@end

typedef NSObject<OS_dispatch_queue_attr> *dispatch_queue_attr_t;

NS_RETURNS_RETAINED dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
const char *dispatch_queue_get_label(dispatch_queue_t queue);

namespace std {

template <typename StorageType>
void swap(StorageType& a, StorageType& b)
{
StorageType temp = static_cast<StorageType&&>(a);
a = static_cast<StorageType&&>(b);
b = static_cast<StorageType&&>(temp);
}

template <typename StorageType, typename ValueType>
StorageType exchange(StorageType& obj, ValueType& value)
{
StorageType returnValue = static_cast<StorageType&&>(obj);
obj = static_cast<StorageType&&>(value);
return returnValue;
}

}

namespace WTF {

void WTFCrash(void);
Expand Down Expand Up @@ -293,6 +345,117 @@ template<typename T> inline RetainPtr<T> retainPtr(T* ptr)
return ptr;
}

template<typename> class OSObjectPtr;
template<typename T> OSObjectPtr<T> adoptOSObject(T);

template<typename T> static inline void retainOSObject(T ptr)
{
#if !__has_feature(objc_arc)
[ptr retain];
#endif
}

template<typename T> static inline void releaseOSObject(T ptr)
{
#if !__has_feature(objc_arc)
[ptr release];
#endif
}

template<typename T> class OSObjectPtr {
public:
OSObjectPtr()
: m_ptr(nullptr)
{
}

~OSObjectPtr()
{
if (m_ptr)
releaseOSObject(m_ptr);
}

T get() const { return m_ptr; }

explicit operator bool() const { return m_ptr; }
bool operator!() const { return !m_ptr; }

OSObjectPtr(const OSObjectPtr& other)
: m_ptr(other.m_ptr)
{
if (m_ptr)
retainOSObject(m_ptr);
}

OSObjectPtr(OSObjectPtr&& other)
: m_ptr(std::move(other.m_ptr))
{
other.m_ptr = nullptr;
}

OSObjectPtr(T ptr)
: m_ptr(std::move(ptr))
{
if (m_ptr)
retainOSObject(m_ptr);
}

OSObjectPtr& operator=(const OSObjectPtr& other)
{
OSObjectPtr ptr = other;
swap(ptr);
return *this;
}

OSObjectPtr& operator=(OSObjectPtr&& other)
{
OSObjectPtr ptr = std::move(other);
swap(ptr);
return *this;
}

OSObjectPtr& operator=(decltype(nullptr))
{
if (m_ptr)
releaseOSObject(m_ptr);
m_ptr = nullptr;
return *this;
}

OSObjectPtr& operator=(T other)
{
OSObjectPtr ptr = std::move(other);
swap(ptr);
return *this;
}

void swap(OSObjectPtr& other)
{
std::swap(m_ptr, other.m_ptr);
}

T leakRef()
{
return std::exchange(m_ptr, nullptr);
}

friend OSObjectPtr adoptOSObject<T>(T);

private:
struct AdoptOSObject { };
OSObjectPtr(AdoptOSObject, T ptr)
: m_ptr(std::move(ptr))
{
}

T m_ptr;
};

template<typename T> inline OSObjectPtr<T> adoptOSObject(T ptr)
{
return OSObjectPtr<T> { typename OSObjectPtr<T>::AdoptOSObject { }, std::move(ptr) };
}

inline NSObject *bridge_cast(CFTypeRef object)
{
return (__bridge NSObject *)object;
Expand Down Expand Up @@ -455,6 +618,8 @@ using WTF::RetainPtr;
using WTF::adoptNS;
using WTF::adoptCF;
using WTF::retainPtr;
using WTF::OSObjectPtr;
using WTF::adoptOSObject;
using WTF::downcast;
using WTF::bridge_cast;
using WTF::bridge_id_cast;
Expand Down
3 changes: 0 additions & 3 deletions clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ T* addressof(T& arg);
template<typename T>
T&& forward(T& arg);

template<typename T>
T&& move( T&& t );

template<typename ToType, typename FromType>
ToType bit_cast(FromType from);

Expand Down
15 changes: 12 additions & 3 deletions clang/test/Analysis/Checkers/WebKit/unretained-call-args-arc.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

SomeObj *provide();
CFMutableArrayRef provide_cf();
dispatch_queue_t provide_os();
void someFunction();
CGImageRef provideImage();
NSString *stringForImage(CGImageRef);
Expand All @@ -14,6 +15,7 @@ void foo() {
[provide() doWork];
CFArrayAppendValue(provide_cf(), nullptr);
// expected-warning@-1{{Call argument for parameter 'theArray' is unretained and unsafe [alpha.webkit.UnretainedCallArgsChecker]}}
dispatch_queue_get_label(provide_os());
}

} // namespace raw_ptr
Expand All @@ -22,15 +24,17 @@ void foo() {

extern NSString * const SomeConstant;
extern CFDictionaryRef const SomeDictionary;
void doWork(NSString *str, CFDictionaryRef dict);
extern dispatch_queue_t const SomeDispatch;
void doWork(NSString *str, CFDictionaryRef dict, dispatch_queue_t dispatch);
void use_const_global() {
doWork(SomeConstant, SomeDictionary);
doWork(SomeConstant, SomeDictionary, SomeDispatch);
}

NSString *provide_str();
CFDictionaryRef provide_dict();
dispatch_queue_t provide_dispatch();
void use_const_local() {
doWork(provide_str(), provide_dict());
doWork(provide_str(), provide_dict(), provide_dispatch());
// expected-warning@-1{{Call argument for parameter 'dict' is unretained and unsafe}}
}

Expand Down Expand Up @@ -65,4 +69,9 @@ - (NSString *)convertImage {
RetainPtr<CGImageRef> image = [self createImage];
return stringForImage(image.get());
}

- (const char *)dispatchLabel {
OSObjectPtr obj = provide_os();
return dispatch_queue_get_label(obj.get());
}
@end
Loading