public NRefactoryCodeAction(string id, string title, ICSharpCode.NRefactory.PlayScript.Refactoring.CodeAction act)
 {
     this.IdString       = id;
     this.Title          = title;
     this.act            = act;
     this.DocumentRegion = new Mono.TextEditor.DocumentRegion(act.Start, act.End);
 }
			public override void VisitConditionalExpression (ConditionalExpression conditionalExpression)
			{
				base.VisitConditionalExpression (conditionalExpression);

				if (!conditionalExpression.TrueExpression.Match (conditionalExpression.FalseExpression).Success)
					return;
				var action = new CodeAction (ctx.TranslateString ("Replace '?:' with branch"),
					script => script.Replace (conditionalExpression, conditionalExpression.TrueExpression.Clone ()));
				AddIssue (conditionalExpression, 
					ctx.TranslateString ("'?:' expression has identical true and false branches"), new [] { action });
			}
			public override void VisitIsExpression (IsExpression isExpression)
			{
				base.VisitIsExpression (isExpression);

				var type = ctx.Resolve (isExpression.Expression).Type;
				var providedType = ctx.ResolveType (isExpression.Type);

//				var foundConversion = conversions.ImplicitConversion(type, providedType);
				if (!IsValidReferenceOrBoxingConversion(type, providedType))
					return;

				var action = new CodeAction (ctx.TranslateString ("Compare with 'null'"), 
					scrpit => scrpit.Replace (isExpression, new BinaryOperatorExpression (
						isExpression.Expression.Clone (), BinaryOperatorType.InEquality, new PrimitiveExpression (null))));
				AddIssue (isExpression, ctx.TranslateString ("Given expression is always of the provided type. " +
					"Consider comparing with 'null' instead"), new [] { action });
			}
			public override void VisitCatchClause(CatchClause catchClause)
			{
				base.VisitCatchClause(catchClause);
				var exceptionResolveResult = ctx.Resolve(catchClause.VariableNameToken) as LocalResolveResult;
				if (exceptionResolveResult == null)
					return;

				var catchVisitor = new CatchClauseVisitor(ctx, exceptionResolveResult.Variable);
				catchClause.Body.AcceptVisitor(catchVisitor);

				foreach (var throwStatement in catchVisitor.OffendingThrows) {
					var localThrowStatement = throwStatement;
					var title = ctx.TranslateString("The exception is rethrown with explicit usage of the variable");
					var action = new CodeAction(ctx.TranslateString("Change to 'throw;'"), script => {
						script.Replace(localThrowStatement, new ThrowStatement());
					});
					AddIssue(localThrowStatement, title, action);
				}
			}
			void AddIssuesForClauses(List<CatchClause> redundantCatchClauses)
			{
				var allCatchClausesMessage = ctx.TranslateString("Remove all '{0}' redundant catches");
				var removeAllRedundantClausesAction = new CodeAction(allCatchClausesMessage, script => {
					foreach (var redundantCatchClause in redundantCatchClauses) {
						script.Remove(redundantCatchClause);
					}
				});
				var singleCatchClauseMessage = ctx.TranslateString("Remove redundant catch clause");
				var redundantCatchClauseMessage = ctx.TranslateString("A catch clause containing a single empty throw statement is redundant.");
				foreach (var redundantCatchClause in redundantCatchClauses) {
					var closureLocalCatchClause = redundantCatchClause;
					var removeRedundantClauseAction = new CodeAction(singleCatchClauseMessage, script => {
						script.Remove(closureLocalCatchClause);
					});
					var actions = new List<CodeAction>();
					actions.Add(removeRedundantClauseAction);
					if (redundantCatchClauses.Count > 1) {
						actions.Add(removeAllRedundantClausesAction);
					}
					AddIssue(closureLocalCatchClause, redundantCatchClauseMessage, actions);
				}
			}
			public override void VisitInvocationExpression (InvocationExpression invocationExpression)
			{
				base.VisitInvocationExpression (invocationExpression);

				// Quickly determine if this invocation is eligible to speed up the inspector
				var nameToken = invocationExpression.Target.GetChildByRole(Roles.Identifier);
				if (nameToken.Name != "ReferenceEquals")
					return;

				var resolveResult = ctx.Resolve (invocationExpression) as InvocationResolveResult;
				if (resolveResult == null || 
					resolveResult.Member.DeclaringTypeDefinition == null ||
					resolveResult.Member.DeclaringTypeDefinition.KnownTypeCode != KnownTypeCode.Object ||
					resolveResult.Member.Name != "ReferenceEquals" ||
					invocationExpression.Arguments.All(arg => ctx.Resolve(arg).Type.IsReferenceType ?? true))
					return;

				var action = new CodeAction (ctx.TranslateString ("Use Equals()"),
					script => script.Replace (invocationExpression.Target, new MemberReferenceExpression (
						new TypeReferenceExpression (new PrimitiveType ("object")), "Equals")));
				AddIssue (invocationExpression,
					ctx.TranslateString ("'Object.ReferenceEquals' is always false because it is called with value type"),
					new [] { action });
			}
				bool AddStatement(Statement statement)
				{
					if (reachability.IsReachable (statement))
						return false;
					if (collectedStatements.Contains (statement))
						return true;
					var prevEnd = statement.GetPrevNode ().EndLocation;

					// group multiple continuous statements into one issue
					var start = statement.StartLocation;
					collectedStatements.Add (statement);
					visitor.unreachableNodes.Add (statement);
					while (statement.NextSibling is Statement) {
						statement = (Statement)statement.NextSibling;
						collectedStatements.Add (statement);
						visitor.unreachableNodes.Add (statement);
					}
					var end = statement.EndLocation;

					var removeAction = new CodeAction (visitor.ctx.TranslateString ("Remove unreachable code"),
						script =>
						{
							var startOffset = script.GetCurrentOffset (prevEnd);
							var endOffset = script.GetCurrentOffset (end);
							script.RemoveText (startOffset, endOffset - startOffset);
						});
					var commentAction = new CodeAction (visitor.ctx.TranslateString ("Comment unreachable code"),
						script =>
						{
							var startOffset = script.GetCurrentOffset (prevEnd);
							script.InsertText (startOffset, Environment.NewLine + "/*");
							var endOffset = script.GetCurrentOffset (end);
							script.InsertText (endOffset, Environment.NewLine + "*/");
						});
					var actions = new [] { removeAction, commentAction };
					visitor.AddIssue (start, end, visitor.ctx.TranslateString ("Code is unreachable"), actions);
					return true;
				}
		/// <summary>
		/// Initializes a new instance of the <see cref="ICSharpCode.NRefactory.PlayScript.Refactoring.CodeIssue"/> class.
		/// </summary>
		/// <param name='description'>
		/// The desription of the issue.
		/// </param>
		/// <param name='start'>
		/// The issue start location.
		/// </param>
		/// <param name='end'>
		/// the issue end location.
		/// </param>
		/// <param name='action'>
		/// A potential solution for the issue.
		/// </param>
		public CodeIssue(string description, TextLocation start, TextLocation end, CodeAction action) : this (description, start, end, action != null ? new [] { action } : null)
		{
		}
		public NRefactoryCodeAction (string id, string title, ICSharpCode.NRefactory.PlayScript.Refactoring.CodeAction act)
		{
			this.IdString = id;
			this.Title = title;
			this.act = act;
		}
            void CheckMethodCall <T> (T node, IEnumerable <Expression> args, Func <T, IEnumerable <Expression>, T> generateReplacement) where T : AstNode
            {
                // The first two checks are unnecessary, but eliminates the majority of calls early,
                // improving performance.
                var arguments = args.ToArray();

                if (arguments.Length == 0)
                {
                    return;
                }
                var lastArg = arguments[arguments.Length - 1];

                if (!(lastArg is PrimitiveExpression || lastArg is NamedArgumentExpression))
                {
                    return;
                }

                var invocationResolveResult = ctx.Resolve(node) as CSharpInvocationResolveResult;

                if (invocationResolveResult == null)
                {
                    return;
                }

                string actionMessage = ctx.TranslateString("Remove redundant arguments");

                var redundantArguments = GetRedundantArguments(arguments, invocationResolveResult);
                var action             = new CodeAction(actionMessage, script => {
                    var newArgumentList = arguments
                                          .Where(arg => !redundantArguments.Contains(arg))
                                          .Select(arg => arg.Clone());
                    var newInvocation = generateReplacement(node, newArgumentList);
                    script.Replace(node, newInvocation);
                });
                var issueMessage           = ctx.TranslateString("Argument is identical to the default value");
                var lastPositionalArgument = redundantArguments.FirstOrDefault(expression => !(expression is NamedArgumentExpression));

                foreach (var argument in redundantArguments)
                {
                    var localArgument = argument;
                    var actions       = new List <CodeAction>();
                    actions.Add(action);

                    if (localArgument is NamedArgumentExpression || localArgument == lastPositionalArgument)
                    {
                        var title = ctx.TranslateString("Remove this argument");
                        actions.Add(new CodeAction(title, script => {
                            var newArgumentList = arguments
                                                  .Where(arg => arg != localArgument)
                                                  .Select(arg => arg.Clone());
                            var newInvocation = generateReplacement(node, newArgumentList);
                            script.Replace(node, newInvocation);
                        }));
                    }
                    else
                    {
                        var title = ctx.TranslateString("Remove this and the following positional arguments");
                        actions.Add(new CodeAction(title, script => {
                            var newArgumentList = arguments
                                                  .Where(arg => arg.StartLocation < localArgument.StartLocation && !(arg is NamedArgumentExpression))
                                                  .Select(arg => arg.Clone());
                            var newInvocation = generateReplacement(node, newArgumentList);
                            script.Replace(node, newInvocation);
                        }));
                    }

                    AddIssue(localArgument, issueMessage, actions);
                }
            }
		protected void AddIssue(TextLocation start, TextLocation end, string title, CodeAction fix)
		{
			FoundIssues.Add(new CodeIssue (title, start, end, fix));
		}
		protected void AddIssue(AstNode node, string title, CodeAction fix)
		{
			FoundIssues.Add(new CodeIssue(title, node.StartLocation, node.EndLocation, fix));
		}
			void AddIssueForTryCatchStatement(TryCatchStatement tryCatchStatement)
			{
				var lastCatch = tryCatchStatement.CatchClauses.LastOrNullObject();
				if (lastCatch.IsNull)
					return;

				var removeTryCatchMessage = ctx.TranslateString("Remove try statement");

				var removeTryStatementAction = new CodeAction(removeTryCatchMessage, script => {
					var statements = tryCatchStatement.TryBlock.Statements;
					if (statements.Count == 1 || tryCatchStatement.Parent is BlockStatement) {
						foreach (var statement in statements) {
							script.InsertAfter(tryCatchStatement.PrevSibling, statement.Clone());
						}
						script.Remove(tryCatchStatement);
					} else {
						var blockStatement = new BlockStatement();
						foreach (var statement in statements) {
							blockStatement.Statements.Add(statement.Clone());
						}
						script.Replace(tryCatchStatement, blockStatement);
					}
					// The replace and insert script functions does not format these things well on their own
					script.FormatText(tryCatchStatement.Parent);
				});

				var fixes = new [] {
					removeTryStatementAction
				};
				AddIssue(tryCatchStatement.TryBlock.EndLocation, lastCatch.EndLocation, removeTryCatchMessage, fixes);
			}
			void CheckCondition (Expression condition)
			{
				if (condition is PrimitiveExpression)
					return;

				var resolveResult = ctx.Resolve (condition);
				if (!(resolveResult.IsCompileTimeConstant && resolveResult.ConstantValue is bool))
					return;

				var value = (bool)resolveResult.ConstantValue;
				var conditionalExpr = condition.Parent as ConditionalExpression;
				var ifElseStatement = condition.Parent as IfElseStatement;
				var valueStr = value.ToString ().ToLower ();

				CodeAction action;
				if (conditionalExpr != null) {
					var replaceExpr = value ? conditionalExpr.TrueExpression : conditionalExpr.FalseExpression;
					action = new CodeAction (
						string.Format (ctx.TranslateString ("Replace '?:' with '{0}' branch"), valueStr),
						script => script.Replace (conditionalExpr, replaceExpr.Clone ()));
				} else if (ifElseStatement != null) {
					action = new CodeAction (
						string.Format (ctx.TranslateString ("Replace 'if' with '{0}' branch"), valueStr),
						script => {
							var statement = value ? ifElseStatement.TrueStatement : ifElseStatement.FalseStatement;
							var blockStatement = statement as BlockStatement;
							if (statement.IsNull || (blockStatement != null && blockStatement.Statements.Count == 0)) {
								script.Remove (ifElseStatement);
								return;
							}

							TextLocation start, end;
							if (blockStatement != null) {
								start = blockStatement.Statements.FirstOrNullObject ().StartLocation;
								end = blockStatement.Statements.LastOrNullObject ().EndLocation;
							} else {
								start = statement.StartLocation;
								end = statement.EndLocation;
							}
							RemoveText (script, ifElseStatement.StartLocation, start);
							RemoveText (script, end, ifElseStatement.EndLocation);
							script.FormatText (ifElseStatement.Parent);
						});
				} else {
					action = new CodeAction (
						string.Format (ctx.TranslateString ("Replace expression with '{0}'"), valueStr),
						script => script.Replace (condition, new PrimitiveExpression (value)));
				}
				AddIssue (condition, string.Format (ctx.TranslateString ("Condition is always '{0}'"), valueStr), 
					new [] { action });
			}
 public NRefactoryCodeAction(string id, string title, ICSharpCode.NRefactory.PlayScript.Refactoring.CodeAction act)
 {
     this.IdString = id;
     this.Title    = title;
     this.act      = act;
 }