private static void ExpandInvocationOperation( IInvocationOperation invocationOperation, WellKnownSymbolsInfo wellKnownSymbolsInfo, Queue <IOperation> queue) { // Check the arguments of this invocation to see if this is a deferred executing method. // e.g. // var a = b.Concat(c); // When we looking at the creation of 'a', we want to find both 'b' and 'c' foreach (var argument in invocationOperation.Arguments) { if (IsLinqChainInvocation(invocationOperation, argument, wellKnownSymbolsInfo, out _)) { queue.Enqueue(argument.Value); } } // Also check it's invocation instance if the extension method could be used in reduced form. // e.g. // Dim a = b.Concat(c) // We need enqueue the invocation instance (which is 'b') if the target method is a reduced extension method if (IsLinqChainInvocation(invocationOperation, wellKnownSymbolsInfo, out _)) { queue.Enqueue(invocationOperation.Instance); } }
private static void ExpandConversionOperation( IConversionOperation conversionOperation, WellKnownSymbolsInfo wellKnownSymbolsInfo, Queue <IOperation> queue) { if (IsValidImplicitConversion(conversionOperation, wellKnownSymbolsInfo)) { queue.Enqueue(conversionOperation.Operand); } }
static (IOperation linqChainTailOperation, EnumerationCount enumerationCount) VisitLinqChainAndCoversionMethod( IOperation operation, EnumerationCount enumerationCount, WellKnownSymbolsInfo wellKnownSymbolsInfo) { if (IsValidImplicitConversion(operation.Parent, wellKnownSymbolsInfo)) { // Go to the implicit conversion if needed // e.g. // void Bar (IOrderedEnumerable<T> c) // { // c.First(); // } // here 'c' would be converted to IEnumerable<T> return(VisitLinqChainAndCoversionMethod(operation.Parent, enumerationCount, wellKnownSymbolsInfo)); } if (IsOperationIsArgumentOfLinqChainInvocation(operation.Parent, wellKnownSymbolsInfo, out var enumerateArgument)) { // This operation is used as an argument of a deferred execution method. // Check if the invocation of the deferred execution method is used in another deferred execution method. return(VisitLinqChainAndCoversionMethod( operation.Parent.Parent, enumerateArgument ? InvocationSetHelpers.AddInvocationCount(enumerationCount, EnumerationCount.One) : enumerationCount, wellKnownSymbolsInfo)); } if (IsInstanceOfLinqChainInvocation(operation, wellKnownSymbolsInfo, out var enumerateInstance)) { // If the extension method could be used as reduced method, also check its invocation instance. // Like in VB, // 'i.Select(Function(a) a)', 'i' is the invocation instance of 'Select' return(VisitLinqChainAndCoversionMethod( operation.Parent, enumerateInstance ? InvocationSetHelpers.AddInvocationCount(enumerationCount, EnumerationCount.One) : enumerationCount, wellKnownSymbolsInfo)); } return(operation, enumerationCount); }
private EnumerationCount GetEnumerationCount(IOperation parameterOrLocalReferenceOperation, WellKnownSymbolsInfo wellKnownSymbolsInfo) { var(linqChainTailOperation, linqChainEnumerationCount) = SkipLinqChainAndConversionMethod( parameterOrLocalReferenceOperation, wellKnownSymbolsInfo); if (IsOperationEnumeratedByInvocation(linqChainTailOperation, wellKnownSymbolsInfo) || IsGetEnumeratorOfForEachLoopInvoked(linqChainTailOperation)) { return(InvocationSetHelpers.AddInvocationCount(linqChainEnumerationCount, EnumerationCount.One)); } return(linqChainEnumerationCount); }
protected AvoidMultipleEnumerationsFlowStateDictionaryFlowOperationVisitor( GlobalFlowStateDictionaryAnalysisContext analysisContext, WellKnownSymbolsInfo wellKnownSymbolsInfo) : base(analysisContext) { _wellKnownSymbolsInfo = wellKnownSymbolsInfo; }
/// <summary> /// Skip the deferred method call and conversion operation in Linq methods call chain. /// Return the tail of the Linq chain operation, and possible enumerationCount by the Linq Chain Method. /// </summary> public static (IOperation linqChainTailOperation, EnumerationCount linqChainEnumerationCount) SkipLinqChainAndConversionMethod( IOperation operation, WellKnownSymbolsInfo wellKnownSymbolsInfo) { RoslynDebug.Assert(operation is IParameterReferenceOperation or ILocalReferenceOperation); return(VisitLinqChainAndCoversionMethod(operation, EnumerationCount.Zero, wellKnownSymbolsInfo));