From 077c1e7377edeef3438ba59cd8151177868b62d4 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Mon, 2 Mar 2009 21:55:29 +0000 Subject: [PATCH] Diagnose a variety of access of ivars when they conflict with 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 | 4 ++ lib/Sema/SemaExpr.cpp | 41 ++++++++++++++------- test/SemaObjC/ivar-ref-misuse.m | 41 +++++++++++++++++++++ 3 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 test/SemaObjC/ivar-ref-misuse.m diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 104371e49c..4648a7d314 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -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") diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index aca19cdca6..32ef0f7b35 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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(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(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)<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 index 0000000000..814d465baf --- /dev/null +++ b/test/SemaObjC/ivar-ref-misuse.m @@ -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 -- 2.40.0