private static ITypeSymbol GetRegularExpressionType(SemanticModel semanticModel, SyntaxNode node) { // regular case. always use ConvertedType to get implicit conversion right. var expression = node.GetUnparenthesizedExpression(); var info = semanticModel.GetTypeInfo(expression); var conv = semanticModel.GetConversion(expression); if (info.ConvertedType == null || info.ConvertedType.IsErrorType()) { // there is no implicit conversion involved. no need to go further return info.Type; } // always use converted type if method group if ((!node.IsKind(SyntaxKind.ObjectCreationExpression) && semanticModel.GetMemberGroup(expression).Length > 0) || IsCoClassImplicitConversion(info, conv, semanticModel.Compilation.CoClassType())) { return info.ConvertedType; } // check implicit conversion if (conv.IsImplicit && (conv.IsConstantExpression || conv.IsEnumeration)) { return info.ConvertedType; } // always try to use type that is more specific than object type if possible. return !info.Type.IsObjectType() ? info.Type : info.ConvertedType; }
/// <summary> /// Analyzes the assignment expression and rejects a given declaration if it is unsuitable for implicit typing. /// </summary> /// <returns> /// false, if implicit typing cannot be used. /// true, otherwise. /// </returns> protected override bool AssignmentSupportsStylePreference(SyntaxToken identifier, TypeSyntax typeName, EqualsValueClauseSyntax initializer, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken) { var expression = GetInitializerExpression(initializer); // var cannot be assigned null if (expression.IsKind(SyntaxKind.NullLiteralExpression)) { return false; } // cannot use implicit typing on method group, anonymous function or on dynamic var declaredType = semanticModel.GetTypeInfo(typeName, cancellationToken).Type; if (declaredType != null && (declaredType.TypeKind == TypeKind.Delegate || declaredType.TypeKind == TypeKind.Dynamic)) { return false; } // variables declared using var cannot be used further in the same initialization expression. if (initializer.DescendantNodesAndSelf() .Where(n => (n as IdentifierNameSyntax)?.Identifier.ValueText.Equals(identifier.ValueText) == true) .Any(n => semanticModel.GetSymbolInfo(n, cancellationToken).Symbol?.IsKind(SymbolKind.Local) == true)) { return false; } // Get the conversion that occurred between the expression's type and type implied by the expression's context // and filter out implicit conversions. If an implicit conversion (other than identity) exists // and if we're replacing the declaration with 'var' we'd be changing the semantics by inferring type of // initializer expression and thereby losing the conversion. var conversion = semanticModel.GetConversion(expression, cancellationToken); if (conversion.Exists && conversion.IsImplicit && !conversion.IsIdentity) { return false; } // final check to compare type information on both sides of assignment. var initializerType = semanticModel.GetTypeInfo(expression, cancellationToken).Type; return declaredType.Equals(initializerType); }