/// <summary> /// Checks if a given method implements IEqualityComparer.Equals or IEquatable.Equals. /// </summary> private static bool IsEqualsInterfaceImplementation(IMethodSymbol method, Compilation compilation) { if (method.Name != WellKnownMemberNames.ObjectEquals) { return(false); } int paramCount = method.Parameters.Length; if (method.ReturnType.SpecialType == SpecialType.System_Boolean && (paramCount == 1 || paramCount == 2)) { // Substitute the type of the first parameter of Equals in the generic interface and then check if that // interface method is implemented by the given method. INamedTypeSymbol iEqualityComparer = WellKnownTypes.GenericIEqualityComparer(compilation); if (method.IsImplementationOfInterfaceMethod(method.Parameters.First().Type, iEqualityComparer, WellKnownMemberNames.ObjectEquals)) { return(true); } // Substitute the type of the first parameter of Equals in the generic interface and then check if that // interface method is implemented by the given method. INamedTypeSymbol iEquatable = WellKnownTypes.GenericIEquatable(compilation); if (method.IsImplementationOfInterfaceMethod(method.Parameters.First().Type, iEquatable, WellKnownMemberNames.ObjectEquals)) { return(true); } } return(false); }
/// <summary> /// Checks if a given method implements IEqualityComparer.GetHashCode or IHashCodeProvider.GetHashCode. /// </summary> /// <param name="method"></param> /// <param name="compilation"></param> /// <returns></returns> private static bool IsGetHashCodeInterfaceImplementation(IMethodSymbol method, Compilation compilation) { if (method.Name != WellKnownMemberNames.ObjectGetHashCode) { return(false); } if (method.ReturnType.SpecialType == SpecialType.System_Int32 && method.Parameters.Length == 1) { // Substitute the type of the first parameter of Equals in the generic interface and then check if that // interface method is implemented by the given method. INamedTypeSymbol iEqualityComparer = WellKnownTypes.GenericIEqualityComparer(compilation); if (method.IsImplementationOfInterfaceMethod(method.Parameters.First().Type, iEqualityComparer, WellKnownMemberNames.ObjectGetHashCode)) { return(true); } INamedTypeSymbol iHashCodeProvider = WellKnownTypes.IHashCodeProvider(compilation); if (method.IsImplementationOfInterfaceMethod(null, iHashCodeProvider, WellKnownMemberNames.ObjectGetHashCode)) { return(true); } } return(false); }
public override void Initialize(AnalysisContext analysisContext) { analysisContext.EnableConcurrentExecution(); analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction(compilationStartAnalysisContext => { INamedTypeSymbol equalityComparerType = WellKnownTypes.GenericIEqualityComparer(compilationStartAnalysisContext.Compilation); IMethodSymbol iEqualityComparerGetHashCodeMethod = equalityComparerType?.GetMembers("GetHashCode").Single() as IMethodSymbol; // Analyze named types and fields. compilationStartAnalysisContext.RegisterSymbolAction(symbolContext => { AnalyzeSymbol(symbolContext.Symbol, symbolContext); }, SymbolKind.NamedType, SymbolKind.Field); // Analyze properties and methods, and their parameters. compilationStartAnalysisContext.RegisterSymbolAction(symbolContext => { var method = symbolContext.Symbol as IMethodSymbol; if (method != null) { if (method.IsEqualsOverride()) { // Ignore, given the method signature and parameter names are auto-generated by the IDE: // public override bool Equals(object obj) return; } if (IsIEqualityComparerGetHashCodeInterfaceImplementation(method, iEqualityComparerGetHashCodeMethod)) { // Ignore, given the method signature and parameter names are auto-generated by the IDE: // public int GetHashCode(SomeType obj) return; } } AnalyzeSymbol(symbolContext.Symbol, symbolContext); ImmutableArray <IParameterSymbol> parameters = symbolContext.Symbol.Kind == SymbolKind.Property ? ((IPropertySymbol)symbolContext.Symbol).Parameters : ((IMethodSymbol)symbolContext.Symbol).Parameters; foreach (IParameterSymbol param in parameters) { AnalyzeSymbol(param, symbolContext); } }, SymbolKind.Property, SymbolKind.Method); }); }