private async Task <CSharpSyntaxNode> GetInitializerFromNameAndTypeAsync(ITypeSymbol typeSymbol, VBSyntax.ModifiedIdentifierSyntax name, CSharpSyntaxNode initializer) { if (!SyntaxTokenExtensions.IsKind(name.Nullable, SyntaxKind.None)) { if (typeSymbol.IsArrayType()) { initializer = null; } } var rankSpecifiers = await ConvertArrayRankSpecifierSyntaxesAsync(name.ArrayRankSpecifiers, name.ArrayBounds, false); if (rankSpecifiers.Count > 0) { var rankSpecifiersWithSizes = await ConvertArrayRankSpecifierSyntaxesAsync(name.ArrayRankSpecifiers, name.ArrayBounds); var arrayTypeSyntax = ((ArrayTypeSyntax)GetTypeSyntax(typeSymbol)).WithRankSpecifiers(rankSpecifiersWithSizes); if (rankSpecifiersWithSizes.SelectMany(ars => ars.Sizes).Any(e => !e.IsKind(CSSyntaxKind.OmittedArraySizeExpression))) { initializer = SyntaxFactory.ArrayCreationExpression(arrayTypeSyntax); } else if (initializer is CSSyntax.ImplicitArrayCreationExpressionSyntax iaces && iaces.Initializer != null) { initializer = SyntaxFactory.ArrayCreationExpression(arrayTypeSyntax, iaces.Initializer); } } return(initializer); }
/// <summary> /// Returns true only if expressions static (i.e. doesn't reference the containing instance) /// </summary> public static bool IsDefinitelyStatic(this SemanticModel semanticModel, VBSyntax.ModifiedIdentifierSyntax vbName, VBSyntax.ExpressionSyntax vbInitValue) { var arrayBoundExpressions = vbName.ArrayBounds != null?vbName.ArrayBounds.Arguments.Select(a => a.GetExpression()) : Enumerable.Empty <VBSyntax.ExpressionSyntax>(); var expressions = vbInitValue.Yield().Concat(arrayBoundExpressions).Where(x => x != null).ToArray(); return(expressions.All(e => semanticModel.IsDefinitelyStatic(e))); }
/// <summary> /// This check is entirely to avoid some unnecessary default initializations so the code looks less cluttered and more like the VB did. /// The caller should default to outputting an initializer which is always safe for equivalence/correctness. /// </summary> public static bool IsDefinitelyAssignedBeforeRead(this SemanticModel semanticModel, ISymbol locallyDeclaredSymbol, VBSyntax.ModifiedIdentifierSyntax syntaxForSymbol) { var methodBlockBaseSyntax = syntaxForSymbol.GetAncestor <VBSyntax.MethodBlockBaseSyntax>(); var methodFlow = semanticModel.AnalyzeDataFlow(methodBlockBaseSyntax.Statements.First(), methodBlockBaseSyntax.Statements.Last()); return(DefiniteAssignmentAnalyzer.IsDefinitelyAssignedBeforeRead(locallyDeclaredSymbol, methodFlow)); }
private async Task <CSSyntax.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; CSSyntax.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.HasInstanceConstructorsOutsideThisPart) { var lhs = SyntaxFactory.IdentifierName(ConvertIdentifier(vbName.Identifier, sourceTriviaMapKind: SourceTriviaMapKind.None)); _typeContext.Initializers.AdditionalInstanceInitializers.Add(new Assignment(lhs, CSSyntaxKind.SimpleAssignmentExpression, adjustedInitializerExpr)); equalsValueClauseSyntax = null; } else { var returnBlock = SyntaxFactory.Block(SyntaxFactory.ReturnStatement(adjustedInitializerExpr)); _typeContext.PerScopeState.Hoist(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); }
/// <remarks> /// In CS we need to lift non-static initializers to the constructor. But for partial classes these can be in different files. /// Rather than re-architect to allow communication between files, we create an initializer function, and call it from the other part, and just hope the name doesn't clash. /// </remarks> public static string GetInitialValueFunctionName(VBSyntax.ModifiedIdentifierSyntax vbName) { return("initial" + vbName.Identifier.ValueText.ToPascalCase()); }