]> granicus.if.org Git - clang/commitdiff
Diagnose a variety of access of ivars when they conflict with
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 2 Mar 2009 21:55:29 +0000 (21:55 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 2 Mar 2009 21:55:29 +0000 (21:55 +0000)
local or global variables in instance/class methods.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65879 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.def
lib/Sema/SemaExpr.cpp
test/SemaObjC/ivar-ref-misuse.m [new file with mode: 0644]

index 104371e49c1894b92a6f59fd876f056a68bca6ac..4648a7d314bc780784deda090827710c2f20a59d 100644 (file)
@@ -1436,4 +1436,8 @@ DIAG(err_invalid_protocol_qualifiers, ERROR,
      "invalid protocol qualifiers on non-ObjC type")
 DIAG(err_qualified_class_unsupported, ERROR,
      "protocol qualified 'Class' is unsupported")
+DIAG(warn_ivar_use_hidden, WARNING,
+     "local declaration of %0 hides instance variable")
+DIAG(error_ivar_use_in_class_method, ERROR,
+     "instance variable %0 accessed in class method")
 
index aca19cdca675fc8d393aba314755e8c7c04d42a4..32ef0f7b35190b5da900323ed01112f0600b3466 100644 (file)
@@ -627,27 +627,42 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
   if (II && getCurMethodDecl()) {
     // There are two cases to handle here.  1) scoped lookup could have failed,
     // in which case we should look for an ivar.  2) scoped lookup could have
-    // found a decl, but that decl is outside the current method (i.e. a global
-    // variable).  In these two cases, we do a lookup for an ivar with this
-    // name, if the lookup suceeds, we replace it our current decl.
+    // found a decl, but that decl is outside the current instance method (i.e. 
+    // a global variable).  In these two cases, we do a lookup for an ivar with 
+    // this name, if the lookup sucedes, we replace it our current decl.
     if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) {
       ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
       if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II)) {
         // Check if referencing a field with __attribute__((deprecated)).
         if (DiagnoseUseOfDecl(IV, Loc))
           return ExprError();
-
-        // FIXME: This should use a new expr for a direct reference, don't turn
-        // this into Self->ivar, just return a BareIVarExpr or something.
-        IdentifierInfo &II = Context.Idents.get("self");
-        OwningExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false);
-        ObjCIvarRefExpr *MRef = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
-                                  Loc, static_cast<Expr*>(SelfExpr.release()),
-                                  true, true);
-        Context.setFieldDecl(IFace, IV, MRef);
-        return Owned(MRef);
+        bool IsClsMethod = getCurMethodDecl()->isClassMethod();
+        // If a class method attemps to use a free standing ivar, this is
+        // an error.
+        if (IsClsMethod && D && !D->isDefinedOutsideFunctionOrMethod())
+           return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method)
+                           << IV->getDeclName());
+        // If a class method uses a global variable, even if an ivar with
+        // same name exists, use the global.
+        if (!IsClsMethod) {
+          // FIXME: This should use a new expr for a direct reference, don't turn
+          // this into Self->ivar, just return a BareIVarExpr or something.
+          IdentifierInfo &II = Context.Idents.get("self");
+          OwningExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false);
+          ObjCIvarRefExpr *MRef = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
+                                    Loc, static_cast<Expr*>(SelfExpr.release()),
+                                    true, true);
+          Context.setFieldDecl(IFace, IV, MRef);
+          return Owned(MRef);
+        }
       }
     }
+    else if (getCurMethodDecl()->isInstanceMethod()) {
+      // We should warn if a local variable hides an ivar.
+      ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
+      if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II))
+        Diag(Loc, diag::warn_ivar_use_hidden)<<IV->getDeclName();
+    }
     // Needed to implement property "super.method" notation.
     if (D == 0 && II->isStr("super")) {
       QualType T = Context.getPointerType(Context.getObjCInterfaceType(
diff --git a/test/SemaObjC/ivar-ref-misuse.m b/test/SemaObjC/ivar-ref-misuse.m
new file mode 100644 (file)
index 0000000..814d465
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: clang -fsyntax-only -verify %s
+
+@interface Sprite {
+  int sprite, spree;
+  int UseGlobalBar;
+}
++ (void)setFoo:(int)foo;
++ (void)setSprite:(int)sprite;
+- (void)setFoo:(int)foo;
+- (void)setSprite:(int)sprite;
+@end
+
+int spree = 23;
+int UseGlobalBar;
+
+@implementation Sprite
++ (void)setFoo:(int)foo {
+  sprite = foo;   // expected-error {{use of undeclared identifier 'sprite'}}
+  spree = foo;
+  Xsprite = foo; // expected-error {{use of undeclared identifier 'Xsprite'}} 
+  UseGlobalBar = 10;
+}
++ (void)setSprite:(int)sprite {
+  int spree;
+  sprite = 15;
+  spree = 17;
+  ((Sprite *)self)->sprite = 16;   /* NB: This is how one _should_ access */
+  ((Sprite *)self)->spree = 18;    /* ivars from within class methods!    */
+}
+- (void)setFoo:(int)foo {
+  sprite = foo;
+  spree = foo;
+}
+- (void)setSprite:(int)sprite {
+  int spree;
+  sprite = 15;  // expected-warning {{local declaration of 'sprite' hides instance variable}}
+  self->sprite = 16;
+  spree = 17;  // expected-warning {{local declaration of 'spree' hides instance variable}}
+  self->spree = 18;
+}   
+@end