private static bool TryGetX(SyntaxNodeAnalysisContext context, out ReflectedMember member, out Name name, out Flags flags, out Types types)
        {
            name = default(Name);
            if (context.Node is InvocationExpressionSyntax candidate)
            {
                return(GetX.TryMatchGetConstructor(candidate, context, out member, out flags, out types) ||
                       GetX.TryMatchGetEvent(candidate, context, out member, out name, out flags) ||
                       GetX.TryMatchGetField(candidate, context, out member, out name, out flags) ||
                       GetX.TryMatchGetMethod(candidate, context, out member, out name, out flags, out types) ||
                       GetX.TryMatchGetNestedType(candidate, context, out member, out name, out flags) ||
                       GetX.TryMatchGetProperty(candidate, context, out member, out name, out flags, out types));
            }

            member = default(ReflectedMember);
            flags  = default(Flags);
            types  = default(Types);
            return(false);
        }
Exemplo n.º 2
0
        private static bool TryGet(ExpressionSyntax expression, SyntaxNodeAnalysisContext context, PooledSet <ExpressionSyntax> visited, out ITypeSymbol result, out ExpressionSyntax source)
        {
            switch (expression)
            {
            case MemberAccessExpressionSyntax memberAccess when memberAccess.Name.Identifier.ValueText == "ReturnType" &&
                memberAccess.Expression is InvocationExpressionSyntax invocation &&
                GetX.TryMatchGetMethod(invocation, context, out var reflectedMember, out _, out _, out _) &&
                reflectedMember.Match == FilterMatch.Single &&
                reflectedMember.Symbol is IMethodSymbol method:
                source = memberAccess;
                result = method.ReturnType;
                return(true);

            case MemberAccessExpressionSyntax memberAccess when memberAccess.Name.Identifier.ValueText == "FieldType" &&
                memberAccess.Expression is InvocationExpressionSyntax invocation &&
                GetX.TryMatchGetField(invocation, context, out var reflectedMember, out _, out _) &&
                reflectedMember.Match == FilterMatch.Single &&
                reflectedMember.Symbol is IFieldSymbol field:
                source = memberAccess;
                result = field.Type;
                return(true);

            case MemberAccessExpressionSyntax memberAccess when memberAccess.Name.Identifier.ValueText == "PropertyType" &&
                memberAccess.Expression is InvocationExpressionSyntax invocation &&
                GetX.TryMatchGetProperty(invocation, context, out var reflectedMember, out _, out _, out _) &&
                reflectedMember.Match == FilterMatch.Single &&
                reflectedMember.Symbol is IPropertySymbol field:
                source = memberAccess;
                result = field.Type;
                return(true);

            case TypeOfExpressionSyntax typeOf:
                source = typeOf;
                return(context.SemanticModel.TryGetType(typeOf.Type, context.CancellationToken, out result));

            case InvocationExpressionSyntax invocation when invocation.ArgumentList is ArgumentListSyntax args &&
                args.Arguments.Count == 0 &&
                invocation.TryGetMethodName(out var name) &&
                name == "GetType":
                switch (invocation.Expression)
                {
                case MemberAccessExpressionSyntax typeAccess:
                    source = invocation;
                    if (context.SemanticModel.TryGetType(typeAccess.Expression, context.CancellationToken, out result))
                    {
                        if (result is INamedTypeSymbol namedType &&
                            namedType.ConstructedFrom?.SpecialType == SpecialType.System_Nullable_T)
                        {
                            result = namedType.TypeArguments[0];
                        }

                        return(true);
                    }

                    return(false);

                case IdentifierNameSyntax _ when expression.TryFirstAncestor(out TypeDeclarationSyntax containingType):
                    source = invocation;

                    return(context.SemanticModel.TryGetSymbol(containingType, context.CancellationToken, out result));

                case MemberBindingExpressionSyntax memberBinding when memberBinding.Parent?.Parent is ConditionalAccessExpressionSyntax conditionalAccess:
                    source = invocation;
                    return(context.SemanticModel.TryGetType(conditionalAccess.Expression, context.CancellationToken, out result));
                }

                break;

            case InvocationExpressionSyntax candidate when TryMatchTypeGetType(candidate, context, out var typeName, out var ignoreCase):
                source = candidate;

                result = context.Compilation.GetTypeByMetadataName(typeName, ignoreCase.Value);
                return(result != null);

            case InvocationExpressionSyntax candidate when TryMatchAssemblyGetType(candidate, context, out var typeName, out var ignoreCase):
                source = candidate;

                result = Assembly.TryGet(candidate.Expression, context, out var assembly)
                        ? assembly.GetTypeByMetadataName(typeName, ignoreCase.Value)
                        : null;
                return(result != null);

            case InvocationExpressionSyntax invocation when invocation.TryGetTarget(KnownSymbol.Type.GetGenericTypeDefinition, context.SemanticModel, context.CancellationToken, out _) &&
                invocation.Expression is MemberAccessExpressionSyntax memberAccess &&
                TryGet(memberAccess.Expression, context, visited, out var definingType, out _) &&
                definingType is INamedTypeSymbol namedType:
                source = invocation;

                result = namedType.ConstructedFrom;
                return(true);

            case InvocationExpressionSyntax invocation when GetX.TryMatchGetNestedType(invocation, context, out var reflectedMember, out _, out _):
                source = invocation;

                result = reflectedMember.Symbol as ITypeSymbol;
                return(result != null && reflectedMember.Match == FilterMatch.Single);

            case InvocationExpressionSyntax invocation when invocation.TryGetTarget(KnownSymbol.Type.MakeGenericType, context.SemanticModel, context.CancellationToken, out _) &&
                invocation.Expression is MemberAccessExpressionSyntax memberAccess &&
                TypeArguments.TryCreate(invocation, context, out var typeArguments) &&
                typeArguments.TryGetArgumentsTypes(context, out var types):
#pragma warning disable IDISP003 // Dispose previous before re-assigning.
                using (visited = visited.IncrementUsage())
#pragma warning restore IDISP003 // Dispose previous before re-assigning.
                {
                    if (visited.Add(invocation) &&
                        TryGet(memberAccess.Expression, context, visited, out var definition, out _) &&
                        definition is INamedTypeSymbol namedType)
                    {
                        source = invocation;
                        result = namedType.Construct(types);
                        return(result != null);
                    }
                }

                break;

            case ConditionalAccessExpressionSyntax conditionalAccess:
                source = conditionalAccess;
                return(TryGet(conditionalAccess.WhenNotNull, context, out result, out _));
            }

            if (expression.IsEither(SyntaxKind.IdentifierName, SyntaxKind.SimpleMemberAccessExpression) &&
                context.SemanticModel.TryGetSymbol(expression, context.CancellationToken, out ISymbol local))
            {
#pragma warning disable IDISP003 // Dispose previous before re-assigning.
                using (visited = visited.IncrementUsage())
#pragma warning restore IDISP003 // Dispose previous before re-assigning.
                {
                    source = null;
                    result = null;
                    return(AssignedValue.TryGetSingle(local, context.SemanticModel, context.CancellationToken, out var assignedValue) &&
                           visited.Add(assignedValue) &&
                           TryGet(assignedValue, context, visited, out result, out source));
                }
            }

            source = null;
            result = null;
            return(false);
        }