static CodeAction AddIsNaNIssue(Document document, SemanticModel semanticModel, SyntaxNode root, BinaryExpressionSyntax node, ExpressionSyntax argExpr, string floatType) { return CodeActionFactory.Create(node.Span, DiagnosticSeverity.Warning, string.Format(node.IsKind(SyntaxKind.EqualsExpression) ? "Replace with '{0}.IsNaN(...)' call" : "Replace with '!{0}.IsNaN(...)' call", floatType), token => { SyntaxNode newRoot; ExpressionSyntax expr; var arguments = new SeparatedSyntaxList<ArgumentSyntax>(); arguments = arguments.Add(SyntaxFactory.Argument(argExpr)); expr = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ParseExpression(floatType), SyntaxFactory.IdentifierName("IsNaN") ), SyntaxFactory.ArgumentList( arguments ) ); if (node.IsKind(SyntaxKind.NotEqualsExpression)) expr = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, expr); expr = expr.WithAdditionalAnnotations(Formatter.Annotation); newRoot = root.ReplaceNode((SyntaxNode)node, expr); return Task.FromResult(document.WithSyntaxRoot(newRoot)); }); }
protected override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node) { var nameSyntax = FindIdentifierName (node.Left); if (nameSyntax == null) return base.VisitBinaryExpression (node); switch (node.Kind) { case SyntaxKind.AddAssignExpression: case SyntaxKind.OrAssignExpression: case SyntaxKind.SubtractAssignExpression: case SyntaxKind.MultiplyAssignExpression: case SyntaxKind.DivideAssignExpression: case SyntaxKind.ModuloAssignExpression: case SyntaxKind.RightShiftAssignExpression: case SyntaxKind.LeftShiftAssignExpression: case SyntaxKind.AndAssignExpression: case SyntaxKind.ExclusiveOrAssignExpression: var token = Syntax.Token (GetComplexAssignOperator (node.Kind)); ExpressionSyntax expr = Syntax.ParseExpression (nameSyntax.PlainName + token + node.Right); return node.Update (node.Left, AssignToken, GetLogExpression (nameSyntax.PlainName, expr)); case SyntaxKind.AssignExpression: return node.Update (node.Left, node.OperatorToken, GetLogExpression (nameSyntax.PlainName, node.Right)); default: return base.VisitBinaryExpression (node); } }
static bool TryFlip(BinaryExpressionSyntax expr, out SyntaxKind flippedKind, out string operatorText) { switch (expr.Kind()) { case SyntaxKind.LessThanExpression: flippedKind = SyntaxKind.GreaterThanExpression; operatorText = ">"; return true; case SyntaxKind.LessThanOrEqualExpression: flippedKind = SyntaxKind.GreaterThanOrEqualExpression; operatorText = ">="; return true; case SyntaxKind.GreaterThanExpression: flippedKind = SyntaxKind.LessThanExpression; operatorText = "<"; return true; case SyntaxKind.GreaterThanOrEqualExpression: flippedKind = SyntaxKind.LessThanOrEqualExpression; operatorText = "<="; return true; } flippedKind = SyntaxKind.None; operatorText = null; return false; }
public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node) { var based = base.VisitBinaryExpression (node); if (node.Left.FindIdentifierName() == null) return node; switch (node.Kind) { case SyntaxKind.AddAssignExpression: case SyntaxKind.OrAssignExpression: case SyntaxKind.SubtractAssignExpression: case SyntaxKind.MultiplyAssignExpression: case SyntaxKind.DivideAssignExpression: case SyntaxKind.ModuloAssignExpression: case SyntaxKind.RightShiftAssignExpression: case SyntaxKind.LeftShiftAssignExpression: case SyntaxKind.AndAssignExpression: case SyntaxKind.ExclusiveOrAssignExpression: case SyntaxKind.AssignExpression: return based.WithTrailingTrivia (based.GetTrailingTrivia().Prepend (GetIdComment())); default: return node; } }
internal static ExpressionSyntax GetOuterLeft(BinaryExpressionSyntax bop) { var leftBop = bop.Left as BinaryExpressionSyntax; if (leftBop != null && bop.OperatorToken.IsKind(leftBop.OperatorToken.Kind())) return GetOuterLeft(leftBop); return bop.Left; }
public BoundBinaryExpression(BoundExpression left, BoundExpression right, BinaryOperators @operator, BinaryExpressionSyntax binaryExpressionSyntax, IType type) : base(binaryExpressionSyntax, type) { Left = left; Right = right; Operator = @operator; }
private static SyntaxNode CalculateNewRoot(SyntaxNode root, BinaryExpressionSyntax currentAsBinary) { return root.ReplaceNode(currentAsBinary, SyntaxFactory.ConcatenateExpression( currentAsBinary.Left, SyntaxFactory.Token(SyntaxKind.AmpersandToken).WithTriviaFrom(currentAsBinary.OperatorToken), currentAsBinary.Right)); }
ExpressionSyntax GenerateTarget(SemanticModel model, BinaryExpressionSyntax node) { var symbols = model.LookupSymbols(node.SpanStart).OfType<IMethodSymbol>(); if (!symbols.Any() || HasDifferentEqualsMethod(symbols)) return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ParseExpression("object"), SyntaxFactory.IdentifierName("Equals")); else return SyntaxFactory.IdentifierName("Equals"); }
static Document PerformAction(Document document, SyntaxNode root, BinaryExpressionSyntax bop) { var nodeToReplace = bop.IsParentKind(SyntaxKind.ParenthesizedExpression) ? bop.Parent : bop; var castExpr = (ExpressionSyntax)SyntaxFactory.CastExpression(bop.Right as TypeSyntax, CSharpUtil.AddParensIfRequired(bop.Left.WithoutLeadingTrivia().WithoutTrailingTrivia())).WithLeadingTrivia(bop.GetLeadingTrivia()).WithTrailingTrivia(bop.GetTrailingTrivia()); var newRoot = root.ReplaceNode((SyntaxNode)nodeToReplace, castExpr); return document.WithSyntaxRoot(newRoot); }
internal static SyntaxNode ComputeExpression(SyntaxNode nodeToReplace, BinaryExpressionSyntax expression, SyntaxNode root, SemanticModel semanticModel) { var result = semanticModel.GetConstantValue(expression); if (!result.HasValue) return null; var newExpression = SyntaxFactory.ParseExpression(System.Convert.ToString(result.Value, System.Globalization.CultureInfo.InvariantCulture)); var newRoot = root.ReplaceNode(nodeToReplace, newExpression); return newRoot; }
public BoundBinaryExpression(BinaryExpressionSyntax syntax, BinaryOperatorKind operatorKind, BoundExpression left, BoundExpression right, TypeSymbol type) : base(BoundNodeKind.BinaryExpression, syntax) { OperatorKind = operatorKind; Left = left; Right = right; Type = type; }
/// <summary> /// Normalizes the <paramref name="binaryExpression" />. /// </summary> public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax binaryExpression) { if (!IsFormulaType(binaryExpression)) return base.VisitBinaryExpression(binaryExpression); var left = ReplaceImplicitConversion(binaryExpression.Left); var right = ReplaceImplicitConversion(binaryExpression.Right); return binaryExpression.Update(left, binaryExpression.OperatorToken, right); }
private static BinaryExpressionSyntax ChangeOperator(BinaryExpressionSyntax binary) { return SyntaxFactory.BinaryExpression( OppositeExpressionKinds[binary.Kind()], binary.Left, binary.Right) .WithTriviaFrom(binary); }
private static void AnalyzeBinaryExpression(BinaryExpressionSyntax node, SemanticModel model, Action<Diagnostic> addDiagnostic) { var leftType = model.GetTypeInfo(node.Left).Type; var rightType = model.GetTypeInfo(node.Right).Type; if (leftType != null && rightType != null && leftType.SpecialType == SpecialType.System_String && rightType.SpecialType == SpecialType.System_String) { addDiagnostic(node.OperatorToken.GetLocation().CreateDiagnostic(Rule)); } }
public static void Go(OutputWriter writer, BinaryExpressionSyntax expression) { var leftExpression = expression.Left; var rightExpression = expression.Right; var operatorToken = expression.OperatorToken; WriteIt(writer, operatorToken, rightExpression, leftExpression); }
public static IEnumerable<ReplaceAction> GetSimplifications(BinaryExpressionSyntax b, ISemanticModel model, Assumptions assume, CancellationToken cancellationToken = default(CancellationToken)) { if (!b.Left.DefinitelyHasBooleanType(model)) yield break; if (!b.Right.DefinitelyHasBooleanType(model)) yield break; // prep basic analysis var leftEffects = b.Left.HasSideEffects(model, assume) != false; var rightEffects = b.Right.HasSideEffects(model, assume) != false; var lv = b.Left.TryGetConstBoolValue(); var rv = b.Right.TryGetConstBoolValue(); var cmp = b.Left.TryEvalAlternativeComparison(b.Right, model, assume); // prep utility funcs for adding simplifications var actions = new List<ReplaceAction>(); Action<String, ExpressionSyntax> include = (desc, rep) => actions.Add(new ReplaceAction(desc, b, rep)); Action<bool> useRight = v => { if (!leftEffects) include(v ? "rhs" : "!rhs", b.Right.MaybeInverted(!v)); }; Action<bool> useLeft = v => { if (!rightEffects) include(v ? "lhs" : "!lhs", b.Left.MaybeInverted(!v)); }; Action<bool> useBool = v => { if (!leftEffects && !rightEffects) { actions.Clear(); // override left/right include(v + "", v.AsLiteral()); } }; // try to simplify equality operators ==, !=, ^ bool? equality = null; if (b.Kind == SyntaxKind.EqualsExpression) equality = true; if (b.Kind == SyntaxKind.ExclusiveOrExpression || b.Kind == SyntaxKind.NotEqualsExpression) equality = false; if (equality != null) { if (lv != null) useRight(lv == equality); if (rv != null) useLeft(rv == equality); if (cmp != null) useBool(cmp == equality); } // try to simplify and/or operators &&, &, ||, | var sticky = b.Kind.IsAndBL() ? false : b.Kind.IsOrBL() ? true : (bool?)null; if (sticky != null) { if (b.Kind.IsShortCircuitingLogic() && lv == sticky) rightEffects = false; // short-circuit prevents effects if (cmp == true || lv == !sticky) useRight(true); if (cmp == true || rv == !sticky) useLeft(true); if (cmp == false || lv == sticky || rv == sticky) useBool(sticky.Value); } // expose simplifications as code issues/actions foreach (var action in actions) yield return action; }
private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, BinaryExpressionSyntax syntax) { var newNode = SyntaxFactory.ParenthesizedExpression(syntax.WithoutTrivia()) .WithTriviaFrom(syntax) .WithoutFormatting(); var newSyntaxRoot = root.ReplaceNode(syntax, newNode); return Task.FromResult(document.WithSyntaxRoot(newSyntaxRoot)); }
/// <summary> /// Normalizes the <paramref name="binaryExpression" />. /// </summary> public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax binaryExpression) { var expressionType = DetermineType(binaryExpression); if (expressionType == ExpressionType.Other) return base.VisitBinaryExpression(binaryExpression); var left = ReplaceImplicitConversion(expressionType, binaryExpression.Left); var right = ReplaceImplicitConversion(expressionType, binaryExpression.Right); return binaryExpression.Update(left, binaryExpression.OperatorToken, right); }
internal static SyntaxNode CreateNestedIf(BinaryExpressionSyntax condition, SyntaxNode root) { var ifStatement = condition.FirstAncestorOfType<IfStatementSyntax>(); var nestedIf = SyntaxFactory.IfStatement(condition.Right, ifStatement.Statement); var newStatement = ifStatement.Statement.IsKind(SyntaxKind.Block) ? (StatementSyntax)SyntaxFactory.Block(nestedIf) : nestedIf; var newIf = ifStatement.WithCondition(condition.Left) .WithStatement(newStatement) .WithAdditionalAnnotations(Formatter.Annotation); var newRoot = root.ReplaceNode(ifStatement, newIf); return newRoot; }
private async Task<Document> IntegrateStringsAsync(Document document, BinaryExpressionSyntax addExpression, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newExpression = ToIntegratedString(addExpression.Left, addExpression.Right); var newRoot = root.ReplaceNode(addExpression, newExpression); var newDocument = document.WithSyntaxRoot(newRoot); return newDocument; }
static bool CheckConditionAndAssignment(SyntaxNodeAnalysisContext nodeContext, AssignmentExpressionSyntax assignment, BinaryExpressionSyntax condition) { if (assignment == null) return false; var assignmentTarget = nodeContext.SemanticModel.GetSymbolInfo(assignment.Left).Symbol; if (assignmentTarget == null) return false; var condLeftSymbol = nodeContext.SemanticModel.GetSymbolInfo(condition.Left).Symbol; var condRightSymbol = nodeContext.SemanticModel.GetSymbolInfo(condition.Right).Symbol; var assignmentValue = nodeContext.SemanticModel.GetSymbolInfo(assignment.Right).Symbol; var constant = nodeContext.SemanticModel.GetConstantValue(assignment.Right); bool constantAssignment = assignmentValue == null && constant.HasValue; if (assignmentTarget.Equals(condLeftSymbol)) { if (constantAssignment) { var condRightValue = nodeContext.SemanticModel.GetConstantValue(condition.Right); if (condRightValue.HasValue) return condRightValue.Value == constant.Value; } else { if ((assignmentValue == null) || !assignmentValue.Equals(condRightSymbol)) return false; } return true; } // flipped operands if (assignmentTarget.Equals(condRightSymbol)) { if (constantAssignment) { var condLeftValue = nodeContext.SemanticModel.GetConstantValue(condition.Left); if (condLeftValue.HasValue) return condLeftValue.Value == constant.Value; } else { if ((assignmentValue == null) || !assignmentValue.Equals(condLeftSymbol)) return false; } return true; } return false; }
private static async Task<Document> ChangeToIsNotAsync(Document document, UnaryExpressionSyntax unary, BinaryExpressionSyntax isExpression, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken); var newRoot = root.ReplaceNode( unary, SyntaxFactory.BinaryExpression( SyntaxKind.IsNotExpression, isExpression.Left, SyntaxFactory.Token(SyntaxKind.IsNotKeyword).WithTriviaFrom(isExpression.OperatorToken), isExpression.Right)); return document.WithSyntaxRoot(newRoot); }
internal static ExpressionSyntax GetLeftSide(BinaryExpressionSyntax expression) { var parent = expression.Parent as BinaryExpressionSyntax; if (parent != null) { if (parent.Right.IsEquivalentTo(expression)) { var parentClone = parent.WithRight(expression.Left); return parentClone; } } return expression.Left; }
Document PerformAction(Document document, SyntaxNode root, BinaryExpressionSyntax boP, ExpressionSyntax flagsExpression, ExpressionSyntax targetExpression, bool testFlagset) { var nodeToReplace = boP.SkipParens(); var castExpr = BuildHasFlagExpression(targetExpression, flagsExpression); if (testFlagset) { castExpr = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, castExpr); } var newRoot = root.ReplaceNode((SyntaxNode)nodeToReplace, castExpr.WithAdditionalAnnotations(Formatter.Annotation)); return document.WithSyntaxRoot(newRoot); }
SyntaxNode CreateEquals(SemanticModel model, BinaryExpressionSyntax node) { var expr = SyntaxFactory.InvocationExpression( GenerateTarget(model, node), SyntaxFactory.ArgumentList( new SeparatedSyntaxList<ArgumentSyntax>() .Add(SyntaxFactory.Argument(node.Left)) .Add(SyntaxFactory.Argument(node.Right)) ) ); if (node.IsKind(SyntaxKind.NotEqualsExpression)) return SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, expr).WithAdditionalAnnotations(Formatter.Annotation); return expr.WithAdditionalAnnotations(Formatter.Annotation); }
public override void VisitBinaryExpression(BinaryExpressionSyntax node) { node.Left.Accept(this); node.Right.Accept(this); switch (node.Kind()) { case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: break; default: throw new InvalidPreprocessorExpressionException("Expected logical and/or expression"); } }
public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node) { node = node.WithLeft((ExpressionSyntax)base.Visit((SyntaxNode)node.Left)); node = node.WithRight((ExpressionSyntax)base.Visit((SyntaxNode)node.Right)); switch (node.Left.Kind) { case SyntaxKind.CharacterLiteralExpression: case SyntaxKind.FalseLiteralExpression: case SyntaxKind.NumericLiteralExpression: case SyntaxKind.StringLiteralExpression: case SyntaxKind.TrueLiteralExpression: break; default: return node; } switch (node.Right.Kind) { case SyntaxKind.CharacterLiteralExpression: case SyntaxKind.FalseLiteralExpression: case SyntaxKind.NumericLiteralExpression: case SyntaxKind.StringLiteralExpression: case SyntaxKind.TrueLiteralExpression: break; default: return node; } dynamic nodeValue = (dynamic)session.Execute(node.ToFullString()); if (nodeValue is String) { return Syntax.LiteralExpression(SyntaxKind.StringLiteralExpression, Syntax.Literal(nodeValue)); } else if (nodeValue is Char) { return Syntax.LiteralExpression(SyntaxKind.CharacterLiteralExpression, Syntax.Literal(nodeValue)); } else if (nodeValue is Boolean) { if (nodeValue == true) { return Syntax.LiteralExpression(SyntaxKind.TrueLiteralExpression, Syntax.Token(SyntaxKind.TrueKeyword)); } else { return Syntax.LiteralExpression(SyntaxKind.FalseLiteralExpression, Syntax.Token(SyntaxKind.FalseKeyword)); } } return Syntax.LiteralExpression(SyntaxKind.NumericLiteralExpression, Syntax.Literal(nodeValue)); }
private bool IsEqualButNotTheSame(BinaryExpressionSyntax exp1, BinaryExpressionSyntax exp2, SemanticModel semanticModel) { if (exp1.Equals(exp2)) return false; var exp1AndNestings = exp1.DescendantNodesAndSelf().OfType<BinaryExpressionSyntax>().ToList(); var exp2AndNestings = exp2.DescendantNodesAndSelf().OfType<BinaryExpressionSyntax>().ToList(); if (exp1AndNestings.Count() != exp2AndNestings.Count()) return false; for (var i = 0; i < exp1AndNestings.Count(); i++) { if (!IsOperatorEqual(exp1AndNestings[i], exp2AndNestings[i])) return false; if (!AreContainedLiteralExpressionsEqual(exp1AndNestings[i], exp2AndNestings[i])) return false; if (!AreContainedSymbolsEqual(exp1AndNestings[i], exp2AndNestings[i], semanticModel)) return false; } return true; }
private static ExpressionSyntax GetRefactoredExpression(BinaryExpressionSyntax binary) { var typeofExpression = binary.Left as TypeOfExpressionSyntax; var getTypeSide = binary.Right; if (typeofExpression == null) { typeofExpression = (TypeOfExpressionSyntax)binary.Right; getTypeSide = binary.Left; } var isOperatorCall = GetIsOperatorCall(typeofExpression, getTypeSide, true); return binary.IsKind(SyntaxKind.EqualsExpression) ? GetExpressionWithParensIfNeeded(isOperatorCall, binary.Parent) : SyntaxFactory.PrefixUnaryExpression( SyntaxKind.LogicalNotExpression, SyntaxFactory.ParenthesizedExpression(isOperatorCall)); }
public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node) { var result = base.VisitBinaryExpression(node); var reducedNode = result as BinaryExpressionSyntax; if (reducedNode != node && reducedNode != null) { if ((node.Left.IsKind(SyntaxKind.CastExpression) && !reducedNode.Left.IsKind(SyntaxKind.CastExpression)) || (node.Right.IsKind(SyntaxKind.CastExpression) && !reducedNode.Right.IsKind(SyntaxKind.CastExpression))) { // Cast simplification inside a binary expression, check if we need to parenthesize the binary expression to avoid breaking parent syntax. // For example, cast removal in below case leads to syntax errors in error free code, unless parenting binary expression is parenthesized: // Original: Foo(x < (int)i, x > y) // Incorrect cast removal: Foo(x < i, x > y) // Correct cast removal: Foo((x < i), x > y) // We'll do the following to detect such cases: // 1) Get the topmostExpressionAncestor of node. // 2) Get the reducedAncestor after replacing node with reducedNode within it. // 3) Reparse the reducedAncestor to get reparsedAncestor. // 4) Check for syntax equivalence of reducedAncestor and reparsedAncestor. If not syntactically equivalent, // then cast removal breaks the syntax and needs explicit parentheses around the binary expression. var topmostExpressionAncestor = node .AncestorsAndSelf() .OfType<ExpressionSyntax>() .LastOrDefault(); if (topmostExpressionAncestor != null && topmostExpressionAncestor != node) { var reducedAncestor = topmostExpressionAncestor.ReplaceNode(node, reducedNode); var reparsedAncestor = SyntaxFactory.ParseExpression(reducedAncestor.ToFullString()); if (reparsedAncestor != null && !reparsedAncestor.IsEquivalentTo(reducedAncestor)) { return SyntaxFactory.ParenthesizedExpression(reducedNode) .WithAdditionalAnnotations(Simplifier.Annotation); } } } } return result; }
internal static IEnumerable <CodeAction> ScanIfElse(SemanticModel ctx, Document document, SyntaxNode root, IfStatementSyntax ifElseStatement, BinaryExpressionSyntax isExpression, out int foundCastCount) { foundCastCount = 0; var innerCondition = ifElseStatement.Condition.SkipParens(); if (innerCondition != null && innerCondition.IsKind(SyntaxKind.LogicalNotExpression)) { var c2 = ((PrefixUnaryExpressionSyntax)innerCondition).Operand.SkipParens(); if (c2.IsKind(SyntaxKind.IsExpression)) { return(HandleNegatedCase(ctx, document, root, ifElseStatement, ifElseStatement.Condition, isExpression, out foundCastCount)); } return(Enumerable.Empty <CodeAction>()); } var castToType = isExpression.Right; var embeddedStatment = ifElseStatement.Statement; var rr = ctx.GetTypeInfo(castToType); if (rr.Type == null || !rr.Type.IsReferenceType) { return(Enumerable.Empty <CodeAction>()); } List <SyntaxNode> foundCasts; foundCasts = embeddedStatment.DescendantNodesAndSelf(n => !IsCast(ctx, n, rr.Type)).Where(arg => IsCast(ctx, arg, rr.Type)).ToList(); foundCasts.AddRange(ifElseStatement.Condition.DescendantNodesAndSelf(n => !IsCast(ctx, n, rr.Type)).Where(arg => arg.SpanStart > isExpression.Span.End && IsCast(ctx, arg, rr.Type))); foundCastCount = foundCasts.Count; return(new[] { CodeActionFactory.Create( isExpression.Span, DiagnosticSeverity.Info, GettextCatalog.GetString("Use 'as' and check for null"), t2 => { var varName = NameGenerator.GenerateSafeCSharpName( ReplaceAutoPropertyWithPropertyAndBackingFieldCodeRefactoringProvider.GetNameProposal(RefactoringHelpers.GuessNameFromType(rr.Type), ctx, isExpression)); var varDec = SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration( SyntaxFactory.ParseTypeName("var"), SyntaxFactory.SeparatedList(new [] { SyntaxFactory.VariableDeclarator(varName) .WithInitializer(SyntaxFactory.EqualsValueClause( SyntaxFactory.BinaryExpression(SyntaxKind.AsExpression, isExpression.Left, isExpression.Right) )) }) )); var outerIs = isExpression.AncestorsAndSelf().FirstOrDefault(e => !(e.Parent is ParenthesizedExpressionSyntax)); var binaryOperatorExpression = SyntaxFactory.BinaryExpression(SyntaxKind.NotEqualsExpression, SyntaxFactory.IdentifierName(varName), SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)); SyntaxNode newRoot; if (IsEmbeddedStatement(ifElseStatement)) { foundCasts = ifElseStatement.DescendantNodesAndSelf(n => !IsCast(ctx, n, rr.Type)).Where(arg => IsCast(ctx, arg, rr.Type)).ToList(); var newIf = ifElseStatement.TrackNodes(foundCasts.Concat(new [] { outerIs })); newIf = newIf.ReplaceNode((SyntaxNode)newIf.GetCurrentNode(outerIs), binaryOperatorExpression.WithAdditionalAnnotations(Formatter.Annotation)); foreach (var c in foundCasts) { newIf = newIf.ReplaceNode((SyntaxNode)newIf.GetCurrentNode(c), SyntaxFactory.IdentifierName(varName).WithAdditionalAnnotations(Formatter.Annotation)); } var block = SyntaxFactory.Block(new StatementSyntax[] { varDec, newIf }); newRoot = root.ReplaceNode((SyntaxNode)ifElseStatement, block.WithAdditionalAnnotations(Formatter.Annotation)); } else { newRoot = root.TrackNodes(foundCasts.Concat(new SyntaxNode[] { ifElseStatement, outerIs })); newRoot = newRoot.InsertNodesBefore(newRoot.GetCurrentNode(ifElseStatement), new [] { varDec.WithAdditionalAnnotations(Formatter.Annotation) }); newRoot = newRoot.ReplaceNode((SyntaxNode)newRoot.GetCurrentNode(outerIs), binaryOperatorExpression.WithAdditionalAnnotations(Formatter.Annotation)); foreach (var c in foundCasts) { newRoot = newRoot.ReplaceNode((SyntaxNode)newRoot.GetCurrentNode(c), SyntaxFactory.IdentifierName(varName).WithAdditionalAnnotations(Formatter.Annotation)); } } return Task.FromResult(document.WithSyntaxRoot(newRoot)); } ) }); }
private ProgramState VisitComparisonBinaryOperator(ProgramState programState, BinaryExpressionSyntax comparison, Func <SymbolicValue, SymbolicValue, SymbolicValue> svFactory) { var newProgramState = programState .PopValue(out var rightSymbol) .PopValue(out var leftSymbol); var op = SemanticModel.GetSymbolInfo(comparison).Symbol as IMethodSymbol; var isValueTypeOperator = op?.ContainingType?.IsValueType ?? false; var isLiftedOperator = isValueTypeOperator && (leftSymbol.IsNull(programState) || rightSymbol.IsNull(programState)); var comparisonValue = isLiftedOperator ? SymbolicValue.False : svFactory(leftSymbol, rightSymbol); return(newProgramState.PushValue(comparisonValue)); }
public override void VisitBinaryExpression(BinaryExpressionSyntax node) { Check(node.Left); Check(node.Right); }
private static async Task <Document> UseConditionalAccessAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); SyntaxKind kind = binaryExpression.Kind(); (ExpressionSyntax left, ExpressionSyntax right) = UseConditionalAccessAnalyzer.GetFixableExpressions(binaryExpression, kind, semanticModel, cancellationToken); NullCheckStyles allowedStyles = (kind == SyntaxKind.LogicalAndExpression) ? NullCheckStyles.NotEqualsToNull : NullCheckStyles.EqualsToNull; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(left, semanticModel, allowedStyles: allowedStyles, cancellationToken: cancellationToken); ExpressionSyntax expression = nullCheck.Expression; bool isNullable = semanticModel.GetTypeSymbol(expression, cancellationToken).IsNullableType(); ExpressionSyntax expression2 = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed( expression, right, isNullable: isNullable, semanticModel, cancellationToken); var builder = new SyntaxNodeTextBuilder(binaryExpression, StringBuilderCache.GetInstance(binaryExpression.FullSpan.Length)); builder.Append(TextSpan.FromBounds(binaryExpression.FullSpan.Start, left.SpanStart)); int parenDiff = GetParenTokenDiff(); if (parenDiff > 0) { builder.Append('(', parenDiff); } builder.AppendSpan(expression); builder.Append("?"); builder.Append(TextSpan.FromBounds(expression2.Span.End, right.Span.End)); switch (right.Kind()) { case SyntaxKind.LogicalOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.IsExpression: case SyntaxKind.AsExpression: case SyntaxKind.IsPatternExpression: { break; } case SyntaxKind.LogicalNotExpression: { builder.Append((kind == SyntaxKind.LogicalAndExpression) ? " == false" : " != true"); break; } default: { builder.Append((kind == SyntaxKind.LogicalAndExpression) ? " == true" : " != false"); break; } } if (parenDiff < 0) { builder.Append(')', -parenDiff); } builder.Append(TextSpan.FromBounds(right.Span.End, binaryExpression.FullSpan.End)); string text = StringBuilderCache.GetStringAndFree(builder.StringBuilder); ParenthesizedExpressionSyntax newNode = SyntaxFactory.ParseExpression(text) .WithFormatterAnnotation() .Parenthesize(); return(await document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken).ConfigureAwait(false)); int GetParenTokenDiff() { int count = 0; foreach (SyntaxToken token in binaryExpression.DescendantTokens(TextSpan.FromBounds(left.SpanStart, expression2.Span.End))) { SyntaxKind tokenKind = token.Kind(); if (tokenKind == SyntaxKind.OpenParenToken) { if (token.IsParentKind(SyntaxKind.ParenthesizedExpression)) { count++; } } else if (tokenKind == SyntaxKind.CloseParenToken) { if (token.IsParentKind(SyntaxKind.ParenthesizedExpression)) { count--; } } } return(count); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression)) { return; } Document document = context.Document; foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case DiagnosticIdentifiers.ConstantValuesShouldBePlacedOnRightSideOfComparisons: { CodeAction codeAction = CodeAction.Create( "Swap operands", ct => document.ReplaceNodeAsync(binaryExpression, SyntaxRefactorings.SwapBinaryOperands(binaryExpression), ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod: { CodeAction codeAction = CodeAction.Create( "Use 'string.IsNullOrEmpty' method", ct => UseStringIsNullOrEmptyMethodAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.SimplifyCoalesceExpression: { ExpressionSyntax expression = binaryExpression.Left; if (expression == null || !context.Span.Contains(expression.Span)) { expression = binaryExpression.Right; } CodeAction codeAction = CodeAction.Create( "Simplify coalesce expression", ct => SimplifyCoalesceExpressionRefactoring.RefactorAsync(document, binaryExpression, expression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.RemoveRedundantAsOperator: { CodeAction codeAction = CodeAction.Create( "Remove redundant 'as' operator", ct => RemoveRedundantAsOperatorRefactoring.RefactorAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString: { CodeAction codeAction = CodeAction.Create( "Use string.Length", ct => UseStringLengthInsteadOfComparisonWithEmptyStringAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); CodeAction codeAction = CodeAction.Create( $"Use EqualityComparer<{typeSymbol.Name}>.Default", ct => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken); string title; if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) || typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName)) { ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions()); title = $"Replace 'null' with '{expression}'"; } else { title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.DisplayName)}>.Default"; } CodeAction codeAction = CodeAction.Create( title, ct => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.JoinStringExpressions: { CodeAction codeAction = CodeAction.Create( "Join string expressions", ct => JoinStringExpressionsRefactoring.RefactorAsync(document, binaryExpression, context.Span, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseExclusiveOrOperator: { CodeAction codeAction = CodeAction.Create( "Use ^ operator", ct => UseExclusiveOrOperatorRefactoring.RefactorAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnnecessaryNullCheck: { CodeAction codeAction = CodeAction.Create( "Remove unnecessary null check", ct => RemoveUnnecessaryNullCheckAsync(document, binaryExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UseShortCircuitingOperator: { SyntaxToken operatorToken = binaryExpression.OperatorToken; SyntaxKind kind = binaryExpression.Kind(); SyntaxToken newToken = default; if (kind == SyntaxKind.BitwiseAndExpression) { newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, operatorToken.TrailingTrivia); } else if (kind == SyntaxKind.BitwiseOrExpression) { newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.BarBarToken, operatorToken.TrailingTrivia); } CodeAction codeAction = CodeAction.Create( $"Use '{newToken.ToString()}' operator", ct => { BinaryExpressionSyntax newBinaryExpression = null; if (kind == SyntaxKind.BitwiseAndExpression) { newBinaryExpression = LogicalAndExpression(binaryExpression.Left, newToken, binaryExpression.Right); } else if (kind == SyntaxKind.BitwiseOrExpression) { newBinaryExpression = LogicalOrExpression(binaryExpression.Left, newToken, binaryExpression.Right); } return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.UnnecessaryOperator: { CodeAction codeAction = CodeAction.Create( "Use '==' operator", ct => { SyntaxToken operatorToken = binaryExpression.OperatorToken; BinaryExpressionSyntax newBinaryExpression = EqualsExpression( binaryExpression.Left, Token(operatorToken.LeadingTrivia, SyntaxKind.EqualsEqualsToken, operatorToken.TrailingTrivia), binaryExpression.Right); return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
private static bool IsTopLevelSubtraction(BinaryExpressionSyntax subtraction) { var parent = subtraction.Parent as BinaryExpressionSyntax; return(parent == null || !parent.IsKind(SyntaxKind.SubtractExpression)); }
private static bool IsStringConcatenation(SyntaxNodeAnalysisContext context, BinaryExpressionSyntax binaryExpression) { return(binaryExpression.IsKind(SyntaxKind.AddExpression) && (IsStringExpression(context, binaryExpression.Left) || IsStringExpression(context, binaryExpression.Right))); }
public override void VisitBinaryExpression(BinaryExpressionSyntax node) { Emit <BinaryExpressionBlock, BinaryExpressionSyntax>(node); }
private static IsPatternExpressionSyntax RewriteWorker(BinaryExpressionSyntax binary) => binary.Right.IsKind(SyntaxKind.NullLiteralExpression) ? Rewrite(binary, binary.Left, binary.Right) : Rewrite(binary, binary.Right, binary.Left);
private bool IsVariableAndLiteralBinaryExpression(BinaryExpressionSyntax binaryExpression, string identifierName) => (IsIdentifier(binaryExpression.Left, identifierName) && binaryExpression.Right.IsKind(SyntaxKind.NumericLiteralExpression)) || (binaryExpression.Left.IsKind(SyntaxKind.NumericLiteralExpression) && IsIdentifier(binaryExpression.Right, identifierName));
private static bool IsShortcuttingExpression(BinaryExpressionSyntax expression, bool constantValueIsTrue) { return(expression != null && (expression.IsKind(SyntaxKind.LogicalAndExpression) && !constantValueIsTrue || expression.IsKind(SyntaxKind.LogicalOrExpression) && constantValueIsTrue)); }
private bool TryCheckVariableAndIfStatementForm( SyntaxNodeAnalysisContext syntaxContext, IfStatementSyntax ifStatement, BinaryExpressionSyntax condition, ExpressionStatementSyntax expressionStatement, InvocationExpressionSyntax invocationExpression, ReportDiagnostic severity) { var cancellationToken = syntaxContext.CancellationToken; cancellationToken.ThrowIfCancellationRequested(); // look for the form "if (a != null)" or "if (null != a)" if (!ifStatement.Parent.IsKind(SyntaxKind.Block)) { return(false); } if (!IsNullCheckExpression(condition.Left, condition.Right) && !IsNullCheckExpression(condition.Right, condition.Left)) { return(false); } var expression = invocationExpression.Expression; if (!expression.IsKind(SyntaxKind.IdentifierName)) { return(false); } var conditionName = condition.Left is IdentifierNameSyntax ? (IdentifierNameSyntax)condition.Left : (IdentifierNameSyntax)condition.Right; var invocationName = (IdentifierNameSyntax)expression; if (!Equals(conditionName.Identifier.ValueText, invocationName.Identifier.ValueText)) { return(false); } // Now make sure the previous statement is "var a = ..." var parentBlock = (BlockSyntax)ifStatement.Parent; var ifIndex = parentBlock.Statements.IndexOf(ifStatement); if (ifIndex == 0) { return(false); } var previousStatement = parentBlock.Statements[ifIndex - 1]; if (!previousStatement.IsKind(SyntaxKind.LocalDeclarationStatement)) { return(false); } var localDeclarationStatement = (LocalDeclarationStatementSyntax)previousStatement; var variableDeclaration = localDeclarationStatement.Declaration; if (variableDeclaration.Variables.Count != 1) { return(false); } var declarator = variableDeclaration.Variables[0]; if (declarator.Initializer == null) { return(false); } cancellationToken.ThrowIfCancellationRequested(); if (!Equals(declarator.Identifier.ValueText, conditionName.Identifier.ValueText)) { return(false); } // Syntactically this looks good. Now make sure that the local is a delegate type. var semanticModel = syntaxContext.SemanticModel; var localSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(declarator, cancellationToken); // Ok, we made a local just to check it for null and invoke it. Looks like something // we can suggest an improvement for! // But first make sure we're only using the local only within the body of this if statement. var analysis = semanticModel.AnalyzeDataFlow(localDeclarationStatement, ifStatement); if (analysis.ReadOutside.Contains(localSymbol) || analysis.WrittenOutside.Contains(localSymbol)) { return(false); } // Looks good! var tree = semanticModel.SyntaxTree; var additionalLocations = new List <Location> { Location.Create(tree, localDeclarationStatement.Span), Location.Create(tree, ifStatement.Span), Location.Create(tree, expressionStatement.Span) }; ReportDiagnostics(syntaxContext, localDeclarationStatement, ifStatement, expressionStatement, severity, additionalLocations, Constants.VariableAndIfStatementForm); return(true); }
public bool TryGetPatternPieces( BinaryExpressionSyntax isExpression, out IfStatementSyntax ifStatement, out LocalDeclarationStatementSyntax localDeclarationStatement, out VariableDeclaratorSyntax declarator, out CastExpressionSyntax castExpression) { ifStatement = null; localDeclarationStatement = null; declarator = null; castExpression = null; // The is check has to be in an if check: "if (x is Type) if (!isExpression.Parent.IsKind(SyntaxKind.IfStatement, out ifStatement)) { return(false); } if (!ifStatement.Statement.IsKind(SyntaxKind.Block, out BlockSyntax ifBlock)) { return(false); } if (ifBlock.Statements.Count == 0) { return(false); } var firstStatement = ifBlock.Statements[0]; if (!firstStatement.IsKind(SyntaxKind.LocalDeclarationStatement, out localDeclarationStatement)) { return(false); } if (localDeclarationStatement.Declaration.Variables.Count != 1) { return(false); } declarator = localDeclarationStatement.Declaration.Variables[0]; if (declarator.Initializer == null) { return(false); } var declaratorValue = declarator.Initializer.Value.WalkDownParentheses(); if (!declaratorValue.IsKind(SyntaxKind.CastExpression, out castExpression)) { return(false); } if (!SyntaxFactory.AreEquivalent(isExpression.Left.WalkDownParentheses(), castExpression.Expression.WalkDownParentheses(), topLevel: false) || !SyntaxFactory.AreEquivalent(isExpression.Right.WalkDownParentheses(), castExpression.Type, topLevel: false)) { return(false); } return(true); }
public Task <Document> RefactorAsync( Document document, IfStatementSyntax ifStatement, BinaryExpressionSyntax condition, in ExpressionChain expressionChain,
private static void CheckRightExpressionForRemovableToStringCall(SyntaxNodeAnalysisContext context, BinaryExpressionSyntax binary) { CheckExpressionForRemovableToStringCall(context, binary.Right, binary.Left, 1); }
public override void VisitBinaryExpression(BinaryExpressionSyntax node) { var ci = m_ClassInfoStack.Peek(); var oper = m_Model.GetOperation(node) as IHasOperatorMethodExpression; if (null != oper && oper.UsesOperatorMethod) { IMethodSymbol msym = oper.OperatorMethod; var castOper = oper as IConversionExpression; if (null != castOper) { InvocationInfo ii = new InvocationInfo(); var arglist = new List <ExpressionSyntax>() { node.Left }; ii.Init(msym, arglist, m_Model); OutputOperatorInvoke(ii, node); } else { InvocationInfo ii = new InvocationInfo(); var arglist = new List <ExpressionSyntax>() { node.Left, node.Right }; ii.Init(msym, arglist, m_Model); OutputOperatorInvoke(ii, node); } } else { string op = node.OperatorToken.Text; ProcessBinaryOperator(node, ref op); string functor; if (s_BinaryFunctor.TryGetValue(op, out functor)) { CodeBuilder.AppendFormat("{0}(", functor); VisitExpressionSyntax(node.Left); CodeBuilder.Append(", "); if (op == "as" || op == "is") { var typeInfo = m_Model.GetTypeInfo(node.Right); var type = typeInfo.Type; OutputType(type, node, ci, op); } else if (op == "??") { var rightOper = m_Model.GetOperation(node.Right); bool rightIsConst = null != rightOper && rightOper.ConstantValue.HasValue; if (rightIsConst) { CodeBuilder.Append("true, "); VisitExpressionSyntax(node.Right); } else { CodeBuilder.Append("false, (function() return "); VisitExpressionSyntax(node.Right); CodeBuilder.Append("; end)"); } } else { VisitExpressionSyntax(node.Right); } CodeBuilder.Append(")"); } else if (op == "+") { ProcessAddOrStringConcat(node.Left, node.Right); } else if (op == "==" || op == "~=") { ProcessEqualOrNotEqual(op, node.Left, node.Right); } else { CodeBuilder.Append("("); VisitExpressionSyntax(node.Left); CodeBuilder.AppendFormat(" {0} ", op); VisitExpressionSyntax(node.Right); CodeBuilder.Append(")"); } } }
public override JsExpression VisitBinaryExpression(BinaryExpressionSyntax node) { switch (node.Kind()) { case SyntaxKind.IsExpression: { var operand = node.Left.Accept(this); var type = (INamedTypeSymbol)model.GetSymbolInfo(node.Right).Symbol; var typeIs = GetExpressionMethod("TypeIs", Context.Instance.Expression, Context.Instance.TypeType); return(idioms.InvokeStatic(typeIs, operand, idioms.TypeOf(type))); } case SyntaxKind.AsExpression: { var operand = node.Left.Accept(this); var type = (INamedTypeSymbol)model.GetSymbolInfo(node.Right).Symbol; var typeAs = GetExpressionMethod("TypeAs", Context.Instance.Expression, Context.Instance.TypeType); return(idioms.InvokeStatic(typeAs, operand, idioms.TypeOf(type))); } } ExpressionType op; switch (node.Kind()) { case SyntaxKind.AddExpression: op = ExpressionType.Add; break; case SyntaxKind.MultiplyExpression: op = ExpressionType.Multiply; break; case SyntaxKind.BitwiseAndExpression: op = ExpressionType.And; break; case SyntaxKind.BitwiseOrExpression: op = ExpressionType.Or; break; case SyntaxKind.DivideExpression: op = ExpressionType.Divide; break; case SyntaxKind.GreaterThanExpression: op = ExpressionType.GreaterThan; break; case SyntaxKind.EqualsExpression: op = ExpressionType.Equal; break; case SyntaxKind.ExclusiveOrExpression: op = ExpressionType.OrElse; break; case SyntaxKind.GreaterThanOrEqualExpression: op = ExpressionType.GreaterThanOrEqual; break; case SyntaxKind.LessThanExpression: op = ExpressionType.LessThan; break; case SyntaxKind.LessThanOrEqualExpression: op = ExpressionType.LessThanOrEqual; break; case SyntaxKind.ModuloExpression: op = ExpressionType.Modulo; break; case SyntaxKind.LeftShiftExpression: op = ExpressionType.LeftShift; break; case SyntaxKind.RightShiftExpression: op = ExpressionType.RightShift; break; case SyntaxKind.SubtractExpression: op = ExpressionType.Subtract; break; case SyntaxKind.CoalesceExpression: op = ExpressionType.Coalesce; break; case SyntaxKind.LogicalAndExpression: op = ExpressionType.AndAlso; break; case SyntaxKind.LogicalOrExpression: op = ExpressionType.OrElse; break; default: throw new Exception("Unknown operation: " + node.Kind()); } var left = node.Left.Accept(this); var right = node.Right.Accept(this); var jsMethodInfo = GetExpressionMethod("MakeBinary", Context.Instance.ExpressionType, Context.Instance.Expression, Context.Instance.Expression); var opExpression = idioms.GetEnumValue(Context.Instance.ExpressionType.GetMembers(op.ToString()).OfType <IFieldSymbol>().Single()); var jsMethod = idioms.InvokeStatic(jsMethodInfo, opExpression, left, right); return(jsMethod); }
private static async Task <ExpressionSyntax> CreateNewNodeAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { ExpressionSyntax left = binaryExpression.Left; ExpressionSyntax right = binaryExpression.Right; TextSpan span = TextSpan.FromBounds(left.Span.End, right.SpanStart); IEnumerable <SyntaxTrivia> trivia = binaryExpression.DescendantTrivia(span); bool isWhiteSpaceOrEndOfLine = trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (CSharpFacts.IsBooleanLiteralExpression(left.Kind())) { SyntaxTriviaList leadingTrivia = binaryExpression.GetLeadingTrivia(); if (!isWhiteSpaceOrEndOfLine) { leadingTrivia = leadingTrivia.AddRange(trivia); } if (right.IsKind(SyntaxKind.LogicalNotExpression)) { var logicalNot = (PrefixUnaryExpressionSyntax)right; ExpressionSyntax operand = logicalNot.Operand; if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean)) { return(binaryExpression .WithLeft(Inverter.LogicallyNegate(left, semanticModel, cancellationToken)) .WithRight(operand.WithTriviaFrom(right))); } } return(Inverter.LogicallyNegate(right, semanticModel, cancellationToken) .WithLeadingTrivia(leadingTrivia)); } else if (CSharpFacts.IsBooleanLiteralExpression(right.Kind())) { SyntaxTriviaList trailingTrivia = binaryExpression.GetTrailingTrivia(); if (!isWhiteSpaceOrEndOfLine) { trailingTrivia = trailingTrivia.InsertRange(0, trivia); } if (left.IsKind(SyntaxKind.LogicalNotExpression)) { var logicalNot = (PrefixUnaryExpressionSyntax)left; ExpressionSyntax operand = logicalNot.Operand; if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean)) { return(binaryExpression .WithLeft(operand.WithTriviaFrom(left)) .WithRight(Inverter.LogicallyNegate(right, semanticModel, cancellationToken))); } } return(Inverter.LogicallyNegate(left, semanticModel, cancellationToken) .WithTrailingTrivia(trailingTrivia)); } Debug.Fail(binaryExpression.ToString()); return(binaryExpression); }
private bool ReplacementBreaksIsOrAsExpression(BinaryExpressionSyntax originalIsOrAsExpression, BinaryExpressionSyntax newIsOrAsExpression) { // Special case: Lambda expressions and anonymous delegates cannot appear // on the left-side of an 'is' or 'as' cast. We can handle this case syntactically. if (!originalIsOrAsExpression.Left.WalkDownParentheses().IsAnyLambdaOrAnonymousMethod() && newIsOrAsExpression.Left.WalkDownParentheses().IsAnyLambdaOrAnonymousMethod()) { return(true); } var originalConvertedType = this.OriginalSemanticModel.GetTypeInfo(originalIsOrAsExpression.Right).Type; var newConvertedType = this.SpeculativeSemanticModel.GetTypeInfo(newIsOrAsExpression.Right).Type; if (originalConvertedType == null || newConvertedType == null) { return(originalConvertedType != newConvertedType); } var originalConversion = this.OriginalSemanticModel.ClassifyConversion(originalIsOrAsExpression.Left, originalConvertedType, isExplicitInSource: true); var newConversion = this.SpeculativeSemanticModel.ClassifyConversion(newIsOrAsExpression.Left, newConvertedType, isExplicitInSource: true); // Is and As operators do not consider any user-defined operators, just ensure that the conversion exists. return(originalConversion.Exists != newConversion.Exists); }
private static bool IsIgnoredNullableOperation(BinaryExpressionSyntax expression, SemanticModel semanticModel) { return(expression.OperatorToken.IsAnyKind(ignoredNullableOperators) && (IsNullable(expression.Left, semanticModel) || IsNullable(expression.Right, semanticModel))); }
private bool ReplacementBreaksBinaryExpression(BinaryExpressionSyntax binaryExpression, BinaryExpressionSyntax newBinaryExpression) { if ((binaryExpression.IsKind(SyntaxKind.AsExpression) || binaryExpression.IsKind(SyntaxKind.IsExpression)) && ReplacementBreaksIsOrAsExpression(binaryExpression, newBinaryExpression)) { return(true); } return(!SymbolsAreCompatible(binaryExpression, newBinaryExpression) || !TypesAreCompatible(binaryExpression, newBinaryExpression)); }
private static void CheckFollowingExpressions(SyntaxNodeAnalysisContext c, int currentExpressionIndex, List <ExpressionSyntax> expressionsInChain, ExpressionSyntax expressionComparedToNull, BinaryExpressionSyntax comparisonToNull) { for (var j = currentExpressionIndex + 1; j < expressionsInChain.Count; j++) { var descendantNodes = expressionsInChain[j].DescendantNodes() .Where(descendant => descendant.IsKind(expressionComparedToNull.Kind()) && EquivalenceChecker.AreEquivalent(expressionComparedToNull, descendant)) .Where(descendant => (descendant.Parent is MemberAccessExpressionSyntax && EquivalenceChecker.AreEquivalent(expressionComparedToNull, ((MemberAccessExpressionSyntax)descendant.Parent).Expression)) || (descendant.Parent is ElementAccessExpressionSyntax && EquivalenceChecker.AreEquivalent(expressionComparedToNull, ((ElementAccessExpressionSyntax)descendant.Parent).Expression))) .ToList(); if (descendantNodes.Any()) { c.ReportDiagnostic(Diagnostic.Create(Rule, comparisonToNull.GetLocation(), expressionComparedToNull.ToString())); } } }
private static async Task <Document> FixAllAsync( Document document, ImmutableArray <Diagnostic> diagnostics, bool negate, CancellationToken cancellationToken ) { var semanticModel = await document .GetSemanticModelAsync(cancellationToken) .ConfigureAwait(false); var root = await document .GetRequiredSyntaxRootAsync(cancellationToken) .ConfigureAwait(false); var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); var generator = editor.Generator; var generatorInternal = document.GetRequiredLanguageService <SyntaxGeneratorInternal>(); foreach (var diagnostic in diagnostics) { var node = diagnostic.AdditionalLocations[0].FindNode( getInnermostNodeForTie: true, cancellationToken ); Debug.Assert( node.IsKind(SyntaxKind.IsExpression) || node.IsKind(SyntaxKind.IsPatternExpression) ); // Negate the result if requested. var updatedNode = negate ? generator.Negate(generatorInternal, node, semanticModel, cancellationToken) : node; var isNode = updatedNode .DescendantNodesAndSelf() .First( n => n.IsKind(SyntaxKind.IsExpression) || n.IsKind(SyntaxKind.IsPatternExpression) ); var left = isNode switch { BinaryExpressionSyntax binary => binary.Left, IsPatternExpressionSyntax isPattern => isPattern.Expression, _ => throw ExceptionUtilities.UnexpectedValue(node), }; // Remove the suppression operator. var suppression = (PostfixUnaryExpressionSyntax)left; var withoutSuppression = suppression.Operand.WithAppendedTrailingTrivia( suppression.OperatorToken.GetAllTrivia() ); var isWithoutSuppression = updatedNode.ReplaceNode(suppression, withoutSuppression); editor.ReplaceNode(node, isWithoutSuppression); } return(document.WithSyntaxRoot(editor.GetChangedRoot())); }
private static void AnalyzeEqualsNotEquals( SyntaxNodeAnalysisContext context, BinaryExpressionSyntax binaryExpression, ExpressionSyntax left, ExpressionSyntax right, SyntaxKind kind, SyntaxKind kind2) { SyntaxKind leftKind = left.Kind(); if (leftKind == kind) { switch (AnalyzeExpression(right, context.SemanticModel, context.CancellationToken)) { case AnalysisResult.Boolean: { SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: true); break; } case AnalysisResult.LogicalNotWithNullableBoolean: { SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false); break; } } } else if (leftKind == kind2) { switch (AnalyzeExpression(right, context.SemanticModel, context.CancellationToken)) { case AnalysisResult.Boolean: { RemoveRedundantBooleanLiteralAnalysis.ReportDiagnostic(context, binaryExpression, left, right); break; } case AnalysisResult.LogicalNotWithNullableBoolean: { SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false); break; } } } else { SyntaxKind rightKind = right.Kind(); if (rightKind == kind) { switch (AnalyzeExpression(left, context.SemanticModel, context.CancellationToken)) { case AnalysisResult.Boolean: { SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: true); break; } case AnalysisResult.LogicalNotWithNullableBoolean: { SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false); break; } } } else if (rightKind == kind2) { switch (AnalyzeExpression(left, context.SemanticModel, context.CancellationToken)) { case AnalysisResult.Boolean: { RemoveRedundantBooleanLiteralAnalysis.ReportDiagnostic(context, binaryExpression, left, right); break; } case AnalysisResult.LogicalNotWithNullableBoolean: { SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false); break; } } } } }
public static async Task ComputeRefactoringsAsync(RefactoringContext context, BinaryExpressionSyntax binaryExpression) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.NegateOperator)) { SyntaxToken operatorToken = binaryExpression.OperatorToken; if (operatorToken.Span.Contains(context.Span) && NegateOperatorRefactoring.CanBeNegated(operatorToken)) { context.RegisterRefactoring( "Negate operator", cancellationToken => NegateOperatorRefactoring.RefactorAsync(context.Document, operatorToken, cancellationToken)); } } if (context.IsRefactoringEnabled(RefactoringIdentifiers.FormatBinaryExpression)) { FormatBinaryExpressionRefactoring.ComputeRefactorings(context, binaryExpression); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.NegateBinaryExpression)) { NegateBinaryExpressionRefactoring.ComputeRefactoring(context, binaryExpression); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.ExpandCoalesceExpression) && binaryExpression.OperatorToken.Span.Contains(context.Span)) { ExpandCoalesceExpressionRefactoring.ComputeRefactoring(context, binaryExpression); } if (context.IsAnyRefactoringEnabled( RefactoringIdentifiers.JoinStringExpressions, RefactoringIdentifiers.UseStringBuilderInsteadOfConcatenation) && context.Span.IsBetweenSpans(binaryExpression) && binaryExpression.IsKind(SyntaxKind.AddExpression)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); StringConcatenationExpressionInfo concatenationInfo = SyntaxInfo.StringConcatenationExpressionInfo(binaryExpression, semanticModel, context.CancellationToken); if (concatenationInfo.Success) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.JoinStringExpressions)) { JoinStringExpressionsRefactoring.ComputeRefactoring(context, concatenationInfo); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.UseStringBuilderInsteadOfConcatenation)) { UseStringBuilderInsteadOfConcatenationRefactoring.ComputeRefactoring(context, concatenationInfo); } } } if (context.IsRefactoringEnabled(RefactoringIdentifiers.SwapExpressionsInBinaryExpression) && context.Span.IsBetweenSpans(binaryExpression)) { SwapExpressionsInBinaryExpressionRefactoring.ComputeRefactoring(context, binaryExpression); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceAsWithCast) && context.Span.IsEmptyAndContainedInSpanOrBetweenSpans(binaryExpression)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (ReplaceAsWithCastAnalysis.IsFixable(binaryExpression, semanticModel, context.CancellationToken)) { context.RegisterRefactoring( "Replace as with cast", cancellationToken => ReplaceAsWithCastRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken)); } } if (context.IsRefactoringEnabled(RefactoringIdentifiers.NegateIsExpression)) { NegateIsExpressionRefactoring.ComputeRefactoring(context, binaryExpression); } if (context.Span.IsContainedInSpanOrBetweenSpans(binaryExpression.OperatorToken)) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceEqualsExpressionWithStringEquals)) { await ReplaceEqualsExpressionWithStringEqualsRefactoring.ComputeRefactoringAsync(context, binaryExpression).ConfigureAwait(false); } if (context.IsAnyRefactoringEnabled( RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrEmpty, RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrWhiteSpace)) { await ReplaceEqualsExpressionRefactoring.ComputeRefactoringsAsync(context, binaryExpression).ConfigureAwait(false); } } if (!context.Span.IsBetweenSpans(binaryExpression) && context.IsAnyRefactoringEnabled( RefactoringIdentifiers.ExtractExpressionFromCondition, RefactoringIdentifiers.JoinStringExpressions)) { BinaryExpressionSelection binaryExpressionSelection = BinaryExpressionSelection.Create(binaryExpression, context.Span); if (binaryExpressionSelection.Success && binaryExpressionSelection.Expressions.Length > 1) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.ExtractExpressionFromCondition)) { ExtractConditionRefactoring.ComputeRefactoring(context, binaryExpressionSelection); } if (context.IsRefactoringEnabled(RefactoringIdentifiers.JoinStringExpressions) && binaryExpression.IsKind(SyntaxKind.AddExpression)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); StringConcatenationExpressionInfo concatenation = SyntaxInfo.StringConcatenationExpressionInfo(binaryExpressionSelection, semanticModel, context.CancellationToken); if (concatenation.Success) { JoinStringExpressionsRefactoring.ComputeRefactoring(context, concatenation); } } } } }
public override void VisitBinaryExpression(BinaryExpressionSyntax node) { }
public override IEnumerable <MemberAccessExpressionSyntax> VisitBinaryExpression(BinaryExpressionSyntax node) { switch (node.Kind()) { case SyntaxKind.BitwiseAndExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.AddExpression: break; default: throw new CodeGeneratorException(node.GetLocation(), $"Unsupported binary expression {node.Kind()}. Only bitwise OR, AND, XOR and addition is allowed."); } return(node.ChildNodes().SelectMany(n => Visit(n))); }
public static bool IsStringConcatenation(BinaryExpressionSyntax addExpression, SemanticModel semanticModel, CancellationToken cancellationToken = default) { return(addExpression.Kind() == SyntaxKind.AddExpression && SymbolUtility.IsStringAdditionOperator(semanticModel.GetMethodSymbol(addExpression, cancellationToken))); }
public static Task <Document> RefactorAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken = default(CancellationToken)) { if (!(binaryExpression.Left is InvocationExpressionSyntax invocationExpression)) { invocationExpression = (InvocationExpressionSyntax)binaryExpression.Right; } ExpressionSyntax left = binaryExpression.Left; ExpressionSyntax right = binaryExpression.Right; ExpressionSyntax newNode = null; SyntaxKind kind = binaryExpression.Kind(); if (kind == SyntaxKind.EqualsExpression) { // Count() == 0 >>> !Any() newNode = ChangeInvokedMethodName(invocationExpression, "Any"); newNode = LogicalNotExpression(newNode.Parenthesize()); } else if (kind == SyntaxKind.NotEqualsExpression) { // Count() != 0 >>> Any() newNode = ChangeInvokedMethodName(invocationExpression, "Any"); } else if (kind == SyntaxKind.LessThanExpression) { if (invocationExpression == left) { // Count() < 1 >>> !Any() // Count() < i >>> !Skip(i - 1).Any() newNode = CreateNewExpression(invocationExpression, right, "1", subtract: true, negate: true); } else { // 0 < Count() >>> Any() // i < Count() >>> Skip(i).Any() newNode = CreateNewExpression(invocationExpression, left, "0"); } } else if (kind == SyntaxKind.LessThanOrEqualExpression) { if (invocationExpression == left) { // Count() <= 0 >>> !Any() // Count() <= i >>> !Skip(i).Any() newNode = CreateNewExpression(invocationExpression, right, "0", negate: true); } else { // 1 <= Count() >>> Any() // i <= Count() >>> Skip(i - 1).Any() newNode = CreateNewExpression(invocationExpression, left, "1", subtract: true); } } else if (kind == SyntaxKind.GreaterThanExpression) { if (invocationExpression == left) { // Count() > 0 >>> Any() // Count() > i >>> Skip(i).Any() newNode = CreateNewExpression(invocationExpression, right, "0"); } else { // 1 > Count() >>> !Any() // i > Count() >>> !Skip(i - 1).Any() newNode = CreateNewExpression(invocationExpression, left, "1", subtract: true, negate: true); } } else if (kind == SyntaxKind.GreaterThanOrEqualExpression) { if (invocationExpression == left) { // Count() >= 1 >>> Any() // Count() >= i >>> Skip(i - 1).Any() newNode = CreateNewExpression(invocationExpression, right, "1", subtract: true); } else { // 0 >= Count() >>> !Any() // i >= Count() >>> !Skip(i).Any() newNode = CreateNewExpression(invocationExpression, left, "0", negate: true); } } newNode = newNode .WithTriviaFrom(binaryExpression) .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken)); }
private static async Task <Document> RefactorAsync( Document document, StatementSyntax statement, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(statement); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(statement); switch (statement) { case IfStatementSyntax ifStatement: { var expressionStatement = (ExpressionStatementSyntax)ifStatement.SingleNonBlockStatementOrDefault(); var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression; ExpressionSyntax left = assignment.Left; ExpressionSyntax right = assignment.Right; BinaryExpressionSyntax coalesceExpression = CreateCoalesceExpression( left.WithoutLeadingTrivia().WithTrailingTrivia(Space), right.WithLeadingTrivia(Space), semanticModel.GetTypeSymbol(left, cancellationToken)); AssignmentExpressionSyntax newAssignment = assignment.WithRight(coalesceExpression.WithTriviaFrom(right)); ExpressionStatementSyntax newNode = expressionStatement.WithExpression(newAssignment); IEnumerable <SyntaxTrivia> trivia = ifStatement.DescendantTrivia(TextSpan.FromBounds(ifStatement.SpanStart, expressionStatement.SpanStart)); if (trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia())) { newNode = newNode.WithLeadingTrivia(ifStatement.GetLeadingTrivia()); } else { newNode = newNode .WithLeadingTrivia(ifStatement.GetLeadingTrivia().Concat(trivia)) .WithFormatterAnnotation(); } return(await document.ReplaceNodeAsync(ifStatement, newNode, cancellationToken).ConfigureAwait(false)); } case ExpressionStatementSyntax expressionStatement: { var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression; return(await RefactorAsync(document, expressionStatement, (IfStatementSyntax)statements[index + 1], index, statementsInfo, assignment.Right, semanticModel, cancellationToken).ConfigureAwait(false)); } case LocalDeclarationStatementSyntax localDeclaration: { ExpressionSyntax value = localDeclaration .Declaration .Variables[0] .Initializer .Value; return(await RefactorAsync(document, localDeclaration, (IfStatementSyntax)statements[index + 1], index, statementsInfo, value, semanticModel, cancellationToken).ConfigureAwait(false)); } default: { Debug.Fail(statement.Kind().ToString()); return(document); } } }