提交 6f20b92c 编写于 作者: S Srivatsn Narayanan

Moving CA1036 to System.Runtime.Analyzers. Also:

- Make all analyzers cache the wellknown type by implementing compilationstart action.
- Cleaning up the resx file in FxCopAnalyzers.
上级 7b1e026f
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// Runtime Version:4.0.30319.34014 // Runtime Version:4.0.30319.0
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
...@@ -159,15 +159,6 @@ internal class FxCopFixersResources { ...@@ -159,15 +159,6 @@ internal class FxCopFixersResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Implement IDisposable Interface.
/// </summary>
internal static string ImplementIDisposableInterface {
get {
return ResourceManager.GetString("ImplementIDisposableInterface", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Implement Serialization constructor. /// Looks up a localized string similar to Implement Serialization constructor.
/// </summary> /// </summary>
......
...@@ -117,9 +117,6 @@ ...@@ -117,9 +117,6 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="ImplementIDisposableInterface" xml:space="preserve">
<value>Implement IDisposable Interface</value>
</data>
<data name="OverloadOperatorEqualsOnOverridingValueTypeEquals" xml:space="preserve"> <data name="OverloadOperatorEqualsOnOverridingValueTypeEquals" xml:space="preserve">
<value>Overload operator equals on overriding ValueType.Equals</value> <value>Overload operator equals on overriding ValueType.Equals</value>
</data> </data>
......
...@@ -152,7 +152,6 @@ ...@@ -152,7 +152,6 @@
<Compile Include="Shared\WellKnownTypes.cs" /> <Compile Include="Shared\WellKnownTypes.cs" />
<Compile Include="Shared\WordParser.cs" /> <Compile Include="Shared\WordParser.cs" />
<Compile Include="Shared\WordParserOptions.cs" /> <Compile Include="Shared\WordParserOptions.cs" />
<Compile Include="Design\CA1036DiagnosticAnalyzer.cs" />
<Compile Include="SolutionChangeAction.cs" /> <Compile Include="SolutionChangeAction.cs" />
<Compile Include="Usage\CA2200DiagnosticAnalyzer.cs" /> <Compile Include="Usage\CA2200DiagnosticAnalyzer.cs" />
<Compile Include="Usage\CA2213DiagnosticAnalyzer.cs" /> <Compile Include="Usage\CA2213DiagnosticAnalyzer.cs" />
......
...@@ -195,15 +195,6 @@ internal class FxCopRulesResources { ...@@ -195,15 +195,6 @@ internal class FxCopRulesResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Custom attributes should have AttributeUsage attribute defined..
/// </summary>
internal static string CustomAttrShouldHaveAttributeUsage {
get {
return ResourceManager.GetString("CustomAttrShouldHaveAttributeUsage", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Disposable fields should be disposed. /// Looks up a localized string similar to Disposable fields should be disposed.
/// </summary> /// </summary>
...@@ -438,15 +429,6 @@ internal class FxCopRulesResources { ...@@ -438,15 +429,6 @@ internal class FxCopRulesResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Specify AttributeUsage attribute on &apos;{0}&apos; attribute class..
/// </summary>
internal static string MarkAttributesWithAttributeUsage {
get {
return ResourceManager.GetString("MarkAttributesWithAttributeUsage", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Mark Enum with FlagsAttribute. /// Looks up a localized string similar to Mark Enum with FlagsAttribute.
/// </summary> /// </summary>
...@@ -501,24 +483,6 @@ internal class FxCopRulesResources { ...@@ -501,24 +483,6 @@ internal class FxCopRulesResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Overload operator Equals and comparison operators when implementing System.IComparable.
/// </summary>
internal static string OverloadOperatorEqualsOnIComparableInterface {
get {
return ResourceManager.GetString("OverloadOperatorEqualsOnIComparableInterface", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 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..
/// </summary>
internal static string OverloadOperatorEqualsOnIComparableInterfaceDescription {
get {
return ResourceManager.GetString("OverloadOperatorEqualsOnIComparableInterfaceDescription", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Overload operator equals on overriding ValueType.Equals. /// Looks up a localized string similar to Overload operator equals on overriding ValueType.Equals.
/// </summary> /// </summary>
......
...@@ -201,12 +201,6 @@ ...@@ -201,12 +201,6 @@
<data name="ImplementSerializationConstructor" xml:space="preserve"> <data name="ImplementSerializationConstructor" xml:space="preserve">
<value>Implement Serialization constructor</value> <value>Implement Serialization constructor</value>
</data> </data>
<data name="MarkAttributesWithAttributeUsage" xml:space="preserve">
<value>Specify AttributeUsage attribute on '{0}' attribute class.</value>
</data>
<data name="OverloadOperatorEqualsOnIComparableInterface" xml:space="preserve">
<value>Overload operator Equals and comparison operators when implementing System.IComparable</value>
</data>
<data name="IdentifierNamesShouldDifferMoreThanCase" xml:space="preserve"> <data name="IdentifierNamesShouldDifferMoreThanCase" xml:space="preserve">
<value>{0} '{1}' have identical names in a case-insensitive manner.</value> <value>{0} '{1}' have identical names in a case-insensitive manner.</value>
</data> </data>
...@@ -216,9 +210,6 @@ ...@@ -216,9 +210,6 @@
<data name="AvoidUnsealedAttributes" xml:space="preserve"> <data name="AvoidUnsealedAttributes" xml:space="preserve">
<value>Avoid unsealed attributes.</value> <value>Avoid unsealed attributes.</value>
</data> </data>
<data name="CustomAttrShouldHaveAttributeUsage" xml:space="preserve">
<value>Custom attributes should have AttributeUsage attribute defined.</value>
</data>
<data name="DoNotLockOnObjectsWithWeakIdentity" xml:space="preserve"> <data name="DoNotLockOnObjectsWithWeakIdentity" xml:space="preserve">
<value>Do not lock on objects with weak identity.</value> <value>Do not lock on objects with weak identity.</value>
</data> </data>
...@@ -315,9 +306,6 @@ ...@@ -315,9 +306,6 @@
<data name="MarkISerializableTypesWithAttributeDescription" xml:space="preserve"> <data name="MarkISerializableTypesWithAttributeDescription" xml:space="preserve">
<value>The System.Runtime.Serialization.ISerializable interface allows the type to customize its serialization, while the Serializable attribute enables the runtime to recognize the type as being serializable.</value> <value>The System.Runtime.Serialization.ISerializable interface allows the type to customize its serialization, while the Serializable attribute enables the runtime to recognize the type as being serializable.</value>
</data> </data>
<data name="OverloadOperatorEqualsOnIComparableInterfaceDescription" xml:space="preserve">
<value>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.</value>
</data>
<data name="OverloadOperatorEqualsOnOverridingValueTypeEqualsDescription" xml:space="preserve"> <data name="OverloadOperatorEqualsOnOverridingValueTypeEqualsDescription" xml:space="preserve">
<value>Value types that redefine System.ValueType.Equals should redefine the equality operator as well to ensure that these members return the same results. This helps ensure that types that rely on Equals (such as ArrayList and Hashtable) behave in a manner that is expected and consistent with the equality operator.</value> <value>Value types that redefine System.ValueType.Equals should redefine the equality operator as well to ensure that these members return the same results. This helps ensure that types that rely on Equals (such as ArrayList and Hashtable) behave in a manner that is expected and consistent with the equality operator.</value>
</data> </data>
......
...@@ -43,14 +43,23 @@ public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics ...@@ -43,14 +43,23 @@ public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
public override void Initialize(AnalysisContext analysisContext) public override void Initialize(AnalysisContext analysisContext)
{ {
analysisContext.RegisterSymbolAction(context => analysisContext.RegisterCompilationStartAction(compilationContext =>
{ {
AnalyzeSymbol((INamedTypeSymbol)context.Symbol, context.Compilation, context.ReportDiagnostic, context.Options, context.CancellationToken); var attributeType = WellKnownTypes.IDisposable(compilationContext.Compilation);
}, if (attributeType == null)
SymbolKind.NamedType); {
return;
}
compilationContext.RegisterSymbolAction(context =>
{
AnalyzeSymbol((INamedTypeSymbol)context.Symbol, attributeType, context.Compilation, context.ReportDiagnostic);
},
SymbolKind.NamedType);
});
} }
private void AnalyzeSymbol(INamedTypeSymbol symbol, Compilation compilation, Action<Diagnostic> addDiagnostic, AnalyzerOptions options, CancellationToken cancellationToken) private void AnalyzeSymbol(INamedTypeSymbol symbol, INamedTypeSymbol attributeType, Compilation compilation, Action<Diagnostic> addDiagnostic)
{ {
if (symbol != null && symbol.GetBaseTypesAndThis().Contains(WellKnownTypes.Attribute(compilation)) && symbol.DeclaredAccessibility != Accessibility.Private) if (symbol != null && symbol.GetBaseTypesAndThis().Contains(WellKnownTypes.Attribute(compilation)) && symbol.DeclaredAccessibility != Accessibility.Private)
{ {
......
...@@ -28,42 +28,35 @@ public sealed class MarkAttributesWithAttributeUsageAnalyzer : DiagnosticAnalyze ...@@ -28,42 +28,35 @@ public sealed class MarkAttributesWithAttributeUsageAnalyzer : DiagnosticAnalyze
helpLinkUri: "http://msdn.microsoft.com/library/ms182158.aspx", helpLinkUri: "http://msdn.microsoft.com/library/ms182158.aspx",
customTags: WellKnownDiagnosticTags.Telemetry); customTags: WellKnownDiagnosticTags.Telemetry);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
{
get
{
return ImmutableArray.Create(Rule);
}
}
public override void Initialize(AnalysisContext analysisContext) public override void Initialize(AnalysisContext analysisContext)
{ {
analysisContext.RegisterSymbolAction(context => analysisContext.RegisterCompilationStartAction(compilationContext =>
{ {
AnalyzeSymbol((INamedTypeSymbol)context.Symbol, context.Compilation, context.ReportDiagnostic, context.Options, context.CancellationToken); var attributeType = WellKnownTypes.Attribute(compilationContext.Compilation);
}, var attributeUsageAttributeType = WellKnownTypes.AttributeUsageAttribute(compilationContext.Compilation);
SymbolKind.NamedType); if (attributeType == null || attributeUsageAttributeType == null)
{
return;
}
compilationContext.RegisterSymbolAction(context =>
{
AnalyzeSymbol((INamedTypeSymbol)context.Symbol, attributeType, attributeUsageAttributeType, context.ReportDiagnostic);
},
SymbolKind.NamedType);
});
} }
private static void AnalyzeSymbol(INamedTypeSymbol symbol, Compilation compilation, Action<Diagnostic> addDiagnostic, AnalyzerOptions options, CancellationToken cancellationToken) private static void AnalyzeSymbol(INamedTypeSymbol symbol, INamedTypeSymbol attributeType, INamedTypeSymbol attributeUsageAttributeType, Action<Diagnostic> addDiagnostic)
{ {
var attributeUsageAttribute = WellKnownTypes.AttributeUsageAttribute(compilation); if (symbol.IsAbstract || !symbol.GetBaseTypesAndThis().Contains(attributeType))
if (attributeUsageAttribute == null)
{
return;
}
if (symbol.IsAbstract || !symbol.GetBaseTypesAndThis().Contains(WellKnownTypes.Attribute(compilation)))
{
return;
}
if (attributeUsageAttribute == null)
{ {
return; return;
} }
var hasAttributeUsageAttribute = symbol.GetAttributes().Any(attribute => attribute.AttributeClass == attributeUsageAttribute); var hasAttributeUsageAttribute = symbol.GetAttributes().Any(attribute => attribute.AttributeClass == attributeUsageAttributeType);
if (!hasAttributeUsageAttribute) if (!hasAttributeUsageAttribute)
{ {
addDiagnostic(symbol.CreateDiagnostic(Rule, symbol.Name)); addDiagnostic(symbol.CreateDiagnostic(Rule, symbol.Name));
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // 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;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.FxCopAnalyzers.Utilities;
namespace Microsoft.CodeAnalysis.FxCopAnalyzers.Design namespace System.Runtime.Analyzers
{ {
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class CA1036DiagnosticAnalyzer : AbstractNamedTypeAnalyzer public sealed class OverrideMethodsOnComparableTypesAnalyzer : DiagnosticAnalyzer
{ {
internal const string RuleId = "CA1036"; internal const string RuleId = "CA1036";
private static LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(FxCopRulesResources.OverloadOperatorEqualsOnIComparableInterface), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources)); private static LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.OverloadOperatorEqualsOnIComparableInterface), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
private static LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(FxCopRulesResources.OverloadOperatorEqualsOnIComparableInterface), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources)); private static LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.OverloadOperatorEqualsOnIComparableInterface), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
private static LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(FxCopRulesResources.OverloadOperatorEqualsOnIComparableInterfaceDescription), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources)); private static LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.OverloadOperatorEqualsOnIComparableInterfaceDescription), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId,
s_localizableTitle, s_localizableTitle,
s_localizableMessage, s_localizableMessage,
FxCopDiagnosticCategory.Design, DiagnosticCategory.Design,
DiagnosticSeverity.Warning, DiagnosticSeverity.Warning,
isEnabledByDefault: true, isEnabledByDefault: true,
description: s_localizableDescription, description: s_localizableDescription,
helpLinkUri: "http://msdn.microsoft.com/library/ms182163.aspx", helpLinkUri: "http://msdn.microsoft.com/library/ms182163.aspx",
customTags: DiagnosticCustomTags.Microsoft); customTags: WellKnownDiagnosticTags.Telemetry);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext analysisContext)
{ {
get analysisContext.RegisterCompilationStartAction(compilationContext =>
{ {
return ImmutableArray.Create(Rule); var comparableType = WellKnownTypes.IComparable(compilationContext.Compilation);
} var genericComparableType = WellKnownTypes.GenericIComparable(compilationContext.Compilation);
}
protected override void AnalyzeSymbol(INamedTypeSymbol namedTypeSymbol, Compilation compilation, Action<Diagnostic> addDiagnostic, AnalyzerOptions options, CancellationToken cancellationToken) // Even if one of them is available, we should continue analysis.
{ if (comparableType == null && genericComparableType == null)
var comparableType = WellKnownTypes.IComparable(compilation); {
return;
}
if (comparableType == null) compilationContext.RegisterSymbolAction(context =>
{ {
return; AnalyzeSymbol((INamedTypeSymbol)context.Symbol, comparableType, genericComparableType, context.ReportDiagnostic);
} },
SymbolKind.NamedType);
});
}
if (namedTypeSymbol.DeclaredAccessibility == Accessibility.Private) private static void AnalyzeSymbol(INamedTypeSymbol namedTypeSymbol, INamedTypeSymbol comparableType, INamedTypeSymbol genericComparableType, Action<Diagnostic> addDiagnostic)
{
if (namedTypeSymbol.DeclaredAccessibility == Accessibility.Private || namedTypeSymbol.TypeKind == TypeKind.Interface)
{ {
return; return;
} }
if (namedTypeSymbol.Interfaces.Contains(comparableType)) if (namedTypeSymbol.AllInterfaces.Any(t => t.Equals(comparableType) ||
(t.ConstructedFrom?.Equals(genericComparableType) ?? false)))
{ {
if (!(DoesOverrideEquals(namedTypeSymbol) && IsEqualityOperatorImplemented(namedTypeSymbol))) if (!(DoesOverrideEquals(namedTypeSymbol) && IsEqualityOperatorImplemented(namedTypeSymbol)))
{ {
......
...@@ -17,7 +17,6 @@ public sealed class TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer : Dia ...@@ -17,7 +17,6 @@ public sealed class TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer : Dia
{ {
internal const string RuleId = "CA1001"; internal const string RuleId = "CA1001";
internal const string Dispose = "Dispose"; internal const string Dispose = "Dispose";
internal const string IDisposable = "System.IDisposable";
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId, internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId,
new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.TypesThatOwnDisposableFieldsShouldBeDisposable), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources)), new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.TypesThatOwnDisposableFieldsShouldBeDisposable), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources)),
...@@ -28,27 +27,29 @@ public sealed class TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer : Dia ...@@ -28,27 +27,29 @@ public sealed class TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer : Dia
helpLinkUri: "http://msdn.microsoft.com/library/ms182172.aspx", helpLinkUri: "http://msdn.microsoft.com/library/ms182172.aspx",
customTags: WellKnownDiagnosticTags.Telemetry); customTags: WellKnownDiagnosticTags.Telemetry);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
{
get
{
return ImmutableArray.Create(Rule);
}
}
public override void Initialize(AnalysisContext analysisContext) public override void Initialize(AnalysisContext analysisContext)
{ {
analysisContext.RegisterSymbolAction(context => analysisContext.RegisterCompilationStartAction(compilationContext =>
{ {
AnalyzeSymbol((INamedTypeSymbol)context.Symbol, context.Compilation, context.ReportDiagnostic, context.Options, context.CancellationToken); var disposableType = WellKnownTypes.IDisposable(compilationContext.Compilation);
}, if (disposableType == null)
SymbolKind.NamedType); {
return;
}
compilationContext.RegisterSymbolAction(context =>
{
AnalyzeSymbol((INamedTypeSymbol)context.Symbol, disposableType, context.ReportDiagnostic);
},
SymbolKind.NamedType);
});
} }
private static void AnalyzeSymbol(INamedTypeSymbol symbol, Compilation compilation, Action<Diagnostic> addDiagnostic, AnalyzerOptions options, CancellationToken cancellationToken) private static void AnalyzeSymbol(INamedTypeSymbol symbol, INamedTypeSymbol disposableType, Action<Diagnostic> addDiagnostic)
{ {
var disposableType = WellKnownTypes.IDisposable(compilation); if (!symbol.AllInterfaces.Contains(disposableType))
if (disposableType != null && !symbol.AllInterfaces.Contains(disposableType))
{ {
var disposableFields = from member in symbol.GetMembers() var disposableFields = from member in symbol.GetMembers()
where member.Kind == SymbolKind.Field && !member.IsStatic where member.Kind == SymbolKind.Field && !member.IsStatic
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Design\OverrideMethodsOnComparableTypes.cs" />
<Compile Include="Design\DefineAccessorsForAttributeArguments.cs" /> <Compile Include="Design\DefineAccessorsForAttributeArguments.cs" />
<Compile Include="Design\DefineAccessorsForAttributeArguments.Fixer.cs" /> <Compile Include="Design\DefineAccessorsForAttributeArguments.Fixer.cs" />
<Compile Include="Design\MarkAttributesWithAttributeUsage.cs" /> <Compile Include="Design\MarkAttributesWithAttributeUsage.cs" />
......
...@@ -187,6 +187,24 @@ internal class SystemRuntimeAnalyzersResources { ...@@ -187,6 +187,24 @@ internal class SystemRuntimeAnalyzersResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Overload operator Equals and comparison operators when implementing System.IComparable.
/// </summary>
internal static string OverloadOperatorEqualsOnIComparableInterface {
get {
return ResourceManager.GetString("OverloadOperatorEqualsOnIComparableInterface", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 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..
/// </summary>
internal static string OverloadOperatorEqualsOnIComparableInterfaceDescription {
get {
return ResourceManager.GetString("OverloadOperatorEqualsOnIComparableInterfaceDescription", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Type &apos;{0}&apos; owns disposable fields but is not disposable. /// Looks up a localized string similar to Type &apos;{0}&apos; owns disposable fields but is not disposable.
/// </summary> /// </summary>
......
...@@ -165,4 +165,10 @@ ...@@ -165,4 +165,10 @@
<data name="DefineAccessorsForAttributeArgumentsRemoveSetter" xml:space="preserve"> <data name="DefineAccessorsForAttributeArgumentsRemoveSetter" xml:space="preserve">
<value>Remove the property setter from '{0}' or reduce its accessibility because it corresponds to positional argument '{1}'.</value> <value>Remove the property setter from '{0}' or reduce its accessibility because it corresponds to positional argument '{1}'.</value>
</data> </data>
<data name="OverloadOperatorEqualsOnIComparableInterface" xml:space="preserve">
<value>Overload operator Equals and comparison operators when implementing System.IComparable</value>
</data>
<data name="OverloadOperatorEqualsOnIComparableInterfaceDescription" xml:space="preserve">
<value>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.</value>
</data>
</root> </root>
\ No newline at end of file
...@@ -141,6 +141,11 @@ public static INamedTypeSymbol IComparable(Compilation compilation) ...@@ -141,6 +141,11 @@ public static INamedTypeSymbol IComparable(Compilation compilation)
return compilation.GetTypeByMetadataName("System.IComparable"); return compilation.GetTypeByMetadataName("System.IComparable");
} }
public static INamedTypeSymbol GenericIComparable(Compilation compilation)
{
return compilation.GetTypeByMetadataName("System.IComparable`1");
}
public static INamedTypeSymbol ComSourceInterfaceAttribute(Compilation compilation) public static INamedTypeSymbol ComSourceInterfaceAttribute(Compilation compilation)
{ {
return compilation.GetTypeByMetadataName("System.Runtime.InteropServices.ComSourceInterfacesAttribute"); return compilation.GetTypeByMetadataName("System.Runtime.InteropServices.ComSourceInterfacesAttribute");
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // 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 Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.FxCopAnalyzers.Design;
using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.UnitTests;
using Roslyn.Test.Utilities; using Roslyn.Test.Utilities;
using Xunit; using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests namespace System.Runtime.Analyzers.UnitTests
{ {
[WorkItem(858659, "DevDiv")] [WorkItem(858659, "DevDiv")]
public partial class CA1030Tests : DiagnosticAnalyzerTestBase public partial class OverrideMethodsOnComparableTypesTests : DiagnosticAnalyzerTestBase
{ {
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{ {
return new CA1036DiagnosticAnalyzer(); return new OverrideMethodsOnComparableTypesAnalyzer();
} }
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{ {
return new CA1036DiagnosticAnalyzer(); return new OverrideMethodsOnComparableTypesAnalyzer();
} }
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
...@@ -397,6 +397,82 @@ public override bool Equals(object obj) ...@@ -397,6 +397,82 @@ public override bool Equals(object obj)
GetCA1036CSharpResultAt(4, 19)); GetCA1036CSharpResultAt(4, 19));
} }
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CA1036ClassWithGenericIComparableCSharp()
{
VerifyCSharp(@"
using System;
public class A : IComparable<int>
{
public override int GetHashCode()
{
return 1234;
}
public int CompareTo(int obj)
{
return 1;
}
public override bool Equals(object obj)
{
return true;
}
public static bool operator <(A objLeft, A objRight)
{
return true;
}
public static bool operator >(A objLeft, A objRight)
{
return true;
}
}
",
GetCA1036CSharpResultAt(4, 18));
}
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CA1036ClassWithDerivedIComparableCSharp()
{
VerifyCSharp(@"
using System;
interface IDerived : IComparable<int> { }
public class A : IDerived
{
public override int GetHashCode()
{
return 1234;
}
public int CompareTo(int obj)
{
return 1;
}
public override bool Equals(object obj)
{
return true;
}
public static bool operator <(A objLeft, A objRight)
{
return true;
}
public static bool operator >(A objLeft, A objRight)
{
return true;
}
}
",
GetCA1036CSharpResultAt(6, 18));
}
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CA1036ClassNoWarningBasic() public void CA1036ClassNoWarningBasic()
{ {
...@@ -723,6 +799,76 @@ End Class ...@@ -723,6 +799,76 @@ End Class
GetCA1036BasicResultAt(4, 18)); GetCA1036BasicResultAt(4, 18));
} }
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CA1036ClassWithGenericIComparableBasic()
{
VerifyBasic(@"
Imports System
Public Structure A : Implements IComparable(Of Integer)
Public Function Overrides GetHashCode() As Integer
Return 1234
End Function
Public Function CompareTo(obj As Integer) As Integer
Return 1
End Function
Public Overloads Overrides Function Equals(obj As Object) As Boolean
Return True
End Function
Public Shared Operator =(objLeft As A, objRight As A) As Boolean
Return True
End Operator
Public Shared Operator <>(objLeft As A, objRight As A) As Boolean
Return True
End Operator
End Class
",
GetCA1036BasicResultAt(4, 18));
}
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CA1036ClassWithDerivedIComparableBasic()
{
VerifyBasic(@"
Imports System
Public Interface IDerived
Inherits IComparable(Of Integer)
End Interface
Public Structure A : Implements IDerived
Public Function Overrides GetHashCode() As Integer
Return 1234
End Function
Public Function CompareTo(obj As Object) As Integer
Return 1
End Function
Public Overloads Overrides Function Equals(obj As Object) As Boolean
Return True
End Function
Public Shared Operator =(objLeft As A, objRight As A) As Boolean
Return True
End Operator
Public Shared Operator <>(objLeft As A, objRight As A) As Boolean
Return True
End Operator
End Class
",
GetCA1036BasicResultAt(8, 18));
}
internal static string CA1036Name = "CA1036"; internal static string CA1036Name = "CA1036";
internal static string CA1036Message = "Overload operator Equals and comparison operators when implementing System.IComparable"; internal static string CA1036Message = "Overload operator Equals and comparison operators when implementing System.IComparable";
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
namespace System.Runtime.Analyzers.UnitTests namespace System.Runtime.Analyzers.UnitTests
{ {
public partial class CA1001FixerTests : CodeFixTestBase public partial class TypesThatOwnDisposableFieldsShouldBeDisposableFixerTests : CodeFixTestBase
{ {
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{ {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
namespace System.Runtime.Analyzers.UnitTests namespace System.Runtime.Analyzers.UnitTests
{ {
public partial class CA1001Tests : DiagnosticAnalyzerTestBase public partial class TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzerTests : DiagnosticAnalyzerTestBase
{ {
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{ {
......
...@@ -97,6 +97,7 @@ ...@@ -97,6 +97,7 @@
<None Include="packages.config" /> <None Include="packages.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Design\OverrideMethodsOnComparableTypesTests.cs" />
<Compile Include="Design\DefineAccessorsForAttributeArgumentsTests.Fixer.cs" /> <Compile Include="Design\DefineAccessorsForAttributeArgumentsTests.Fixer.cs" />
<Compile Include="Design\DefineAccessorsForAttributeArgumentsTests.cs" /> <Compile Include="Design\DefineAccessorsForAttributeArgumentsTests.cs" />
<Compile Include="Design\MarkAttributesWithAttributeUsageTests.cs" /> <Compile Include="Design\MarkAttributesWithAttributeUsageTests.cs" />
......
...@@ -106,7 +106,6 @@ ...@@ -106,7 +106,6 @@
<Compile Include="Performance\CodeFixes\CA1813FixerTests.cs" /> <Compile Include="Performance\CodeFixes\CA1813FixerTests.cs" />
<Compile Include="Performance\CodeFixes\CA1821FixerTests.cs" /> <Compile Include="Performance\CodeFixes\CA1821FixerTests.cs" />
<Compile Include="Reliability\CA2002Tests.cs" /> <Compile Include="Reliability\CA2002Tests.cs" />
<Compile Include="Design\CA1036Tests.cs" />
<Compile Include="Usage\CA2200Tests.cs" /> <Compile Include="Usage\CA2200Tests.cs" />
<Compile Include="Usage\CA2213Tests.cs" /> <Compile Include="Usage\CA2213Tests.cs" />
<Compile Include="Usage\CA2214Tests.cs" /> <Compile Include="Usage\CA2214Tests.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册