public void LambdaFlow_04() { string source = @" struct C { void M(System.Action d1, System.Action<bool, bool> d2) /*<bind>*/{ d1 = () => { d2 = (bool result1, bool input1) => { result1 = input1; }; }; void local(bool result2, bool input2) => result2 = input2; }/*</bind>*/ } "; var compilation = CreateCompilation(source); var tree = compilation.SyntaxTrees.Single(); var semanticModel = compilation.GetSemanticModel(tree); var graphM = ControlFlowGraph.Create((IMethodBodyOperation)semanticModel.GetOperation(tree.GetRoot().DescendantNodes().OfType <MethodDeclarationSyntax>().Single())); Assert.NotNull(graphM); Assert.Null(graphM.Parent); IFlowAnonymousFunctionOperation lambdaD1 = getLambda(graphM); Assert.Throws <ArgumentNullException>(() => graphM.GetLocalFunctionControlFlowGraph(null)); Assert.Throws <ArgumentOutOfRangeException>(() => graphM.GetLocalFunctionControlFlowGraph(lambdaD1.Symbol)); Assert.Throws <ArgumentNullException>(() => graphM.GetLocalFunctionControlFlowGraphInScope(null)); Assert.Throws <ArgumentOutOfRangeException>(() => graphM.GetLocalFunctionControlFlowGraphInScope(lambdaD1.Symbol)); var graphD1 = graphM.GetAnonymousFunctionControlFlowGraph(lambdaD1); Assert.NotNull(graphD1); Assert.Same(graphM, graphD1.Parent); var graphD1_FromExtension = graphM.GetAnonymousFunctionControlFlowGraphInScope(lambdaD1); Assert.Same(graphD1, graphD1_FromExtension); IFlowAnonymousFunctionOperation lambdaD2 = getLambda(graphD1); var graphD2 = graphD1.GetAnonymousFunctionControlFlowGraph(lambdaD2); Assert.NotNull(graphD2); Assert.Same(graphD1, graphD2.Parent); Assert.Throws <ArgumentNullException>(() => graphM.GetAnonymousFunctionControlFlowGraph(null)); Assert.Throws <ArgumentOutOfRangeException>(() => graphM.GetAnonymousFunctionControlFlowGraph(lambdaD2)); Assert.Throws <ArgumentNullException>(() => graphM.GetAnonymousFunctionControlFlowGraphInScope(null)); Assert.Throws <ArgumentOutOfRangeException>(() => graphM.GetAnonymousFunctionControlFlowGraphInScope(lambdaD2)); IFlowAnonymousFunctionOperation getLambda(ControlFlowGraph graph) { return(graph.Blocks.SelectMany(b => b.Operations.SelectMany(o => o.DescendantsAndSelf())).OfType <IFlowAnonymousFunctionOperation>().Single()); } }
/// <summary> /// Gets or creates a control flow graph for the given <paramref name="anonymousFunction"/> defined in /// the given <paramref name="controlFlowGraph"/> or any of it's parent control flow graphs. /// </summary> public static ControlFlowGraph GetAnonymousFunctionControlFlowGraphInScope( this ControlFlowGraph controlFlowGraph, IFlowAnonymousFunctionOperation anonymousFunction, CancellationToken cancellationToken = default ) { if (controlFlowGraph == null) { throw new ArgumentNullException(nameof(controlFlowGraph)); } if (anonymousFunction == null) { throw new ArgumentNullException(nameof(anonymousFunction)); } ControlFlowGraph?currentGraph = controlFlowGraph; do { if ( currentGraph.TryGetAnonymousFunctionControlFlowGraph( anonymousFunction, cancellationToken, out ControlFlowGraph? localFunctionControlFlowGraph ) ) { return(localFunctionControlFlowGraph); } } while ((currentGraph = currentGraph.Parent) != null); throw new ArgumentOutOfRangeException(nameof(anonymousFunction)); }
public override ParameterValidationAbstractValue VisitInvocation_Lambda( IFlowAnonymousFunctionOperation lambda, ImmutableArray <IArgumentOperation> visitedArguments, IOperation originalOperation, ParameterValidationAbstractValue defaultValue) { var value = base.VisitInvocation_Lambda(lambda, visitedArguments, originalOperation, defaultValue); ProcessLambdaOrLocalFunctionInvocation(lambda.Symbol, originalOperation); return(value); }
public override IOperation VisitFlowAnonymousFunction( IFlowAnonymousFunctionOperation operation, object?argument ) { var anonymous = (FlowAnonymousFunctionOperation)operation; return(new FlowAnonymousFunctionOperation( in anonymous.Context, anonymous.Original, operation.IsImplicit )); }
public override TaintedDataAbstractValue VisitInvocation_Lambda(IFlowAnonymousFunctionOperation lambda, ImmutableArray <IArgumentOperation> visitedArguments, IOperation originalOperation, TaintedDataAbstractValue defaultValue) { // Always invoke base visit. TaintedDataAbstractValue baseValue = base.VisitInvocation_Lambda(lambda, visitedArguments, originalOperation, defaultValue); IEnumerable <IArgumentOperation> taintedArguments = GetTaintedArguments(visitedArguments); if (taintedArguments.Any()) { ProcessTaintedDataEnteringInvocationOrCreation(lambda.Symbol, taintedArguments, originalOperation); } return(baseValue); }
public BasicBlockAnalysisData AnalyzeLambdaInvocation(IFlowAnonymousFunctionOperation lambda, CancellationToken cancellationToken) { if (!LambdaOrLocalFunctionsBeingAnalyzed.Add(lambda.Symbol)) { ResetState(); return(CurrentBlockAnalysisData); } else { var result = AnalyzeLambdaInvocationCore(lambda, cancellationToken); LambdaOrLocalFunctionsBeingAnalyzed.Remove(lambda.Symbol); return(result); } }
public override void VisitFlowAnonymousFunction(IFlowAnonymousFunctionOperation operation) { base.VisitFlowAnonymousFunction(operation); LogString("{"); LogNewLine(); var g = _graph.GetAnonymousFunctionControlFlowGraph(operation); int id = _anonymousFunctionsMap.Count; _anonymousFunctionsMap.Add(operation, g); Assert.Equal(OperationKind.AnonymousFunction, g.OriginalOperation.Kind); GetFlowGraph(_builder, _compilation, g, _region, $"#A{id}{_idSuffix}", _currentIndent.Length + 4); LogString("}"); LogNewLine(); }
public ControlFlowGraph GetAnonymousFunctionControlFlowGraph(IFlowAnonymousFunctionOperation lambda) { // TODO: https://github.com/dotnet/roslyn-analyzers/issues/1812 // Remove the below workaround. try { return(ControlFlowGraph.GetAnonymousFunctionControlFlowGraph(lambda)); } catch (ArgumentOutOfRangeException) { if (ParentControlFlowGraphOpt != null && InterproceduralAnalysisDataOpt != null) { var parentAnalysisContext = InterproceduralAnalysisDataOpt.MethodsBeingAnalyzed.FirstOrDefault(context => context.ControlFlowGraph == ParentControlFlowGraphOpt); return(parentAnalysisContext?.GetAnonymousFunctionControlFlowGraph(lambda)); } // Unable to find control flow graph for lambda. // This can happen for cases where lambda creation and invocations are in different interprocedural call trees. // See unit test "DisposeObjectsBeforeLosingScopeTests.InvocationOfLambdaCachedOntoField_InterproceduralAnalysis" // for an example. // Currently, we don't support interprocedural analysis of such lambda invocations. return(null); } }
public override void SetLambdaTargetForDelegate(IOperation write, IFlowAnonymousFunctionOperation lambdaTarget) => throw ExceptionUtilities.Unreachable;
// Lambda target needs flow analysis, not supported/reachable in operation tree based analysis. protected override BasicBlockAnalysisData AnalyzeLambdaInvocationCore(IFlowAnonymousFunctionOperation lambda, CancellationToken cancellationToken) => throw ExceptionUtilities.Unreachable;
public virtual void VisitFlowAnonymousFunction(IFlowAnonymousFunctionOperation operation) { DefaultVisit(operation); }
public abstract void SetLambdaTargetForDelegate(IOperation write, IFlowAnonymousFunctionOperation lambdaTarget);
protected abstract BasicBlockAnalysisData AnalyzeLambdaInvocationCore(IFlowAnonymousFunctionOperation lambda, CancellationToken cancellationToken);
public override void VisitFlowAnonymousFunction(IFlowAnonymousFunctionOperation operation) { Assert.Equal(OperationKind.FlowAnonymousFunction, operation.Kind); Assert.NotNull(operation.Symbol); Assert.Empty(operation.Children); }