public override void VisitIfElseStatement(IfElseStatement ifElseStatement) { base.VisitIfElseStatement(ifElseStatement); var match = ifPattern.Match(ifElseStatement); if (match.Success) { var cond1 = match.Get <Expression>("condition").Single(); var cond2 = match.Get <Expression>("condition2").Single(); if (!AlUtil.AreConditionsEqual(cond1, cond2)) { return; } AddIssue(new CodeIssue( ifElseStatement.IfToken, ctx.TranslateString("Statement can be simplified to 'while' statement"), ctx.TranslateString("Replace with 'while'"), script => { script.Replace( ifElseStatement, new WhileStatement( cond1.Clone(), match.Get <Statement>("EmbeddedStatement").Single().Clone() ) ); } ) { IssueMarker = IssueMarker.DottedLine }); } }
public override void VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression) { base.VisitUnaryOperatorExpression(unaryOperatorExpression); if (unaryOperatorExpression.Operator != UnaryOperatorType.Not) { return; } var invocation = AlUtil.GetInnerMostExpression(unaryOperatorExpression.Expression) as InvocationExpression; if (invocation == null) { return; } var rr = ctx.Resolve(invocation) as AlInvocationResolveResult; if (rr == null || rr.IsError) { return; } if (rr.Member.DeclaringType.Name != "Enumerable" || rr.Member.DeclaringType.Namespace != "System.Linq") { return; } if (!new[] { "All", "Any" }.Contains(rr.Member.Name)) { return; } if (invocation.Arguments.Count != 1) { return; } var arg = invocation.Arguments.First(); var match = argumentPattern.Match(arg); if (!match.Success) { return; } AddIssue(new CodeIssue( unaryOperatorExpression, ctx.TranslateString("Simplify LINQ expression"), ctx.TranslateString("Simplify LINQ expression"), s => { var target = invocation.Target.Clone() as MemberReferenceExpression; target.MemberName = target.MemberName == "All" ? "Any" : "All"; var expr = arg.Clone(); var nmatch = argumentPattern.Match(expr); var cond = nmatch.Get <Expression>("expr").Single(); cond.ReplaceWith(AlUtil.InvertCondition(cond)); var simplifiedInvocation = new InvocationExpression( target, expr ); s.Replace(unaryOperatorExpression, simplifiedInvocation); } )); }
void GenerateNewScript(Script script, IfElseStatement ifStatement) { var mergedIfStatement = new IfElseStatement { Condition = AlUtil.InvertCondition(ifStatement.Condition), TrueStatement = new ContinueStatement() }; mergedIfStatement.Condition.AcceptVisitor(_insertParenthesesVisitor); script.Replace(ifStatement, mergedIfStatement); SimplifyIfFlowAction.InsertBody(script, ifStatement); }
public override void VisitInvocationExpression(InvocationExpression invocationExpression) { base.VisitInvocationExpression(invocationExpression); var rr = ctx.Resolve(invocationExpression) as InvocationResolveResult; if (rr == null || rr.Member.Name != "Equals" || !rr.Member.ReturnType.IsKnownType(KnownTypeCode.Boolean)) { return; } if (rr.Member.IsStatic) { if (rr.Member.Parameters.Count != 2) { return; } if (AlUtil.AreConditionsEqual(invocationExpression.Arguments.FirstOrDefault(), invocationExpression.Arguments.Last())) { if ((invocationExpression.Parent is UnaryOperatorExpression) && ((UnaryOperatorExpression)invocationExpression.Parent).Operator == UnaryOperatorType.Not) { AddIssue(invocationExpression.Parent, invocationExpression.Parent, false); } else { AddIssue(invocationExpression, invocationExpression, true); } } } else { if (rr.Member.Parameters.Count != 1) { return; } var target = invocationExpression.Target as MemberReferenceExpression; if (target == null) { return; } if (AlUtil.AreConditionsEqual(invocationExpression.Arguments.FirstOrDefault(), target.Target)) { if ((invocationExpression.Parent is UnaryOperatorExpression) && ((UnaryOperatorExpression)invocationExpression.Parent).Operator == UnaryOperatorType.Not) { AddIssue(invocationExpression.Parent, invocationExpression.Parent, false); } else { AddIssue(invocationExpression, invocationExpression, true); } } } }
Expression Subtract(Expression expr, Expression step) { if (step != null && AlUtil.GetInnerMostExpression(expr).IsMatch(AlUtil.GetInnerMostExpression(step))) { return(new PrimitiveExpression(0)); } var pe = expr as PrimitiveExpression; if (pe != null) { if (step == null) { return(new PrimitiveExpression((int)pe.Value - 1)); } var stepExpr = step as PrimitiveExpression; if (stepExpr != null) { return(new PrimitiveExpression((int)pe.Value - (int)stepExpr.Value)); } } var bOp = expr as BinaryOperatorExpression; if (bOp != null) { if (bOp.Operator == BinaryOperatorType.Subtract) { var right = Add(bOp.Right, step); if (zeroExpr.IsMatch(right)) { return(bOp.Left.Clone()); } return(new BinaryOperatorExpression(bOp.Left.Clone(), BinaryOperatorType.Subtract, right)); } if (bOp.Operator == BinaryOperatorType.Add) { var right = Subtract(bOp.Right, step); if (zeroExpr.IsMatch(right)) { return(bOp.Left.Clone()); } return(new BinaryOperatorExpression(bOp.Left.Clone(), BinaryOperatorType.Add, Subtract(bOp.Right, step))); } } if (step == null) { return(new BinaryOperatorExpression(expr.Clone(), BinaryOperatorType.Subtract, new PrimitiveExpression(1))); } return(new BinaryOperatorExpression(expr.Clone(), BinaryOperatorType.Subtract, AlUtil.AddParensForUnaryExpressionIfRequired(step.Clone()))); }
public override void VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression) { base.VisitUnaryOperatorExpression(unaryOperatorExpression); if (unaryOperatorExpression.Operator != UnaryOperatorType.Not) { return; } var expr = unaryOperatorExpression.Expression; while (expr != null && expr is ParenthesizedExpression) { expr = ((ParenthesizedExpression)expr).Expression; } var binaryOperatorExpr = expr as BinaryOperatorExpression; if (binaryOperatorExpr == null) { return; } switch (binaryOperatorExpr.Operator) { case BinaryOperatorType.BitwiseAnd: case BinaryOperatorType.BitwiseOr: case BinaryOperatorType.ConditionalAnd: case BinaryOperatorType.ConditionalOr: case BinaryOperatorType.ExclusiveOr: return; } var negatedOp = AlUtil.NegateRelationalOperator(binaryOperatorExpr.Operator); if (negatedOp == BinaryOperatorType.Any) { return; } if (IsFloatingPoint(binaryOperatorExpr.Left) || IsFloatingPoint(binaryOperatorExpr.Right)) { if (negatedOp != BinaryOperatorType.Equality && negatedOp != BinaryOperatorType.InEquality) { return; } } AddIssue(new CodeIssue(unaryOperatorExpression, ctx.TranslateString("Simplify negative relational expression"), ctx.TranslateString("Simplify negative relational expression"), script => script.Replace(unaryOperatorExpression, new BinaryOperatorExpression(binaryOperatorExpr.Left.Clone(), negatedOp, binaryOperatorExpr.Right.Clone())))); }
public override System.Collections.Generic.IEnumerable <CodeAction> GetActions(RefactoringContext context) { Expression expr = null; AstNode token; if (!NegateRelationalExpressionAction.GetLogicalExpression(context, out expr, out token)) { yield break; } var uOp = expr as UnaryOperatorExpression; if (uOp != null) { yield return(new CodeAction( string.Format(context.TranslateString("Invert '{0}'"), expr), script => { script.Replace(uOp, AlUtil.InvertCondition(AlUtil.GetInnerMostExpression(uOp.Expression))); }, token )); yield break; } var negativeExpression = AlUtil.InvertCondition(expr); if (expr.Parent is ParenthesizedExpression && expr.Parent.Parent is UnaryOperatorExpression) { var unaryOperatorExpression = expr.Parent.Parent as UnaryOperatorExpression; if (unaryOperatorExpression.Operator == UnaryOperatorType.Not) { yield return(new CodeAction( string.Format(context.TranslateString("Invert '{0}'"), unaryOperatorExpression), script => { script.Replace(unaryOperatorExpression, negativeExpression); }, token )); yield break; } } var newExpression = new UnaryOperatorExpression(UnaryOperatorType.Not, new ParenthesizedExpression(negativeExpression)); yield return(new CodeAction( string.Format(context.TranslateString("Invert '{0}'"), expr), script => { script.Replace(expr, newExpression); }, token )); }
void AddIssue(AstNode invocationExpression, Match match, bool negate = false) { AddIssue(new CodeIssue( invocationExpression, ctx.TranslateString("Use 'is' operator"), ctx.TranslateString("Replace with 'is' operator"), s => { Expression expression = new IsExpression(AlUtil.AddParensForUnaryExpressionIfRequired(match.Get <Expression>("object").Single().Clone()), match.Get <AstType>("Type").Single().Clone()); if (negate) { expression = new UnaryOperatorExpression(UnaryOperatorType.Not, new ParenthesizedExpression(expression)); } s.Replace(invocationExpression, expression); } )); }
bool CheckNullComparison(BinaryOperatorExpression binaryOperatorExpression, Expression right, Expression nullNode) { if (binaryOperatorExpression.Operator != BinaryOperatorType.Equality && binaryOperatorExpression.Operator != BinaryOperatorType.InEquality) { return(false); } // note null == null is checked by similiar expression comparison. var expr = AlUtil.GetInnerMostExpression(right); var rr = ctx.Resolve(expr); if (rr.Type.IsReferenceType == false) { // nullable check if (NullableType.IsNullable(rr.Type)) { return(false); } var conversion = ctx.GetConversion(nullNode); if (conversion.ConversionAfterUserDefinedOperator == Conversion.IdentityConversion) { return(false); } // check for user operators foreach (var op in rr.Type.GetMethods(m => m.SymbolKind == SymbolKind.Operator && m.Parameters.Count == 2)) { if (op.Parameters[0].Type.IsReferenceType == false && op.Parameters[1].Type.IsReferenceType == false) { continue; } if (binaryOperatorExpression.Operator == BinaryOperatorType.Equality && op.Name == "op_Equality") { return(false); } if (binaryOperatorExpression.Operator == BinaryOperatorType.InEquality && op.Name == "op_Inequality") { return(false); } } AddIssue(binaryOperatorExpression, binaryOperatorExpression.Operator != BinaryOperatorType.Equality); return(true); } return(false); }
public override System.Collections.Generic.IEnumerable <CodeAction> GetActions(RefactoringContext context) { Expression expr = null; AstNode token; if (!GetLogicalExpression(context, out expr, out token)) { yield break; } yield return(new CodeAction( string.Format(context.TranslateString("Negate '{0}'"), expr), script => { script.Replace(expr, AlUtil.InvertCondition(expr)); }, token )); }
protected override CodeAction GetAction(RefactoringContext context, UnaryOperatorExpression node) { if (node.Operator != UnaryOperatorType.PostIncrement && node.Operator != UnaryOperatorType.PostDecrement) { return(null); } string desc = node.Operator == UnaryOperatorType.PostIncrement ? context.TranslateString("Replace with '{0} += 1'") : context.TranslateString("Replace with '{0} -= 1'"); return(new CodeAction( string.Format(desc, AlUtil.GetInnerMostExpression(node.Expression)), s => s.Replace(node, new AssignmentExpression( AlUtil.GetInnerMostExpression(node.Expression).Clone(), node.Operator == UnaryOperatorType.PostIncrement ? AssignmentOperatorType.Add : AssignmentOperatorType.Subtract, new PrimitiveExpression(1) )), node.OperatorToken )); }
public override IEnumerable <CodeAction> GetActions(RefactoringContext context) { // TODO: Invert if without else // ex. if (cond) DoSomething () == if (!cond) return; DoSomething () // beware of loop contexts return should be continue then. var ifStatement = GetIfElseStatement(context); if (!(ifStatement != null && !ifStatement.TrueStatement.IsNull && !ifStatement.FalseStatement.IsNull)) { yield break; } yield return(new CodeAction(context.TranslateString("Invert if"), script => { script.Replace(ifStatement.Condition, AlUtil.InvertCondition(ifStatement.Condition.Clone())); script.Replace(ifStatement.TrueStatement, ifStatement.FalseStatement.Clone()); script.Replace(ifStatement.FalseStatement, ifStatement.TrueStatement.Clone()); script.FormatText(ifStatement); }, ifStatement)); }
public static bool GetLogicalExpression(RefactoringContext context, out Expression expr, out AstNode token) { expr = null; token = null; var bOp = context.GetNode <BinaryOperatorExpression>(); if (bOp != null && bOp.OperatorToken.Contains(context.Location) && AlUtil.IsRelationalOperator(bOp.Operator)) { expr = bOp; token = bOp.OperatorToken; return(true); } var uOp = context.GetNode <UnaryOperatorExpression>(); if (uOp != null && uOp.OperatorToken.Contains(context.Location) && uOp.Operator == UnaryOperatorType.Not) { expr = uOp; token = uOp.OperatorToken; return(true); } return(false); }
protected override CodeAction GetAction(RefactoringContext context, ConditionalExpression conditionalExpr) { if (context.Location != conditionalExpr.Condition.StartLocation && context.Location < conditionalExpr.Condition.EndLocation || context.Location != conditionalExpr.TrueExpression.StartLocation && conditionalExpr.TrueExpression.Contains(context.Location) || context.Location != conditionalExpr.FalseExpression.StartLocation && conditionalExpr.FalseExpression.Contains(context.Location)) { return(null); } var node = conditionalExpr.GetNodeAt(context.Location); if (node == null) { return(null); } return(new CodeAction(context.TranslateString("Invert '?:'"), script => { script.Replace(conditionalExpr.Condition, AlUtil.InvertCondition(conditionalExpr.Condition.Clone())); script.Replace(conditionalExpr.TrueExpression, conditionalExpr.FalseExpression.Clone()); script.Replace(conditionalExpr.FalseExpression, conditionalExpr.TrueExpression.Clone()); script.FormatText(conditionalExpr); }, node)); }
protected override CodeAction GetAction(RefactoringContext context, WhileStatement node) { if (!node.WhileToken.Contains(context.Location)) { return(null); } return(new CodeAction( context.TranslateString("Extract condition to internal 'if' statement"), script => { script.Replace(node.Condition, new PrimitiveExpression(true)); var ifStmt = new IfElseStatement( AlUtil.InvertCondition(node.Condition), new BreakStatement() ); var block = node.EmbeddedStatement as BlockStatement; if (block != null) { script.InsertAfter(block.LBraceToken, ifStmt); } else { var blockStatement = new BlockStatement { ifStmt }; if (!(node.EmbeddedStatement is EmptyStatement)) { blockStatement.Statements.Add(node.EmbeddedStatement.Clone()); } script.Replace(node.EmbeddedStatement, blockStatement); } }, node )); }
public override void VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression) { if (CheckConstant(binaryOperatorExpression)) { return; } if (AlUtil.GetInnerMostExpression(binaryOperatorExpression.Left) is NullReferenceExpression) { if (CheckNullComparison(binaryOperatorExpression, binaryOperatorExpression.Right, binaryOperatorExpression.Left)) { return; } } if (AlUtil.GetInnerMostExpression(binaryOperatorExpression.Right) is NullReferenceExpression) { if (CheckNullComparison(binaryOperatorExpression, binaryOperatorExpression.Left, binaryOperatorExpression.Right)) { return; } } base.VisitBinaryOperatorExpression(binaryOperatorExpression); }
AssignmentExpression GetTransformedAssignmentExpression(RefactoringContext context, ForeachStatement foreachStatement) { var enumerableToIterate = foreachStatement.InExpression.Clone(); Statement statement = foreachStatement.EmbeddedStatement; Expression leftExpression, rightExpression; if (!ExtractExpression(statement, out leftExpression, out rightExpression)) { return(null); } if (leftExpression == null || rightExpression == null) { return(null); } var type = context.Resolve(leftExpression).Type; if (!IsLinqSummableType(type)) { return(null); } if (rightExpression.DescendantsAndSelf.OfType <AssignmentExpression>().Any()) { // Reject loops such as // int k = 0; // foreach (var x in y) { k += (z = 2); } return(null); } if (rightExpression.DescendantsAndSelf.OfType <UnaryOperatorExpression>().Any(IsUnaryModifierExpression)) { // int k = 0; // foreach (var x in y) { k += (z++); } return(null); } var zeroLiteral = new PrimitiveExpression(0); Expression baseExpression = enumerableToIterate; for (;;) { ConditionalExpression condition = rightExpression as ConditionalExpression; if (condition == null) { break; } if (SameNode(zeroLiteral, condition.TrueExpression)) { baseExpression = new InvocationExpression(new MemberReferenceExpression(baseExpression.Clone(), "Where"), BuildLambda(foreachStatement.VariableName, AlUtil.InvertCondition(condition.Condition))); rightExpression = condition.FalseExpression.Clone(); continue; } if (SameNode(zeroLiteral, condition.FalseExpression)) { baseExpression = new InvocationExpression(new MemberReferenceExpression(baseExpression.Clone(), "Where"), BuildLambda(foreachStatement.VariableName, condition.Condition.Clone())); rightExpression = condition.TrueExpression.Clone(); continue; } break; } var primitiveOne = new PrimitiveExpression(1); bool isPrimitiveOne = SameNode(primitiveOne, rightExpression); var arguments = new List <Expression>(); string method = isPrimitiveOne ? "Count" : "Sum"; if (!isPrimitiveOne && !IsIdentifier(rightExpression, foreachStatement.VariableName)) { var lambda = BuildLambda(foreachStatement.VariableName, rightExpression); arguments.Add(lambda); } var rightSide = new InvocationExpression(new MemberReferenceExpression(baseExpression, method), arguments); return(new AssignmentExpression(leftExpression.Clone(), AssignmentOperatorType.Add, rightSide)); }
public override void VisitIfElseStatement(IfElseStatement ifElseStatement) { base.VisitIfElseStatement(ifElseStatement); var match = ifPattern.Match(ifElseStatement); if (match.Success) { var varDeclaration = ifElseStatement.GetPrevSibling(s => s.Role == BlockStatement.StatementRole) as VariableDeclarationStatement; var target = match.Get <Expression>("target").Single(); var match2 = varDelarationPattern.Match(varDeclaration); if (match2.Success) { var initializer = varDeclaration.Variables.FirstOrDefault(); if (initializer != null && target is IdentifierExpression && ((IdentifierExpression)target).Identifier != initializer.Name) { return; } var expr = match.Get <Expression>("condition").Single(); if (!ConvertIfToOrExpressionIssue.CheckTarget(target, expr)) { return; } AddIssue(new CodeIssue( ifElseStatement.IfToken, ctx.TranslateString("Convert to '&&' expresssion"), ctx.TranslateString("Replace with '&&'"), script => { var variable = initializer; var initalizerExpression = variable.Initializer.Clone(); var bOp = initalizerExpression as BinaryOperatorExpression; if (bOp != null && bOp.Operator == BinaryOperatorType.ConditionalOr) { initalizerExpression = new ParenthesizedExpression(initalizerExpression); } script.Replace( varDeclaration, new VariableDeclarationStatement( varDeclaration.Type.Clone(), variable.Name, new BinaryOperatorExpression(initalizerExpression, BinaryOperatorType.ConditionalAnd, AlUtil.InvertCondition(expr)) ) ); script.Remove(ifElseStatement); } ) { IssueMarker = IssueMarker.DottedLine }); return; } else { var expr = match.Get <Expression>("condition").Single(); if (!ConvertIfToOrExpressionIssue.CheckTarget(target, expr)) { return; } AddIssue(new CodeIssue( ifElseStatement.IfToken, ctx.TranslateString("Convert to '&=' expresssion"), ctx.TranslateString("Replace with '&='"), script => script.Replace( ifElseStatement, new ExpressionStatement( new AssignmentExpression( target.Clone(), AssignmentOperatorType.BitwiseAnd, AlUtil.InvertCondition(expr) ) ) ) ) { IssueMarker = IssueMarker.DottedLine }); } } }
public override void VisitConditionalExpression(ConditionalExpression conditionalExpression) { base.VisitConditionalExpression(conditionalExpression); bool?trueBranch = GetBool(AlUtil.GetInnerMostExpression(conditionalExpression.TrueExpression)); bool?falseBranch = GetBool(AlUtil.GetInnerMostExpression(conditionalExpression.FalseExpression)); if (trueBranch == falseBranch || trueBranch == true && falseBranch == false) // Handled by RedundantTernaryExpressionIssue { return; } AddIssue(new CodeIssue( conditionalExpression.QuestionMarkToken.StartLocation, conditionalExpression.FalseExpression.EndLocation, ctx.TranslateString("Simplify conditional expression"), ctx.TranslateString("Simplify conditional expression"), script => { if (trueBranch == false && falseBranch == true) { script.Replace(conditionalExpression, AlUtil.InvertCondition(conditionalExpression.Condition)); return; } if (trueBranch == true) { script.Replace( conditionalExpression, new BinaryOperatorExpression( conditionalExpression.Condition.Clone(), BinaryOperatorType.ConditionalOr, conditionalExpression.FalseExpression.Clone() ) ); return; } if (trueBranch == false) { script.Replace( conditionalExpression, new BinaryOperatorExpression( AlUtil.InvertCondition(conditionalExpression.Condition), BinaryOperatorType.ConditionalAnd, conditionalExpression.FalseExpression.Clone() ) ); return; } if (falseBranch == true) { script.Replace( conditionalExpression, new BinaryOperatorExpression( AlUtil.InvertCondition(conditionalExpression.Condition), BinaryOperatorType.ConditionalOr, conditionalExpression.TrueExpression.Clone() ) ); return; } if (falseBranch == false) { script.Replace( conditionalExpression, new BinaryOperatorExpression( conditionalExpression.Condition.Clone(), BinaryOperatorType.ConditionalAnd, conditionalExpression.TrueExpression.Clone() ) ); return; } // Should never happen } )); }
static CodeAction HandleNegatedCase(BaseRefactoringContext ctx, IfElseStatement ifElseStatement, Match match, out IsExpression isExpression, out int foundCastCount) { foundCastCount = 0; var outerIs = match.Get <Expression>("isExpression").Single(); isExpression = AlUtil.GetInnerMostExpression(outerIs) as IsExpression; var obj = AlUtil.GetInnerMostExpression(isExpression.Expression); var castToType = isExpression.Type; var cast = new Choice { PatternHelper.OptionalParentheses(PatternHelper.OptionalParentheses(obj.Clone()).CastTo(castToType.Clone())), PatternHelper.OptionalParentheses(PatternHelper.OptionalParentheses(obj.Clone()).CastAs(castToType.Clone())) }; var rr = ctx.Resolve(castToType); if (rr == null || rr.IsError || rr.Type.IsReferenceType == false) { return(null); } var foundCasts = ifElseStatement.GetParent <BlockStatement>().DescendantNodes(n => n.StartLocation >= ifElseStatement.StartLocation && !cast.IsMatch(n)).Where(n => cast.IsMatch(n)).ToList(); foundCastCount = foundCasts.Count; return(new CodeAction(ctx.TranslateString("Use 'as' and check for null"), script => { var varName = ctx.GetNameProposal(CreateMethodDeclarationAction.GuessNameFromType(rr.Type), ifElseStatement.StartLocation); var varDec = new VariableDeclarationStatement(new PrimitiveType("var"), varName, new AsExpression(obj.Clone(), castToType.Clone())); var binaryOperatorIdentifier = new IdentifierExpression(varName); var binaryOperatorExpression = new BinaryOperatorExpression(binaryOperatorIdentifier, BinaryOperatorType.Equality, new NullReferenceExpression()); var linkedNodes = new List <AstNode>(); linkedNodes.Add(varDec.Variables.First().NameToken); linkedNodes.Add(binaryOperatorIdentifier); if (IsEmbeddedStatement(ifElseStatement)) { var block = new BlockStatement(); block.Add(varDec); var newIf = (IfElseStatement)ifElseStatement.Clone(); newIf.Condition = binaryOperatorExpression; foreach (var node in newIf.DescendantNodesAndSelf(n => !cast.IsMatch(n)).Where(n => cast.IsMatch(n))) { var id = new IdentifierExpression(varName); linkedNodes.Add(id); node.ReplaceWith(id); } block.Add(newIf); script.Replace(ifElseStatement, block); } else { script.InsertBefore(ifElseStatement, varDec); script.Replace(ifElseStatement.Condition, binaryOperatorExpression); foreach (var c in foundCasts) { var id = new IdentifierExpression(varName); linkedNodes.Add(id); script.Replace(c, id); } } script.Link(linkedNodes); }, isExpression.IsToken)); }