summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaDeclObjC.cpp
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2014-01-03 18:32:18 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2014-01-03 18:32:18 +0000
commitee82f63db35fa073e6a981c91c3bee58bab0ccc0 (patch)
treea18b0f42153b35b281decf96d5002d8299ffd87d /lib/Sema/SemaDeclObjC.cpp
parentb88a33ac1d3f5acf2e8ace6a7ddc4dc4da36c092 (diff)
[objc] Refactor and improve functionality for the -Wunused-property-ivar warning.
- Remove the additions to ObjCMethodDecl & ObjCIVarDecl that were getting de/serialized and consolidate all functionality for the checking for this warning in Sema::DiagnoseUnusedBackingIvarInAccessor - Don't check immediately after the method body is finished, check when the @implementation is finished. This is so we can see if the ivar was referenced by any other method, even if the method was defined after the accessor. - Don't silence the warning if any method is called from the accessor silence it if the accessor delegates to another method via self. rdar://15727325 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@198432 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclObjC.cpp')
-rw-r--r--lib/Sema/SemaDeclObjC.cpp96
1 files changed, 71 insertions, 25 deletions
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index edbd714184..8279263d99 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DataRecursiveASTVisitor.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
@@ -2693,6 +2694,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
ImplMethodsVsClassMethods(S, IC, IDecl);
AtomicPropertySetterGetterRules(IC, IDecl);
DiagnoseOwningPropertyGetterSynthesis(IC);
+ DiagnoseUnusedBackingIvarInAccessor(S, IC);
if (IDecl->hasDesignatedInitializers())
DiagnoseMissingDesignatedInitOverrides(IC, IDecl);
@@ -3494,39 +3496,83 @@ Sema::GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method,
const ObjCInterfaceDecl *IDecl = Method->getClassInterface();
if (!IDecl)
return 0;
- Method = IDecl->lookupMethod(Method->getSelector(), true);
+ Method = IDecl->lookupMethod(Method->getSelector(), /*isInstance=*/true,
+ /*shallowCategoryLookup=*/false,
+ /*followSuper=*/false);
if (!Method || !Method->isPropertyAccessor())
return 0;
- if ((PDecl = Method->findPropertyDecl())) {
- if (!PDecl->getDeclContext())
- return 0;
- // Make sure property belongs to accessor's class and not to
- // one of its super classes.
- if (const ObjCInterfaceDecl *CID =
- dyn_cast<ObjCInterfaceDecl>(PDecl->getDeclContext()))
- if (CID != IDecl)
- return 0;
+ if ((PDecl = Method->findPropertyDecl()))
return PDecl->getPropertyIvarDecl();
- }
+
return 0;
}
-void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S) {
- if (S->hasUnrecoverableErrorOccurred() || !S->isInObjcMethodOuterScope())
- return;
-
- const ObjCMethodDecl *CurMethod = getCurMethodDecl();
- if (!CurMethod)
+namespace {
+ /// Used by Sema::DiagnoseUnusedBackingIvarInAccessor to check if a property
+ /// accessor references the backing ivar.
+ class UnusedBackingIvarChecker : public DataRecursiveASTVisitor<UnusedBackingIvarChecker> {
+ public:
+ Sema &S;
+ const ObjCMethodDecl *Method;
+ const ObjCIvarDecl *IvarD;
+ bool AccessedIvar;
+ bool InvokedSelfMethod;
+
+ UnusedBackingIvarChecker(Sema &S, const ObjCMethodDecl *Method,
+ const ObjCIvarDecl *IvarD)
+ : S(S), Method(Method), IvarD(IvarD),
+ AccessedIvar(false), InvokedSelfMethod(false) {
+ assert(IvarD);
+ }
+
+ bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ if (E->getDecl() == IvarD) {
+ AccessedIvar = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (E->getReceiverKind() == ObjCMessageExpr::Instance &&
+ S.isSelfExpr(E->getInstanceReceiver(), Method)) {
+ InvokedSelfMethod = true;
+ }
+ return true;
+ }
+ };
+}
+
+void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S,
+ const ObjCImplementationDecl *ImplD) {
+ if (S->hasUnrecoverableErrorOccurred())
return;
- const ObjCPropertyDecl *PDecl;
- const ObjCIvarDecl *IV = GetIvarBackingPropertyAccessor(CurMethod, PDecl);
- if (IV && !IV->getBackingIvarReferencedInAccessor()) {
+
+ for (ObjCImplementationDecl::instmeth_iterator
+ MI = ImplD->instmeth_begin(),
+ ME = ImplD->instmeth_end(); MI != ME; ++MI) {
+ const ObjCMethodDecl *CurMethod = *MI;
+ unsigned DIAG = diag::warn_unused_property_backing_ivar;
+ SourceLocation Loc = CurMethod->getLocation();
+ if (Diags.getDiagnosticLevel(DIAG, Loc) == DiagnosticsEngine::Ignored)
+ continue;
+
+ const ObjCPropertyDecl *PDecl;
+ const ObjCIvarDecl *IV = GetIvarBackingPropertyAccessor(CurMethod, PDecl);
+ if (!IV)
+ continue;
+
+ UnusedBackingIvarChecker Checker(*this, CurMethod, IV);
+ Checker.TraverseStmt(CurMethod->getBody());
+ if (Checker.AccessedIvar)
+ continue;
+
// Do not issue this warning if backing ivar is used somewhere and accessor
- // implementation makes a call to a method. This is to prevent false positive in
- // some corner cases.
- if (!IV->isReferenced() || !CurMethod->getMethodCallsMethod()) {
- Diag(getCurMethodDecl()->getLocation(), diag::warn_unused_property_backing_ivar)
- << IV->getDeclName();
+ // implementation makes a self call. This is to prevent false positive in
+ // cases where the ivar is accessed by another method that the accessor
+ // delegates to.
+ if (!IV->isReferenced() || !Checker.InvokedSelfMethod) {
+ Diag(Loc, DIAG) << IV->getDeclName();
Diag(PDecl->getLocation(), diag::note_property_declare);
}
}