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

Bail out from unused value assignment analysis in presence of delegates passed...

Bail out from unused value assignment analysis in presence of delegates passed as arguments to method invocation.
上级 89071513
......@@ -2643,6 +2643,37 @@ void M(object p)
}", optionName);
}
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
public async Task UseInLambda_PassedAsArgument_02(string optionName)
{
await TestMissingInRegularAndScriptAsync(
@"using System;
class C
{
public C(bool flag)
{
Flag = flag;
}
public bool Flag { get; }
public static bool M()
{
bool flag = true;
var c = Create(() => flag);
M2(c);
[|flag|] = false;
return M2(c);
}
private static C Create(Func<bool> isFlagTrue) { return new C(isFlagTrue()); }
private static bool M2(C c) => c.Flag;
}", optionName);
}
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnusedValues)]
[InlineData(nameof(PreferDiscard))]
[InlineData(nameof(PreferUnusedLocal))]
......
......@@ -29,6 +29,12 @@ private sealed partial class BlockAnalyzer
/// </summary>
private bool _hasDelegateCreationOrAnonymousFunction;
/// <summary>
/// Indicates if the operation block has an <see cref="IArgumentOperation"/> with a delegate type argument.
/// We use this value in <see cref="ShouldAnalyze(IOperation, ISymbol)"/> to determine whether to bail from analysis or not.
/// </summary>
private bool _hasDelegateTypeArgument;
/// <summary>
/// Indicates if a delegate instance escaped this operation block, via an assignment to a field or a property symbol.
/// that can be accessed outside this executable code block.
......@@ -76,6 +82,7 @@ public static void Analyze(OperationBlockStartAnalysisContext context, SymbolSta
var blockAnalyzer = new BlockAnalyzer(symbolStartAnalyzer, options);
context.RegisterOperationAction(blockAnalyzer.AnalyzeExpressionStatement, OperationKind.ExpressionStatement);
context.RegisterOperationAction(blockAnalyzer.AnalyzeDelegateCreationOrAnonymousFunction, OperationKind.DelegateCreation, OperationKind.AnonymousFunction);
context.RegisterOperationAction(blockAnalyzer.AnalyzeArgument, OperationKind.Argument);
context.RegisterOperationAction(blockAnalyzer.AnalyzeConversion, OperationKind.Conversion);
context.RegisterOperationAction(blockAnalyzer.AnalyzeFieldOrPropertyReference, OperationKind.FieldReference, OperationKind.PropertyReference);
context.RegisterOperationAction(blockAnalyzer.AnalyzeParameterReference, OperationKind.ParameterReference);
......@@ -153,6 +160,16 @@ private void AnalyzeExpressionStatement(OperationAnalysisContext context)
private void AnalyzeDelegateCreationOrAnonymousFunction(OperationAnalysisContext operationAnalysisContext)
=> _hasDelegateCreationOrAnonymousFunction = true;
private void AnalyzeArgument(OperationAnalysisContext operationAnalysisContext)
{
var argument = (IArgumentOperation)operationAnalysisContext.Operation;
if (!_hasDelegateTypeArgument &&
argument.Value.Type.IsDelegateType())
{
_hasDelegateTypeArgument = true;
}
}
private void AnalyzeConversion(OperationAnalysisContext operationAnalysisContext)
{
var conversion = (IConversionOperation)operationAnalysisContext.Operation;
......@@ -229,7 +246,14 @@ private bool ShouldAnalyze(IOperation operationBlock, ISymbol owningSymbol)
return false;
}
// 4. Bail out for method returning delegates or ref/out parameters of delegate type.
// 4. Bail out if we pass a delegate type as an argument to a method.
// We can analyze this correctly when we do points-to-analysis.
if (_hasDelegateTypeArgument)
{
return false;
}
// 5. Bail out for method returning delegates or ref/out parameters of delegate type.
// We can analyze this correctly when we do points-to-analysis.
if (owningSymbol is IMethodSymbol method &&
(method.ReturnType.IsDelegateType() ||
......@@ -238,7 +262,7 @@ private bool ShouldAnalyze(IOperation operationBlock, ISymbol owningSymbol)
return false;
}
// 5. Otherwise, we execute analysis by walking the reaching symbol write chain to attempt to
// 6. Otherwise, we execute analysis by walking the reaching symbol write chain to attempt to
// find the target method being invoked.
// This works for most common and simple cases where a local is assigned a lambda and invoked later.
// If we are unable to find a target, we will conservatively mark all current symbol writes as read.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册