diff options
author | John McCall <rjmccall@apple.com> | 2013-03-19 07:04:25 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2013-03-19 07:04:25 +0000 |
commit | 7cca821e1acf0f1b4fe892c3111bfb2086832e4e (patch) | |
tree | 52d32c5d35d69267c5b5ea16f7e5e6e89a55c6fb /lib/Sema/SemaExprObjC.cpp | |
parent | a5a3e01c504c00b1860286540090695ec0167531 (diff) |
Add a clarifying note when a return statement is rejected because
we expect a related result type.
rdar://12493140
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177378 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExprObjC.cpp')
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index b0d5453808..af8380df18 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1094,6 +1094,73 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType, return ReceiverType; } +/// Look for an ObjC method whose result type exactly matches the given type. +static const ObjCMethodDecl * +findExplicitInstancetypeDeclarer(const ObjCMethodDecl *MD, + QualType instancetype) { + if (MD->getResultType() == instancetype) return MD; + + // For these purposes, a method in an @implementation overrides a + // declaration in the @interface. + if (const ObjCImplDecl *impl = + dyn_cast<ObjCImplDecl>(MD->getDeclContext())) { + const ObjCContainerDecl *iface; + if (const ObjCCategoryImplDecl *catImpl = + dyn_cast<ObjCCategoryImplDecl>(impl)) { + iface = catImpl->getCategoryDecl(); + } else { + iface = impl->getClassInterface(); + } + + const ObjCMethodDecl *ifaceMD = + iface->getMethod(MD->getSelector(), MD->isInstanceMethod()); + if (ifaceMD) return findExplicitInstancetypeDeclarer(ifaceMD, instancetype); + } + + SmallVector<const ObjCMethodDecl *, 4> overrides; + MD->getOverriddenMethods(overrides); + for (unsigned i = 0, e = overrides.size(); i != e; ++i) { + if (const ObjCMethodDecl *result = + findExplicitInstancetypeDeclarer(overrides[i], instancetype)) + return result; + } + + return 0; +} + +void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) { + // Only complain if we're in an ObjC method and the required return + // type doesn't match the method's declared return type. + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurContext); + if (!MD || !MD->hasRelatedResultType() || + Context.hasSameUnqualifiedType(destType, MD->getResultType())) + return; + + // Look for a method overridden by this method which explicitly uses + // 'instancetype'. + if (const ObjCMethodDecl *overridden = + findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) { + SourceLocation loc; + SourceRange range; + if (TypeSourceInfo *TSI = overridden->getResultTypeSourceInfo()) { + range = TSI->getTypeLoc().getSourceRange(); + loc = range.getBegin(); + } + if (loc.isInvalid()) + loc = overridden->getLocation(); + Diag(loc, diag::note_related_result_type_explicit) + << /*current method*/ 1 << range; + return; + } + + // Otherwise, if we have an interesting method family, note that. + // This should always trigger if the above didn't. + if (ObjCMethodFamily family = MD->getMethodFamily()) + Diag(MD->getLocation(), diag::note_related_result_type_family) + << /*current method*/ 1 + << family; +} + void Sema::EmitRelatedResultTypeNote(const Expr *E) { E = E->IgnoreParenImpCasts(); const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E); |