Пример #1
0
 static bool FindDeclarationPoint(DefiniteAssignmentAnalysis daa, string variableName, bool allowPassIntoLoops, BlockStatement block, out Statement declarationPoint)
 {
     // declarationPoint: The point where the variable would be declared, if we decide to declare it in this block
     declarationPoint = null;
     foreach (Statement stmt in block.Statements)
     {
         if (UsesVariable(stmt, variableName))
         {
             if (declarationPoint == null)
             {
                 declarationPoint = stmt;
             }
             if (!CanMoveVariableUseIntoSubBlock(stmt, variableName, allowPassIntoLoops))
             {
                 // If it's not possible to move the variable use into a nested block,
                 // we need to declare the variable in this block
                 return(false);
             }
             // If we can move the variable into the sub-block, we need to ensure that the remaining code
             // does not use the value that was assigned by the first sub-block
             Statement nextStatement = stmt.GetNextStatement();
             if (nextStatement != null)
             {
                 // Analyze the range from the next statement to the end of the block
                 daa.SetAnalyzedRange(nextStatement, block);
                 daa.Analyze(variableName);
                 if (daa.UnassignedVariableUses.Count > 0)
                 {
                     return(false);
                 }
             }
         }
     }
     return(true);
 }
Пример #2
0
		static bool FindDeclarationPoint(DefiniteAssignmentAnalysis daa, string variableName, bool allowPassIntoLoops, BlockStatement block, out Statement declarationPoint)
		{
			// declarationPoint: The point where the variable would be declared, if we decide to declare it in this block
			declarationPoint = null;
			foreach (Statement stmt in block.Statements) {
				if (UsesVariable(stmt, variableName)) {
					if (declarationPoint == null)
						declarationPoint = stmt;
					if (!CanMoveVariableUseIntoSubBlock(stmt, variableName, allowPassIntoLoops)) {
						// If it's not possible to move the variable use into a nested block,
						// we need to declare the variable in this block
						return false;
					}
					// If we can move the variable into the sub-block, we need to ensure that the remaining code
					// does not use the value that was assigned by the first sub-block
					Statement nextStatement = stmt.GetNextStatement();
					if (nextStatement != null) {
						// Analyze the range from the next statement to the end of the block
						daa.SetAnalyzedRange(nextStatement, block);
						daa.Analyze(variableName);
						if (daa.UnassignedVariableUses.Count > 0) {
							return false;
						}
					}
				}
			}
			return true;
		}
		CodeAction CreateFromStatements(RefactoringContext context, List<Statement> statements)
		{
			if (!(statements [0].Parent is Statement))
				return null;
			
			return new CodeAction(context.TranslateString("Extract method"), script => {
				string methodName = "NewMethod";
				var method = new MethodDeclaration() {
					ReturnType = new PrimitiveType("void"),
					Name = methodName,
					Body = new BlockStatement()
				};
				bool usesNonStaticMember = false;
				foreach (Statement node in statements) {
					usesNonStaticMember |= StaticVisitor.UsesNotStaticMember(context, node);
					method.Body.Add(node.Clone());
				}
				if (!usesNonStaticMember)
					method.Modifiers |= Modifiers.Static;
				
				var target = new IdentifierExpression(methodName);
				var invocation = new InvocationExpression(target);
				
				var usedVariables = VariableLookupVisitor.Analyze(context, statements);
				
				var extractedCodeAnalysis = new DefiniteAssignmentAnalysis(
					(Statement)statements [0].Parent,
					context.Resolver,
					context.CancellationToken);
				var lastStatement = statements [statements.Count - 1];
				extractedCodeAnalysis.SetAnalyzedRange(statements [0], lastStatement);
				var statusAfterMethod = new List<Tuple<IVariable, DefiniteAssignmentStatus>>();
				
				foreach (var variable in usedVariables) {
					extractedCodeAnalysis.Analyze(
						variable.Name,
						DefiniteAssignmentStatus.PotentiallyAssigned,
						context.CancellationToken);
					statusAfterMethod.Add(Tuple.Create(variable, extractedCodeAnalysis.GetStatusAfter(lastStatement)));
				}
				var stmt = statements [0].GetParent<BlockStatement>();
				while (stmt.GetParent<BlockStatement> () != null) {
					stmt = stmt.GetParent<BlockStatement>();
				}
				
				var wholeCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken);
				var statusBeforeMethod = new Dictionary<IVariable, DefiniteAssignmentStatus>();
				foreach (var variable in usedVariables) {
					wholeCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
					statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]);
				}
				
				var afterCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken);
				var statusAtEnd = new Dictionary<IVariable, DefiniteAssignmentStatus>();
				afterCodeAnalysis.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true);
				
				foreach (var variable in usedVariables) {
					afterCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
					statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]);
				}
				var beforeVisitor = new VariableLookupVisitor(context);
				beforeVisitor.SetAnalyzedRange(stmt, statements [0], true, false);
				stmt.AcceptVisitor(beforeVisitor);
				var afterVisitor = new VariableLookupVisitor(context);
				afterVisitor.SetAnalyzedRange(lastStatement, stmt, false, true);
				stmt.AcceptVisitor(afterVisitor);
				
				foreach (var status in statusAfterMethod) {
					if (!beforeVisitor.UsedVariables.Contains(status.Item1) && !afterVisitor.UsedVariables.Contains(status.Item1))
						continue;
					Expression argumentExpression = new IdentifierExpression(status.Item1.Name); 
					
					ParameterModifier mod;
					switch (status.Item2) {
						case DefiniteAssignmentStatus.AssignedAfterTrueExpression:
						case DefiniteAssignmentStatus.AssignedAfterFalseExpression:
						case DefiniteAssignmentStatus.PotentiallyAssigned:
							mod = ParameterModifier.Ref;
							argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression);
							break;
						case DefiniteAssignmentStatus.DefinitelyAssigned:
							if (statusBeforeMethod [status.Item1] != DefiniteAssignmentStatus.PotentiallyAssigned)
								goto case DefiniteAssignmentStatus.PotentiallyAssigned;
							mod = ParameterModifier.Out;
							argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression);
							break;
							//						case DefiniteAssignmentStatus.Unassigned:
						default:
							mod = ParameterModifier.None;
							break;
					}
					method.Parameters.Add(
						new ParameterDeclaration(context.CreateShortType(status.Item1.Type), status.Item1.Name, mod));
					invocation.Arguments.Add(argumentExpression);
				}
				var task = script.InsertWithCursor(context.TranslateString("Extract method"), Script.InsertPosition.Before, method);
				task.ContinueWith (delegate {
					foreach (var node in statements.Skip (1)) {
						script.Remove(node);
					}
					script.Replace(statements [0], new ExpressionStatement(invocation));
					script.Link(target, method.NameToken);
				}, TaskScheduler.FromCurrentSynchronizationContext ());
			});
		}
        CodeAction CreateFromStatements(RefactoringContext context, List <Statement> statements)
        {
            if (!(statements [0].Parent is Statement))
            {
                return(null);
            }

            return(new CodeAction(context.TranslateString("Extract method"), script => {
                string methodName = "NewMethod";
                var method = new MethodDeclaration()
                {
                    ReturnType = new PrimitiveType("void"),
                    Name = methodName,
                    Body = new BlockStatement()
                };
                bool usesNonStaticMember = false;
                foreach (Statement node in statements)
                {
                    usesNonStaticMember |= StaticVisitor.UsesNotStaticMember(context, node);
                    method.Body.Add(node.Clone());
                }
                if (!usesNonStaticMember)
                {
                    method.Modifiers |= Modifiers.Static;
                }

                var target = new IdentifierExpression(methodName);
                var invocation = new InvocationExpression(target);

                var usedVariables = VariableLookupVisitor.Analyze(context, statements);

                var extractedCodeAnalysis = new DefiniteAssignmentAnalysis((Statement)statements [0].Parent, context.Resolver, context.CancellationToken);
                var lastStatement = statements [statements.Count - 1];
                extractedCodeAnalysis.SetAnalyzedRange(statements [0], lastStatement);
                var statusAfterMethod = new List <Tuple <IVariable, DefiniteAssignmentStatus> >();

                foreach (var variable in usedVariables)
                {
                    extractedCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
                    statusAfterMethod.Add(Tuple.Create(variable, extractedCodeAnalysis.GetStatusAfter(lastStatement)));
                }
                var stmt = statements [0].GetParent <BlockStatement>();
                while (stmt.GetParent <BlockStatement> () != null)
                {
                    stmt = stmt.GetParent <BlockStatement>();
                }

                var wholeCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken);
                var statusBeforeMethod = new Dictionary <IVariable, DefiniteAssignmentStatus>();
                foreach (var variable in usedVariables)
                {
                    wholeCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
                    statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]);
                }

                var afterCodeAnalysis = new DefiniteAssignmentAnalysis(stmt, context.Resolver, context.CancellationToken);
                var statusAtEnd = new Dictionary <IVariable, DefiniteAssignmentStatus>();
                afterCodeAnalysis.SetAnalyzedRange(lastStatement, stmt.Statements.Last(), false, true);

                foreach (var variable in usedVariables)
                {
                    afterCodeAnalysis.Analyze(variable.Name, DefiniteAssignmentStatus.PotentiallyAssigned, context.CancellationToken);
                    statusBeforeMethod [variable] = extractedCodeAnalysis.GetStatusBefore(statements [0]);
                }
                var beforeVisitor = new VariableLookupVisitor(context);
                beforeVisitor.SetAnalyzedRange(stmt, statements [0], true, false);
                stmt.AcceptVisitor(beforeVisitor);
                var afterVisitor = new VariableLookupVisitor(context);
                afterVisitor.SetAnalyzedRange(lastStatement, stmt, false, true);
                stmt.AcceptVisitor(afterVisitor);

                foreach (var status in statusAfterMethod)
                {
                    if (!beforeVisitor.UsedVariables.Contains(status.Item1) && !afterVisitor.UsedVariables.Contains(status.Item1))
                    {
                        continue;
                    }
                    Expression argumentExpression = new IdentifierExpression(status.Item1.Name);

                    ParameterModifier mod;
                    switch (status.Item2)
                    {
                    case DefiniteAssignmentStatus.AssignedAfterTrueExpression:
                    case DefiniteAssignmentStatus.AssignedAfterFalseExpression:
                    case DefiniteAssignmentStatus.PotentiallyAssigned:
                        mod = ParameterModifier.Ref;
                        argumentExpression = new DirectionExpression(FieldDirection.Ref, argumentExpression);
                        break;

                    case DefiniteAssignmentStatus.DefinitelyAssigned:
                        if (statusBeforeMethod [status.Item1] != DefiniteAssignmentStatus.PotentiallyAssigned)
                        {
                            goto case DefiniteAssignmentStatus.PotentiallyAssigned;
                        }
                        mod = ParameterModifier.Out;
                        argumentExpression = new DirectionExpression(FieldDirection.Out, argumentExpression);
                        break;

//						case DefiniteAssignmentStatus.Unassigned:
                    default:
                        mod = ParameterModifier.None;
                        break;
                    }
                    method.Parameters.Add(new ParameterDeclaration(context.CreateShortType(status.Item1.Type), status.Item1.Name, mod));
                    invocation.Arguments.Add(argumentExpression);
                }

                foreach (var node in statements.Skip(1))
                {
                    script.Remove(node);
                }
                script.Replace(statements [0], new ExpressionStatement(invocation));
                script.InsertWithCursor(context.TranslateString("Extract method"), method, Script.InsertPosition.Before);
                //script.Link(target, method.NameToken);
            }));
        }