public CodeRefactoring GetRefactoring(IDocument document, TextSpan textSpan, CancellationToken cancellationToken) { var tree = (SyntaxTree)document.GetSyntaxTree(cancellationToken); var token = tree.GetRoot().FindToken(textSpan.Start); if (token.Parent is ClassDeclarationSyntax || token.Parent is StructDeclarationSyntax) { var t = (TypeDeclarationSyntax)token.Parent; if (!CanInferNonTrivialConstructor(t)) return null; return new CodeRefactoring(new[] { new ReadyCodeAction("Infer Non-Trivial Constructor", document, t, () => { var c = TryInferNonTrivialConstructor(t, document.TryGetSemanticModel()); var i = 0; var ms = t.Members.Insert(i, new[] {c}).List(); return t.With(members: ms); })}); } if (token.Parent is MemberDeclarationSyntax && (token.Parent.Parent is ClassDeclarationSyntax || token.Parent.Parent is StructDeclarationSyntax)) { var m = (MemberDeclarationSyntax)token.Parent; var t = (TypeDeclarationSyntax)m.Parent; if (!CanInferNonTrivialConstructor(t)) return null; return new CodeRefactoring(new[] { new ReadyCodeAction("Infer Non-Trivial Constructor Here", document, t, () => { var c = TryInferNonTrivialConstructor(t, document.TryGetSemanticModel()); var i = t.Members.IndexOf(m); var ms = t.Members.Insert(i, new[] {c}).List(); return t.With(members: ms); })}); } return null; }
/* Check the preconditions of rename refactoring, return true if can be finished succesfully. */ public static bool CheckRenamePreconditions(IDocument document, int start, int length) { var service = ServiceArchive.getInstance().RenameService; ISemanticModel model; document.TryGetSemanticModel(out model); return false; }
public CodeRefactoring GetRefactoring(IDocument document, TextSpan textSpan, CancellationToken cancellationToken) { var tree = (SyntaxTree)document.GetSyntaxTree(cancellationToken); var root = tree.GetRoot(cancellationToken); var token = tree.GetRoot().FindToken(textSpan.Start); var m = token.Parent as MethodDeclarationSyntax; if (m == null) return null; var model = document.TryGetSemanticModel(); if (model == null) return null; return new CodeRefactoring(new[] { new ReadyCodeAction( "Remove method and calls to method (including any side-effects in arguments)", document, root, () => document.NewRootForNukeMethodAndAnySideEffectsInArguments(m))}); }
public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken) { var assume = Assumptions.All; var c = (StatementSyntax)node; if (!(c.Parent is BlockSyntax)) { if (c is EmptyStatementSyntax) return null; if (c is BlockSyntax && c.Statements().None()) return null; } if (c.HasSideEffects(document.TryGetSemanticModel(), assume) != false) return null; return new[] { new CodeIssue(CodeIssue.Severity.Warning, c.Span, "Statement without any effect", new[] { new ReadyCodeAction( "Remove Unnecessary Statement", document, c, () => c.Parent is BlockSyntax ? null : Syntax.EmptyStatement())})}; }
public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken) { var model = document.TryGetSemanticModel(); if (model == null) return null; if (model.GetDiagnostics().Any(e => e.Info.Severity == DiagnosticSeverity.Error)) return null; if (document.Project.Documents.Any(e => e.GetSyntaxTree() == null || e.GetSemanticModel() == null)) return null; var fieldNode = (FieldDeclarationSyntax)node; if (fieldNode.IsReadOnly()) return null; var classDecl = fieldNode.Ancestors().OfType<ClassDeclarationSyntax>().FirstOrDefault(); if (classDecl == null) return null; var constructors = classDecl.Members.OfType<ConstructorDeclarationSyntax>().ToRet(); var modsWithReadOnly = fieldNode.Modifiers.Append(SyntaxKind.ReadOnlyKeyword.AsToken()).AsTokenList(); var scopes = fieldNode.IsPrivate() ? new[] {Tuple.Create((CommonSyntaxNode)classDecl, model)} : document.Project.Documents.Select(e => Tuple.Create(e.GetSyntaxTree().GetRoot(), e.GetSemanticModel())); var unmutatedVars = fieldNode.Declaration.Variables.Where(v => { var field = model.GetDeclaredSymbol(v); if (scopes.Any(c => c.Item1.DescendantNodes(e => !constructors.Contains(e)).OfType<ExpressionSyntax>().Any(e => SurfaceWritesTo(e, c.Item2, field)))) return false; return true; }).ToArray(); if (unmutatedVars.Length == 0) return null; if (unmutatedVars.Length == fieldNode.Declaration.Variables.Count) { var r = new ReadyCodeAction("Make readonly", document, fieldNode, () => fieldNode.WithModifiers(modsWithReadOnly)); var desc = unmutatedVars.Length == 1 ? "Mutable field is never modified." : "Mutable fields are never modified."; return r.CodeIssues1(CodeIssue.Severity.Warning, fieldNode.Declaration.Type.Span, desc); } return unmutatedVars.Select(v => { var singleReadOnly = fieldNode.WithModifiers(modsWithReadOnly) .WithDeclaration(fieldNode.Declaration.WithVariables(v.SepList1())); var rest = fieldNode .WithLeadingTrivia() .WithTrailingTrivia(Syntax.Whitespace(Environment.NewLine)) .WithDeclaration(fieldNode.Declaration.WithVariables(fieldNode.Declaration.Variables.Without(v))); var newClassDecl = classDecl.With(members: classDecl.Members.WithItemReplacedByMany(fieldNode, new[] { singleReadOnly, rest })); var action = new ReadyCodeAction("Split readonly", document, classDecl, () => newClassDecl); return new CodeIssue(CodeIssue.Severity.Warning, v.Identifier.Span, "Mutable field is never modified.", new[] { action }); }).ToArray(); }
public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken) { var forLoop = (ForEachStatementSyntax)node; var model = document.TryGetSemanticModel(); if (model == null) return null; // list created just before loop starts? var initStatement = forLoop.TryGetPrevStatement(); var lhs = initStatement.TryGetLHSExpOfAssignmentOrInit() as IdentifierNameSyntax; if (lhs == null) return null; var target = lhs.Identifier; var rhs = initStatement.TryGetRHSOfAssignmentOrInit() as ObjectCreationExpressionSyntax; if (rhs == null) return null; var cr = model.GetTypeInfo(rhs).Type; if (cr.AllInterfaces.All(e => e.Name != "IList")) return null; // loop adds things directly into the list? var adderStatement = forLoop.Statement.Statements().SingleOrDefaultAllowMany() as ExpressionStatementSyntax; if (adderStatement == null) return null; var adderInvoke = adderStatement.Expression as InvocationExpressionSyntax; if (adderInvoke == null) return null; var adderAccess = adderInvoke.Expression as MemberAccessExpressionSyntax; if (adderAccess == null) return null; var adderTarget = adderAccess.Expression as IdentifierNameSyntax; if (adderTarget == null) return null; if (adderTarget.PlainName != target.ValueText) return null; if (adderAccess.Name.PlainName != "Add") return null; if (adderInvoke.ArgumentList.Arguments.Count != 1) return null; var adderExp = adderInvoke.ArgumentList.Arguments.Single().Expression as SimpleNameSyntax; if (adderExp == null) return null; if (adderExp.PlainName != forLoop.Identifier.ValueText) return null; var linqed = forLoop.Expression.Accessing("ToList").Invoking(); var replacedInit = initStatement.TryWithNewRightHandSideOfAssignmentOrSingleInit(linqed); var action = new ReadyCodeAction( "Select into list", document, new[] { initStatement, forLoop }, (e, a) => e == initStatement ? replacedInit : a.Dropped()); return action.CodeIssues1( CodeIssue.Severity.Warning, forLoop.ForEachKeyword.Span, "Initializing a list with a 'for each' loop."); }