Example #1
0
        public async static Task <IImmutableList <SyntaxNode> > GenerateMocksAsync(
            ILogSink logSink,
            Language language,
            string solutionPath,
            string xmlPath)
        {
            if (!File.Exists(xmlPath))
            {
                var message = $"XML input file '{xmlPath}' no found.";
                logSink.Error(logSource, message);
                throw new IOException(message);
            }

            logSink.Info(logSource, "Loading XML input file '{0}'.", xmlPath);

            var document      = XDocument.Load(xmlPath);
            var configuration = Configuration.FromXDocument(logSink, document);

            return(await Generator.GenerateMocksAsync(
                       logSink,
                       language,
                       solutionPath,
                       configuration.GetInterfacePredicate(),
                       configuration.GetNamespaceSelector(),
                       configuration.GetNameSelector(),
                       configuration.GetPlugins()));
        }
Example #2
0
        public static IImmutableList <SyntaxNode> GenerateMocks(
            ILogSink logSink,
            Language language,
            IImmutableList <Compilation> compilations,
            string xmlPath)
        {
            logSink = logSink
                      .WithSource(typeof(XmlBasedGenerator));

            if (!File.Exists(xmlPath))
            {
                logSink.Error("XML input file '{0}' not found.", xmlPath);
                return(ImmutableList <SyntaxNode> .Empty);
            }

            logSink.Info("Loading XML input file '{0}'.", xmlPath);

            var document      = XDocument.Load(xmlPath);
            var configuration = Configuration.FromXDocument(logSink, document);

            return(Generator.GenerateMocks(
                       logSink,
                       language,
                       compilations,
                       configuration.GetPlugins(),
                       configuration.GetInterfacePredicate(),
                       configuration.GetNamespaceSelector(),
                       configuration.GetNameSelector()));
        }
Example #3
0
        override public void Error(string value, int verbosity = Int32.MinValue)
        {
            if (verbosity > Verbosity)
            {
                return;
            }

            Sink.Error(ApplyTags(value));
        }
Example #4
0
        public void Log <TState>(
            MS.LogLevel logLevel,
            MS.EventId eventId,
            TState state,
            Exception exception,
            Func <TState, Exception, string> formatter)
        {
            if (logLevel == MS.LogLevel.Trace)
            {
                return;
            }

            var message = formatter(state, exception);

            // Very annoyingly, MSBuild appends new lines onto messages itself.
            if (message.EndsWith("\r\n"))
            {
                message = message.Substring(0, message.Length - 2);
            }

            switch (logLevel)
            {
            case MS.LogLevel.Debug:
                logSink.Debug(message);
                break;

            case MS.LogLevel.Information:
                logSink.Info(message);
                break;

            case MS.LogLevel.Warning:
                logSink.Warn(message);
                break;

            default:
                logSink.Error(message);
                break;
            }
        }
Example #5
0
        /// <inheritdoc />
        public SyntaxNode GenerateConfigureBehavior(
            ILogSink logSink,
            SyntaxGenerator syntaxGenerator,
            SemanticModel semanticModel,
            ISymbol symbol)
        {
            logSink.Debug(logSource, "Considering symbol '{0}'.", symbol);

            var propertySymbol = symbol as IPropertySymbol;
            var methodSymbol   = symbol as IMethodSymbol;

            INamedTypeSymbol returnType = null;

            if (propertySymbol != null)
            {
                if (propertySymbol.GetMethod == null)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a write-only property.", symbol);
                    return(null);
                }

                returnType = propertySymbol.GetMethod.ReturnType as INamedTypeSymbol;
            }
            else if (methodSymbol != null)
            {
                if (methodSymbol.AssociatedSymbol != null)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a method with an associated symbol.", symbol);
                    return(null);
                }

                if (methodSymbol.IsGenericMethod)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a generic method.", symbol);
                    return(null);
                }

                returnType = methodSymbol.ReturnType as INamedTypeSymbol;
            }
            else
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because it is neither a property nor a method.", symbol);
                return(null);
            }

            if (returnType == null)
            {
                logSink.Warn(logSource, "Ignoring symbol '{0}' because its return type could not be determined (it's probably a generic).", symbol);
                return(null);
            }

            var taskBaseType = semanticModel
                               .Compilation
                               .GetTypeByMetadataName("System.Threading.Tasks.Task");

            var genericTaskBaseType = semanticModel
                                      .Compilation
                                      .GetTypeByMetadataName("System.Threading.Tasks.Task`1");

            if (taskBaseType == null || genericTaskBaseType == null)
            {
                logSink.Warn(logSource, "Failed to resolve Task classes.");
                return(null);
            }

            var itType = semanticModel
                         .Compilation
                         .GetTypeByMetadataName("PCLMock.It");

            if (itType == null)
            {
                logSink.Error(logSource, "Failed to resolve It class.");
                return(null);
            }

            var isAnyMethod = itType
                              .GetMembers("IsAny")
                              .Single();

            if (isAnyMethod == null)
            {
                logSink.Error(logSource, "Failed to resolve IsAny method.");
                return(null);
            }

            var isGenericTask = returnType.IsGenericType && returnType.ConstructedFrom == genericTaskBaseType;
            var isTask        = returnType == taskBaseType;

            if (!isTask && !isGenericTask)
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because it does not return a Task or Task<T>.", symbol);
                return(null);
            }

            ITypeSymbol taskType = semanticModel
                                   .Compilation
                                   .GetSpecialType(SpecialType.System_Boolean);

            if (isGenericTask)
            {
                taskType = returnType.TypeArguments[0];
            }

            var lambdaParameterName = symbol.GetUniqueName();

            SyntaxNode lambdaExpression;

            if (propertySymbol != null)
            {
                if (!propertySymbol.IsIndexer)
                {
                    // GENERATED CODE:
                    //
                    //     this
                    //         .When(x => x.SymbolName)
                    //         .Return(Task.FromResult(default(T)));
                    lambdaExpression = syntaxGenerator.MemberAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        propertySymbol.Name);
                }
                else
                {
                    // GENERATED CODE:
                    //
                    //     this
                    //         .When(x => x[It.IsAny<P1>(), It.IsAny<P2>() ...)
                    //         .Return(Task.FromResult(default(T)));
                    var whenArguments = propertySymbol
                                        .Parameters
                                        .Select(
                        parameter =>
                        syntaxGenerator.InvocationExpression(
                            syntaxGenerator.MemberAccessExpression(
                                syntaxGenerator.TypeExpression(itType),
                                syntaxGenerator.GenericName(
                                    "IsAny",
                                    typeArguments: new[]
                    {
                        parameter.Type
                    }))));

                    lambdaExpression = syntaxGenerator.ElementAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        arguments: whenArguments);
                }
            }
            else
            {
                // GENERATED CODE:
                //
                //     this
                //         .When(x => x.SymbolName(It.IsAny<P1>(), It.IsAny<P2>() ...)
                //         .Return(Task.FromResult(default(T)));
                var whenArguments = methodSymbol
                                    .Parameters
                                    .Select(
                    parameter =>
                    syntaxGenerator.InvocationExpression(
                        syntaxGenerator.MemberAccessExpression(
                            syntaxGenerator.TypeExpression(itType),
                            syntaxGenerator.GenericName(
                                "IsAny",
                                typeArguments: new[]
                {
                    parameter.Type
                }))));

                lambdaExpression = syntaxGenerator.InvocationExpression(
                    syntaxGenerator.MemberAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        methodSymbol.Name),
                    arguments: whenArguments);
            }

            var whenLambdaArgument = syntaxGenerator.ValueReturningLambdaExpression(
                lambdaParameterName,
                lambdaExpression);

            var whenInvocation = syntaxGenerator.InvocationExpression(
                syntaxGenerator.MemberAccessExpression(
                    syntaxGenerator.ThisExpression(),
                    syntaxGenerator.IdentifierName("When")),
                whenLambdaArgument);

            var fromResultInvocation = syntaxGenerator.InvocationExpression(
                syntaxGenerator.WithTypeArguments(
                    syntaxGenerator.MemberAccessExpression(
                        syntaxGenerator.TypeExpression(taskBaseType),
                        "FromResult"),
                    syntaxGenerator.TypeExpression(taskType)),
                arguments: new[]
            {
                syntaxGenerator.DefaultExpression(taskType)
            });

            var result = syntaxGenerator.ExpressionStatement(
                syntaxGenerator.InvocationExpression(
                    syntaxGenerator.MemberAccessExpression(
                        whenInvocation,
                        syntaxGenerator.IdentifierName("Return")),
                    arguments: new[]
            {
                fromResultInvocation
            }));

            return(result);
        }
Example #6
0
        /// <inheritdoc />
        public SyntaxNode GenerateConfigureBehavior(
            ILogSink logSink,
            SyntaxGenerator syntaxGenerator,
            SemanticModel semanticModel,
            ISymbol symbol)
        {
            logSink.Debug(logSource, "Considering symbol '{0}'.", symbol);

            var propertySymbol = symbol as IPropertySymbol;
            var methodSymbol   = symbol as IMethodSymbol;

            INamedTypeSymbol returnType = null;

            if (propertySymbol != null)
            {
                if (propertySymbol.GetMethod == null)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a write-only property.", symbol);
                    return(null);
                }

                returnType = propertySymbol.GetMethod.ReturnType as INamedTypeSymbol;
            }
            else if (methodSymbol != null)
            {
                if (methodSymbol.AssociatedSymbol != null)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a method with an associated symbol.", symbol);
                    return(null);
                }

                if (methodSymbol.IsGenericMethod)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a generic method.", symbol);
                    return(null);
                }

                returnType = methodSymbol.ReturnType as INamedTypeSymbol;
            }
            else
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because it is neither a property nor a method.", symbol);
                return(null);
            }

            if (returnType == null)
            {
                logSink.Warn(logSource, "Ignoring symbol '{0}' because its return type could not be determined (it's probably a generic).", symbol);
                return(null);
            }

            var disposableInterfaceType = semanticModel
                                          .Compilation
                                          .GetTypeByMetadataName("System.IDisposable");

            if (disposableInterfaceType == null)
            {
                logSink.Warn(logSource, "Failed to resolve IDisposable type.");
                return(null);
            }

            if (returnType != disposableInterfaceType)
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because its return type is not IDisposable.");
                return(null);
            }

            var disposableType = semanticModel
                                 .Compilation
                                 .GetTypeByMetadataName("System.Reactive.Disposables.Disposable");

            if (disposableType == null)
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because Disposable type could not be resolved (probably a missing reference to System.Reactive.Core).");
                return(null);
            }

            var itType = semanticModel
                         .Compilation
                         .GetTypeByMetadataName("PCLMock.It");

            if (itType == null)
            {
                logSink.Error(logSource, "Failed to resolve It class.");
                return(null);
            }

            var isAnyMethod = itType
                              .GetMembers("IsAny")
                              .Single();

            if (isAnyMethod == null)
            {
                logSink.Error(logSource, "Failed to resolve IsAny method.");
                return(null);
            }

            var lambdaParameterName = symbol.GetUniqueName();

            SyntaxNode lambdaExpression;

            if (propertySymbol != null)
            {
                if (!propertySymbol.IsIndexer)
                {
                    // GENERATED CODE:
                    //
                    //     this
                    //         .When(x => x.SymbolName)
                    //         .Return(Disposable.Empty);
                    lambdaExpression = syntaxGenerator.MemberAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        propertySymbol.Name);
                }
                else
                {
                    // GENERATED CODE:
                    //
                    //     this
                    //         .When(x => x[It.IsAny<P1>(), It.IsAny<P2>() ...)
                    //         .Return(Disposable.Empty);
                    var whenArguments = propertySymbol
                                        .Parameters
                                        .Select(
                        parameter =>
                        syntaxGenerator.InvocationExpression(
                            syntaxGenerator.MemberAccessExpression(
                                syntaxGenerator.TypeExpression(itType),
                                syntaxGenerator.GenericName(
                                    "IsAny",
                                    typeArguments: new[]
                    {
                        parameter.Type
                    }))));

                    lambdaExpression = syntaxGenerator.ElementAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        arguments: whenArguments);
                }
            }
            else
            {
                // GENERATED CODE:
                //
                //     this
                //         .When(x => x.SymbolName(It.IsAny<P1>(), It.IsAny<P2>() ...)
                //         .Return(Disposable.Empty);
                var whenArguments = methodSymbol
                                    .Parameters
                                    .Select(
                    parameter =>
                    syntaxGenerator.InvocationExpression(
                        syntaxGenerator.MemberAccessExpression(
                            syntaxGenerator.TypeExpression(itType),
                            syntaxGenerator.GenericName(
                                "IsAny",
                                typeArguments: new[]
                {
                    parameter.Type
                }))));

                lambdaExpression = syntaxGenerator.InvocationExpression(
                    syntaxGenerator.MemberAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        methodSymbol.Name),
                    arguments: whenArguments);
            }

            var whenLambdaArgument = syntaxGenerator.ValueReturningLambdaExpression(
                lambdaParameterName,
                lambdaExpression);

            var whenInvocation = syntaxGenerator.InvocationExpression(
                syntaxGenerator.MemberAccessExpression(
                    syntaxGenerator.ThisExpression(),
                    syntaxGenerator.IdentifierName("When")),
                whenLambdaArgument);

            var result = syntaxGenerator.ExpressionStatement(
                syntaxGenerator.InvocationExpression(
                    syntaxGenerator.MemberAccessExpression(
                        whenInvocation,
                        syntaxGenerator.IdentifierName("Return")),
                    arguments: new[]
            {
                syntaxGenerator.MemberAccessExpression(
                    syntaxGenerator.TypeExpression(disposableType),
                    syntaxGenerator.IdentifierName("Empty"))
            }));

            return(result);
        }
Example #7
0
        /// <inheritdoc />
        public SyntaxNode GenerateConfigureBehavior(
            ILogSink logSink,
            SyntaxGenerator syntaxGenerator,
            SemanticModel semanticModel,
            ISymbol symbol)
        {
            logSink.Debug(logSource, "Considering symbol '{0}'.", symbol);

            var propertySymbol = symbol as IPropertySymbol;
            var methodSymbol   = symbol as IMethodSymbol;

            INamedTypeSymbol returnType = null;

            if (propertySymbol != null)
            {
                if (propertySymbol.GetMethod == null)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a write-only property.", symbol);
                    return(null);
                }

                returnType = propertySymbol.GetMethod.ReturnType as INamedTypeSymbol;
            }
            else if (methodSymbol != null)
            {
                if (methodSymbol.AssociatedSymbol != null)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a method with an associated symbol.", symbol);
                    return(null);
                }

                if (methodSymbol.IsGenericMethod)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a generic method.", symbol);
                    return(null);
                }

                returnType = methodSymbol.ReturnType as INamedTypeSymbol;
            }
            else
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because it is neither a property nor a method.", symbol);
                return(null);
            }

            if (returnType == null)
            {
                logSink.Warn(logSource, "Ignoring symbol '{0}' because its return type could not be determined (it's probably a sgeneric).", symbol);
                return(null);
            }

            var observableInterfaceType = semanticModel
                                          .Compilation
                                          .GetTypeByMetadataName("System.IObservable`1");

            var observableType = semanticModel
                                 .Compilation
                                 .GetTypeByMetadataName("System.Reactive.Linq.Observable");

            if (observableInterfaceType == null)
            {
                logSink.Warn(logSource, "Failed to resolve System.IObservable<T>.");
                return(null);
            }

            if (observableType == null)
            {
                logSink.Warn(logSource, "Failed to resolve System.Reactive.Linq.Observable.");
                return(null);
            }

            var itType = semanticModel
                         .Compilation
                         .GetTypeByMetadataName("PCLMock.It");

            if (itType == null)
            {
                logSink.Error(logSource, "Failed to resolve It class.");
                return(null);
            }

            var isAnyMethod = itType
                              .GetMembers("IsAny")
                              .Single();

            if (isAnyMethod == null)
            {
                logSink.Error(logSource, "Failed to resolve IsAny method.");
                return(null);
            }

            var isObservable = returnType.IsGenericType && returnType.ConstructedFrom == observableInterfaceType;

            if (!isObservable)
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because it does not return IObservable<T>.", symbol);
                return(null);
            }

            var observableInnerType = returnType.TypeArguments[0];
            var lambdaParameterName = symbol.GetUniqueName();

            SyntaxNode lambdaExpression;

            if (propertySymbol != null)
            {
                if (!propertySymbol.IsIndexer)
                {
                    // GENERATED CODE:
                    //
                    //     this
                    //         .When(x => x.SymbolName)
                    //         .Return(Observable.Empty<T>());
                    lambdaExpression = syntaxGenerator.MemberAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        propertySymbol.Name);
                }
                else
                {
                    // GENERATED CODE:
                    //
                    //     this
                    //         .When(x => x[It.IsAny<P1>(), It.IsAny<P2>() ...)
                    //         .Return(Observable.Empty<T>());
                    var whenArguments = propertySymbol
                                        .Parameters
                                        .Select(
                        parameter =>
                        syntaxGenerator.InvocationExpression(
                            syntaxGenerator.MemberAccessExpression(
                                syntaxGenerator.TypeExpression(itType),
                                syntaxGenerator.GenericName(
                                    "IsAny",
                                    typeArguments: new[]
                    {
                        parameter.Type
                    }))));

                    lambdaExpression = syntaxGenerator.ElementAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        arguments: whenArguments);
                }
            }
            else
            {
                // GENERATED CODE:
                //
                //     this
                //         .When(x => x.SymbolName(It.IsAny<P1>(), It.IsAny<P2>() ...)
                //         .Return(Observable.Return<T>(default(T)));
                var whenArguments = methodSymbol
                                    .Parameters
                                    .Select(
                    parameter =>
                    syntaxGenerator.InvocationExpression(
                        syntaxGenerator.MemberAccessExpression(
                            syntaxGenerator.TypeExpression(itType),
                            syntaxGenerator.GenericName(
                                "IsAny",
                                typeArguments: new[]
                {
                    parameter.Type
                }))));

                lambdaExpression = syntaxGenerator.InvocationExpression(
                    syntaxGenerator.MemberAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        methodSymbol.Name),
                    arguments: whenArguments);
            }

            var whenLambdaArgument = syntaxGenerator.ValueReturningLambdaExpression(
                lambdaParameterName,
                lambdaExpression);

            var whenInvocation = syntaxGenerator.InvocationExpression(
                syntaxGenerator.MemberAccessExpression(
                    syntaxGenerator.ThisExpression(),
                    syntaxGenerator.IdentifierName("When")),
                whenLambdaArgument);

            SyntaxNode observableInvocation;

            if (propertySymbol != null)
            {
                // properties are given collection semantics by returning Observable.Empty<T>()
                observableInvocation = syntaxGenerator.InvocationExpression(
                    syntaxGenerator.WithTypeArguments(
                        syntaxGenerator.MemberAccessExpression(
                            syntaxGenerator.TypeExpression(observableType),
                            "Empty"),
                        syntaxGenerator.TypeExpression(observableInnerType)));
            }
            else
            {
                // methods are given async operation semantics by returning Observable.Return(default(T))
                observableInvocation = syntaxGenerator.InvocationExpression(
                    syntaxGenerator.WithTypeArguments(
                        syntaxGenerator.MemberAccessExpression(
                            syntaxGenerator.TypeExpression(observableType),
                            "Return"),
                        syntaxGenerator.TypeExpression(observableInnerType)),
                    arguments: new[]
                {
                    syntaxGenerator.DefaultExpression(observableInnerType)
                });
            }

            var result = syntaxGenerator.ExpressionStatement(
                syntaxGenerator.InvocationExpression(
                    syntaxGenerator.MemberAccessExpression(
                        whenInvocation,
                        syntaxGenerator.IdentifierName("Return")),
                    arguments: new[]
            {
                observableInvocation
            }));

            return(result);
        }
Example #8
0
 public void Flush()
 {
     _sink.Error(_entry);
 }
Example #9
0
        /// <inheritdoc />
        public SyntaxNode GenerateConfigureBehavior(
            ILogSink logSink,
            SyntaxGenerator syntaxGenerator,
            SemanticModel semanticModel,
            ISymbol symbol)
        {
            logSink.Debug(logSource, "Considering symbol '{0}'.", symbol);

            var propertySymbol = symbol as IPropertySymbol;
            var methodSymbol   = symbol as IMethodSymbol;

            INamedTypeSymbol returnType = null;

            if (propertySymbol != null)
            {
                if (propertySymbol.GetMethod == null)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a write-only property.", symbol);
                    return(null);
                }

                returnType = propertySymbol.GetMethod.ReturnType as INamedTypeSymbol;
            }
            else if (methodSymbol != null)
            {
                if (methodSymbol.AssociatedSymbol != null)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a method with an associated symbol.", symbol);
                    return(null);
                }

                if (methodSymbol.IsGenericMethod)
                {
                    logSink.Debug(logSource, "Ignoring symbol '{0}' because it is a generic method.", symbol);
                    return(null);
                }

                returnType = methodSymbol.ReturnType as INamedTypeSymbol;
            }
            else
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because it is neither a property nor a method.", symbol);
                return(null);
            }

            if (returnType == null)
            {
                logSink.Warn(logSource, "Ignoring symbol '{0}' because its return type could not be determined (it's probably a generic).", symbol);
                return(null);
            }

            if (!returnType.IsGenericType)
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because its return type is not a generic type, so it cannot be one of the supported collection types.");
                return(null);
            }

            SyntaxNode returnValueSyntax;

            if (!TryGetReturnValueSyntaxForEnumerableReturnType(logSink, syntaxGenerator, semanticModel, returnType, out returnValueSyntax) &&
                !TryGetReturnValueSyntaxForCollectionReturnType(logSink, syntaxGenerator, semanticModel, returnType, out returnValueSyntax) &&
                !TryGetReturnValueSyntaxForDictionaryReturnType(logSink, syntaxGenerator, semanticModel, returnType, out returnValueSyntax) &&
                !TryGetReturnValueSyntaxForSetReturnType(logSink, syntaxGenerator, semanticModel, returnType, out returnValueSyntax) &&
                !TryGetReturnValueSyntaxForImmutableListReturnType(logSink, syntaxGenerator, semanticModel, returnType, out returnValueSyntax) &&
                !TryGetReturnValueSyntaxForImmutableDictionaryReturnType(logSink, syntaxGenerator, semanticModel, returnType, out returnValueSyntax) &&
                !TryGetReturnValueSyntaxForImmutableQueueReturnType(logSink, syntaxGenerator, semanticModel, returnType, out returnValueSyntax) &&
                !TryGetReturnValueSyntaxForImmutableSetReturnType(logSink, syntaxGenerator, semanticModel, returnType, out returnValueSyntax) &&
                !TryGetReturnValueSyntaxForImmutableStackReturnType(logSink, syntaxGenerator, semanticModel, returnType, out returnValueSyntax))
            {
                logSink.Debug(logSource, "Ignoring symbol '{0}' because it does not return a supported collection type.", symbol);
                return(null);
            }

            var itType = semanticModel
                         .Compilation
                         .GetTypeByMetadataName("PCLMock.It");

            if (itType == null)
            {
                logSink.Error(logSource, "Failed to resolve It class.");
                return(null);
            }

            var isAnyMethod = itType
                              .GetMembers("IsAny")
                              .Single();

            if (isAnyMethod == null)
            {
                logSink.Error(logSource, "Failed to resolve IsAny method.");
                return(null);
            }

            var lambdaParameterName = symbol.GetUniqueName();

            SyntaxNode lambdaExpression;

            if (propertySymbol != null)
            {
                if (!propertySymbol.IsIndexer)
                {
                    // GENERATED CODE:
                    //
                    //     this
                    //         .When(x => x.SymbolName)
                    //         .Return(returnValueSyntax);
                    lambdaExpression = syntaxGenerator.MemberAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        propertySymbol.Name);
                }
                else
                {
                    // GENERATED CODE:
                    //
                    //     this
                    //         .When(x => x[It.IsAny<P1>(), It.IsAny<P2>() ...)
                    //         .Return(returnValueSyntax);
                    var whenArguments = propertySymbol
                                        .Parameters
                                        .Select(
                        parameter =>
                        syntaxGenerator.InvocationExpression(
                            syntaxGenerator.MemberAccessExpression(
                                syntaxGenerator.TypeExpression(itType),
                                syntaxGenerator.GenericName(
                                    "IsAny",
                                    typeArguments: new[]
                    {
                        parameter.Type
                    }))));

                    lambdaExpression = syntaxGenerator.ElementAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        arguments: whenArguments);
                }
            }
            else
            {
                // GENERATED CODE:
                //
                //     this
                //         .When(x => x.SymbolName(It.IsAny<P1>(), It.IsAny<P2>() ...)
                //         .Return(returnValueSyntax);
                var whenArguments = methodSymbol
                                    .Parameters
                                    .Select(
                    parameter =>
                    syntaxGenerator.InvocationExpression(
                        syntaxGenerator.MemberAccessExpression(
                            syntaxGenerator.TypeExpression(itType),
                            syntaxGenerator.GenericName(
                                "IsAny",
                                typeArguments: new[]
                {
                    parameter.Type
                }))));

                lambdaExpression = syntaxGenerator.InvocationExpression(
                    syntaxGenerator.MemberAccessExpression(
                        syntaxGenerator.IdentifierName(lambdaParameterName),
                        methodSymbol.Name),
                    arguments: whenArguments);
            }

            var whenLambdaArgument = syntaxGenerator.ValueReturningLambdaExpression(
                lambdaParameterName,
                lambdaExpression);

            var whenInvocation = syntaxGenerator.InvocationExpression(
                syntaxGenerator.MemberAccessExpression(
                    syntaxGenerator.ThisExpression(),
                    syntaxGenerator.IdentifierName("When")),
                whenLambdaArgument);

            var result = syntaxGenerator.ExpressionStatement(
                syntaxGenerator.InvocationExpression(
                    syntaxGenerator.MemberAccessExpression(
                        whenInvocation,
                        syntaxGenerator.IdentifierName("Return")),
                    arguments: new[]
            {
                returnValueSyntax
            }));

            return(result);
        }