提交 b376181c 编写于 作者: J John Hamby

Merge remote-tracking branch 'upstream/master' into BaseAnalyzerDocComments

......@@ -77,7 +77,6 @@
<Compile Include="Design\CodeFixes\CA1052CSharpCodeFixProvider.cs" />
<Compile Include="Design\CodeFixes\EnumWithFlagsCSharpCodeFixProvider.cs" />
<Compile Include="Design\CSharpCA1003DiagnosticAnalyzer.cs" />
<Compile Include="Design\CSharpCA1019DiagnosticAnalyzer.cs" />
<Compile Include="Design\CSharpCA1024DiagnosticAnalyzer.cs" />
<Compile Include="Design\CSharpEnumWithFlagsDiagnosticAnalyzer.cs" />
<Compile Include="Globalization\CodeFixes\CA1309CSharpCodeFixProvider.cs" />
......
//------------------------------------------------------------------------------
// <auto-generated>
// 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
// the code is regenerated.
......@@ -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>
/// Looks up a localized string similar to Implement Serialization constructor.
/// </summary>
......
......@@ -117,9 +117,6 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ImplementIDisposableInterface" xml:space="preserve">
<value>Implement IDisposable Interface</value>
</data>
<data name="OverloadOperatorEqualsOnOverridingValueTypeEquals" xml:space="preserve">
<value>Overload operator equals on overriding ValueType.Equals</value>
</data>
......
......@@ -107,8 +107,6 @@
<Compile Include="Design\CA1008DiagnosticAnalyzer.cs" />
<Compile Include="Design\CA1012DiagnosticAnalyzer.cs" />
<Compile Include="Design\CA1017DiagnosticAnalyzer.cs" />
<Compile Include="Design\CA1018DiagnosticAnalyzer.cs" />
<Compile Include="Design\CA1019DiagnosticAnalyzer.cs" />
<Compile Include="Design\CA1024DiagnosticAnalyzer.cs" />
<Compile Include="Design\CA1060DiagnosticAnalyzer.cs" />
<Compile Include="Design\CodeFixes\CA1008CodeFixProviderBase.cs" />
......@@ -154,7 +152,6 @@
<Compile Include="Shared\WellKnownTypes.cs" />
<Compile Include="Shared\WordParser.cs" />
<Compile Include="Shared\WordParserOptions.cs" />
<Compile Include="Design\CA1036DiagnosticAnalyzer.cs" />
<Compile Include="SolutionChangeAction.cs" />
<Compile Include="Usage\CA2200DiagnosticAnalyzer.cs" />
<Compile Include="Usage\CA2213DiagnosticAnalyzer.cs" />
......
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.35317
// Runtime Version:4.0.30319.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
......@@ -195,51 +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>
/// Looks up a localized string similar to Define accessors for attribute arguments..
/// </summary>
internal static string DefineAccessorsForAttributeArguments {
get {
return ResourceManager.GetString("DefineAccessorsForAttributeArguments", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Add a public read-only property accessor for positional argument &apos;{0}&apos; of attribute &apos;{1}&apos;..
/// </summary>
internal static string DefineAccessorsForAttributeArgumentsDefault {
get {
return ResourceManager.GetString("DefineAccessorsForAttributeArgumentsDefault", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to If &apos;{0}&apos; is the property accessor for positional argument &apos;{1}&apos;, ensure that property getter is public..
/// </summary>
internal static string DefineAccessorsForAttributeArgumentsIncreaseVisibility {
get {
return ResourceManager.GetString("DefineAccessorsForAttributeArgumentsIncreaseVisibility", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Remove the property setter from &apos;{0}&apos; or reduce its accessibility because it corresponds to positional argument &apos;{1}&apos;..
/// </summary>
internal static string DefineAccessorsForAttributeArgumentsRemoveSetter {
get {
return ResourceManager.GetString("DefineAccessorsForAttributeArgumentsRemoveSetter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Disposable fields should be disposed.
/// </summary>
......@@ -474,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>
/// Looks up a localized string similar to Mark Enum with FlagsAttribute.
/// </summary>
......@@ -537,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>
/// Looks up a localized string similar to Overload operator equals on overriding ValueType.Equals.
/// </summary>
......
......@@ -192,15 +192,6 @@
<data name="ChangeToAPropertyIfAppropriate" xml:space="preserve">
<value>Change '{0}' to a property if appropriate.</value>
</data>
<data name="DefineAccessorsForAttributeArgumentsDefault" xml:space="preserve">
<value>Add a public read-only property accessor for positional argument '{0}' of attribute '{1}'.</value>
</data>
<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>
</data>
<data name="DefineAccessorsForAttributeArgumentsIncreaseVisibility" xml:space="preserve">
<value>If '{0}' is the property accessor for positional argument '{1}', ensure that property getter is public.</value>
</data>
<data name="MarkEnumsWithFlagsMessage" xml:space="preserve">
<value>The constituent members of '{0}' appear to represent flags that can be combined rather than discrete values. If this is correct, mark the enumeration with FlagsAttribute.</value>
</data>
......@@ -210,12 +201,6 @@
<data name="ImplementSerializationConstructor" xml:space="preserve">
<value>Implement Serialization constructor</value>
</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">
<value>{0} '{1}' have identical names in a case-insensitive manner.</value>
</data>
......@@ -225,12 +210,6 @@
<data name="AvoidUnsealedAttributes" xml:space="preserve">
<value>Avoid unsealed attributes.</value>
</data>
<data name="CustomAttrShouldHaveAttributeUsage" xml:space="preserve">
<value>Custom attributes should have AttributeUsage attribute defined.</value>
</data>
<data name="DefineAccessorsForAttributeArguments" xml:space="preserve">
<value>Define accessors for attribute arguments.</value>
</data>
<data name="DoNotLockOnObjectsWithWeakIdentity" xml:space="preserve">
<value>Do not lock on objects with weak identity.</value>
</data>
......@@ -327,9 +306,6 @@
<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>
</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">
<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>
......
......@@ -71,8 +71,10 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="Design\" />
<Compile Include="Design\DefineAccessorsForAttributeArguments.cs" />
<Compile Include="Design\OverrideMethodsOnComparableTypes.Fixer.cs" />
</ItemGroup>
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Imports.targets" />
......
// 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;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.FxCopAnalyzers.Design;
namespace Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers.Design
namespace System.Runtime.Analyzers
{
/// <summary>
/// CA1019: Define accessors for attribute arguments
......@@ -12,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.FxCopAnalyzers.Design
/// In its constructor, an attribute defines arguments that do not have corresponding properties.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class CSharpCA1019DiagnosticAnalyzer : CA1019DiagnosticAnalyzer
public class CSharpDefineAccessorsForAttributeArgumentsAnalyzer : DefineAccessorsForAttributeArgumentsAnalyzer
{
protected override bool IsAssignableTo(ITypeSymbol fromSymbol, ITypeSymbol toSymbol, Compilation compilation)
{
......
// 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.Composition;
using System.Diagnostics;
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<SyntaxNode> 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<AttributeListSyntax>),
SyntaxFactory.TokenList(new[] { SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword) }),
(TypeSyntax)returnType,
SyntaxFactory.Token(SyntaxKind.OperatorKeyword),
operatorToken,
SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters.Cast<ParameterSyntax>())),
SyntaxFactory.Block((StatementSyntax)notImplementedStatement),
default(SyntaxToken));
}
}
}
// 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.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
namespace System.Runtime.Analyzers
{
public abstract class CodeFixProviderBase : CodeFixProvider
{
protected abstract string GetCodeFixDescription(Diagnostic diagnostic);
internal abstract Task<Document> GetUpdatedDocumentAsync(Document document, SemanticModel model, SyntaxNode root, SyntaxNode nodeToFix, Diagnostic diagnostic, CancellationToken cancellationToken);
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var cancellationToken = context.CancellationToken;
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
foreach (var diagnostic in context.Diagnostics)
{
cancellationToken.ThrowIfCancellationRequested();
var nodeToFix = root.FindNode(diagnostic.Location.SourceSpan);
var newDocument = await GetUpdatedDocumentAsync(document, model, root, nodeToFix, diagnostic, cancellationToken).ConfigureAwait(false);
Debug.Assert(newDocument != null);
if (newDocument != document)
{
var codeFixDescription = GetCodeFixDescription(diagnostic);
context.RegisterCodeFix(new MyCodeAction(codeFixDescription, newDocument), diagnostic);
}
}
}
private class MyCodeAction : DocumentChangeAction
{
public MyCodeAction(string title, Document newDocument) :
base(title, c => Task.FromResult(newDocument))
{
}
}
}
}
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.Editing;
namespace System.Runtime.Analyzers
{
[ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic), Shared]
public class DefineAccessorsForAttributeArgumentsFixer : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(DefineAccessorsForAttributeArgumentsAnalyzer.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 node = root.FindNode(context.Span);
// We cannot have multiple overlapping diagnostics of this id.
var diagnostic = context.Diagnostics.Single();
string fixCase;
if (diagnostic.Properties.TryGetValue("case", out fixCase))
{
switch (fixCase)
{
case DefineAccessorsForAttributeArgumentsAnalyzer.AddAccessorCase:
var parameter = generator.GetDeclaration(node, DeclarationKind.Parameter);
if (parameter != null)
{
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.MakeGetterPublic,
async ct => await MakePublic(context.Document, node, ct).ConfigureAwait(false)),
diagnostic);
return;
case DefineAccessorsForAttributeArgumentsAnalyzer.RemoveSetterCase:
context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.MakeSetterNonPublic,
async ct => await RemoveSetter(context.Document, node, ct).ConfigureAwait(false)),
diagnostic);
return;
default:
return;
}
}
}
private async Task<Document> AddAccessor(Document document, SyntaxNode parameter, CancellationToken cancellationToken)
{
SymbolEditor symbolEditor = SymbolEditor.Create(document);
var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var parameterSymbol = model.GetDeclaredSymbol(parameter, cancellationToken) as IParameterSymbol;
if (parameterSymbol == null)
{
return document;
}
// Make the first character uppercase since we are generating a property.
var propName = char.ToUpper(parameterSymbol.Name[0]).ToString() + parameterSymbol.Name.Substring(1);
var typeSymbol = parameterSymbol.ContainingType;
var propertySymbol = typeSymbol.GetMembers(propName).Where(m => m.Kind == SymbolKind.Property).FirstOrDefault();
// Add a new property
if (propertySymbol == null)
{
await symbolEditor.EditOneDeclarationAsync(typeSymbol,
parameter.GetLocation(), // edit the partial declaration that has this parameter symbol.
(editor, typeDeclaration) =>
{
var newProperty = editor.Generator.PropertyDeclaration(propName,
editor.Generator.TypeExpression(parameterSymbol.Type),
Accessibility.Public,
DeclarationModifiers.ReadOnly);
newProperty = editor.Generator.WithGetAccessorStatements(newProperty, null);
editor.AddMember(typeDeclaration, newProperty);
},
cancellationToken).ConfigureAwait(false);
}
else
{
await symbolEditor.EditOneDeclarationAsync(propertySymbol,
(editor, propertyDeclaration) =>
{
editor.SetGetAccessorStatements(propertyDeclaration, null);
},
cancellationToken).ConfigureAwait(false);
}
return symbolEditor.GetChangedDocuments().First();
}
private async Task<Document> MakePublic(Document document, SyntaxNode getMethod, CancellationToken cancellationToken)
{
DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
editor.SetAccessibility(getMethod, Accessibility.Public);
return editor.GetChangedDocument();
}
private async Task<Document> RemoveSetter(Document document, SyntaxNode setMethod, CancellationToken cancellationToken)
{
DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
editor.SetAccessibility(setMethod, Accessibility.Internal);
return editor.GetChangedDocument();
}
private class MyCodeAction : DocumentChangeAction
{
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument)
: base(title, createChangedDocument)
{
}
}
}
}
......@@ -5,10 +5,10 @@
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.FxCopAnalyzers.Utilities;
namespace Microsoft.CodeAnalysis.FxCopAnalyzers.Design
namespace System.Runtime.Analyzers
{
/// <summary>
/// CA1019: Define accessors for attribute arguments
......@@ -16,19 +16,22 @@ namespace Microsoft.CodeAnalysis.FxCopAnalyzers.Design
/// Cause:
/// In its constructor, an attribute defines arguments that do not have corresponding properties.
/// </summary>
public abstract class CA1019DiagnosticAnalyzer : AbstractNamedTypeAnalyzer
public abstract class DefineAccessorsForAttributeArgumentsAnalyzer : DiagnosticAnalyzer
{
internal const string RuleId = "CA1019";
private static LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(FxCopRulesResources.DefineAccessorsForAttributeArguments), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources));
internal const string AddAccessorCase = "AddAccessor";
internal const string MakePublicCase = "MakePublic";
internal const string RemoveSetterCase = "RemoveSetter";
private static LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArguments), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId,
s_localizableTitle,
"{0}",
FxCopDiagnosticCategory.Design,
DiagnosticCategory.Design,
DiagnosticSeverity.Warning,
isEnabledByDefault: false,
helpLinkUri: "http://msdn.microsoft.com/library/ms182136.aspx",
customTags: DiagnosticCustomTags.Microsoft);
customTags: WellKnownDiagnosticTags.Telemetry);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
......@@ -38,9 +41,27 @@ public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
}
}
protected override void AnalyzeSymbol(INamedTypeSymbol symbol, Compilation compilation, Action<Diagnostic> addDiagnostic, AnalyzerOptions options, CancellationToken cancellationToken)
public override void Initialize(AnalysisContext analysisContext)
{
if (symbol != null && symbol.IsAttribute() && symbol.DeclaredAccessibility != Accessibility.Private)
analysisContext.RegisterCompilationStartAction(compilationContext =>
{
var attributeType = WellKnownTypes.IDisposable(compilationContext.Compilation);
if (attributeType == null)
{
return;
}
compilationContext.RegisterSymbolAction(context =>
{
AnalyzeSymbol((INamedTypeSymbol)context.Symbol, attributeType, context.Compilation, context.ReportDiagnostic);
},
SymbolKind.NamedType);
});
}
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)
{
IEnumerable<IParameterSymbol> parametersToCheck = GetAllPublicConstructorParameters(symbol);
if (parametersToCheck.Any())
......@@ -98,7 +119,7 @@ private void AnalyzeParameters(Compilation compilation, IEnumerable<IParameterSy
{
foreach (var parameter in parameters)
{
if (!parameter.Type.IsErrorType())
if (parameter.Type.Kind != SymbolKind.ErrorType)
{
IPropertySymbol property;
if (!propertiesMap.TryGetValue(parameter.Name, out property) ||
......@@ -148,22 +169,22 @@ private void AnalyzeParameters(Compilation compilation, IEnumerable<IParameterSy
private static Diagnostic GetDefaultDiagnostic(IParameterSymbol parameter, INamedTypeSymbol attributeType)
{
// Add a public read-only property accessor for positional argument '{0}' of attribute '{1}'.
var message = string.Format(FxCopRulesResources.DefineAccessorsForAttributeArgumentsDefault, parameter.Name, attributeType.Name);
return parameter.CreateDiagnostic(Rule, message);
var message = string.Format(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArgumentsDefault, parameter.Name, attributeType.Name);
return parameter.Locations.CreateDiagnostic(Rule, new Dictionary<string, string> { { "case", AddAccessorCase } }.ToImmutableDictionary(), message);
}
private static Diagnostic GetIncreaseVisibilityDiagnostic(IParameterSymbol parameter, IPropertySymbol property)
{
// If '{0}' is the property accessor for positional argument '{1}', make it public.
var message = string.Format(FxCopRulesResources.DefineAccessorsForAttributeArgumentsIncreaseVisibility, property.Name, parameter.Name);
return property.GetMethod.CreateDiagnostic(Rule, message);
var message = string.Format(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArgumentsIncreaseVisibility, property.Name, parameter.Name);
return property.GetMethod.Locations.CreateDiagnostic(Rule, new Dictionary<string, string> { { "case", MakePublicCase } }.ToImmutableDictionary(), message);
}
private static Diagnostic GetRemoveSetterDiagnostic(IParameterSymbol parameter, IPropertySymbol property)
{
// Remove the property setter from '{0}' or reduce its accessibility because it corresponds to positional argument '{1}'.
var message = string.Format(FxCopRulesResources.DefineAccessorsForAttributeArgumentsRemoveSetter, property.Name, parameter.Name);
return property.SetMethod.CreateDiagnostic(Rule, message);
var message = string.Format(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArgumentsRemoveSetter, property.Name, parameter.Name);
return property.SetMethod.Locations.CreateDiagnostic(Rule, new Dictionary<string, string> { { "case", RemoveSetterCase } }.ToImmutableDictionary(), message);
}
}
}
......@@ -4,57 +4,59 @@
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.FxCopAnalyzers.Utilities;
namespace Microsoft.CodeAnalysis.FxCopAnalyzers.Design
namespace System.Runtime.Analyzers
{
/// <summary>
/// CA1018: Custom attributes should have AttributeUsage attribute defined.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class CA1018DiagnosticAnalyzer : AbstractNamedTypeAnalyzer
public sealed class MarkAttributesWithAttributeUsageAnalyzer : DiagnosticAnalyzer
{
internal const string RuleId = "CA1018";
private static LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(FxCopRulesResources.CustomAttrShouldHaveAttributeUsage), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources));
private static LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(FxCopRulesResources.MarkAttributesWithAttributeUsage), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources));
private static LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.CustomAttrShouldHaveAttributeUsage), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
private static LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.MarkAttributesWithAttributeUsage), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId,
s_localizableTitle,
s_localizableMessage,
FxCopDiagnosticCategory.Design,
DiagnosticCategory.Design,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
helpLinkUri: "http://msdn.microsoft.com/library/ms182158.aspx",
customTags: DiagnosticCustomTags.Microsoft);
customTags: WellKnownDiagnosticTags.Telemetry);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
return ImmutableArray.Create(Rule);
}
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
protected override void AnalyzeSymbol(INamedTypeSymbol symbol, Compilation compilation, Action<Diagnostic> addDiagnostic, AnalyzerOptions options, CancellationToken cancellationToken)
public override void Initialize(AnalysisContext analysisContext)
{
var attributeUsageAttribute = WellKnownTypes.AttributeUsageAttribute(compilation);
if (attributeUsageAttribute == null)
analysisContext.RegisterCompilationStartAction(compilationContext =>
{
return;
}
var attributeType = WellKnownTypes.Attribute(compilationContext.Compilation);
var attributeUsageAttributeType = WellKnownTypes.AttributeUsageAttribute(compilationContext.Compilation);
if (attributeType == null || attributeUsageAttributeType == null)
{
return;
}
if (symbol.IsAbstract || !symbol.IsAttribute())
{
return;
}
compilationContext.RegisterSymbolAction(context =>
{
AnalyzeSymbol((INamedTypeSymbol)context.Symbol, attributeType, attributeUsageAttributeType, context.ReportDiagnostic);
},
SymbolKind.NamedType);
});
}
if (attributeUsageAttribute == null)
private static void AnalyzeSymbol(INamedTypeSymbol symbol, INamedTypeSymbol attributeType, INamedTypeSymbol attributeUsageAttributeType, Action<Diagnostic> addDiagnostic)
{
if (symbol.IsAbstract || !symbol.GetBaseTypesAndThis().Contains(attributeType))
{
return;
}
var hasAttributeUsageAttribute = symbol.GetAttributes().Any(attribute => attribute.AttributeClass == attributeUsageAttribute);
var hasAttributeUsageAttribute = symbol.GetAttributes().Any(attribute => attribute.AttributeClass == attributeUsageAttributeType);
if (!hasAttributeUsageAttribute)
{
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.
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<string> 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<SyntaxNode> parameters, SyntaxNode notImplementedStatement);
private async Task<Document> ImplementComparable(Document document, SyntaxNode declaration, INamedTypeSymbol typeSymbol, CancellationToken cancellationToken)
{
DocumentEditor editor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false);
var generator = editor.Generator;
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<CancellationToken, Task<Document>> createChangedDocument)
: base(title, createChangedDocument)
{
}
}
}
}
// 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.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.FxCopAnalyzers.Utilities;
namespace Microsoft.CodeAnalysis.FxCopAnalyzers.Design
namespace System.Runtime.Analyzers
{
/// <summary>
/// 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.
/// </summary>
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class CA1036DiagnosticAnalyzer : AbstractNamedTypeAnalyzer
public sealed class OverrideMethodsOnComparableTypesAnalyzer : DiagnosticAnalyzer
{
internal const string RuleId = "CA1036";
private static LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(FxCopRulesResources.OverloadOperatorEqualsOnIComparableInterface), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources));
private static LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(FxCopRulesResources.OverloadOperatorEqualsOnIComparableInterface), FxCopRulesResources.ResourceManager, typeof(FxCopRulesResources));
private static LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(FxCopRulesResources.OverloadOperatorEqualsOnIComparableInterfaceDescription), 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(SystemRuntimeAnalyzersResources.OverloadOperatorEqualsOnIComparableInterface), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
private static LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.OverloadOperatorEqualsOnIComparableInterfaceDescription), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources));
internal static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId,
s_localizableTitle,
s_localizableMessage,
FxCopDiagnosticCategory.Design,
DiagnosticCategory.Design,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
description: s_localizableDescription,
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)
{
var comparableType = WellKnownTypes.IComparable(compilation);
// Even if one of them is available, we should continue analysis.
if (comparableType == null && genericComparableType == null)
{
return;
}
if (comparableType == null)
{
return;
}
compilationContext.RegisterSymbolAction(context =>
{
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;
}
if (namedTypeSymbol.Interfaces.Contains(comparableType))
if (namedTypeSymbol.AllInterfaces.Any(t => t.Equals(comparableType) ||
(t.ConstructedFrom?.Equals(genericComparableType) ?? false)))
{
if (!(DoesOverrideEquals(namedTypeSymbol) && IsEqualityOperatorImplemented(namedTypeSymbol)))
{
......@@ -58,25 +71,33 @@ protected override void AnalyzeSymbol(INamedTypeSymbol namedTypeSymbol, Compilat
}
}
private static bool DoesOverrideEquals(INamedTypeSymbol symbol)
internal static bool DoesOverrideEquals(INamedTypeSymbol symbol)
{
// Does the symbol override Object.Equals?
return symbol.GetMembers(WellKnownMemberNames.ObjectEquals).OfType<IMethodSymbol>().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<IMethodSymbol>().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.)
......@@ -86,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<IMethodSymbol>().Where(m => m.MethodKind == MethodKind.UserDefinedOperator).Any();
......
......@@ -21,15 +21,7 @@ public class TypesThatOwnDisposableFieldsShouldBeDisposableFixer : CodeFixProvid
protected const string NotImplementedExceptionName = "System.NotImplementedException";
protected const string IDisposableName = "System.IDisposable";
public sealed override ImmutableArray<string> FixableDiagnosticIds
{
get { return ImmutableArray.Create(TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer.RuleId); }
}
protected string GetCodeFixDescription(Diagnostic diagnostic)
{
return SystemRuntimeAnalyzersResources.ImplementIDisposableInterface;
}
public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer.RuleId);
public async override Task RegisterCodeFixesAsync(CodeFixContext context)
{
......@@ -47,8 +39,8 @@ public async override Task RegisterCodeFixesAsync(CodeFixContext context)
// We cannot have multiple overlapping diagnostics of this id.
var diagnostic = context.Diagnostics.Single();
context.RegisterCodeFix(new DocumentChangeAction(SystemRuntimeAnalyzersResources.ImplementIDisposableInterface,
async ct => await ImplementIDisposable(context.Document, declaration, ct).ConfigureAwait(false)),
context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.ImplementIDisposableInterface,
async ct => await ImplementIDisposable(context.Document, declaration, ct).ConfigureAwait(false)),
diagnostic);
}
......@@ -81,5 +73,13 @@ private async Task<Document> ImplementIDisposable(Document document, SyntaxNode
return editor.GetChangedDocument();
}
private class MyCodeAction : DocumentChangeAction
{
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument)
: base(title, createChangedDocument)
{
}
}
}
}
......@@ -17,7 +17,6 @@ public sealed class TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer : Dia
{
internal const string RuleId = "CA1001";
internal const string Dispose = "Dispose";
internal const string IDisposable = "System.IDisposable";
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(RuleId,
new LocalizableResourceString(nameof(SystemRuntimeAnalyzersResources.TypesThatOwnDisposableFieldsShouldBeDisposable), SystemRuntimeAnalyzersResources.ResourceManager, typeof(SystemRuntimeAnalyzersResources)),
......@@ -28,27 +27,29 @@ public sealed class TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzer : Dia
helpLinkUri: "http://msdn.microsoft.com/library/ms182172.aspx",
customTags: WellKnownDiagnosticTags.Telemetry);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
return ImmutableArray.Create(Rule);
}
}
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext analysisContext)
{
analysisContext.RegisterSymbolAction(context =>
analysisContext.RegisterCompilationStartAction(compilationContext =>
{
AnalyzeSymbol((INamedTypeSymbol)context.Symbol, context.Compilation, context.ReportDiagnostic, context.Options, context.CancellationToken);
},
SymbolKind.NamedType);
var disposableType = WellKnownTypes.IDisposable(compilationContext.Compilation);
if (disposableType == null)
{
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 (disposableType != null && !symbol.AllInterfaces.Contains(disposableType))
if (!symbol.AllInterfaces.Contains(disposableType))
{
var disposableFields = from member in symbol.GetMembers()
where member.Kind == SymbolKind.Field && !member.IsStatic
......
// 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.Linq;
using Microsoft.CodeAnalysis;
......@@ -84,17 +85,6 @@ internal static class DiagnosticExtensions
return symbol.Locations.CreateDiagnostic(rule, args);
}
public static IEnumerable<Diagnostic> CreateDiagnostics(
this IEnumerable<Location> locations,
DiagnosticDescriptor rule,
params object[] args)
{
foreach (var location in locations)
{
yield return location.CreateDiagnostic(rule, args);
}
}
public static Diagnostic CreateDiagnostic(
this Location location,
DiagnosticDescriptor rule,
......@@ -131,5 +121,20 @@ internal static class DiagnosticExtensions
additionalLocations: additionalLocations,
messageArgs: args);
}
public static Diagnostic CreateDiagnostic(
this IEnumerable<Location> locations,
DiagnosticDescriptor rule,
ImmutableDictionary<string, string> properties,
params object[] args)
{
var location = locations.First(l => l.IsInSource);
var additionalLocations = locations.Where(l => l.IsInSource).Skip(1);
return Diagnostic.Create(rule,
location: location,
additionalLocations: additionalLocations,
properties: properties,
messageArgs: args);
}
}
}
// 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 Microsoft.CodeAnalysis;
namespace System.Runtime.Analyzers
{
internal static class INamedTypeSymbolExtensions
{
public static IEnumerable<INamedTypeSymbol> GetBaseTypesAndThis(this INamedTypeSymbol type)
{
var current = type;
while (current != null)
{
yield return current;
current = current.BaseType;
}
}
}
}
......@@ -53,12 +53,17 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="CodeFixProviderBase.cs" />
<Compile Include="Design\OverrideMethodsOnComparableTypes.cs" />
<Compile Include="Design\DefineAccessorsForAttributeArguments.cs" />
<Compile Include="Design\DefineAccessorsForAttributeArguments.Fixer.cs" />
<Compile Include="Design\MarkAttributesWithAttributeUsage.cs" />
<Compile Include="Design\OverrideMethodsOnComparableTypes.Fixer.cs" />
<Compile Include="Design\TypesThatOwnDisposableFieldsShouldBeDisposable.Fixer.cs" />
<Compile Include="Design\TypesThatOwnDisposableFieldsShouldBeDisposable.cs" />
<Compile Include="DiagnosticCategory.cs" />
<Compile Include="DiagnosticExtensions.cs" />
<Compile Include="Extensions\DiagnosticExtensions.cs" />
<Compile Include="DocumentChangeAction.cs" />
<Compile Include="Extensions\INamedTypeSymbolExtensions.cs" />
<Compile Include="SystemRuntimeAnalyzersResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
......@@ -78,4 +83,4 @@
<Import Project="..\..\..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -124,6 +124,69 @@ internal class SystemRuntimeAnalyzersResources {
}
}
/// <summary>
/// Looks up a localized string similar to Create a property accessor..
/// </summary>
internal static string CreatePropertyAccessorForParameter {
get {
return ResourceManager.GetString("CreatePropertyAccessorForParameter", resourceCulture);
}
}
/// <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>
/// Looks up a localized string similar to Define accessors for attribute arguments..
/// </summary>
internal static string DefineAccessorsForAttributeArguments {
get {
return ResourceManager.GetString("DefineAccessorsForAttributeArguments", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Add a public read-only property accessor for positional argument &apos;{0}&apos; of attribute &apos;{1}&apos;..
/// </summary>
internal static string DefineAccessorsForAttributeArgumentsDefault {
get {
return ResourceManager.GetString("DefineAccessorsForAttributeArgumentsDefault", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to If &apos;{0}&apos; is the property accessor for positional argument &apos;{1}&apos;, ensure that property getter is public..
/// </summary>
internal static string DefineAccessorsForAttributeArgumentsIncreaseVisibility {
get {
return ResourceManager.GetString("DefineAccessorsForAttributeArgumentsIncreaseVisibility", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Remove the property setter from &apos;{0}&apos; or reduce its accessibility because it corresponds to positional argument &apos;{1}&apos;..
/// </summary>
internal static string DefineAccessorsForAttributeArgumentsRemoveSetter {
get {
return ResourceManager.GetString("DefineAccessorsForAttributeArgumentsRemoveSetter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Implement Equality and Comparison methods and operators.
/// </summary>
internal static string ImplementComparable {
get {
return ResourceManager.GetString("ImplementComparable", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Implement IDisposable Interface.
/// </summary>
......@@ -133,6 +196,51 @@ internal class SystemRuntimeAnalyzersResources {
}
}
/// <summary>
/// Looks up a localized string similar to Make the getter of the property public.
/// </summary>
internal static string MakeGetterPublic {
get {
return ResourceManager.GetString("MakeGetterPublic", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Make the setter of the property non-public.
/// </summary>
internal static string MakeSetterNonPublic {
get {
return ResourceManager.GetString("MakeSetterNonPublic", resourceCulture);
}
}
/// <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>
/// 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>
/// Looks up a localized string similar to Type &apos;{0}&apos; owns disposable fields but is not disposable.
/// </summary>
......
......@@ -147,4 +147,40 @@
<data name="TypeOwnsDisposableFieldButIsNotDisposable" xml:space="preserve">
<value>Type '{0}' owns disposable fields but is not disposable</value>
</data>
<data name="CustomAttrShouldHaveAttributeUsage" xml:space="preserve">
<value>Custom attributes should have AttributeUsage attribute defined.</value>
</data>
<data name="MarkAttributesWithAttributeUsage" xml:space="preserve">
<value>Specify AttributeUsage attribute on '{0}' attribute class.</value>
</data>
<data name="DefineAccessorsForAttributeArguments" xml:space="preserve">
<value>Define accessors for attribute arguments.</value>
</data>
<data name="DefineAccessorsForAttributeArgumentsDefault" xml:space="preserve">
<value>Add a public read-only property accessor for positional argument '{0}' of attribute '{1}'.</value>
</data>
<data name="DefineAccessorsForAttributeArgumentsIncreaseVisibility" xml:space="preserve">
<value>If '{0}' is the property accessor for positional argument '{1}', ensure that property getter is public.</value>
</data>
<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>
</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>
<data name="CreatePropertyAccessorForParameter" xml:space="preserve">
<value>Create a property accessor.</value>
</data>
<data name="ImplementComparable" xml:space="preserve">
<value>Implement Equality and Comparison methods and operators</value>
</data>
<data name="MakeGetterPublic" xml:space="preserve">
<value>Make the getter of the property public</value>
</data>
<data name="MakeSetterNonPublic" xml:space="preserve">
<value>Make the setter of the property non-public</value>
</data>
</root>
\ No newline at end of file
......@@ -141,6 +141,11 @@ public static INamedTypeSymbol IComparable(Compilation compilation)
return compilation.GetTypeByMetadataName("System.IComparable");
}
public static INamedTypeSymbol GenericIComparable(Compilation compilation)
{
return compilation.GetTypeByMetadataName("System.IComparable`1");
}
public static INamedTypeSymbol ComSourceInterfaceAttribute(Compilation compilation)
{
return compilation.GetTypeByMetadataName("System.Runtime.InteropServices.ComSourceInterfacesAttribute");
......@@ -170,5 +175,10 @@ public static INamedTypeSymbol NotImplementedException(Compilation compilation)
{
return compilation.GetTypeByMetadataName("System.NotImplementedException");
}
public static INamedTypeSymbol Attribute(Compilation compilation)
{
return compilation.GetTypeByMetadataName("System.Attribute");
}
}
}
// 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.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.UnitTests;
using Xunit;
namespace System.Runtime.Analyzers.UnitTests
{
public partial class DefineAccessorsForAttributeArgumentsTests : CodeFixTestBase
{
protected override CodeFixProvider GetCSharpCodeFixProvider()
{
return new DefineAccessorsForAttributeArgumentsFixer();
}
protected override CodeFixProvider GetBasicCodeFixProvider()
{
return new DefineAccessorsForAttributeArgumentsFixer();
}
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CSharp_CA1019_AddAccessor()
{
VerifyCSharpFix(@"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class NoAccessorTestAttribute : Attribute
{
private string m_name;
public NoAccessorTestAttribute(string name)
{
m_name = name;
}
}", @"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class NoAccessorTestAttribute : Attribute
{
private string m_name;
public NoAccessorTestAttribute(string name)
{
m_name = name;
}
public string Name { get; }
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CSharp_CA1019_AddAccessor1()
{
VerifyCSharpFix(@"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class SetterOnlyTestAttribute : Attribute
{
private string m_name;
public SetterOnlyTestAttribute(string name)
{
m_name = name;
}
public string Name
{
set { m_name = value }
}
}", @"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class SetterOnlyTestAttribute : Attribute
{
private string m_name;
public SetterOnlyTestAttribute(string name)
{
m_name = name;
}
public string Name
{
set { m_name = value }
get;
}
}", allowNewCompilerDiagnostics: true);
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/662"), Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CSharp_CA1019_MakeGetterPublic()
{
VerifyCSharpFix(@"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class InternalGetterTestAttribute : Attribute
{
private string m_name;
public InternalGetterTestAttribute(string name)
{
m_name = name;
}
public string Name
{
internal get { return m_name; }
set { m_name = value; }
}
}", @"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class InternalGetterTestAttribute : Attribute
{
private string m_name;
public InternalGetterTestAttribute(string name)
{
m_name = name;
}
public string Name
{
get { return m_name; }
set { m_name = value; }
}
}");
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/662"), Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CSharp_CA1019_MakeGetterPublic2()
{
VerifyCSharpFix(@"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class InternalGetterTestAttribute : Attribute
{
private string m_name;
public InternalGetterTestAttribute(string name)
{
m_name = name;
}
internal string Name
{
get { return m_name; }
set { m_name = value; }
}
}", @"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class InternalGetterTestAttribute : Attribute
{
private string m_name;
public InternalGetterTestAttribute(string name)
{
m_name = name;
}
public string Name
{
get { return m_name; }
set { m_name = value; }
}
}");
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/662"), Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void CSharp_CA1019_MakeSetterInternal()
{
VerifyCSharpFix(@"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class PublicSetterTestAttribute : Attribute
{
private string m_name;
public PublicSetterTestAttribute(string name)
{
m_name = name;
}
public string Name
{
get { return m_name; }
set { m_name = value; }
}
}", @"
using System;
[AttributeUsage(AttributeTargets.All)]
public sealed class PublicSetterTestAttribute : Attribute
{
private string m_name;
public PublicSetterTestAttribute(string name)
{
m_name = name;
}
public string Name
{
get { return m_name; }
internal set { m_name = value; }
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void VisualBasic_CA1019_AddAccessor()
{
VerifyBasicFix(@"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class NoAccessorTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
End Class", @"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class NoAccessorTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
Public ReadOnly Property Name As String
Get
End Get
End Property
End Class", allowNewCompilerDiagnostics: true);
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/679"), Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void VisualBasic_CA1019_AddAccessor2()
{
VerifyBasicFix(@"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class SetterOnlyTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
Public WriteOnly Property Name() As String
Set
m_name = value
End Set
End Property
End Class", @"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class SetterOnlyTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
Public Property Name() As String
Set
m_name = value
End Set
Get
End Get
End Property
End Class", allowNewCompilerDiagnostics: true);
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/662"), Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void VisualBasic_CA1019_MakeGetterPublic()
{
VerifyBasicFix(@"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class InternalGetterTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
Public Property Name() As String
Friend Get
Return m_name
End Get
Set
m_name = value
End Set
End Property
End Class", @"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class InternalGetterTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
Public Property Name() As String
Get
Return m_name
End Get
Set
m_name = value
End Set
End Property
End Class", allowNewCompilerDiagnostics: true);
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/662"), Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void VisualBasic_CA1019_MakeGetterPublic2()
{
VerifyBasicFix(@"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class InternalGetterTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
Friend Property Name() As String
Get
Return m_name
End Get
Set
m_name = value
End Set
End Property
End Class", @"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class InternalGetterTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
Public Property Name() As String
Get
Return m_name
End Get
Set
m_name = value
End Set
End Property
End Class", allowNewCompilerDiagnostics: true);
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/662"), Trait(Traits.Feature, Traits.Features.Diagnostics)]
public void VisualBasic_CA1019_MakeSetterInternal()
{
VerifyBasicFix(@"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class PublicSetterTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
Property Name() As String
Get
Return m_name
End Get
Set
m_name = value
End Set
End Property
End Class", @"
Imports System
<AttributeUsage(AttributeTargets.All)> _
Public NotInheritable Class PublicSetterTestAttribute
Inherits Attribute
Private m_name As String
Public Sub New(name As String)
m_name = name
End Sub
Public Property Name() As String
Get
Return m_name
End Get
Friend Set
m_name = value
End Set
End Property
End Class", allowNewCompilerDiagnostics: true);
}
}
}
// 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.CSharp.FxCopAnalyzers.Design;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.FxCopAnalyzers;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.VisualBasic.FxCopAnalyzers.Design;
using Roslyn.Test.Utilities;
using Microsoft.CodeAnalysis.UnitTests;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests
namespace System.Runtime.Analyzers.UnitTests
{
public partial class CA1019Tests : DiagnosticAnalyzerTestBase
public partial class DefineAccessorsForAttributeArgumentsTests : CodeFixTestBase
{
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{
return new BasicCA1019DiagnosticAnalyzer();
return new BasicDefineAccessorsForAttributeArgumentsAnalyzer();
}
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
return new CSharpCA1019DiagnosticAnalyzer();
return new CSharpDefineAccessorsForAttributeArgumentsAnalyzer();
}
#region No Diagnostic Tests
......@@ -2761,42 +2758,42 @@ End Class
private static DiagnosticResult GetCA1019CSharpDefaultResultAt(int line, int column, string paramName, string attributeTypeName)
{
// Add a public read-only property accessor for positional argument '{0}' of attribute '{1}'.
var message = string.Format(FxCopRulesResources.DefineAccessorsForAttributeArgumentsDefault, paramName, attributeTypeName);
var message = string.Format(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArgumentsDefault, paramName, attributeTypeName);
return GetCSharpResultAt(line, column, CA1019Name, message);
}
private static DiagnosticResult GetCA1019BasicDefaultResultAt(int line, int column, string paramName, string attributeTypeName)
{
// Add a public read-only property accessor for positional argument '{0}' of attribute '{1}'.
var message = string.Format(FxCopRulesResources.DefineAccessorsForAttributeArgumentsDefault, paramName, attributeTypeName);
var message = string.Format(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArgumentsDefault, paramName, attributeTypeName);
return GetBasicResultAt(line, column, CA1019Name, message);
}
private static DiagnosticResult GetCA1019CSharpIncreaseVisibilityResultAt(int line, int column, string propertyName, string paramName)
{
// If '{0}' is the property accessor for positional argument '{1}', make it public.
var message = string.Format(FxCopRulesResources.DefineAccessorsForAttributeArgumentsIncreaseVisibility, propertyName, paramName);
var message = string.Format(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArgumentsIncreaseVisibility, propertyName, paramName);
return GetCSharpResultAt(line, column, CA1019Name, message);
}
private static DiagnosticResult GetCA1019BasicIncreaseVisibilityResultAt(int line, int column, string propertyName, string paramName)
{
// If '{0}' is the property accessor for positional argument '{1}', make it public.
var message = string.Format(FxCopRulesResources.DefineAccessorsForAttributeArgumentsIncreaseVisibility, propertyName, paramName);
var message = string.Format(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArgumentsIncreaseVisibility, propertyName, paramName);
return GetBasicResultAt(line, column, CA1019Name, message);
}
private static DiagnosticResult GetCA1019CSharpRemoveSetterResultAt(int line, int column, string propertyName, string paramName)
{
// Remove the property setter from '{0}' or reduce its accessibility because it corresponds to positional argument '{1}'.
var message = string.Format(FxCopRulesResources.DefineAccessorsForAttributeArgumentsRemoveSetter, propertyName, paramName);
var message = string.Format(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArgumentsRemoveSetter, propertyName, paramName);
return GetCSharpResultAt(line, column, CA1019Name, message);
}
private static DiagnosticResult GetCA1019BasicRemoveSetterResultAt(int line, int column, string propertyName, string paramName)
{
// Remove the property setter from '{0}' or reduce its accessibility because it corresponds to positional argument '{1}'.
var message = string.Format(FxCopRulesResources.DefineAccessorsForAttributeArgumentsRemoveSetter, propertyName, paramName);
var message = string.Format(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArgumentsRemoveSetter, propertyName, paramName);
return GetBasicResultAt(line, column, CA1019Name, message);
}
}
......
// 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.FxCopAnalyzers;
using Microsoft.CodeAnalysis.FxCopAnalyzers.Design;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.UnitTests;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests
namespace System.Runtime.Analyzers.UnitTests
{
public partial class CA1018Tests : DiagnosticAnalyzerTestBase
public partial class MarkAttributesWithAttributeUsageTests : DiagnosticAnalyzerTestBase
{
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{
return new CA1018DiagnosticAnalyzer();
return new MarkAttributesWithAttributeUsageAnalyzer();
}
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
return new CA1018DiagnosticAnalyzer();
return new MarkAttributesWithAttributeUsageAnalyzer();
}
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
......@@ -109,7 +108,7 @@ End Class
}
internal static string CA1018Name = "CA1018";
internal static string CA1018Message = FxCopRulesResources.MarkAttributesWithAttributeUsage;
internal static string CA1018Message = SystemRuntimeAnalyzersResources.MarkAttributesWithAttributeUsage;
private static DiagnosticResult GetCA1018CSharpResultAt(int line, int column, string objectName)
{
......
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");
}
}
}
// 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.FxCopAnalyzers.Design;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.UnitTests;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests
namespace System.Runtime.Analyzers.UnitTests
{
[WorkItem(858659, "DevDiv")]
public partial class CA1030Tests : DiagnosticAnalyzerTestBase
public partial class OverrideMethodsOnComparableTypesTests : CodeFixTestBase
{
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{
return new CA1036DiagnosticAnalyzer();
return new OverrideMethodsOnComparableTypesAnalyzer();
}
protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
return new CA1036DiagnosticAnalyzer();
return new OverrideMethodsOnComparableTypesAnalyzer();
}
[Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)]
......@@ -397,6 +397,82 @@ public override bool Equals(object obj)
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)]
public void CA1036ClassNoWarningBasic()
{
......@@ -723,6 +799,76 @@ End Class
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 CA1036Message = "Overload operator Equals and comparison operators when implementing System.IComparable";
......
......@@ -4,12 +4,11 @@
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.UnitTests;
using Roslyn.Test.Utilities;
using Xunit;
namespace System.Runtime.Analyzers.UnitTests
{
public partial class CA1001FixerTests : CodeFixTestBase
public partial class TypesThatOwnDisposableFieldsShouldBeDisposableFixerTests : CodeFixTestBase
{
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{
......
......@@ -7,7 +7,7 @@
namespace System.Runtime.Analyzers.UnitTests
{
public partial class CA1001Tests : DiagnosticAnalyzerTestBase
public partial class TypesThatOwnDisposableFieldsShouldBeDisposableAnalyzerTests : DiagnosticAnalyzerTestBase
{
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{
......
......@@ -97,8 +97,13 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="TypesThatOwnDisposableFieldsShouldBeDisposableTests.Fixer.cs" />
<Compile Include="TypesThatOwnDisposableFieldsShouldBeDisposableTests.cs" />
<Compile Include="Design\OverrideMethodsOnComparableTypesTests.cs" />
<Compile Include="Design\DefineAccessorsForAttributeArgumentsTests.Fixer.cs" />
<Compile Include="Design\DefineAccessorsForAttributeArgumentsTests.cs" />
<Compile Include="Design\MarkAttributesWithAttributeUsageTests.cs" />
<Compile Include="Design\OverrideMethodsOnComparableTypesTests.Fixer.cs" />
<Compile Include="Design\TypesThatOwnDisposableFieldsShouldBeDisposableTests.Fixer.cs" />
<Compile Include="Design\TypesThatOwnDisposableFieldsShouldBeDisposableTests.cs" />
</ItemGroup>
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Imports.targets" />
......
......@@ -70,10 +70,13 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Compile Include="Design\DefineAccessorsForAttributeArguments.vb" />
<Compile Include="Design\OverrideMethodsOnComparableTypes.Fixer.vb" />
</ItemGroup>
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Imports.targets" />
<Import Project="..\..\..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
' 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 Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.FxCopAnalyzers.Design
Imports Microsoft.CodeAnalysis.VisualBasic
Namespace Microsoft.CodeAnalysis.VisualBasic.FxCopAnalyzers.Design
Namespace System.Runtime.Analyzers
<DiagnosticAnalyzer(LanguageNames.VisualBasic)>
Public Class BasicCA1019DiagnosticAnalyzer
Inherits CA1019DiagnosticAnalyzer
Public Class BasicDefineAccessorsForAttributeArgumentsAnalyzer
Inherits DefineAccessorsForAttributeArgumentsAnalyzer
Protected Overrides Function IsAssignableTo(fromSymbol As ITypeSymbol, toSymbol As ITypeSymbol, compilation As Compilation) As Boolean
Return fromSymbol IsNot Nothing AndAlso toSymbol IsNot Nothing AndAlso DirectCast(compilation, VisualBasicCompilation).ClassifyConversion(fromSymbol, toSymbol).IsWidening
......
' 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
<ExportCodeFixProvider(LanguageNames.VisualBasic), [Shared]>
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
......@@ -86,8 +86,6 @@
<Compile Include="Design\CA1014Tests.cs" />
<Compile Include="Design\CA1016Tests.cs" />
<Compile Include="Design\CA1017Tests.cs" />
<Compile Include="Design\CA1018Tests.cs" />
<Compile Include="Design\CA1019Tests.cs" />
<Compile Include="Design\CA1024Tests.cs" />
<Compile Include="Design\CA1052Tests.cs" />
<Compile Include="Design\CA1053Tests.cs" />
......@@ -108,7 +106,6 @@
<Compile Include="Performance\CodeFixes\CA1813FixerTests.cs" />
<Compile Include="Performance\CodeFixes\CA1821FixerTests.cs" />
<Compile Include="Reliability\CA2002Tests.cs" />
<Compile Include="Design\CA1036Tests.cs" />
<Compile Include="Usage\CA2200Tests.cs" />
<Compile Include="Usage\CA2213Tests.cs" />
<Compile Include="Usage\CA2214Tests.cs" />
......
......@@ -96,7 +96,6 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Design\BasicCA1003DiagnosticAnalyzer.vb" />
<Compile Include="Design\BasicCA1019DiagnosticAnalyzer.vb" />
<Compile Include="Design\BasicCA1024DiagnosticAnalyzer.vb" />
<Compile Include="Design\BasicEnumWithFlagsDiagnosticAnalyzer.vb" />
<Compile Include="Design\CodeFixes\CA1008BasicCodeFixProvider.vb" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册