Example #1
0
 private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node, DiagnosticBag diagnostics)
 {
     var expression = BindExpression(node.Expression, diagnostics);
     var hasErrors = node.HasErrors || IsOperandErrors(node, expression, diagnostics);
     var pattern = BindPattern(node.Pattern, expression, expression.Type, hasErrors, diagnostics);
     return new BoundIsPatternExpression(
         node, expression, pattern, GetSpecialType(SpecialType.System_Boolean, diagnostics, node), hasErrors);
 }
        private static IfStatementSyntax GetUpdatedIfStatement(
            IsPatternExpressionSyntax updatedCondition,
            ImmutableArray <SyntaxTrivia> trivia,
            IfStatementSyntax originalIf,
            IfStatementSyntax currentIf)
        {
            var newIf = currentIf.ReplaceNode(currentIf.Condition, updatedCondition);

            newIf = originalIf.IsParentKind(SyntaxKind.ElseClause)
                ? newIf.ReplaceToken(newIf.CloseParenToken, newIf.CloseParenToken.WithTrailingTrivia(trivia))
                : newIf.WithPrependedLeadingTrivia(trivia);

            return(newIf.WithAdditionalAnnotations(Formatter.Annotation));
        }
        private VariableDeclaratorSyntax ConvertToVariableDeclarator(IsPatternExpressionSyntax node)
        {
            return(node.Pattern.TypeSwitch(
                       (DeclarationPatternSyntax d) => {
                var id = ((IdentifierNameSyntax)d.Designation.Accept(_nodesVisitor)).Identifier;
                var ids = SyntaxFactory.SingletonSeparatedList(SyntaxFactory.ModifiedIdentifier(id));
                TypeSyntax right = (TypeSyntax)d.Type.Accept(_nodesVisitor);

                var simpleAsClauseSyntax = SyntaxFactory.SimpleAsClause(right);
                var equalsValueSyntax = SyntaxFactory.EqualsValue(SyntaxFactory.LiteralExpression(SyntaxKind.NothingLiteralExpression, SyntaxFactory.Token(SyntaxKind.NothingKeyword)));
                return SyntaxFactory.VariableDeclarator(ids, simpleAsClauseSyntax, equalsValueSyntax);
            },
                       p => throw new ArgumentOutOfRangeException(nameof(p), p, null)));
        }
Example #4
0
        public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
        {
            if (!PreVisit(node))
            {
                return;
            }

            node.Pattern?.Accept(this);
            node.Expression?.Accept(this);

            base.VisitIsPatternExpression(node);

            PostVisit(node);
        }
Example #5
0
        private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node, DiagnosticBag diagnostics)
        {
            var expression = BindValue(node.Expression, diagnostics, BindValueKind.RValue);
            var hasErrors = IsOperandErrors(node, ref expression, diagnostics);
            var expressionType = expression.Type;
            if ((object)expressionType == null)
            {
                expressionType = CreateErrorType();
                if (!hasErrors)
                {
                    // value expected
                    diagnostics.Add(ErrorCode.ERR_BadIsPatternExpression, node.Expression.Location, expression.Display);
                    hasErrors = true;
                }
            }

            var pattern = BindPattern(node.Pattern, expression, expressionType, hasErrors, diagnostics);
            return new BoundIsPatternExpression(
                node, expression, pattern, GetSpecialType(SpecialType.System_Boolean, diagnostics, node), hasErrors);
        }
        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.GetSyntaxRootAsync(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()));
        }
Example #7
0
        private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node, DiagnosticBag diagnostics)
        {
            var expression     = BindValue(node.Expression, diagnostics, BindValueKind.RValue);
            var hasErrors      = IsOperandErrors(node, ref expression, diagnostics);
            var expressionType = expression.Type;

            if ((object)expressionType == null)
            {
                expressionType = CreateErrorType();
                if (!hasErrors)
                {
                    // value expected
                    diagnostics.Add(ErrorCode.ERR_BadIsPatternExpression, node.Expression.Location, expression.Display);
                    hasErrors = true;
                }
            }

            var pattern = BindPattern(node.Pattern, expression, expressionType, hasErrors, diagnostics);

            return(new BoundIsPatternExpression(
                       node, expression, pattern, GetSpecialType(SpecialType.System_Boolean, diagnostics, node), hasErrors));
        }
        private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
        {
            var node = context.Node;
            var left = node switch
            {
                BinaryExpressionSyntax binary => binary.Left,
                IsPatternExpressionSyntax isPattern => isPattern.Expression,
                _ => throw ExceptionUtilities.UnexpectedValue(node),
            };

            if (left.Kind() != SyntaxKind.SuppressNullableWarningExpression)
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticHelper.Create(
                                         Descriptor,
                                         ((PostfixUnaryExpressionSyntax)left).OperatorToken.GetLocation(),
                                         ReportDiagnostic.Warn,
                                         ImmutableArray.Create(node.GetLocation()),
                                         properties: null));
        }
Example #9
0
            public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
            {
                base.VisitIsPatternExpression(node);

                var declaration = node.Pattern as DeclarationPatternSyntax;

                if (declaration == null)
                {
                    return;
                }

                if (declaration.Designation is SingleVariableDesignationSyntax variableDesignation)
                {
                    var symbol = model.GetDeclaredSymbol(variableDesignation);
                    if (symbol != null)
                    {
                        // variables declared in patterns are never null
                        var item = new Assignment(symbol, node.Expression, ValueType.NotNull);
                        Assignments.Add(item);
                    }
                }
            }
            private IEnumerable<TypeInferenceInfo> InferTypeInIsPatternExpression(
                IsPatternExpressionSyntax isPatternExpression,
                ExpressionSyntax expression)
            {
                if (expression == isPatternExpression.Expression)
                {
                    return GetPatternTypes(isPatternExpression.Pattern);
                }

                return null;
            }
Example #11
0
        //public override void VisitInvocationExpression(InvocationExpressionSyntax node)
        //{
        //    base.VisitInvocationExpression(node);
        //}

        public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
        {
            Visit(node.Expression);
            //base.VisitIsPatternExpression(node);
        }
Example #12
0
 /// <inheritdoc />
 public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
 {
     if (NullCheck.IsNullCheck(node, default, default, out _))
Example #13
0
 public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
 {
     throw new NotImplementedException();
 }
 public override SyntaxNode VisitIsPatternExpression(IsPatternExpressionSyntax node)
 {
     //不支持的语法
     return(ReportAndAttachError(base.VisitIsPatternExpression(node), "[Cs2LuaRewriter] Unsupported 'is pattern' Syntax !"));
 }
Example #15
0
 // is表达式
 public virtual void VisitIsPatternExpressionSyntax(IsPatternExpressionSyntax value)
 {
     DefaultVisit(value);
 }
        private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
        {
            var node       = syntaxContext.Node;
            var syntaxTree = node.SyntaxTree;

            // "x is Type y" is only available in C# 7.0 and above. Don't offer this refactoring
            // in projects targeting a lesser version.
            if (((CSharpParseOptions)syntaxTree.Options).LanguageVersion < LanguageVersion.CSharp7)
            {
                return;
            }

            var options           = syntaxContext.Options;
            var cancellationToken = syntaxContext.CancellationToken;

            var styleOption = options.GetOption(CSharpCodeStyleOptions.PreferPatternMatchingOverAsWithNullCheck, syntaxTree, cancellationToken);

            if (!styleOption.Value)
            {
                // Bail immediately if the user has disabled this feature.
                return;
            }

            var comparison = (ExpressionSyntax)node;

            var(comparisonLeft, comparisonRight) = comparison switch
            {
                BinaryExpressionSyntax binaryExpression => (binaryExpression.Left, (SyntaxNode)binaryExpression.Right),
                IsPatternExpressionSyntax isPattern => (isPattern.Expression, isPattern.Pattern),
                _ => throw ExceptionUtilities.Unreachable,
            };
            var operand = GetNullCheckOperand(comparisonLeft, comparison.Kind(), comparisonRight)?.WalkDownParentheses();
            if (operand == null)
            {
                return;
            }

            var semanticModel = syntaxContext.SemanticModel;

            if (operand.IsKind(SyntaxKind.CastExpression, out CastExpressionSyntax? castExpression))
            {
                // Unwrap object cast
                var castType = semanticModel.GetTypeInfo(castExpression.Type).Type;
                if (castType?.SpecialType == SpecialType.System_Object)
                {
                    operand = castExpression.Expression;
                }
            }

            if (semanticModel.GetSymbolInfo(comparison, cancellationToken).GetAnySymbol().IsUserDefinedOperator())
            {
                return;
            }

            if (!TryGetTypeCheckParts(semanticModel, operand,
                                      out var declarator,
                                      out var asExpression,
                                      out var localSymbol))
            {
                return;
            }

            var localStatement = declarator.Parent?.Parent;
            var enclosingBlock = localStatement?.Parent;

            if (localStatement == null ||
                enclosingBlock == null)
            {
                return;
            }

            // Don't convert if the as is part of a using statement
            // eg using (var x = y as MyObject) { }
            if (localStatement is UsingStatementSyntax)
            {
                return;
            }

            // Don't convert if the as is part of a local declaration with a using keyword
            // eg using var x = y as MyObject;
            if (localStatement is LocalDeclarationStatementSyntax localDecl && localDecl.UsingKeyword != default)
            {
                return;
            }

            var typeNode = asExpression.Right;
            var asType   = semanticModel.GetTypeInfo(typeNode, cancellationToken).Type;

            if (asType.IsNullable())
            {
                // Not legal to write "x is int? y"
                return;
            }

            if (asType?.TypeKind == TypeKind.Dynamic)
            {
                // Not legal to use dynamic in a pattern.
                return;
            }

            if (!localSymbol.Type.Equals(asType))
            {
                // We have something like:
                //
                //      BaseType b = x as DerivedType;
                //      if (b != null) { ... }
                //
                // It's not necessarily safe to convert this to:
                //
                //      if (x is DerivedType b) { ... }
                //
                // That's because there may be later code that wants to do something like assign a
                // 'BaseType' into 'b'.  As we've now claimed that it must be DerivedType, that
                // won't work.  This might also cause unintended changes like changing overload
                // resolution.  So, we conservatively do not offer the change in a situation like this.
                return;
            }

            // Check if the as operand is ever written up to the point of null check.
            //
            //      var s = field as string;
            //      field = null;
            //      if (s != null) { ... }
            //
            // It's no longer safe to use pattern-matching because 'field is string s' would never be true.
            //
            // Additionally, also bail out if the assigned local is referenced (i.e. read/write/nameof) up to the point of null check.
            //      var s = field as string;
            //      MethodCall(flag: s == null);
            //      if (s != null) { ... }
            //
            var asOperand           = semanticModel.GetSymbolInfo(asExpression.Left, cancellationToken).Symbol;
            var localStatementStart = localStatement.SpanStart;
            var comparisonSpanStart = comparison.SpanStart;

            foreach (var descendentNode in enclosingBlock.DescendantNodes())
            {
                var descendentNodeSpanStart = descendentNode.SpanStart;
                if (descendentNodeSpanStart <= localStatementStart)
                {
                    continue;
                }

                if (descendentNodeSpanStart >= comparisonSpanStart)
                {
                    break;
                }

                if (descendentNode.IsKind(SyntaxKind.IdentifierName, out IdentifierNameSyntax? identifierName))
                {
                    // Check if this is a 'write' to the asOperand.
                    if (identifierName.Identifier.ValueText == asOperand?.Name &&
                        asOperand.Equals(semanticModel.GetSymbolInfo(identifierName, cancellationToken).Symbol) &&
                        identifierName.IsWrittenTo())
                    {
                        return;
                    }

                    // Check is a reference of any sort (i.e. read/write/nameof) to the local.
                    if (identifierName.Identifier.ValueText == localSymbol.Name)
                    {
                        return;
                    }
                }
            }

            if (!Analyzer.CanSafelyConvertToPatternMatching(
                    semanticModel, localSymbol, comparison, operand,
                    localStatement, enclosingBlock, cancellationToken))
            {
                return;
            }

            // Looks good!
            var additionalLocations = ImmutableArray.Create(
                declarator.GetLocation(),
                comparison.GetLocation(),
                asExpression.GetLocation());

            // Put a diagnostic with the appropriate severity on the declaration-statement itself.
            syntaxContext.ReportDiagnostic(DiagnosticHelper.Create(
                                               Descriptor,
                                               localStatement.GetLocation(),
                                               styleOption.Notification.Severity,
                                               additionalLocations,
                                               properties: null));
        }
Example #17
0
 public static void ComputeRefactoring(RefactoringContext context, IsPatternExpressionSyntax isPatternExpression)
 {
     ComputeRefactoringCore(context, isPatternExpression);
 }
Example #18
0
 public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
 {
     this.VisitExpression(node);
 }
Example #19
0
 public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
 {
     LogUnsupportedSyntax(node);
 }
 public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
 {
     this.HandleAssignedValue(node.Pattern, node.Expression);
     base.VisitIsPatternExpression(node);
 }
 public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
 {
     this.isPatterns.Add(node);
     base.VisitIsPatternExpression(node);
 }
Example #22
0
 public override void VisitIsPatternExpression(IsPatternExpressionSyntax node) => base.VisitIsPatternExpression(node);
 public override void VisitIsPatternExpression(IsPatternExpressionSyntax node)
 {
 }
Example #24
0
 public TameIsPatternExpressionSyntax(IsPatternExpressionSyntax node)
 {
     Node = node;
     AddChildren();
 }
Example #25
0
 public IsPatternStatementInterpreter(StatementInterpreterHandler statementInterpreterHandler, IsPatternExpressionSyntax patternExpressionSyntax)
 {
     this.statementInterpreterHandler = statementInterpreterHandler;
     this.patternExpressionSyntax     = patternExpressionSyntax;
 }
        private static async Task <Document> UsePatternMatchingAsync(
            Document document,
            IfStatementSyntax ifStatement,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            IsKindExpressionInfo isKindExpression = IsKindExpressionInfo.Create(ifStatement.Condition, semanticModel, cancellationToken: cancellationToken);

            switch (isKindExpression.Style)
            {
            case IsKindExpressionStyle.IsKind:
            case IsKindExpressionStyle.IsKindConditional:
            case IsKindExpressionStyle.Kind:
            case IsKindExpressionStyle.KindConditional:
            {
                var block = (BlockSyntax)ifStatement.Statement;

                IsPatternExpressionSyntax isPatternExpression = CreateIsPatternExpression(block.Statements[0]);

                BlockSyntax newBlock = block.WithStatements(block.Statements.RemoveAt(0));

                IfStatementSyntax newIfStatement = ifStatement.Update(
                    ifStatement.IfKeyword,
                    ifStatement.OpenParenToken,
                    isPatternExpression,
                    ifStatement.CloseParenToken,
                    newBlock,
                    ifStatement.Else);

                newIfStatement = newIfStatement.WithFormatterAnnotation();

                return(await document.ReplaceNodeAsync(ifStatement, newIfStatement, cancellationToken).ConfigureAwait(false));
            }

            case IsKindExpressionStyle.NotIsKind:
            case IsKindExpressionStyle.NotIsKindConditional:
            case IsKindExpressionStyle.NotKind:
            case IsKindExpressionStyle.NotKindConditional:
            {
                StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement);

                SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

                int index = statements.IndexOf(ifStatement);

                IsPatternExpressionSyntax isPatternExpression = CreateIsPatternExpression(statements[index + 1]);

                IfStatementSyntax newIfStatement = ifStatement.WithCondition(LogicalNotExpression(isPatternExpression.Parenthesize()).WithTriviaFrom(ifStatement.Condition));

                SyntaxList <StatementSyntax> newStatements = statements
                                                             .ReplaceAt(index, newIfStatement)
                                                             .RemoveAt(index + 1);

                return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false));
            }

            default:
            {
                throw new InvalidOperationException();
            }
            }

            IsPatternExpressionSyntax CreateIsPatternExpression(StatementSyntax statement)
            {
                SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement);

                var castExpression = (CastExpressionSyntax)localInfo.Value;

                return(IsPatternExpression(
                           isKindExpression.Expression,
                           DeclarationPattern(castExpression.Type, SingleVariableDesignation(localInfo.Identifier))));
            }
        }
 //
 // Summary:
 //     Called when the visitor visits a IsPatternExpressionSyntax node.
 public virtual void VisitIsPatternExpression(IsPatternExpressionSyntax node);