This patch includes a conceptually simple, but very intrusive/pervasive change.
The idea is to segregate Objective-C "object" pointers from general C pointers (utilizing the recently added ObjCObjectPointerType). The fun starts in Sema::GetTypeForDeclarator(), where "SomeInterface *" is now represented by a single AST node (rather than a PointerType whose Pointee is an ObjCInterfaceType). Since a significant amount of code assumed ObjC object pointers where based on C pointers/structs, this patch is very tedious. It should also explain why it is hard to accomplish this in smaller, self-contained patches.
This patch does most of the "heavy lifting" related to moving from PointerType->ObjCObjectPointerType. It doesn't include all potential "cleanups". The good news is additional cleanups can be done later (some are noted in the code). This patch is so large that I didn't want to include any changes that are purely aesthetic.
By making the ObjC types truly built-in, they are much easier to work with (and require fewer "hacks"). For example, there is no need for ASTContext::isObjCIdStructType() or ASTContext::isObjCClassStructType()! We believe this change (and the follow-up cleanups) will pay dividends over time.
Given the amount of code change, I do expect some fallout from this change (though it does pass all of the clang tests). If you notice any problems, please let us know asap! Thanks.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75314 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index aa85769..b454a36 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -31,26 +31,21 @@
using namespace clang;
-static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
- Expr* Receiver = ME->getReceiver();
+static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
+ const Expr* Receiver = ME->getReceiver();
if (!Receiver)
return NULL;
- QualType X = Receiver->getType();
-
- if (X->isPointerType()) {
- Type* TP = X.getTypePtr();
- const PointerType* T = TP->getAsPointerType();
- return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
- }
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAsObjCObjectPointerType())
+ return PT->getInterfaceType();
- // FIXME: Support ObjCQualifiedIdType?
return NULL;
}
-static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
- ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
+ const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
: NULL;
}
@@ -67,7 +62,7 @@
BugReporter& BR;
ASTContext &Ctx;
- bool isNSString(ObjCInterfaceType* T, const char* suffix);
+ bool isNSString(const ObjCInterfaceType *T, const char* suffix);
bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
void Warn(NodeTy* N, Expr* E, const std::string& s);
@@ -114,7 +109,7 @@
ObjCMessageExpr* ME =
cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
- ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+ const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
if (!ReceiverType)
return false;
@@ -129,8 +124,7 @@
name += 2;
- // FIXME: Make all of this faster.
-
+ // FIXME: Make all of this faster.
if (isNSString(ReceiverType, name))
return AuditNSString(N, ME);
@@ -163,9 +157,8 @@
// NSString checking.
//===----------------------------------------------------------------------===//
-bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
- const char* suffix) {
-
+bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T,
+ const char* suffix) {
return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
}
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index c74668c..1cfd783 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -547,14 +547,12 @@
return I == M.end() ? M.find(ObjCSummaryKey(S)) : I;
}
- ObjCInterfaceDecl* getReceiverDecl(Expr* E) {
-
- const PointerType* PT = E->getType()->getAsPointerType();
- if (!PT) return 0;
-
- ObjCInterfaceType* OI = dyn_cast<ObjCInterfaceType>(PT->getPointeeType());
-
- return OI ? OI->getDecl() : 0;
+ const ObjCInterfaceDecl* getReceiverDecl(Expr* E) {
+ if (const ObjCObjectPointerType* PT =
+ E->getType()->getAsObjCObjectPointerType())
+ return PT->getInterfaceDecl();
+
+ return NULL;
}
iterator end() { return M.end(); }
@@ -564,7 +562,7 @@
Selector S = ME->getSelector();
if (Expr* Receiver = ME->getReceiver()) {
- ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
+ const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
}
@@ -886,20 +884,20 @@
if (!Ctx.isObjCObjectPointerType(Ty))
return false;
- // We assume that id<..>, id, and "Class" all represent tracked objects.
- const PointerType *PT = Ty->getAsPointerType();
- if (PT == 0)
+ const ObjCObjectPointerType *PT = Ty->getAsObjCObjectPointerType();
+
+ // Can be true for objects with the 'NSObject' attribute.
+ if (!PT)
return true;
-
- const ObjCInterfaceType *OT = PT->getPointeeType()->getAsObjCInterfaceType();
+
+ // We assume that id<..>, id, and "Class" all represent tracked objects.
+ if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
+ PT->isObjCClassType())
+ return true;
- // We assume that id<..>, id, and "Class" all represent tracked objects.
- if (!OT)
- return true;
-
// Does the interface subclass NSObject?
// FIXME: We can memoize here if this gets too expensive.
- ObjCInterfaceDecl* ID = OT->getDecl();
+ const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
// Assume that anything declared with a forward declaration and no
// @interface subclasses NSObject.
@@ -908,7 +906,6 @@
IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
-
for ( ; ID ; ID = ID->getSuperClass())
if (ID->getIdentifier() == NSObjectII)
return true;
@@ -977,7 +974,7 @@
case 17:
// Handle: id NSMakeCollectable(CFTypeRef)
if (!memcmp(FName, "NSMakeCollectable", 17)) {
- S = (RetTy == Ctx.getObjCIdType())
+ S = (RetTy->isObjCIdType())
? getUnarySummary(FT, cfmakecollectable)
: getPersistentStopSummary();
}
@@ -2726,34 +2723,26 @@
/// While the the return type can be queried directly from RetEx, when
/// invoking class methods we augment to the return type to be that of
/// a pointer to the class (as opposed it just being id).
-static QualType GetReturnType(Expr* RetE, ASTContext& Ctx) {
-
+static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
QualType RetTy = RetE->getType();
-
- // FIXME: We aren't handling id<...>.
- const PointerType* PT = RetTy->getAsPointerType();
- if (!PT)
- return RetTy;
-
- // If RetEx is not a message expression just return its type.
- // If RetEx is a message expression, return its types if it is something
+ // If RetE is not a message expression just return its type.
+ // If RetE is a message expression, return its types if it is something
/// more specific than id.
+ if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
+ if (const ObjCObjectPointerType *PT = RetTy->getAsObjCObjectPointerType())
+ if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() ||
+ PT->isObjCClassType()) {
+ // At this point we know the return type of the message expression is
+ // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
+ // is a call to a class method whose type we can resolve. In such
+ // cases, promote the return type to XXX* (where XXX is the class).
+ const ObjCInterfaceDecl *D = ME->getClassInfo().first;
+ return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
+ }
- ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(RetE);
-
- if (!ME || !Ctx.isObjCIdStructType(PT->getPointeeType()))
- return RetTy;
-
- ObjCInterfaceDecl* D = ME->getClassInfo().first;
-
- // At this point we know the return type of the message expression is id.
- // If we have an ObjCInterceDecl, we know this is a call to a class method
- // whose type we can resolve. In such cases, promote the return type to
- // Class*.
- return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
+ return RetTy;
}
-
void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
GRExprEngine& Eng,
GRStmtNodeBuilder<GRState>& Builder,
@@ -3009,26 +2998,21 @@
SVal V = St->getSValAsScalarOrLoc(Receiver);
SymbolRef Sym = V.getAsLocSymbol();
+
if (Sym) {
if (const RefVal* T = St->get<RefBindings>(Sym)) {
- QualType Ty = T->getType();
-
- if (const PointerType* PT = Ty->getAsPointerType()) {
- QualType PointeeTy = PT->getPointeeType();
-
- if (ObjCInterfaceType* IT = dyn_cast<ObjCInterfaceType>(PointeeTy))
- ID = IT->getDecl();
- }
+ if (const ObjCObjectPointerType* PT =
+ T->getType()->getAsObjCObjectPointerType())
+ ID = PT->getInterfaceDecl();
}
}
// FIXME: this is a hack. This may or may not be the actual method
// that is called.
if (!ID) {
- if (const PointerType *PT = Receiver->getType()->getAsPointerType())
- if (const ObjCInterfaceType *p =
- PT->getPointeeType()->getAsObjCInterfaceType())
- ID = p->getDecl();
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAsObjCObjectPointerType())
+ ID = PT->getInterfaceDecl();
}
// FIXME: The receiver could be a reference to a class, meaning that
diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp
index c91442b..c1382d0 100644
--- a/lib/Analysis/CheckNSError.cpp
+++ b/lib/Analysis/CheckNSError.cpp
@@ -162,16 +162,22 @@
bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) {
const PointerType* PPT = ArgTy->getAsPointerType();
- if (!PPT) return false;
+ if (!PPT)
+ return false;
- const PointerType* PT = PPT->getPointeeType()->getAsPointerType();
- if (!PT) return false;
+ const ObjCObjectPointerType* PT =
+ PPT->getPointeeType()->getAsObjCObjectPointerType();
+
+ if (!PT)
+ return false;
- const ObjCInterfaceType *IT =
- PT->getPointeeType()->getAsObjCInterfaceType();
+ const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
- if (!IT) return false;
- return IT->getDecl()->getIdentifier() == II;
+ // FIXME: Can ID ever be NULL?
+ if (ID)
+ return II == ID->getIdentifier();
+
+ return false;
}
bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) {
diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp
index 2881486..c4e586d 100644
--- a/lib/Analysis/CheckObjCInstMethSignature.cpp
+++ b/lib/Analysis/CheckObjCInstMethSignature.cpp
@@ -30,8 +30,8 @@
// Right now don't compare the compatibility of pointers. That involves
// looking at subtyping relationships. FIXME: Future patch.
- if ((Derived->isPointerType() || Derived->isObjCQualifiedIdType()) &&
- (Ancestor->isPointerType() || Ancestor->isObjCQualifiedIdType()))
+ if ((Derived->isPointerType() || Derived->isObjCObjectPointerType()) &&
+ (Ancestor->isPointerType() || Ancestor->isObjCObjectPointerType()))
return true;
return C.typesAreCompatible(Derived, Ancestor);