private static void CheckNonOverrideMember( Symbol hidingMember, bool hidingMemberIsNew, OverriddenOrHiddenMembersResult overriddenOrHiddenMembers, DiagnosticBag diagnostics, out bool suppressAccessors) { suppressAccessors = false; var hidingMemberLocation = hidingMember.Locations[0]; Debug.Assert(overriddenOrHiddenMembers != null); Debug.Assert(!overriddenOrHiddenMembers.OverriddenMembers.Any()); //since hidingMethod.IsOverride is false Debug.Assert(!overriddenOrHiddenMembers.RuntimeOverriddenMembers.Any()); //since hidingMethod.IsOverride is false var hiddenMembers = overriddenOrHiddenMembers.HiddenMembers; Debug.Assert(!hiddenMembers.IsDefault); if (hiddenMembers.Length == 0) { if (hidingMemberIsNew && !hidingMember.IsAccessor()) { diagnostics.Add(ErrorCode.WRN_NewNotRequired, hidingMemberLocation, hidingMember); } } else { var diagnosticAdded = false; //for interfaces, we always report WRN_NewRequired //if we went into the loop, the pseudo-abstract nature of interfaces would throw off the other checks if (!hidingMember.ContainingType.IsInterface) { foreach (var hiddenMember in hiddenMembers) { diagnosticAdded |= AddHidingAbstractDiagnostic(hidingMember, hidingMemberLocation, hiddenMember, diagnostics, ref suppressAccessors); //can actually get both, so don't use else if if (!hidingMemberIsNew && hiddenMember.Kind == hidingMember.Kind && !hidingMember.IsAccessor() && (hiddenMember.IsAbstract || hiddenMember.IsVirtual || hiddenMember.IsOverride)) { diagnostics.Add(ErrorCode.WRN_NewOrOverrideExpected, hidingMemberLocation, hidingMember, hiddenMember); diagnosticAdded = true; } if (diagnosticAdded) { break; } } } if (!hidingMemberIsNew && !diagnosticAdded && !hidingMember.IsAccessor() && !hidingMember.IsOperator()) { diagnostics.Add(ErrorCode.WRN_NewRequired, hidingMemberLocation, hidingMember, hiddenMembers[0]); } } }
private static void CheckOverrideMember(Symbol overridingMember, OverriddenOrHiddenMembersResult overriddenOrHiddenMembers, DiagnosticBag diagnostics, out bool suppressAccessors) { Debug.Assert((object)overridingMember != null); Debug.Assert(overriddenOrHiddenMembers != null); suppressAccessors = false; var overridingMemberIsMethod = overridingMember.Kind == SymbolKind.Method; var overridingMemberIsProperty = overridingMember.Kind == SymbolKind.Property; var overridingMemberIsEvent = overridingMember.Kind == SymbolKind.Event; Debug.Assert(overridingMemberIsMethod ^ overridingMemberIsProperty ^ overridingMemberIsEvent); var overridingMemberLocation = overridingMember.Locations[0]; var overriddenMembers = overriddenOrHiddenMembers.OverriddenMembers; Debug.Assert(!overriddenMembers.IsDefault); if (overriddenMembers.Length == 0) { var hiddenMembers = overriddenOrHiddenMembers.HiddenMembers; Debug.Assert(!hiddenMembers.IsDefault); if (hiddenMembers.Any()) { ErrorCode errorCode = overridingMemberIsMethod ? ErrorCode.ERR_CantOverrideNonFunction : overridingMemberIsProperty ? ErrorCode.ERR_CantOverrideNonProperty : ErrorCode.ERR_CantOverrideNonEvent; diagnostics.Add(errorCode, overridingMemberLocation, overridingMember, hiddenMembers[0]); } else { Symbol associatedPropertyOrEvent = null; if (overridingMemberIsMethod) { associatedPropertyOrEvent = ((MethodSymbol)overridingMember).AssociatedSymbol; } if ((object)associatedPropertyOrEvent == null) { diagnostics.Add(ErrorCode.ERR_OverrideNotExpected, overridingMemberLocation, overridingMember); } else if (associatedPropertyOrEvent.Kind == SymbolKind.Property) //no specific errors for event accessors { PropertySymbol associatedProperty = (PropertySymbol)associatedPropertyOrEvent; PropertySymbol overriddenProperty = associatedProperty.OverriddenProperty; if ((object)overriddenProperty == null) { //skip remaining checks } else if (associatedProperty.GetMethod == overridingMember && (object)overriddenProperty.GetMethod == null) { diagnostics.Add(ErrorCode.ERR_NoGetToOverride, overridingMemberLocation, overridingMember, overriddenProperty); } else if (associatedProperty.SetMethod == overridingMember && (object)overriddenProperty.SetMethod == null) { diagnostics.Add(ErrorCode.ERR_NoSetToOverride, overridingMemberLocation, overridingMember, overriddenProperty); } else { diagnostics.Add(ErrorCode.ERR_OverrideNotExpected, overridingMemberLocation, overridingMember); } } } } else { NamedTypeSymbol overridingType = overridingMember.ContainingType; if (overriddenMembers.Length > 1) { diagnostics.Add(ErrorCode.ERR_AmbigOverride, overridingMemberLocation, overriddenMembers[0].OriginalDefinition, overriddenMembers[1].OriginalDefinition, overridingType); suppressAccessors = true; } else { var overriddenMember = overriddenMembers[0]; //otherwise, it would have been excluded during lookup HashSet<DiagnosticInfo> useSiteDiagnosticsNotUsed = null; Debug.Assert(AccessCheck.IsSymbolAccessible(overriddenMember, overridingType, ref useSiteDiagnosticsNotUsed)); Debug.Assert(overriddenMember.Kind == overridingMember.Kind); if (overriddenMember.MustCallMethodsDirectly()) { diagnostics.Add(ErrorCode.ERR_CantOverrideBogusMethod, overridingMemberLocation, overridingMember, overriddenMember); suppressAccessors = true; } else if (!overriddenMember.IsVirtual && !overriddenMember.IsAbstract && !overriddenMember.IsOverride && !(overridingMemberIsMethod && ((MethodSymbol)overriddenMember).MethodKind == MethodKind.Destructor)) //destructors are metadata virtual { // CONSIDER: To match Dev10, skip the error for properties, and don't suppressAccessors diagnostics.Add(ErrorCode.ERR_CantOverrideNonVirtual, overridingMemberLocation, overridingMember, overriddenMember); suppressAccessors = true; } else if (overriddenMember.IsSealed) { // CONSIDER: To match Dev10, skip the error for properties, and don't suppressAccessors diagnostics.Add(ErrorCode.ERR_CantOverrideSealed, overridingMemberLocation, overridingMember, overriddenMember); suppressAccessors = true; } else if (!overridingMember.IsPartialMethod() && !OverrideHasCorrectAccessibility(overriddenMember, overridingMember)) { var accessibility = SyntaxFacts.GetText(overriddenMember.DeclaredAccessibility); diagnostics.Add(ErrorCode.ERR_CantChangeAccessOnOverride, overridingMemberLocation, overridingMember, accessibility, overriddenMember); suppressAccessors = true; } else { // As in dev11, we don't compare obsoleteness to the immediately-overridden member, // but to the least-overridden member. var leastOverriddenMember = overriddenMember.GetLeastOverriddenMember(overriddenMember.ContainingType); overridingMember.ForceCompleteObsoleteAttribute(); leastOverriddenMember.ForceCompleteObsoleteAttribute(); Debug.Assert(overridingMember.ObsoleteState != ThreeState.Unknown); Debug.Assert(leastOverriddenMember.ObsoleteState != ThreeState.Unknown); bool overridingMemberIsObsolete = overridingMember.ObsoleteState == ThreeState.True; bool leastOverriddenMemberIsObsolete = leastOverriddenMember.ObsoleteState == ThreeState.True; if (overridingMemberIsObsolete != leastOverriddenMemberIsObsolete) { ErrorCode code = overridingMemberIsObsolete ? ErrorCode.WRN_ObsoleteOverridingNonObsolete : ErrorCode.WRN_NonObsoleteOverridingObsolete; diagnostics.Add(code, overridingMemberLocation, overridingMember, leastOverriddenMember); } else if (overridingMemberIsProperty) { PropertySymbol overridingProperty = (PropertySymbol)overridingMember; PropertySymbol overriddenProperty = (PropertySymbol)overriddenMember; TypeSymbol overridingMemberType = overridingProperty.Type; TypeSymbol overriddenMemberType = overriddenProperty.Type; // Ignore custom modifiers because this diagnostic is based on the C# semantics. if (!overridingMemberType.Equals(overriddenMemberType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true)) { diagnostics.Add(ErrorCode.ERR_CantChangeTypeOnOverride, overridingMemberLocation, overridingMember, overriddenMember, overriddenMemberType); suppressAccessors = true; //we get really unhelpful errors from the accessor if the type is mismatched } // If the overriding property is sealed, then the overridden accessors cannot be inaccessible, since we // have to override them to make them sealed in metadata. // CONSIDER: It might be nice if this had its own error code(s) since it's an implementation restriction, // rather than a language restriction as above. if (overridingProperty.IsSealed) { MethodSymbol ownOrInheritedGetMethod = overridingProperty.GetOwnOrInheritedGetMethod(); HashSet<DiagnosticInfo> useSiteDiagnostics = null; if (overridingProperty.GetMethod != ownOrInheritedGetMethod && !AccessCheck.IsSymbolAccessible(ownOrInheritedGetMethod, overridingType, ref useSiteDiagnostics)) { diagnostics.Add(ErrorCode.ERR_NoGetToOverride, overridingMemberLocation, overridingProperty, overriddenProperty); } MethodSymbol ownOrInheritedSetMethod = overridingProperty.GetOwnOrInheritedSetMethod(); if (overridingProperty.SetMethod != ownOrInheritedSetMethod && !AccessCheck.IsSymbolAccessible(ownOrInheritedSetMethod, overridingType, ref useSiteDiagnostics)) { diagnostics.Add(ErrorCode.ERR_NoSetToOverride, overridingMemberLocation, overridingProperty, overriddenProperty); } diagnostics.Add(overridingMemberLocation, useSiteDiagnostics); } } else if (overridingMemberIsEvent) { EventSymbol overridingEvent = (EventSymbol)overridingMember; EventSymbol overriddenEvent = (EventSymbol)overriddenMember; TypeSymbol overridingMemberType = overridingEvent.Type; TypeSymbol overriddenMemberType = overriddenEvent.Type; // Ignore custom modifiers because this diagnostic is based on the C# semantics. if (!overridingMemberType.Equals(overriddenMemberType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true)) { diagnostics.Add(ErrorCode.ERR_CantChangeTypeOnOverride, overridingMemberLocation, overridingMember, overriddenMember, overriddenMemberType); suppressAccessors = true; //we get really unhelpful errors from the accessor if the type is mismatched } } else { Debug.Assert(overridingMemberIsMethod); var overridingMethod = (MethodSymbol)overridingMember; var overriddenMethod = (MethodSymbol)overriddenMember; // Ignore custom modifiers, because this diagnostic is based on the C# semantics. if (!MemberSignatureComparer.HaveSameReturnTypes(overridingMethod, overriddenMethod, considerCustomModifiers: false)) { // Suppose we have a virtual base class method M<T>() that returns C<T>, and the overriding // method M<V> returns void. The error should be "return type must be C<V>", not // "return type must be C<T>". TypeSymbol returnType = overriddenMethod.IsGenericMethod ? overriddenMethod.Construct(overridingMethod.TypeParameters.Cast<TypeParameterSymbol, TypeSymbol>()).ReturnType : overriddenMethod.ReturnType; // error CS0508: return type must be 'C<V>' to match overridden member 'M<T>()' diagnostics.Add(ErrorCode.ERR_CantChangeReturnTypeOnOverride, overridingMemberLocation, overridingMember, overriddenMember, returnType); } else if (overriddenMethod.IsRuntimeFinalizer()) { diagnostics.Add(ErrorCode.ERR_OverrideFinalizeDeprecated, overridingMemberLocation); } } // NOTE: this error may be redundant (if an error has already been reported // for the return type or parameter type in question), but the scenario is // too rare to justify complicated checks. DiagnosticInfo useSiteDiagnostic = overriddenMember.GetUseSiteDiagnostic(); if (useSiteDiagnostic != null) { suppressAccessors = ReportUseSiteDiagnostic(useSiteDiagnostic, diagnostics, overridingMember.Locations[0]); } } } } // From: SymbolPreparer.cpp // DevDiv Bugs 115384: Both out and ref parameters are implemented as references. In addition, out parameters are // decorated with OutAttribute. In CLR when a signature is looked up in virtual dispatch, CLR does not distinguish // between these to parameter types. The choice is the last method in the vtable. Therefore we check and warn if // there would potentially be a mismatch in CLRs and C#s choice of the overridden method. Unfortunately we have no // way of communicating to CLR which method is the overridden one. We only run into this problem when the // parameters are generic. var runtimeOverriddenMembers = overriddenOrHiddenMembers.RuntimeOverriddenMembers; Debug.Assert(!runtimeOverriddenMembers.IsDefault); if (runtimeOverriddenMembers.Length > 1 && overridingMember.Kind == SymbolKind.Method) // The runtime doesn't define overriding for properties or events. { // CONSIDER: Dev10 doesn't seem to report this warning for indexers. var ambiguousMethod = runtimeOverriddenMembers[0]; diagnostics.Add(ErrorCode.WRN_MultipleRuntimeOverrideMatches, ambiguousMethod.Locations[0], ambiguousMethod, overridingMember); suppressAccessors = true; } }