private static bool HasWrongFlags(ReflectedMember member, Flags flags, out Location location, out string flagText)
        {
            if (member.Match == FilterMatch.WrongFlags &&
                Flags.TryGetExpectedBindingFlags(member.ReflectedType, member.Symbol, out var correctFlags))
            {
                flagText = correctFlags.ToDisplayString(flags.Argument);
                if (flags.Argument is ArgumentSyntax argument)
                {
                    location = argument.GetLocation();
                    return(true);
                }

                if (member.Invocation?.ArgumentList is ArgumentListSyntax argumentList)
                {
                    location = member.GetX == KnownSymbol.Type.GetConstructor
                        ? argumentList.OpenParenToken.GetLocation()
                        : argumentList.CloseParenToken.GetLocation();
                    return(true);
                }
            }

            location = null;
            flagText = null;
            return(false);
        }
        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 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));
                    }
                }
            }
예제 #5
0
        protected override async Task RegisterCodeFixesAsync(DocumentEditorCodeFixContext context)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(context.CancellationToken)
                             .ConfigureAwait(false);

            var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken)
                                .ConfigureAwait(false);

            foreach (var diagnostic in context.Diagnostics)
            {
                if (syntaxRoot.TryFindNode(diagnostic, out ArgumentListSyntax argumentList) &&
                    argumentList.Arguments.TrySingle(out var arg) &&
                    arg.TryGetStringValue(semanticModel, context.CancellationToken, out var memberName) &&
                    argumentList.Parent is InvocationExpressionSyntax invocation &&
                    diagnostic.Properties.TryGetValue(nameof(INamedTypeSymbol), out var typeName) &&
                    semanticModel.Compilation.GetTypeByMetadataName(typeName) is INamedTypeSymbol type)
                {
                    if (invocation.TryGetTarget(KnownSymbol.Type.GetMethod, semanticModel, context.CancellationToken, out _))
                    {
                        foreach (var member in type.GetMembers())
                        {
                            if (member is IMethodSymbol method &&
                                method.MetadataName == memberName &&
                                Flags.TryGetExpectedBindingFlags(type, method, out var flags) &&
                                flags.ToDisplayString(invocation) is string flagsText &&
                                Types.TryGetTypesArrayText(method.Parameters, semanticModel, invocation.SpanStart, out var typesArrayText))
                            {
                                context.RegisterCodeFix(
                                    $"Use: {typesArrayText}.",
                                    (editor, _) => editor.AddUsing(SystemReflection)
                                    .ReplaceNode(
                                        argumentList,
                                        x => x.WithArguments(x.Arguments.AddRange(new[] { ParseArgument(flagsText), NullArgument, ParseArgument(typesArrayText), NullArgument }))
                                        .WithTriviaFrom(x)),
                                    nameof(DisambiguateFix),
                                    diagnostic);
                            }
                        }
                    }

                    if (invocation.TryGetTarget(KnownSymbol.Type.GetProperty, semanticModel, context.CancellationToken, out _))
                    {
                        foreach (var member in type.GetMembers())
                        {
                            if (member is IPropertySymbol property &&
                                property.MetadataName == memberName &&
                                Flags.TryGetExpectedBindingFlags(type, property, out var flags) &&
                                flags.ToDisplayString(invocation) is string flagsText &&
                                Types.TryGetTypesArrayText(property.Parameters, semanticModel, invocation.SpanStart, out var typesArrayText))
                            {
                                context.RegisterCodeFix(
                                    $"Use: {typesArrayText}.",
                                    (editor, _) => editor.AddUsing(SystemReflection)
                                    .ReplaceNode(
                                        argumentList,
                                        x => x.WithArguments(x.Arguments.AddRange(new[]
                                {
                                    ParseArgument(flagsText),
                                    NullArgument,
                                    ParseArgument($"typeof({property.Type.ToString(semanticModel, invocation.SpanStart)})"),
                                    ParseArgument(typesArrayText),
                                    NullArgument,
                                }))
                                        .WithTriviaFrom(x)),
                                    nameof(DisambiguateFix),
                                    diagnostic);
                            }
                        }
                    }
                }
            }
        }
예제 #6
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}\"";
            }
        }