[clang] 2662009 - [ODRHash] Hash `ObjCMethodDecl` and diagnose discovered mismatches.
Volodymyr Sapsai via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 17 18:54:31 PDT 2022
Author: Volodymyr Sapsai
Date: 2022-10-17T18:48:24-07:00
New Revision: 2662009c87f470ec5bc13c237cd62c57b28e4032
URL: https://github.com/llvm/llvm-project/commit/2662009c87f470ec5bc13c237cd62c57b28e4032
DIFF: https://github.com/llvm/llvm-project/commit/2662009c87f470ec5bc13c237cd62c57b28e4032.diff
LOG: [ODRHash] Hash `ObjCMethodDecl` and diagnose discovered mismatches.
Differential Revision: https://reviews.llvm.org/D130325
Added:
Modified:
clang/include/clang/AST/ODRDiagsEmitter.h
clang/include/clang/Basic/DiagnosticASTKinds.td
clang/lib/AST/ODRDiagsEmitter.cpp
clang/lib/AST/ODRHash.cpp
clang/test/Modules/compare-objc-protocol.m
Removed:
################################################################################
diff --git a/clang/include/clang/AST/ODRDiagsEmitter.h b/clang/include/clang/AST/ODRDiagsEmitter.h
index d79b3e1c0649..cbabaa7e69b4 100644
--- a/clang/include/clang/AST/ODRDiagsEmitter.h
+++ b/clang/include/clang/AST/ODRDiagsEmitter.h
@@ -62,8 +62,10 @@ class ODRDiagsEmitter {
private:
using DeclHashes = llvm::SmallVector<std::pair<const Decl *, unsigned>, 4>;
- // Used with err_module_odr_violation_mismatch_decl and
- // note_module_odr_violation_mismatch_decl
+ // Used with err_module_odr_violation_mismatch_decl,
+ // note_module_odr_violation_mismatch_decl,
+ // err_module_odr_violation_mismatch_decl_unknown,
+ // and note_module_odr_violation_mismatch_decl_unknown
// This list should be the same Decl's as in ODRHash::isSubDeclToBeProcessed
enum ODRMismatchDecl {
EndOfClass,
@@ -78,6 +80,7 @@ class ODRDiagsEmitter {
Var,
Friend,
FunctionTemplate,
+ ObjCMethod,
Other
};
@@ -137,6 +140,15 @@ class ODRDiagsEmitter {
const ObjCContainerDecl *SecondContainer,
StringRef SecondModule) const;
+ /// Check if Objective-C methods are the same and diagnose if
diff erent.
+ ///
+ /// Returns true if found a mismatch and diagnosed it.
+ bool diagnoseSubMismatchObjCMethod(const NamedDecl *FirstObjCContainer,
+ StringRef FirstModule,
+ StringRef SecondModule,
+ const ObjCMethodDecl *FirstMethod,
+ const ObjCMethodDecl *SecondMethod) const;
+
private:
DiagnosticsEngine &Diags;
const ASTContext &Context;
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 2517f52a7cf7..c4f520442549 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -621,11 +621,11 @@ def err_module_odr_violation_mismatch_decl : Error<
"%select{definition in module '%2'|defined here}1 found "
"%select{end of class|public access specifier|private access specifier|"
"protected access specifier|static assert|field|method|type alias|typedef|"
- "data member|friend declaration|function template}3">;
+ "data member|friend declaration|function template|method}3">;
def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
"%select{end of class|public access specifier|private access specifier|"
"protected access specifier|static assert|field|method|type alias|typedef|"
- "data member|friend declaration|function template}1">;
+ "data member|friend declaration|function template|method}1">;
def err_module_odr_violation_record : Error<
"%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
@@ -649,12 +649,6 @@ def err_module_odr_violation_record : Error<
"is %select{not const|const}6|"
"%select{method %5|constructor|destructor}4 "
"is %select{not inline|inline}6|"
- "%select{method %5|constructor|destructor}4 "
- "that has %6 parameter%s6|"
- "%select{method %5|constructor|destructor}4 "
- "with %ordinal6 parameter of type %7%select{| decayed from %9}8|"
- "%select{method %5|constructor|destructor}4 "
- "with %ordinal6 parameter named %7|"
"%select{method %5|constructor|destructor}4 "
"with %ordinal6 parameter with%select{out|}7 a default argument|"
"%select{method %5|constructor|destructor}4 "
@@ -706,12 +700,6 @@ def note_module_odr_violation_record : Note<"but in '%0' found "
"is %select{not const|const}4|"
"%select{method %3|constructor|destructor}2 "
"is %select{not inline|inline}4|"
- "%select{method %3|constructor|destructor}2 "
- "that has %4 parameter%s4|"
- "%select{method %3|constructor|destructor}2 "
- "with %ordinal4 parameter of type %5%select{| decayed from %7}6|"
- "%select{method %3|constructor|destructor}2 "
- "with %ordinal4 parameter named %5|"
"%select{method %3|constructor|destructor}2 "
"with %ordinal4 parameter with%select{out|}5 a default argument|"
"%select{method %3|constructor|destructor}2 "
@@ -861,17 +849,59 @@ def note_module_odr_violation_referenced_protocols : Note <"but in '%0' found "
"%ordinal2 referenced protocol with
diff erent name %3"
"}1">;
+def err_module_odr_violation_objc_method : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "method %4 with return type %5|"
+ "%select{class|instance}5 method %4|"
+ "%select{no|'required'|'optional'}4 method control|"
+ "method %4 with %select{no designated initializer|designated initializer}5|"
+ "%select{regular|direct}5 method %4|"
+ "method %4"
+ "}3">;
+def note_module_odr_violation_objc_method : Note<"but in '%0' found "
+ "%select{"
+ "method %2 with
diff erent return type %3|"
+ "method %2 as %select{class|instance}3 method|"
+ "%select{no|'required'|'optional'}2 method control|"
+ "method %2 with %select{no designated initializer|designated initializer}3|"
+ "%select{regular|direct}3 method %2|"
+ "
diff erent method %2"
+ "}1">;
+
+def err_module_odr_violation_method_params : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "%select{method %5|constructor|destructor}4 "
+ "that has %6 parameter%s6|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter of type %7%select{| decayed from %9}8|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter named %7"
+ "}3">;
+def note_module_odr_violation_method_params : Note<"but in '%0' found "
+ "%select{"
+ "%select{method %3|constructor|destructor}2 "
+ "that has %4 parameter%s4|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter of type %5%select{| decayed from %7}6|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter named %5"
+ "}1">;
+
def err_module_odr_violation_mismatch_decl_unknown : Error<
"%q0 %select{with definition in module '%2'|defined here}1 has
diff erent "
"definitions in
diff erent modules; first
diff erence is this "
"%select{||||static assert|field|method|type alias|typedef|data member|"
- "friend declaration|function template|"
+ "friend declaration|function template|method|"
"unexpected decl}3">;
def note_module_odr_violation_mismatch_decl_unknown : Note<
"but in '%0' found "
"%select{||||
diff erent static assert|
diff erent field|
diff erent method|"
"
diff erent type alias|
diff erent typedef|
diff erent data member|"
- "
diff erent friend declaration|
diff erent function template|"
+ "
diff erent friend declaration|
diff erent function template|
diff erent method|"
"another unexpected decl}1">;
diff --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp
index 1fda502e323b..429bb16a17c5 100644
--- a/clang/lib/AST/ODRDiagsEmitter.cpp
+++ b/clang/lib/AST/ODRDiagsEmitter.cpp
@@ -49,6 +49,97 @@ std::string ODRDiagsEmitter::getOwningModuleNameForDiagnostic(const Decl *D) {
return {};
}
+template <typename MethodT>
+static bool diagnoseSubMismatchMethodParameters(DiagnosticsEngine &Diags,
+ const NamedDecl *FirstContainer,
+ StringRef FirstModule,
+ StringRef SecondModule,
+ const MethodT *FirstMethod,
+ const MethodT *SecondMethod) {
+ enum DiagMethodType {
+ DiagMethod,
+ DiagConstructor,
+ DiagDestructor,
+ };
+ auto GetDiagMethodType = [](const NamedDecl *D) {
+ if (isa<CXXConstructorDecl>(D))
+ return DiagConstructor;
+ if (isa<CXXDestructorDecl>(D))
+ return DiagDestructor;
+ return DiagMethod;
+ };
+
+ enum ODRMethodParametersDifference {
+ NumberParameters,
+ ParameterType,
+ ParameterName,
+ };
+ auto DiagError = [&Diags, &GetDiagMethodType, FirstContainer, FirstModule,
+ FirstMethod](ODRMethodParametersDifference DiffType) {
+ DeclarationName FirstName = FirstMethod->getDeclName();
+ DiagMethodType FirstMethodType = GetDiagMethodType(FirstMethod);
+ return Diags.Report(FirstMethod->getLocation(),
+ diag::err_module_odr_violation_method_params)
+ << FirstContainer << FirstModule.empty() << FirstModule
+ << FirstMethod->getSourceRange() << DiffType << FirstMethodType
+ << FirstName;
+ };
+ auto DiagNote = [&Diags, &GetDiagMethodType, SecondModule,
+ SecondMethod](ODRMethodParametersDifference DiffType) {
+ DeclarationName SecondName = SecondMethod->getDeclName();
+ DiagMethodType SecondMethodType = GetDiagMethodType(SecondMethod);
+ return Diags.Report(SecondMethod->getLocation(),
+ diag::note_module_odr_violation_method_params)
+ << SecondModule << SecondMethod->getSourceRange() << DiffType
+ << SecondMethodType << SecondName;
+ };
+
+ const unsigned FirstNumParameters = FirstMethod->param_size();
+ const unsigned SecondNumParameters = SecondMethod->param_size();
+ if (FirstNumParameters != SecondNumParameters) {
+ DiagError(NumberParameters) << FirstNumParameters;
+ DiagNote(NumberParameters) << SecondNumParameters;
+ return true;
+ }
+
+ for (unsigned I = 0; I < FirstNumParameters; ++I) {
+ const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
+ const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
+
+ QualType FirstParamType = FirstParam->getType();
+ QualType SecondParamType = SecondParam->getType();
+ if (FirstParamType != SecondParamType &&
+ computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) {
+ if (const DecayedType *ParamDecayedType =
+ FirstParamType->getAs<DecayedType>()) {
+ DiagError(ParameterType) << (I + 1) << FirstParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagError(ParameterType) << (I + 1) << FirstParamType << false;
+ }
+
+ if (const DecayedType *ParamDecayedType =
+ SecondParamType->getAs<DecayedType>()) {
+ DiagNote(ParameterType) << (I + 1) << SecondParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagNote(ParameterType) << (I + 1) << SecondParamType << false;
+ }
+ return true;
+ }
+
+ DeclarationName FirstParamName = FirstParam->getDeclName();
+ DeclarationName SecondParamName = SecondParam->getDeclName();
+ if (FirstParamName != SecondParamName) {
+ DiagError(ParameterName) << (I + 1) << FirstParamName;
+ DiagNote(ParameterName) << (I + 1) << SecondParamName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool ODRDiagsEmitter::diagnoseSubMismatchField(
const NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule,
const FieldDecl *FirstField, const FieldDecl *SecondField) const {
@@ -325,6 +416,87 @@ bool ODRDiagsEmitter::diagnoseSubMismatchProtocols(
return false;
}
+bool ODRDiagsEmitter::diagnoseSubMismatchObjCMethod(
+ const NamedDecl *FirstObjCContainer, StringRef FirstModule,
+ StringRef SecondModule, const ObjCMethodDecl *FirstMethod,
+ const ObjCMethodDecl *SecondMethod) const {
+ enum ODRMethodDifference {
+ ReturnType,
+ InstanceOrClass,
+ ControlLevel, // optional/required
+ DesignatedInitializer,
+ Directness,
+ Name,
+ };
+
+ auto DiagError = [FirstObjCContainer, FirstModule, FirstMethod,
+ this](ODRMethodDifference DiffType) {
+ return Diag(FirstMethod->getLocation(),
+ diag::err_module_odr_violation_objc_method)
+ << FirstObjCContainer << FirstModule.empty() << FirstModule
+ << FirstMethod->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondModule, SecondMethod,
+ this](ODRMethodDifference DiffType) {
+ return Diag(SecondMethod->getLocation(),
+ diag::note_module_odr_violation_objc_method)
+ << SecondModule << SecondMethod->getSourceRange() << DiffType;
+ };
+
+ if (computeODRHash(FirstMethod->getReturnType()) !=
+ computeODRHash(SecondMethod->getReturnType())) {
+ DiagError(ReturnType) << FirstMethod << FirstMethod->getReturnType();
+ DiagNote(ReturnType) << SecondMethod << SecondMethod->getReturnType();
+ return true;
+ }
+
+ if (FirstMethod->isInstanceMethod() != SecondMethod->isInstanceMethod()) {
+ DiagError(InstanceOrClass)
+ << FirstMethod << FirstMethod->isInstanceMethod();
+ DiagNote(InstanceOrClass)
+ << SecondMethod << SecondMethod->isInstanceMethod();
+ return true;
+ }
+ if (FirstMethod->getImplementationControl() !=
+ SecondMethod->getImplementationControl()) {
+ DiagError(ControlLevel) << FirstMethod->getImplementationControl();
+ DiagNote(ControlLevel) << SecondMethod->getImplementationControl();
+ return true;
+ }
+ if (FirstMethod->isThisDeclarationADesignatedInitializer() !=
+ SecondMethod->isThisDeclarationADesignatedInitializer()) {
+ DiagError(DesignatedInitializer)
+ << FirstMethod
+ << FirstMethod->isThisDeclarationADesignatedInitializer();
+ DiagNote(DesignatedInitializer)
+ << SecondMethod
+ << SecondMethod->isThisDeclarationADesignatedInitializer();
+ return true;
+ }
+ if (FirstMethod->isDirectMethod() != SecondMethod->isDirectMethod()) {
+ DiagError(Directness) << FirstMethod << FirstMethod->isDirectMethod();
+ DiagNote(Directness) << SecondMethod << SecondMethod->isDirectMethod();
+ return true;
+ }
+ if (diagnoseSubMismatchMethodParameters(Diags, FirstObjCContainer,
+ FirstModule, SecondModule,
+ FirstMethod, SecondMethod))
+ return true;
+
+ // Check method name *after* looking at the parameters otherwise we get a
+ // less ideal diagnostics: a ObjCMethodName mismatch given that selectors
+ // for
diff erent parameters are likely to be
diff erent.
+ DeclarationName FirstName = FirstMethod->getDeclName();
+ DeclarationName SecondName = SecondMethod->getDeclName();
+ if (FirstName != SecondName) {
+ DiagError(Name) << FirstName;
+ DiagNote(Name) << SecondName;
+ return true;
+ }
+
+ return false;
+}
+
ODRDiagsEmitter::DiffResult
ODRDiagsEmitter::FindTypeDiffs(DeclHashes &FirstHashes,
DeclHashes &SecondHashes) {
@@ -363,6 +535,8 @@ ODRDiagsEmitter::FindTypeDiffs(DeclHashes &FirstHashes,
return Friend;
case Decl::FunctionTemplate:
return FunctionTemplate;
+ case Decl::ObjCMethod:
+ return ObjCMethod;
}
};
@@ -418,9 +592,11 @@ void ODRDiagsEmitter::diagnoseSubMismatchDifferentDeclKinds(
ODRMismatchDecl DiffType, const Decl *D) {
SourceLocation Loc;
SourceRange Range;
- auto *Tag = dyn_cast<TagDecl>(Container);
- if (DiffType == EndOfClass && Tag) {
- Loc = Tag->getBraceRange().getEnd();
+ if (DiffType == EndOfClass) {
+ if (auto *Tag = dyn_cast<TagDecl>(Container))
+ Loc = Tag->getBraceRange().getEnd();
+ else
+ Loc = Container->getEndLoc();
} else {
Loc = D->getLocation();
Range = D->getSourceRange();
@@ -674,9 +850,6 @@ bool ODRDiagsEmitter::diagnoseMismatch(
MethodVolatile,
MethodConst,
MethodInline,
- MethodNumberParameters,
- MethodParameterType,
- MethodParameterName,
MethodParameterSingleDefaultArgument,
MethodParameterDifferentDefaultArgument,
MethodNoTemplateArguments,
@@ -715,6 +888,7 @@ bool ODRDiagsEmitter::diagnoseMismatch(
case PublicSpecifer:
case PrivateSpecifer:
case ProtectedSpecifer:
+ case ObjCMethod:
llvm_unreachable("Invalid
diff type");
case StaticAssert: {
@@ -882,52 +1056,15 @@ bool ODRDiagsEmitter::diagnoseMismatch(
return true;
}
- const unsigned FirstNumParameters = FirstMethod->param_size();
- const unsigned SecondNumParameters = SecondMethod->param_size();
- if (FirstNumParameters != SecondNumParameters) {
- DiagMethodError(MethodNumberParameters) << FirstNumParameters;
- DiagMethodNote(MethodNumberParameters) << SecondNumParameters;
+ if (diagnoseSubMismatchMethodParameters(Diags, FirstRecord,
+ FirstModule, SecondModule,
+ FirstMethod, SecondMethod))
return true;
- }
- for (unsigned I = 0; I < FirstNumParameters; ++I) {
+ for (unsigned I = 0, N = FirstMethod->param_size(); I < N; ++I) {
const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
- QualType FirstParamType = FirstParam->getType();
- QualType SecondParamType = SecondParam->getType();
- if (FirstParamType != SecondParamType &&
- computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) {
- if (const DecayedType *ParamDecayedType =
- FirstParamType->getAs<DecayedType>()) {
- DiagMethodError(MethodParameterType)
- << (I + 1) << FirstParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagMethodError(MethodParameterType)
- << (I + 1) << FirstParamType << false;
- }
-
- if (const DecayedType *ParamDecayedType =
- SecondParamType->getAs<DecayedType>()) {
- DiagMethodNote(MethodParameterType)
- << (I + 1) << SecondParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagMethodNote(MethodParameterType)
- << (I + 1) << SecondParamType << false;
- }
- return true;
- }
-
- DeclarationName FirstParamName = FirstParam->getDeclName();
- DeclarationName SecondParamName = SecondParam->getDeclName();
- if (FirstParamName != SecondParamName) {
- DiagMethodError(MethodParameterName) << (I + 1) << FirstParamName;
- DiagMethodNote(MethodParameterName) << (I + 1) << SecondParamName;
- return true;
- }
-
const Expr *FirstInit = FirstParam->getInit();
const Expr *SecondInit = SecondParam->getInit();
if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
@@ -1670,6 +1807,13 @@ bool ODRDiagsEmitter::diagnoseMismatch(
case Friend:
case FunctionTemplate:
llvm_unreachable("Invalid
diff type");
+ case ObjCMethod: {
+ if (diagnoseSubMismatchObjCMethod(FirstProtocol, FirstModule, SecondModule,
+ cast<ObjCMethodDecl>(FirstDecl),
+ cast<ObjCMethodDecl>(SecondDecl)))
+ return true;
+ break;
+ }
}
Diag(FirstDecl->getLocation(),
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index b485e93f76c2..d07a0afd1b42 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -72,7 +72,10 @@ void ODRHash::AddDeclarationNameImpl(DeclarationName Name) {
AddBoolean(S.isUnarySelector());
unsigned NumArgs = S.getNumArgs();
ID.AddInteger(NumArgs);
- for (unsigned i = 0; i < NumArgs; ++i) {
+ // Compare all selector slots. For selectors with arguments it means all arg
+ // slots. And if there are no arguments, compare the first-and-only slot.
+ unsigned SlotsToCheck = NumArgs > 0 ? NumArgs : 1;
+ for (unsigned i = 0; i < SlotsToCheck; ++i) {
const IdentifierInfo *II = S.getIdentifierInfoForSlot(i);
AddBoolean(II);
if (II) {
@@ -347,6 +350,64 @@ class ODRDeclVisitor : public ConstDeclVisitor<ODRDeclVisitor> {
Inherited::VisitCXXMethodDecl(D);
}
+ void VisitObjCMethodDecl(const ObjCMethodDecl *Method) {
+ ID.AddInteger(Method->getDeclKind());
+ Hash.AddBoolean(Method->isInstanceMethod()); // false if class method
+ Hash.AddBoolean(Method->isPropertyAccessor());
+ Hash.AddBoolean(Method->isVariadic());
+ Hash.AddBoolean(Method->isSynthesizedAccessorStub());
+ Hash.AddBoolean(Method->isDefined());
+ Hash.AddBoolean(Method->isOverriding());
+ Hash.AddBoolean(Method->isDirectMethod());
+ Hash.AddBoolean(Method->isThisDeclarationADesignatedInitializer());
+ Hash.AddBoolean(Method->hasSkippedBody());
+
+ ID.AddInteger(Method->getImplementationControl());
+ ID.AddInteger(Method->getMethodFamily());
+ ImplicitParamDecl *Cmd = Method->getCmdDecl();
+ Hash.AddBoolean(Cmd);
+ if (Cmd)
+ ID.AddInteger(Cmd->getParameterKind());
+
+ ImplicitParamDecl *Self = Method->getSelfDecl();
+ Hash.AddBoolean(Self);
+ if (Self)
+ ID.AddInteger(Self->getParameterKind());
+
+ AddDecl(Method);
+
+ AddQualType(Method->getReturnType());
+ ID.AddInteger(Method->param_size());
+ for (auto Param : Method->parameters())
+ Hash.AddSubDecl(Param);
+
+ if (Method->hasBody()) {
+ const bool IsDefinition = Method->isThisDeclarationADefinition();
+ Hash.AddBoolean(IsDefinition);
+ if (IsDefinition) {
+ Stmt *Body = Method->getBody();
+ Hash.AddBoolean(Body);
+ if (Body)
+ AddStmt(Body);
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : Method->decls())
+ if (ODRHash::isSubDeclToBeProcessed(SubDecl, Method))
+ Decls.push_back(SubDecl);
+
+ ID.AddInteger(Decls.size());
+ for (auto SubDecl : Decls)
+ Hash.AddSubDecl(SubDecl);
+ }
+ } else {
+ Hash.AddBoolean(false);
+ }
+
+ Inherited::VisitObjCMethodDecl(Method);
+ }
+
void VisitTypedefNameDecl(const TypedefNameDecl *D) {
AddQualType(D->getUnderlyingType());
@@ -460,6 +521,7 @@ bool ODRHash::isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent) {
case Decl::TypeAlias:
case Decl::Typedef:
case Decl::Var:
+ case Decl::ObjCMethod:
return true;
}
}
diff --git a/clang/test/Modules/compare-objc-protocol.m b/clang/test/Modules/compare-objc-protocol.m
index 9acaa26e36d6..706a4b2e8534 100644
--- a/clang/test/Modules/compare-objc-protocol.m
+++ b/clang/test/Modules/compare-objc-protocol.m
@@ -111,3 +111,134 @@ @protocol CompareProtocolOrder<ExtraProtocol, CommonProtocol> @end
// expected-error at first.h:* {{'CompareProtocolOrder' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found 1st referenced protocol with name 'CommonProtocol'}}
// expected-note at second.h:* {{but in 'Second' found 1st referenced protocol with
diff erent name 'ExtraProtocol'}}
#endif
+
+#if defined(FIRST)
+ at protocol CompareMatchingMethods
+- (float)matchingMethod:(int)arg;
+ at end
+
+ at protocol CompareMethodPresence1
+- (void)presenceMethod1;
+ at end
+ at protocol CompareMethodPresence2
+ at end
+
+ at protocol CompareMethodName
+- (void)methodNameA;
+ at end
+
+ at protocol CompareMethodArgCount
+- (void)methodArgCount:(int)arg0 :(int)arg1;
+ at end
+ at protocol CompareMethodArgName
+- (void)methodArgName:(int)argNameA;
+ at end
+ at protocol CompareMethodArgType
+- (void)methodArgType:(int)argType;
+ at end
+
+ at protocol CompareMethodReturnType
+- (int)methodReturnType;
+ at end
+
+ at protocol CompareMethodOrder
+- (void)methodOrderFirst;
+- (void)methodOrderSecond;
+ at end
+
+ at protocol CompareMethodClassInstance
+- (void)methodClassInstance;
+ at end
+
+ at protocol CompareMethodRequirednessExplicit
+ at optional
+- (void)methodRequiredness;
+ at end
+ at protocol CompareMethodRequirednessDefault
+// @required is default
+- (void)methodRequiredness;
+ at end
+#elif defined(SECOND)
+ at protocol CompareMatchingMethods
+- (float)matchingMethod:(int)arg;
+ at end
+
+ at protocol CompareMethodPresence1
+ at end
+ at protocol CompareMethodPresence2
+- (void)presenceMethod2;
+ at end
+
+ at protocol CompareMethodName
+- (void)methodNameB;
+ at end
+
+ at protocol CompareMethodArgCount
+- (void)methodArgCount:(int)arg0;
+ at end
+ at protocol CompareMethodArgName
+- (void)methodArgName:(int)argNameB;
+ at end
+ at protocol CompareMethodArgType
+- (void)methodArgType:(float)argType;
+ at end
+
+ at protocol CompareMethodReturnType
+- (float)methodReturnType;
+ at end
+
+ at protocol CompareMethodOrder
+- (void)methodOrderSecond;
+- (void)methodOrderFirst;
+ at end
+
+ at protocol CompareMethodClassInstance
++ (void)methodClassInstance;
+ at end
+
+ at protocol CompareMethodRequirednessExplicit
+ at required
+- (void)methodRequiredness;
+ at end
+ at protocol CompareMethodRequirednessDefault
+ at required
+- (void)methodRequiredness;
+ at end
+#else
+id<CompareMatchingMethods> compareMatchingMethods; // no error
+id<CompareMethodPresence1> compareMethodPresence1;
+// expected-error at first.h:* {{'CompareMethodPresence1' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found method}}
+// expected-note at second.h:* {{but in 'Second' found end of class}}
+id<CompareMethodPresence2> compareMethodPresence2;
+// expected-error at first.h:* {{'CompareMethodPresence2' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found end of class}}
+// expected-note at second.h:* {{but in 'Second' found method}}
+id<CompareMethodName> compareMethodName;
+// expected-error at first.h:* {{'CompareMethodName' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found method 'methodNameA'}}
+// expected-note at second.h:* {{but in 'Second' found
diff erent method 'methodNameB'}}
+
+id<CompareMethodArgCount> compareMethodArgCount;
+// expected-error at first.h:* {{'CompareMethodArgCount' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found method 'methodArgCount::' that has 2 parameters}}
+// expected-note at second.h:* {{but in 'Second' found method 'methodArgCount:' that has 1 parameter}}
+id<CompareMethodArgName> compareMethodArgName;
+// expected-error at first.h:* {{'CompareMethodArgName' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found method 'methodArgName:' with 1st parameter named 'argNameA'}}
+// expected-note at second.h:* {{but in 'Second' found method 'methodArgName:' with 1st parameter named 'argNameB'}}
+id<CompareMethodArgType> compareMethodArgType;
+// expected-error at first.h:* {{'CompareMethodArgType' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found method 'methodArgType:' with 1st parameter of type 'int'}}
+// expected-note at second.h:* {{but in 'Second' found method 'methodArgType:' with 1st parameter of type 'float'}}
+
+id<CompareMethodReturnType> compareMethodReturnType;
+// expected-error at first.h:* {{'CompareMethodReturnType' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found method 'methodReturnType' with return type 'int'}}
+// expected-note at second.h:* {{but in 'Second' found method 'methodReturnType' with
diff erent return type 'float'}}
+
+id<CompareMethodOrder> compareMethodOrder;
+// expected-error at first.h:* {{'CompareMethodOrder' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found method 'methodOrderFirst'}}
+// expected-note at second.h:* {{but in 'Second' found
diff erent method 'methodOrderSecond'}}
+id<CompareMethodClassInstance> compareMethodClassInstance;
+// expected-error at first.h:* {{'CompareMethodClassInstance' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found instance method 'methodClassInstance'}}
+// expected-note at second.h:* {{but in 'Second' found method 'methodClassInstance' as class method}}
+
+id<CompareMethodRequirednessExplicit> compareMethodRequirednessExplicit;
+// expected-error at first.h:* {{'CompareMethodRequirednessExplicit' has
diff erent definitions in
diff erent modules; first
diff erence is definition in module 'First.Hidden' found 'optional' method control}}
+// expected-note at second.h:* {{but in 'Second' found 'required' method control}}
+id<CompareMethodRequirednessDefault> compareMethodRequirednessDefault; // no error
+#endif
More information about the cfe-commits
mailing list