diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -4438,6 +4438,11 @@ ResultTypeCompatibilityKind RTC) { if (!ObjCMethod) return; + auto IsMethodInCurrentClass = [CurrentClass](const ObjCMethodDecl *M) { + // Checking canonical decl works across modules. + return M->getClassInterface()->getCanonicalDecl() == + CurrentClass->getCanonicalDecl(); + }; // Search for overridden methods and merge information down from them. OverrideSearch overrides(*this, ObjCMethod); // Keep track if the method overrides any method in the class's base classes, @@ -4449,8 +4454,7 @@ for (ObjCMethodDecl *overridden : overrides) { if (!hasOverriddenMethodsInBaseOrProtocol) { if (isa(overridden->getDeclContext()) || - CurrentClass != overridden->getClassInterface() || - overridden->isOverriding()) { + !IsMethodInCurrentClass(overridden) || overridden->isOverriding()) { CheckObjCMethodDirectOverrides(ObjCMethod, overridden); hasOverriddenMethodsInBaseOrProtocol = true; } else if (isa(ObjCMethod->getDeclContext())) { @@ -4475,7 +4479,7 @@ OverrideSearch overrides(*this, overridden); for (ObjCMethodDecl *SuperOverridden : overrides) { if (isa(SuperOverridden->getDeclContext()) || - CurrentClass != SuperOverridden->getClassInterface()) { + !IsMethodInCurrentClass(SuperOverridden)) { CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden); hasOverriddenMethodsInBaseOrProtocol = true; overridden->setOverriding(true); diff --git a/clang/test/Modules/override.m b/clang/test/Modules/override.m new file mode 100644 --- /dev/null +++ b/clang/test/Modules/override.m @@ -0,0 +1,69 @@ +// UNSUPPORTED: -aix +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: %clang_cc1 -fsyntax-only -I%t/include %t/test.m \ +// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache -fmodule-name=CheckOverride + +// Test that if we have the same method in a different module, it's not an +// override as it is the same method and it has the same DeclContext but a +// different object in the memory. + + +//--- include/CheckOverride.h +@interface NSObject +@end + +@interface CheckOverrideInterfaceOnly: NSObject +- (void)potentialOverrideInterfaceOnly; +@end + +@interface CheckOverrideCategoryOnly: NSObject +@end +@interface CheckOverrideCategoryOnly(CategoryOnly) +- (void)potentialOverrideCategoryOnly; +@end + +@interface CheckOverrideImplementationOfInterface: NSObject +- (void)potentialOverrideImplementationOfInterface; +@end + +@interface CheckOverrideImplementationOfCategory: NSObject +@end +@interface CheckOverrideImplementationOfCategory(CategoryImpl) +- (void)potentialOverrideImplementationOfCategory; +@end + +//--- include/Redirect.h +// Ensure CheckOverride is imported as the module despite all `-fmodule-name` flags. +#import + +//--- include/module.modulemap +module CheckOverride { + header "CheckOverride.h" +} +module Redirect { + header "Redirect.h" + export * +} + +//--- test.m +#import +#import + +@implementation CheckOverrideImplementationOfInterface +- (void)potentialOverrideImplementationOfInterface {} +@end + +@implementation CheckOverrideImplementationOfCategory +- (void)potentialOverrideImplementationOfCategory {} +@end + +void triggerOverrideCheck(CheckOverrideInterfaceOnly *intfOnly, + CheckOverrideCategoryOnly *catOnly, + CheckOverrideImplementationOfInterface *intfImpl, + CheckOverrideImplementationOfCategory *catImpl) { + [intfOnly potentialOverrideInterfaceOnly]; + [catOnly potentialOverrideCategoryOnly]; + [intfImpl potentialOverrideImplementationOfInterface]; + [catImpl potentialOverrideImplementationOfCategory]; +}