internal static bool TryCreate(IMethodSymbol getX, InvocationExpressionSyntax invocation, INamedTypeSymbol type, ExpressionSyntax typeSource, Name name, BindingFlags flags, Types types, Compilation compilation, out ReflectedMember member)
        {
            var match = TryGetMember(getX, type, name, flags, types, compilation, out var memberSymbol);

            member = new ReflectedMember(type, typeSource, memberSymbol, getX, invocation, match);
            return(true);
        }
Beispiel #2
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is InvocationExpressionSyntax invocation &&
                invocation.TryGetTarget(KnownSymbol.Type.GetInterface, context.SemanticModel, context.CancellationToken, out var getInterface) &&
                getInterface.TryFindParameter(KnownSymbol.String, out var nameParameter) &&
                invocation.TryFindArgument(nameParameter, out var nameArg) &&
                TryGetName(nameArg, context, out var maybeNameSyntax, out var name) &&
                ReflectedMember.TryGetType(invocation, context, out var type, out _))
            {
                var count = CountInterfaces(type, name, out var match);

                if (count > 1)
                {
                    context.ReportDiagnostic(Diagnostic.Create(REFL020AmbiguousMatchInterface.Descriptor, nameArg.GetLocation()));
                }

                if (count == 1 && match.MetadataName == name)
                {
                    switch (nameArg.Expression)
                    {
                    case LiteralExpressionSyntax literal when literal.IsKind(SyntaxKind.StringLiteralExpression):
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL022UseFullyQualifiedName.Descriptor,
                                literal.GetLocation(),
                                ImmutableDictionary <string, string> .Empty.Add(
                                    nameof(SyntaxKind.StringLiteralExpression),
                                    $"{match.ContainingNamespace}.{match.MetadataName}")));

                        break;

                    default:
                        if (maybeNameSyntax.HasValue &&
                            maybeNameSyntax.Value.Identifier.ValueText == "Name")
                        {
                            context.ReportDiagnostic(
                                Diagnostic.Create(
                                    REFL022UseFullyQualifiedName.Descriptor,
                                    maybeNameSyntax.Value.Identifier.GetLocation(),
                                    ImmutableDictionary <string, string> .Empty.Add(
                                        nameof(SimpleNameSyntax),
                                        "FullName")));
                        }
                        else
                        {
                            context.ReportDiagnostic(Diagnostic.Create(REFL022UseFullyQualifiedName.Descriptor, nameArg.GetLocation()));
                        }

                        break;
                    }
                }

                if (count == 0)
                {
                    context.ReportDiagnostic(Diagnostic.Create(REFL023TypeDoesNotImplementInterface.Descriptor, nameArg.GetLocation()));
                }
            }
        }
        private static bool HasRedundantFlag(ReflectedMember member, Flags flags, out string flagsText)
        {
            if (member.Match != FilterMatch.Single ||
                !member.ReflectedType.Locations.Any(x => x.IsInSource))
            {
                flagsText = null;
                return(false);
            }

            if (flags.Argument is ArgumentSyntax argument &&
                Flags.TryGetExpectedBindingFlags(member.ReflectedType, member.Symbol, out var expectedFlags))
            {
                if (member.Symbol is IMethodSymbol method &&
                    method.MethodKind == MethodKind.Constructor &&
                    (flags.Explicit.HasFlagFast(BindingFlags.DeclaredOnly) ||
                     flags.Explicit.HasFlagFast(BindingFlags.FlattenHierarchy)))
                {
                    flagsText = expectedFlags.ToDisplayString(argument);
                    return(true);
                }

                if (member.Symbol is ITypeSymbol &&
                    (flags.Explicit.HasFlagFast(BindingFlags.Instance) ||
                     flags.Explicit.HasFlagFast(BindingFlags.Static) ||
                     flags.Explicit.HasFlagFast(BindingFlags.DeclaredOnly) ||
                     flags.Explicit.HasFlagFast(BindingFlags.FlattenHierarchy)))
                {
                    flagsText = expectedFlags.ToDisplayString(argument);
                    return(true);
                }

                if ((member.Symbol.DeclaredAccessibility == Accessibility.Public &&
                     flags.Explicit.HasFlagFast(BindingFlags.NonPublic)) ||
                    (member.Symbol.DeclaredAccessibility != Accessibility.Public &&
                     flags.Explicit.HasFlagFast(BindingFlags.Public)) ||
                    (member.Symbol.IsStatic &&
                     flags.Explicit.HasFlagFast(BindingFlags.Instance)) ||
                    (!member.Symbol.IsStatic &&
                     flags.Explicit.HasFlagFast(BindingFlags.Static)) ||
                    (!member.Symbol.IsStatic &&
                     flags.Explicit.HasFlagFast(BindingFlags.FlattenHierarchy)) ||
                    (Equals(member.Symbol.ContainingType, member.ReflectedType) &&
                     flags.Explicit.HasFlagFast(BindingFlags.FlattenHierarchy)) ||
                    (!Equals(member.Symbol.ContainingType, member.ReflectedType) &&
                     flags.Explicit.HasFlagFast(BindingFlags.DeclaredOnly)) ||
                    flags.Explicit.HasFlagFast(BindingFlags.IgnoreCase))
                {
                    flagsText = expectedFlags.ToDisplayString(argument);
                    return(true);
                }
            }

            flagsText = null;
            return(false);
        }
        private static bool HasMissingFlags(ReflectedMember member, Flags flags, out Location location, out string flagsText)
        {
            if (Flags.TryGetExpectedBindingFlags(member.ReflectedType, member.Symbol, out var correctFlags) &&
                member.Invocation?.ArgumentList is ArgumentListSyntax argumentList &&
                (member.Match == FilterMatch.Single || member.Match == FilterMatch.WrongFlags))
            {
                if (flags.Argument == null)
                {
                    location  = MissingFlagsLocation();
                    flagsText = correctFlags.ToDisplayString(member.Invocation);
                    return(true);
                }

                if (flags.Argument is ArgumentSyntax argument &&
                    HasMissingFlag())
                {
                    location  = argument.GetLocation();
                    flagsText = correctFlags.ToDisplayString(member.Invocation);
                    return(true);
                }
            }

            location  = null;
            flagsText = null;
            return(false);

            bool HasMissingFlag()
            {
                if (member.Symbol is ITypeSymbol ||
                    (member.Symbol is IMethodSymbol method &&
                     method.MethodKind == MethodKind.Constructor))
                {
                    return(false);
                }

                return(Equals(member.Symbol.ContainingType, member.ReflectedType) &&
                       !flags.Explicit.HasFlagFast(BindingFlags.DeclaredOnly));
            }

            Location MissingFlagsLocation()
            {
                return(member.GetX == KnownSymbol.Type.GetConstructor
                    ? argumentList.OpenParenToken.GetLocation()
                    : argumentList.CloseParenToken.GetLocation());
            }
        }
        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);
        }
Beispiel #6
0
        private static bool HasMissingTypes(ReflectedMember member, Types types, SyntaxNodeAnalysisContext context, out string typesArrayText)
        {
            if ((member.Symbol as IMethodSymbol)?.AssociatedSymbol != null)
            {
                typesArrayText = null;
                return false;
            }

            if (member.Match == FilterMatch.Single &&
                types.Argument == null &&
                member.GetX == KnownSymbol.Type.GetMethod &&
                member.Symbol is IMethodSymbol method &&
                !method.IsGenericMethod)
            {
                return Types.TryGetTypesArrayText(method.Parameters, context.SemanticModel, context.Node.SpanStart, out typesArrayText);
            }

            typesArrayText = null;
            return false;
        }
        private static bool IsPreferGetMemberThenAccessor(ReflectedMember member, Name name, Flags flags, Types types, SyntaxNodeAnalysisContext context, out string callText)
        {
            if (member.Invocation?.Expression is MemberAccessExpressionSyntax memberAccess)
            {
                if (member.Symbol is IMethodSymbol method &&
                    member.Match == FilterMatch.Single)
                {
                    if (method.AssociatedSymbol is IPropertySymbol property &&
                        Flags.TryGetExpectedBindingFlags(property.ContainingType, property, out var bindingFlags))
                    {
                        return(TryGetPropertyAccessor(MemberName(property), bindingFlags, property.Type, out callText));
                    }

                    if (method.AssociatedSymbol is IEventSymbol eventSymbol &&
                        Flags.TryGetExpectedBindingFlags(eventSymbol.ContainingType, eventSymbol, out bindingFlags))
                    {
                        return(TryGetEventAccessor(MemberName(eventSymbol), bindingFlags, out callText));
                    }
                }
                else if (member.Match == FilterMatch.PotentiallyInvisible &&
                         types.Argument == null &&
                         flags.Explicit.HasFlagFast(BindingFlags.NonPublic))
                {
                    if (TryGetInvisibleMemberName("get_", out var memberName) ||
                        TryGetInvisibleMemberName("set_", out memberName))
                    {
                        return(TryGetPropertyAccessor(memberName, flags.Explicit, null, out callText));
                    }

                    if (TryGetInvisibleMemberName("add_", out memberName) ||
                        TryGetInvisibleMemberName("remove_", out memberName) ||
                        TryGetInvisibleMemberName("raise_", out memberName))
                    {
                        return(TryGetEventAccessor(memberName, flags.Explicit, out callText));
                    }
                }
            }
Beispiel #8
0
        internal static bool TryGetExpressionText(ReflectedMember member, SyntaxNodeAnalysisContext context, out string targetName)
        {
            targetName = null;
            if (member.Symbol.ContainingType.IsAnonymousType)
            {
                if (member.TypeSource is InvocationExpressionSyntax getType &&
                    getType.TryGetTarget(KnownSymbol.Object.GetType, context.SemanticModel, context.CancellationToken, out _) &&
                    getType.Expression is MemberAccessExpressionSyntax memberAccess &&
                    memberAccess.Expression is IdentifierNameSyntax identifierName)
                {
                    targetName = $"{identifierName}.{member.Symbol.Name}";
                    return(true);
                }

                return(false);
            }

            if (!context.SemanticModel.IsAccessible(context.Node.SpanStart, member.Symbol) ||
                (member.Symbol is INamedTypeSymbol type && type.IsGenericType) ||
                (member.Symbol is IMethodSymbol method &&
                 method.AssociatedSymbol != null))
            {
                return(false);
            }

            if (context.ContainingSymbol.ContainingType.IsAssignableTo(member.Symbol.ContainingType, context.Compilation))
            {
                targetName = member.Symbol.IsStatic ||
                             member.Symbol is ITypeSymbol ||
                             IsStaticContext(context)
                    ? $"{member.Symbol.Name}"
                    : context.SemanticModel.UnderscoreFields()
                        ? $"{member.Symbol.Name}"
                        : $"this.{member.Symbol.Name}";
                return(true);
            }

            if (member.Symbol.ContainingType.TupleUnderlyingType is INamedTypeSymbol tupleType)
            {
                targetName = member.Symbol is IFieldSymbol field &&
                             field.CorrespondingTupleField is IFieldSymbol tupleField
                    ? $"{TypeOfString(tupleType)}.{tupleField.Name}"
                    : $"{TypeOfString(tupleType)}.{member.Symbol.Name}";
                return(true);
            }

            targetName = context.SemanticModel.IsAccessible(context.Node.SpanStart, member.Symbol)
                ? $"{TypeOfString(member.Symbol.ContainingType)}.{member.Symbol.Name}"
                : $"\"{member.Symbol.Name}\"";
            return(true);

            string TypeOfString(ITypeSymbol t)
            {
                if (t is INamedTypeSymbol namedType &&
                    namedType.TupleUnderlyingType is INamedTypeSymbol utt &&
                    utt != namedType)
                {
                    return(TypeOfString(utt));
                }

                return(t.ToMinimalDisplayString(context.SemanticModel, context.Node.SpanStart, Format));
            }
        }
Beispiel #9
0
 /// <summary>
 /// Check if <paramref name="invocation"/> is a call to Type.GetEvent.
 /// </summary>
 internal static bool TryMatchGetEvent(InvocationExpressionSyntax invocation, SyntaxNodeAnalysisContext context, out ReflectedMember member, out Name name, out Flags flags)
 {
     return(TryMatchGetX(invocation, KnownSymbol.Type.GetEvent, context, out member, out name, out flags));
 }
Beispiel #10
0
        /// <summary>
        /// Check if <paramref name="invocation"/> is a call to Type.GetMethod.
        /// </summary>
        internal static bool TryMatchGetConstructor(InvocationExpressionSyntax invocation, SyntaxNodeAnalysisContext context, out ReflectedMember member, out Flags flags, out Types types)
        {
            if (invocation.ArgumentList != null &&
                invocation.TryGetTarget(KnownSymbol.Type.GetConstructor, context.SemanticModel, context.CancellationToken, out var getX))
            {
                if (ReflectedMember.TryGetType(invocation, context, out var type, out var typeSource) &&
                    IsKnownSignature(invocation, getX) &&
                    Flags.TryCreate(invocation, getX, context, out flags) &&
                    Types.TryCreate(invocation, getX, context, out types))
                {
                    return(ReflectedMember.TryCreate(getX, invocation, type, typeSource, Name.Ctor, flags.Effective, types, context, out member));
                }

                if (Flags.TryCreate(invocation, getX, context, out flags) &&
                    flags.AreInSufficient)
                {
                    member = new ReflectedMember(type, typeSource, null, getX, invocation, FilterMatch.InSufficientFlags);
                    _      = Types.TryCreate(invocation, getX, context, out types);
                    return(true);
                }
            }

            member = default(ReflectedMember);
            flags  = default(Flags);
            types  = default(Types);
            return(false);
        }
Beispiel #11
0
        /// <summary>
        /// Handles GetField, GetEvent, GetMember, GetMethod...
        /// </summary>
        private static bool TryMatchGetX(InvocationExpressionSyntax invocation, QualifiedMethod getXMethod, SyntaxNodeAnalysisContext context, out ReflectedMember member, out Name name, out Flags flags)
        {
            if (invocation.ArgumentList != null &&
                invocation.TryGetTarget(getXMethod, context.SemanticModel, context.CancellationToken, out var getX))
            {
                if (ReflectedMember.TryGetType(invocation, context, out var type, out var typeSource) &&
                    Name.TryCreate(invocation, getX, context, out name) &&
                    Flags.TryCreate(invocation, getX, context, out flags) &&
                    ReflectedMember.TryCreate(getX, invocation, type, typeSource, name, flags.Effective, Types.Any, context, out member))
                {
                    return(true);
                }

                if (getXMethod.Name != "GetNestedType" &&
                    Flags.TryCreate(invocation, getX, context, out flags) &&
                    flags.AreInSufficient)
                {
                    _      = Name.TryCreate(invocation, getX, context, out name);
                    member = new ReflectedMember(type, typeSource, null, getX, invocation, FilterMatch.InSufficientFlags);
                    return(true);
                }
            }

            member = default(ReflectedMember);
            name   = default(Name);
            flags  = default(Flags);
            return(false);
        }
Beispiel #12
0
        private static bool IsPreferGetMemberThenAccessor(ReflectedMember member, Name name, Flags flags, Types types, SyntaxNodeAnalysisContext context, out string callText)
        {
            if (member.Invocation?.Expression is MemberAccessExpressionSyntax memberAccess)
            {
                if (member.Symbol is IMethodSymbol method)
                {
                    if (method.AssociatedSymbol is IPropertySymbol property &&
                        Flags.TryGetExpectedBindingFlags(property.ContainingType, property, out var bindingFlags))
                    {
                        return TryGetPropertyAccessor(MemberName(property), bindingFlags, property.Type, out callText);
                    }

                    if (method.AssociatedSymbol is IEventSymbol eventSymbol &&
                        Flags.TryGetExpectedBindingFlags(eventSymbol.ContainingType, eventSymbol, out bindingFlags))
                    {
                        return TryGetEventAccessor(MemberName(eventSymbol), bindingFlags, out callText);
                    }
                }
                //// For symbols not in source and not visible in metadata.
                else if (member.Symbol is null &&
                         types.Argument == null &&
                         flags.Explicit.HasFlagFast(BindingFlags.NonPublic))
                {
                    if (TryGetInvisibleMemberName("get_", out var memberName) ||
                        TryGetInvisibleMemberName("set_", out memberName))
                    {
                        return TryGetPropertyAccessor(memberName, flags.Explicit, null, out callText);
                    }

                    if (TryGetInvisibleMemberName("add_", out memberName) ||
                        TryGetInvisibleMemberName("remove_", out memberName) ||
                        TryGetInvisibleMemberName("raise_", out memberName))
                    {
                        return TryGetEventAccessor(memberName, flags.Explicit, out callText);
                    }
                }
            }

            callText = null;
            return false;

            bool TryGetPropertyAccessor(string propertyName, BindingFlags bindingFlags, ITypeSymbol type, out string result)
            {
                if (name.MetadataName.StartsWith("get_", StringComparison.OrdinalIgnoreCase))
                {
                    result = types.Argument == null
                        ? $"{memberAccess.Expression}.GetProperty({propertyName}, {bindingFlags.ToDisplayString(memberAccess)}).GetMethod"
                        : $"{memberAccess.Expression}.GetProperty({propertyName}, {bindingFlags.ToDisplayString(memberAccess)}, null, typeof({type.ToString(context)}), {types.Argument}, null).GetMethod";
                    return true;
                }

                if (name.MetadataName.StartsWith("set_", StringComparison.OrdinalIgnoreCase))
                {
                    result = types.Argument == null
                        ? $"{memberAccess.Expression}.GetProperty({propertyName}, {bindingFlags.ToDisplayString(memberAccess)}).SetMethod"
                        : $"{memberAccess.Expression}.GetProperty({propertyName}, {bindingFlags.ToDisplayString(memberAccess)}, null, typeof({type.ToString(context)}), {types.Argument}, null).SetMethod";

                    return true;
                }

                result = null;
                return false;
            }

            bool TryGetEventAccessor(string eventName, BindingFlags bindingFlags, out string result)
            {
                if (name.MetadataName.StartsWith("add_", StringComparison.OrdinalIgnoreCase))
                {
                    result = $"{memberAccess.Expression}.GetEvent({eventName}, {bindingFlags.ToDisplayString(memberAccess)}).AddMethod";
                    return true;
                }

                if (name.MetadataName.StartsWith("remove_", StringComparison.OrdinalIgnoreCase))
                {
                    result = $"{memberAccess.Expression}.GetEvent({eventName}, {bindingFlags.ToDisplayString(memberAccess)}).RemoveMethod";
                    return true;
                }

                if (name.MetadataName.StartsWith("raise_", StringComparison.OrdinalIgnoreCase))
                {
                    result = $"{memberAccess.Expression}.GetEvent({eventName}, {bindingFlags.ToDisplayString(memberAccess)}).RaiseMethod";
                    return true;
                }

                result = null;
                return false;
            }

            bool TryGetInvisibleMemberName(string prefix, out string memberName)
            {
                if (name.MetadataName is string metadataName &&
                    metadataName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
                {
                    memberName = $"\"{metadataName.Substring(prefix.Length)}\"";
                    return true;
                }

                memberName = null;
                return false;
            }

            string MemberName(ISymbol associatedSymbol)
            {
                if (associatedSymbol is IPropertySymbol property &&
                    property.IsIndexer)
                {
                    return $"\"{associatedSymbol.MetadataName}\"";
                }

                if (context.ContainingSymbol.ContainingType == associatedSymbol.ContainingType)
                {
                    if (member.Symbol.IsStatic)
                    {
                        return $"nameof({associatedSymbol.Name})";
                    }

                    return context.SemanticModel.UnderscoreFields() ? associatedSymbol.Name : $"nameof(this.{associatedSymbol.Name})";
                }

                return context.SemanticModel.IsAccessible(context.Node.SpanStart, associatedSymbol)
                    ? $"nameof({associatedSymbol.ContainingType.ToString(context)}.{associatedSymbol.Name})"
                    : $"\"{associatedSymbol.Name}\"";
            }
        }