public State( SyntaxNode declaration, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken ) { TypeStylePreference = default; IsInIntrinsicTypeContext = default; IsTypeApparentInContext = default; var styleForIntrinsicTypes = optionSet.GetOption( CSharpCodeStyleOptions.VarForBuiltInTypes ); var styleForApparent = optionSet.GetOption( CSharpCodeStyleOptions.VarWhenTypeIsApparent ); var styleForElsewhere = optionSet.GetOption(CSharpCodeStyleOptions.VarElsewhere); _forBuiltInTypes = styleForIntrinsicTypes.Notification.Severity; _whenTypeIsApparent = styleForApparent.Notification.Severity; _elsewhere = styleForElsewhere.Notification.Severity; var stylePreferences = UseVarPreference.None; if (styleForIntrinsicTypes.Value) { stylePreferences |= UseVarPreference.ForBuiltInTypes; } if (styleForApparent.Value) { stylePreferences |= UseVarPreference.WhenTypeIsApparent; } if (styleForElsewhere.Value) { stylePreferences |= UseVarPreference.Elsewhere; } this.TypeStylePreference = stylePreferences; IsTypeApparentInContext = declaration.IsKind( SyntaxKind.VariableDeclaration, out VariableDeclarationSyntax? varDecl ) && IsTypeApparentInDeclaration( varDecl, semanticModel, TypeStylePreference, cancellationToken ); IsInIntrinsicTypeContext = IsPredefinedTypeInDeclaration(declaration, semanticModel) || IsInferredPredefinedType(declaration, semanticModel); }
private static bool IsImplicitStylePreferred( UseVarPreference stylePreferences, bool isBuiltInTypeContext, bool isTypeApparentContext) { return(isBuiltInTypeContext ? stylePreferences.HasFlag(UseVarPreference.ForBuiltInTypes) : isTypeApparentContext ? stylePreferences.HasFlag(UseVarPreference.WhenTypeIsApparent) : stylePreferences.HasFlag(UseVarPreference.Elsewhere)); }
/// <summary> /// Returns true if type information could be gleaned by simply looking at the given statement. /// This typically means that the type name occurs in right hand side of an assignment. /// </summary> private static bool IsTypeApparentInDeclaration( VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, UseVarPreference stylePreferences, CancellationToken cancellationToken ) { if (variableDeclaration.Variables.Count != 1) { return(false); } var initializer = variableDeclaration.Variables[0].Initializer; if (initializer == null) { return(false); } var initializerExpression = CSharpUseImplicitTypeHelper.GetInitializerExpression( initializer.Value ); var declaredTypeSymbol = semanticModel.GetTypeInfo( variableDeclaration.Type.StripRefIfNeeded(), cancellationToken ).Type; return(TypeStyleHelper.IsTypeApparentInAssignmentExpression( stylePreferences, initializerExpression, semanticModel, declaredTypeSymbol, cancellationToken )); }
/// <summary> /// Analyzes if type information is obvious to the reader by simply looking at the assignment expression. /// </summary> /// <remarks> /// <paramref name="typeInDeclaration"/> accepts null, to be able to cater to codegen features /// that are about to generate a local declaration and do not have this information to pass in. /// Things (like analyzers) that do have a local declaration already, should pass this in. /// </remarks> public static bool IsTypeApparentInAssignmentExpression( UseVarPreference stylePreferences, ExpressionSyntax initializerExpression, SemanticModel semanticModel, ITypeSymbol typeInDeclaration, CancellationToken cancellationToken) { // tuple literals if (initializerExpression.IsKind(SyntaxKind.TupleExpression, out TupleExpressionSyntax tuple)) { if (typeInDeclaration == null || !typeInDeclaration.IsTupleType) { return(false); } var tupleType = (INamedTypeSymbol)typeInDeclaration; if (tupleType.TupleElements.Length != tuple.Arguments.Count) { return(false); } for (int i = 0, n = tuple.Arguments.Count; i < n; i++) { var argument = tuple.Arguments[i]; var tupleElementType = tupleType.TupleElements[i].Type; if (!IsTypeApparentInAssignmentExpression( stylePreferences, argument.Expression, semanticModel, tupleElementType, cancellationToken)) { return(false); } } return(true); } // default(type) if (initializerExpression.IsKind(SyntaxKind.DefaultExpression)) { return(true); } // literals, use var if options allow usage here. if (initializerExpression.IsAnyLiteralExpression()) { return(stylePreferences.HasFlag(UseVarPreference.ForBuiltInTypes)); } // constructor invocations cases: // = new type(); if (initializerExpression.IsKind(SyntaxKind.ObjectCreationExpression, SyntaxKind.ArrayCreationExpression) && !initializerExpression.IsKind(SyntaxKind.AnonymousObjectCreationExpression)) { return(true); } // explicit conversion cases: // (type)expr, expr is type, expr as type if (initializerExpression.IsKind(SyntaxKind.CastExpression) || initializerExpression.IsKind(SyntaxKind.IsExpression) || initializerExpression.IsKind(SyntaxKind.AsExpression)) { return(true); } // other Conversion cases: // a. conversion with helpers like: int.Parse methods // b. types that implement IConvertible and then invoking .ToType() // c. System.Convert.ToType() var memberName = GetRightmostInvocationExpression(initializerExpression).GetRightmostName(); if (memberName == null) { return(false); } if (!(semanticModel.GetSymbolInfo(memberName, cancellationToken).Symbol is IMethodSymbol methodSymbol)) { return(false); } if (memberName.IsRightSideOfDot()) { var containingTypeName = memberName.GetLeftSideOfDot(); return(IsPossibleCreationOrConversionMethod(methodSymbol, typeInDeclaration, semanticModel, containingTypeName, cancellationToken)); } return(false); }