bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, const CXXMethodDecl *& MD) const { QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal); DeclContext::lookup_const_iterator Op, OpEnd; for (llvm::tie(Op, OpEnd) = this->lookup(OpName); Op != OpEnd; ++Op) { // C++ [class.copy]p9: // A user-declared copy assignment operator is a non-static non-template // member function of class X with exactly one parameter of type X, X&, // const X&, volatile X& or const volatile X&. const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op); if (!Method) continue; if (Method->isStatic()) continue; if (Method->getPrimaryTemplate()) continue; const FunctionProtoType *FnType = Method->getType()->getAs<FunctionProtoType>(); assert(FnType && "Overloaded operator has no prototype."); // Don't assert on this; an invalid decl might have been left in the AST. if (FnType->getNumArgs() != 1 || FnType->isVariadic()) continue; bool AcceptsConst = true; QualType ArgType = FnType->getArgType(0); if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) { ArgType = Ref->getPointeeType(); // Is it a non-const lvalue reference? if (!ArgType.isConstQualified()) AcceptsConst = false; } if (!Context.hasSameUnqualifiedType(ArgType, ClassType)) continue; MD = Method; // We have a single argument of type cv X or cv X&, i.e. we've found the // copy assignment operator. Return whether it accepts const arguments. return AcceptsConst; } assert(isInvalidDecl() && "No copy assignment operator declared in valid code."); return false; }
void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl) { // We're interested specifically in copy assignment operators. const FunctionProtoType *FnType = OpDecl->getType()->getAs<FunctionProtoType>(); assert(FnType && "Overloaded operator has no proto function type."); assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); // Copy assignment operators must be non-templates. if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate()) return; QualType ArgType = FnType->getArgType(0); if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) ArgType = Ref->getPointeeType(); ArgType = ArgType.getUnqualifiedType(); QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) return; // This is a copy assignment operator. // Note on the decl that it is a copy assignment operator. OpDecl->setCopyAssignment(true); // Suppress the implicit declaration of a copy constructor. data().UserDeclaredCopyAssignment = true; data().DeclaredCopyAssignment = true; // C++ [class.copy]p11: // A copy assignment operator is trivial if it is implicitly declared. // FIXME: C++0x: don't do this for "= default" copy operators. data().HasTrivialCopyAssignment = false; // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. data().PlainOldData = false; }
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; // FIXME. Don't know what todo with attributes, skip for now. if (Method->hasAttrs()) 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.hasSameUnqualifiedType(ArgType, GRT) || SetterMethod->hasAttrs()) continue; edit::Commit commit(*Editor); rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit); Editor->commit(commit); } } }
/// \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); }