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);
        }