internal static void FindExplicitlyImplementedMemberVerification( this Symbol implementingMember, Symbol implementedMember, BindingDiagnosticBag diagnostics ) { if ((object)implementedMember == null) { return; } if ( implementingMember.ContainsTupleNames() && MemberSignatureComparer.ConsideringTupleNamesCreatesDifference( implementingMember, implementedMember ) ) { // it is ok to explicitly implement with no tuple names, for compatibility with C# 6, but otherwise names should match var memberLocation = implementingMember.Locations[0]; diagnostics.Add( ErrorCode.ERR_ImplBadTupleNames, memberLocation, implementingMember, implementedMember ); } // In constructed types, it is possible that two method signatures could differ by only ref/out // after substitution. We look for this as part of explicit implementation because, if someone // tried to implement the ambiguous interface implicitly, we would separately raise an error about // the implicit implementation methods differing by only ref/out. FindExplicitImplementationCollisions( implementingMember, implementedMember, diagnostics ); }
private static Symbol FindExplicitlyImplementedMember( Symbol implementingMember, TypeSymbol explicitInterfaceType, string interfaceMemberName, ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifierSyntax, DiagnosticBag diagnostics) { if ((object)explicitInterfaceType == null) { return(null); } var memberLocation = implementingMember.Locations[0]; var containingType = implementingMember.ContainingType; var containingTypeKind = containingType.TypeKind; if (containingTypeKind != TypeKind.Class && containingTypeKind != TypeKind.Struct) { diagnostics.Add(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, memberLocation, implementingMember); return(null); } if (!explicitInterfaceType.IsInterfaceType()) { //we'd like to highlight just the type part of the name var explicitInterfaceSyntax = explicitInterfaceSpecifierSyntax.Name; var location = new SourceLocation(explicitInterfaceSyntax); diagnostics.Add(ErrorCode.ERR_ExplicitInterfaceImplementationNotInterface, location, explicitInterfaceType); return(null); } var explicitInterfaceNamedType = (NamedTypeSymbol)explicitInterfaceType; // 13.4.1: "For an explicit interface member implementation to be valid, the class or struct must name an // interface in its base class list that contains a member ..." if (!containingType.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics.Contains(explicitInterfaceNamedType)) { //we'd like to highlight just the type part of the name var explicitInterfaceSyntax = explicitInterfaceSpecifierSyntax.Name; var location = new SourceLocation(explicitInterfaceSyntax); diagnostics.Add(ErrorCode.ERR_ClassDoesntImplementInterface, location, implementingMember, explicitInterfaceNamedType); //do a lookup anyway } var hasParamsParam = implementingMember.HasParamsParameter(); // Setting this flag to true does not imply that an interface member has been successfully implemented. // It just indicates that a corresponding interface member has been found (there may still be errors). var foundMatchingMember = false; Symbol implementedMember = null; foreach (Symbol interfaceMember in explicitInterfaceNamedType.GetMembers(interfaceMemberName)) { // At this point, we know that explicitInterfaceNamedType is an interface, so candidate must be public // and, therefore, accessible. So we don't need to check that. // However, metadata interface members can be static - we ignore them, as does Dev10. if (interfaceMember.Kind != implementingMember.Kind || interfaceMember.IsStatic) { continue; } if (MemberSignatureComparer.ExplicitImplementationComparer.Equals(implementingMember, interfaceMember)) { foundMatchingMember = true; // Cannot implement accessor directly unless // the accessor is from an indexed property. if (interfaceMember.IsAccessor() && !((MethodSymbol)interfaceMember).IsIndexedPropertyAccessor()) { diagnostics.Add(ErrorCode.ERR_ExplicitMethodImplAccessor, memberLocation, implementingMember, interfaceMember); } else { if (interfaceMember.MustCallMethodsDirectly()) { diagnostics.Add(ErrorCode.ERR_BogusExplicitImpl, memberLocation, implementingMember, interfaceMember); } else if (hasParamsParam && !interfaceMember.HasParamsParameter()) { // Note: no error for !hasParamsParam && interfaceMethod.HasParamsParameter() // Still counts as an implementation. diagnostics.Add(ErrorCode.ERR_ExplicitImplParams, memberLocation, implementingMember, interfaceMember); } implementedMember = interfaceMember; break; } } } if (!foundMatchingMember) { // CONSIDER: we may wish to suppress this error in the event that another error // has been reported about the signature. diagnostics.Add(ErrorCode.ERR_InterfaceMemberNotFound, memberLocation, implementingMember); } if (implementingMember.ContainsTupleNames() && MemberSignatureComparer.ConsideringTupleNamesCreatesDifference(implementingMember, implementedMember)) { // it is ok to explicitly implement with no tuple names, for compatibility with C# 6, but otherwise names should match diagnostics.Add(ErrorCode.ERR_ImplBadTupleNames, memberLocation, implementingMember, implementedMember); } // In constructed types, it is possible that two method signatures could differ by only ref/out // after substitution. We look for this as part of explicit implementation because, if someone // tried to implement the ambiguous interface implicitly, we would separately raise an error about // the implicit implementation methods differing by only ref/out. FindExplicitImplementationCollisions(implementingMember, implementedMember, diagnostics); return(implementedMember); }