Move the logic that searches for overridden methods from libclang to

ASTContext so that it can be widely available.

llvm-svn: 165473
This commit is contained in:
Argyrios Kyrtzidis 2012-10-09 01:23:50 +00:00
parent cc4ca0a324
commit b9556e695f
3 changed files with 202 additions and 180 deletions

View File

@ -625,6 +625,16 @@ public:
/// Overridden method.
void addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden);
/// \brief Return C++ or ObjC overridden methods for the given \p Method.
///
/// An ObjC method is considered to override any method in the class's
/// base classes, its protocols, or its categories' protocols, that has
/// the same selector and is of the same kind (class or instance).
/// A method in an implementation is not considered as overriding the same
/// method in the interface or its categories.
void getOverriddenMethods(const NamedDecl *Method,
SmallVectorImpl<const NamedDecl *> &Overridden);
/// \brief Notify the AST context that a new import declaration has been
/// parsed or implicitly created within this translation unit.

View File

@ -1026,6 +1026,192 @@ void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method,
OverriddenMethods[Method].push_back(Overridden);
}
static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
const ObjCMethodDecl *Method,
SmallVectorImpl<const NamedDecl *> &Methods,
bool MovedToSuper) {
if (!Container)
return;
// In categories look for overriden methods from protocols. A method from
// category is not "overriden" since it is considered as the "same" method
// (same USR) as the one from the interface.
if (const ObjCCategoryDecl *
Category = dyn_cast<ObjCCategoryDecl>(Container)) {
// Check whether we have a matching method at this category but only if we
// are at the super class level.
if (MovedToSuper)
if (ObjCMethodDecl *
Overridden = Container->getMethod(Method->getSelector(),
Method->isInstanceMethod()))
if (Method != Overridden) {
// We found an override at this category; there is no need to look
// into its protocols.
Methods.push_back(Overridden);
return;
}
for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
PEnd = Category->protocol_end();
P != PEnd; ++P)
CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
return;
}
// Check whether we have a matching method at this level.
if (const ObjCMethodDecl *
Overridden = Container->getMethod(Method->getSelector(),
Method->isInstanceMethod()))
if (Method != Overridden) {
// We found an override at this level; there is no need to look
// into other protocols or categories.
Methods.push_back(Overridden);
return;
}
if (const ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)){
for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
PEnd = Protocol->protocol_end();
P != PEnd; ++P)
CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
}
if (const ObjCInterfaceDecl *
Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
PEnd = Interface->protocol_end();
P != PEnd; ++P)
CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
for (const ObjCCategoryDecl *Category = Interface->getCategoryList();
Category; Category = Category->getNextClassCategory())
CollectOverriddenMethodsRecurse(Category, Method, Methods,
MovedToSuper);
if (const ObjCInterfaceDecl *Super = Interface->getSuperClass())
return CollectOverriddenMethodsRecurse(Super, Method, Methods,
/*MovedToSuper=*/true);
}
}
static inline void CollectOverriddenMethods(const ObjCContainerDecl *Container,
const ObjCMethodDecl *Method,
SmallVectorImpl<const NamedDecl *> &Methods) {
CollectOverriddenMethodsRecurse(Container, Method, Methods,
/*MovedToSuper=*/false);
}
static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
SmallVectorImpl<const NamedDecl *> &overridden) {
assert(Method->isOverriding());
if (const ObjCProtocolDecl *
ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
CollectOverriddenMethods(ProtD, Method, overridden);
} else if (const ObjCImplDecl *
IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) {
const ObjCInterfaceDecl *ID = IMD->getClassInterface();
if (!ID)
return;
// Start searching for overridden methods using the method from the
// interface as starting point.
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
Method->isInstanceMethod()))
Method = IFaceMeth;
CollectOverriddenMethods(ID, Method, overridden);
} else if (const ObjCCategoryDecl *
CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) {
const ObjCInterfaceDecl *ID = CatD->getClassInterface();
if (!ID)
return;
// Start searching for overridden methods using the method from the
// interface as starting point.
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
Method->isInstanceMethod()))
Method = IFaceMeth;
CollectOverriddenMethods(ID, Method, overridden);
} else {
CollectOverriddenMethods(
dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()),
Method, overridden);
}
}
static void collectOnCategoriesAfterLocation(SourceLocation Loc,
const ObjCInterfaceDecl *Class,
SourceManager &SM,
const ObjCMethodDecl *Method,
SmallVectorImpl<const NamedDecl *> &Methods) {
if (!Class)
return;
for (const ObjCCategoryDecl *Category = Class->getCategoryList();
Category; Category = Category->getNextClassCategory())
if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
CollectOverriddenMethodsRecurse(Category, Method, Methods, true);
collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM,
Method, Methods);
}
/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding()
/// returns false.
/// You'd think that in that case there are no overrides but categories can
/// "introduce" new overridden methods that are missed by Sema because the
/// overrides lookup that it does for methods, inside implementations, will
/// stop at the interface level (if there is a method there) and not look
/// further in super classes.
static void collectOverriddenMethodsFast(SourceManager &SM,
const ObjCMethodDecl *Method,
SmallVectorImpl<const NamedDecl *> &Methods) {
assert(!Method->isOverriding());
const ObjCContainerDecl *
ContD = cast<ObjCContainerDecl>(Method->getDeclContext());
if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD))
return;
const ObjCInterfaceDecl *Class = Method->getClassInterface();
if (!Class)
return;
collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(),
SM, Method, Methods);
}
void ASTContext::getOverriddenMethods(const NamedDecl *D,
SmallVectorImpl<const NamedDecl *> &Overridden) {
assert(D);
if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
for (CXXMethodDecl::method_iterator
M = CXXMethod->begin_overridden_methods(),
MEnd = CXXMethod->end_overridden_methods();
M != MEnd; ++M)
Overridden.push_back(*M);
return;
}
const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
if (!Method)
return;
if (Method->isRedeclaration()) {
Method = cast<ObjCContainerDecl>(Method->getDeclContext())->
getMethod(Method->getSelector(), Method->isInstanceMethod());
}
if (!Method->isOverriding()) {
collectOverriddenMethodsFast(SourceMgr, Method, Overridden);
} else {
collectOverriddenMethodsSlow(Method, Overridden);
assert(!Overridden.empty() &&
"ObjCMethodDecl's overriding bit is not as expected");
}
}
void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
assert(!Import->NextLocalImport && "Import declaration already in the chain");
assert(!Import->isFromASTFile() && "Non-local import declaration");

View File

@ -795,194 +795,20 @@ CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) {
return static_cast<CXTranslationUnit>(Cursor.data[2]);
}
static void CollectOverriddenMethodsRecurse(CXTranslationUnit TU,
ObjCContainerDecl *Container,
ObjCMethodDecl *Method,
SmallVectorImpl<CXCursor> &Methods,
bool MovedToSuper) {
if (!Container)
return;
// In categories look for overriden methods from protocols. A method from
// category is not "overriden" since it is considered as the "same" method
// (same USR) as the one from the interface.
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
// Check whether we have a matching method at this category but only if we
// are at the super class level.
if (MovedToSuper)
if (ObjCMethodDecl *
Overridden = Container->getMethod(Method->getSelector(),
Method->isInstanceMethod()))
if (Method != Overridden) {
// We found an override at this category; there is no need to look
// into its protocols.
Methods.push_back(MakeCXCursor(Overridden, TU));
return;
}
for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
PEnd = Category->protocol_end();
P != PEnd; ++P)
CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
return;
}
// Check whether we have a matching method at this level.
if (ObjCMethodDecl *Overridden = Container->getMethod(Method->getSelector(),
Method->isInstanceMethod()))
if (Method != Overridden) {
// We found an override at this level; there is no need to look
// into other protocols or categories.
Methods.push_back(MakeCXCursor(Overridden, TU));
return;
}
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
PEnd = Protocol->protocol_end();
P != PEnd; ++P)
CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
}
if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
PEnd = Interface->protocol_end();
P != PEnd; ++P)
CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
for (ObjCCategoryDecl *Category = Interface->getCategoryList();
Category; Category = Category->getNextClassCategory())
CollectOverriddenMethodsRecurse(TU, Category, Method, Methods,
MovedToSuper);
if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
return CollectOverriddenMethodsRecurse(TU, Super, Method, Methods,
/*MovedToSuper=*/true);
}
}
static inline void CollectOverriddenMethods(CXTranslationUnit TU,
ObjCContainerDecl *Container,
ObjCMethodDecl *Method,
SmallVectorImpl<CXCursor> &Methods) {
CollectOverriddenMethodsRecurse(TU, Container, Method, Methods,
/*MovedToSuper=*/false);
}
static void collectOverriddenMethodsSlow(CXTranslationUnit TU,
ObjCMethodDecl *Method,
SmallVectorImpl<CXCursor> &overridden) {
assert(Method->isOverriding());
if (ObjCProtocolDecl *
ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
CollectOverriddenMethods(TU, ProtD, Method, overridden);
} else if (ObjCImplDecl *
IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) {
ObjCInterfaceDecl *ID = IMD->getClassInterface();
if (!ID)
return;
// Start searching for overridden methods using the method from the
// interface as starting point.
if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
Method->isInstanceMethod()))
Method = IFaceMeth;
CollectOverriddenMethods(TU, ID, Method, overridden);
} else if (ObjCCategoryDecl *
CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) {
ObjCInterfaceDecl *ID = CatD->getClassInterface();
if (!ID)
return;
// Start searching for overridden methods using the method from the
// interface as starting point.
if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
Method->isInstanceMethod()))
Method = IFaceMeth;
CollectOverriddenMethods(TU, ID, Method, overridden);
} else {
CollectOverriddenMethods(TU,
dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()),
Method, overridden);
}
}
static void collectOnCategoriesAfterLocation(SourceLocation Loc,
ObjCInterfaceDecl *Class,
CXTranslationUnit TU,
ObjCMethodDecl *Method,
SmallVectorImpl<CXCursor> &Methods) {
if (!Class)
return;
SourceManager &SM = static_cast<ASTUnit *>(TU->TUData)->getSourceManager();
for (ObjCCategoryDecl *Category = Class->getCategoryList();
Category; Category = Category->getNextClassCategory())
if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
CollectOverriddenMethodsRecurse(TU, Category, Method, Methods, true);
collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), TU,
Method, Methods);
}
/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding()
/// returns false.
/// You'd think that in that case there are no overrides but categories can
/// "introduce" new overridden methods that are missed by Sema because the
/// overrides lookup that it does for methods, inside implementations, will
/// stop at the interface level (if there is a method there) and not look
/// further in super classes.
static void collectOverriddenMethodsFast(CXTranslationUnit TU,
ObjCMethodDecl *Method,
SmallVectorImpl<CXCursor> &Methods) {
assert(!Method->isOverriding());
ObjCContainerDecl *ContD = cast<ObjCContainerDecl>(Method->getDeclContext());
if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD))
return;
ObjCInterfaceDecl *Class = Method->getClassInterface();
if (!Class)
return;
collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(),
TU, Method, Methods);
}
void cxcursor::getOverriddenCursors(CXCursor cursor,
SmallVectorImpl<CXCursor> &overridden) {
assert(clang_isDeclaration(cursor.kind));
Decl *D = getCursorDecl(cursor);
const NamedDecl *D = dyn_cast_or_null<NamedDecl>(getCursorDecl(cursor));
if (!D)
return;
// Handle C++ member functions.
CXTranslationUnit TU = getCursorTU(cursor);
if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
for (CXXMethodDecl::method_iterator
M = CXXMethod->begin_overridden_methods(),
MEnd = CXXMethod->end_overridden_methods();
M != MEnd; ++M)
overridden.push_back(MakeCXCursor(const_cast<CXXMethodDecl*>(*M), TU));
return;
}
SmallVector<const NamedDecl *, 8> OverDecls;
D->getASTContext().getOverriddenMethods(D, OverDecls);
ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
if (!Method)
return;
if (Method->isRedeclaration()) {
Method = cast<ObjCContainerDecl>(Method->getDeclContext())->
getMethod(Method->getSelector(), Method->isInstanceMethod());
}
if (!Method->isOverriding()) {
collectOverriddenMethodsFast(TU, Method, overridden);
} else {
collectOverriddenMethodsSlow(TU, Method, overridden);
assert(!overridden.empty() &&
"ObjCMethodDecl's overriding bit is not as expected");
for (SmallVector<const NamedDecl *, 8>::iterator
I = OverDecls.begin(), E = OverDecls.end(); I != E; ++I) {
overridden.push_back(MakeCXCursor(const_cast<NamedDecl*>(*I), TU));
}
}