未验证 提交 ec581add 编写于 作者: M Manish Vasani 提交者: GitHub

Merge pull request #31595 from mavasani/CoupleUnusedMemberBugs

Fix couple of bugs in unused private members analyzer
......@@ -310,6 +310,19 @@ class MyClass
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
[WorkItem(31572, "https://github.com/dotnet/roslyn/issues/31572")]
public async Task EntryPointMethodNotFlagged_05()
{
await TestDiagnosticMissingAsync(
@"using System.Threading.Tasks;
class MyClass
{
private static int [|Main|]() => 0;
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
public async Task FieldIsUnused_ReadOnly()
{
......@@ -898,6 +911,32 @@ public async Task FieldInNameOf()
expected: Diagnostic("IDE0052"));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
[WorkItem(31581, "https://github.com/dotnet/roslyn/issues/31581")]
public async Task MethodInNameOf()
{
await TestDiagnosticsAsync(
@"class MyClass
{
private void [|M|]() { }
private string _goo = nameof(M);
}",
expected: Diagnostic("IDE0052"));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
[WorkItem(31581, "https://github.com/dotnet/roslyn/issues/31581")]
public async Task PropertyInNameOf()
{
await TestDiagnosticsAsync(
@"class MyClass
{
private int [|P|] { get; }
private string _goo = nameof(P);
}",
expected: Diagnostic("IDE0052"));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)]
public async Task FieldInDocComment()
{
......
......@@ -648,6 +648,29 @@ End Class", parameters:=Nothing,
Diagnostic("IDE0052"))
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)>
<WorkItem(31581, "https://github.com/dotnet/roslyn/issues/31581")>
Public Async Function MethodInNameOf() As Task
Await TestDiagnosticsAsync(
"Class C
Private Sub [|M|]()
End Sub
Private _goo2 As String = NameOf(M)
End Class", parameters:=Nothing,
Diagnostic("IDE0052"))
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)>
<WorkItem(31581, "https://github.com/dotnet/roslyn/issues/31581")>
Public Async Function PropertyInNameOf() As Task
Await TestDiagnosticsAsync(
"Class C
Private ReadOnly Property [|P|] As Integer
Private _goo2 As String = NameOf(P)
End Class", parameters:=Nothing,
Diagnostic("IDE0052"))
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedMembers)>
Public Async Function FieldInDocComment() As Task
Await TestDiagnosticsAsync(
......
......@@ -86,7 +86,6 @@ internal static class DiagnosticHelper
throw new ArgumentNullException(nameof(descriptor));
}
var warningLevel = effectiveSeverity.ToDiagnosticSeverity() ?? descriptor.DefaultSeverity;
return Diagnostic.Create(
descriptor.Id,
descriptor.Category,
......
......@@ -10,7 +10,6 @@
namespace Microsoft.CodeAnalysis {
using System;
using System.Reflection;
/// <summary>
......@@ -40,7 +39,7 @@ internal class FeaturesResources {
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.CodeAnalysis.FeaturesResources", typeof(FeaturesResources).GetTypeInfo().Assembly);
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.CodeAnalysis.FeaturesResources", typeof(FeaturesResources).Assembly);
resourceMan = temp;
}
return resourceMan;
......@@ -2798,6 +2797,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Private method &apos;{0}&apos; can be removed as it is never invoked..
/// </summary>
internal static string Private_method_0_can_be_removed_as_it_is_never_invoked {
get {
return ResourceManager.GetString("Private_method_0_can_be_removed_as_it_is_never_invoked", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Project.
/// </summary>
......
......@@ -1439,6 +1439,9 @@ This version used in: {2}</value>
<data name="Private_member_0_can_be_removed_as_the_value_assigned_to_it_is_never_read" xml:space="preserve">
<value>Private member '{0}' can be removed as the value assigned to it is never read.</value>
</data>
<data name="Private_method_0_can_be_removed_as_it_is_never_invoked" xml:space="preserve">
<value>Private method '{0}' can be removed as it is never invoked.</value>
</data>
<data name="Code_Quality" xml:space="preserve">
<value>Code Quality</value>
</data>
......
......@@ -165,6 +165,7 @@ private void RegisterActions(CompilationStartAnalysisContext compilationStartCon
symbolStartContext.RegisterOperationAction(AnalyzeMemberReferenceOperation, OperationKind.FieldReference, OperationKind.MethodReference, OperationKind.PropertyReference, OperationKind.EventReference);
symbolStartContext.RegisterOperationAction(AnalyzeFieldInitializer, OperationKind.FieldInitializer);
symbolStartContext.RegisterOperationAction(AnalyzeInvocationOperation, OperationKind.Invocation);
symbolStartContext.RegisterOperationAction(AnalyzeNameOfOperation, OperationKind.NameOf);
symbolStartContext.RegisterOperationAction(AnalyzeObjectCreationOperation, OperationKind.ObjectCreation);
symbolStartContext.RegisterOperationAction(_ => hasInvalidOperation = true, OperationKind.Invalid);
symbolStartContext.RegisterSymbolEndAction(symbolEndContext => OnSymbolEnd(symbolEndContext, hasInvalidOperation));
......@@ -294,6 +295,34 @@ private void AnalyzeInvocationOperation(OperationAnalysisContext operationContex
OnSymbolUsage(targetMethod, ValueUsageInfo.Read);
}
private void AnalyzeNameOfOperation(OperationAnalysisContext operationContext)
{
// Workaround for https://github.com/dotnet/roslyn/issues/19965
// IOperation API does not expose potential references to methods/properties within
// a bound method group/property group.
var nameofArgument = ((INameOfOperation)operationContext.Operation).Argument;
if (nameofArgument is IMemberReferenceOperation)
{
// Already analyzed in AnalyzeMemberReferenceOperation.
return;
}
var symbolInfo = nameofArgument.SemanticModel.GetSymbolInfo(nameofArgument.Syntax, operationContext.CancellationToken);
foreach (var symbol in symbolInfo.GetAllSymbols())
{
switch (symbol.Kind)
{
// Handle potential references to methods/properties from missing IOperation
// for method group/property group.
case SymbolKind.Method:
case SymbolKind.Property:
OnSymbolUsage(symbol, ValueUsageInfo.NameOnly);
break;
}
}
}
private void AnalyzeObjectCreationOperation(OperationAnalysisContext operationContext)
{
var constructor = ((IObjectCreationOperation)operationContext.Operation).Constructor.OriginalDefinition;
......@@ -377,12 +406,13 @@ private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasInvalid
// Most of the members should have a single location, except for partial methods.
// We report the diagnostic on the first location of the member.
var diagnostic = Diagnostic.Create(
var diagnostic = DiagnosticHelper.CreateWithMessage(
rule,
member.Locations[0],
rule.GetEffectiveSeverity(symbolEndContext.Compilation.Options),
additionalLocations: null,
properties: null,
$"{member.ContainingType.Name}.{member.Name}");
GetMessage(rule, member));
symbolEndContext.ReportDiagnostic(diagnostic);
}
}
......@@ -396,6 +426,22 @@ private void OnSymbolEnd(SymbolAnalysisContext symbolEndContext, bool hasInvalid
return;
}
private static LocalizableString GetMessage(
DiagnosticDescriptor rule,
ISymbol member)
{
var messageFormat = rule.MessageFormat;
if (rule == s_removeUnreadMembersRule &&
member is IMethodSymbol)
{
// IDE0052 has a different message for method symbols.
messageFormat = FeaturesResources.Private_method_0_can_be_removed_as_it_is_never_invoked;
}
var memberName = $"{member.ContainingType.Name}.{member.Name}";
return new DiagnosticHelper.LocalizableStringWithArguments(messageFormat, memberName);
}
private static bool HasSyntaxErrors(INamedTypeSymbol namedTypeSymbol, CancellationToken cancellationToken)
{
foreach (var tree in namedTypeSymbol.Locations.Select(l => l.SourceTree))
......@@ -601,8 +647,9 @@ private bool IsEntryPoint(IMethodSymbol methodSymbol)
=> methodSymbol.Name == WellKnownMemberNames.EntryPointMethodName &&
methodSymbol.IsStatic &&
(methodSymbol.ReturnsVoid ||
methodSymbol.ReturnType.OriginalDefinition == _taskType ||
methodSymbol.ReturnType.OriginalDefinition == _genericTaskType);
methodSymbol.ReturnType.SpecialType == SpecialType.System_Int32 ||
methodSymbol.ReturnType.OriginalDefinition.Equals(_taskType) ||
methodSymbol.ReturnType.OriginalDefinition.Equals(_genericTaskType));
private bool IsMethodWithSpecialAttribute(IMethodSymbol methodSymbol)
=> methodSymbol.GetAttributes().Any(a => _attributeSetForMethodsToIgnore.Contains(a.AttributeClass));
......
......@@ -162,6 +162,11 @@
<target state="translated">Když se upraví zdrojový soubor {0}, relace ladění nebude moct pokračovat kvůli vnitřní chybě: {1}</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">Podpisy souvisejících metod nalezené v metadatech se nebudou aktualizovat.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">In Metadaten gefundene ähnliche Methodensignaturen werden nicht aktualisiert.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">Las signaturas de método relacionadas encontradas en los metadatos no se actualizarán.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">Les signatures de méthode associées trouvées dans les métadonnées ne seront pas mises à jour.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">Le firme del metodo correlate trovate nei metadati non verranno aggiornate.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">メタデータ内に検出される関連するメソッド シグネチャは更新されません。</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">메타데이터에서 찾은 관련 메서드 시그니처가 업데이트되지 않습니다.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">Sygnatury powiązanych metod znalezione w metadanych nie zostaną zaktualizowane.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">As assinaturas de método relacionadas encontradas nos metadados não serão atualizadas.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">Связанные сигнатуры методов, найденные в метаданных, не будут обновлены.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">Meta verilerde bulunan ilgili metot imzaları güncelleştirilmez.</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">不更新在元数据中发现的相关方法签名。</target>
......
......@@ -162,6 +162,11 @@
<target state="new">Invert conditional</target>
<note />
</trans-unit>
<trans-unit id="Private_method_0_can_be_removed_as_it_is_never_invoked">
<source>Private method '{0}' can be removed as it is never invoked.</source>
<target state="new">Private method '{0}' can be removed as it is never invoked.</target>
<note />
</trans-unit>
<trans-unit id="Related_method_signatures_found_in_metadata_will_not_be_updated">
<source>Related method signatures found in metadata will not be updated.</source>
<target state="translated">將不會更新中繼資料中所找到的相關方法簽章。</target>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册