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