private static bool UsedOutsideParentBlock(SemanticModel semanticModel, StatementSyntax expressionStatement, ISymbol identitySymbol) { var block = expressionStatement.FirstAncestorOrSelf <BlockSyntax>(); var method = expressionStatement.FirstAncestorOrSelf <MethodDeclarationSyntax>(); var methodBlock = method.Body; if (methodBlock.Equals(block)) { return(false); } var collectionOfStatementsAfter = GetStatementsInBlocksAfter(block); foreach (var allStatementsAfterBlock in collectionOfStatementsAfter) { if (!allStatementsAfterBlock.Any()) { continue; } var dataFlowAnalysis = semanticModel.AnalyzeDataFlow(allStatementsAfterBlock.First(), allStatementsAfterBlock.Last()); if (!dataFlowAnalysis.Succeeded) { continue; } var isUsed = dataFlowAnalysis.ReadInside.Contains(identitySymbol) || dataFlowAnalysis.WrittenInside.Contains(identitySymbol); if (isUsed) { return(true); } } return(false); }
private static List <List <StatementSyntax> > GetStatementsInBlocksAfter(StatementSyntax node) { var collectionOfStatements = new List <List <StatementSyntax> >(); var method = node.FirstAncestorOrSelf <MethodDeclarationSyntax>(); if (method?.Body == null) { return(collectionOfStatements); } var currentBlock = node.FirstAncestorOfType <BlockSyntax>(); while (currentBlock != null) { var statements = new List <StatementSyntax>(); foreach (var statement in currentBlock.Statements) { if (statement.SpanStart > node.SpanStart) { statements.Add(statement); } } if (statements.Any()) { collectionOfStatements.Add(statements); } if (method.Body.Equals(currentBlock)) { break; } currentBlock = currentBlock.FirstAncestorOfType <BlockSyntax>(); } return(collectionOfStatements); }
private static IList <StatementSyntax> GetChildStatementsAfter(StatementSyntax node) { var block = node.FirstAncestorOrSelf <BlockSyntax>(); var statements = block.Statements.Where(s => s.SpanStart > node.SpanStart).ToList(); return(statements); }
private static Document MakeObjectInitializer(Document document, SyntaxNode root, StatementSyntax statement, ISymbol variableSymbol, SemanticModel semanticModel) { var blockParent = statement.FirstAncestorOrSelf<BlockSyntax>(); var objectCreationExpression = statement.DescendantNodes().OfType<ObjectCreationExpressionSyntax>().Single(); var newBlockParent = CreateNewBlockParent(statement, semanticModel, objectCreationExpression, variableSymbol); var newRoot = root.ReplaceNode(blockParent, newBlockParent); var newDocument = document.WithSyntaxRoot(newRoot); return newDocument; }
private static Document MakeObjectInitializer(Document document, SyntaxNode root, StatementSyntax statement, ISymbol variableSymbol, SemanticModel semanticModel) { var blockParent = statement.FirstAncestorOrSelf <BlockSyntax>(); var objectCreationExpression = statement.DescendantNodes().OfType <ObjectCreationExpressionSyntax>().First(); var newBlockParent = CreateNewBlockParent(statement, semanticModel, objectCreationExpression, variableSymbol); var newRoot = root.ReplaceNode(blockParent, newBlockParent); var newDocument = document.WithSyntaxRoot(newRoot); return(newDocument); }
private static BlockSyntax CreateNewBlockParent(StatementSyntax statement, SemanticModel semanticModel, ObjectCreationExpressionSyntax objectCreationExpression, ISymbol variableSymbol) { var blockParent = statement.FirstAncestorOrSelf<BlockSyntax>(); var assignmentExpressions = ObjectInitializerAnalyzer.FindAssignmentExpressions(semanticModel, statement, variableSymbol); var newBlockParent = SyntaxFactory.Block() .WithLeadingTrivia(blockParent.GetLeadingTrivia()) .WithTrailingTrivia(blockParent.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); var newAssignmentExpressions = new List<ExpressionStatementSyntax>(); for (int i = 0; i < blockParent.Statements.Count; i++) { var blockStatement = blockParent.Statements[i]; if (blockStatement.Equals(statement)) { var initializationExpressions = new List<AssignmentExpressionSyntax>(); foreach (var expressionStatement in assignmentExpressions) { var assignmentExpression = expressionStatement.Expression as AssignmentExpressionSyntax; var memberAccess = assignmentExpression.Left as MemberAccessExpressionSyntax; var propertyIdentifier = memberAccess.Name as IdentifierNameSyntax; initializationExpressions.Add(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, propertyIdentifier, assignmentExpression.Right)); } var initializers = SyntaxFactory.SeparatedList<ExpressionSyntax>(initializationExpressions); var newObjectCreationExpression = objectCreationExpression.WithInitializer( SyntaxFactory.InitializerExpression( SyntaxKind.ObjectInitializerExpression, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.OpenBraceToken, SyntaxFactory.ParseTrailingTrivia("\n")), initializers, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.CloseBraceToken, SyntaxFactory.ParseTrailingTrivia("")) )) .WithLeadingTrivia(objectCreationExpression.GetLeadingTrivia()) .WithTrailingTrivia(objectCreationExpression.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); if (newObjectCreationExpression.ArgumentList?.Arguments.Count == 0) { newObjectCreationExpression = newObjectCreationExpression.WithArgumentList(null); } var newLocalDeclarationStatement = statement.ReplaceNode(objectCreationExpression, newObjectCreationExpression) .WithLeadingTrivia(statement.GetLeadingTrivia()) .WithTrailingTrivia(statement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); newBlockParent = newBlockParent.AddStatements(newLocalDeclarationStatement); i += initializationExpressions.Count; } else { newBlockParent = newBlockParent.AddStatements(blockStatement .WithLeadingTrivia(blockStatement.GetLeadingTrivia()) .WithTrailingTrivia(blockStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation)); } } return newBlockParent; }
private async Task <Document> MakeObjectInitializerAsync(Document document, StatementSyntax statement, ISymbol variableSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { var blockParent = statement.FirstAncestorOrSelf <BlockSyntax>(); var objectCreationExpression = statement.DescendantNodes().OfType <ObjectCreationExpressionSyntax>().Single(); var newBlockParent = CreateNewBlockParent(statement, semanticModel, objectCreationExpression, variableSymbol); var root = await document.GetSyntaxRootAsync(cancellationToken); var newRoot = root.ReplaceNode(blockParent, newBlockParent); var newDocument = document.WithSyntaxRoot(newRoot); return(newDocument); }
public static List <ExpressionStatementSyntax> FindAssingmentExpressions(SemanticModel semanticModel, StatementSyntax statement, ISymbol variableSymbol) { var blockParent = statement.FirstAncestorOrSelf <BlockSyntax>(); var isBefore = true; var assignmentExpressions = new List <ExpressionStatementSyntax>(); foreach (var blockStatement in blockParent.Statements) { if (isBefore) { if (blockStatement.Equals(statement)) { isBefore = false; } } else { var expressionStatement = blockStatement as ExpressionStatementSyntax; if (expressionStatement == null) { break; } var assignmentExpression = expressionStatement.Expression as AssignmentExpressionSyntax; if (assignmentExpression == null || !assignmentExpression.IsKind(SyntaxKind.SimpleAssignmentExpression)) { break; } var memberAccess = assignmentExpression.Left as MemberAccessExpressionSyntax; if (memberAccess == null || !memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { break; } var memberIdentifier = memberAccess.Expression as IdentifierNameSyntax; if (memberIdentifier == null) { break; } var propertyIdentifier = memberAccess.Name as IdentifierNameSyntax; if (propertyIdentifier == null) { break; } if (!semanticModel.GetSymbolInfo(memberIdentifier).Symbol.Equals(variableSymbol)) { break; } assignmentExpressions.Add(expressionStatement); } } return(assignmentExpressions); }
private static BlockSyntax CreateNewBlockParent(StatementSyntax statement, SemanticModel semanticModel, ObjectCreationExpressionSyntax objectCreationExpression, ISymbol variableSymbol) { var blockParent = statement.FirstAncestorOrSelf <BlockSyntax>(); var assignmentExpressions = ObjectInitializerAnalyzer.FindAssingmentExpressions(semanticModel, statement, variableSymbol); var newBlockParent = SyntaxFactory.Block() .WithLeadingTrivia(blockParent.GetLeadingTrivia()) .WithTrailingTrivia(blockParent.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); var newAssignmentExpressions = new List <ExpressionStatementSyntax>(); for (int i = 0; i < blockParent.Statements.Count; i++) { var blockStatement = blockParent.Statements[i]; if (blockStatement.Equals(statement)) { var initializationExpressions = new List <AssignmentExpressionSyntax>(); foreach (var expressionStatement in assignmentExpressions) { var assignmentExpression = expressionStatement.Expression as AssignmentExpressionSyntax; var memberAccess = assignmentExpression.Left as MemberAccessExpressionSyntax; var propertyIdentifier = memberAccess.Name as IdentifierNameSyntax; initializationExpressions.Add(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, propertyIdentifier, assignmentExpression.Right)); } var initializers = SyntaxFactory.SeparatedList <ExpressionSyntax>(initializationExpressions); var newObjectCreationExpression = objectCreationExpression.WithInitializer( SyntaxFactory.InitializerExpression( SyntaxKind.ObjectInitializerExpression, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.OpenBraceToken, SyntaxFactory.ParseTrailingTrivia("\n")), initializers, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.CloseBraceToken, SyntaxFactory.ParseTrailingTrivia("")) )) .WithLeadingTrivia(objectCreationExpression.GetLeadingTrivia()) .WithTrailingTrivia(objectCreationExpression.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); var newLocalDeclarationStatement = statement.ReplaceNode(objectCreationExpression, newObjectCreationExpression) .WithLeadingTrivia(statement.GetLeadingTrivia()) .WithTrailingTrivia(statement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); newBlockParent = newBlockParent.AddStatements(newLocalDeclarationStatement); i += initializationExpressions.Count; } else { newBlockParent = newBlockParent.AddStatements(blockStatement .WithLeadingTrivia(blockStatement.GetLeadingTrivia()) .WithTrailingTrivia(blockStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation)); } } return(newBlockParent); }
private static bool IsDisposedOrAssigned(SemanticModel semanticModel, StatementSyntax statement, ILocalSymbol identitySymbol) { var method = statement.FirstAncestorOrSelf <MethodDeclarationSyntax>(); if (method == null) { return(false); } if (IsReturned(method, statement, semanticModel, identitySymbol)) { return(true); } foreach (var childStatements in method.Body.DescendantNodes().OfType <StatementSyntax>()) { if (childStatements.SpanStart > statement.SpanStart && (IsCorrectDispose(childStatements as ExpressionStatementSyntax, semanticModel, identitySymbol) || IsAssignedToField(childStatements as ExpressionStatementSyntax, semanticModel, identitySymbol))) { return(true); } } return(false); }
private static IList<StatementSyntax> GetChildStatementsAfter(StatementSyntax node) { var block = node.FirstAncestorOrSelf<BlockSyntax>(); var statements = block.Statements.Where(s => s.SpanStart > node.SpanStart).ToList(); return statements; }
private static List<List<StatementSyntax>> GetStatementsInBlocksAfter(StatementSyntax node) { var collectionOfStatements = new List<List<StatementSyntax>>(); var method = node.FirstAncestorOrSelf<MethodDeclarationSyntax>(); if (method?.Body == null) return collectionOfStatements; var currentBlock = node.FirstAncestorOfType<BlockSyntax>(); while (currentBlock != null) { var statements = new List<StatementSyntax>(); foreach (var statement in currentBlock.Statements) if (statement.SpanStart > node.SpanStart) statements.Add(statement); if (statements.Any()) collectionOfStatements.Add(statements); if (method.Body.Equals(currentBlock)) break; currentBlock = currentBlock.FirstAncestorOfType<BlockSyntax>(); } return collectionOfStatements; }
private static bool UsedOutsideParentBlock(SemanticModel semanticModel, StatementSyntax expressionStatement, ISymbol identitySymbol) { var block = expressionStatement.FirstAncestorOrSelf<BlockSyntax>(); var method = expressionStatement.FirstAncestorOrSelf<MethodDeclarationSyntax>(); var methodBlock = method.Body; if (methodBlock.Equals(block)) return false; var collectionOfStatementsAfter = GetStatementsInBlocksAfter(block); foreach (var allStatementsAfterBlock in collectionOfStatementsAfter) { if (!allStatementsAfterBlock.Any()) continue; var dataFlowAnalysis = semanticModel.AnalyzeDataFlow(allStatementsAfterBlock.First(), allStatementsAfterBlock.Last()); if (!dataFlowAnalysis.Succeeded) continue; var isUsed = dataFlowAnalysis.ReadInside.Contains(identitySymbol) || dataFlowAnalysis.WrittenInside.Contains(identitySymbol); if (isUsed) return true; } return false; }
private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) { if (context.IsGenerated()) { return; } var objectCreation = context.Node as ObjectCreationExpressionSyntax; if (objectCreation == null) { return; } if (objectCreation?.Parent is UsingStatementSyntax) { return; } if (objectCreation?.Parent is ReturnStatementSyntax) { return; } if (objectCreation.Ancestors().Any(i => i.IsAnyKind( SyntaxKind.ThisConstructorInitializer, SyntaxKind.BaseConstructorInitializer, SyntaxKind.ObjectCreationExpression))) { return; } var semanticModel = context.SemanticModel; var type = semanticModel.GetSymbolInfo(objectCreation.Type).Symbol as INamedTypeSymbol; if (type == null) { return; } if (!type.AllInterfaces.Any(i => i.ToString() == "System.IDisposable")) { return; } ISymbol identitySymbol = null; StatementSyntax statement = null; if (objectCreation.Parent.IsKind(SyntaxKind.SimpleAssignmentExpression)) { var assignmentExpression = (AssignmentExpressionSyntax)objectCreation.Parent; identitySymbol = semanticModel.GetSymbolInfo(assignmentExpression.Left).Symbol; if (identitySymbol?.Kind != SymbolKind.Local) { return; } if (assignmentExpression.FirstAncestorOrSelf <MethodDeclarationSyntax>() == null) { return; } var usingStatement = assignmentExpression.Parent as UsingStatementSyntax; if (usingStatement != null) { return; } statement = assignmentExpression.Parent as ExpressionStatementSyntax; } else if (objectCreation.Parent.IsKind(SyntaxKind.EqualsValueClause) && objectCreation.Parent.Parent.IsKind(SyntaxKind.VariableDeclarator)) { var variableDeclarator = (VariableDeclaratorSyntax)objectCreation.Parent.Parent; var variableDeclaration = variableDeclarator?.Parent as VariableDeclarationSyntax; identitySymbol = semanticModel.GetDeclaredSymbol(variableDeclarator); if (identitySymbol == null) { return; } var usingStatement = variableDeclaration?.Parent as UsingStatementSyntax; if (usingStatement != null) { return; } statement = variableDeclaration.Parent as LocalDeclarationStatementSyntax; if ((statement?.FirstAncestorOrSelf <MethodDeclarationSyntax>()) == null) { return; } } else { var props = new Dictionary <string, string> { { "typeName", type.Name } }.ToImmutableDictionary(); context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.GetLocation(), props, type.Name.ToString())); return; } if (statement != null && identitySymbol != null) { var isDisposeOrAssigned = IsDisposedOrAssigned(semanticModel, statement, (ILocalSymbol)identitySymbol); if (isDisposeOrAssigned) { return; } var props = new Dictionary <string, string> { { "typeName", type.Name } }.ToImmutableDictionary(); context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.GetLocation(), props, type.Name.ToString())); } }
private static BlockSyntax CreateNewBlockParent(StatementSyntax statement, SemanticModel semanticModel, ObjectCreationExpressionSyntax objectCreationExpression, ISymbol variableSymbol) { var blockParent = statement.FirstAncestorOrSelf<BlockSyntax>(); var assignmentExpressions = ObjectInitializerAnalyzer.FindAssignmentExpressions(semanticModel, statement, variableSymbol); var newBlockParent = SyntaxFactory.Block() .WithLeadingTrivia(blockParent.GetLeadingTrivia()) .WithTrailingTrivia(blockParent.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); for (int i = 0; i < blockParent.Statements.Count; i++) { var blockStatement = blockParent.Statements[i]; if (blockStatement.Equals(statement)) { var initializationExpressions = new List<AssignmentExpressionSyntax>(); foreach (var expressionStatement in assignmentExpressions) { var assignmentExpression = expressionStatement.Expression as AssignmentExpressionSyntax; var memberAccess = assignmentExpression.Left as MemberAccessExpressionSyntax; var propertyIdentifier = memberAccess.Name as IdentifierNameSyntax; var newAssignmentExpression = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, propertyIdentifier, assignmentExpression.Right); initializationExpressions.Add(newAssignmentExpression.WithTriviaFrom(expressionStatement)); } if (objectCreationExpression.Initializer != null) { var existentInitilizers = objectCreationExpression.Initializer.Expressions.Cast<AssignmentExpressionSyntax>() .Where(ae => { var propertyIdentifier = ae.Left.ToFullString().Trim(); return initializationExpressions.All(ie => ie.Left.ToFullString().Trim() != propertyIdentifier); }) .Select(ae => ae.WithoutTrivia()) .ToList(); initializationExpressions.InsertRange(0, existentInitilizers); } // Trailing trivia will be added before the separator if a simple separator list is used. This builds the separator token for expression // such that the trailing trivia from the original expression is added after the comma on the same line. var initializerSeparators = initializationExpressions.Take(initializationExpressions.Count - 1).Select(expr => SyntaxFactory.Token(SyntaxKind.CommaToken).WithTrailingTrivia(expr.GetTrailingTrivia())).ToList(); var lastInitializer = initializationExpressions.Last(); // Preserve the last initializer before rebuilding the list. // Get all but the last initializer without the trailing trivia. Trivia will be added after the separator from the list above. initializationExpressions = initializationExpressions.Take(initializationExpressions.Count - 1).Select(expr => expr.WithoutTrailingTrivia()).ToList(); initializationExpressions.Add(lastInitializer); // Add the last initializer with all of its trivia. var initializers = SyntaxFactory.SeparatedList<ExpressionSyntax>(initializationExpressions, initializerSeparators); var newObjectCreationExpression = objectCreationExpression.WithInitializer( SyntaxFactory.InitializerExpression( SyntaxKind.ObjectInitializerExpression, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.OpenBraceToken, SyntaxFactory.ParseTrailingTrivia(Environment.NewLine)), initializers, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.CloseBraceToken, SyntaxFactory.ParseTrailingTrivia("")) )) .WithLeadingTrivia(objectCreationExpression.GetLeadingTrivia()) .WithTrailingTrivia(objectCreationExpression.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); if (newObjectCreationExpression.ArgumentList?.Arguments.Count == 0) { newObjectCreationExpression = newObjectCreationExpression.WithArgumentList(null); } var newLocalDeclarationStatement = statement.ReplaceNode(objectCreationExpression, newObjectCreationExpression) .WithLeadingTrivia(statement.GetLeadingTrivia()) .WithTrailingTrivia(statement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); newBlockParent = newBlockParent.AddStatements(newLocalDeclarationStatement); i += initializationExpressions.Count; } else { newBlockParent = newBlockParent.AddStatements(blockStatement .WithLeadingTrivia(blockStatement.GetLeadingTrivia()) .WithTrailingTrivia(blockStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation)); } } return newBlockParent; }
public static List<ExpressionStatementSyntax> FindAssignmentExpressions(SemanticModel semanticModel, StatementSyntax statement, ISymbol variableSymbol) { var blockParent = statement.FirstAncestorOrSelf<BlockSyntax>(); var isBefore = true; var assignmentExpressions = new List<ExpressionStatementSyntax>(); foreach (var blockStatement in blockParent.Statements) { if (isBefore) { if (blockStatement.Equals(statement)) isBefore = false; } else { var expressionStatement = blockStatement as ExpressionStatementSyntax; if (expressionStatement == null) break; var assignmentExpression = expressionStatement.Expression as AssignmentExpressionSyntax; if (assignmentExpression == null || !assignmentExpression.IsKind(SyntaxKind.SimpleAssignmentExpression)) break; var memberAccess = assignmentExpression.Left as MemberAccessExpressionSyntax; if (memberAccess == null || !memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression)) break; var memberIdentifier = memberAccess.Expression as IdentifierNameSyntax; if (memberIdentifier == null) break; var propertyIdentifier = memberAccess.Name as IdentifierNameSyntax; if (propertyIdentifier == null) break; if (!semanticModel.GetSymbolInfo(memberIdentifier).Symbol.Equals(variableSymbol)) break; assignmentExpressions.Add(expressionStatement); } } return assignmentExpressions; }
private static bool IsDisposedOrAssigned(SemanticModel semanticModel, StatementSyntax statement, ILocalSymbol identitySymbol) { var method = statement.FirstAncestorOrSelf<MethodDeclarationSyntax>(); if (method == null) return false; if (IsReturned(method, statement, semanticModel, identitySymbol)) return true; foreach (var childStatements in method.Body.DescendantNodes().OfType<StatementSyntax>()) { if (childStatements.SpanStart > statement.SpanStart && (IsCorrectDispose(childStatements as ExpressionStatementSyntax, semanticModel, identitySymbol) || IsAssignedToField(childStatements as ExpressionStatementSyntax, semanticModel, identitySymbol))) return true; } return false; }
private static BlockSyntax CreateNewBlockParent(StatementSyntax statement, SemanticModel semanticModel, ObjectCreationExpressionSyntax objectCreationExpression, ISymbol variableSymbol) { var blockParent = statement.FirstAncestorOrSelf <BlockSyntax>(); var assignmentExpressions = ObjectInitializerAnalyzer.FindAssignmentExpressions(semanticModel, statement, variableSymbol); var newBlockParent = SyntaxFactory.Block() .WithLeadingTrivia(blockParent.GetLeadingTrivia()) .WithTrailingTrivia(blockParent.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); for (int i = 0; i < blockParent.Statements.Count; i++) { var blockStatement = blockParent.Statements[i]; if (blockStatement.Equals(statement)) { var initializationExpressions = new List <AssignmentExpressionSyntax>(); foreach (var expressionStatement in assignmentExpressions) { var assignmentExpression = expressionStatement.Expression as AssignmentExpressionSyntax; var memberAccess = assignmentExpression.Left as MemberAccessExpressionSyntax; var propertyIdentifier = memberAccess.Name as IdentifierNameSyntax; var newAssignmentExpression = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, propertyIdentifier, assignmentExpression.Right); initializationExpressions.Add(newAssignmentExpression.WithTriviaFrom(expressionStatement)); } if (objectCreationExpression.Initializer != null) { var existentInitilizers = objectCreationExpression.Initializer.Expressions.Cast <AssignmentExpressionSyntax>() .Where(ae => { var propertyIdentifier = ae.Left.ToFullString().Trim(); return(initializationExpressions.All(ie => ie.Left.ToFullString().Trim() != propertyIdentifier)); }) .Select(ae => ae.WithoutTrivia()) .ToList(); initializationExpressions.InsertRange(0, existentInitilizers); } // Trailing trivia will be added before the separator if a simple separator list is used. This builds the separator token for expression // such that the trailing trivia from the original expression is added after the comma on the same line. var initializerSeparators = initializationExpressions.Take(initializationExpressions.Count - 1).Select(expr => SyntaxFactory.Token(SyntaxKind.CommaToken).WithTrailingTrivia(expr.GetTrailingTrivia())).ToList(); var lastInitializer = initializationExpressions.Last(); // Preserve the last initializer before rebuilding the list. // Get all but the last initializer without the trailing trivia. Trivia will be added after the separator from the list above. initializationExpressions = initializationExpressions.Take(initializationExpressions.Count - 1).Select(expr => expr.WithoutTrailingTrivia()).ToList(); initializationExpressions.Add(lastInitializer); // Add the last initializer with all of its trivia. var initializers = SyntaxFactory.SeparatedList <ExpressionSyntax>(initializationExpressions, initializerSeparators); var newObjectCreationExpression = objectCreationExpression.WithInitializer( SyntaxFactory.InitializerExpression( SyntaxKind.ObjectInitializerExpression, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.OpenBraceToken, SyntaxFactory.ParseTrailingTrivia(Environment.NewLine)), initializers, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.CloseBraceToken, SyntaxFactory.ParseTrailingTrivia("")) )) .WithLeadingTrivia(objectCreationExpression.GetLeadingTrivia()) .WithTrailingTrivia(objectCreationExpression.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); if (newObjectCreationExpression.ArgumentList?.Arguments.Count == 0) { newObjectCreationExpression = newObjectCreationExpression.WithArgumentList(null); } var newLocalDeclarationStatement = statement.ReplaceNode(objectCreationExpression, newObjectCreationExpression) .WithLeadingTrivia(statement.GetLeadingTrivia()) .WithTrailingTrivia(statement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); newBlockParent = newBlockParent.AddStatements(newLocalDeclarationStatement); i += assignmentExpressions.Count; } else { newBlockParent = newBlockParent.AddStatements(blockStatement .WithLeadingTrivia(blockStatement.GetLeadingTrivia()) .WithTrailingTrivia(blockStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation)); } } return(newBlockParent); }
private static BlockSyntax CreateNewBlockParent(StatementSyntax statement, SemanticModel semanticModel, ObjectCreationExpressionSyntax objectCreationExpression, ISymbol variableSymbol) { var blockParent = statement.FirstAncestorOrSelf <BlockSyntax>(); var assignmentExpressions = ObjectInitializerAnalyzer.FindAssignmentExpressions(semanticModel, statement, variableSymbol); var newBlockParent = SyntaxFactory.Block() .WithLeadingTrivia(blockParent.GetLeadingTrivia()) .WithTrailingTrivia(blockParent.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); for (int i = 0; i < blockParent.Statements.Count; i++) { var blockStatement = blockParent.Statements[i]; if (blockStatement.Equals(statement)) { var initializationExpressions = new List <AssignmentExpressionSyntax>(); foreach (var expressionStatement in assignmentExpressions) { var assignmentExpression = expressionStatement.Expression as AssignmentExpressionSyntax; var memberAccess = assignmentExpression.Left as MemberAccessExpressionSyntax; var propertyIdentifier = memberAccess.Name as IdentifierNameSyntax; var newAssignmentExpression = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, propertyIdentifier, assignmentExpression.Right); initializationExpressions.Add(newAssignmentExpression); } if (objectCreationExpression.Initializer != null) { var existentInitilizers = objectCreationExpression.Initializer.Expressions.Cast <AssignmentExpressionSyntax>() .Where(ae => { var propertyIdentifier = ae.Left.ToFullString().Trim(); return(initializationExpressions.All(ie => ie.Left.ToFullString().Trim() != propertyIdentifier)); }) .Select(ae => ae.WithoutTrivia()) .ToList(); initializationExpressions.InsertRange(0, existentInitilizers); } var initializers = SyntaxFactory.SeparatedList <ExpressionSyntax>(initializationExpressions); var newObjectCreationExpression = objectCreationExpression.WithInitializer( SyntaxFactory.InitializerExpression( SyntaxKind.ObjectInitializerExpression, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.OpenBraceToken, SyntaxFactory.ParseTrailingTrivia(Environment.NewLine)), initializers, SyntaxFactory.Token(SyntaxFactory.ParseLeadingTrivia(" "), SyntaxKind.CloseBraceToken, SyntaxFactory.ParseTrailingTrivia("")) )) .WithLeadingTrivia(objectCreationExpression.GetLeadingTrivia()) .WithTrailingTrivia(objectCreationExpression.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); if (newObjectCreationExpression.ArgumentList?.Arguments.Count == 0) { newObjectCreationExpression = newObjectCreationExpression.WithArgumentList(null); } var newLocalDeclarationStatement = statement.ReplaceNode(objectCreationExpression, newObjectCreationExpression) .WithLeadingTrivia(statement.GetLeadingTrivia()) .WithTrailingTrivia(statement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation); newBlockParent = newBlockParent.AddStatements(newLocalDeclarationStatement); i += initializationExpressions.Count; } else { newBlockParent = newBlockParent.AddStatements(blockStatement .WithLeadingTrivia(blockStatement.GetLeadingTrivia()) .WithTrailingTrivia(blockStatement.GetTrailingTrivia()) .WithAdditionalAnnotations(Formatter.Annotation)); } } return(newBlockParent); }
public Document GetRefactoredDocument(CancellationToken cancellationToken) { lock (this) { var start = DateTime.Now; Utils.Trace(string.Format("Trying to extract method, span: {0}", this.textSpan)); var localDocument = document; var extracted = ExtractMethodService.ExtractMethod(localDocument, this.textSpan, new ExtractMethodOptions(true), cancellationToken); Utils.TraceTime("Roslyn extract method", DateTime.Now - start); if (!extracted.Succeeded) { Utils.Trace("Method Extraction failed!"); return(null); } Utils.Trace("Extract method: ok"); var clock = DateTime.Now; var resultingTree = localDocument.GetSyntaxTree(cancellationToken).GetRoot(cancellationToken); var newMethodSyntax = extracted.MethodDeclarationNode as MethodDeclarationSyntax; if (newMethodSyntax == null) { return(null); } var body = newMethodSyntax.Body; var compilationUnitDeclaration = resultingTree as CompilationUnitSyntax; if (compilationUnitDeclaration == null) { return(null); } var oldTree = localDocument.GetSyntaxTree(cancellationToken); if (oldTree == null) { return(null); } Utils.Trace("Got the original syntax tree"); var oldRoot = oldTree.GetRoot() as SyntaxNode; // find the smallest containing statement (and the Utils.Trace("Searching for the statement containing the new call"); StatementSyntax containingStatement = extracted.InvocationNameToken.Parent.FirstAncestorOrSelf <StatementSyntax>(); if (containingStatement == null) { Utils.Trace("No containing statement found. Aborting"); return(null); } Utils.Trace("Containing statement found"); Utils.Trace("Searching for the right spots where to place the placeholder calls"); var oldText = oldTree.GetText().ToString(); var beforeRefactoringText = oldText.Substring(0, containingStatement.Span.Start - 1); var afterRefactoringText = oldText.Substring(containingStatement.Span.Start + containingStatement.Span.Length); //var sub = oldText.Substring(containingStatement.Span.Start, containingStatement.Span.Length); var sub = oldText.Substring(this.textSpan.Start, this.textSpan.Length); Utils.Trace("Generating the Precondition marker"); var actualParameters = ""; var formalParameters = ""; var ps = newMethodSyntax.ParameterList.Parameters; for (int i = 0, j = 0, n = ps.Count; i < n; i++) { var p = ps[i]; { var modifiers = ""; foreach (var modifier in p.Modifiers) { modifiers = modifiers + modifier.ValueText + " "; } // Avoid the refs when emitting the condition if (!String.IsNullOrEmpty(modifiers)) { if (0 < j) { actualParameters += ","; formalParameters += ","; } var name = p.Identifier.ValueText; actualParameters += name; formalParameters += p.Type + " " + name; j++; } } } // todo: just use invocation, but replace the method name with __PreconditionMarker! var preconditionMarker = "__PreconditionMarker(" + actualParameters + ");"; Utils.Trace("Generating the Postcondition marker"); var postconditionMarker = "__PostconditionMarker(" + (actualParameters.Length > 0 ? actualParameters : ""); BinaryExpressionSyntax assignment = null; var invocationExpression = extracted.InvocationNameToken.Parent.Parent as InvocationExpressionSyntax; if (invocationExpression != null) { var expression = invocationExpression.Parent.FirstAncestorOrSelf <ExpressionSyntax>(); if (expression != null && expression.Kind == SyntaxKind.AssignExpression) { // TODO: what about += or local declarations? should they be included? assignment = (BinaryExpressionSyntax)expression; } } if (assignment == null) // then the extraction was at the statement level { postconditionMarker += (actualParameters.Length > 0 ? "," : "") + "false"; } else { postconditionMarker += (actualParameters.Length > 0 ? "," : "") + assignment.Left.GetText() + ", true"; } postconditionMarker += ");"; Utils.Trace("Searching for the enclosing method"); // now need to climb up to enclosing method so definitions of the markers can be inserted MethodDeclarationSyntax containingMethod = containingStatement.FirstAncestorOrSelf <MethodDeclarationSyntax>(); if (containingMethod == null) { Utils.Trace("No enclosing method found: Aborting"); return(null); } Utils.Trace("Enclosing method found"); Utils.Trace("Computing string positions for dummy methods"); var beforeMethodText = oldText.Substring(0, containingMethod.Span.Start - 1); var inMethodBeforeRefactoringText = oldText.Substring(containingMethod.Span.Start, this.textSpan.Start - containingMethod.Span.Start); var remaining = oldText.Substring(this.textSpan.End); Utils.Trace("Adding dummy methods"); var preconditionMarkerDef = "[Pure]\npublic void __PreconditionMarker(" + formalParameters + "){}\n"; // It is generic only if there is a parameter representing the return value var postconditionMarkerDef = assignment != null ? "[Pure]\npublic void __PostconditionMarker<T>(" + formalParameters + (formalParameters.Length > 0 ? "," : "") + "T x,bool returnValue){}\n" : "[Pure]\npublic void __PostconditionMarker(" + formalParameters + (formalParameters.Length > 0 ? "," : "") + " bool returnValue = false){}\n" ; var newProg = String.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}\n{6}\n{7}", beforeMethodText, preconditionMarkerDef, postconditionMarkerDef, inMethodBeforeRefactoringText, preconditionMarker, sub, postconditionMarker, remaining); var newSolution = localDocument.Project.Solution.WithDocumentText(document.Id, new StringText(newProg)); //var newSolution = localDocument.Project.Solution.UpdateDocument(document.Id, new StringText(newProg)); localDocument = newSolution.GetDocument(document.Id); var newTree = localDocument.GetSyntaxTree(); Utils.Trace("Dumping annotated tree"); Utils.DumpCSFile(@"AnnotatedTree.cs", newTree.GetText().ToString(), @"Program with marker explicits"); var newRoot = (CompilationUnitSyntax)newTree.GetRoot(); if (newRoot.ContainsDiagnostics) { return(null); } Utils.Trace("Searching the extracted method"); MethodDeclarationSyntax newExtractedMethod, originalMethod; newExtractedMethod = extracted.MethodDeclarationNode as MethodDeclarationSyntax; if (newExtractedMethod == null) { Utils.Trace("Extracted method not found: aborting"); return(null); } Utils.Trace("Extracted method found"); originalMethod = newExtractedMethod; // Getting the name of the method MethodDeclarationSyntax methodToAnalyze = containingStatement.FirstAncestorOrSelf <MethodDeclarationSyntax>(); if (methodToAnalyze == null) { Utils.Trace("Extractee method not found: aborting"); return(null); } Utils.Trace("Extractee method found."); Utils.TraceTime("Generating annotated tree", DateTime.Now - clock); clock = DateTime.Now; // reset the clock // now let Clousot see the rewritten unit Utils.Trace("Running Clousot to extract <Ps, Qs>"); newExtractedMethod = ExtractAndAddPsQs(ref cancellationToken, localDocument, newRoot, newExtractedMethod); Utils.TraceTime("Running Clousot to extract <Ps, Qs>", DateTime.Now - clock); clock = DateTime.Now; if (newExtractedMethod == null) { Utils.Trace("Aborting: failed to infer <Ps, Qs>"); return(null); } Utils.Trace("Checking we have new contracts"); #if DEBUG || TRACE // If we added some contract if (newExtractedMethod == originalMethod) { Utils.Trace("no new contract, but we continue to get the <Pm, Qm>"); //return null; } #endif Utils.Trace("Creating a new tree"); var refactoredTree = (SyntaxNode)extracted.Document.GetSyntaxRoot().ReplaceNode(originalMethod, Formatter.Annotation.AddAnnotationTo(newExtractedMethod)); //(SyntaxNode)resultingTree.ReplaceNode(originalMethod, Formatter.Annotation.AddAnnotationTo(newExtractedMethod)); Utils.DumpCSFile(@"RefactoredProgram.cs", refactoredTree.ToFullString(), "Program with extracted contracts (Ps, Qs)"); //Utils.DumpCSFile(@"RefactoredProgram.cs", refactoredTree.GetFullText(), "Program with extracted contracts (Ps, Qs)"); var annotatedMethod = ExtractAndAddPmQm(ref cancellationToken, localDocument, refactoredTree, newExtractedMethod); if (annotatedMethod == null) { Utils.Trace("Aborting: failed to annotate the method"); return(null); } Utils.TraceTime("Running Clousot to extract <Pm, Qm>", DateTime.Now - clock); if (annotatedMethod != newExtractedMethod) { Utils.Trace("Found new contracts, updating the method"); Utils.TraceTime("Done!", DateTime.Now - start); refactoredTree = (SyntaxNode)extracted.Document.GetSyntaxRoot().ReplaceNode(originalMethod, Formatter.Annotation.AddAnnotationTo(annotatedMethod)); } Utils.TraceTime("Done!", DateTime.Now - start); return(localDocument.WithSyntaxRoot(refactoredTree)); //return this.editFactory.CreateTreeTransformEdit(localDocument.Project.Solution, localDocument.GetSyntaxTree(), refactoredTree); } }