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))); }
public override void VisitIsPatternExpression(IsPatternExpressionSyntax node) { if (!PreVisit(node)) { return; } node.Pattern?.Accept(this); node.Expression?.Accept(this); base.VisitIsPatternExpression(node); PostVisit(node); }
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())); }
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)); }
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; }
//public override void VisitInvocationExpression(InvocationExpressionSyntax node) //{ // base.VisitInvocationExpression(node); //} public override void VisitIsPatternExpression(IsPatternExpressionSyntax node) { Visit(node.Expression); //base.VisitIsPatternExpression(node); }
/// <inheritdoc /> public override void VisitIsPatternExpression(IsPatternExpressionSyntax node) { if (NullCheck.IsNullCheck(node, default, default, out _))
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 !")); }
// 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)); }
public static void ComputeRefactoring(RefactoringContext context, IsPatternExpressionSyntax isPatternExpression) { ComputeRefactoringCore(context, isPatternExpression); }
public override void VisitIsPatternExpression(IsPatternExpressionSyntax node) { this.VisitExpression(node); }
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); }
public override void VisitIsPatternExpression(IsPatternExpressionSyntax node) => base.VisitIsPatternExpression(node);
public override void VisitIsPatternExpression(IsPatternExpressionSyntax node) { }
public TameIsPatternExpressionSyntax(IsPatternExpressionSyntax node) { Node = node; AddChildren(); }
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);