提交 c1c54cc9 编写于 作者: M Manish Vasani

Address PR feedback

上级 76f4c480
......@@ -2,14 +2,14 @@
using System.Collections.Generic;
using System.Composition;
using Microsoft.CodeAnalysis.AvoidUnusedMembers;
using Microsoft.CodeAnalysis.RemoveUnusedMembers;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Microsoft.CodeAnalysis.CSharp.AvoidUnusedMembers
namespace Microsoft.CodeAnalysis.CSharp.RemoveUnusedMembers
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.AvoidUnusedMembers), Shared]
internal class CSharpAvoidUnusedMembersCodeFixProvider : AbstractAvoidUnusedMembersCodeFixProvider<FieldDeclarationSyntax>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.RemoveUnusedMembers), Shared]
internal class CSharpRemoveUnusedMembersCodeFixProvider : AbstractRemoveUnusedMembersCodeFixProvider<FieldDeclarationSyntax>
{
protected override void AdjustDeclarators(HashSet<FieldDeclarationSyntax> fieldDeclarators, HashSet<SyntaxNode> declarators)
{
......
// 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.RemoveUnusedMembers;
namespace Microsoft.CodeAnalysis.CSharp.RemoveUnusedMembers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class CSharpRemoveUnusedMembersDiagnosticAnalyzer : AbstractRemoveUnusedMembersDiagnosticAnalyzer
{
}
}
......@@ -12,7 +12,6 @@ internal static class PredefinedCodeFixProviderNames
public const string AliasAmbiguousType = nameof(AliasAmbiguousType);
public const string ApplyNamingStyle = nameof(ApplyNamingStyle);
public const string AddBraces = nameof(AddBraces);
public const string AvoidUnusedMembers = nameof(AvoidUnusedMembers);
public const string ChangeReturnType = nameof(ChangeReturnType);
public const string ChangeToYield = nameof(ChangeToYield);
public const string ConvertToAsync = nameof(ConvertToAsync);
......@@ -44,6 +43,7 @@ internal static class PredefinedCodeFixProviderNames
public const string RemoveUnnecessaryImports = nameof(RemoveUnnecessaryImports);
public const string RemoveUnreachableCode = nameof(RemoveUnreachableCode);
public const string RemoveUnusedLocalFunction = nameof(RemoveUnusedLocalFunction);
public const string RemoveUnusedMembers = nameof(RemoveUnusedMembers);
public const string RemoveUnusedVariable = nameof(RemoveUnusedVariable);
public const string RenameTracking = nameof(RenameTracking);
public const string SimplifyNames = nameof(SimplifyNames);
......
......@@ -79,7 +79,7 @@ internal static class IDEDiagnosticIds
public const string ConvertAnonymousTypeToTupleDiagnosticId = "IDE0050";
public const string AvoidUnusedMembersDiagnosticId = "IDE0051";
public const string RemoveUnusedMembersDiagnosticId = "IDE0051";
// Analyzer error Ids
public const string AnalyzerChangedId = "IDE1001";
......
......@@ -630,33 +630,6 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Type &apos;{0}&apos; has a private member &apos;{1}&apos; which can be removed as the value assigned to it is never used..
/// </summary>
internal static string Avoid_Members_Without_Reads_Message {
get {
return ResourceManager.GetString("Avoid_Members_Without_Reads_Message", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type &apos;{0}&apos; has an unused private member &apos;{1}&apos; which can be removed..
/// </summary>
internal static string Avoid_Unused_Members_Message {
get {
return ResourceManager.GetString("Avoid_Unused_Members_Message", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Avoid unused private members..
/// </summary>
internal static string Avoid_Unused_Members_Title {
get {
return ResourceManager.GetString("Avoid_Unused_Members_Title", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Awaited task returns.
/// </summary>
......@@ -2823,6 +2796,24 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Remove unused private members.
/// </summary>
internal static string Remove_Unused_Private_Members {
get {
return ResourceManager.GetString("Remove_Unused_Private_Members", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type &apos;{0}&apos; has a private member &apos;{1}&apos; which can be removed as it is either never used or the value assigned to it is never used..
/// </summary>
internal static string Remove_Unused_Private_Members_Message {
get {
return ResourceManager.GetString("Remove_Unused_Private_Members_Message", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Remove unused variable.
/// </summary>
......
......@@ -1409,13 +1409,10 @@ This version used in: {2}</value>
<data name="Remove_unused_member" xml:space="preserve">
<value>Remove unused member</value>
</data>
<data name="Avoid_Unused_Members_Message" xml:space="preserve">
<value>Type '{0}' has an unused private member '{1}' which can be removed.</value>
<data name="Remove_Unused_Private_Members_Message" xml:space="preserve">
<value>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</value>
</data>
<data name="Avoid_Unused_Members_Title" xml:space="preserve">
<value>Avoid unused private members.</value>
</data>
<data name="Avoid_Members_Without_Reads_Message" xml:space="preserve">
<value>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</value>
<data name="Remove_Unused_Private_Members" xml:space="preserve">
<value>Remove unused private members</value>
</data>
</root>
\ No newline at end of file
......@@ -34,8 +34,10 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
return Task.CompletedTask;
}
private async Task FixWithEditorAsync(
Document document, SyntaxEditor editor, ImmutableArray<Diagnostic> diagnostics,
protected override async Task FixAllAsync(
Document document,
ImmutableArray<Diagnostic> diagnostics,
SyntaxEditor editor,
CancellationToken cancellationToken)
{
var declarators = new List<TSymbolSyntax>();
......@@ -90,15 +92,6 @@ private async Task MakeFieldReadonlyAsync(Document document, SyntaxEditor editor
}
}
protected override Task FixAllAsync(
Document document,
ImmutableArray<Diagnostic> diagnostics,
SyntaxEditor editor,
CancellationToken cancellationToken)
{
return FixWithEditorAsync(document, editor, diagnostics, cancellationToken);
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument) :
......
......@@ -155,7 +155,7 @@ private static bool IsFieldWrite(IFieldReferenceOperation fieldReference, ISymbo
{
// Check if the underlying member is being written or a writable reference to the member is taken.
var valueUsageInfo = fieldReference.GetValueUsageInfo();
if ((valueUsageInfo & (ValueUsageInfo.Write | ValueUsageInfo.WritableRef)) == 0)
if (!valueUsageInfo.ContainsWriteOrWritableRef())
{
return false;
}
......@@ -174,7 +174,7 @@ private static bool IsFieldWrite(IFieldReferenceOperation fieldReference, ISymbo
// For instance fields, ensure that the instance reference is being initialized by the constructor.
var instanceFieldWrittenInCtor = isInConstructor &&
fieldReference.Instance?.Kind == OperationKind.InstanceReference &&
(!(fieldReference.Parent is IAssignmentOperation) || fieldReference.Parent.Parent?.Kind != OperationKind.ObjectOrCollectionInitializer);
!fieldReference.IsTargetOfObjectMemberInitializer();
// For static fields, ensure that we are in the static constructor.
var staticFieldWrittenInStaticCtor = isInStaticConstructor && field.IsStatic;
......@@ -214,7 +214,7 @@ private static bool IsInAnonymousFunctionOrLocalFunction(IOperation operation)
private static CodeStyleOption<bool> GetCodeStyleOption(IFieldSymbol field, AnalyzerOptions options, CancellationToken cancellationToken)
{
var optionSet = options.GetDocumentOptionSetAsync(field.Locations[0].SourceTree, cancellationToken).GetAwaiter().GetResult();
return optionSet?.GetOption(CodeStyleOptions.AvoidUnusedMembers, field.Language);
return optionSet?.GetOption(CodeStyleOptions.RemoveUnusedMembers, field.Language);
}
private static bool IsMutableValueType(ITypeSymbol type)
......
......@@ -4,21 +4,24 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AvoidUnusedMembers
namespace Microsoft.CodeAnalysis.RemoveUnusedMembers
{
internal abstract class AbstractAvoidUnusedMembersCodeFixProvider<TFieldDeclarationSyntax> : SyntaxEditorBasedCodeFixProvider
internal abstract class AbstractRemoveUnusedMembersCodeFixProvider<TFieldDeclarationSyntax> : SyntaxEditorBasedCodeFixProvider
where TFieldDeclarationSyntax : SyntaxNode
{
public override ImmutableArray<string> FixableDiagnosticIds
=> ImmutableArray.Create(IDEDiagnosticIds.AvoidUnusedMembersDiagnosticId);
=> ImmutableArray.Create(IDEDiagnosticIds.RemoveUnusedMembersDiagnosticId);
// Adjust declarators to remove based on whether or not all variable declarators within a field declaration should be removed.
protected abstract void AdjustDeclarators(HashSet<TFieldDeclarationSyntax> fieldDeclarators, HashSet<SyntaxNode> declarators);
......@@ -31,18 +34,11 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
return Task.CompletedTask;
}
protected override Task FixAllAsync(
protected override async Task FixAllAsync(
Document document,
ImmutableArray<Diagnostic> diagnostics,
SyntaxEditor editor,
CancellationToken cancellationToken)
{
return FixWithEditorAsync(document, editor, diagnostics, cancellationToken);
}
private async Task FixWithEditorAsync(
Document document, SyntaxEditor editor, ImmutableArray<Diagnostic> diagnostics,
CancellationToken cancellationToken)
{
var declarators = new HashSet<SyntaxNode>();
var fieldDeclarators = new HashSet<TFieldDeclarationSyntax>();
......@@ -51,27 +47,37 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
foreach (var diagnostic in diagnostics)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var diagnosticSpan = diagnostic.Location.SourceSpan;
var symbolName = diagnostic.Properties[AvoidUnusedMembersDiagnosticAnalyzer.UnunsedMemberNameProperty];
var symbolKind = diagnostic.Properties[AvoidUnusedMembersDiagnosticAnalyzer.UnunsedMemberKindProperty];
var node = GetTopmostSyntaxNodeForSymbolDeclaration(root.FindNode(diagnosticSpan),
isSymbolDeclarationNode: n => n != null && semanticModel.GetDeclaredSymbol(n, cancellationToken)?.Name == symbolName);
// Get symbol to be removed.
var diagnosticNode = diagnostic.Location.FindNode(getInnermostNodeForTie: true, cancellationToken);
var symbol = semanticModel.GetDeclaredSymbol(diagnosticNode, cancellationToken);
Debug.Assert(symbol != null);
declarators.Add(node);
if (symbolKind == nameof(SymbolKind.Field))
// Get symbol declarations to be removed.
var declarationService = document.GetLanguageService<ISymbolDeclarationService>();
foreach (var declReference in declarationService.GetDeclarations(symbol))
{
var fieldDeclarator = node.FirstAncestorOrSelf<TFieldDeclarationSyntax>();
fieldDeclarators.Add(fieldDeclarator);
var node = await declReference.GetSyntaxAsync(cancellationToken).ConfigureAwait(false);
declarators.Add(node);
// For fields, the declaration node is the variable declarator.
// We also track the ancestor FieldDeclarationSyntax which may declare more then one field.
if (symbol.Kind == SymbolKind.Field)
{
var fieldDeclarator = node.FirstAncestorOrSelf<TFieldDeclarationSyntax>();
fieldDeclarators.Add(fieldDeclarator);
}
}
}
// If all the fields declared within a field declaration are unused,
// we can remove the entire field declaration instead of individual variable declarators.
if (fieldDeclarators.Count > 0)
{
AdjustDeclarators(fieldDeclarators, declarators);
}
// Remove all the symbol declarator nodes.
foreach (var declarator in declarators)
{
editor.RemoveNode(declarator);
......@@ -83,9 +89,18 @@ protected virtual SyntaxNode GetTopmostSyntaxNodeForSymbolDeclaration(SyntaxNode
return syntaxNode.FirstAncestorOrSelf(isSymbolDeclarationNode);
}
/// <summary>
/// If all the <paramref name="childDeclarators"/> are contained in <paramref name="declarators"/>,
/// the removes the <paramref name="childDeclarators"/> from <paramref name="declarators"/>, and
/// adds the <paramref name="parentDeclaration"/> to the <paramref name="declarators"/>.
/// </summary>
protected void AdjustChildDeclarators(SyntaxNode parentDeclaration, IEnumerable<SyntaxNode> childDeclarators, HashSet<SyntaxNode> declarators)
{
Debug.Assert(!declarators.Contains(parentDeclaration));
if(declarators.Contains(parentDeclaration))
{
Debug.Assert(childDeclarators.All(c => !declarators.Contains(c)));
return;
}
var declaratorsContainsAllChildren = true;
foreach (var childDeclarator in childDeclarators)
......
// 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.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.RemoveUnusedMembers
{
internal abstract class AbstractRemoveUnusedMembersDiagnosticAnalyzer
: AbstractCodeStyleDiagnosticAnalyzer
{
private readonly bool _treatCompoundAssignmentAsWriteOnlyOperation;
public AbstractRemoveUnusedMembersDiagnosticAnalyzer(bool treatCompoundAssignmentAsWriteOnlyOperation = false)
: base(
IDEDiagnosticIds.RemoveUnusedMembersDiagnosticId,
new LocalizableResourceString(nameof(FeaturesResources.Remove_Unused_Private_Members), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
new LocalizableResourceString(nameof(FeaturesResources.Remove_Unused_Private_Members_Message), FeaturesResources.ResourceManager, typeof(FeaturesResources)))
{
_treatCompoundAssignmentAsWriteOnlyOperation = treatCompoundAssignmentAsWriteOnlyOperation;
}
public override bool OpenFileOnly(Workspace workspace) => false;
// We need to analyze the whole document even for edits within a method body.
public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticDocumentAnalysis;
protected override void InitializeWorker(AnalysisContext context)
{
// We want to analyze references in generated code, but not report unused members in generated code.
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze);
context.RegisterCompilationStartAction(compilationStartContext =>
{
var compilationAnalyzer = new CompilationAnalyzer(compilationStartContext.Compilation, UnnecessaryWithSuggestionDescriptor, _treatCompoundAssignmentAsWriteOnlyOperation);
// We register following actions in the compilation:
// 1. A symbol action for member symbols to ensure the member's unused state is initialized to true for every private member symbol.
// 2. Operation actions for member references and invocations to detect member usages, i.e. read or read reference taken.
// 3. A symbol start/end action for named types to report diagnostics for candidate members that have no usage in executable code.
//
// Note that we need to register separately for OperationKind.Invocation due to https://github.com/dotnet/roslyn/issues/26206
compilationStartContext.RegisterSymbolAction(compilationAnalyzer.AnalyzeSymbolDeclaration, SymbolKind.Method, SymbolKind.Field, SymbolKind.Property, SymbolKind.Event);
compilationStartContext.RegisterSymbolStartAction(symbolStartContext =>
{
symbolStartContext.RegisterOperationAction(compilationAnalyzer.AnalyzeMemberReferenceOperation, OperationKind.FieldReference, OperationKind.MethodReference, OperationKind.PropertyReference, OperationKind.EventReference);
symbolStartContext.RegisterOperationAction(compilationAnalyzer.AnalyzeInvocationOperation, OperationKind.Invocation);
symbolStartContext.RegisterSymbolEndAction(compilationAnalyzer.OnSymbolEnd);
}, SymbolKind.NamedType);
});
}
private sealed class CompilationAnalyzer
{
private readonly DiagnosticDescriptor _rule;
private readonly bool _treatCompoundAssignmentAsWriteOnlyOperation;
private readonly object _gate;
private readonly Dictionary<ISymbol, ValueUsageInfo> _symbolValueUsageStateMap;
private readonly Lazy<INamedTypeSymbol> _lazyTaskType, _lazyGenericTaskType;
public CompilationAnalyzer(Compilation compilation, DiagnosticDescriptor rule, bool treatCompoundAssignmentAsWriteOnlyOperation)
{
_rule = rule;
_treatCompoundAssignmentAsWriteOnlyOperation = treatCompoundAssignmentAsWriteOnlyOperation;
_gate = new object();
// State map for candidate member symbols, with the value indicating how each symbol is used in executable code.
_symbolValueUsageStateMap = new Dictionary<ISymbol, ValueUsageInfo>();
_lazyTaskType = new Lazy<INamedTypeSymbol>(() => compilation.TaskType());
_lazyGenericTaskType = new Lazy<INamedTypeSymbol>(() => compilation.TaskOfTType());
}
public void AnalyzeSymbolDeclaration(SymbolAnalysisContext symbolContext)
{
if (IsCandidateSymbol(symbolContext.Symbol))
{
lock (_gate)
{
// Initialize unused state to 'true'.
// Note that we might receive a symbol reference (AnalyzeMemberOperation) callback before
// this symbol declaration callback, so even though we cannot receive duplicate callbacks for a symbol,
// an entry might already be present of the declared symbol here.
if (!_symbolValueUsageStateMap.ContainsKey(symbolContext.Symbol))
{
_symbolValueUsageStateMap.Add(symbolContext.Symbol, ValueUsageInfo.None);
}
}
}
}
private void OnSymbolUsage(ISymbol memberSymbol, ValueUsageInfo usageInfo)
{
Debug.Assert(IsCandidateSymbol(memberSymbol));
lock (_gate)
{
// Update the usage info for the memberSymbol
if (_symbolValueUsageStateMap.TryGetValue(memberSymbol, out var currentUsageInfo))
{
usageInfo = currentUsageInfo | usageInfo;
}
_symbolValueUsageStateMap[memberSymbol] = usageInfo;
}
}
private bool TryRemove(ISymbol memberSymbol, out ValueUsageInfo valueUsageInfo)
{
lock (_gate)
{
if (_symbolValueUsageStateMap.TryGetValue(memberSymbol, out valueUsageInfo))
{
_symbolValueUsageStateMap.Remove(memberSymbol);
return true;
}
return false;
}
}
public void AnalyzeMemberReferenceOperation(OperationAnalysisContext operationContext)
{
var memberReference = (IMemberReferenceOperation)operationContext.Operation;
if (IsCandidateSymbol(memberReference.Member))
{
// Get the value usage info.
var valueUsageInfo = memberReference.GetValueUsageInfo();
// Usages which are neither value read nor value write (e.g. in nameof, typeof, sizeof)
// are treated as a read to avoid flagging them.
// https://github.com/dotnet/roslyn/issues/29519 covers improving this behavior.
if (valueUsageInfo == ValueUsageInfo.None)
{
valueUsageInfo = ValueUsageInfo.Read;
}
// Is this a compound assignment that must be treated as a write-only usage?
if (_treatCompoundAssignmentAsWriteOnlyOperation &&
memberReference.Parent is ICompoundAssignmentOperation compoundAssignment &&
compoundAssignment.Target == memberReference)
{
valueUsageInfo = ValueUsageInfo.Write;
}
OnSymbolUsage(memberReference.Member, valueUsageInfo);
}
}
public void AnalyzeInvocationOperation(OperationAnalysisContext operationContext)
{
var invocation = (IInvocationOperation)operationContext.Operation;
if (IsCandidateSymbol(invocation.TargetMethod))
{
OnSymbolUsage(invocation.TargetMethod, ValueUsageInfo.Read);
}
}
public void OnSymbolEnd(SymbolAnalysisContext symbolEndContext)
{
// Report diagnostics for unused candidate members.
var members = ((INamedTypeSymbol)symbolEndContext.Symbol).GetMembers();
foreach (var member in members)
{
// Check if the underlying member is neither read nor a readable reference to the member is taken.
if (TryRemove(member, out var valueUsageInfo) &&
!valueUsageInfo.ContainsReadOrReadableRef())
{
Debug.Assert(IsCandidateSymbol(member));
Debug.Assert(!member.IsImplicitlyDeclared);
var option = TryGetCodeStyleOption(member, symbolEndContext);
if (option != null && option.Value)
{
var diagnostic = DiagnosticHelper.Create(
_rule,
member.Locations[0],
option.Notification.Severity,
additionalLocations: member.Locations,
properties: null,
member.ContainingType.Name,
member.Name);
symbolEndContext.ReportDiagnostic(diagnostic);
}
}
}
}
private bool IsCandidateSymbol(ISymbol memberSymbol)
{
if (memberSymbol.DeclaredAccessibility == Accessibility.Private &&
!memberSymbol.IsImplicitlyDeclared)
{
// Do not track accessors, as we will track the associated symbol.
// Also skip entry point (Main) method
switch (memberSymbol.Kind)
{
case SymbolKind.Method:
var methodSymbol = (IMethodSymbol)memberSymbol;
return methodSymbol.AssociatedSymbol == null && !IsEntryPoint(methodSymbol);
case SymbolKind.Field:
return ((IFieldSymbol)memberSymbol).AssociatedSymbol == null;
default:
return true;
}
}
return false;
// Local functions.
bool IsEntryPoint(IMethodSymbol methodSymbol)
{
if (methodSymbol.Name != WellKnownMemberNames.EntryPointMethodName ||
!methodSymbol.IsStatic)
{
return false;
}
if (methodSymbol.ReturnsVoid)
{
return true;
}
if (methodSymbol.IsAsync &&
(methodSymbol.ReturnType.OriginalDefinition == _lazyTaskType.Value ||
methodSymbol.ReturnType.OriginalDefinition == _lazyGenericTaskType.Value))
{
return true;
}
return false;
}
}
private static CodeStyleOption<bool> TryGetCodeStyleOption(ISymbol memberSymbol, SymbolAnalysisContext symbolEndContext)
{
var optionSet = symbolEndContext.Options.GetDocumentOptionSetAsync(memberSymbol.Locations[0].SourceTree, symbolEndContext.CancellationToken).GetAwaiter().GetResult();
return optionSet?.GetOption(CodeStyleOptions.RemoveUnusedMembers, memberSymbol.Language);
}
}
}
}
// 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.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AvoidUnusedMembers
{
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
internal sealed class AvoidUnusedMembersDiagnosticAnalyzer
: AbstractCodeStyleDiagnosticAnalyzer
{
internal static string UnunsedMemberNameProperty = nameof(UnunsedMemberNameProperty);
internal static string UnunsedMemberKindProperty = nameof(UnunsedMemberKindProperty);
private readonly DiagnosticDescriptor _noReadsUnnecessaryWithSuggestionDescriptor;
public AvoidUnusedMembersDiagnosticAnalyzer()
: base(
IDEDiagnosticIds.AvoidUnusedMembersDiagnosticId,
new LocalizableResourceString(nameof(FeaturesResources.Avoid_Unused_Members_Title), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
new LocalizableResourceString(nameof(FeaturesResources.Avoid_Unused_Members_Message), FeaturesResources.ResourceManager, typeof(FeaturesResources)))
{
_noReadsUnnecessaryWithSuggestionDescriptor = new DiagnosticDescriptor(
UnnecessaryWithSuggestionDescriptor.Id,
UnnecessaryWithSuggestionDescriptor.Title,
new LocalizableResourceString(nameof(FeaturesResources.Avoid_Members_Without_Reads_Message), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
UnnecessaryWithSuggestionDescriptor.Category,
UnnecessaryWithSuggestionDescriptor.DefaultSeverity,
UnnecessaryWithSuggestionDescriptor.IsEnabledByDefault,
UnnecessaryWithSuggestionDescriptor.Description,
UnnecessaryWithSuggestionDescriptor.HelpLinkUri,
UnnecessaryWithSuggestionDescriptor.CustomTags.ToArray());
}
public override bool OpenFileOnly(Workspace workspace) => false;
public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticDocumentAnalysis;
protected override void InitializeWorker(AnalysisContext context)
{
context.EnableConcurrentExecution();
// We want to analyze references in generated code, but not report unused members in generated code.
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze);
context.RegisterCompilationStartAction(compilationStartContext =>
{
var entryPoint = compilationStartContext.Compilation.GetEntryPoint(compilationStartContext.CancellationToken);
// State map for candidate member symbols, with the value indicating how each symbol is used in executable code.
var symbolValueUsageStateMap = new ConcurrentDictionary<ISymbol, ValueUsageInfo>();
// We register following actions in the compilation:
// 1. A symbol action for member symbols to ensure the member's unused state is initialized to true for every private member symbol.
// 2. Operation actions for member references and invocations to detect member usages, i.e. read or read reference taken.
// 3. A symbol start/end action for named types to report diagnostics for candidate members that have no usage in executable code.
compilationStartContext.RegisterSymbolAction(AnalyzeSymbolDeclaration, SymbolKind.Method, SymbolKind.Field, SymbolKind.Property, SymbolKind.Event);
compilationStartContext.RegisterSymbolStartAction(symbolStartContext =>
{
symbolStartContext.RegisterOperationAction(AnalyzeMemberReferenceOperation, OperationKind.FieldReference, OperationKind.MethodReference, OperationKind.PropertyReference, OperationKind.EventReference);
symbolStartContext.RegisterOperationAction(AnalyzeInvocationOperation, OperationKind.Invocation);
symbolStartContext.RegisterSymbolEndAction(OnSymbolEnd);
}, SymbolKind.NamedType);
return;
// Local functions.
void AnalyzeSymbolDeclaration(SymbolAnalysisContext symbolContext)
{
if (IsCandidateSymbol(symbolContext.Symbol))
{
// Initialize unused state to 'true'.
symbolValueUsageStateMap.GetOrAdd(symbolContext.Symbol, valueFactory: s => ValueUsageInfo.None);
}
}
void OnSymbolUsage(ISymbol memberSymbol, ValueUsageInfo usageInfo)
{
Debug.Assert(IsCandidateSymbol(memberSymbol));
// Update the usage info for the memberSymbol
symbolValueUsageStateMap.AddOrUpdate(
memberSymbol,
addValue: usageInfo,
updateValueFactory: (sym, currentUsageInfo) => currentUsageInfo | usageInfo);
}
void AnalyzeMemberReferenceOperation(OperationAnalysisContext operationContext)
{
var memberReference = (IMemberReferenceOperation)operationContext.Operation;
if (IsCandidateSymbol(memberReference.Member))
{
// Get the value usage info.
var valueUsageInfo = memberReference.GetValueUsageInfo();
// Special case for VB
// Compound assigment is a statement in VB that does not return a value.
// So, we treat this usage as a write-only usage.
if (memberReference.Language == LanguageNames.VisualBasic &&
memberReference.Parent is ICompoundAssignmentOperation compoundAssignment &&
compoundAssignment.Target == memberReference)
{
valueUsageInfo = ValueUsageInfo.Write;
}
OnSymbolUsage(memberReference.Member, valueUsageInfo);
}
}
void AnalyzeInvocationOperation(OperationAnalysisContext operationContext)
{
var invocation = (IInvocationOperation)operationContext.Operation;
if (IsCandidateSymbol(invocation.TargetMethod))
{
OnSymbolUsage(invocation.TargetMethod, ValueUsageInfo.Read);
}
}
void OnSymbolEnd(SymbolAnalysisContext symbolEndContext)
{
// Report diagnostics for unused candidate members.
var members = ((INamedTypeSymbol)symbolEndContext.Symbol).GetMembers();
foreach (var member in members)
{
// Check if the underlying member is neither read nor a readable reference to the member is taken.
if (symbolValueUsageStateMap.TryRemove(member, out var valueUsageInfo) &&
(valueUsageInfo & (ValueUsageInfo.Read | ValueUsageInfo.ReadableRef)) == 0)
{
Debug.Assert(IsCandidateSymbol(member));
var option = GetCodeStyleOption(member, symbolEndContext);
if (option != null && option.Value)
{
// Give appropriate message based on usage:
// 1. No read or writes: Type '{0}' has an unused private member '{1}' which can be removed.
// 2. Only writes: Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.
var rule = (valueUsageInfo & (ValueUsageInfo.Write | ValueUsageInfo.WritableRef)) != 0 ?
_noReadsUnnecessaryWithSuggestionDescriptor :
UnnecessaryWithSuggestionDescriptor;
var additionalLocations = member.Locations.Skip(1).ToImmutableArrayOrEmpty();
var diagnostic = DiagnosticHelper.Create(
rule,
member.Locations[0],
option.Notification.Severity,
additionalLocations,
properties: ImmutableDictionary.CreateRange(new[] {
new KeyValuePair<string, string>(UnunsedMemberNameProperty, member.Name),
new KeyValuePair<string, string>(UnunsedMemberKindProperty, member.Kind.ToString()) }),
member.ContainingSymbol.Name,
member.Name);
symbolEndContext.ReportDiagnostic(diagnostic);
}
}
}
}
bool IsCandidateSymbol(ISymbol memberSymbol)
{
if (memberSymbol.DeclaredAccessibility == Accessibility.Private &&
!memberSymbol.IsImplicitlyDeclared)
{
// Do not track accessors, as we will track the associated symbol.
switch (memberSymbol.Kind)
{
case SymbolKind.Method:
return ((IMethodSymbol)memberSymbol).AssociatedSymbol == null &&
memberSymbol != entryPoint;
case SymbolKind.Field:
return ((IFieldSymbol)memberSymbol).AssociatedSymbol == null;
default:
return true;
}
}
return false;
}
CodeStyleOption<bool> GetCodeStyleOption(ISymbol memberSymbol, SymbolAnalysisContext symbolEndContext)
{
var optionSet = symbolEndContext.Options.GetDocumentOptionSetAsync(memberSymbol.Locations[0].SourceTree, symbolEndContext.CancellationToken).GetAwaiter().GetResult();
return optionSet?.GetOption(CodeStyleOptions.AvoidUnusedMembers, memberSymbol.Language);
}
});
}
}
}
......@@ -22,21 +22,6 @@
<target state="translated">Akce nemůžou zůstat prázdné.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">Aktionen dürfen nicht leer sein.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">Las acciones no pueden estar vacías.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">Les actions ne peuvent pas être vides.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">Il campo Azioni non può essere vuoto.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">アクションは空にできません。</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">작업은 비워 둘 수 없습니다.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">Akcje nie mogą być puste.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">Ações não podem ficar vazias.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">Действия не могут быть пустыми.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">Eylemler boş olamaz.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">操作不能为空。</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -22,21 +22,6 @@
<target state="translated">動作不可為空。</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Members_Without_Reads_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Message">
<source>Type '{0}' has an unused private member '{1}' which can be removed.</source>
<target state="new">Type '{0}' has an unused private member '{1}' which can be removed.</target>
<note />
</trans-unit>
<trans-unit id="Avoid_Unused_Members_Title">
<source>Avoid unused private members.</source>
<target state="new">Avoid unused private members.</target>
<note />
</trans-unit>
<trans-unit id="Convert_to_linq">
<source>Convert to LINQ</source>
<target state="new">Convert to LINQ</target>
......@@ -82,6 +67,16 @@
<target state="new">Related method signatures found in metadata will not be updated.</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members">
<source>Remove unused private members</source>
<target state="new">Remove unused private members</target>
<note />
</trans-unit>
<trans-unit id="Remove_Unused_Private_Members_Message">
<source>Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</source>
<target state="new">Type '{0}' has a private member '{1}' which can be removed as it is either never used or the value assigned to it is never used.</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_member">
<source>Remove unused member</source>
<target state="new">Remove unused member</target>
......
......@@ -2,13 +2,13 @@
Imports System.Composition
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.AvoidUnusedMembers
Imports Microsoft.CodeAnalysis.RemoveUnusedMembers
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.AvoidUnusedMembers
<ExportCodeFixProvider(LanguageNames.VisualBasic, Name:=PredefinedCodeFixProviderNames.AvoidUnusedMembers), [Shared]>
Friend Class VisualBasicAvoidUnusedMembersCodeFixProvider
Inherits AbstractAvoidUnusedMembersCodeFixProvider(Of FieldDeclarationSyntax)
Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedMembers
<ExportCodeFixProvider(LanguageNames.VisualBasic, Name:=PredefinedCodeFixProviderNames.RemoveUnusedMembers), [Shared]>
Friend Class VisualBasicRemoveUnusedMembersCodeFixProvider
Inherits AbstractRemoveUnusedMembersCodeFixProvider(Of FieldDeclarationSyntax)
Protected Overrides Function GetTopmostSyntaxNodeForSymbolDeclaration(syntaxNode As SyntaxNode, isSymbolDeclarationNode As Func(Of SyntaxNode, Boolean)) As SyntaxNode
Dim symbolDeclNode = MyBase.GetTopmostSyntaxNodeForSymbolDeclaration(syntaxNode, isSymbolDeclarationNode)
......
' 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.Diagnostics
Imports Microsoft.CodeAnalysis.RemoveUnusedMembers
Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnusedMembers
<DiagnosticAnalyzer(LanguageNames.VisualBasic)>
Friend NotInheritable Class VisualBasicRemoveUnusedMembersDiagnosticAnalyzer
Inherits AbstractRemoveUnusedMembersDiagnosticAnalyzer
Public Sub New()
' Compound assigment is a statement in VB that does not return a value.
' So, we treat it as a write-only usage.
MyBase.New(treatCompoundAssignmentAsWriteOnlyOperation:=True)
End Sub
End Class
End Namespace
......@@ -45,7 +45,6 @@ public static class Features
public const string CodeActionsAddParameter = "CodeActions.AddParameter";
public const string CodeActionsAddParenthesesAroundConditionalExpressionInInterpolatedString = "CodeActions.AddParenthesesAroundConditionalExpressionInInterpolatedString";
public const string CodeActionsAliasAmbiguousType = "CodeActions.AliasAmbiguousType";
public const string CodeActionsAvoidUnusedMembers = "CodeActions.AvoidUnusedMembers";
public const string CodeActionsChangeToAsync = "CodeActions.ChangeToAsync";
public const string CodeActionsChangeToIEnumerable = "CodeActions.ChangeToIEnumerable";
public const string CodeActionsChangeToYield = "CodeActions.ChangeToYield";
......@@ -110,6 +109,7 @@ public static class Features
public const string CodeActionsRemoveUnnecessaryCast = "CodeActions.RemoveUnnecessaryCast";
public const string CodeActionsRemoveUnnecessaryParentheses = "CodeActions.RemoveUnnecessaryParentheses";
public const string CodeActionsRemoveUnusedLocalFunction = "CodeActions.RemoveUnusedLocalFunction";
public const string CodeActionsRemoveUnusedMembers = "CodeActions.RemoveUnusedMembers";
public const string CodeActionsRemoveUnusedVariable = "CodeActions.RemoveUnusedVariable";
public const string CodeActionsRemoveUnnecessaryImports = "CodeActions.RemoveUnnecessaryImports";
public const string CodeActionsRemoveUnreachableCode = "CodeActions.RemoveUnreachableCode";
......
......@@ -725,10 +725,10 @@ public string Style_PreferReadonly
set { SetXmlOption(CodeStyleOptions.PreferReadonly, value); }
}
public string Style_AvoidUnusedMembers
public string Style_RemoveUnusedMembers
{
get { return GetXmlOption(CodeStyleOptions.AvoidUnusedMembers); }
set { SetXmlOption(CodeStyleOptions.AvoidUnusedMembers, value); }
get { return GetXmlOption(CodeStyleOptions.RemoveUnusedMembers); }
set { SetXmlOption(CodeStyleOptions.RemoveUnusedMembers, value); }
}
public int Wrapping_IgnoreSpacesAroundBinaryOperators
......
......@@ -929,7 +929,7 @@ class Customer2
}}
";
private static readonly string s_avoidUnusedMembers = $@"
private static readonly string s_removeUnusedMembers = $@"
class Customer1
{{
//[
......@@ -1109,7 +1109,6 @@ internal StyleViewModel(OptionSet optionSet, IServiceProvider serviceProvider) :
var predefinedTypesGroupTitle = CSharpVSResources.predefined_type_preferences_colon;
var varGroupTitle = CSharpVSResources.var_preferences_colon;
var nullCheckingGroupTitle = CSharpVSResources.null_checking_colon;
var fieldGroupTitle = ServicesVSResources.Field_preferences_colon;
var memberGroupTitle = ServicesVSResources.Member_preferences_colon;
var codeBlockPreferencesGroupTitle = ServicesVSResources.Code_block_preferences_colon;
var expressionPreferencesGroupTitle = ServicesVSResources.Expression_preferences_colon;
......@@ -1178,11 +1177,9 @@ internal StyleViewModel(OptionSet optionSet, IServiceProvider serviceProvider) :
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferNullPropagation, ServicesVSResources.Prefer_null_propagation, s_preferNullPropagation, s_preferNullPropagation, this, optionSet, nullCheckingGroupTitle));
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferIsNullCheckOverReferenceEqualityMethod, CSharpVSResources.Prefer_is_null_for_reference_equality_checks, s_preferIsNullOverReferenceEquals, s_preferIsNullOverReferenceEquals, this, optionSet, nullCheckingGroupTitle));
// Field preferences.
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferReadonly, ServicesVSResources.Prefer_readonly, s_preferReadonly, s_preferReadonly, this, optionSet, fieldGroupTitle));
// Member preferences (field/method/property/event).
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions.AvoidUnusedMembers, ServicesVSResources.Avoid_unused_members, s_avoidUnusedMembers, s_avoidUnusedMembers, this, optionSet, memberGroupTitle));
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferReadonly, ServicesVSResources.Prefer_readonly_fields, s_preferReadonly, s_preferReadonly, this, optionSet, memberGroupTitle));
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions.RemoveUnusedMembers, ServicesVSResources.Remove_unused_members, s_removeUnusedMembers, s_removeUnusedMembers, this, optionSet, memberGroupTitle));
}
private void AddParenthesesOptions(OptionSet optionSet)
......
......@@ -325,15 +325,6 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Avoid unused members.
/// </summary>
internal static string Avoid_unused_members {
get {
return ResourceManager.GetString("Avoid_unused_members", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Base Types.
/// </summary>
......@@ -961,15 +952,6 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Field preferences:.
/// </summary>
internal static string Field_preferences_colon {
get {
return ResourceManager.GetString("Field_preferences_colon", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to File already exists.
/// </summary>
......@@ -1335,7 +1317,7 @@ internal class ServicesVSResources {
}
/// <summary>
/// Looks up a localized string similar to Member preferences (field/method/property/event):.
/// Looks up a localized string similar to Member preferences:.
/// </summary>
internal static string Member_preferences_colon {
get {
......@@ -1894,11 +1876,11 @@ internal class ServicesVSResources {
}
/// <summary>
/// Looks up a localized string similar to Prefer readonly.
/// Looks up a localized string similar to Prefer readonly fields.
/// </summary>
internal static string Prefer_readonly {
internal static string Prefer_readonly_fields {
get {
return ResourceManager.GetString("Prefer_readonly", resourceCulture);
return ResourceManager.GetString("Prefer_readonly_fields", resourceCulture);
}
}
......@@ -2133,6 +2115,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Remove unused members.
/// </summary>
internal static string Remove_unused_members {
get {
return ResourceManager.GetString("Remove_unused_members", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reorder.
/// </summary>
......
......@@ -1027,11 +1027,8 @@ I agree to all of the foregoing:</value>
<data name="Code_style_header_use_editor_config" xml:space="preserve">
<value>The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</value>
</data>
<data name="Field_preferences_colon" xml:space="preserve">
<value>Field preferences:</value>
</data>
<data name="Prefer_readonly" xml:space="preserve">
<value>Prefer readonly</value>
<data name="Prefer_readonly_fields" xml:space="preserve">
<value>Prefer readonly fields</value>
</data>
<data name="Analyzing_0" xml:space="preserve">
<value>Analyzing '{0}'</value>
......@@ -1051,10 +1048,10 @@ I agree to all of the foregoing:</value>
<data name="We_notice_you_suspended_0_Reset_keymappings_to_continue_to_navigate_and_refactor" xml:space="preserve">
<value>We notice you suspended '{0}'. Reset keymappings to continue to navigate and refactor.</value>
</data>
<data name="Avoid_unused_members" xml:space="preserve">
<value>Avoid unused members</value>
<data name="Remove_unused_members" xml:space="preserve">
<value>Remove unused members</value>
</data>
<data name="Member_preferences_colon" xml:space="preserve">
<value>Member preferences (field/method/property/event):</value>
<value>Member preferences:</value>
</data>
</root>
\ No newline at end of file
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">Element není platný.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ Souhlasím se všemi výše uvedenými podmínkami:</target>
<target state="translated">Změny nelze použít – neočekávaná chyba: {0}</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">Předvolby pole:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">Upřednostnit jen pro čtení</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">Spravovat styly pojmenování</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">Das Element ist ungültig.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ Ich stimme allen vorstehenden Bedingungen zu:</target>
<target state="translated">Änderungen können nicht angewendet werden -- unerwarteter Fehler: {0}</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">Feldeinstellungen:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">Schreibgeschützte vorziehen</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">Benennungsstile verwalten</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">El elemento no es válido.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ Estoy de acuerdo con todo lo anterior:</target>
<target state="translated">No se pueden aplicar los cambios: error inesperado "{0}"</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">Preferencias de campo:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">Preferir solo lectura</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">Administrar estilos de nomenclatura</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">L'élément n'est pas valide.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ Je suis d'accord avec tout ce qui précède :</target>
<target state="translated">Impossible d'appliquer les changements -- Erreur inattendue : '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">Préférences de champ :</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">Préférer readonly</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">Gérer les styles de nommage</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">L'elemento non è valido.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ L'utente accetta le condizioni sopra riportate:</target>
<target state="translated">Non è possibile applicare le modifiche. Errore imprevisto: '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">Preferenze campi:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">Preferisci readonly</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">Gestisci stili di denominazione</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">要素が有効ではありません。</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ I agree to all of the foregoing:</source>
<target state="translated">変更を適用できません。予期しないエラー: '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">フィールド設定:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">読み取り専用を優先する</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">名前付けスタイルを管理する</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">요소가 잘못되었습니다.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ I agree to all of the foregoing:</source>
<target state="translated">변경 내용을 적용할 수 없음 - 예기치 않은 오류: '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">필드 기본 설정:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">읽기 전용 기본 사용</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">명명 스타일 관리</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">Element jest nieprawidłowy.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ Wyrażam zgodę na wszystkie następujące postanowienia:</target>
<target state="translated">Nie można zastosować zmian — nieoczekiwany błąd: „{0}”</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">Preferencje pola:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">Preferuj tylko do odczytu</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">Zarządzaj stylami nazewnictwa</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">O elemento é inválido.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ Eu concordo com todo o conteúdo supracitado:</target>
<target state="translated">Não é possível aplicar as alterações – erro inesperado: '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">Preferências de campo:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">Preferir somente leitura</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">Gerenciar estilos de nomenclatura</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">Элемент недопустим.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ I agree to all of the foregoing:</source>
<target state="translated">Не удается применить изменения, так как возникла непредвиденная ошибка: "{0}"</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">Предпочтения для полей:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">Предпочитать только для чтения</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">Управление стилями именования</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">Öğe geçerli değil.</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ Aşağıdakilerin tümünü onaylıyorum:</target>
<target state="translated">Değişiklikler uygulanamıyor - beklenmeyen hata: '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">Alan tercihleri:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">Salt okunur özelliğini tercih et</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">Adlandırma stillerini yönetme</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">元素无效。</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ I agree to all of the foregoing:</source>
<target state="translated">无法应用更改 - 意外错误:“{0}”</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">字段首选项:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">首选只读</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">管理命名样式</target>
......
......@@ -12,11 +12,6 @@
<target state="new">Apply '{0}' keymapping scheme</target>
<note />
</trans-unit>
<trans-unit id="Avoid_unused_members">
<source>Avoid unused members</source>
<target state="new">Avoid unused members</target>
<note />
</trans-unit>
<trans-unit id="Element_is_not_valid">
<source>Element is not valid.</source>
<target state="translated">元素無效。</target>
......@@ -33,8 +28,8 @@
<note />
</trans-unit>
<trans-unit id="Member_preferences_colon">
<source>Member preferences (field/method/property/event):</source>
<target state="new">Member preferences (field/method/property/event):</target>
<source>Member preferences:</source>
<target state="new">Member preferences:</target>
<note />
</trans-unit>
<trans-unit id="Never_if_unnecessary">
......@@ -47,6 +42,16 @@
<target state="new">Parentheses preferences:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly_fields">
<source>Prefer readonly fields</source>
<target state="new">Prefer readonly fields</target>
<note />
</trans-unit>
<trans-unit id="Remove_unused_members">
<source>Remove unused members</source>
<target state="new">Remove unused members</target>
<note />
</trans-unit>
<trans-unit id="Reset_Visual_Studio_default_keymapping">
<source>Reset Visual Studio default keymapping</source>
<target state="new">Reset Visual Studio default keymapping</target>
......@@ -1533,16 +1538,6 @@ I agree to all of the foregoing:</source>
<target state="translated">無法套用變更 -- 未預期的錯誤: '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Field_preferences_colon">
<source>Field preferences:</source>
<target state="translated">欄位喜好設定:</target>
<note />
</trans-unit>
<trans-unit id="Prefer_readonly">
<source>Prefer readonly</source>
<target state="translated">偏好唯讀</target>
<note />
</trans-unit>
<trans-unit id="Manage_naming_styles">
<source>Manage naming styles</source>
<target state="translated">管理命名樣式</target>
......
......@@ -288,12 +288,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
End Set
End Property
Public Property Style_AvoidUnusedMembers As String
Public Property Style_RemoveUnusedMembers As String
Get
Return GetXmlOption(CodeStyleOptions.AvoidUnusedMembers)
Return GetXmlOption(CodeStyleOptions.RemoveUnusedMembers)
End Get
Set(value As String)
SetXmlOption(CodeStyleOptions.AvoidUnusedMembers, value)
SetXmlOption(CodeStyleOptions.RemoveUnusedMembers, value)
End Set
End Property
......
......@@ -511,7 +511,7 @@ Class Customer2
//]
End Class"
Private Shared ReadOnly s_avoidUnusedMembers As String = $"
Private Shared ReadOnly s_removeUnusedMembers As String = $"
Class Customer1
//[
' {ServicesVSResources.Prefer_colon}
......@@ -558,7 +558,6 @@ End Class"
Dim codeBlockPreferencesGroupTitle = ServicesVSResources.Code_block_preferences_colon
Dim expressionPreferencesGroupTitle = ServicesVSResources.Expression_preferences_colon
Dim nothingPreferencesGroupTitle = BasicVSResources.nothing_checking_colon
Dim fieldPreferencesGroupTitle = ServicesVSResources.Field_preferences_colon
Dim memberPreferencesGroupTitle = ServicesVSResources.Member_preferences_colon
' qualify with Me. group
......@@ -589,11 +588,9 @@ End Class"
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferNullPropagation, ServicesVSResources.Prefer_null_propagation, s_preferNullPropagation, s_preferNullPropagation, Me, optionSet, nothingPreferencesGroupTitle))
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferIsNullCheckOverReferenceEqualityMethod, BasicVSResources.Prefer_Is_Nothing_for_reference_equality_checks, s_preferIsNothingCheckOverReferenceEquals, s_preferIsNothingCheckOverReferenceEquals, Me, optionSet, nothingPreferencesGroupTitle))
' field preferences
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferReadonly, ServicesVSResources.Prefer_readonly, s_preferReadonly, s_preferReadonly, Me, optionSet, fieldPreferencesGroupTitle))
' Member preferences (field/method/property/event).
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.AvoidUnusedMembers, ServicesVSResources.Avoid_unused_members, s_avoidUnusedMembers, s_avoidUnusedMembers, Me, optionSet, memberPreferencesGroupTitle))
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferReadonly, ServicesVSResources.Prefer_readonly_fields, s_preferReadonly, s_preferReadonly, Me, optionSet, memberPreferencesGroupTitle))
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.RemoveUnusedMembers, ServicesVSResources.Remove_unused_members, s_removeUnusedMembers, s_removeUnusedMembers, Me, optionSet, memberPreferencesGroupTitle))
End Sub
Private Sub AddParenthesesOptions(optionSet As OptionSet)
......
......@@ -208,13 +208,13 @@ public class CodeStyleOptions
EditorConfigStorageLocation.ForBoolCodeStyleOption("dotnet_style_readonly_field"),
new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferReadonly") });
internal static readonly PerLanguageOption<CodeStyleOption<bool>> AvoidUnusedMembers = new PerLanguageOption<CodeStyleOption<bool>>(
internal static readonly PerLanguageOption<CodeStyleOption<bool>> RemoveUnusedMembers = new PerLanguageOption<CodeStyleOption<bool>>(
nameof(CodeStyleOptions),
nameof(AvoidUnusedMembers),
nameof(RemoveUnusedMembers),
defaultValue: TrueWithSuggestionEnforcement,
storageLocations: new OptionStorageLocation[]{
EditorConfigStorageLocation.ForBoolCodeStyleOption("dotnet_style_avoid_unused_member"),
new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.AvoidUnusedMembers") });
EditorConfigStorageLocation.ForBoolCodeStyleOption("dotnet_style_remove_unused_member"),
new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.RemoveUnusedMembers") });
private static CodeStyleOption<AccessibilityModifiersRequired> ParseAccessibilityModifiersRequired(string optionString)
{
......
......@@ -242,7 +242,7 @@ protected void WriteOptionSetTo(OptionSet options, string language, ObjectWriter
WriteOptionTo(options, language, CodeStyleOptions.PreferInferredTupleNames, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferInferredAnonymousTypeMemberNames, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferReadonly, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.AvoidUnusedMembers, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.RemoveUnusedMembers, writer, cancellationToken);
}
protected OptionSet ReadOptionSetFrom(OptionSet options, string language, ObjectReader reader, CancellationToken cancellationToken)
......@@ -273,7 +273,7 @@ protected OptionSet ReadOptionSetFrom(OptionSet options, string language, Object
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferInferredTupleNames, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferInferredAnonymousTypeMemberNames, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferReadonly, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.AvoidUnusedMembers, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.RemoveUnusedMembers, reader, cancellationToken);
return options;
}
......
......@@ -15,6 +15,11 @@ namespace Microsoft.CodeAnalysis
{
internal static partial class OperationExtensions
{
public static bool IsTargetOfObjectMemberInitializer(this IOperation operation)
=> operation.Parent is IAssignmentOperation assignmentOperation &&
assignmentOperation.Target == operation &&
assignmentOperation.Parent?.Kind == OperationKind.ObjectOrCollectionInitializer;
/// <summary>
/// Returns the <see cref="ValueUsageInfo"/> for the given operation.
/// This extension can be removed once https://github.com/dotnet/roslyn/issues/25057 is implemented.
......@@ -28,18 +33,18 @@ public static ValueUsageInfo GetValueUsageInfo(this IOperation operation)
| x.Prop += 1 | ✔️ | ✔️ | | |
| x.Prop++ | ✔️ | ✔️ | | |
| Foo(x.Prop) | ✔️ | | | |
| Foo(x.Prop)* | | | ✔️ | |
| Foo(x.Prop), | | | ✔️ | |
where void Foo(in T v)
| Foo(out x.Prop) | | | | ✔️ |
| Foo(ref x.Prop) | | | ✔️ | ✔️ |
* where void Foo(in T v)
*/
if (operation.Parent is IAssignmentOperation assignmentOperation &&
assignmentOperation.Target == operation)
{
return operation.Parent.Kind == OperationKind.CompoundAssignment
? ValueUsageInfo.ReadWrite
? ValueUsageInfo.ReadWrite
: ValueUsageInfo.Write;
}
else if (operation.Parent is IIncrementOrDecrementOperation)
......@@ -51,8 +56,8 @@ public static ValueUsageInfo GetValueUsageInfo(this IOperation operation)
return parenthesizedOperation.GetValueUsageInfo();
}
else if (operation.Parent is INameOfOperation ||
operation.Parent is ITypeOfOperation ||
operation.Parent is ISizeOfOperation)
operation.Parent is ITypeOfOperation ||
operation.Parent is ISizeOfOperation)
{
return ValueUsageInfo.None;
}
......
......@@ -16,4 +16,13 @@ internal enum ValueUsageInfo
ReadWrite = Read | Write,
ReadableWritableRef = ReadableRef | WritableRef
}
internal static class ValueUsageInfoExtensions
{
public static bool ContainsReadOrReadableRef(this ValueUsageInfo valueUsageInfo)
=> (valueUsageInfo & (ValueUsageInfo.Read | ValueUsageInfo.ReadableRef)) != 0;
public static bool ContainsWriteOrWritableRef(this ValueUsageInfo valueUsageInfo)
=> (valueUsageInfo & (ValueUsageInfo.Write | ValueUsageInfo.WritableRef)) != 0;
}
}
......@@ -55,7 +55,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
begin = DirectCast(parent, EventBlockSyntax).EventStatement
Case SyntaxKind.VariableDeclarator
begin = node
If DirectCast(parent, VariableDeclaratorSyntax).Names.Count = 1 Then
begin = node
End If
End Select
End If
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册