private ITypeSymbol[] GetArgumentTypeInfo(SubstituteContext <TInvocationExpression> substituteContext, TArgumentSyntax arrayArgument)
        {
            var typeInfo = GetTypeInfo(substituteContext, arrayArgument.DescendantNodes().First());

            if (typeInfo.ConvertedType != null &&
                typeInfo.ConvertedType.TypeKind == TypeKind.Array &&
                typeInfo.Type == null)
            {
                return(null);
            }

            // new object[] { }; // means we dont pass any arguments
            var parameterExpressionsFromArrayArgument = GetParameterExpressionsFromArrayArgument(arrayArgument);

            if (parameterExpressionsFromArrayArgument == null)
            {
                return(null);
            }

            // new object[] { 1, 2, 3}); // means we pass arguments
            var types = parameterExpressionsFromArrayArgument
                        .Select(exp => GetTypeInfo(substituteContext, exp).Type)
                        .ToArray();

            return(types);
        }
Exemple #2
0
        private void AnalyzePartialSubstitute(SubstituteContext <TInvocationExpressionSyntax> substituteContext)
        {
            if (AnalyzeProxies(substituteContext))
            {
                return;
            }

            var proxyType = _substituteProxyAnalysis.GetActualProxyTypeSymbol(substituteContext);

            if (proxyType == null)
            {
                return;
            }

            if (AnalyzeTypeKind(substituteContext, proxyType))
            {
                return;
            }

            if (AnalyzeTypeAccessability(substituteContext, proxyType))
            {
                return;
            }

            if (proxyType.TypeKind != TypeKind.Class)
            {
                return;
            }

            var constructorContext = _substituteConstructorAnalysis.CollectConstructorContext(substituteContext, proxyType);

            AnalyzeConstructor(substituteContext, constructorContext);
        }
        private bool AnalyzeConstructorInvocation(SubstituteContext <TInvocationExpressionSyntax> substituteContext, ConstructorContext constructorContext)
        {
            if (constructorContext.ConstructorType.TypeKind != TypeKind.Class || constructorContext.InvocationParameters == null || constructorContext.PossibleConstructors == null)
            {
                return(false);
            }

            if (constructorContext.PossibleConstructors.All(ctor =>
                                                            SubstituteConstructorMatcher.MatchesInvocation(
                                                                substituteContext.SyntaxNodeAnalysisContext.SemanticModel.Compilation, ctor, constructorContext.InvocationParameters) ==
                                                            false))
            {
                var symbol     = substituteContext.SyntaxNodeAnalysisContext.SemanticModel.GetSymbolInfo(substituteContext.InvocationExpression);
                var x          = symbol.Symbol.ToMinimalDisplayString(substituteContext.SyntaxNodeAnalysisContext.SemanticModel, 10, SymbolDisplayFormat.CSharpErrorMessageFormat);
                var diagnostic = Diagnostic.Create(
                    DiagnosticDescriptorsProvider.SubstituteConstructorMismatch,
                    substituteContext.InvocationExpression.GetLocation(),
                    symbol.Symbol.ToMinimalMethodString(substituteContext.SyntaxNodeAnalysisContext.SemanticModel),
                    constructorContext.ConstructorType.ToString());

                substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic);
                return(true);
            }

            return(false);
        }
        private void AnalyzeSubstituteForPartsOf(SubstituteContext <TInvocationExpressionSyntax> substituteContext)
        {
            var proxyType = substituteContext.MethodSymbol.TypeArguments.FirstOrDefault();

            if (proxyType == null)
            {
                return;
            }

            if (AnalyzeTypeKind(substituteContext, proxyType))
            {
                return;
            }

            if (AnalyzeTypeAccessability(substituteContext, proxyType))
            {
                return;
            }

            if (proxyType.TypeKind != TypeKind.Class)
            {
                return;
            }

            var constructorContext = SubstituteConstructorAnalysis.CollectConstructorContext(substituteContext, proxyType);

            AnalyzeConstructor(substituteContext, constructorContext);
        }
        private ITypeSymbol[] GetGenericInvocationArgumentTypes(SubstituteContext <TInvocationExpression> substituteContext)
        {
            var arguments = GetInvocationArguments(substituteContext.InvocationExpression);

            if (arguments == null)
            {
                return(null);
            }

            if (arguments.Count == 0)
            {
                return(Array.Empty <ITypeSymbol>());
            }

            var typeInfos = arguments.Select(arg => GetTypeInfo(substituteContext, arg.DescendantNodes().First()))
                            .ToList();

            var possibleParamsArgument = typeInfos.First();

            // if passing array of objects as a sole element
            if (arguments.Count == 1 &&
                possibleParamsArgument.ConvertedType is IArrayTypeSymbol arrayTypeSymbol &&
                arrayTypeSymbol.ElementType.Equals(substituteContext.SyntaxNodeAnalysisContext.Compilation.ObjectType))
            {
                return(GetArgumentTypeInfo(substituteContext, arguments.First()));
            }

            return(typeInfos.Select(type => type.Type).ToArray());
        }
        private ITypeSymbol[] GetInvocationInfo(SubstituteContext <TInvocationExpression> substituteContext)
        {
            var infos = substituteContext.MethodSymbol.IsGenericMethod
                ? GetGenericInvocationArgumentTypes(substituteContext)
                : GetNonGenericInvocationArgumentTypes(substituteContext);

            return(infos);
        }
Exemple #7
0
        public ITypeSymbol GetActualProxyTypeSymbol(SubstituteContext <TInvocationExpressionSyntax> substituteContext)
        {
            var proxies = GetProxySymbols(substituteContext).ToList();

            var classSymbol = proxies.FirstOrDefault(symbol => symbol.TypeKind == TypeKind.Class);

            return(classSymbol ?? proxies.FirstOrDefault());
        }
        private ITypeSymbol[] GetNonGenericInvocationArgumentTypes(SubstituteContext <TInvocationExpression> substituteContext)
        {
            // Substitute.For(new [] { typeof(T) }, new object[] { 1, 2, 3}) // actual arguments reside in second arg
            var arrayArgument = GetInvocationArguments(substituteContext.InvocationExpression)?.Skip(1).FirstOrDefault();

            if (arrayArgument == null)
            {
                return(null);
            }

            return(GetArgumentTypeInfo(substituteContext, arrayArgument));
        }
Exemple #9
0
        private bool AnalyzeTypeAccessability(SubstituteContext <TInvocationExpressionSyntax> substituteContext, ITypeSymbol proxyType)
        {
            if (proxyType.DeclaredAccessibility == Accessibility.Internal && proxyType.InternalsVisibleToProxyGenerator() == false)
            {
                var diagnostic = Diagnostic.Create(
                    DiagnosticDescriptorsProvider.SubstituteForInternalMember,
                    substituteContext.InvocationExpression.GetLocation());

                substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic);
                return(true);
            }

            return(false);
        }
        private bool AnalyzeTypeKind(SubstituteContext <TInvocationExpressionSyntax> substituteContext, ITypeSymbol proxyType)
        {
            if (proxyType.TypeKind == TypeKind.Interface || proxyType.TypeKind == TypeKind.Delegate)
            {
                var diagnostic = Diagnostic.Create(
                    DiagnosticDescriptorsProvider.SubstituteForPartsOfUsedForInterface,
                    substituteContext.InvocationExpression.GetLocation(),
                    proxyType.ToString());

                substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic);
                return(true);
            }

            return(false);
        }
Exemple #11
0
        private bool AnalyzeConstructorAccessibility(SubstituteContext <TInvocationExpressionSyntax> substituteContext, ConstructorContext constructorContext)
        {
            if (constructorContext.ConstructorType.TypeKind == TypeKind.Class && constructorContext.AccessibleConstructors != null && constructorContext.AccessibleConstructors.Any() == false)
            {
                var diagnostic = Diagnostic.Create(
                    DiagnosticDescriptorsProvider.SubstituteForWithoutAccessibleConstructor,
                    substituteContext.InvocationExpression.GetLocation(),
                    constructorContext.ConstructorType.ToString());

                substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic);
                return(true);
            }

            return(false);
        }
Exemple #12
0
        private bool AnalyzeTypeKind(SubstituteContext <TInvocationExpressionSyntax> substituteContext, ITypeSymbol proxyType)
        {
            if (proxyType.TypeKind == TypeKind.Interface || proxyType.TypeKind == TypeKind.Delegate)
            {
                var diagnostic = Diagnostic.Create(
                    DiagnosticDescriptorsProvider.PartialSubstituteForUnsupportedType,
                    substituteContext.InvocationExpression.GetLocation(),
                    GetCorrespondingSubstituteMethod(substituteContext.InvocationExpression, substituteContext.MethodSymbol),
                    substituteContext.InvocationExpression.ToString());

                substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic);
                return(true);
            }

            return(false);
        }
Exemple #13
0
        private bool AnalyzeConstructorParametersCount(SubstituteContext <TInvocationExpressionSyntax> substituteContext, ConstructorContext constructorContext)
        {
            var invocationArgumentTypes = constructorContext.InvocationParameters?.Length;

            switch (constructorContext.ConstructorType.TypeKind)
            {
            case TypeKind.Interface when invocationArgumentTypes > 0:
                var diagnostic = Diagnostic.Create(
                    DiagnosticDescriptorsProvider.SubstituteConstructorArgumentsForInterface,
                    substituteContext.InvocationExpression.GetLocation(),
                    GetSubstituteMethodWithoutConstructorArguments(substituteContext.InvocationExpression, substituteContext.MethodSymbol));

                substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic);
                return(true);

            case TypeKind.Interface:
                return(false);

            case TypeKind.Delegate when invocationArgumentTypes > 0:
                var delegateDiagnostic = Diagnostic.Create(
                    DiagnosticDescriptorsProvider.SubstituteConstructorArgumentsForDelegate,
                    substituteContext.InvocationExpression.GetLocation(),
                    GetSubstituteMethodWithoutConstructorArguments(substituteContext.InvocationExpression, substituteContext.MethodSymbol));

                substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(delegateDiagnostic);
                return(true);

            case TypeKind.Delegate:
                return(false);
            }

            if (constructorContext.PossibleConstructors != null && constructorContext.PossibleConstructors.Any() == false)
            {
                var symbol     = substituteContext.SyntaxNodeAnalysisContext.SemanticModel.GetSymbolInfo(substituteContext.InvocationExpression);
                var diagnostic = Diagnostic.Create(
                    DiagnosticDescriptorsProvider.SubstituteForConstructorParametersMismatch,
                    substituteContext.InvocationExpression.GetLocation(),
                    symbol.Symbol.ToMinimalMethodString(substituteContext.SyntaxNodeAnalysisContext.SemanticModel),
                    constructorContext.ConstructorType);

                substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic);
                return(true);
            }

            return(false);
        }
Exemple #14
0
        private bool AnalyzeProxies(SubstituteContext <TInvocationExpressionSyntax> substituteContext)
        {
            var proxies      = _substituteProxyAnalysis.GetProxySymbols(substituteContext).ToList();
            var classProxies = proxies.Where(proxy => proxy.TypeKind == TypeKind.Class).Distinct();

            if (classProxies.Count() > 1)
            {
                var diagnostic = Diagnostic.Create(
                    DiagnosticDescriptorsProvider.SubstituteMultipleClasses,
                    substituteContext.InvocationExpression.GetLocation());

                substituteContext.SyntaxNodeAnalysisContext.ReportDiagnostic(diagnostic);
                return(true);
            }

            return(false);
        }
Exemple #15
0
        private void AnalyzeConstructor(SubstituteContext <TInvocationExpressionSyntax> substituteContext, ConstructorContext constructorContext)
        {
            if (AnalyzeConstructorAccessibility(substituteContext, constructorContext))
            {
                return;
            }

            if (AnalyzeConstructorParametersCount(substituteContext, constructorContext))
            {
                return;
            }

            if (AnalyzeConstructorInvocation(substituteContext, constructorContext))
            {
                return;
            }
        }
        public ConstructorContext CollectConstructorContext(SubstituteContext <TInvocationExpression> substituteContext, ITypeSymbol proxyTypeSymbol)
        {
            if (proxyTypeSymbol.Kind == SymbolKind.TypeParameter)
            {
                return(new ConstructorContext(proxyTypeSymbol, null, null, null));
            }

            var accessibleConstructors   = GetAccessibleConstructors(proxyTypeSymbol);
            var invocationParameterTypes = GetInvocationInfo(substituteContext);
            var possibleConstructors     = invocationParameterTypes != null && accessibleConstructors != null
                ? accessibleConstructors.Where(ctor => ctor.Parameters.Length == invocationParameterTypes.Length)
                                           .ToArray()
                : null;

            return(new ConstructorContext(
                       proxyTypeSymbol,
                       accessibleConstructors,
                       possibleConstructors,
                       invocationParameterTypes));
        }
        private void AnalyzeSubstituteForMethod(SubstituteContext <TInvocationExpressionSyntax> substituteContext)
        {
            if (AnalyzeProxies(substituteContext))
            {
                return;
            }

            var proxyType = SubstituteProxyAnalysis.GetActualProxyTypeSymbol(substituteContext);

            if (proxyType == null)
            {
                return;
            }

            if (AnalyzeTypeAccessability(substituteContext, proxyType))
            {
                return;
            }

            var constructorContext = SubstituteConstructorAnalysis.CollectConstructorContext(substituteContext, proxyType);

            AnalyzeConstructor(substituteContext, constructorContext);
        }
Exemple #18
0
        private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext)
        {
            var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node;
            var methodSymbolInfo     = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression);

            if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method)
            {
                return;
            }

            var methodSymbol = (IMethodSymbol)methodSymbolInfo.Symbol;

            if (methodSymbol == null || methodSymbol.MethodKind != MethodKind.Ordinary)
            {
                return;
            }

            if (methodSymbol.IsSubstituteCreateLikeMethod() == false)
            {
                return;
            }

            var substituteContext = new SubstituteContext <TInvocationExpressionSyntax>(syntaxNodeContext, invocationExpression, methodSymbol);

            if (methodSymbol.Name.Equals(MetadataNames.NSubstituteForMethod, StringComparison.Ordinal) ||
                methodSymbol.Name.Equals(MetadataNames.SubstituteFactoryCreate, StringComparison.Ordinal))
            {
                AnalyzeSubstitute(substituteContext);
                return;
            }

            if (methodSymbol.Name.Equals(MetadataNames.NSubstituteForPartsOfMethod, StringComparison.Ordinal) ||
                methodSymbol.Name.Equals(MetadataNames.SubstituteFactoryCreatePartial, StringComparison.Ordinal))
            {
                AnalyzePartialSubstitute(substituteContext);
            }
        }
Exemple #19
0
        public ImmutableArray <ITypeSymbol> GetProxySymbols(SubstituteContext <TInvocationExpressionSyntax> substituteContext)
        {
            if (substituteContext.MethodSymbol.IsGenericMethod)
            {
                return(substituteContext.MethodSymbol.TypeArguments);
            }

            var arrayParameters = GetArrayInitializerArguments(substituteContext.InvocationExpression)?.ToList();

            if (arrayParameters == null)
            {
                return(ImmutableArray <ITypeSymbol> .Empty);
            }

            var proxyTypes = GetTypeOfLikeExpressions(arrayParameters)
                             .Select(exp =>
                                     substituteContext.SyntaxNodeAnalysisContext.SemanticModel
                                     .GetTypeInfo(exp.DescendantNodes().First()))
                             .Where(model => model.Type != null)
                             .Select(model => model.Type)
                             .ToImmutableArray();

            return(arrayParameters.Count == proxyTypes.Length ? proxyTypes : ImmutableArray <ITypeSymbol> .Empty);
        }
 public ImmutableArray <ITypeSymbol> GetProxySymbols(SubstituteContext <TInvocationExpressionSyntax> substituteContext)
 {
     return(GetProxySymbols(substituteContext.SyntaxNodeAnalysisContext.SemanticModel, substituteContext.InvocationExpression, substituteContext.MethodSymbol));
 }
 public ITypeSymbol GetActualProxyTypeSymbol(SubstituteContext <TInvocationExpressionSyntax> substituteContext)
 {
     return(GetActualProxyTypeSymbol(substituteContext.SyntaxNodeAnalysisContext.SemanticModel, substituteContext.InvocationExpression, substituteContext.MethodSymbol));
 }
 private TypeInfo GetTypeInfo(SubstituteContext <TInvocationExpression> substituteContext, SyntaxNode syntax)
 {
     return(substituteContext.SyntaxNodeAnalysisContext.SemanticModel.GetTypeInfo(syntax));
 }