提交 bfa2e27c 编写于 作者: S Srivatsn Narayanan

Add a codefix for CA1036 that generates Equals\GetHashCode and operators =,...

Add a codefix for CA1036 that generates Equals\GetHashCode and operators =, !=, > and <. Note that the syntax generator doesn't have an API to generate operators and so I've had to create language specific fixes.
上级 6f20b92c
......@@ -74,6 +74,7 @@
<ItemGroup />
<ItemGroup>
<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" />
......
using System.Collections.Generic;
using System.Composition;
using System.Diagnostics;
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace System.Runtime.Analyzers
{
[ExportCodeFixProvider(LanguageNames.CSharp), Shared]
public class CSharpOverrideMethodsOnComparableTypesFixer : OverrideMethodsOnComparableTypesFixer
{
protected override SyntaxNode GenerateOperatorDeclaration(SyntaxNode returnType, string operatorName, IEnumerable<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));
}
}
}
......@@ -31,20 +31,20 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
var parameter = generator.GetDeclaration(node, DeclarationKind.Parameter);
if (parameter != null)
{
context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArguments,
context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.CreatePropertyAccessorForParameter,
async ct => await AddAccessor(context.Document, parameter, ct).ConfigureAwait(false)),
diagnostic);
}
return;
case DefineAccessorsForAttributeArgumentsAnalyzer.MakePublicCase:
context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArguments,
context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.MakeGetterPublic,
async ct => await MakePublic(context.Document, node, ct).ConfigureAwait(false)),
diagnostic);
return;
case DefineAccessorsForAttributeArgumentsAnalyzer.RemoveSetterCase:
context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.DefineAccessorsForAttributeArguments,
context.RegisterCodeFix(new MyCodeAction(SystemRuntimeAnalyzersResources.MakeSetterNonPublic,
async ct => await RemoveSetter(context.Document, node, ct).ConfigureAwait(false)),
diagnostic);
return;
......
// 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;
var throwStatement = generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException")));
if (!OverrideMethodsOnComparableTypesAnalyzer.DoesOverrideEquals(typeSymbol))
{
var equalsMethod = generator.MethodDeclaration(WellKnownMemberNames.ObjectEquals,
new[] { generator.ParameterDeclaration("obj", generator.TypeExpression(SpecialType.System_Object)) },
returnType: generator.TypeExpression(SpecialType.System_Boolean),
accessibility: Accessibility.Public,
modifiers: DeclarationModifiers.Override,
statements: new[] { generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException")))});
editor.AddMember(declaration, equalsMethod);
}
if (!OverrideMethodsOnComparableTypesAnalyzer.DoesOverrideGetHashCode(typeSymbol))
{
var getHashCodeMethod = generator.MethodDeclaration(WellKnownMemberNames.ObjectGetHashCode,
returnType: generator.TypeExpression(SpecialType.System_Int32),
accessibility: Accessibility.Public,
modifiers: DeclarationModifiers.Override,
statements: new[] { generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))) });
editor.AddMember(declaration, getHashCodeMethod);
}
if (!OverrideMethodsOnComparableTypesAnalyzer.IsOperatorImplemented(typeSymbol, WellKnownMemberNames.EqualityOperatorName))
{
var equalityOperator = GenerateOperatorDeclaration(generator.TypeExpression(SpecialType.System_Boolean),
WellKnownMemberNames.EqualityOperatorName,
new[]
{
generator.ParameterDeclaration("left", generator.TypeExpression(typeSymbol)),
generator.ParameterDeclaration("right", generator.TypeExpression(typeSymbol)),
},
generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))));
editor.AddMember(declaration, equalityOperator);
}
if (!OverrideMethodsOnComparableTypesAnalyzer.IsOperatorImplemented(typeSymbol, WellKnownMemberNames.InequalityOperatorName))
{
var inequalityOperator = GenerateOperatorDeclaration(generator.TypeExpression(SpecialType.System_Boolean),
WellKnownMemberNames.InequalityOperatorName,
new[]
{
generator.ParameterDeclaration("left", generator.TypeExpression(typeSymbol)),
generator.ParameterDeclaration("right", generator.TypeExpression(typeSymbol)),
},
generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))));
editor.AddMember(declaration, inequalityOperator);
}
if (!OverrideMethodsOnComparableTypesAnalyzer.IsOperatorImplemented(typeSymbol, WellKnownMemberNames.LessThanOperatorName))
{
var lessThanOperator = GenerateOperatorDeclaration(generator.TypeExpression(SpecialType.System_Boolean),
WellKnownMemberNames.LessThanOperatorName,
new[]
{
generator.ParameterDeclaration("left", generator.TypeExpression(typeSymbol)),
generator.ParameterDeclaration("right", generator.TypeExpression(typeSymbol)),
},
generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))));
editor.AddMember(declaration, lessThanOperator);
}
if (!OverrideMethodsOnComparableTypesAnalyzer.IsOperatorImplemented(typeSymbol, WellKnownMemberNames.GreaterThanOperatorName))
{
var greaterThanOperator = GenerateOperatorDeclaration(generator.TypeExpression(SpecialType.System_Boolean),
WellKnownMemberNames.GreaterThanOperatorName,
new[]
{
generator.ParameterDeclaration("left", generator.TypeExpression(typeSymbol)),
generator.ParameterDeclaration("right", generator.TypeExpression(typeSymbol)),
},
generator.ThrowStatement(generator.ObjectCreationExpression(generator.DottedName("System.NotImplementedException"))));
editor.AddMember(declaration, greaterThanOperator);
}
return editor.GetChangedDocument();
}
private class MyCodeAction : DocumentChangeAction
{
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument)
: base(title, createChangedDocument)
{
}
}
}
}
......@@ -2,12 +2,17 @@
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
namespace System.Runtime.Analyzers
{
/// <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 OverrideMethodsOnComparableTypesAnalyzer : DiagnosticAnalyzer
{
......@@ -66,25 +71,33 @@ private static void AnalyzeSymbol(INamedTypeSymbol namedTypeSymbol, INamedTypeSy
}
}
private static bool DoesOverrideEquals(INamedTypeSymbol symbol)
internal static bool DoesOverrideEquals(INamedTypeSymbol symbol)
{
// Does the symbol override Object.Equals?
return symbol.GetMembers(WellKnownMemberNames.ObjectEquals).OfType<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.)
......@@ -94,7 +107,7 @@ private static bool IsEqualityOperatorImplemented(INamedTypeSymbol symbol)
IsOperatorImplemented(symbol, WellKnownMemberNames.GreaterThanOperatorName);
}
private static bool IsOperatorImplemented(INamedTypeSymbol symbol, string op)
internal static bool IsOperatorImplemented(INamedTypeSymbol symbol, string op)
{
// TODO: should this filter on the right-hand-side operator type?
return symbol.GetMembers(op).OfType<IMethodSymbol>().Where(m => m.MethodKind == MethodKind.UserDefinedOperator).Any();
......
......@@ -57,6 +57,7 @@
<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" />
......
......@@ -124,6 +124,15 @@ 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>
......@@ -169,6 +178,15 @@ internal class SystemRuntimeAnalyzersResources {
}
}
/// <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>
......@@ -178,6 +196,24 @@ 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>
......
......@@ -171,4 +171,16 @@
<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
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");
}
}
}
......@@ -9,7 +9,7 @@
namespace System.Runtime.Analyzers.UnitTests
{
[WorkItem(858659, "DevDiv")]
public partial class OverrideMethodsOnComparableTypesTests : DiagnosticAnalyzerTestBase
public partial class OverrideMethodsOnComparableTypesTests : CodeFixTestBase
{
protected override DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
{
......
......@@ -101,6 +101,7 @@
<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>
......
......@@ -72,6 +72,7 @@
</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" />
......
' 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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册