diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj
index 6a816466266bcf761db61d73777c93bb865ba43c..d838fc4d6d9f8a7b1099f8f100cc0123a667d779 100644
--- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/CSharpSystemRuntimeAnalyzers.csproj
@@ -74,6 +74,7 @@
+
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/Design/OverrideMethodsOnComparableTypes.Fixer.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/Design/OverrideMethodsOnComparableTypes.Fixer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2c632e3a70fe0b9634a00ed14bbff8baf9cfaf3c
--- /dev/null
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/CSharp/Design/OverrideMethodsOnComparableTypes.Fixer.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using System.Composition;
+using System.Diagnostics;
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace System.Runtime.Analyzers
+{
+ [ExportCodeFixProvider(LanguageNames.CSharp), Shared]
+ public class CSharpOverrideMethodsOnComparableTypesFixer : OverrideMethodsOnComparableTypesFixer
+ {
+ protected override SyntaxNode GenerateOperatorDeclaration(SyntaxNode returnType, string operatorName, IEnumerable parameters, SyntaxNode notImplementedStatement)
+ {
+ Debug.Assert(returnType is TypeSyntax);
+
+ SyntaxToken operatorToken;
+ switch (operatorName)
+ {
+ case WellKnownMemberNames.EqualityOperatorName:
+ operatorToken = SyntaxFactory.Token(SyntaxKind.EqualsEqualsToken);
+ break;
+ case WellKnownMemberNames.InequalityOperatorName:
+ operatorToken = SyntaxFactory.Token(SyntaxKind.ExclamationEqualsToken);
+ break;
+ case WellKnownMemberNames.LessThanOperatorName:
+ operatorToken = SyntaxFactory.Token(SyntaxKind.LessThanToken);
+ break;
+ case WellKnownMemberNames.GreaterThanOperatorName:
+ operatorToken = SyntaxFactory.Token(SyntaxKind.GreaterThanToken);
+ break;
+ default:
+ return null;
+ }
+
+ return SyntaxFactory.OperatorDeclaration(
+ default(SyntaxList),
+ SyntaxFactory.TokenList(new[] { SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword) }),
+ (TypeSyntax)returnType,
+ SyntaxFactory.Token(SyntaxKind.OperatorKeyword),
+ operatorToken,
+ SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters.Cast())),
+ SyntaxFactory.Block((StatementSyntax)notImplementedStatement),
+ default(SyntaxToken));
+ }
+ }
+}
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/DefineAccessorsForAttributeArguments.Fixer.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/DefineAccessorsForAttributeArguments.Fixer.cs
index d5b79ea040dfc850c48214d3eb39462841825c66..6979007997b33b7a33fada503ad96ae82fe68a39 100644
--- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/DefineAccessorsForAttributeArguments.Fixer.cs
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/DefineAccessorsForAttributeArguments.Fixer.cs
@@ -31,20 +31,20 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
var parameter = generator.GetDeclaration(node, DeclarationKind.Parameter);
if (parameter != null)
{
- context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArguments,
+ context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.CreatePropertyAccessorForParameter,
async ct => await AddAccessor(context.Document, parameter, ct).ConfigureAwait(false)),
diagnostic);
}
return;
case DefineAccessorsForAttributeArgumentsAnalyzer.MakePublicCase:
- context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArguments,
+ context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.MakeGetterPublic,
async ct => await MakePublic(context.Document, node, ct).ConfigureAwait(false)),
diagnostic);
return;
case DefineAccessorsForAttributeArgumentsAnalyzer.RemoveSetterCase:
- context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArguments,
+ context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.MakeSetterNonPublic,
async ct => await RemoveSetter(context.Document, node, ct).ConfigureAwait(false)),
diagnostic);
return;
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/OverrideMethodsOnComparableTypes.Fixer.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/OverrideMethodsOnComparableTypes.Fixer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b63209ceb280899f12ebd48fe1f4c0a6bdabdb36
--- /dev/null
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/OverrideMethodsOnComparableTypes.Fixer.cs
@@ -0,0 +1,140 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Editing;
+
+namespace System.Runtime.Analyzers
+{
+ public abstract class OverrideMethodsOnComparableTypesFixer : CodeFixProvider
+ {
+ public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(OverrideMethodsOnComparableTypesAnalyzer.RuleId);
+
+ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ var generator = SyntaxGenerator.GetGenerator(context.Document);
+ var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
+
+ var declaration = root.FindNode(context.Span);
+ declaration = generator.GetDeclaration(declaration);
+ if (declaration == null)
+ {
+ return;
+ }
+
+ var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
+ var typeSymbol = model.GetDeclaredSymbol(declaration) as INamedTypeSymbol;
+ if (typeSymbol == null)
+ {
+ return;
+ }
+
+ // We cannot have multiple overlapping diagnostics of this id.
+ var diagnostic = context.Diagnostics.Single();
+
+ context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.ImplementComparable,
+ async ct => await ImplementComparable(context.Document, declaration, typeSymbol, ct).ConfigureAwait(false)),
+ diagnostic);
+ }
+
+ protected abstract SyntaxNode GenerateOperatorDeclaration(SyntaxNode returnType, string operatorName, IEnumerable parameters, SyntaxNode notImplementedStatement);
+
+ private async Task ImplementComparable(Document document, SyntaxNode declaration, INamedTypeSymbol typeSymbol, CancellationToken cancellationToken)
+ {
+ DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
+ var generator = editor.Generator;
+
+ var throwStatement = generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException")));
+
+ if (!OverrideMethodsOnComparableTypesAnalyzer.DoesOverrideEquals(typeSymbol))
+ {
+ var equalsMethod = generator.MethodDeclaration(WellKnownMemberNames.ObjectEquals,
+ new[] { generator.ParameterDeclaration("obj", generator.TypeExpression(SpecialType.System_Object)) },
+ returnType: generator.TypeExpression(SpecialType.System_Boolean),
+ accessibility: Accessibility.Public,
+ modifiers: DeclarationModifiers.Override,
+ statements: new[] { generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException")))});
+ editor.AddMember(declaration, equalsMethod);
+ }
+
+ if (!OverrideMethodsOnComparableTypesAnalyzer.DoesOverrideGetHashCode(typeSymbol))
+ {
+ var getHashCodeMethod = generator.MethodDeclaration(WellKnownMemberNames.ObjectGetHashCode,
+ returnType: generator.TypeExpression(SpecialType.System_Int32),
+ accessibility: Accessibility.Public,
+ modifiers: DeclarationModifiers.Override,
+ statements: new[] { generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))) });
+ editor.AddMember(declaration, getHashCodeMethod);
+ }
+
+ if (!OverrideMethodsOnComparableTypesAnalyzer.IsOperatorImplemented(typeSymbol, WellKnownMemberNames.EqualityOperatorName))
+ {
+ var equalityOperator = GenerateOperatorDeclaration(generator.TypeExpression(SpecialType.System_Boolean),
+ WellKnownMemberNames.EqualityOperatorName,
+ new[]
+ {
+ generator.ParameterDeclaration("left", generator.TypeExpression(typeSymbol)),
+ generator.ParameterDeclaration("right", generator.TypeExpression(typeSymbol)),
+ },
+ generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))));
+ editor.AddMember(declaration, equalityOperator);
+ }
+
+ if (!OverrideMethodsOnComparableTypesAnalyzer.IsOperatorImplemented(typeSymbol, WellKnownMemberNames.InequalityOperatorName))
+ {
+ var inequalityOperator = GenerateOperatorDeclaration(generator.TypeExpression(SpecialType.System_Boolean),
+ WellKnownMemberNames.InequalityOperatorName,
+ new[]
+ {
+ generator.ParameterDeclaration("left", generator.TypeExpression(typeSymbol)),
+ generator.ParameterDeclaration("right", generator.TypeExpression(typeSymbol)),
+ },
+ generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))));
+ editor.AddMember(declaration, inequalityOperator);
+ }
+
+ if (!OverrideMethodsOnComparableTypesAnalyzer.IsOperatorImplemented(typeSymbol, WellKnownMemberNames.LessThanOperatorName))
+ {
+ var lessThanOperator = GenerateOperatorDeclaration(generator.TypeExpression(SpecialType.System_Boolean),
+ WellKnownMemberNames.LessThanOperatorName,
+ new[]
+ {
+ generator.ParameterDeclaration("left", generator.TypeExpression(typeSymbol)),
+ generator.ParameterDeclaration("right", generator.TypeExpression(typeSymbol)),
+ },
+ generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))));
+ editor.AddMember(declaration, lessThanOperator);
+ }
+
+ if (!OverrideMethodsOnComparableTypesAnalyzer.IsOperatorImplemented(typeSymbol, WellKnownMemberNames.GreaterThanOperatorName))
+ {
+ var greaterThanOperator = GenerateOperatorDeclaration(generator.TypeExpression(SpecialType.System_Boolean),
+ WellKnownMemberNames.GreaterThanOperatorName,
+ new[]
+ {
+ generator.ParameterDeclaration("left", generator.TypeExpression(typeSymbol)),
+ generator.ParameterDeclaration("right", generator.TypeExpression(typeSymbol)),
+ },
+ generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))));
+ editor.AddMember(declaration, greaterThanOperator);
+ }
+
+ return editor.GetChangedDocument();
+ }
+
+ private class MyCodeAction : DocumentChangeAction
+ {
+ public MyCodeAction(string title, Func> createChangedDocument)
+ : base(title, createChangedDocument)
+ {
+ }
+ }
+ }
+}
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/OverrideMethodsOnComparableTypes.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/OverrideMethodsOnComparableTypes.cs
index e3d5c1d3195b2755f507363389a4183d476d38b8..5dd70dd7db522b05102c885b01f43c0ec3be9376 100644
--- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/OverrideMethodsOnComparableTypes.cs
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/Design/OverrideMethodsOnComparableTypes.cs
@@ -2,12 +2,17 @@
using System.Collections.Immutable;
using System.Linq;
-using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
namespace System.Runtime.Analyzers
{
+ ///
+ /// CA1036: A public or protected type implements the System.IComparable interface and
+ /// does not override Object.Equals or does not overload the language-specific operator
+ /// for equality, inequality, less than, or greater than. The rule does not report a
+ /// violation if the type inherits only an implementation of the interface.
+ ///
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class OverrideMethodsOnComparableTypesAnalyzer : DiagnosticAnalyzer
{
@@ -66,25 +71,33 @@ private static void AnalyzeSymbol(INamedTypeSymbol namedTypeSymbol, INamedTypeSy
}
}
- private static bool DoesOverrideEquals(INamedTypeSymbol symbol)
+ internal static bool DoesOverrideEquals(INamedTypeSymbol symbol)
{
// Does the symbol override Object.Equals?
return symbol.GetMembers(WellKnownMemberNames.ObjectEquals).OfType().Where(m => IsEqualsOverride(m)).Any();
}
- // Rule: A public or protected type implements the System.IComparable interface and
- // does not override Object.Equals or does not overload the language-specific operator
- // for equality, inequality, less than, or greater than. The rule does not report a
- // violation if the type inherits only an implementation of the interface.
private static bool IsEqualsOverride(IMethodSymbol method)
{
- // TODO: reimplement using OverriddenMethods, possibly exposing that property if needed
return method.IsOverride &&
method.ReturnType.SpecialType == SpecialType.System_Boolean &&
method.Parameters.Length == 1 &&
method.Parameters[0].Type.SpecialType == SpecialType.System_Object;
}
+ internal static bool DoesOverrideGetHashCode(INamedTypeSymbol symbol)
+ {
+ // Does the symbol override Object.GetHashCode?
+ return symbol.GetMembers(WellKnownMemberNames.ObjectGetHashCode).OfType().Where(m => IsGetHashCodeOverride(m)).Any();
+ }
+
+ private static bool IsGetHashCodeOverride(IMethodSymbol method)
+ {
+ return method.IsOverride &&
+ method.ReturnType.SpecialType == SpecialType.System_Int32 &&
+ method.Parameters.Length == 0;
+ }
+
private static bool IsEqualityOperatorImplemented(INamedTypeSymbol symbol)
{
// Does the symbol overload all of the equality operators? (All are required per http://msdn.microsoft.com/en-us/library/ms182163.aspx example.)
@@ -94,7 +107,7 @@ private static bool IsEqualityOperatorImplemented(INamedTypeSymbol symbol)
IsOperatorImplemented(symbol, WellKnownMemberNames.GreaterThanOperatorName);
}
- private static bool IsOperatorImplemented(INamedTypeSymbol symbol, string op)
+ internal static bool IsOperatorImplemented(INamedTypeSymbol symbol, string op)
{
// TODO: should this filter on the right-hand-side operator type?
return symbol.GetMembers(op).OfType().Where(m => m.MethodKind == MethodKind.UserDefinedOperator).Any();
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj
index a92bdd0f1b2a8682af26bd67bc73daa1e16f235b..b0e1d8e83f4de1a91ec71b77889108b437e7efc2 100644
--- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzers.csproj
@@ -57,6 +57,7 @@
+
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.Designer.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.Designer.cs
index a103026ae59fc4b11b5100df86115a931d592574..420000e1c416794cf5b449a97fa085dab7f0be99 100644
--- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.Designer.cs
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.Designer.cs
@@ -124,6 +124,15 @@ internal class SystemRuntimeAnalyzersResources {
}
}
+ ///
+ /// Looks up a localized string similar to Create a property accessor..
+ ///
+ internal static string CreatePropertyAccessorForParameter {
+ get {
+ return ResourceManager.GetString("CreatePropertyAccessorForParameter", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Custom attributes should have AttributeUsage attribute defined..
///
@@ -169,6 +178,15 @@ internal class SystemRuntimeAnalyzersResources {
}
}
+ ///
+ /// Looks up a localized string similar to Implement Equality and Comparison methods and operators.
+ ///
+ internal static string ImplementComparable {
+ get {
+ return ResourceManager.GetString("ImplementComparable", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Implement IDisposable Interface.
///
@@ -178,6 +196,24 @@ internal class SystemRuntimeAnalyzersResources {
}
}
+ ///
+ /// Looks up a localized string similar to Make the getter of the property public.
+ ///
+ internal static string MakeGetterPublic {
+ get {
+ return ResourceManager.GetString("MakeGetterPublic", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Make the setter of the property non-public.
+ ///
+ internal static string MakeSetterNonPublic {
+ get {
+ return ResourceManager.GetString("MakeSetterNonPublic", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Specify AttributeUsage attribute on '{0}' attribute class..
///
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.resx b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.resx
index 29907925bfb4b6476af741e964f2f6249640c5f3..9649a0feecc9b4e52913985f3f48c9fb40f6d049 100644
--- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.resx
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Core/SystemRuntimeAnalyzersResources.resx
@@ -171,4 +171,16 @@
Types that implement IComparable should redefine Equals and comparison operators to keep the meanings of less than, greater than, and equals consistent throughout the type.
+
+ Create a property accessor.
+
+
+ Implement Equality and Comparison methods and operators
+
+
+ Make the getter of the property public
+
+
+ Make the setter of the property non-public
+
\ No newline at end of file
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/Design/OverrideMethodsOnComparableTypesTests.Fixer.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/Design/OverrideMethodsOnComparableTypesTests.Fixer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f898ca9ea0d0fc13f4d29b148c0ffc24ab5b13d7
--- /dev/null
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/Design/OverrideMethodsOnComparableTypesTests.Fixer.cs
@@ -0,0 +1,248 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Test.Utilities;
+using Xunit;
+
+namespace System.Runtime.Analyzers.UnitTests
+{
+ public partial class OverrideMethodsOnComparableTypesTests
+ {
+ protected override CodeFixProvider GetCSharpCodeFixProvider()
+ {
+ return new CSharpOverrideMethodsOnComparableTypesFixer();
+ }
+
+ protected override CodeFixProvider GetBasicCodeFixProvider()
+ {
+ return new BasicOverrideMethodsOnComparableTypesFixer();
+ }
+
+ [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
+ public void CA1036GenerateAllCSharp()
+ {
+ VerifyCSharpFix(@"
+using System;
+
+public class A : IComparable
+{
+ public int CompareTo(object obj)
+ {
+ return 1;
+ }
+}
+", @"
+using System;
+
+public class A : IComparable
+{
+ public int CompareTo(object obj)
+ {
+ return 1;
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override int GetHashCode()
+ {
+ throw new NotImplementedException();
+ }
+
+ public static bool operator ==(A left, A right)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static bool operator !=(A left, A right)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static bool operator <(A left, A right)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static bool operator >(A left, A right)
+ {
+ throw new NotImplementedException();
+ }
+}
+");
+ }
+
+ [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
+ public void CA1036GenerateSomeCSharp()
+ {
+ VerifyCSharpFix(@"
+using System;
+
+public class A : IComparable
+{
+ public override int GetHashCode()
+ {
+ return 1234;
+ }
+
+ public int CompareTo(object obj)
+ {
+ return 1;
+ }
+
+ public static bool operator !=(A objLeft, A objRight)
+ {
+ return true;
+ }
+}
+", @"
+using System;
+
+public class A : IComparable
+{
+ public override int GetHashCode()
+ {
+ return 1234;
+ }
+
+ public int CompareTo(object obj)
+ {
+ return 1;
+ }
+
+ public static bool operator !=(A objLeft, A objRight)
+ {
+ return true;
+ }
+
+ public override bool Equals(object obj)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static bool operator ==(A left, A right)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static bool operator <(A left, A right)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static bool operator >(A left, A right)
+ {
+ throw new NotImplementedException();
+ }
+}
+");
+ }
+
+ [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
+ public void CA1036GenerateAllVisualBasic()
+ {
+ VerifyBasicFix(@"
+Imports System
+
+Public Class A : Implements IComparable
+
+ Public Function CompareTo(obj As Object) As Integer
+ Return 1
+ End Function
+
+End Class", @"
+Imports System
+
+Public Class A : Implements IComparable
+
+ Public Function CompareTo(obj As Object) As Integer
+ Return 1
+ End Function
+
+ Public Overrides Function Equals(obj As Object) As Boolean
+ Throw New NotImplementedException()
+ End Function
+
+ Public Overrides Function GetHashCode() As Integer
+ Throw New NotImplementedException()
+ End Function
+
+ Public Shared Operator =(left As A, right As A) As Boolean
+ Throw New NotImplementedException()
+ End Operator
+
+ Public Shared Operator <>(left As A, right As A) As Boolean
+ Throw New NotImplementedException()
+ End Operator
+
+ Public Shared Operator <(left As A, right As A) As Boolean
+ Throw New NotImplementedException()
+ End Operator
+
+ Public Shared Operator >(left As A, right As A) As Boolean
+ Throw New NotImplementedException()
+ End Operator
+End Class");
+ }
+
+ [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
+ public void CA1036GenerateSomeVisualBasic()
+ {
+ VerifyBasicFix(@"
+Imports System
+
+Public Class A : Implements IComparable
+
+ Public Overrides Function GetHashCode() As Integer
+ Return 1234
+ End Function
+
+ Public Shared Operator <(objLeft As A, objRight As A) As Boolean
+ Return True
+ End Operator
+
+ Public Function CompareTo(obj As Object) As Integer
+ Return 1
+ End Function
+
+End Class", @"
+Imports System
+
+Public Class A : Implements IComparable
+
+ Public Overrides Function GetHashCode() As Integer
+ Return 1234
+ End Function
+
+ Public Shared Operator <(objLeft As A, objRight As A) As Boolean
+ Return True
+ End Operator
+
+ Public Function CompareTo(obj As Object) As Integer
+ Return 1
+ End Function
+
+ Public Overrides Function Equals(obj As Object) As Boolean
+ Throw New NotImplementedException()
+ End Function
+
+ Public Shared Operator =(left As A, right As A) As Boolean
+ Throw New NotImplementedException()
+ End Operator
+
+ Public Shared Operator <>(left As A, right As A) As Boolean
+ Throw New NotImplementedException()
+ End Operator
+
+ Public Shared Operator >(left As A, right As A) As Boolean
+ Throw New NotImplementedException()
+ End Operator
+End Class");
+ }
+ }
+}
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/Design/OverrideMethodsOnComparableTypesTests.cs b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/Design/OverrideMethodsOnComparableTypesTests.cs
index 5a814c83914d388ba7b8b3128677200db684375d..88d66e04c5a8e8dc4932bed5ab99dd4dc797ede7 100644
--- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/Design/OverrideMethodsOnComparableTypesTests.cs
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/Design/OverrideMethodsOnComparableTypesTests.cs
@@ -9,7 +9,7 @@
namespace System.Runtime.Analyzers.UnitTests
{
[WorkItem(858659, "DevDiv")]
- public partial class OverrideMethodsOnComparableTypesTests : DiagnosticAnalyzerTestBase
+ public partial class OverrideMethodsOnComparableTypesTests : CodeFixTestBase
{
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj
index 8f7ad581799587409d179b40989c1a4f890d88e6..47e1902627734f1cec0a28434c04cfa6fc7a4657 100644
--- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/Test/SystemRuntimeAnalyzersTest.csproj
@@ -101,6 +101,7 @@
+
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj
index 6fde3b40edc8141e97d51c04072bd8cc3f2a9c3a..8c60d7075f206f8d935d410e83954c4d8c486dd6 100644
--- a/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/BasicSystemRuntimeAnalyzers.vbproj
@@ -72,6 +72,7 @@
+
diff --git a/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/Design/OverrideMethodsOnComparableTypes.Fixer.vb b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/Design/OverrideMethodsOnComparableTypes.Fixer.vb
new file mode 100644
index 0000000000000000000000000000000000000000..104cc30bf0042b0dc74496234f786896a9270de1
--- /dev/null
+++ b/src/Diagnostics/FxCop/System.Runtime.Analyzers/VisualBasic/Design/OverrideMethodsOnComparableTypes.Fixer.vb
@@ -0,0 +1,42 @@
+' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+Imports System.Composition
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.CodeFixes
+Imports Microsoft.CodeAnalysis.VisualBasic
+Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
+
+Namespace System.Runtime.Analyzers
+
+ Public Class BasicOverrideMethodsOnComparableTypesFixer
+ Inherits OverrideMethodsOnComparableTypesFixer
+
+ Protected Overrides Function GenerateOperatorDeclaration(returnType As SyntaxNode, operatorName As String, parameters As IEnumerable(Of SyntaxNode), notImplementedStatement As SyntaxNode) As SyntaxNode
+ Debug.Assert(TypeOf returnType Is TypeSyntax)
+
+ Dim operatorToken As SyntaxToken
+ Select Case operatorName
+ Case WellKnownMemberNames.EqualityOperatorName
+ operatorToken = SyntaxFactory.Token(SyntaxKind.EqualsToken)
+ Case WellKnownMemberNames.InequalityOperatorName
+ operatorToken = SyntaxFactory.Token(SyntaxKind.LessThanGreaterThanToken)
+ Case WellKnownMemberNames.LessThanOperatorName
+ operatorToken = SyntaxFactory.Token(SyntaxKind.LessThanToken)
+ Case WellKnownMemberNames.GreaterThanOperatorName
+ operatorToken = SyntaxFactory.Token(SyntaxKind.GreaterThanToken)
+ Case Else
+ Return Nothing
+ End Select
+
+ Dim operatorStatement = SyntaxFactory.OperatorStatement(Nothing,
+ SyntaxFactory.TokenList(New SyntaxToken() {SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.SharedKeyword)}),
+ SyntaxFactory.Token(SyntaxKind.OperatorKeyword),
+ operatorToken,
+ SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters.Cast(Of ParameterSyntax)())),
+ SyntaxFactory.SimpleAsClause(DirectCast(returnType, TypeSyntax)))
+
+ Return SyntaxFactory.OperatorBlock(operatorStatement,
+ SyntaxFactory.SingletonList(DirectCast(notImplementedStatement, StatementSyntax)))
+ End Function
+ End Class
+End Namespace