Ejemplo n.º 1
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);
      }
  }
}
Ejemplo n.º 2
0
static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E,
                                 QualType &DeducedType,
                                 QualType &AlternateType) {
  // Handle ReturnStmts with no expressions.
  if (!E) {
    if (AlternateType.isNull())
      AlternateType = Ctx.VoidTy;

    return Ctx.hasSameType(DeducedType, Ctx.VoidTy);
  }

  QualType StrictType = E->getType();
  QualType LooseType = StrictType;

  // In C, enum constants have the type of their underlying integer type,
  // not the enum. When inferring block return types, we should allow
  // the enum type if an enum constant is used, unless the enum is
  // anonymous (in which case there can be no variables of its type).
  if (!Ctx.getLangOpts().CPlusPlus) {
    const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
    if (DRE) {
      const Decl *D = DRE->getDecl();
      if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
        const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
        if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl())
          LooseType = Ctx.getTypeDeclType(Enum);
      }
    }
  }

  // Special case for the first return statement we find.
  // The return type has already been tentatively set, but we might still
  // have an alternate type we should prefer.
  if (AlternateType.isNull())
    AlternateType = LooseType;

  if (Ctx.hasSameType(DeducedType, StrictType)) {
    // FIXME: The loose type is different when there are constants from two
    // different enums. We could consider warning here.
    if (AlternateType != Ctx.DependentTy)
      if (!Ctx.hasSameType(AlternateType, LooseType))
        AlternateType = Ctx.VoidTy;
    return true;
  }

  if (Ctx.hasSameType(DeducedType, LooseType)) {
    // Use DependentTy to signal that we're using an alternate type and may
    // need to add casts somewhere.
    AlternateType = Ctx.DependentTy;
    return true;
  }

  if (Ctx.hasSameType(AlternateType, StrictType) ||
      Ctx.hasSameType(AlternateType, LooseType)) {
    DeducedType = AlternateType;
    // Use DependentTy to signal that we're using an alternate type and may
    // need to add casts somewhere.
    AlternateType = Ctx.DependentTy;
    return true;
  }

  return false;
}
/// \brief The LoopFixer callback, which determines if loops discovered by the
/// matchers are convertible, printing information about the loops if so.
void LoopFixer::run(const MatchFinder::MatchResult &Result) {
  const BoundNodes &Nodes = Result.Nodes;
  Confidence ConfidenceLevel(RL_Safe);
  ASTContext *Context = Result.Context;
  const ForStmt *TheLoop = Nodes.getStmtAs<ForStmt>(LoopName);

  if (!Owner.isFileModifiable(Context->getSourceManager(),TheLoop->getForLoc()))
    return;

  // Check that we have exactly one index variable and at most one end variable.
  const VarDecl *LoopVar = Nodes.getDeclAs<VarDecl>(IncrementVarName);
  const VarDecl *CondVar = Nodes.getDeclAs<VarDecl>(ConditionVarName);
  const VarDecl *InitVar = Nodes.getDeclAs<VarDecl>(InitVarName);
  if (!areSameVariable(LoopVar, CondVar) || !areSameVariable(LoopVar, InitVar))
    return;
  const VarDecl *EndVar = Nodes.getDeclAs<VarDecl>(EndVarName);
  const VarDecl *ConditionEndVar =
      Nodes.getDeclAs<VarDecl>(ConditionEndVarName);
  if (EndVar && !areSameVariable(EndVar, ConditionEndVar))
    return;

  // If the end comparison isn't a variable, we can try to work with the
  // expression the loop variable is being tested against instead.
  const CXXMemberCallExpr *EndCall =
      Nodes.getStmtAs<CXXMemberCallExpr>(EndCallName);
  const Expr *BoundExpr = Nodes.getStmtAs<Expr>(ConditionBoundName);
  // If the loop calls end()/size() after each iteration, lower our confidence
  // level.
  if (FixerKind != LFK_Array && !EndVar)
    ConfidenceLevel.lowerTo(RL_Reasonable);

  const Expr *ContainerExpr = nullptr;
  bool DerefByValue = false;
  bool DerefByConstRef = false;
  bool ContainerNeedsDereference = false;
  // FIXME: Try to put most of this logic inside a matcher. Currently, matchers
  // don't allow the right-recursive checks in digThroughConstructors.
  if (FixerKind == LFK_Iterator) {
    ContainerExpr = findContainer(Context, LoopVar->getInit(),
                                  EndVar ? EndVar->getInit() : EndCall,
                                  &ContainerNeedsDereference);

    QualType InitVarType = InitVar->getType();
    QualType CanonicalInitVarType = InitVarType.getCanonicalType();

    const CXXMemberCallExpr *BeginCall =
        Nodes.getNodeAs<CXXMemberCallExpr>(BeginCallName);
    assert(BeginCall && "Bad Callback. No begin call expression.");
    QualType CanonicalBeginType =
        BeginCall->getMethodDecl()->getReturnType().getCanonicalType();

    if (CanonicalBeginType->isPointerType() &&
        CanonicalInitVarType->isPointerType()) {
      QualType BeginPointeeType = CanonicalBeginType->getPointeeType();
      QualType InitPointeeType = CanonicalInitVarType->getPointeeType();
      // If the initializer and the variable are both pointers check if the
      // un-qualified pointee types match otherwise we don't use auto.
      if (!Context->hasSameUnqualifiedType(InitPointeeType, BeginPointeeType))
        return;
    } else {
      // Check for qualified types to avoid conversions from non-const to const
      // iterator types.
      if (!Context->hasSameType(CanonicalInitVarType, CanonicalBeginType))
        return;
    }

    DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != nullptr;
    if (!DerefByValue) {
      if (const QualType *DerefType =
              Nodes.getNodeAs<QualType>(DerefByRefResultName)) {
        // A node will only be bound with DerefByRefResultName if we're dealing
        // with a user-defined iterator type. Test the const qualification of
        // the reference type.
        DerefByConstRef = (*DerefType)->getAs<ReferenceType>()->getPointeeType()
            .isConstQualified();
      } else {
        // By nature of the matcher this case is triggered only for built-in
        // iterator types (i.e. pointers).
        assert(isa<PointerType>(CanonicalInitVarType) &&
               "Non-class iterator type is not a pointer type");
        QualType InitPointeeType = CanonicalInitVarType->getPointeeType();
        QualType BeginPointeeType = CanonicalBeginType->getPointeeType();
        // If the initializer and variable have both the same type just use auto
        // otherwise we test for const qualification of the pointed-at type.
        if (!Context->hasSameType(InitPointeeType, BeginPointeeType))
          DerefByConstRef = InitPointeeType.isConstQualified();
      }
    } else {
      // If the dereference operator returns by value then test for the
      // canonical const qualification of the init variable type.
      DerefByConstRef = CanonicalInitVarType.isConstQualified();
    }
  } else if (FixerKind == LFK_PseudoArray) {
    if (!EndCall)
      return;
    ContainerExpr = EndCall->getImplicitObjectArgument();
    const MemberExpr *Member = dyn_cast<MemberExpr>(EndCall->getCallee());
    if (!Member)
      return;
    ContainerNeedsDereference = Member->isArrow();
  }
  // We must know the container or an array length bound.
  if (!ContainerExpr && !BoundExpr)
    return;

  findAndVerifyUsages(Context, LoopVar, EndVar, ContainerExpr, BoundExpr,
                      ContainerNeedsDereference, DerefByValue, DerefByConstRef,
                      TheLoop, ConfidenceLevel);
}
Ejemplo n.º 4
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;
}