private (TypeSyntax, ExpressionSyntax) AdjustFromName(TypeSyntax rawType, ModifiedIdentifierSyntax name, ExpressionSyntax initializer) { var type = rawType; if (!SyntaxTokenExtensions.IsKind(name.Nullable, SyntaxKind.None)) { if (type is ArrayTypeSyntax) { type = ((ArrayTypeSyntax)type).WithElementType( SyntaxFactory.NullableType(((ArrayTypeSyntax)type).ElementType)); initializer = null; } else { type = SyntaxFactory.NullableType(type); } } var rankSpecifiers = ConvertArrayRankSpecifierSyntaxes(name.ArrayRankSpecifiers, name.ArrayBounds, false); if (rankSpecifiers.Count > 0) { var rankSpecifiersWithSizes = ConvertArrayRankSpecifierSyntaxes(name.ArrayRankSpecifiers, name.ArrayBounds); if (!rankSpecifiersWithSizes.SelectMany(ars => ars.Sizes).OfType <OmittedArraySizeExpressionSyntax>().Any()) { initializer = SyntaxFactory.ArrayCreationExpression( SyntaxFactory.ArrayType(type, rankSpecifiersWithSizes)); } type = SyntaxFactory.ArrayType(type, rankSpecifiers); } return(type, initializer); }
/// <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, ModifiedIdentifierSyntax syntaxForSymbol) { var methodBlockBaseSyntax = syntaxForSymbol.GetAncestor <MethodBlockBaseSyntax>(); var methodFlow = semanticModel.AnalyzeDataFlow(methodBlockBaseSyntax.Statements.First(), methodBlockBaseSyntax.Statements.Last()); return(DefiniteAssignmentAnalyzer.IsDefinitelyAssignedBeforeRead(locallyDeclaredSymbol, methodFlow)); }
/// <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, VariableDeclaratorSyntax localDeclarator, ModifiedIdentifierSyntax name) { Func <string, bool> equalsId = s => s.Equals(name.Identifier.ValueText, StringComparison.OrdinalIgnoreCase); // Find the first and second statements in the method (property, constructor, etc.) which contain the identifier // This may overshoot where there are multiple identifiers with the same name - this is ok, it just means we could output an initializer where one is not needed var statements = localDeclarator.GetAncestor <MethodBlockBaseSyntax>().Statements.Where(s => s.DescendantTokens().Any(id => ((SyntaxToken)id).IsKind(SyntaxKind.IdentifierToken) && equalsId(id.ValueText)) ).Take(2).ToList(); var first = statements.First(); var second = statements.Last(); // Analyze the data flow in this block to see if initialization is required // If the second statement where the identifier is used is an if block, we look at the condition rather than the whole statement. This is an easy special // case which catches eg. the if (TryParse()) pattern. This could happen for any node which allows multiple statements. var dataFlow = second is MultiLineIfBlockSyntax ifBlock ? semanticModel.AnalyzeDataFlow(ifBlock.IfStatement.Condition) : semanticModel.AnalyzeDataFlow(first, second); bool alwaysAssigned = dataFlow.AlwaysAssigned.Any(s => equalsId(s.Name)); bool readInside = dataFlow.ReadInside.Any(s => equalsId(s.Name)); bool writtenInside = dataFlow.WrittenInside.Any(s => equalsId(s.Name)); return(alwaysAssigned && !writtenInside || !readInside); }
/// <summary> /// Generates .NET code a constant field decl. /// </summary> /// <param name="context">Const decl AST.</param> /// <returns></returns> public override CodeGeneratorBase VisitConstStmt(VisualBasic6Parser.ConstStmtContext context) { List <SyntaxToken> modifiers = new List <SyntaxToken>(); VisualBasic6Parser.PublicPrivateGlobalVisibilityContext vis = context.publicPrivateGlobalVisibility(); if (vis != null) { if (vis.PUBLIC() != null || vis.GLOBAL() != null) { modifiers.Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword)); } else if (vis.PRIVATE() != null) { modifiers.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)); } } modifiers.Add(SyntaxFactory.Token(SyntaxKind.ConstKeyword)); foreach (VisualBasic6Parser.ConstSubStmtContext subStmt in context.constSubStmt()) { SimpleAsClauseSyntax asClause = null; if (subStmt.asTypeClause() != null) { asClause = SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName(subStmt.asTypeClause().type().GetText())); } ModifiedIdentifierSyntax identifier = SyntaxFactory.ModifiedIdentifier(subStmt.ambiguousIdentifier().GetText()); ExpressionSyntax initialiser = null; string initialiserExpr = subStmt.valueStmt().GetText(); //ParseExpression can't handle date/time literals - Roslyn bug? - //so handle them manually here if (initialiserExpr.StartsWith("#")) { string trimmedInitialiser = initialiserExpr.Trim(new char[] { '#' }); DateTime parsedVal = new DateTime(); if (trimmedInitialiser.Contains("AM") || trimmedInitialiser.Contains("PM")) { parsedVal = DateTime.ParseExact(trimmedInitialiser, "M/d/yyyy h:mm:ss tt", CultureInfo.InvariantCulture); } else { parsedVal = DateTime.ParseExact(trimmedInitialiser, "M/d/yyyy", CultureInfo.InvariantCulture); } initialiser = SyntaxFactory.DateLiteralExpression(SyntaxFactory.DateLiteralToken(initialiserExpr, parsedVal)); } else { initialiser = SyntaxFactory.ParseExpression(initialiserExpr); } VariableDeclaratorSyntax varDecl = SyntaxFactory.VariableDeclarator(identifier).WithInitializer(SyntaxFactory.EqualsValue(initialiser)); if (asClause != null) { varDecl = varDecl.WithAsClause(asClause); } mMainDeclMembers.Add(SyntaxFactory.FieldDeclaration(varDecl).WithModifiers(SyntaxFactory.TokenList(modifiers))); } return(base.VisitConstStmt(context)); }