From 21b4b7cd8ac1281864c5d88e2afeb9e31e9a07aa Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Tue, 27 Oct 2020 17:35:17 -0700 Subject: [PATCH] Move language-specific functionality to derived types --- .../CSharp/CSharpDoNotCopyValue.cs | 49 ++++++++++++++++ ...CopyValue.cs => AbstractDoNotCopyValue.cs} | 58 ++++++++----------- .../Roslyn.Diagnostics.Analyzers.sarif | 52 +++++++++++------ .../UnitTests/DoNotCopyValueTests.cs | 40 ++++++------- .../VisualBasic/VisualBasicDoNotCopyValue.vb | 31 ++++++++++ 5 files changed, 157 insertions(+), 73 deletions(-) create mode 100644 src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotCopyValue.cs rename src/Roslyn.Diagnostics.Analyzers/Core/{DoNotCopyValue.cs => AbstractDoNotCopyValue.cs} (96%) create mode 100644 src/Roslyn.Diagnostics.Analyzers/VisualBasic/VisualBasicDoNotCopyValue.vb diff --git a/src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotCopyValue.cs b/src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotCopyValue.cs new file mode 100644 index 0000000000..ddc6ca8d60 --- /dev/null +++ b/src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpDoNotCopyValue.cs @@ -0,0 +1,49 @@ +// 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.CodeAnalysis; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Operations; +using Roslyn.Diagnostics.Analyzers; + +namespace Roslyn.Diagnostics.CSharp.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public sealed class CSharpDoNotCopyValue : AbstractDoNotCopyValue + { + protected override NonCopyableWalker CreateWalker(OperationBlockAnalysisContext context, NonCopyableTypesCache cache) + => new CSharpNonCopyableWalker(context, cache); + + private sealed class CSharpNonCopyableWalker : NonCopyableWalker + { + public CSharpNonCopyableWalker(OperationBlockAnalysisContext context, NonCopyableTypesCache cache) + : base(context, cache) + { + } + + protected override bool CheckForEachGetEnumerator(IForEachLoopOperation operation, [DisallowNull] ref IConversionOperation? conversion, [DisallowNull] ref IOperation? instance) + { + if (operation.Syntax is CommonForEachStatementSyntax syntax + && operation.SemanticModel.GetForEachStatementInfo(syntax).GetEnumeratorMethod is { } getEnumeratorMethod) + { + CheckMethodSymbolInUnsupportedContext(operation, getEnumeratorMethod); + + if (instance is not null + && Cache.IsNonCopyableType(getEnumeratorMethod.ReceiverType) + && !getEnumeratorMethod.IsReadOnly + && Acquire(instance) == RefKind.In) + { + // mark the instance as not checked by this method + instance = null; + } + + return true; + } + + return false; + } + } + } +} diff --git a/src/Roslyn.Diagnostics.Analyzers/Core/DoNotCopyValue.cs b/src/Roslyn.Diagnostics.Analyzers/Core/AbstractDoNotCopyValue.cs similarity index 96% rename from src/Roslyn.Diagnostics.Analyzers/Core/DoNotCopyValue.cs rename to src/Roslyn.Diagnostics.Analyzers/Core/AbstractDoNotCopyValue.cs index 29a9933cab..88bad32987 100644 --- a/src/Roslyn.Diagnostics.Analyzers/Core/DoNotCopyValue.cs +++ b/src/Roslyn.Diagnostics.Analyzers/Core/AbstractDoNotCopyValue.cs @@ -9,16 +9,13 @@ using Analyzer.Utilities; using Analyzer.Utilities.Extensions; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.FlowAnalysis; using Microsoft.CodeAnalysis.Operations; namespace Roslyn.Diagnostics.Analyzers { - [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] - public sealed class DoNotCopyValue : DiagnosticAnalyzer + public abstract class AbstractDoNotCopyValue : DiagnosticAnalyzer { private static readonly LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(RoslynDiagnosticsAnalyzersResources.DoNotCopyValueTitle), RoslynDiagnosticsAnalyzersResources.ResourceManager, typeof(RoslynDiagnosticsAnalyzersResources)); private static readonly LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(RoslynDiagnosticsAnalyzersResources.DoNotCopyValueMessage), RoslynDiagnosticsAnalyzersResources.ResourceManager, typeof(RoslynDiagnosticsAnalyzersResources)); @@ -93,6 +90,8 @@ public sealed class DoNotCopyValue : DiagnosticAnalyzer public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule, UnsupportedUseRule, NoBoxingRule, NoUnboxingRule); + protected abstract NonCopyableWalker CreateWalker(OperationBlockAnalysisContext context, NonCopyableTypesCache cache); + public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); @@ -105,9 +104,9 @@ public override void Initialize(AnalysisContext context) }); } - private static void AnalyzeOperationBlock(OperationBlockAnalysisContext context, NonCopyableTypesCache cache) + private void AnalyzeOperationBlock(OperationBlockAnalysisContext context, NonCopyableTypesCache cache) { - var walker = new NonCopyableWalker(context, cache); + var walker = CreateWalker(context, cache); foreach (var operation in context.OperationBlocks) { walker.Visit(operation); @@ -149,18 +148,21 @@ public void Dispose() } } - private sealed class NonCopyableWalker : OperationWalker + protected abstract class NonCopyableWalker : OperationWalker { private readonly OperationBlockAnalysisContext _context; - private readonly NonCopyableTypesCache _cache; private readonly HashSet _handledOperations = new HashSet(); - public NonCopyableWalker(OperationBlockAnalysisContext context, NonCopyableTypesCache cache) + protected NonCopyableWalker(OperationBlockAnalysisContext context, NonCopyableTypesCache cache) { _context = context; - _cache = cache; + Cache = cache; } + protected NonCopyableTypesCache Cache { get; } + + protected abstract bool CheckForEachGetEnumerator(IForEachLoopOperation operation, [DisallowNull] ref IConversionOperation? conversion, [DisallowNull] ref IOperation? instance); + public override void VisitAddressOf(IAddressOfOperation operation) { CheckTypeInUnsupportedContext(operation); @@ -222,11 +224,11 @@ public override void VisitAwait(IAwaitOperation operation) { // Treat await of ValueTask the same way handling of a return if (operation.Type is { } type - && _cache.IsNonCopyableType(type) + && Cache.IsNonCopyableType(type) && operation.Operation.Type is INamedTypeSymbol { OriginalDefinition: var taskType }) { - if (!SymbolEqualityComparer.Default.Equals(taskType, _cache.ValueTaskT) - && !SymbolEqualityComparer.Default.Equals(taskType, _cache.ConfiguredValueTaskAwaitableT)) + if (!SymbolEqualityComparer.Default.Equals(taskType, Cache.ValueTaskT) + && !SymbolEqualityComparer.Default.Equals(taskType, Cache.ConfiguredValueTaskAwaitableT)) { CheckTypeInUnsupportedContext(operation); } @@ -566,21 +568,7 @@ public override void VisitForEachLoop(IForEachLoopOperation operation) else { // Treat this as an invocation of the GetEnumerator method. - if (operation.Syntax is CommonForEachStatementSyntax syntax - && operation.SemanticModel.GetForEachStatementInfo(syntax).GetEnumeratorMethod is { } getEnumeratorMethod) - { - CheckMethodSymbolInUnsupportedContext(operation, getEnumeratorMethod); - - if (instance2 is not null - && _cache.IsNonCopyableType(getEnumeratorMethod.ReceiverType) - && !getEnumeratorMethod.IsReadOnly - && Acquire(instance) == RefKind.In) - { - // mark the instance as not checked by this method - instance2 = null; - } - } - else + if (!CheckForEachGetEnumerator(operation, ref instance, ref instance2)) { // Not supported instance = null; @@ -669,7 +657,7 @@ public override void VisitInvocation(IInvocationOperation operation) var instance = operation.Instance; if (instance is object - && _cache.IsNonCopyableType(operation.TargetMethod.ReceiverType) + && Cache.IsNonCopyableType(operation.TargetMethod.ReceiverType) && !operation.TargetMethod.IsReadOnly && Acquire(instance) == RefKind.In) { @@ -837,7 +825,7 @@ public override void VisitPropertyReference(IPropertyReferenceOperation operatio var instance = operation.Instance; if (instance is object - && _cache.IsNonCopyableType(operation.Property.ContainingType) + && Cache.IsNonCopyableType(operation.Property.ContainingType) && Acquire(instance) == RefKind.In) { if (operation.IsSetMethodInvocation()) @@ -1144,7 +1132,7 @@ private static bool CanAssign(RefKind sourceRefKind, RefKind targetRefKind) }; } - private RefKind Acquire(IOperation? operation) + protected RefKind Acquire(IOperation? operation) { if (operation is null) return RefKind.RefReadOnly; @@ -1338,7 +1326,7 @@ private void CheckTypeSymbolInUnsupportedContext(IOperation operation, ITypeSymb if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { var nullableUnderlyingType = ((INamedTypeSymbol)type).TypeArguments.FirstOrDefault(); - if (_cache.IsNonCopyableType(nullableUnderlyingType)) + if (Cache.IsNonCopyableType(nullableUnderlyingType)) { _context.ReportDiagnostic(operation.Syntax.CreateDiagnostic(AvoidNullableWrapperRule, type, operation.Kind)); } @@ -1380,7 +1368,7 @@ private void CheckLocalSymbolInUnsupportedContext(IOperation operation, ILocalSy CheckTypeSymbolInUnsupportedContext(operation, local.Type); } - private void CheckMethodSymbolInUnsupportedContext(IOperation operation, IMethodSymbol? symbol) + protected void CheckMethodSymbolInUnsupportedContext(IOperation operation, IMethodSymbol? symbol) { if (symbol is null) return; @@ -1424,7 +1412,7 @@ private void CheckTypeInUnsupportedContext(IOperation operation) return; } - if (!_cache.IsNonCopyableType(symbol)) + if (!Cache.IsNonCopyableType(symbol)) { // Copies of this type are allowed return; @@ -1434,7 +1422,7 @@ private void CheckTypeInUnsupportedContext(IOperation operation) } } - private sealed class NonCopyableTypesCache + protected sealed class NonCopyableTypesCache { private readonly ConcurrentDictionary _typesToNonCopyable = new ConcurrentDictionary(); diff --git a/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.sarif b/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.sarif index a50e93335c..4785c916d2 100644 --- a/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.sarif +++ b/src/Roslyn.Diagnostics.Analyzers/Roslyn.Diagnostics.Analyzers.sarif @@ -134,24 +134,6 @@ ] } }, - "RS0042": { - "id": "RS0042", - "shortDescription": "Do not copy value", - "fullDescription": "Do not unbox non-copyable value types.", - "defaultLevel": "warning", - "properties": { - "category": "RoslynDiagnosticsReliability", - "isEnabledByDefault": true, - "typeName": "DoNotCopyValue", - "languages": [ - "C#", - "Visual Basic" - ], - "tags": [ - "Telemetry" - ] - } - }, "RS0043": { "id": "RS0043", "shortDescription": "Do not call 'GetTestAccessor()'", @@ -248,6 +230,23 @@ ] } }, + "RS0042": { + "id": "RS0042", + "shortDescription": "Do not copy value", + "fullDescription": "Do not unbox non-copyable value types.", + "defaultLevel": "warning", + "properties": { + "category": "RoslynDiagnosticsReliability", + "isEnabledByDefault": true, + "typeName": "CSharpDoNotCopyValue", + "languages": [ + "C#" + ], + "tags": [ + "Telemetry" + ] + } + }, "RS0046": { "id": "RS0046", "shortDescription": "Avoid the 'Opt' suffix", @@ -394,6 +393,23 @@ ] } }, + "RS0042": { + "id": "RS0042", + "shortDescription": "Do not copy value", + "fullDescription": "Do not unbox non-copyable value types.", + "defaultLevel": "warning", + "properties": { + "category": "RoslynDiagnosticsReliability", + "isEnabledByDefault": true, + "typeName": "VisualBasicDoNotCopyValue", + "languages": [ + "Visual Basic" + ], + "tags": [ + "Telemetry" + ] + } + }, "RS0101": { "id": "RS0101", "shortDescription": "Avoid multiple blank lines", diff --git a/src/Roslyn.Diagnostics.Analyzers/UnitTests/DoNotCopyValueTests.cs b/src/Roslyn.Diagnostics.Analyzers/UnitTests/DoNotCopyValueTests.cs index 378ce78db8..09a5a728ac 100644 --- a/src/Roslyn.Diagnostics.Analyzers/UnitTests/DoNotCopyValueTests.cs +++ b/src/Roslyn.Diagnostics.Analyzers/UnitTests/DoNotCopyValueTests.cs @@ -6,10 +6,10 @@ using Microsoft.CodeAnalysis.Testing; using Xunit; using VerifyCS = Test.Utilities.CSharpSecurityCodeFixVerifier< - Roslyn.Diagnostics.Analyzers.DoNotCopyValue, + Roslyn.Diagnostics.CSharp.Analyzers.CSharpDoNotCopyValue, Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; using VerifyVB = Test.Utilities.VisualBasicSecurityCodeFixVerifier< - Roslyn.Diagnostics.Analyzers.DoNotCopyValue, + Roslyn.Diagnostics.VisualBasic.Analyzers.VisualBasicDoNotCopyValue, Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; namespace Roslyn.Diagnostics.Analyzers.UnitTests @@ -91,7 +91,7 @@ async Task M({csharpAwaitableType} task) }} ", // /0/Test0.cs(10,21): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'Await' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "Await")); + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "Await")); await VerifyVB.VerifyAnalyzerAsync($@" Imports System.Runtime.CompilerServices @@ -104,7 +104,7 @@ Async Function M(task as {visualBasicAwaitableType}) As Task End Function End Class", // /0/Test0.vb(8,21): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'Await' operation - VerifyVB.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "Await")); + VerifyVB.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "Await")); } [Theory] @@ -198,7 +198,7 @@ void M() } ", // /0/Test0.cs(8,21): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'Invocation' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "Invocation")); + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "Invocation")); } [Fact] @@ -232,9 +232,9 @@ void M() } ", // /0/Test0.cs(23,13): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'FieldReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), // /0/Test0.cs(17,13): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'LocalReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(1).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference")); + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(1).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference")); } [Fact] @@ -268,9 +268,9 @@ void M() } ", // /0/Test0.cs(23,13): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'FieldReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), // /0/Test0.cs(17,13): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'LocalReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(1).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference")); + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(1).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference")); } [Fact] @@ -324,19 +324,19 @@ public static void XIn(this in GCHandle handle) { } } ", // /0/Test0.cs(31,9): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'FieldReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), // /0/Test0.cs(32,9): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'LocalReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(1).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference"), + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(1).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference"), // /0/Test0.cs(33,9): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'FieldReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(2).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(2).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), // /0/Test0.cs(34,9): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'FieldReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(3).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(3).WithArguments("System.Runtime.InteropServices.GCHandle", "FieldReference"), // /0/Test0.cs(35,9): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'LocalReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(4).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference"), + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(4).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference"), // /0/Test0.cs(36,9): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'LocalReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(5).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference"), + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(5).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference"), // /0/Test0.cs(37,9): warning RS0042: Unsupported use of non-copyable type 'System.Runtime.InteropServices.GCHandle' in 'LocalReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(6).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference")); + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(6).WithArguments("System.Runtime.InteropServices.GCHandle", "LocalReference")); } [Theory] @@ -558,7 +558,7 @@ internal sealed class NonCopyableAttribute : System.Attribute { } // non-copyable field. // // /0/Test0.cs(42,16): warning RS0042: Unsupported use of non-copyable type 'CannotCopy' in 'FieldReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("CannotCopy", "FieldReference"), + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("CannotCopy", "FieldReference"), }, LanguageVersion = Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8, }.RunAsync(); @@ -723,7 +723,7 @@ internal sealed class NonCopyableAttribute : System.Attribute {{ }} var expected = (parameterModifiers, getEnumeratorModifiers) switch { // /0/Test0.cs(8,29): warning RS0042: Unsupported use of non-copyable type 'CannotCopy' in 'ParameterReference' operation - ("in", "") => new[] { VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("CannotCopy", "ParameterReference") }, + ("in", "") => new[] { VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("CannotCopy", "ParameterReference") }, _ => DiagnosticResult.EmptyDiagnosticResults, }; @@ -848,7 +848,7 @@ struct CannotCopy internal sealed class NonCopyableAttribute : System.Attribute { } ", // /0/Test0.cs(12,16): warning RS0042: Unsupported use of non-copyable type 'CannotCopy' in 'FieldReference' operation - VerifyCS.Diagnostic(DoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("CannotCopy", "FieldReference")); + VerifyCS.Diagnostic(AbstractDoNotCopyValue.UnsupportedUseRule).WithLocation(0).WithArguments("CannotCopy", "FieldReference")); } [Fact] @@ -863,7 +863,7 @@ class C } ", // /0/Test0.cs(6,21): warning RS0042: Do not wrap non-copyable type 'System.Runtime.InteropServices.GCHandle?' in 'FieldInitializer' operation - VerifyCS.Diagnostic(DoNotCopyValue.AvoidNullableWrapperRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle?", "FieldInitializer")); + VerifyCS.Diagnostic(AbstractDoNotCopyValue.AvoidNullableWrapperRule).WithLocation(0).WithArguments("System.Runtime.InteropServices.GCHandle?", "FieldInitializer")); } } } diff --git a/src/Roslyn.Diagnostics.Analyzers/VisualBasic/VisualBasicDoNotCopyValue.vb b/src/Roslyn.Diagnostics.Analyzers/VisualBasic/VisualBasicDoNotCopyValue.vb new file mode 100644 index 0000000000..e638f00188 --- /dev/null +++ b/src/Roslyn.Diagnostics.Analyzers/VisualBasic/VisualBasicDoNotCopyValue.vb @@ -0,0 +1,31 @@ +' 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.Diagnostics.CodeAnalysis +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Operations +Imports Roslyn.Diagnostics.Analyzers + +Namespace Roslyn.Diagnostics.VisualBasic.Analyzers + + Public NotInheritable Class VisualBasicDoNotCopyValue + Inherits AbstractDoNotCopyValue + + Protected Overrides Function CreateWalker(context As OperationBlockAnalysisContext, cache As NonCopyableTypesCache) As NonCopyableWalker + Return New VisualBasicNonCopyableWalker(context, cache) + End Function + + Private NotInheritable Class VisualBasicNonCopyableWalker + Inherits NonCopyableWalker + + Public Sub New(context As OperationBlockAnalysisContext, cache As NonCopyableTypesCache) + MyBase.New(context, cache) + End Sub + + Protected Overrides Function CheckForEachGetEnumerator(operation As IForEachLoopOperation, ByRef conversion As IConversionOperation, ByRef instance As IOperation) As Boolean + ' Not supported (yet) + Return False + End Function + End Class + End Class +End Namespace