private static void AddMemberAccessExpressionTerms(MemberAccessExpressionSyntax memberAccessExpression, IList <string> terms, ref ExpressionType expressionType) { var flags = ExpressionType.Invalid; // These operators always have a RHS of a name node, which we know would // "claim" to be a valid term, but is not valid without the LHS present. // So, we don't bother collecting anything from the RHS... AddSubExpressionTerms(memberAccessExpression.Expression, terms, ref flags); // If the LHS says it's a valid term, then we add it ONLY if our PARENT // is NOT another dot/arrow. This allows the expression 'a.b.c.d' to // add both 'a.b.c.d' and 'a.b.c', but not 'a.b' and 'a'. if (IsValidTerm(flags) && !memberAccessExpression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) && !memberAccessExpression.IsParentKind(SyntaxKind.PointerMemberAccessExpression)) { terms.Add(ConvertToString(memberAccessExpression.Expression)); } // And this expression itself is a valid term if the LHS is a valid // expression, and its PARENT is not an invocation. if (IsValidExpression(flags) && !memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression)) { expressionType = ExpressionType.ValidTerm; } else { expressionType = ExpressionType.ValidExpression; } }
public static bool CanRefactor( MemberAccessExpressionSyntax memberAccess, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { if (memberAccess == null) { throw new ArgumentNullException(nameof(memberAccess)); } if (semanticModel == null) { throw new ArgumentNullException(nameof(semanticModel)); } if (!memberAccess.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) && memberAccess.Expression != null && memberAccess.Name?.Identifier.ValueText == "Empty") { var fieldSymbol = semanticModel.GetSymbol(memberAccess.Name, cancellationToken) as IFieldSymbol; return(fieldSymbol != null && fieldSymbol.IsPublic() && fieldSymbol.IsReadOnly && fieldSymbol.IsStatic && fieldSymbol.ContainingType?.IsString() == true); } return(false); }
public static bool IsFixable( MemberAccessExpressionSyntax memberAccess, SemanticModel semanticModel, CancellationToken cancellationToken = default) { if (memberAccess.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { return(false); } if (memberAccess.Expression == null) { return(false); } if (memberAccess.Name?.Identifier.ValueText != "Empty") { return(false); } var fieldSymbol = semanticModel.GetSymbol(memberAccess.Name, cancellationToken) as IFieldSymbol; return(SymbolUtility.IsPublicStaticReadOnly(fieldSymbol) && fieldSymbol.ContainingType?.SpecialType == SpecialType.System_String); }
private static void AnalyzePredefinedType( SyntaxNodeAnalysisContext context, MemberAccessExpressionSyntax memberAccess) { if (!memberAccess.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { ExpressionSyntax expression = memberAccess.Expression; if (expression?.IsKind( SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.IdentifierName) == true) { var namedTypeSymbol = context.SemanticModel .GetSymbolInfo(expression, context.CancellationToken) .Symbol as INamedTypeSymbol; if (namedTypeSymbol?.SupportsPredefinedType() == true) { IAliasSymbol aliasSymbol = context.SemanticModel.GetAliasInfo(expression, context.CancellationToken); if (aliasSymbol == null) { context.ReportDiagnostic( DiagnosticDescriptors.UsePredefinedType, expression.GetLocation()); } } } } }
public static void Analyze(SyntaxNodeAnalysisContext context, MemberAccessExpressionSyntax memberAccess) { if (memberAccess.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { return; } ExpressionSyntax expression = memberAccess.Expression; if (expression == null) { return; } SyntaxKind kind = expression.Kind(); if (kind == SyntaxKind.IdentifierName) { if (!SupportsPredefinedType((IdentifierNameSyntax)expression)) { return; } } else if (kind == SyntaxKind.SimpleMemberAccessExpression) { memberAccess = (MemberAccessExpressionSyntax)expression; if (!(memberAccess.Name is IdentifierNameSyntax identifierName)) { return; } if (!SupportsPredefinedType(identifierName)) { return; } } else { return; } var typeSymbol = context.SemanticModel.GetSymbol(expression, context.CancellationToken) as ITypeSymbol; if (typeSymbol?.SupportsPredefinedType() != true) { return; } IAliasSymbol aliasSymbol = context.SemanticModel.GetAliasInfo(expression, context.CancellationToken); if (aliasSymbol != null) { return; } ReportDiagnostic(context, expression); }
private static MemberAccessExpressionSyntax GetTopmostMemberAccessExpression(MemberAccessExpressionSyntax memberAccess) { while (memberAccess.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { memberAccess = (MemberAccessExpressionSyntax)memberAccess.Parent; } return(memberAccess); }
public static void Analyze(SyntaxNodeAnalysisContext context, MemberAccessExpressionSyntax memberAccess) { if (!memberAccess.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { ExpressionSyntax expression = memberAccess.Expression; if (expression?.IsKind( SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.IdentifierName) == true) { var typeSymbol = context.SemanticModel.GetSymbol(expression, context.CancellationToken) as ITypeSymbol; if (typeSymbol?.SupportsPredefinedType() == true) { IAliasSymbol aliasSymbol = context.SemanticModel.GetAliasInfo(expression, context.CancellationToken); if (aliasSymbol == null) { ReportDiagnostic(context, expression); } } } } }
private IEnumerable<TypeInferenceInfo> InferTypeForExpressionOfMemberAccessExpression( MemberAccessExpressionSyntax memberAccessExpression) { // If we're on the left side of a dot, it's possible in a few cases // to figure out what type we should be. Specifically, if we have // // await foo.ConfigureAwait() // // then we can figure out what 'foo' should be based on teh await // context. var name = memberAccessExpression.Name.Identifier.Value; if (name.Equals(nameof(Task<int>.ConfigureAwait)) && memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) && memberAccessExpression.Parent.IsParentKind(SyntaxKind.AwaitExpression)) { return InferTypes((ExpressionSyntax)memberAccessExpression.Parent); } else if (name.Equals(nameof(Task<int>.ContinueWith))) { // foo.ContinueWith(...) // We want to infer Task<T>. For now, we'll just do Task<object>, // in the future it would be nice to figure out the actual result // type based on the argument to ContinueWith. var taskOfT = this.Compilation.TaskOfTType(); if (taskOfT != null) { return SpecializedCollections.SingletonEnumerable( new TypeInferenceInfo(taskOfT.Construct(this.Compilation.ObjectType))); } } else if (name.Equals(nameof(Enumerable.Select)) || name.Equals(nameof(Enumerable.Where))) { var ienumerableType = this.Compilation.IEnumerableOfTType(); // foo.Select // We want to infer IEnumerable<T>. We can try to figure out what // T if we get a delegate as the first argument to Select/Where. if (ienumerableType != null && memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression)) { var invocation = (InvocationExpressionSyntax)memberAccessExpression.Parent; if (invocation.ArgumentList.Arguments.Count > 0) { var argumentExpression = invocation.ArgumentList.Arguments[0].Expression; if (argumentExpression != null) { var argumentTypes = GetTypes(argumentExpression); var delegateType = argumentTypes.FirstOrDefault().InferredType.GetDelegateType(this.Compilation); var typeArg = delegateType?.TypeArguments.Length > 0 ? delegateType.TypeArguments[0] : this.Compilation.ObjectType; if (IsUnusableType(typeArg) && argumentExpression is LambdaExpressionSyntax) { typeArg = InferTypeForFirstParameterOfLambda((LambdaExpressionSyntax)argumentExpression) ?? this.Compilation.ObjectType; } return SpecializedCollections.SingletonEnumerable( new TypeInferenceInfo(ienumerableType.Construct(typeArg))); } } } } return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>(); }
private static void AddMemberAccessExpressionTerms(MemberAccessExpressionSyntax memberAccessExpression, IList<string> terms, ref ExpressionType expressionType) { var flags = ExpressionType.Invalid; // These operators always have a RHS of a name node, which we know would // "claim" to be a valid term, but is not valid without the LHS present. // So, we don't bother collecting anything from the RHS... AddSubExpressionTerms(memberAccessExpression.Expression, terms, ref flags); // If the LHS says it's a valid term, then we add it ONLY if our PARENT // is NOT another dot/arrow. This allows the expression 'a.b.c.d' to // add both 'a.b.c.d' and 'a.b.c', but not 'a.b' and 'a'. if (IsValidTerm(flags) && !memberAccessExpression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) && !memberAccessExpression.IsParentKind(SyntaxKind.PointerMemberAccessExpression)) { terms.Add(ConvertToString(memberAccessExpression.Expression)); } // And this expression itself is a valid term if the LHS is a valid // expression, and its PARENT is not an invocation. if (IsValidExpression(flags) && !memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression)) { expressionType = ExpressionType.ValidTerm; } else { expressionType = ExpressionType.ValidExpression; } }