void ObjCMethodDecl::createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *OID) { QualType selfTy; if (isInstanceMethod()) { // There may be no interface context due to error in declaration // of the interface (which has been reported). Recover gracefully. if (OID) { selfTy = Context.getObjCInterfaceType(OID); selfTy = Context.getObjCObjectPointerType(selfTy); } else { selfTy = Context.getObjCIdType(); } } else // we have a factory method. selfTy = Context.getObjCClassType(); bool selfIsPseudoStrong = false; bool selfIsConsumed = false; if (Context.getLangOpts().ObjCAutoRefCount) { if (isInstanceMethod()) { selfIsConsumed = hasAttr<NSConsumesSelfAttr>(); // 'self' is always __strong. It's actually pseudo-strong except // in init methods (or methods labeled ns_consumes_self), though. Qualifiers qs; qs.setObjCLifetime(Qualifiers::OCL_Strong); selfTy = Context.getQualifiedType(selfTy, qs); // In addition, 'self' is const unless this is an init method. if (getMethodFamily() != OMF_init && !selfIsConsumed) { selfTy = selfTy.withConst(); selfIsPseudoStrong = true; } } else { assert(isClassMethod()); // 'self' is always const in class methods. selfTy = selfTy.withConst(); selfIsPseudoStrong = true; } } ImplicitParamDecl *self = ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("self"), selfTy); setSelfDecl(self); if (selfIsConsumed) self->addAttr(new (Context) NSConsumedAttr(SourceLocation(), Context)); if (selfIsPseudoStrong) self->setARCPseudoStrong(true); setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("_cmd"), Context.getObjCSelType())); }
void ObjCMethodDecl::createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *OID) { QualType selfTy; if (isInstanceMethod()) { // There may be no interface context due to error in declaration // of the interface (which has been reported). Recover gracefully. if (OID) { selfTy = Context.getObjCInterfaceType(OID); selfTy = Context.getObjCObjectPointerType(selfTy); } else { selfTy = Context.getObjCIdType(); } } else // we have a factory method. selfTy = Context.getObjCClassType(); setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("self"), selfTy)); setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("_cmd"), Context.getObjCSelType())); }
// Returns a desugared version of the QualType, and marks ShouldAKA as true // whenever we remove significant sugar from the type. static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { QualifierCollector QC; while (true) { const Type *Ty = QC.strip(QT); // Don't aka just because we saw an elaborated type... if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) { QT = ET->desugar(); continue; } // ... or a paren type ... if (const ParenType *PT = dyn_cast<ParenType>(Ty)) { QT = PT->desugar(); continue; } // ...or a substituted template type parameter ... if (const SubstTemplateTypeParmType *ST = dyn_cast<SubstTemplateTypeParmType>(Ty)) { QT = ST->desugar(); continue; } // ...or an attributed type... if (const AttributedType *AT = dyn_cast<AttributedType>(Ty)) { QT = AT->desugar(); continue; } // ... or an auto type. if (const AutoType *AT = dyn_cast<AutoType>(Ty)) { if (!AT->isSugared()) break; QT = AT->desugar(); continue; } // Don't desugar template specializations. if (isa<TemplateSpecializationType>(Ty)) break; // Don't desugar magic Objective-C types. if (QualType(Ty,0) == Context.getObjCIdType() || QualType(Ty,0) == Context.getObjCClassType() || QualType(Ty,0) == Context.getObjCSelType() || QualType(Ty,0) == Context.getObjCProtoType()) break; // Don't desugar va_list. if (QualType(Ty,0) == Context.getBuiltinVaListType()) break; // Otherwise, do a single-step desugar. QualType Underlying; bool IsSugar = false; switch (Ty->getTypeClass()) { #define ABSTRACT_TYPE(Class, Base) #define TYPE(Class, Base) \ case Type::Class: { \ const Class##Type *CTy = cast<Class##Type>(Ty); \ if (CTy->isSugared()) { \ IsSugar = true; \ Underlying = CTy->desugar(); \ } \ break; \ } #include "clang/AST/TypeNodes.def" } // If it wasn't sugared, we're done. if (!IsSugar) break; // If the desugared type is a vector type, we don't want to expand // it, it will turn into an attribute mess. People want their "vec4". if (isa<VectorType>(Underlying)) break; // Don't desugar through the primary typedef of an anonymous type. if (const TagType *UTT = Underlying->getAs<TagType>()) if (const TypedefType *QTT = dyn_cast<TypedefType>(QT)) if (UTT->getDecl()->getTypedefForAnonDecl() == QTT->getDecl()) break; // Record that we actually looked through an opaque type here. ShouldAKA = true; QT = Underlying; } // If we have a pointer-like type, desugar the pointee as well. // FIXME: Handle other pointer-like types. if (const PointerType *Ty = QT->getAs<PointerType>()) { QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) { QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); } return QC.apply(Context, QT); }
/// Determines whether we should have an a.k.a. clause when /// pretty-printing a type. There are three main criteria: /// /// 1) Some types provide very minimal sugar that doesn't impede the /// user's understanding --- for example, elaborated type /// specifiers. If this is all the sugar we see, we don't want an /// a.k.a. clause. /// 2) Some types are technically sugared but are much more familiar /// when seen in their sugared form --- for example, va_list, /// vector types, and the magic Objective C types. We don't /// want to desugar these, even if we do produce an a.k.a. clause. /// 3) Some types may have already been desugared previously in this diagnostic. /// if this is the case, doing another "aka" would just be clutter. /// static bool ShouldAKA(ASTContext &Context, QualType QT, const Diagnostic::ArgumentValue *PrevArgs, unsigned NumPrevArgs, QualType &DesugaredQT) { QualType InputTy = QT; bool AKA = false; QualifierCollector Qc; while (true) { const Type *Ty = Qc.strip(QT); // Don't aka just because we saw an elaborated type... if (isa<ElaboratedType>(Ty)) { QT = cast<ElaboratedType>(Ty)->desugar(); continue; } // ...or a qualified name type... if (isa<QualifiedNameType>(Ty)) { QT = cast<QualifiedNameType>(Ty)->desugar(); continue; } // ...or an injected class name... if (isa<InjectedClassNameType>(Ty)) { QT = cast<InjectedClassNameType>(Ty)->desugar(); continue; } // ...or a substituted template type parameter. if (isa<SubstTemplateTypeParmType>(Ty)) { QT = cast<SubstTemplateTypeParmType>(Ty)->desugar(); continue; } // Don't desugar template specializations. if (isa<TemplateSpecializationType>(Ty)) break; // Don't desugar magic Objective-C types. if (QualType(Ty,0) == Context.getObjCIdType() || QualType(Ty,0) == Context.getObjCClassType() || QualType(Ty,0) == Context.getObjCSelType() || QualType(Ty,0) == Context.getObjCProtoType()) break; // Don't desugar va_list. if (QualType(Ty,0) == Context.getBuiltinVaListType()) break; // Otherwise, do a single-step desugar. QualType Underlying; bool IsSugar = false; switch (Ty->getTypeClass()) { #define ABSTRACT_TYPE(Class, Base) #define TYPE(Class, Base) \ case Type::Class: { \ const Class##Type *CTy = cast<Class##Type>(Ty); \ if (CTy->isSugared()) { \ IsSugar = true; \ Underlying = CTy->desugar(); \ } \ break; \ } #include "clang/AST/TypeNodes.def" } // If it wasn't sugared, we're done. if (!IsSugar) break; // If the desugared type is a vector type, we don't want to expand // it, it will turn into an attribute mess. People want their "vec4". if (isa<VectorType>(Underlying)) break; // Don't desugar through the primary typedef of an anonymous type. if (isa<TagType>(Underlying) && isa<TypedefType>(QT)) if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() == cast<TypedefType>(QT)->getDecl()) break; // Otherwise, we're tearing through something opaque; note that // we'll eventually need an a.k.a. clause and keep going. AKA = true; QT = Underlying; continue; } // If we never tore through opaque sugar, don't print aka. if (!AKA) return false; // If we did, check to see if we already desugared this type in this // diagnostic. If so, don't do it again. for (unsigned i = 0; i != NumPrevArgs; ++i) { // TODO: Handle ak_declcontext case. if (PrevArgs[i].first == Diagnostic::ak_qualtype) { void *Ptr = (void*)PrevArgs[i].second; QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); if (PrevTy == InputTy) return false; } } DesugaredQT = Qc.apply(QT); return true; }