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)); } } }
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); } } } } } }
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}\""; } }