зеркало из https://github.com/microsoft/clang-1.git
[arcmt] Collect all the places where GC attributes __strong/__weak occur.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143883 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
b0d5db1b7c
Коммит
f38fa73e60
|
@ -12,6 +12,7 @@ add_clang_library(clangARCMigrate
|
|||
TransEmptyStatementsAndDealloc.cpp
|
||||
TransformActions.cpp
|
||||
Transforms.cpp
|
||||
TransGCAttrs.cpp
|
||||
TransGCCalls.cpp
|
||||
TransProperties.cpp
|
||||
TransRetainReleaseDealloc.cpp
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
//===--- 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 = 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)) {
|
||||
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
|
||||
|
||||
void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
|
||||
GCAttrsCollector(MigrateCtx).TraverseDecl(
|
||||
MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
|
||||
#if 0
|
||||
llvm::errs() << "\n################\n";
|
||||
for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
|
||||
MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
|
||||
llvm::errs() << "KIND: "
|
||||
<< (Attr.Kind == MigrationContext::GCAttrOccurrence::Strong ? "strong"
|
||||
: "weak");
|
||||
llvm::errs() << "\nLOC: ";
|
||||
Attr.Loc.dump(MigrateCtx.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";
|
||||
#endif
|
||||
}
|
|
@ -27,13 +27,15 @@ class GCCollectableCallsChecker :
|
|||
public:
|
||||
GCCollectableCallsChecker(MigrationContext &ctx, ParentMap &map)
|
||||
: MigrateCtx(ctx), PMap(map) {
|
||||
IdentifierTable &Ids = MigrateCtx.getPass().Ctx.Idents;
|
||||
IdentifierTable &Ids = MigrateCtx.Pass.Ctx.Idents;
|
||||
NSMakeCollectableII = &Ids.get("NSMakeCollectable");
|
||||
CFMakeCollectableII = &Ids.get("CFMakeCollectable");
|
||||
}
|
||||
|
||||
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
||||
|
||||
bool VisitCallExpr(CallExpr *E) {
|
||||
TransformActions &TA = MigrateCtx.getPass().TA;
|
||||
TransformActions &TA = MigrateCtx.Pass.TA;
|
||||
|
||||
if (MigrateCtx.isGCOwnedNonObjC(E->getType())) {
|
||||
TA.reportError("call returns pointer to GC managed memory; "
|
||||
|
|
|
@ -528,6 +528,6 @@ public:
|
|||
|
||||
void PropertyRewriteTraverser::traverseObjCImplementation(
|
||||
ObjCImplementationContext &ImplCtx) {
|
||||
PropertiesRewriter(ImplCtx.getMigrationContext().getPass())
|
||||
PropertiesRewriter(ImplCtx.getMigrationContext().Pass)
|
||||
.doTransform(ImplCtx.getImplementationDecl());
|
||||
}
|
||||
|
|
|
@ -302,6 +302,8 @@ class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
|
|||
public:
|
||||
ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
|
||||
|
||||
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
||||
|
||||
bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
|
||||
ObjCImplementationContext ImplCtx(MigrateCtx, D);
|
||||
for (MigrationContext::traverser_iterator
|
||||
|
@ -355,6 +357,10 @@ bool MigrationContext::isGCOwnedNonObjC(QualType T) {
|
|||
}
|
||||
|
||||
void MigrationContext::traverse(TranslationUnitDecl *TU) {
|
||||
for (traverser_iterator
|
||||
I = traversers_begin(), E = traversers_end(); I != E; ++I)
|
||||
(*I)->traverseTU(*this);
|
||||
|
||||
ASTTransform(*this).TraverseDecl(TU);
|
||||
}
|
||||
|
||||
|
@ -367,6 +373,7 @@ static void traverseAST(MigrationPass &pass) {
|
|||
|
||||
if (pass.isGCMigration()) {
|
||||
MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
|
||||
MigrateCtx.addTraverser(new GCAttrsTraverser());
|
||||
}
|
||||
MigrateCtx.addTraverser(new PropertyRewriteTraverser());
|
||||
|
||||
|
|
|
@ -79,14 +79,26 @@ public:
|
|||
};
|
||||
|
||||
class MigrationContext {
|
||||
MigrationPass &Pass;
|
||||
std::vector<ASTTraverser *> Traversers;
|
||||
|
||||
public:
|
||||
MigrationPass &Pass;
|
||||
|
||||
struct GCAttrOccurrence {
|
||||
enum AttrKind { Weak, Strong } Kind;
|
||||
SourceLocation Loc;
|
||||
QualType ModifiedType;
|
||||
Decl *Dcl;
|
||||
/// \brief true if the attribute is owned, e.g. it is in a body and not just
|
||||
/// in an interface.
|
||||
bool FullyMigratable;
|
||||
};
|
||||
std::vector<GCAttrOccurrence> GCAttrs;
|
||||
|
||||
llvm::DenseSet<unsigned> AttrSet;
|
||||
|
||||
explicit MigrationContext(MigrationPass &pass) : Pass(pass) {}
|
||||
~MigrationContext();
|
||||
|
||||
MigrationPass &getPass() { return Pass; }
|
||||
|
||||
typedef std::vector<ASTTraverser *>::iterator traverser_iterator;
|
||||
traverser_iterator traversers_begin() { return Traversers.begin(); }
|
||||
|
@ -108,6 +120,11 @@ public:
|
|||
|
||||
// GC transformations
|
||||
|
||||
class GCAttrsTraverser : public ASTTraverser {
|
||||
public:
|
||||
virtual void traverseTU(MigrationContext &MigrateCtx);
|
||||
};
|
||||
|
||||
class GCCollectableCallsTraverser : public ASTTraverser {
|
||||
public:
|
||||
virtual void traverseBody(BodyContext &BodyCtx);
|
||||
|
|
Загрузка…
Ссылка в новой задаче