Пример #1
0
    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));
    }
Пример #4
0
    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);
    }
Пример #5
0
 /// <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());
 }