예제 #1
0
/// Try to capture an implicit reference to 'self'.
ObjCMethodDecl *Sema::tryCaptureObjCSelf() {
  // Ignore block scopes: we can capture through them.
  DeclContext *DC = CurContext;
  while (true) {
    if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
    else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext();
    else break;
  }

  // If we're not in an ObjC method, error out.  Note that, unlike the
  // C++ case, we don't require an instance method --- class methods
  // still have a 'self', and we really do still need to capture it!
  ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(DC);
  if (!method)
    return 0;

  ImplicitParamDecl *self = method->getSelfDecl();
  assert(self && "capturing 'self' in non-definition?");

  // Mark that we're closing on 'this' in all the block scopes, if applicable.
  for (unsigned idx = FunctionScopes.size() - 1;
       isa<BlockScopeInfo>(FunctionScopes[idx]);
       --idx) {
    BlockScopeInfo *blockScope = cast<BlockScopeInfo>(FunctionScopes[idx]);
    unsigned &captureIndex = blockScope->CaptureMap[self];
    if (captureIndex) break;

    bool nested = isa<BlockScopeInfo>(FunctionScopes[idx-1]);
    blockScope->Captures.push_back(
              BlockDecl::Capture(self, /*byref*/ false, nested, /*copy*/ 0));
    captureIndex = blockScope->Captures.size(); // +1
  }

  return method;
}
예제 #2
0
void cxcursor::getOverriddenCursors(CXCursor cursor,
                                    SmallVectorImpl<CXCursor> &overridden) { 
  if (!clang_isDeclaration(cursor.kind))
    return;

  Decl *D = getCursorDecl(cursor);
  if (!D)
    return;

  // Handle C++ member functions.
  CXTranslationUnit TU = getCursorTU(cursor);
  if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
    for (CXXMethodDecl::method_iterator
              M = CXXMethod->begin_overridden_methods(),
           MEnd = CXXMethod->end_overridden_methods();
         M != MEnd; ++M)
      overridden.push_back(MakeCXCursor(const_cast<CXXMethodDecl*>(*M), TU));
    return;
  }

  ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
  if (!Method)
    return;

  // Handle Objective-C methods.
  CollectOverriddenMethods(TU, Method->getDeclContext(), Method, overridden);
}
예제 #3
0
void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
                                                      ObjCInterfaceDecl *D) {
  for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
       M != MEnd; ++M) {
    ObjCMethodDecl *Method = (*M);
    if (Method->isPropertyAccessor() ||  Method->param_size() != 0)
      continue;
    // Is this method candidate to be a getter?
    QualType GRT = Method->getResultType();
    if (GRT->isVoidType())
      continue;
    Selector GetterSelector = Method->getSelector();
    IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
    Selector SetterSelector =
      SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
                                             PP.getSelectorTable(),
                                             getterName);
    if (ObjCMethodDecl *SetterMethod = D->lookupMethod(SetterSelector, true)) {
      // Is this a valid setter, matching the target getter?
      QualType SRT = SetterMethod->getResultType();
      if (!SRT->isVoidType())
        continue;
      const ParmVarDecl *argDecl = *SetterMethod->param_begin();
      QualType ArgType = argDecl->getType();
      if (!Ctx.hasSameType(ArgType, GRT))
          continue;
        edit::Commit commit(*Editor);
        edit::rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit);
        Editor->commit(commit);
      }
  }
}
예제 #4
0
TEST(InitializerCheck, find_nonnull_ivars) {
    ASTBuilder builder("@interface Test : NSObject\n"
                       "@property (nonatomic, nonnull) NSString *hello;\n"
                       "@property (nonatomic, nullable) NSNumber *good;\n"
                       "@end\n"
                       "@interface Test()\n"
                       "@property (nonatomic, nonnull) NSString *extension;\n"
                       "@property (nonatomic, nullable) NSNumber *extension2;\n"
                       "@end\n"
                       "@interface Test (Cat)\n"
                       "@property (nonatomic, nonnull) NSString *category;\n"
                       "@property (nonatomic, nullable) NSNumber *category2;\n"
                       "@end\n"
                       "@implementation Test {\n"
                       "  NSString * _Nonnull _impl1;\n"
                       "  NSString * _Nullable _impl2;\n"
                       "}\n"
                       "- (nonnull instancetype)init1 __attribute__((annotate(\"hoge\"))) {\n"
                       "  return self;\n"
                       "}\n"
                       "@end\n");
    
    std::shared_ptr<VariableNullabilityMapping> map(new VariableNullabilityMapping);
    std::shared_ptr<VariableNullabilityEnvironment> env(new VariableNullabilityEnvironment(builder.getASTContext(), map));
    ExpressionNullabilityCalculator calculator(builder.getASTContext(), env);
    VariableNullabilityPropagation prop(calculator, env);
    
    ObjCMethodDecl *method = builder.getMethodDecl("init1");
    
    for (auto attr : method->attrs()) {
        auto kind = attr->getKind();
        if (kind == clang::attr::Annotate) {
            auto annot = llvm::dyn_cast<AnnotateAttr>(attr);
            std::string name = annot->getAnnotation();
            ASSERT_EQ(name, "hoge");
        }
    }
    
    ObjCImplementationDecl *impl = builder.getImplementationDecl("Test");
    
    InitializerChecker checker(builder.getASTContext(), impl);
    
    auto ivars = checker.getNonnullIvars();
    
    std::set<std::string> actualIvarNames;
    for (auto ivar : ivars) {
        actualIvarNames.insert(ivar->getIvarDecl()->getNameAsString());
    }
    
    std::set<std::string> expectedIvarNames;
    expectedIvarNames.insert("_hello");
    expectedIvarNames.insert("_extension");
    expectedIvarNames.insert("_impl1");
    
    ASSERT_EQ(expectedIvarNames, actualIvarNames);
}
예제 #5
0
bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
                                             Selector Sel) const {
  assert(IDecl);
  const SourceManager &SM =
    getState()->getStateManager().getContext().getSourceManager();

  // If the class interface is declared inside the main file, assume it is not
  // subcassed. 
  // TODO: It could actually be subclassed if the subclass is private as well.
  // This is probably very rare.
  SourceLocation InterfLoc = IDecl->getEndOfDefinitionLoc();
  if (InterfLoc.isValid() && SM.isFromMainFile(InterfLoc))
    return false;

  // Assume that property accessors are not overridden.
  if (getMessageKind() == OCM_PropertyAccess)
    return false;

  // We assume that if the method is public (declared outside of main file) or
  // has a parent which publicly declares the method, the method could be
  // overridden in a subclass.

  // Find the first declaration in the class hierarchy that declares
  // the selector.
  ObjCMethodDecl *D = 0;
  while (true) {
    D = IDecl->lookupMethod(Sel, true);

    // Cannot find a public definition.
    if (!D)
      return false;

    // If outside the main file,
    if (D->getLocation().isValid() && !SM.isFromMainFile(D->getLocation()))
      return true;

    if (D->isOverriding()) {
      // Search in the superclass on the next iteration.
      IDecl = D->getClassInterface();
      if (!IDecl)
        return false;

      IDecl = IDecl->getSuperClass();
      if (!IDecl)
        return false;

      continue;
    }

    return false;
  };

  llvm_unreachable("The while loop should always terminate.");
}
예제 #6
0
void StmtDumper::VisitObjCImplicitSetterGetterRefExpr(
                                        ObjCImplicitSetterGetterRefExpr *Node) {
  DumpExpr(Node);

  ObjCMethodDecl *Getter = Node->getGetterMethod();
  ObjCMethodDecl *Setter = Node->getSetterMethod();
  OS << " Kind=MethodRef Getter=\""
     << Getter->getSelector().getAsString()
     << "\" Setter=\"";
  if (Setter)
    OS << Setter->getSelector().getAsString();
  else
    OS << "(null)";
  OS << "\"";
}
예제 #7
0
void ento::CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
                                    BugReporter& BR) {

  const ObjCInterfaceDecl* D = ID->getClassInterface();
  const ObjCInterfaceDecl* C = D->getSuperClass();

  if (!C)
    return;

  ASTContext& Ctx = BR.getContext();

  // Build a DenseMap of the methods for quick querying.
  typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy;
  MapTy IMeths;
  unsigned NumMethods = 0;

  for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(),
       E=ID->instmeth_end(); I!=E; ++I) {

    ObjCMethodDecl* M = *I;
    IMeths[M->getSelector()] = M;
    ++NumMethods;
  }

  // Now recurse the class hierarchy chain looking for methods with the
  // same signatures.
  while (C && NumMethods) {
    for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(),
         E=C->instmeth_end(); I!=E; ++I) {

      ObjCMethodDecl* M = *I;
      Selector S = M->getSelector();

      MapTy::iterator MI = IMeths.find(S);

      if (MI == IMeths.end() || MI->second == 0)
        continue;

      --NumMethods;
      ObjCMethodDecl* MethDerived = MI->second;
      MI->second = 0;

      CompareReturnTypes(MethDerived, M, BR, Ctx, ID);
    }

    C = C->getSuperClass();
  }
}
예제 #8
0
ExprResult Sema::ActOnSuperMessage(Scope *S, 
                                   SourceLocation SuperLoc,
                                   Selector Sel,
                                   SourceLocation LBracLoc,
                                   SourceLocation SelectorLoc,
                                   SourceLocation RBracLoc,
                                   MultiExprArg Args) {
  // Determine whether we are inside a method or not.
  ObjCMethodDecl *Method = tryCaptureObjCSelf();
  if (!Method) {
    Diag(SuperLoc, diag::err_invalid_receiver_to_message_super);
    return ExprError();
  }

  ObjCInterfaceDecl *Class = Method->getClassInterface();
  if (!Class) {
    Diag(SuperLoc, diag::error_no_super_class_message)
      << Method->getDeclName();
    return ExprError();
  }

  ObjCInterfaceDecl *Super = Class->getSuperClass();
  if (!Super) {
    // The current class does not have a superclass.
    Diag(SuperLoc, diag::error_root_class_cannot_use_super)
      << Class->getIdentifier();
    return ExprError();
  }

  // We are in a method whose class has a superclass, so 'super'
  // is acting as a keyword.
  if (Method->isInstanceMethod()) {
    // Since we are in an instance method, this is an instance
    // message to the superclass instance.
    QualType SuperTy = Context.getObjCInterfaceType(Super);
    SuperTy = Context.getObjCObjectPointerType(SuperTy);
    return BuildInstanceMessage(0, SuperTy, SuperLoc,
                                Sel, /*Method=*/0,
                                LBracLoc, SelectorLoc, RBracLoc, move(Args));
  }
  
  // Since we are in a class method, this is a class message to
  // the superclass.
  return BuildClassMessage(/*ReceiverTypeInfo=*/0,
                           Context.getObjCInterfaceType(Super),
                           SuperLoc, Sel, /*Method=*/0,
                           LBracLoc, SelectorLoc, RBracLoc, move(Args));
}
예제 #9
0
/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
/// declarator
QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) {
  ObjCMethodDecl *MDecl = cast<ObjCMethodDecl>(D.getAs<Decl>());
  QualType T = MDecl->getResultType();
  llvm::SmallVector<QualType, 16> ArgTys;
  
  // Add the first two invisible argument types for self and _cmd.
  if (MDecl->isInstanceMethod()) {
    QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface());
    selfTy = Context.getPointerType(selfTy);
    ArgTys.push_back(selfTy);
  } else
    ArgTys.push_back(Context.getObjCIdType());
  ArgTys.push_back(Context.getObjCSelType());
      
  for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(),
       E = MDecl->param_end(); PI != E; ++PI) {
    QualType ArgTy = (*PI)->getType();
    assert(!ArgTy.isNull() && "Couldn't parse type?");
    ArgTy = adjustParameterType(ArgTy);
    ArgTys.push_back(ArgTy);
  }
  T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
                              MDecl->isVariadic(), 0);
  return T;
}
예제 #10
0
void
NSErrorChecker::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy,
                             llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {

  ResultTy = M.getResultType();

  for (ObjCMethodDecl::param_iterator I=M.param_begin(),
       E=M.param_end(); I!=E; ++I)  {

    QualType T = (*I)->getType();

    if (isNSErrorWarning) {
      if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
    }
    else if (CheckCFErrorArgument(T))
      ErrorParams.push_back(*I);
  }
}
예제 #11
0
파일: DeclObjC.cpp 프로젝트: colgur/clang
// Get the local instance/class method declared in this interface.
ObjCMethodDecl *
ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
  // Since instance & class methods can have the same name, the loop below
  // ensures we get the correct method.
  //
  // @interface Whatever
  // - (int) class_method;
  // + (float) class_method;
  // @end
  //
  lookup_const_iterator Meth, MethEnd;
  for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) {
    ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
    if (MD && MD->isInstanceMethod() == isInstance)
      return MD;
  }
  return 0;
}
예제 #12
0
void DeclPrinter::PrintObjCImplementationDecl(ObjCImplementationDecl *OID) {
	std::string I = OID->getName();
	ObjCInterfaceDecl *SID = OID->getSuperClass();

	if (SID)
		Out << "@implementation " << I << " : " << SID->getName();
	else
		Out << "@implementation " << I;

	for (ObjCImplementationDecl::instmeth_iterator I = OID->instmeth_begin(),
		E = OID->instmeth_end(); I != E; ++I) {
			ObjCMethodDecl *OMD = *I;
			PrintObjCMethodDecl(OMD);
			if (OMD->getBody()) {
				Out << ' ';
				OMD->getBody()->printPretty(Out);
				Out << '\n';
			}
	}

	for (ObjCImplementationDecl::classmeth_iterator I = OID->classmeth_begin(),
		E = OID->classmeth_end(); I != E; ++I) {
			ObjCMethodDecl *OMD = *I;
			PrintObjCMethodDecl(OMD);
			if (OMD->getBody()) {
				Out << ' ';
				OMD->getBody()->printPretty(Out);
				Out << '\n';
			}
	}

	Out << "@end\n";
}
예제 #13
0
 bool VisitObjCMessageExpr(ObjCMessageExpr *messageExpr) {
     ObjCMethodDecl *decl = messageExpr->getMethodDecl();
     auto info = findIvarInfo(_NonnullIvars, decl);
     if (!info.expired()) {
         _NonnullIvars.erase(info.lock());
     }
     
     if (isInitializerMethod(decl)) {
         auto receiver = messageExpr->getInstanceReceiver();
         if (receiver) {
             auto varRef = llvm::dyn_cast<DeclRefExpr>(receiver->IgnoreParenImpCasts());
             
             if (varRef) {
                 if (varRef->getDecl()->getNameAsString() == "self" && decl->getClassInterface() == _MethodDecl->getClassInterface()) {
                     _NonnullIvars.clear();
                 }
             }
         }
     }
     
     return true;
 }
static void removeDeallocMethod(MigrationPass &pass) {
  ASTContext &Ctx = pass.Ctx;
  TransformActions &TA = pass.TA;
  DeclContext *DC = Ctx.getTranslationUnitDecl();

  typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
    impl_iterator;
  for (impl_iterator I = impl_iterator(DC->decls_begin()),
                     E = impl_iterator(DC->decls_end()); I != E; ++I) {
    for (ObjCImplementationDecl::instmeth_iterator
           MI = (*I)->instmeth_begin(),
           ME = (*I)->instmeth_end(); MI != ME; ++MI) {
      ObjCMethodDecl *MD = *MI;
      if (MD->getMethodFamily() == OMF_dealloc) {
        if (MD->hasBody() &&
            isBodyEmpty(MD->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
          Transaction Trans(TA);
          TA.remove(MD->getSourceRange());
        }
        break;
      }
    }
  }
}
예제 #15
0
static void GCRewriteFinalize(MigrationPass &pass) {
  ASTContext &Ctx = pass.Ctx;
  TransformActions &TA = pass.TA;
  DeclContext *DC = Ctx.getTranslationUnitDecl();
  Selector FinalizeSel =
   Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));

  typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
  impl_iterator;
  for (impl_iterator I = impl_iterator(DC->decls_begin()),
       E = impl_iterator(DC->decls_end()); I != E; ++I) {
    for (ObjCImplementationDecl::instmeth_iterator
         MI = I->instmeth_begin(),
         ME = I->instmeth_end(); MI != ME; ++MI) {
      ObjCMethodDecl *MD = *MI;
      if (!MD->hasBody())
        continue;

      if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
        ObjCMethodDecl *FinalizeM = MD;
        Transaction Trans(TA);
        TA.insert(FinalizeM->getSourceRange().getBegin(),
                  "#if !__has_feature(objc_arc)\n");
        CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
        const SourceManager &SM = pass.Ctx.getSourceManager();
        const LangOptions &LangOpts = pass.Ctx.getLangOpts();
        bool Invalid;
        std::string str = "\n#endif\n";
        str += Lexer::getSourceText(
                  CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
                                    SM, LangOpts, &Invalid);
        TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);

        break;
      }
    }
  }
}
예제 #16
0
파일: ASTConsumers.cpp 프로젝트: aosm/clang
void DeclPrinter::PrintObjCImplementationDecl(ObjCImplementationDecl *OID) {
  std::string I = OID->getNameAsString();
  ObjCInterfaceDecl *SID = OID->getSuperClass();

  if (SID)
    Out << "@implementation " << I << " : " << SID->getNameAsString();
  else
    Out << "@implementation " << I;
  
  // FIXME: Don't use a NULL context
  ASTContext *Context = 0;
  for (ObjCImplementationDecl::instmeth_iterator 
         I = OID->instmeth_begin(*Context),
         E = OID->instmeth_end(*Context); 
       I != E; ++I) {
    ObjCMethodDecl *OMD = *I;
    PrintObjCMethodDecl(OMD);
    if (OMD->getBody()) {
      Out << ' ';
      OMD->getBody()->printPretty(Out);
      Out << '\n';
    }
  }
  
  for (ObjCImplementationDecl::classmeth_iterator 
         I = OID->classmeth_begin(*Context),
       E = OID->classmeth_end(*Context);
       I != E; ++I) {
    ObjCMethodDecl *OMD = *I;
    PrintObjCMethodDecl(OMD);
    if (OMD->getBody()) {
      Out << ' ';
      OMD->getBody()->printPretty(Out);
      Out << '\n';
    }
  }
  
  for (ObjCImplementationDecl::propimpl_iterator 
         I = OID->propimpl_begin(*Context),
         E = OID->propimpl_end(*Context); I != E; ++I)
    PrintObjCPropertyImplDecl(*I);
  
  Out << "@end\n";
}
예제 #17
0
void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
                                        AnalysisManager &Mgr,
                                        BugReporter &BR) const {
  ASTContext &Ctx = BR.getContext();

  if (!isUIViewControllerSubclass(Ctx, D))
    return;

  const char *SelectorNames[] = 
    {"addChildViewController", "viewDidAppear", "viewDidDisappear", 
     "viewWillAppear", "viewWillDisappear", "removeFromParentViewController",
     "didReceiveMemoryWarning", "viewDidUnload", "viewWillUnload",
     "viewDidLoad"};
  const unsigned SelectorArgumentCounts[] =
   {1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
  const size_t SelectorCount = llvm::array_lengthof(SelectorNames);
  assert(llvm::array_lengthof(SelectorArgumentCounts) == SelectorCount);

  // Fill the Selectors SmallSet with all selectors we want to check.
  llvm::SmallSet<Selector, 16> Selectors;
  for (size_t i = 0; i < SelectorCount; i++) { 
    unsigned ArgumentCount = SelectorArgumentCounts[i];
    const char *SelectorCString = SelectorNames[i];

    // Get the selector.
    IdentifierInfo *II = &Ctx.Idents.get(SelectorCString);
    Selectors.insert(Ctx.Selectors.getSelector(ArgumentCount, &II));
  }

  // Iterate over all instance methods.
  for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
                                                 E = D->instmeth_end();
       I != E; ++I) {
    Selector S = (*I)->getSelector();
    // Find out whether this is a selector that we want to check.
    if (!Selectors.count(S))
      continue;

    ObjCMethodDecl *MD = *I;

    // Check if the method calls its superclass implementation.
    if (MD->getBody())
    {
      FindSuperCallVisitor Visitor(S);
      Visitor.TraverseDecl(MD);

      // It doesn't call super, emit a diagnostic.
      if (!Visitor.DoesCallSuper) {
        PathDiagnosticLocation DLoc =
          PathDiagnosticLocation::createEnd(MD->getBody(),
                                            BR.getSourceManager(),
                                            Mgr.getAnalysisDeclContext(D));

        const char *Name = "Missing call to superclass";
        SmallString<256> Buf;
        llvm::raw_svector_ostream os(Buf);

        os << "The '" << S.getAsString() 
           << "' instance method in UIViewController subclass '" << *D
           << "' is missing a [super " << S.getAsString() << "] call";

        BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC,
                           os.str(), DLoc);
      }
    }
  }
}
예제 #18
0
/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
/// objective C interface.  This is a property reference expression.
Action::OwningExprResult Sema::
HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
                          Expr *BaseExpr, DeclarationName MemberName,
                          SourceLocation MemberLoc) {
  const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
  ObjCInterfaceDecl *IFace = IFaceT->getDecl();
  IdentifierInfo *Member = MemberName.getAsIdentifierInfo();

  // Search for a declared property first.
  if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
    // Check whether we can reference this property.
    if (DiagnoseUseOfDecl(PD, MemberLoc))
      return ExprError();
    QualType ResTy = PD->getType();
    Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
    ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
    if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
      ResTy = Getter->getSendResultType();
    return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
                                                   MemberLoc, BaseExpr));
  }
  // Check protocols on qualified interfaces.
  for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
       E = OPT->qual_end(); I != E; ++I)
    if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
      // Check whether we can reference this property.
      if (DiagnoseUseOfDecl(PD, MemberLoc))
        return ExprError();

      return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
                                                     MemberLoc, BaseExpr));
    }
  // If that failed, look for an "implicit" property by seeing if the nullary
  // selector is implemented.

  // FIXME: The logic for looking up nullary and unary selectors should be
  // shared with the code in ActOnInstanceMessage.

  Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
  ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);

  // If this reference is in an @implementation, check for 'private' methods.
  if (!Getter)
    Getter = IFace->lookupPrivateInstanceMethod(Sel);

  // Look through local category implementations associated with the class.
  if (!Getter)
    Getter = IFace->getCategoryInstanceMethod(Sel);
  if (Getter) {
    // Check if we can reference this property.
    if (DiagnoseUseOfDecl(Getter, MemberLoc))
      return ExprError();
  }
  // If we found a getter then this may be a valid dot-reference, we
  // will look for the matching setter, in case it is needed.
  Selector SetterSel =
    SelectorTable::constructSetterName(PP.getIdentifierTable(),
                                       PP.getSelectorTable(), Member);
  ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
  if (!Setter) {
    // If this reference is in an @implementation, also check for 'private'
    // methods.
    Setter = IFace->lookupPrivateInstanceMethod(SetterSel);
  }
  // Look through local category implementations associated with the class.
  if (!Setter)
    Setter = IFace->getCategoryInstanceMethod(SetterSel);

  if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
    return ExprError();

  if (Getter) {
    QualType PType;
    PType = Getter->getSendResultType();
    return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
                                    Setter, MemberLoc, BaseExpr));
  }

  // Attempt to correct for typos in property names.
  LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName);
  if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) &&
      Res.getAsSingle<ObjCPropertyDecl>()) {
    DeclarationName TypoResult = Res.getLookupName();
    Diag(MemberLoc, diag::err_property_not_found_suggest)
      << MemberName << QualType(OPT, 0) << TypoResult
      << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString());
    ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
    Diag(Property->getLocation(), diag::note_previous_decl)
      << Property->getDeclName();
    return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc);
  }
  
  Diag(MemberLoc, diag::err_property_not_found)
    << MemberName << QualType(OPT, 0);
  if (Setter && !Getter)
    Diag(Setter->getLocation(), diag::note_getter_unavailable)
      << MemberName << BaseExpr->getSourceRange();
  return ExprError();
}
static void cleanupDeallocOrFinalize(MigrationPass &pass) {
  ASTContext &Ctx = pass.Ctx;
  TransformActions &TA = pass.TA;
  DeclContext *DC = Ctx.getTranslationUnitDecl();
  Selector FinalizeSel =
      Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));

  typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
    impl_iterator;
  for (impl_iterator I = impl_iterator(DC->decls_begin()),
                     E = impl_iterator(DC->decls_end()); I != E; ++I) {
    ObjCMethodDecl *DeallocM = 0;
    ObjCMethodDecl *FinalizeM = 0;
    for (ObjCImplementationDecl::instmeth_iterator
           MI = I->instmeth_begin(),
           ME = I->instmeth_end(); MI != ME; ++MI) {
      ObjCMethodDecl *MD = *MI;
      if (!MD->hasBody())
        continue;
  
      if (MD->getMethodFamily() == OMF_dealloc) {
        DeallocM = MD;
      } else if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
        FinalizeM = MD;
      }
    }

    if (DeallocM) {
      if (isBodyEmpty(DeallocM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
        Transaction Trans(TA);
        TA.remove(DeallocM->getSourceRange());
      }

      if (FinalizeM) {
        Transaction Trans(TA);
        TA.remove(FinalizeM->getSourceRange());
      }

    } else if (FinalizeM) {
      if (isBodyEmpty(FinalizeM->getCompoundBody(), Ctx, pass.ARCMTMacroLocs)) {
        Transaction Trans(TA);
        TA.remove(FinalizeM->getSourceRange());
      } else {
        Transaction Trans(TA);
        TA.replaceText(FinalizeM->getSelectorStartLoc(), "finalize", "dealloc");
      }
    }
  }
}
예제 #20
0
static void checkObjCDealloc(const ObjCImplementationDecl *D,
                             const LangOptions& LOpts, BugReporter& BR) {

  assert (LOpts.getGC() != LangOptions::GCOnly);

  ASTContext &Ctx = BR.getContext();
  const ObjCInterfaceDecl *ID = D->getClassInterface();

  // Does the class contain any ivars that are pointers (or id<...>)?
  // If not, skip the check entirely.
  // NOTE: This is motivated by PR 2517:
  //        http://llvm.org/bugs/show_bug.cgi?id=2517

  bool containsPointerIvar = false;

  for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
       I!=E; ++I) {

    ObjCIvarDecl *ID = *I;
    QualType T = ID->getType();

    if (!T->isObjCObjectPointerType() ||
        ID->getAttr<IBOutletAttr>() || // Skip IBOutlets.
        ID->getAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections.
      continue;

    containsPointerIvar = true;
    break;
  }

  if (!containsPointerIvar)
    return;

  // Determine if the class subclasses NSObject.
  IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
  IdentifierInfo* SenTestCaseII = &Ctx.Idents.get("SenTestCase");


  for ( ; ID ; ID = ID->getSuperClass()) {
    IdentifierInfo *II = ID->getIdentifier();

    if (II == NSObjectII)
      break;

    // FIXME: For now, ignore classes that subclass SenTestCase, as these don't
    // need to implement -dealloc.  They implement tear down in another way,
    // which we should try and catch later.
    //  http://llvm.org/bugs/show_bug.cgi?id=3187
    if (II == SenTestCaseII)
      return;
  }

  if (!ID)
    return;

  // Get the "dealloc" selector.
  IdentifierInfo* II = &Ctx.Idents.get("dealloc");
  Selector S = Ctx.Selectors.getSelector(0, &II);
  ObjCMethodDecl *MD = 0;

  // Scan the instance methods for "dealloc".
  for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
       E = D->instmeth_end(); I!=E; ++I) {

    if ((*I)->getSelector() == S) {
      MD = *I;
      break;
    }
  }

  PathDiagnosticLocation DLoc =
    PathDiagnosticLocation::createBegin(D, BR.getSourceManager());

  if (!MD) { // No dealloc found.

    const char* name = LOpts.getGC() == LangOptions::NonGC
                       ? "missing -dealloc"
                       : "missing -dealloc (Hybrid MM, non-GC)";

    std::string buf;
    llvm::raw_string_ostream os(buf);
    os << "Objective-C class '" << *D << "' lacks a 'dealloc' instance method";

    BR.EmitBasicReport(D, name, categories::CoreFoundationObjectiveC,
                       os.str(), DLoc);
    return;
  }

  // dealloc found.  Scan for missing [super dealloc].
  if (MD->getBody() && !scan_dealloc(MD->getBody(), S)) {

    const char* name = LOpts.getGC() == LangOptions::NonGC
                       ? "missing [super dealloc]"
                       : "missing [super dealloc] (Hybrid MM, non-GC)";

    std::string buf;
    llvm::raw_string_ostream os(buf);
    os << "The 'dealloc' instance method in Objective-C class '" << *D
       << "' does not send a 'dealloc' message to its super class"
           " (missing [super dealloc])";

    BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC,
                       os.str(), DLoc);
    return;
  }

  // Get the "release" selector.
  IdentifierInfo* RII = &Ctx.Idents.get("release");
  Selector RS = Ctx.Selectors.getSelector(0, &RII);

  // Get the "self" identifier
  IdentifierInfo* SelfII = &Ctx.Idents.get("self");

  // Scan for missing and extra releases of ivars used by implementations
  // of synthesized properties
  for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(),
       E = D->propimpl_end(); I!=E; ++I) {

    // We can only check the synthesized properties
    if (I->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
      continue;

    ObjCIvarDecl *ID = I->getPropertyIvarDecl();
    if (!ID)
      continue;

    QualType T = ID->getType();
    if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars
      continue;

    const ObjCPropertyDecl *PD = I->getPropertyDecl();
    if (!PD)
      continue;

    // ivars cannot be set via read-only properties, so we'll skip them
    if (PD->isReadOnly())
      continue;

    // ivar must be released if and only if the kind of setter was not 'assign'
    bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
    if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx)
       != requiresRelease) {
      const char *name = 0;
      std::string buf;
      llvm::raw_string_ostream os(buf);

      if (requiresRelease) {
        name = LOpts.getGC() == LangOptions::NonGC
               ? "missing ivar release (leak)"
               : "missing ivar release (Hybrid MM, non-GC)";

        os << "The '" << *ID
           << "' instance variable was retained by a synthesized property but "
              "wasn't released in 'dealloc'";
      } else {
        name = LOpts.getGC() == LangOptions::NonGC
               ? "extra ivar release (use-after-release)"
               : "extra ivar release (Hybrid MM, non-GC)";

        os << "The '" << *ID
           << "' instance variable was not retained by a synthesized property "
              "but was released in 'dealloc'";
      }

      PathDiagnosticLocation SDLoc =
        PathDiagnosticLocation::createBegin(*I, BR.getSourceManager());

      BR.EmitBasicReport(MD, name, categories::CoreFoundationObjectiveC,
                         os.str(), SDLoc);
    }
  }
}
예제 #21
0
static bool 
ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
                                      const ObjCImplementationDecl *ImpDecl,
                                       const ObjCInterfaceDecl *IDecl,
                                      ObjCProtocolDecl *Protocol) {
  // In auto-synthesis, protocol properties are not synthesized. So,
  // a conforming protocol must have its required properties declared
  // in class interface.
  bool HasAtleastOneRequiredProperty = false;
  if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
    for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
         E = PDecl->prop_end(); P != E; ++P) {
      ObjCPropertyDecl *Property = *P;
      if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
        continue;
      HasAtleastOneRequiredProperty = true;
      DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName());
      if (R.size() == 0) {
        // Relax the rule and look into class's implementation for a synthesize
        // or dynamic declaration. Class is implementing a property coming from
        // another protocol. This still makes the target protocol as conforming.
        if (!ImpDecl->FindPropertyImplDecl(
                                  Property->getDeclName().getAsIdentifierInfo()))
          return false;
      }
      else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
          if ((ClassProperty->getPropertyAttributes()
              != Property->getPropertyAttributes()) ||
              !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
            return false;
      }
      else
        return false;
    }
  
  // At this point, all required properties in this protocol conform to those
  // declared in the class.
  // Check that class implements the required methods of the protocol too.
  bool HasAtleastOneRequiredMethod = false;
  if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
    if (PDecl->meth_begin() == PDecl->meth_end())
      return HasAtleastOneRequiredProperty;
    for (ObjCContainerDecl::method_iterator M = PDecl->meth_begin(),
         MEnd = PDecl->meth_end(); M != MEnd; ++M) {
      ObjCMethodDecl *MD = (*M);
      if (MD->isImplicit())
        continue;
      if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
        continue;
      DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName());
      if (R.size() == 0)
        return false;
      bool match = false;
      HasAtleastOneRequiredMethod = true;
      for (unsigned I = 0, N = R.size(); I != N; ++I)
        if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0]))
          if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
            match = true;
            break;
          }
      if (!match)
        return false;
    }
  }
  if (HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod)
    return true;
  return false;
}
예제 #22
0
/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an
/// objective C interface.  This is a property reference expression.
ExprResult Sema::
HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
                          Expr *BaseExpr, DeclarationName MemberName,
                          SourceLocation MemberLoc,
                          SourceLocation SuperLoc, QualType SuperType,
                          bool Super) {
  const ObjCInterfaceType *IFaceT = OPT->getInterfaceType();
  ObjCInterfaceDecl *IFace = IFaceT->getDecl();
  IdentifierInfo *Member = MemberName.getAsIdentifierInfo();

  if (IFace->isForwardDecl()) {
    Diag(MemberLoc, diag::err_property_not_found_forward_class)
         << MemberName << QualType(OPT, 0);
    Diag(IFace->getLocation(), diag::note_forward_class);
    return ExprError();
  }
  // Search for a declared property first.
  if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
    // Check whether we can reference this property.
    if (DiagnoseUseOfDecl(PD, MemberLoc))
      return ExprError();
    QualType ResTy = PD->getType();
    Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
    ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
    if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
      ResTy = Getter->getResultType();

    if (Super)
      return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
                                                     VK_LValue, OK_ObjCProperty,
                                                     MemberLoc, 
                                                     SuperLoc, SuperType));
    else
      return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
                                                     VK_LValue, OK_ObjCProperty,
                                                     MemberLoc, BaseExpr));
  }
  // Check protocols on qualified interfaces.
  for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
       E = OPT->qual_end(); I != E; ++I)
    if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) {
      // Check whether we can reference this property.
      if (DiagnoseUseOfDecl(PD, MemberLoc))
        return ExprError();
      if (Super)
        return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
                                                       VK_LValue,
                                                       OK_ObjCProperty,
                                                       MemberLoc, 
                                                       SuperLoc, SuperType));
      else
        return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
                                                       VK_LValue,
                                                       OK_ObjCProperty,
                                                       MemberLoc,
                                                       BaseExpr));
    }
  // If that failed, look for an "implicit" property by seeing if the nullary
  // selector is implemented.

  // FIXME: The logic for looking up nullary and unary selectors should be
  // shared with the code in ActOnInstanceMessage.

  Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
  ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
  
  // May be founf in property's qualified list.
  if (!Getter)
    Getter = LookupMethodInQualifiedType(Sel, OPT, true);

  // If this reference is in an @implementation, check for 'private' methods.
  if (!Getter)
    Getter = IFace->lookupPrivateMethod(Sel);

  // Look through local category implementations associated with the class.
  if (!Getter)
    Getter = IFace->getCategoryInstanceMethod(Sel);
  if (Getter) {
    // Check if we can reference this property.
    if (DiagnoseUseOfDecl(Getter, MemberLoc))
      return ExprError();
  }
  // If we found a getter then this may be a valid dot-reference, we
  // will look for the matching setter, in case it is needed.
  Selector SetterSel =
    SelectorTable::constructSetterName(PP.getIdentifierTable(),
                                       PP.getSelectorTable(), Member);
  ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
  
  // May be founf in property's qualified list.
  if (!Setter)
    Setter = LookupMethodInQualifiedType(SetterSel, OPT, true);
  
  if (!Setter) {
    // If this reference is in an @implementation, also check for 'private'
    // methods.
    Setter = IFace->lookupPrivateMethod(SetterSel);
  }
  // Look through local category implementations associated with the class.
  if (!Setter)
    Setter = IFace->getCategoryInstanceMethod(SetterSel);
    
  if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
    return ExprError();

  if (Getter || Setter) {
    QualType PType;
    if (Getter)
      PType = Getter->getSendResultType();
    else {
      ParmVarDecl *ArgDecl = *Setter->param_begin();
      PType = ArgDecl->getType();
    }
    
    ExprValueKind VK = VK_LValue;
    ExprObjectKind OK = OK_ObjCProperty;
    if (!getLangOptions().CPlusPlus && !PType.hasQualifiers() &&
        PType->isVoidType())
      VK = VK_RValue, OK = OK_Ordinary;

    if (Super)
      return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
                                                     PType, VK, OK,
                                                     MemberLoc,
                                                     SuperLoc, SuperType));
    else
      return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
                                                     PType, VK, OK,
                                                     MemberLoc, BaseExpr));

  }

  // Attempt to correct for typos in property names.
  LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName);
  if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) &&
      Res.getAsSingle<ObjCPropertyDecl>()) {
    DeclarationName TypoResult = Res.getLookupName();
    Diag(MemberLoc, diag::err_property_not_found_suggest)
      << MemberName << QualType(OPT, 0) << TypoResult
      << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString());
    ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
    Diag(Property->getLocation(), diag::note_previous_decl)
      << Property->getDeclName();
    return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc,
                                     SuperLoc, SuperType, Super);
  }
  ObjCInterfaceDecl *ClassDeclared;
  if (ObjCIvarDecl *Ivar = 
      IFace->lookupInstanceVariable(Member, ClassDeclared)) {
    QualType T = Ivar->getType();
    if (const ObjCObjectPointerType * OBJPT = 
        T->getAsObjCInterfacePointerType()) {
      const ObjCInterfaceType *IFaceT = OBJPT->getInterfaceType();
      if (ObjCInterfaceDecl *IFace = IFaceT->getDecl())
        if (IFace->isForwardDecl()) {
          Diag(MemberLoc, diag::err_property_not_as_forward_class)
          << MemberName << IFace;
          Diag(IFace->getLocation(), diag::note_forward_class);
          return ExprError();
        }
    }
  }
  
  Diag(MemberLoc, diag::err_property_not_found)
    << MemberName << QualType(OPT, 0);
  if (Setter)
    Diag(Setter->getLocation(), diag::note_getter_unavailable)
          << MemberName << BaseExpr->getSourceRange();
  return ExprError();
}
예제 #23
0
ExprResult Sema::
ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
                          IdentifierInfo &propertyName,
                          SourceLocation receiverNameLoc,
                          SourceLocation propertyNameLoc) {

  IdentifierInfo *receiverNamePtr = &receiverName;
  ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
                                                  receiverNameLoc);
  if (IFace == 0) {
    // If the "receiver" is 'super' in a method, handle it as an expression-like
    // property reference.
    if (receiverNamePtr->isStr("super")) {
      if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) {
        if (CurMethod->isInstanceMethod()) {
          QualType T = 
            Context.getObjCInterfaceType(CurMethod->getClassInterface());
          T = Context.getObjCObjectPointerType(T);
        
          return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
                                           /*BaseExpr*/0, &propertyName,
                                           propertyNameLoc,
                                           receiverNameLoc, T, true);
        }

        // Otherwise, if this is a class method, try dispatching to our
        // superclass.
        IFace = CurMethod->getClassInterface()->getSuperClass();
      }
    }
    
    if (IFace == 0) {
      Diag(receiverNameLoc, diag::err_expected_ident_or_lparen);
      return ExprError();
    }
  }

  // Search for a declared property first.
  Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName);
  ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel);

  // If this reference is in an @implementation, check for 'private' methods.
  if (!Getter)
    if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
      if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
        if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
          Getter = ImpDecl->getClassMethod(Sel);

  if (Getter) {
    // FIXME: refactor/share with ActOnMemberReference().
    // Check if we can reference this property.
    if (DiagnoseUseOfDecl(Getter, propertyNameLoc))
      return ExprError();
  }

  // Look for the matching setter, in case it is needed.
  Selector SetterSel =
    SelectorTable::constructSetterName(PP.getIdentifierTable(),
                                       PP.getSelectorTable(), &propertyName);

  ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
  if (!Setter) {
    // If this reference is in an @implementation, also check for 'private'
    // methods.
    if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
      if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
        if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
          Setter = ImpDecl->getClassMethod(SetterSel);
  }
  // Look through local category implementations associated with the class.
  if (!Setter)
    Setter = IFace->getCategoryClassMethod(SetterSel);

  if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc))
    return ExprError();

  if (Getter || Setter) {
    QualType PType;

    ExprValueKind VK = VK_LValue;
    if (Getter) {
      PType = Getter->getSendResultType();
      if (!getLangOptions().CPlusPlus &&
          !PType.hasQualifiers() && PType->isVoidType())
        VK = VK_RValue;
    } else {
      for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(),
           E = Setter->param_end(); PI != E; ++PI)
        PType = (*PI)->getType();
      VK = VK_LValue;
    }

    ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);

    return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
                                                   PType, VK, OK,
                                                   propertyNameLoc,
                                                   receiverNameLoc, IFace));
  }
  return ExprError(Diag(propertyNameLoc, diag::err_property_not_found)
                     << &propertyName << Context.getObjCInterfaceType(IFace));
}