}
}
-static void collectOnCategoriesAfterLocation(SourceLocation Loc,
- const ObjCInterfaceDecl *Class,
- SourceManager &SM,
- const ObjCMethodDecl *Method,
- SmallVectorImpl<const ObjCMethodDecl *> &Methods) {
- if (!Class)
- return;
-
- for (ObjCInterfaceDecl::known_categories_iterator
- Cat = Class->known_categories_begin(),
- CatEnd = Class->known_categories_end();
- Cat != CatEnd; ++Cat) {
- if (SM.isBeforeInTranslationUnit(Loc, Cat->getLocation()))
- CollectOverriddenMethodsRecurse(*Cat, 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.
-/// Methods in an implementation can overide methods in super class's category
-/// but not in current class's category. But, such methods
-static void collectOverriddenMethodsFast(SourceManager &SM,
- const ObjCMethodDecl *Method,
- SmallVectorImpl<const ObjCMethodDecl *> &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 ObjCMethodDecl::getOverriddenMethods(
SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const {
const ObjCMethodDecl *Method = this;
getMethod(Method->getSelector(), Method->isInstanceMethod());
}
- if (!Method->isOverriding()) {
- collectOverriddenMethodsFast(getASTContext().getSourceManager(),
- Method, Overridden);
- } else {
+ if (Method->isOverriding()) {
collectOverriddenMethodsSlow(Method, Overridden);
assert(!Overridden.empty() &&
"ObjCMethodDecl's overriding bit is not as expected");
i = overrides.begin(), e = overrides.end(); i != e; ++i) {
ObjCMethodDecl *overridden = *i;
- if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
- CurrentClass != overridden->getClassInterface() ||
- overridden->isOverriding())
- hasOverriddenMethodsInBaseOrProtocol = true;
+ if (!hasOverriddenMethodsInBaseOrProtocol) {
+ if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
+ CurrentClass != overridden->getClassInterface() ||
+ overridden->isOverriding()) {
+ hasOverriddenMethodsInBaseOrProtocol = true;
+
+ } else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) {
+ // OverrideSearch will return as "overridden" the same method in the
+ // interface. For hasOverriddenMethodsInBaseOrProtocol, we need to
+ // check whether a category of a base class introduced a method with the
+ // same selector, after the interface method declaration.
+ // To avoid unnecessary lookups in the majority of cases, we use the
+ // extra info bits in GlobalMethodPool to check whether there were any
+ // category methods with this selector.
+ GlobalMethodPool::iterator It =
+ MethodPool.find(ObjCMethod->getSelector());
+ if (It != MethodPool.end()) {
+ ObjCMethodList &List =
+ ObjCMethod->isInstanceMethod()? It->second.first: It->second.second;
+ unsigned CategCount = List.getBits();
+ if (CategCount > 0) {
+ // If the method is in a category we'll do lookup if there were at
+ // least 2 category methods recorded, otherwise only one will do.
+ if (CategCount > 1 ||
+ !isa<ObjCCategoryImplDecl>(overridden->getDeclContext())) {
+ OverrideSearch overrides(*this, overridden);
+ for (OverrideSearch::iterator
+ OI= overrides.begin(), OE= overrides.end(); OI!=OE; ++OI) {
+ ObjCMethodDecl *SuperOverridden = *OI;
+ if (CurrentClass != SuperOverridden->getClassInterface()) {
+ hasOverriddenMethodsInBaseOrProtocol = true;
+ overridden->setOverriding(true);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
// Propagate down the 'related result type' bit from overridden methods.
if (RTC != Sema::RTC_Incompatible && overridden->hasRelatedResultType())