private async Task <EqualsValueClauseSyntax> ConvertEqualsValueClauseSyntax( VariableDeclaratorSyntax vbDeclarator, ModifiedIdentifierSyntax vbName, VBSyntax.ExpressionSyntax vbInitValue, ITypeSymbol declaredSymbolType, ISymbol declaredSymbol, CSharpSyntaxNode initializerOrMethodDecl) { var csTypeSyntax = GetTypeSyntax(declaredSymbolType); bool isField = vbDeclarator.Parent.IsKind(SyntaxKind.FieldDeclaration); bool isConst = declaredSymbol is IFieldSymbol fieldSymbol && fieldSymbol.IsConst || declaredSymbol is ILocalSymbol localSymbol && localSymbol.IsConst; EqualsValueClauseSyntax equalsValueClauseSyntax; if (await GetInitializerFromNameAndType(declaredSymbolType, vbName, initializerOrMethodDecl) is ExpressionSyntax adjustedInitializerExpr) { var convertedInitializer = vbInitValue != null ? TypeConversionAnalyzer.AddExplicitConversion(vbInitValue, adjustedInitializerExpr, isConst : isConst) : adjustedInitializerExpr; equalsValueClauseSyntax = SyntaxFactory.EqualsValueClause(convertedInitializer); } else if (isField || declaredSymbol != null && _semanticModel.IsDefinitelyAssignedBeforeRead(declaredSymbol, vbName)) { equalsValueClauseSyntax = null; } else { // VB initializes variables to their default equalsValueClauseSyntax = SyntaxFactory.EqualsValueClause(SyntaxFactory.DefaultExpression(csTypeSyntax)); } return(equalsValueClauseSyntax); }
public ExpressionSyntax AddExplicitConvertTo(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, ITypeSymbol type) { var displayType = type.ToMinimalDisplayString(_semanticModel, vbNode.SpanStart); if (csNode is InvocationExpressionSyntax invoke && invoke.Expression is MemberAccessExpressionSyntax expr && expr.Expression is IdentifierNameSyntax name && name.Identifier.ValueText == "Conversions" && expr.Name.Identifier.ValueText == $"To{displayType}") { return(csNode); } var method = typeof(Conversions).GetMethod($"To{displayType}"); if (method == null) { throw new NotImplementedException($"Unimplemented conversion for {displayType}"); } // Need to use Conversions rather than Convert to match what VB does, eg. True -> -1 _extraUsingDirectives.Add("Microsoft.VisualBasic.CompilerServices"); var memberAccess = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName("Conversions"), SyntaxFactory.IdentifierName($"To{displayType}")); var arguments = SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(csNode))); return(SyntaxFactory.InvocationExpression(memberAccess, arguments)); }
public ExpressionSyntax AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded = false) { var vbConvertedType = ModelExtensions.GetTypeInfo(_semanticModel, vbNode).ConvertedType; switch (conversionKind) { case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: var typeName = (TypeSyntax)_csSyntaxGenerator.TypeExpression(vbConvertedType); if (csNode is CastExpressionSyntax cast && cast.Type.IsEquivalentTo(typeName)) { return(csNode); } return(ValidSyntaxFactory.CastExpression(typeName, csNode)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbConvertedType)); default: throw new ArgumentOutOfRangeException(); } }
private ExpressionSyntax AddTypeConversion(VBSyntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded, ITypeSymbol vbType, ITypeSymbol vbConvertedType) { switch (conversionKind) { case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: return(CreateCast(csNode, vbConvertedType)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbType, vbConvertedType));; case TypeConversionKind.NullableBool: return(SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, csNode, LiteralConversions.GetLiteralExpression(true))); case TypeConversionKind.StringToCharArray: var memberAccessExpressionSyntax = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, csNode, SyntaxFactory.IdentifierName(nameof(string.ToCharArray))); return(SyntaxFactory.InvocationExpression(memberAccessExpressionSyntax, SyntaxFactory.ArgumentList())); default: throw new ArgumentOutOfRangeException(); } }
public ExpressionSyntax AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded = false, ITypeSymbol forceTargetType = null) { var vbConvertedType = forceTargetType ?? ModelExtensions.GetTypeInfo(_semanticModel, vbNode).ConvertedType; switch (conversionKind) { case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: return(CreateCast(csNode, vbConvertedType)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbConvertedType)); case TypeConversionKind.ConstConversion: return(ConstantFold(vbNode, vbConvertedType)); case TypeConversionKind.NullableBool: return(SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, csNode, LiteralConversions.GetLiteralExpression(true))); case TypeConversionKind.StringToCharArray: var memberAccessExpressionSyntax = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, csNode, SyntaxFactory.IdentifierName(nameof(string.ToCharArray))); return(SyntaxFactory.InvocationExpression(memberAccessExpressionSyntax, SyntaxFactory.ArgumentList())); default: throw new ArgumentOutOfRangeException(); } }
public (ExpressionSyntax Expr, bool IsConst) AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded = false, bool requiresConst = false, ITypeSymbol forceSourceType = null, ITypeSymbol forceTargetType = null) { var typeInfo = ModelExtensions.GetTypeInfo(_semanticModel, vbNode); var vbType = forceSourceType ?? typeInfo.Type; var vbConvertedType = forceTargetType ?? typeInfo.ConvertedType; bool resultConst = false; if (requiresConst) { var(constExpression, isCorrectType) = _expressionEvaluator.GetConstantOrNull(vbNode, vbConvertedType, conversionKind, csNode); if (isCorrectType) { return(constExpression, true); } if (constExpression != null) { csNode = constExpression ?? csNode; resultConst = true; } } var typeConvertedResult = AddTypeConversion(vbNode, csNode, conversionKind, addParenthesisIfNeeded, vbType, vbConvertedType); return(typeConvertedResult, resultConst); }
public ExpressionSyntax AddExplicitConvertTo(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, ITypeSymbol type) { var displayType = type.ToMinimalDisplayString(_semanticModel, vbNode.SpanStart); if (csNode is InvocationExpressionSyntax invoke && invoke.Expression is MemberAccessExpressionSyntax expr && expr.Expression is IdentifierNameSyntax name && name.Identifier.ValueText == "Conversions" && expr.Name.Identifier.ValueText == $"To{displayType}") { return(csNode); } if (!ConversionsTypeFullNames.TryGetValue(type.GetFullMetadataName(), out var methodId)) { return(CreateCast(csNode, type)); } // Need to use Conversions rather than Convert to match what VB does, eg. True -> -1 _extraUsingDirectives.Add("Microsoft.VisualBasic.CompilerServices"); var memberAccess = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName("Conversions"), SyntaxFactory.IdentifierName(methodId.Name)); var arguments = SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(csNode))); return(SyntaxFactory.InvocationExpression(memberAccess, arguments)); }
public ExpressionSyntax AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, bool addParenthesisIfNeeded = true, bool defaultToCast = false, bool isConst = false, ITypeSymbol forceTargetType = null) { var conversionKind = AnalyzeConversion(vbNode, defaultToCast, isConst, forceTargetType); csNode = addParenthesisIfNeeded && (conversionKind == TypeConversionKind.DestructiveCast || conversionKind == TypeConversionKind.NonDestructiveCast) ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode; return(AddExplicitConversion(vbNode, csNode, conversionKind, addParenthesisIfNeeded, forceTargetType: forceTargetType)); }
public ExpressionSyntax AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, bool addParenthesisIfNeeded = true, bool alwaysExplicit = false) { var conversionKind = AnalyzeConversion(vbNode, alwaysExplicit); csNode = addParenthesisIfNeeded && (conversionKind == TypeConversionKind.DestructiveCast || conversionKind == TypeConversionKind.NonDestructiveCast) ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode; return(AddExplicitConversion(vbNode, csNode, conversionKind, addParenthesisIfNeeded)); }
public IEnumerable <ExpressionSyntax> ConvertArrayBounds(ArgumentListSyntax argumentListSyntax) { return(argumentListSyntax.Arguments.Select(a => { VBSyntax.ExpressionSyntax upperBoundExpression = a is SimpleArgumentSyntax sas ? sas.Expression : a is RangeArgumentSyntax ras ? ras.UpperBound : throw new ArgumentOutOfRangeException(nameof(a), a, null); return IncreaseArrayUpperBoundExpression(upperBoundExpression); })); }
public TypeConversionKind AnalyzeConversion(VBSyntax.ExpressionSyntax vbNode, bool alwaysExplicit = false, bool isConst = false, ITypeSymbol forceSourceType = null, ITypeSymbol forceTargetType = null) { var(vbType, vbConvertedType) = GetTypeInfo(vbNode, forceSourceType, forceTargetType); if (vbConvertedType is null) { return(TypeConversionKind.Unknown); } if (vbType is null) { return(GetCommonDelegateTypeOrNull(vbNode, vbConvertedType) is {} ? TypeConversionKind.DelegateConstructor : TypeConversionKind.Unknown);
private ExpressionSyntax ConstantFold(VBSyntax.ExpressionSyntax vbNode, ITypeSymbol type) { var vbOperation = _semanticModel.GetOperation(vbNode); if (TryCompileTimeEvaluate(vbOperation, out var result) && ConversionsTypeFullNames.TryGetValue(type.GetFullMetadataName(), out var method)) { result = method.Invoke(null, new[] { result }); return(LiteralConversions.GetLiteralExpression(result)); } throw new NotImplementedException("Cannot generate constant C# expression"); }
private async Task <EqualsValueClauseSyntax> ConvertEqualsValueClauseSyntaxAsync( VariableDeclaratorSyntax vbDeclarator, VBSyntax.ModifiedIdentifierSyntax vbName, VBSyntax.ExpressionSyntax vbInitValue, ITypeSymbol declaredSymbolType, ISymbol declaredSymbol, CSharpSyntaxNode initializerOrMethodDecl) { var csTypeSyntax = GetTypeSyntax(declaredSymbolType); bool isField = vbDeclarator.Parent.IsKind(SyntaxKind.FieldDeclaration); bool declaredConst = declaredSymbol is IFieldSymbol fieldSymbol && fieldSymbol.IsConst || declaredSymbol is ILocalSymbol localSymbol && localSymbol.IsConst; EqualsValueClauseSyntax equalsValueClauseSyntax; if (await GetInitializerFromNameAndTypeAsync(declaredSymbolType, vbName, initializerOrMethodDecl) is ExpressionSyntax adjustedInitializerExpr) { var convertedInitializer = vbInitValue != null ? TypeConversionAnalyzer.AddExplicitConversion(vbInitValue, adjustedInitializerExpr, isConst : declaredConst) : adjustedInitializerExpr; if (isField && !declaredSymbol.IsStatic && !_semanticModel.IsDefinitelyStatic(vbName, vbInitValue)) { if (_typeContext.Initializers.ShouldAddTypeWideInitToThisPart) { var lhs = SyntaxFactory.IdentifierName(ConvertIdentifier(vbName.Identifier, sourceTriviaMapKind: SourceTriviaMapKind.None)); _typeContext.Initializers.AdditionalInstanceInitializers.Add((lhs, CSSyntaxKind.SimpleAssignmentExpression, adjustedInitializerExpr)); equalsValueClauseSyntax = null; } else { var returnBlock = SyntaxFactory.Block(SyntaxFactory.ReturnStatement(adjustedInitializerExpr)); _typeContext.HoistedState.Hoist <HoistedParameterlessFunction>(new HoistedParameterlessFunction(GetInitialValueFunctionName(vbName), csTypeSyntax, returnBlock)); equalsValueClauseSyntax = null; } } else { equalsValueClauseSyntax = SyntaxFactory.EqualsValueClause(convertedInitializer); } } else if (isField || declaredSymbol != null && _semanticModel.IsDefinitelyAssignedBeforeRead(declaredSymbol, vbName)) { equalsValueClauseSyntax = null; } else { // VB initializes variables to their default equalsValueClauseSyntax = SyntaxFactory.EqualsValueClause(SyntaxFactory.DefaultExpression(csTypeSyntax)); } return(equalsValueClauseSyntax); }
public ExpressionSyntax AddExplicitConversion(VBSyntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, bool addParenthesisIfNeeded = true, bool defaultToCast = false, bool isConst = false, ITypeSymbol forceSourceType = null, ITypeSymbol forceTargetType = null) { if (csNode == null) { return(null); } var conversionKind = AnalyzeConversion(vbNode, defaultToCast, isConst, forceSourceType, forceTargetType); csNode = addParenthesisIfNeeded && (conversionKind == TypeConversionKind.DestructiveCast || conversionKind == TypeConversionKind.NonDestructiveCast) ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode; return(AddExplicitConversion(vbNode, csNode, conversionKind, addParenthesisIfNeeded, isConst, forceSourceType: forceSourceType, forceTargetType: forceTargetType).Expr); }
private ExpressionSyntax IncreaseArrayUpperBoundExpression(VBSyntax.ExpressionSyntax expr) { var constant = _semanticModel.GetConstantValue(expr); if (constant.HasValue && constant.Value is int) { return(SyntaxFactory.LiteralExpression(Microsoft.CodeAnalysis.CSharp.SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal((int)constant.Value + 1))); } return(SyntaxFactory.BinaryExpression( Microsoft.CodeAnalysis.CSharp.SyntaxKind.SubtractExpression, (ExpressionSyntax)expr.Accept(_nodesVisitor), SyntaxFactory.Token(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PlusToken), SyntaxFactory.LiteralExpression(Microsoft.CodeAnalysis.CSharp.SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1)))); }
public bool ShouldPreferExplicitType(VBSyntax.ExpressionSyntax exp, ITypeSymbol expConvertedType, out bool isNothingLiteral) { var op = _semanticModel.GetExpressionOperation(exp); exp = op.Syntax as VBSyntax.ExpressionSyntax; var vbInitConstantValue = _semanticModel.GetConstantValue(exp); isNothingLiteral = vbInitConstantValue.HasValue && vbInitConstantValue.Value == null || exp is VBSyntax.LiteralExpressionSyntax les && les.IsKind(SyntaxKind.NothingLiteralExpression); bool shouldPreferExplicitType = expConvertedType != null && (expConvertedType.HasCsKeyword() || !expConvertedType.Equals(op.Type)); return(shouldPreferExplicitType); }
private ITypeSymbol GetCSType(ITypeSymbol vbType, VBSyntax.ExpressionSyntax vbNode = null) { // C# does not have literals for short/ushort, so the actual type here is integer if (vbNode is VBSyntax.LiteralExpressionSyntax literal && literal.IsKind(Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.NumericLiteralExpression) && literal.Token.Text.EndsWith("S")) { return(_csCompilation.GetSpecialType(SpecialType.System_Int32)); } var csType = SymbolFinder.FindSimilarSymbols(vbType, _csCompilation).FirstOrDefault() ?? _csCompilation.GetTypeByMetadataName(vbType.GetFullMetadataName()); return(csType); }
public TypeConversionKind AnalyzeConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, bool alwaysExplicit = false, bool isConst = false, ITypeSymbol forceSourceType = null, ITypeSymbol forceTargetType = null) { var typeInfo = ModelExtensions.GetTypeInfo(_semanticModel, vbNode); var vbType = forceSourceType ?? typeInfo.Type; var vbConvertedType = forceTargetType ?? typeInfo.ConvertedType; if (vbConvertedType is null) { return(TypeConversionKind.Unknown); } if (vbType is null) { return(GetCommonDelegateTypeOrNull(vbNode, vbConvertedType) is {} ? TypeConversionKind.DelegateConstructor : TypeConversionKind.Unknown);
public TypeConversionKind AnalyzeConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, bool alwaysExplicit = false, bool isConst = false, ITypeSymbol forceSourceType = null, ITypeSymbol forceTargetType = null) { var typeInfo = ModelExtensions.GetTypeInfo(_semanticModel, vbNode); var vbType = forceSourceType ?? typeInfo.Type; var vbConvertedType = forceTargetType ?? typeInfo.ConvertedType; if (vbType is null || vbConvertedType is null) { return(TypeConversionKind.Unknown); } if (vbType.IsEnumType()) { if (vbConvertedType.IsNumericType()) { return(TypeConversionKind.NonDestructiveCast); } else if (vbType.Equals(vbConvertedType) || (vbConvertedType.IsNullable() && vbType.Equals(vbConvertedType.GetNullableUnderlyingType())) || vbConvertedType.SpecialType == SpecialType.System_Object) { return(TypeConversionKind.Identity); } else if (vbConvertedType.SpecialType == SpecialType.System_String) { return(TypeConversionKind.EnumCastThenConversion); } else { return(TypeConversionKind.Conversion); } } var vbCompilation = (VBasic.VisualBasicCompilation)_semanticModel.Compilation; var vbConversion = vbCompilation.ClassifyConversion(vbType, vbConvertedType); var csType = GetCSType(vbType, vbNode); var csConvertedType = GetCSType(vbConvertedType); if (csType != null && csConvertedType != null && TryAnalyzeCsConversion(vbNode, csType, csConvertedType, vbConversion, vbConvertedType, vbType, vbCompilation, isConst, out TypeConversionKind analyzeConversion)) { return(analyzeConversion); } return(AnalyzeVbConversion(alwaysExplicit, vbType, vbConvertedType, vbConversion)); }
private ExpressionSyntax AddTypeConversion(VBSyntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded, ITypeSymbol vbType, ITypeSymbol vbConvertedType) { switch (conversionKind) { case TypeConversionKind.FractionalNumberRoundThenCast: csNode = AddRoundInvocation(vbNode, csNode, vbType, vbConvertedType); return(AddTypeConversion(vbNode, csNode, TypeConversionKind.NonDestructiveCast, addParenthesisIfNeeded, vbType, vbConvertedType)); case TypeConversionKind.EnumConversionThenCast: var underlyingType = ((INamedTypeSymbol)vbConvertedType).EnumUnderlyingType; csNode = AddTypeConversion(vbNode, csNode, TypeConversionKind.Conversion, addParenthesisIfNeeded, vbType, underlyingType); return(AddTypeConversion(vbNode, csNode, TypeConversionKind.NonDestructiveCast, addParenthesisIfNeeded, underlyingType, vbConvertedType)); case TypeConversionKind.EnumCastThenConversion: var enumUnderlyingType = ((INamedTypeSymbol)vbType).EnumUnderlyingType; csNode = AddTypeConversion(vbNode, csNode, TypeConversionKind.NonDestructiveCast, addParenthesisIfNeeded, vbType, enumUnderlyingType); return(AddTypeConversion(vbNode, csNode, TypeConversionKind.Conversion, addParenthesisIfNeeded, enumUnderlyingType, vbConvertedType)); case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? vbNode.ParenthesizeIfPrecedenceCouldChange(csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: return(CreateCast(csNode, vbConvertedType)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbType, vbConvertedType));; case TypeConversionKind.NullableBool: return(SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, csNode, LiteralConversions.GetLiteralExpression(true))); case TypeConversionKind.StringToCharArray: var memberAccessExpressionSyntax = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, csNode, SyntaxFactory.IdentifierName(nameof(string.ToCharArray))); return(SyntaxFactory.InvocationExpression(memberAccessExpressionSyntax, SyntaxFactory.ArgumentList())); case TypeConversionKind.DelegateConstructor: return(SyntaxFactory.ObjectCreationExpression(GetCommonDelegateTypeOrNull(vbNode, vbConvertedType)).WithArgumentList(new[] { csNode }.CreateCsArgList())); default: throw new ArgumentOutOfRangeException(); } }
public static bool ConvertStringToCharLiteral(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax node, ITypeSymbol convertedType, out char chr) { var preferChar = node.Parent is VBSyntax.PredefinedCastExpressionSyntax pces && pces.Keyword.IsKind(Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.CCharKeyword) || convertedType?.SpecialType == SpecialType.System_Char; if (preferChar && node.SkipParens() is VBSyntax.LiteralExpressionSyntax les && les.Token.Value is string str && str.Length == 1) { chr = str.Single(); return(true); } chr = default; return(false); }
public TypeConversionKind AnalyzeConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, bool alwaysExplicit = false) { var typeInfo = ModelExtensions.GetTypeInfo(_semanticModel, vbNode); var vbType = typeInfo.Type; var vbConvertedType = typeInfo.ConvertedType; if (vbType is null || vbConvertedType is null) { return(TypeConversionKind.Unknown); } if (vbType.IsEnumType()) { if (vbConvertedType.IsNumericType()) { return(TypeConversionKind.NonDestructiveCast); } else if (vbType.Equals(vbConvertedType) || (vbConvertedType.IsNullable() && vbType.Equals(vbConvertedType.GetNullableUnderlyingType())) || vbConvertedType.SpecialType == SpecialType.System_Object) { return(TypeConversionKind.Identity); } else { return(TypeConversionKind.Conversion); } } var vbCompilation = _semanticModel.Compilation as VisualBasicCompilation; var vbConversion = vbCompilation.ClassifyConversion(vbType, vbConvertedType); var csType = _csCompilation.GetTypeByMetadataName(vbType.GetFullMetadataName()); var csConvertedType = _csCompilation.GetTypeByMetadataName(vbConvertedType.GetFullMetadataName()); if (csType != null && csConvertedType != null && TryAnalyzeCsConversion(vbNode, csType, csConvertedType, vbConversion, vbConvertedType, vbType, vbCompilation, out TypeConversionKind analyzeConversion)) { return(analyzeConversion); } return(AnalyzeVbConversion(alwaysExplicit, vbType, vbConvertedType, vbConversion)); }
public ExpressionSyntax AddExplicitConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded = false) { var vbConvertedType = ModelExtensions.GetTypeInfo(_semanticModel, vbNode).ConvertedType; switch (conversionKind) { case TypeConversionKind.Unknown: case TypeConversionKind.Identity: return(addParenthesisIfNeeded ? VbSyntaxNodeExtensions.ParenthesizeIfPrecedenceCouldChange(vbNode, csNode) : csNode); case TypeConversionKind.DestructiveCast: case TypeConversionKind.NonDestructiveCast: return(CreateCast(csNode, vbConvertedType)); case TypeConversionKind.Conversion: return(AddExplicitConvertTo(vbNode, csNode, vbConvertedType)); default: throw new ArgumentOutOfRangeException(); } }
public (ExpressionSyntax Expr, bool IsConst) AddExplicitConversion(VBSyntax.ExpressionSyntax vbNode, ExpressionSyntax csNode, TypeConversionKind conversionKind, bool addParenthesisIfNeeded = false, bool requiresConst = false, ITypeSymbol forceSourceType = null, ITypeSymbol forceTargetType = null) { var(vbType, vbConvertedType) = GetTypeInfo(vbNode, forceSourceType, forceTargetType); bool resultConst = false; if (requiresConst) { var(constExpression, isCorrectType) = _expressionEvaluator.GetConstantOrNull(vbNode, vbConvertedType, conversionKind, csNode); if (isCorrectType) { return(constExpression, true); } if (constExpression != null) { csNode = constExpression ?? csNode; resultConst = true; } } var typeConvertedResult = AddTypeConversion(vbNode, csNode, conversionKind, addParenthesisIfNeeded, vbType, vbConvertedType); return(typeConvertedResult, resultConst); }
private bool TryAnalyzeCsConversion(Microsoft.CodeAnalysis.VisualBasic.Syntax.ExpressionSyntax vbNode, ITypeSymbol csType, ITypeSymbol csConvertedType, Conversion vbConversion, ITypeSymbol vbConvertedType, ITypeSymbol vbType, VisualBasicCompilation vbCompilation, bool isConst, out TypeConversionKind typeConversionKind) { var csConversion = _csCompilation.ClassifyConversion(csType, csConvertedType); bool isConvertToString = (vbConversion.IsString || vbConversion.IsReference && vbConversion.IsNarrowing) && vbConvertedType.SpecialType == SpecialType.System_String; bool isArithmetic = vbNode.IsKind(Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.AddExpression, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.SubtractExpression, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.MultiplyExpression, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.DivideExpression, Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.IntegerDivideExpression); if (!csConversion.Exists || csConversion.IsUnboxing) { if (ConvertStringToCharLiteral(vbNode, vbConvertedType, out _)) { typeConversionKind = TypeConversionKind.Identity; // Already handled elsewhere by other usage of method return(true); } if (vbType.SpecialType == SpecialType.System_String && vbConvertedType.IsArrayOf(SpecialType.System_Char)) { typeConversionKind = TypeConversionKind.StringToCharArray; return(true); } if (isConvertToString || vbConversion.IsNarrowing) { typeConversionKind = isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } } else if (vbConversion.IsWidening && vbConversion.IsNumeric && csConversion.IsImplicit && csConversion.IsNumeric) { // Safe overapproximation: A cast is really only needed to help resolve the overload for the operator/method used. // e.g. When VB "&" changes to C# "+", there are lots more overloads available that implicit casts could match. // e.g. sbyte * ulong uses the decimal * operator in VB. In C# it's ambiguous - see ExpressionTests.vb "TestMul". typeConversionKind = TypeConversionKind.NonDestructiveCast; return(true); } else if (csConversion.IsExplicit && csConversion.IsEnumeration) { typeConversionKind = TypeConversionKind.NonDestructiveCast; return(true); } else if (isArithmetic) { var arithmeticConversion = vbCompilation.ClassifyConversion(vbConvertedType, vbCompilation.GetTypeByMetadataName("System.Int32")); if (arithmeticConversion.IsWidening && !arithmeticConversion.IsIdentity) { typeConversionKind = isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } } else if (csConversion.IsExplicit && csConversion.IsNumeric && vbConversion.IsNarrowing && isConst) { typeConversionKind = IsImplicitConstantConversion(vbNode) ? TypeConversionKind.Identity : TypeConversionKind.NonDestructiveCast; return(true); } else if (csConversion.IsExplicit && vbConversion.IsNumeric && vbType.TypeKind != TypeKind.Enum) { typeConversionKind = IsImplicitConstantConversion(vbNode) ? TypeConversionKind.Identity : isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } else if (csConversion.IsExplicit && vbConversion.IsIdentity && csConversion.IsNumeric && vbType.TypeKind != TypeKind.Enum) { typeConversionKind = isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } else if (isConvertToString && vbType.SpecialType == SpecialType.System_Object) { typeConversionKind = isConst ? TypeConversionKind.ConstConversion : TypeConversionKind.Conversion; return(true); } else if (csConversion.IsNullable && csConvertedType.SpecialType == SpecialType.System_Boolean) { typeConversionKind = TypeConversionKind.NullableBool; return(true); } else if (csConversion.IsExplicit) { typeConversionKind = TypeConversionKind.DestructiveCast; return(true); } typeConversionKind = csConversion.IsIdentity ? TypeConversionKind.Identity : TypeConversionKind.Unknown; return(false); }
private bool IsImplicitConstantConversion(VBSyntax.ExpressionSyntax vbNode) { return(_semanticModel.GetOperation(vbNode).Parent is IConversionOperation co && co.IsImplicit && co.Operand.ConstantValue.HasValue); }