Objective-C: Provide fixit suggestions when class object
is accessed via accessing 'isa' ivar to use object_getClass/object_setClass apis. // rdar://13503456 llvm-svn: 178282
This commit is contained in:
		
							parent
							
								
									a46059b74d
								
							
						
					
					
						commit
						06bb7f7ef6
					
				| 
						 | 
				
			
			@ -1381,15 +1381,19 @@ class ObjCIsaExpr : public Expr {
 | 
			
		|||
  /// IsaMemberLoc - This is the location of the 'isa'.
 | 
			
		||||
  SourceLocation IsaMemberLoc;
 | 
			
		||||
  
 | 
			
		||||
  /// OpLoc - This is the location of '.' or '->'
 | 
			
		||||
  SourceLocation OpLoc;
 | 
			
		||||
 | 
			
		||||
  /// IsArrow - True if this is "X->F", false if this is "X.F".
 | 
			
		||||
  bool IsArrow;
 | 
			
		||||
public:
 | 
			
		||||
  ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty)
 | 
			
		||||
  ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, SourceLocation oploc,
 | 
			
		||||
              QualType ty)
 | 
			
		||||
    : Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary,
 | 
			
		||||
           /*TypeDependent=*/false, base->isValueDependent(),
 | 
			
		||||
           base->isInstantiationDependent(),
 | 
			
		||||
           /*ContainsUnexpandedParameterPack=*/false),
 | 
			
		||||
      Base(base), IsaMemberLoc(l), IsArrow(isarrow) {}
 | 
			
		||||
      Base(base), IsaMemberLoc(l), OpLoc(oploc), IsArrow(isarrow) {}
 | 
			
		||||
 | 
			
		||||
  /// \brief Build an empty expression.
 | 
			
		||||
  explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { }
 | 
			
		||||
| 
						 | 
				
			
			@ -1405,9 +1409,17 @@ public:
 | 
			
		|||
  SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; }
 | 
			
		||||
  void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; }
 | 
			
		||||
  
 | 
			
		||||
  SourceLocation getOpLoc() const { return OpLoc; }
 | 
			
		||||
  void setOpLoc(SourceLocation L) { OpLoc = L; }
 | 
			
		||||
 | 
			
		||||
  SourceLocation getLocStart() const LLVM_READONLY {
 | 
			
		||||
    return getBase()->getLocStart();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  SourceLocation getBaseLocEnd() const LLVM_READONLY {
 | 
			
		||||
    return getBase()->getLocEnd();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  SourceLocation getLocEnd() const LLVM_READONLY { return IsaMemberLoc; }
 | 
			
		||||
 | 
			
		||||
  SourceLocation getExprLoc() const LLVM_READONLY { return IsaMemberLoc; }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -491,8 +491,18 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  CheckForNullPointerDereference(*this, E);
 | 
			
		||||
  if (isa<ObjCIsaExpr>(E->IgnoreParens()))
 | 
			
		||||
    Diag(E->getExprLoc(), diag::warn_objc_isa_use);
 | 
			
		||||
  if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(E->IgnoreParenCasts())) {
 | 
			
		||||
    NamedDecl *ObjectGetClass = LookupSingleName(TUScope,
 | 
			
		||||
                                     &Context.Idents.get("object_getClass"),
 | 
			
		||||
                                     SourceLocation(), LookupOrdinaryName);
 | 
			
		||||
    if (ObjectGetClass)
 | 
			
		||||
      Diag(E->getExprLoc(), diag::warn_objc_isa_use) <<
 | 
			
		||||
        FixItHint::CreateInsertion(OISA->getLocStart(), "object_getClass(") <<
 | 
			
		||||
        FixItHint::CreateReplacement(
 | 
			
		||||
                    SourceRange(OISA->getOpLoc(), OISA->getIsaMemberLoc()), ")");
 | 
			
		||||
    else
 | 
			
		||||
      Diag(E->getExprLoc(), diag::warn_objc_isa_use);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // C++ [conv.lval]p1:
 | 
			
		||||
  //   [...] If T is a non-class type, the type of the prvalue is the
 | 
			
		||||
| 
						 | 
				
			
			@ -8537,8 +8547,20 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
 | 
			
		|||
  CheckArrayAccess(LHS.get());
 | 
			
		||||
  CheckArrayAccess(RHS.get());
 | 
			
		||||
 | 
			
		||||
  if (isa<ObjCIsaExpr>(LHS.get()->IgnoreParens()))
 | 
			
		||||
    Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign);
 | 
			
		||||
  if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(LHS.get()->IgnoreParenCasts())) {
 | 
			
		||||
    NamedDecl *ObjectSetClass = LookupSingleName(TUScope,
 | 
			
		||||
                                                 &Context.Idents.get("object_setClass"),
 | 
			
		||||
                                                 SourceLocation(), LookupOrdinaryName);
 | 
			
		||||
    if (ObjectSetClass && isa<ObjCIsaExpr>(LHS.get())) {
 | 
			
		||||
      SourceLocation RHSLocEnd = PP.getLocForEndOfToken(RHS.get()->getLocEnd());
 | 
			
		||||
      Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign) <<
 | 
			
		||||
      FixItHint::CreateInsertion(LHS.get()->getLocStart(), "object_setClass(") <<
 | 
			
		||||
      FixItHint::CreateReplacement(SourceRange(OISA->getOpLoc(), OpLoc), ",") <<
 | 
			
		||||
      FixItHint::CreateInsertion(RHSLocEnd, ")");
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (CompResultTy.isNull())
 | 
			
		||||
    return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1132,6 +1132,7 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
 | 
			
		|||
      // apparently.
 | 
			
		||||
      if (OTy->isObjCId() && Member->isStr("isa"))
 | 
			
		||||
        return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
 | 
			
		||||
                                               OpLoc,
 | 
			
		||||
                                               Context.getObjCClassType()));
 | 
			
		||||
      if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
 | 
			
		||||
        return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2389,13 +2389,14 @@ public:
 | 
			
		|||
  /// By default, performs semantic analysis to build the new expression.
 | 
			
		||||
  /// Subclasses may override this routine to provide different behavior.
 | 
			
		||||
  ExprResult RebuildObjCIsaExpr(Expr *BaseArg, SourceLocation IsaLoc,
 | 
			
		||||
                                SourceLocation OpLoc,
 | 
			
		||||
                                      bool IsArrow) {
 | 
			
		||||
    CXXScopeSpec SS;
 | 
			
		||||
    ExprResult Base = getSema().Owned(BaseArg);
 | 
			
		||||
    LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc,
 | 
			
		||||
                   Sema::LookupMemberName);
 | 
			
		||||
    ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
 | 
			
		||||
                                                         /*FIME:*/IsaLoc,
 | 
			
		||||
                                                         OpLoc,
 | 
			
		||||
                                                         SS, 0, false);
 | 
			
		||||
    if (Result.isInvalid() || Base.isInvalid())
 | 
			
		||||
      return ExprError();
 | 
			
		||||
| 
						 | 
				
			
			@ -2404,7 +2405,7 @@ public:
 | 
			
		|||
      return Result;
 | 
			
		||||
 | 
			
		||||
    return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
 | 
			
		||||
                                              /*FIXME:*/IsaLoc, IsArrow,
 | 
			
		||||
                                              OpLoc, IsArrow,
 | 
			
		||||
                                              SS, SourceLocation(),
 | 
			
		||||
                                              /*FirstQualifierInScope=*/0,
 | 
			
		||||
                                              R,
 | 
			
		||||
| 
						 | 
				
			
			@ -8788,6 +8789,7 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
 | 
			
		|||
    return SemaRef.Owned(E);
 | 
			
		||||
 | 
			
		||||
  return getDerived().RebuildObjCIsaExpr(Base.get(), E->getIsaMemberLoc(),
 | 
			
		||||
                                         E->getOpLoc(),
 | 
			
		||||
                                         E->isArrow());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -528,6 +528,7 @@ void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
 | 
			
		|||
  VisitExpr(E);
 | 
			
		||||
  E->setBase(Reader.ReadSubExpr());
 | 
			
		||||
  E->setIsaMemberLoc(ReadSourceLocation(Record, Idx));
 | 
			
		||||
  E->setOpLoc(ReadSourceLocation(Record, Idx));
 | 
			
		||||
  E->setArrow(Record[Idx++]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -498,6 +498,7 @@ void ASTStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) {
 | 
			
		|||
  VisitExpr(E);
 | 
			
		||||
  Writer.AddStmt(E->getBase());
 | 
			
		||||
  Writer.AddSourceLocation(E->getIsaMemberLoc(), Record);
 | 
			
		||||
  Writer.AddSourceLocation(E->getOpLoc(), Record);
 | 
			
		||||
  Record.push_back(E->isArrow());
 | 
			
		||||
  Code = serialization::EXPR_OBJC_ISA;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
// RUN: cp %s %t
 | 
			
		||||
// RUN: %clang_cc1 -x objective-c -fixit %t
 | 
			
		||||
// RUN: %clang_cc1 -x objective-c -Werror %t
 | 
			
		||||
// rdar://13503456
 | 
			
		||||
 | 
			
		||||
void object_setClass(id, id);
 | 
			
		||||
Class object_getClass(id);
 | 
			
		||||
 | 
			
		||||
id rhs();
 | 
			
		||||
 | 
			
		||||
Class pr6302(id x123) {
 | 
			
		||||
  x123->isa  = 0;
 | 
			
		||||
  x123->isa = rhs();
 | 
			
		||||
  x123->isa = (id)(x123->isa);
 | 
			
		||||
  x123->isa = (id)x123->isa;
 | 
			
		||||
  x123->isa = (x123->isa);
 | 
			
		||||
  x123->isa = (id)(x123->isa);
 | 
			
		||||
  return x123->isa;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue