Files
clang-p2996/clang/lib/ARCMigrate/TransGCAttrs.cpp
David Blaikie 6adc78e0df Replace TypeLoc llvm::cast support to be well-defined.
The TypeLoc hierarchy used the llvm::cast machinery to perform undefined
behavior by casting pointers/references to TypeLoc objects to derived types
and then using the derived copy constructors (or even returning pointers to
derived types that actually point to the original TypeLoc object).

Some context is in this thread:
http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-December/056804.html
Though it's spread over a few months which can be hard to read in the mail
archive.

llvm-svn: 175462
2013-02-18 22:06:02 +00:00

360 lines
12 KiB
C++

//===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Transforms.h"
#include "Internals.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace arcmt;
using namespace trans;
namespace {
/// \brief Collects all the places where GC attributes __strong/__weak occur.
class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
MigrationContext &MigrateCtx;
bool FullyMigratable;
std::vector<ObjCPropertyDecl *> &AllProps;
typedef RecursiveASTVisitor<GCAttrsCollector> base;
public:
GCAttrsCollector(MigrationContext &ctx,
std::vector<ObjCPropertyDecl *> &AllProps)
: MigrateCtx(ctx), FullyMigratable(false),
AllProps(AllProps) { }
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
handleAttr(TL);
return true;
}
bool TraverseDecl(Decl *D) {
if (!D || D->isImplicit())
return true;
SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
lookForAttribute(PropD, PropD->getTypeSourceInfo());
AllProps.push_back(PropD);
} else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
lookForAttribute(DD, DD->getTypeSourceInfo());
}
return base::TraverseDecl(D);
}
void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
if (!TInfo)
return;
TypeLoc TL = TInfo->getTypeLoc();
while (TL) {
if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
TL = QL.getUnqualifiedLoc();
} else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
if (handleAttr(Attr, D))
break;
TL = Attr.getModifiedLoc();
} else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
TL = Arr.getElementLoc();
} else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
TL = PT.getPointeeLoc();
} else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
TL = RT.getPointeeLoc();
else
break;
}
}
bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
return false;
SourceLocation Loc = TL.getAttrNameLoc();
unsigned RawLoc = Loc.getRawEncoding();
if (MigrateCtx.AttrSet.count(RawLoc))
return true;
ASTContext &Ctx = MigrateCtx.Pass.Ctx;
SourceManager &SM = Ctx.getSourceManager();
if (Loc.isMacroID())
Loc = SM.getImmediateExpansionRange(Loc).first;
SmallString<32> Buf;
bool Invalid = false;
StringRef Spell = Lexer::getSpelling(
SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
Buf, SM, Ctx.getLangOpts(), &Invalid);
if (Invalid)
return false;
MigrationContext::GCAttrOccurrence::AttrKind Kind;
if (Spell == "strong")
Kind = MigrationContext::GCAttrOccurrence::Strong;
else if (Spell == "weak")
Kind = MigrationContext::GCAttrOccurrence::Weak;
else
return false;
MigrateCtx.AttrSet.insert(RawLoc);
MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
Attr.Kind = Kind;
Attr.Loc = Loc;
Attr.ModifiedType = TL.getModifiedLoc().getType();
Attr.Dcl = D;
Attr.FullyMigratable = FullyMigratable;
return true;
}
bool isMigratable(Decl *D) {
if (isa<TranslationUnitDecl>(D))
return false;
if (isInMainFile(D))
return true;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
return FD->hasBody();
if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
return hasObjCImpl(ContD);
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
for (CXXRecordDecl::method_iterator
MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
if (MI->isOutOfLine())
return true;
}
return false;
}
return isMigratable(cast<Decl>(D->getDeclContext()));
}
static bool hasObjCImpl(Decl *D) {
if (!D)
return false;
if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
return ID->getImplementation() != 0;
if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
return CD->getImplementation() != 0;
if (isa<ObjCImplDecl>(ContD))
return true;
return false;
}
return false;
}
bool isInMainFile(Decl *D) {
if (!D)
return false;
for (Decl::redecl_iterator
I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
if (!isInMainFile(I->getLocation()))
return false;
return true;
}
bool isInMainFile(SourceLocation Loc) {
if (Loc.isInvalid())
return false;
SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
}
};
} // anonymous namespace
static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
TransformActions &TA = MigrateCtx.Pass.TA;
for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
if (Attr.FullyMigratable && Attr.Dcl) {
if (Attr.ModifiedType.isNull())
continue;
if (!Attr.ModifiedType->isObjCRetainableType()) {
TA.reportError("GC managed memory will become unmanaged in ARC",
Attr.Loc);
}
}
}
}
static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
TransformActions &TA = MigrateCtx.Pass.TA;
for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
if (Attr.ModifiedType.isNull() ||
!Attr.ModifiedType->isObjCRetainableType())
continue;
if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
/*AllowOnUnknownClass=*/true)) {
Transaction Trans(TA);
if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
diag::err_arc_unsupported_weak_class,
Attr.Loc);
}
}
}
}
typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
static void checkAllAtProps(MigrationContext &MigrateCtx,
SourceLocation AtLoc,
IndivPropsTy &IndProps) {
if (IndProps.empty())
return;
for (IndivPropsTy::iterator
PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
QualType T = (*PI)->getType();
if (T.isNull() || !T->isObjCRetainableType())
return;
}
SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
bool hasWeak = false, hasStrong = false;
ObjCPropertyDecl::PropertyAttributeKind
Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
for (IndivPropsTy::iterator
PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
ObjCPropertyDecl *PD = *PI;
Attrs = PD->getPropertyAttributesAsWritten();
TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
if (!TInfo)
return;
TypeLoc TL = TInfo->getTypeLoc();
if (AttributedTypeLoc ATL =
TL.getAs<AttributedTypeLoc>()) {
ATLs.push_back(std::make_pair(ATL, PD));
if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
hasWeak = true;
} else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
hasStrong = true;
else
return;
}
}
if (ATLs.empty())
return;
if (hasWeak && hasStrong)
return;
TransformActions &TA = MigrateCtx.Pass.TA;
Transaction Trans(TA);
if (GCAttrsCollector::hasObjCImpl(
cast<Decl>(IndProps.front()->getDeclContext()))) {
if (hasWeak)
MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
} else {
StringRef toAttr = "strong";
if (hasWeak) {
if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
/*AllowOnUnkwownClass=*/true))
toAttr = "weak";
else
toAttr = "unsafe_unretained";
}
if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
else
MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
}
for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
if (Loc.isMacroID())
Loc = MigrateCtx.Pass.Ctx.getSourceManager()
.getImmediateExpansionRange(Loc).first;
TA.remove(Loc);
TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
ATLs[i].second->getLocation());
MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
}
}
static void checkAllProps(MigrationContext &MigrateCtx,
std::vector<ObjCPropertyDecl *> &AllProps) {
typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
ObjCPropertyDecl *PD = AllProps[i];
if (PD->getPropertyAttributesAsWritten() &
(ObjCPropertyDecl::OBJC_PR_assign |
ObjCPropertyDecl::OBJC_PR_readonly)) {
SourceLocation AtLoc = PD->getAtLoc();
if (AtLoc.isInvalid())
continue;
unsigned RawAt = AtLoc.getRawEncoding();
AtProps[RawAt].push_back(PD);
}
}
for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
IndivPropsTy &IndProps = I->second;
checkAllAtProps(MigrateCtx, AtLoc, IndProps);
}
}
void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
std::vector<ObjCPropertyDecl *> AllProps;
GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
errorForGCAttrsOnNonObjC(MigrateCtx);
checkAllProps(MigrateCtx, AllProps);
checkWeakGCAttrs(MigrateCtx);
}
void MigrationContext::dumpGCAttrs() {
llvm::errs() << "\n################\n";
for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
GCAttrOccurrence &Attr = GCAttrs[i];
llvm::errs() << "KIND: "
<< (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
llvm::errs() << "\nLOC: ";
Attr.Loc.dump(Pass.Ctx.getSourceManager());
llvm::errs() << "\nTYPE: ";
Attr.ModifiedType.dump();
if (Attr.Dcl) {
llvm::errs() << "DECL:\n";
Attr.Dcl->dump();
} else {
llvm::errs() << "DECL: NONE";
}
llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
llvm::errs() << "\n----------------\n";
}
llvm::errs() << "\n################\n";
}