blob: 79dc0538b69f84331748d1dd6a3aa56eb854307d [file] [log] [blame]
//===--- 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/Lex/Lexer.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/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;
typedef RecursiveASTVisitor<GCAttrsCollector> base;
public:
explicit GCAttrsCollector(MigrationContext &ctx)
: MigrateCtx(ctx), FullyMigratable(false) { }
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
handleAttr(TL);
return true;
}
bool TraverseDecl(Decl *D) {
if (!D || D->isImplicit())
return true;
bool migratable = isMigratable(D);
SaveAndRestore<bool> Save(FullyMigratable, migratable);
if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D))
lookForAttribute(DD, DD->getTypeSourceInfo());
else if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D))
lookForAttribute(PropD, PropD->getTypeSourceInfo());
return base::TraverseDecl(D);
}
void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
if (!TInfo)
return;
TypeLoc TL = TInfo->getTypeLoc();
while (TL) {
if (const AttributedTypeLoc *Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
if (handleAttr(*Attr, D))
break;
TL = Attr->getModifiedLoc();
} if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
TL = Arr->getElementLoc();
} else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
TL = PT->getPointeeLoc();
} else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
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();
llvm::SmallString<32> Buf;
bool Invalid = false;
StringRef Spell = Lexer::getSpelling(
SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
Buf, SM, Ctx.getLangOptions(), &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 = SM.getImmediateExpansionRange(Loc).first;
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)) {
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;
}
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()));
}
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 clearRedundantStrongs(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::Strong &&
Attr.FullyMigratable && Attr.Dcl) {
TypeSourceInfo *TInfo = 0;
if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(Attr.Dcl))
TInfo = DD->getTypeSourceInfo();
else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(Attr.Dcl))
TInfo = PD->getTypeSourceInfo();
if (!TInfo)
continue;
if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
Transaction Trans(TA);
TA.remove(Attr.Loc);
}
}
}
}
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);
}
}
}
}
void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
GCAttrsCollector(MigrateCtx).TraverseDecl(
MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
clearRedundantStrongs(MigrateCtx);
errorForGCAttrsOnNonObjC(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";
}