protected override IEnumerable <CodeAction> GetFixes(BaseSemanticModel context, Node env, string variableName) { var containingStatement = env.ContainingStatement; // we don't give a fix for these cases since the general fix may not work // lambda in while/do-while/for condition if (containingStatement is WhileStatement || containingStatement is DoWhileStatement || containingStatement is ForStatement) { yield break; } // lambda in for initializer/iterator if (containingStatement.Parent is ForStatement && ((ForStatement)containingStatement.Parent).EmbeddedStatement != containingStatement) { yield break; } Action <Script> action = script => { var newName = LocalVariableNamePicker.PickSafeName( containingStatement.GetParent <EntityDeclaration>(), Enumerable.Range(1, 100).Select(i => variableName + i)); var variableDecl = new VariableDeclarationStatement(new SimpleType("var"), newName, new IdentifierExpression(variableName)); if (containingStatement.Parent is BlockStatement || containingStatement.Parent is SwitchSection) { script.InsertBefore(containingStatement, variableDecl); } else { var offset = script.GetCurrentOffset(containingStatement.StartLocation); script.InsertBefore(containingStatement, variableDecl); script.InsertText(offset, "{"); script.InsertText(script.GetCurrentOffset(containingStatement.EndLocation), "}"); script.FormatText(containingStatement.Parent); } var textNodes = new List <AstNode>(); textNodes.Add(variableDecl.Variables.First().NameToken); foreach (var reference in env.GetAllReferences()) { var identifier = new IdentifierExpression(newName); script.Replace(reference.AstNode, identifier); textNodes.Add(identifier); } script.Link(textNodes.ToArray()); }; yield return(new CodeAction(context.TranslateString("Copy to local variable"), action, env.AstNode)); }
public GatherVisitor(BaseSemanticModel context, SyntaxTree unit, AccessToClosureIssue qualifierDirectiveEvidentIssueProvider) : base(context, qualifierDirectiveEvidentIssueProvider) { this.title = context.TranslateString(qualifierDirectiveEvidentIssueProvider.Title); }
public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) { base.VisitVariableDeclarationStatement(variableDeclarationStatement); var rootNode = variableDeclarationStatement.Parent as BlockStatement; if (rootNode == null) { // We are somewhere weird, like a the ResourceAquisition of a using statement return; } // TODO: Handle declarations with more than one variable? if (variableDeclarationStatement.Variables.Count > 1) { return; } var variableInitializer = variableDeclarationStatement.Variables.First(); var identifiers = GetIdentifiers(rootNode.Descendants, variableInitializer.Name).ToList(); if (identifiers.Count == 0) { // variable is not used return; } if (!CheckForInvocations(variableInitializer.Initializer)) { return; } AstNode deepestCommonAncestor = GetDeepestCommonAncestor(rootNode, identifiers); var path = GetPath(rootNode, deepestCommonAncestor); // The node that will follow the moved declaration statement AstNode anchorNode = GetInitialAnchorNode(rootNode, identifiers, path); // Restrict path to only those where the initializer has not changed var pathToCheck = path.Skip(1).ToList(); var firstInitializerChangeNode = GetFirstInitializerChange(variableDeclarationStatement, pathToCheck, variableInitializer.Initializer); if (firstInitializerChangeNode != null) { // The node changing the initializer expression may not be on the path // to the actual usages of the variable, so we need to merge the paths // so we get the part of the paths that are common between them var pathToChange = GetPath(rootNode, firstInitializerChangeNode); var deepestCommonIndex = GetLowestCommonAncestorIndex(path, pathToChange); anchorNode = pathToChange[deepestCommonIndex + 1]; path = pathToChange.Take(deepestCommonIndex).ToList(); } // Restrict to locations outside of blacklisted node types var firstBlackListedNode = path.Where(node => moveTargetBlacklist.Contains(node.GetType())).FirstOrDefault(); if (firstBlackListedNode != null) { path = GetPath(rootNode, firstBlackListedNode.Parent); anchorNode = firstBlackListedNode; } anchorNode = GetInsertionPoint(anchorNode); if (anchorNode != null && anchorNode != rootNode && anchorNode.Parent != rootNode) { AddDiagnosticAnalyzer(new CodeIssue(variableDeclarationStatement, context.TranslateString("Variable could be moved to a nested scope"), GetActions(variableDeclarationStatement, (Statement)anchorNode))); } }
protected override IEnumerable<CodeAction> GetFixes(BaseSemanticModel context, Node env, string variableName) { var containingStatement = env.ContainingStatement; // we don't give a fix for these cases since the general fix may not work // lambda in while/do-while/for condition if (containingStatement is WhileStatement || containingStatement is DoWhileStatement || containingStatement is ForStatement) yield break; // lambda in for initializer/iterator if (containingStatement.Parent is ForStatement && ((ForStatement)containingStatement.Parent).EmbeddedStatement != containingStatement) yield break; Action<Script> action = script => { var newName = LocalVariableNamePicker.PickSafeName( containingStatement.GetParent<EntityDeclaration>(), Enumerable.Range(1, 100).Select(i => variableName + i)); var variableDecl = new VariableDeclarationStatement(new SimpleType("var"), newName, new IdentifierExpression(variableName)); if (containingStatement.Parent is BlockStatement || containingStatement.Parent is SwitchSection) { script.InsertBefore(containingStatement, variableDecl); } else { var offset = script.GetCurrentOffset(containingStatement.StartLocation); script.InsertBefore(containingStatement, variableDecl); script.InsertText(offset, "{"); script.InsertText(script.GetCurrentOffset(containingStatement.EndLocation), "}"); script.FormatText(containingStatement.Parent); } var textNodes = new List<AstNode>(); textNodes.Add(variableDecl.Variables.First().NameToken); foreach (var reference in env.GetAllReferences()) { var identifier = new IdentifierExpression(newName); script.Replace(reference.AstNode, identifier); textNodes.Add(identifier); } script.Link(textNodes.ToArray()); }; yield return new CodeAction(context.TranslateString("Copy to local variable"), action, env.AstNode); }