private static ExpressionSyntax caseExpression(SwitchLabelSyntax label, ExpressionSyntax control, out bool isDefault) { isDefault = label.Keyword.Kind() == SyntaxKind.DefaultKeyword; var caseLabel = label as CaseSwitchLabelSyntax; if (caseLabel != null) { var result = caseLabel.Value; if (result is BinaryExpressionSyntax) { var expr = result as BinaryExpressionSyntax; if (expr.Left.IsMissing) { return(CSharp.BinaryExpression(expr.Kind(), control, expr.Right)); } return(expr); } return(CSharp.BinaryExpression(SyntaxKind.EqualsExpression, control, result)); } Debug.Assert(isDefault); return(null); }
public int Compare(SwitchLabelSyntax x, SwitchLabelSyntax y) { if (object.ReferenceEquals(x, y)) { return(0); } if (x == null) { return(-1); } if (y == null) { return(1); } var label1 = (CaseSwitchLabelSyntax)x; var label2 = ((CaseSwitchLabelSyntax)y); string value1 = ((LiteralExpressionSyntax)label1.Value).Token.ValueText; string value2 = ((LiteralExpressionSyntax)label2.Value).Token.ValueText; return(StringComparer.CurrentCulture.Compare(value1, value2)); }
protected override IValue VisitCaseSwitchLabel(SwitchLabelSyntax node) { // todo: update throw new NotImplementedException(); //var value = Visit(node.Value); //return new CsharpSwichLabel(value, false); }
public static void AnalyzeSwitchSection(SyntaxNodeAnalysisContext context) { var switchSection = (SwitchSectionSyntax)context.Node; SyntaxList <SwitchLabelSyntax> labels = switchSection.Labels; int count = labels.Count; if (count <= 1) { return; } SwitchLabelSyntax lastLabel = labels.Last(); for (int i = 0; i < count - 1; i++) { SwitchLabelSyntax label = labels[i]; if (label.Kind() == SyntaxKind.DefaultSwitchLabel) { TextSpan span = TextSpan.FromBounds(label.Span.End, lastLabel.SpanStart); if (!switchSection.ContainsDirectives(span)) { context.ReportDiagnostic( DiagnosticDescriptors.DefaultLabelShouldBeLastLabelInSwitchSection, label); break; } } } }
static SwitchSectionSyntax CreateSection(SwitchLabelSyntax label, StatementSyntax statement) { var labels = new SyntaxList <SwitchLabelSyntax>(); labels = labels.Add(label); return(SyntaxFactory.SwitchSection(labels, CreateSectionStatements(statement))); }
public override SyntaxList <StatementSyntax> VisitSelectBlock(VBSyntax.SelectBlockSyntax node) { var expr = (ExpressionSyntax)node.SelectStatement.Expression.Accept(_nodesVisitor); var exprWithoutTrivia = expr.WithoutTrivia().WithoutAnnotations(); var sections = new List <SwitchSectionSyntax>(); foreach (var block in node.CaseBlocks) { var labels = new List <SwitchLabelSyntax>(); foreach (var c in block.CaseStatement.Cases) { if (c is VBSyntax.SimpleCaseClauseSyntax s) { var expressionSyntax = (ExpressionSyntax)s.Value.Accept(_nodesVisitor); SwitchLabelSyntax caseSwitchLabelSyntax = SyntaxFactory.CaseSwitchLabel(expressionSyntax); if (!_semanticModel.GetConstantValue(s.Value).HasValue) { caseSwitchLabelSyntax = WrapInCasePatternSwitchLabelSyntax(expressionSyntax); } labels.Add(caseSwitchLabelSyntax); } else if (c is VBSyntax.ElseCaseClauseSyntax) { labels.Add(SyntaxFactory.DefaultSwitchLabel()); } else if (c is VBSyntax.RelationalCaseClauseSyntax relational) { var operatorKind = VBasic.VisualBasicExtensions.Kind(relational); var cSharpSyntaxNode = SyntaxFactory.BinaryExpression(operatorKind.ConvertToken(TokenContext.Local), exprWithoutTrivia, (ExpressionSyntax)relational.Value.Accept(_nodesVisitor)); labels.Add(WrapInCasePatternSwitchLabelSyntax(cSharpSyntaxNode)); } else if (c is VBSyntax.RangeCaseClauseSyntax range) { var lowerBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, (ExpressionSyntax)range.LowerBound.Accept(_nodesVisitor), exprWithoutTrivia); var upperBoundCheck = SyntaxFactory.BinaryExpression(SyntaxKind.LessThanOrEqualExpression, exprWithoutTrivia, (ExpressionSyntax)range.UpperBound.Accept(_nodesVisitor)); var withinBounds = SyntaxFactory.BinaryExpression(SyntaxKind.LogicalAndExpression, lowerBoundCheck, upperBoundCheck); labels.Add(WrapInCasePatternSwitchLabelSyntax(withinBounds)); } else { throw new NotSupportedException(c.Kind().ToString()); } } var csBlockStatements = block.Statements.SelectMany(s => s.Accept(CommentConvertingVisitor)).ToList(); if (csBlockStatements.LastOrDefault() ?.IsKind(SyntaxKind.ReturnStatement) != true) { csBlockStatements.Add(SyntaxFactory.BreakStatement()); } var list = SingleStatement(SyntaxFactory.Block(csBlockStatements)); sections.Add(SyntaxFactory.SwitchSection(SyntaxFactory.List(labels), list)); } var switchStatementSyntax = SyntaxFactory.SwitchStatement(expr, SyntaxFactory.List(sections)); return(SingleStatement(switchStatementSyntax)); }
private static void AnalyzeSwitchSection(SyntaxNodeAnalysisContext context) { var switchSection = (SwitchSectionSyntax)context.Node; SwitchLabelSyntax label = switchSection.Labels.LastOrDefault(); if (label == null) { return; } StatementSyntax statement = switchSection.Statements.FirstOrDefault(); if (statement == null) { return; } if (!switchSection.SyntaxTree.IsSingleLineSpan(TextSpan.FromBounds(label.Span.End, statement.SpanStart))) { return; } DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.AddNewLineAfterSwitchLabel, Location.Create(statement.SyntaxTree, statement.Span.WithLength(0))); }
private static bool IsDefaultLabel(SyntaxNodeAnalysisContext context, SwitchLabelSyntax switchLabel) { switch (switchLabel.Kind()) { case SyntaxKind.DefaultSwitchLabel: return(true); case SyntaxKind.CasePatternSwitchLabel: { var casePatternSwitchLabel = (CasePatternSwitchLabelSyntax)switchLabel; var condition = casePatternSwitchLabel.WhenClause?.Condition; if (condition != null) { var constantValue = context.SemanticModel.GetConstantValue(condition, context.CancellationToken); return(constantValue.HasValue && constantValue.Value is bool boolValue && boolValue); } return(casePatternSwitchLabel.Pattern.IsKind(SyntaxKind.VarPattern)); } default: return(false); } }
public static bool IsDefaultSwitchLabel(SwitchLabelSyntax node) { // default: if (node.IsKind(SyntaxKind.DefaultSwitchLabel)) { return(true); } if (node.IsKind(SyntaxKind.CasePatternSwitchLabel, out CasePatternSwitchLabelSyntax? @case)) { // case _: if (@case.Pattern.IsKind(SyntaxKind.DiscardPattern)) { return(@case.WhenClause == null); } // case var _: // case var x: if (@case.Pattern.IsKind(SyntaxKind.VarPattern, out VarPatternSyntax? varPattern) && varPattern.Designation.IsKind(SyntaxKind.DiscardDesignation, SyntaxKind.SingleVariableDesignation)) { return(@case.WhenClause == null); } } return(false); }
private static async Task <Document> MoveDefaultLabelToLastPositionAsync( Document document, SwitchSectionSyntax switchSection, CancellationToken cancellationToken = default(CancellationToken)) { SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); SyntaxList <SwitchLabelSyntax> labels = switchSection.Labels; SwitchLabelSyntax defaultLabel = labels.First(f => f.IsKind(SyntaxKind.DefaultSwitchLabel)); int index = labels.IndexOf(defaultLabel); SwitchLabelSyntax lastLabel = labels.Last(); labels = labels.Replace(lastLabel, defaultLabel.WithTriviaFrom(lastLabel)); labels = labels.Replace(labels[index], lastLabel.WithTriviaFrom(defaultLabel)); SwitchSectionSyntax newSwitchSection = switchSection.WithLabels(labels); SyntaxNode newRoot = root.ReplaceNode(switchSection, newSwitchSection); return(document.WithSyntaxRoot(newRoot)); }
private static SwitchSectionSyntax CreateSection(SwitchLabelSyntax label, StatementSyntax statement) { var labels = new SyntaxList<SwitchLabelSyntax>(); labels = labels.Add(label); return SyntaxFactory.SwitchSection( labels, CreateSectionStatements(statement) ); }
public void TestConversionsNull() { var syntaxNode = default(SyntaxNode); var wrapper = (CasePatternSwitchLabelSyntaxWrapper)syntaxNode; SwitchLabelSyntax syntax = wrapper; Assert.Null(syntax); }
private static TextSpan?TryCreateSpanForSwitchLabel(SwitchLabelSyntax switchLabel, int position) { if (switchLabel.Parent is not SwitchSectionSyntax switchSection || switchSection.Statements.Count == 0) { return(null); } return(TryCreateSpanForNode(switchSection.Statements[0], position)); }
public void TestConversions() { var syntaxNode = this.CreateCasePatternSwitchLabel(); var wrapper = (CasePatternSwitchLabelSyntaxWrapper)syntaxNode; SwitchLabelSyntax syntax = wrapper; Assert.Same(syntaxNode, syntax); }
private static TextSpan? TryCreateSpanForSwitchLabel(SwitchLabelSyntax switchLabel, int position) { var switchSection = switchLabel.Parent as SwitchSectionSyntax; if (switchSection == null || switchSection.Statements.Count == 0) { return null; } return TryCreateSpanForNode(switchSection.Statements[0], position); }
private BoundPatternSwitchLabel BindPatternSwitchSectionLabel( Binder sectionBinder, BoundExpression boundSwitchExpression, SwitchLabelSyntax node, LabelSymbol label, ref BoundPatternSwitchLabel defaultLabel, DiagnosticBag diagnostics) { switch (node.Kind()) { case SyntaxKind.CaseSwitchLabel: { var caseLabelSyntax = (CaseSwitchLabelSyntax)node; bool wasExpression; var pattern = sectionBinder.BindConstantPattern( node, boundSwitchExpression, boundSwitchExpression.Type, caseLabelSyntax.Value, node.HasErrors, diagnostics, out wasExpression, wasSwitchCase: true); bool hasErrors = pattern.HasErrors; var constantValue = pattern.ConstantValue; if (!hasErrors && (object)constantValue != null && pattern.Value.Type == SwitchGoverningType && this.FindMatchingSwitchCaseLabel(constantValue, caseLabelSyntax) != label) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, pattern.ConstantValue.GetValueToDisplay() ?? label.Name); hasErrors = true; } return(new BoundPatternSwitchLabel(node, label, pattern, null, hasErrors)); } case SyntaxKind.DefaultSwitchLabel: { var defaultLabelSyntax = (DefaultSwitchLabelSyntax)node; var pattern = new BoundWildcardPattern(node); bool hasErrors = pattern.HasErrors; if (defaultLabel != null) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, label.Name); hasErrors = true; } // Note that this is semantically last! The caller will place it in the decision tree // in the final position. defaultLabel = new BoundPatternSwitchLabel(node, label, pattern, null, hasErrors); return(defaultLabel); } case SyntaxKind.CasePatternSwitchLabel: { var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node; var pattern = sectionBinder.BindPattern( matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics, wasSwitchCase: true); return(new BoundPatternSwitchLabel(node, label, pattern, matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null, node.HasErrors)); } default: throw ExceptionUtilities.UnexpectedValue(node); } }
public static string SwitchLabel(SwitchLabelSyntax label) { if (label.CaseOrDefaultKeyword.IsKind(SyntaxKind.CaseKeyword)) { return("case " + SyntaxNode(label.Value) + ":" + NewLine); } if (label.CaseOrDefaultKeyword.IsKind(SyntaxKind.DefaultKeyword)) { return("default:" + NewLine); } return(""); }
public static string SwitchLabel(SwitchLabelSyntax label) { if (label.CaseOrDefaultKeyword.IsKind(SyntaxKind.CaseKeyword)) { return "case " + SyntaxNode(label.Value) + ":" + NewLine; } if (label.CaseOrDefaultKeyword.IsKind(SyntaxKind.DefaultKeyword)) { return "default:" + NewLine; } return ""; }
public static void Write(this SwitchLabelSyntax syntax, IIndentedTextWriterWrapper textWriter, IContext context) { var caseSwitch = syntax as CaseSwitchLabelSyntax; if (caseSwitch != null) { caseSwitch.Write(textWriter, context); return; } var defaultSwitch = (DefaultSwitchLabelSyntax)syntax; defaultSwitch.Write(textWriter, context); }
public static Statement Create(Context cx, SwitchLabelSyntax node, Switch parent, int child) { switch (node.Kind()) { case SyntaxKind.CaseSwitchLabel: return(CaseLabel.Create(cx, (CaseSwitchLabelSyntax)node, parent, child)); case SyntaxKind.DefaultSwitchLabel: return(CaseDefault.Create(cx, (DefaultSwitchLabelSyntax)node, parent, child)); case SyntaxKind.CasePatternSwitchLabel: return(CasePattern.Create(cx, (CasePatternSwitchLabelSyntax)node, parent, child)); default: throw new InternalError(node, "Unhandled case label"); } }
private BoundSwitchLabel BindSwitchLabel(SwitchLabelSyntax syntax) { BoundExpression boundExpression; switch (syntax.Kind) { case SyntaxKind.CaseSwitchLabel: var caseSwitchLabel = (CaseSwitchLabelSyntax)syntax; boundExpression = Bind(caseSwitchLabel.Value, BindExpression); break; case SyntaxKind.DefaultSwitchLabel: boundExpression = null; break; default: throw new InvalidOperationException(); } return(new BoundSwitchLabel(boundExpression)); }
public static bool CanRefactor(SyntaxNodeAnalysisContext context, SwitchSectionSyntax switchSection) { SwitchLabelSyntax label = switchSection.Labels.LastOrDefault(); if (label != null) { ImmutableArray <Diagnostic> diagnostics = context.SemanticModel.GetDiagnostics(label.Span, context.CancellationToken); for (int i = 0; i < diagnostics.Length; i++) { switch (diagnostics[i].Id) { case "CS0163": case "CS8070": return(true); } } } return(false); }
public static void Analyze(SyntaxNodeAnalysisContext context, SwitchSectionSyntax switchSection) { SyntaxList <SwitchLabelSyntax> labels = switchSection.Labels; for (int i = 0; i < labels.Count - 1; i++) { SwitchLabelSyntax label = labels[i]; if (label.IsKind(SyntaxKind.DefaultSwitchLabel)) { TextSpan span = TextSpan.FromBounds(label.Span.End, labels.Last().Span.Start); if (!switchSection.ContainsDirectives(span)) { context.ReportDiagnostic( DiagnosticDescriptors.DefaultLabelShouldBeLastLabelInSwitchSection, label); } } } }
private static PatternSyntax GetPattern(SwitchLabelSyntax switchLabel, out WhenClauseSyntax whenClauseOpt) { switch (switchLabel.Kind()) { case SyntaxKind.CasePatternSwitchLabel: var node = (CasePatternSwitchLabelSyntax)switchLabel; whenClauseOpt = node.WhenClause; return(node.Pattern); case SyntaxKind.CaseSwitchLabel: whenClauseOpt = null; return(ConstantPattern(((CaseSwitchLabelSyntax)switchLabel).Value)); case SyntaxKind.DefaultSwitchLabel: whenClauseOpt = null; return(DiscardPattern()); case var value: throw ExceptionUtilities.UnexpectedValue(value); } }
public static async Task <Document> RefactorAsync( Document document, SwitchSectionSyntax switchSection, CancellationToken cancellationToken = default(CancellationToken)) { SyntaxList <SwitchLabelSyntax> labels = switchSection.Labels; SwitchLabelSyntax defaultLabel = labels.First(f => f.IsKind(SyntaxKind.DefaultSwitchLabel)); int index = labels.IndexOf(defaultLabel); SwitchLabelSyntax lastLabel = labels.Last(); labels = labels.Replace(lastLabel, defaultLabel.WithTriviaFrom(lastLabel)); labels = labels.Replace(labels[index], lastLabel.WithTriviaFrom(defaultLabel)); SwitchSectionSyntax newSwitchSection = switchSection.WithLabels(labels); return(await document.ReplaceNodeAsync(switchSection, newSwitchSection, cancellationToken).ConfigureAwait(false)); }
private static Task <Document> CopySwitchSectionAsync( Document document, SwitchSectionSyntax switchSection, bool insertNewLine, CancellationToken cancellationToken) { var switchStatement = (SwitchStatementSyntax)switchSection.Parent; SyntaxList <SwitchSectionSyntax> sections = switchStatement.Sections; int index = sections.IndexOf(switchSection); SwitchLabelSyntax label = switchSection.Labels[0]; SyntaxToken firstToken = label.GetFirstToken(); SyntaxToken newFirstToken = firstToken.WithNavigationAnnotation(); if (insertNewLine && !firstToken.LeadingTrivia.Contains(SyntaxKind.EndOfLineTrivia)) { newFirstToken = newFirstToken.PrependToLeadingTrivia(CSharpFactory.NewLine()); } SwitchSectionSyntax newSection = switchSection .WithLabels(switchSection.Labels.ReplaceAt(0, label.ReplaceToken(firstToken, newFirstToken))) .WithFormatterAnnotation(); if (index == sections.Count - 1) { newSection = newSection.TrimTrailingTrivia(); } SyntaxList <SwitchSectionSyntax> newSections = sections.Insert(index + 1, newSection); SwitchStatementSyntax newSwitchStatement = switchStatement.WithSections(newSections); return(document.ReplaceNodeAsync(switchStatement, newSwitchStatement, cancellationToken)); }
private static BoundPatternSwitchLabel BindPatternSwitchSectionLabel(Binder sectionBinder, BoundExpression boundSwitchExpression, SwitchLabelSyntax node, ref DefaultSwitchLabelSyntax defaultLabel, DiagnosticBag diagnostics) { switch (node.Kind()) { case SyntaxKind.CasePatternSwitchLabel: { var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node; var pattern = sectionBinder.BindPattern( matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics, wasSwitchCase: true); return new BoundPatternSwitchLabel(node, pattern, matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null, node.HasErrors); } case SyntaxKind.CaseSwitchLabel: { var caseLabelSyntax = (CaseSwitchLabelSyntax)node; bool wasExpression; var pattern = sectionBinder.BindConstantPattern( node, boundSwitchExpression, boundSwitchExpression.Type, caseLabelSyntax.Value, node.HasErrors, diagnostics, out wasExpression, wasSwitchCase: true); return new BoundPatternSwitchLabel(node, pattern, null, node.HasErrors); } case SyntaxKind.DefaultSwitchLabel: { var defaultLabelSyntax = (DefaultSwitchLabelSyntax)node; var pattern = new BoundWildcardPattern(node); if (defaultLabel != null) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, "default"); } defaultLabel = defaultLabelSyntax; return new BoundPatternSwitchLabel(node, pattern, null, node.HasErrors); // note that this is semantically last! } default: throw ExceptionUtilities.Unreachable; } }
private static ExpressionSyntax caseExpression(SwitchLabelSyntax label, ExpressionSyntax control, out bool isDefault) { isDefault = label.Keyword.Kind() == SyntaxKind.DefaultKeyword; var caseLabel = label as CaseSwitchLabelSyntax; if (caseLabel != null) { var result = caseLabel.Value; if (result is BinaryExpressionSyntax) { var expr = result as BinaryExpressionSyntax; if (expr.Left.IsMissing) return CSharp.BinaryExpression(expr.Kind(), control, expr.Right); return expr; } return CSharp.BinaryExpression(SyntaxKind.EqualsExpression, control, result); } Debug.Assert(isDefault); return null; }
public BoundSwitchLabel(SwitchLabelSyntax syntax, BoundExpression expression) : base(BoundNodeKind.SwitchLabel, syntax) { Expression = expression; }
private BoundSwitchLabel BindSwitchSectionLabel(SwitchLabelSyntax node, Binder sectionBinder, DiagnosticBag diagnostics) { var switchGoverningType = GetSwitchGoverningType(diagnostics); BoundExpression boundLabelExpressionOpt = null; SourceLabelSymbol boundLabelSymbol = null; ConstantValue labelExpressionConstant = null; List<SourceLabelSymbol> matchedLabelSymbols; // Prevent cascading diagnostics bool hasErrors = node.HasErrors; switch (node.Kind()) { case SyntaxKind.CaseSwitchLabel: var caseLabelSyntax = (CaseSwitchLabelSyntax)node; // Bind the label case expression boundLabelExpressionOpt = sectionBinder.BindValue(caseLabelSyntax.Value, diagnostics, BindValueKind.RValue); boundLabelExpressionOpt = ConvertCaseExpression(switchGoverningType, caseLabelSyntax, boundLabelExpressionOpt, sectionBinder, ref labelExpressionConstant, diagnostics); // Check for bind errors hasErrors = hasErrors || boundLabelExpressionOpt.HasAnyErrors; // SPEC: The constant expression of each case label must denote a value that // SPEC: is implicitly convertible (§6.1) to the governing type of the switch statement. // Prevent cascading diagnostics if (!hasErrors && labelExpressionConstant == null) { diagnostics.Add(ErrorCode.ERR_ConstantExpected, caseLabelSyntax.Location); hasErrors = true; } // LabelSymbols for all the switch case labels are created by BuildLabels(). // Fetch the matching switch case label symbols matchedLabelSymbols = FindMatchingSwitchCaseLabels(labelExpressionConstant, caseLabelSyntax); break; case SyntaxKind.CasePatternSwitchLabel: // pattern matching in case is not yet implemented. if (!node.HasErrors) { Error(diagnostics, ErrorCode.ERR_FeatureIsUnimplemented, node, MessageID.IDS_FeaturePatternMatching.Localize()); hasErrors = true; } matchedLabelSymbols = new List<SourceLabelSymbol>(); break; case SyntaxKind.DefaultSwitchLabel: matchedLabelSymbols = GetDefaultLabels(); break; default: throw ExceptionUtilities.Unreachable; } // Get the corresponding matching label symbol created during BuildLabels() // and also check for duplicate case labels. Debug.Assert(hasErrors || !matchedLabelSymbols.IsEmpty()); bool first = true; bool hasDuplicateErrors = false; foreach (SourceLabelSymbol label in matchedLabelSymbols) { if (node.Equals(label.IdentifierNodeOrToken.AsNode())) { // we must have exactly one matching label created during BuildLabels() boundLabelSymbol = label; // SPEC: A compile-time error occurs if two or more case labels // SPEC: in the same switch statement specify the same constant value. if (!hasErrors && !first) { // Skipping the first label symbol ensures that the errors (if any), // are reported on all but the first duplicate case label. diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, label.SwitchCaseLabelConstant?.Value ?? label.Name); hasDuplicateErrors = true; } break; } first = false; } if ((object)boundLabelSymbol == null) { Debug.Assert(hasErrors); boundLabelSymbol = new SourceLabelSymbol((MethodSymbol)this.ContainingMemberOrLambda, node, labelExpressionConstant); } return new BoundSwitchLabel( syntax: node, label: boundLabelSymbol, expressionOpt: boundLabelExpressionOpt, hasErrors: hasErrors || hasDuplicateErrors); }
public ILabelSymbol?ToSymbol(SwitchLabelSyntax node) => Model.GetDeclaredSymbol(node, CancellationToken);
public SwitchLabelTranslation(SwitchLabelSyntax syntax, SyntaxTranslation parent) : base(syntax, parent) { }
public static SwitchSectionSyntax Section(SwitchLabelSyntax label, params StatementSyntax[] statements) { return(SyntaxFactory.SwitchSection(SyntaxFactory.List(new[] { label }), SyntaxFactory.List(statements))); }
private BoundPatternSwitchLabel BindPatternSwitchSectionLabel( Binder sectionBinder, BoundExpression boundSwitchExpression, SwitchLabelSyntax node, LabelSymbol label, ref BoundPatternSwitchLabel defaultLabel, DiagnosticBag diagnostics) { switch (node.Kind()) { case SyntaxKind.CaseSwitchLabel: { var caseLabelSyntax = (CaseSwitchLabelSyntax)node; bool wasExpression; var pattern = sectionBinder.BindConstantPattern( node, boundSwitchExpression, boundSwitchExpression.Type, caseLabelSyntax.Value, node.HasErrors, diagnostics, out wasExpression, wasSwitchCase: true); bool hasErrors = pattern.HasErrors; var constantValue = pattern.ConstantValue; if (!hasErrors && (object)constantValue != null && this.FindMatchingSwitchCaseLabel(constantValue, caseLabelSyntax) != label) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, pattern.ConstantValue.GetValueToDisplay() ?? label.Name); hasErrors = true; } return new BoundPatternSwitchLabel(node, label, pattern, null, hasErrors); } case SyntaxKind.DefaultSwitchLabel: { var defaultLabelSyntax = (DefaultSwitchLabelSyntax)node; var pattern = new BoundWildcardPattern(node); bool hasErrors = pattern.HasErrors; if (defaultLabel != null) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, "default"); hasErrors = true; } // Note that this is semantically last! The caller will place it in the decision tree // in the final position. defaultLabel = new BoundPatternSwitchLabel(node, label, pattern, null, hasErrors); return defaultLabel; } case SyntaxKind.CasePatternSwitchLabel: { var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node; var pattern = sectionBinder.BindPattern( matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics, wasSwitchCase: true); return new BoundPatternSwitchLabel(node, label, pattern, matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null, node.HasErrors); } default: throw ExceptionUtilities.UnexpectedValue(node); } }
public SwitchLabelTranslation(SwitchLabelSyntax syntax, SyntaxTranslation parent) : base(syntax, parent) { }
private static SwitchSectionSyntax CreateSection(SwitchLabelSyntax label) { return(SwitchSection(label, BreakStatement()).WithFormatterAnnotation()); }
/// <summary> /// Given a switch label syntax, get the corresponding label symbol. /// </summary> /// <param name="declarationSyntax">The syntax node of the switch label.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The label symbol for that label.</returns> public abstract ILabelSymbol GetDeclaredSymbol(SwitchLabelSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken));
private BoundSwitchLabel BindSwitchSectionLabel(SwitchLabelSyntax node, Binder sectionBinder, LabelSymbol label, DiagnosticBag diagnostics) { var switchGoverningType = SwitchGoverningType; BoundExpression boundLabelExpressionOpt = null; ConstantValue labelExpressionConstant = null; // Prevent cascading diagnostics bool hasErrors = node.HasErrors; switch (node.Kind()) { case SyntaxKind.CaseSwitchLabel: var caseLabelSyntax = (CaseSwitchLabelSyntax)node; // Bind the label case expression boundLabelExpressionOpt = sectionBinder.BindValue(caseLabelSyntax.Value, diagnostics, BindValueKind.RValue); boundLabelExpressionOpt = ConvertCaseExpression(caseLabelSyntax, boundLabelExpressionOpt, sectionBinder, ref labelExpressionConstant, diagnostics); // Check for bind errors hasErrors = hasErrors || boundLabelExpressionOpt.HasAnyErrors; // SPEC: The constant expression of each case label must denote a value that // SPEC: is implicitly convertible (§6.1) to the governing type of the switch statement. if (!hasErrors && labelExpressionConstant == null) { diagnostics.Add(ErrorCode.ERR_ConstantExpected, caseLabelSyntax.Value.Location); hasErrors = true; } if (!hasErrors && (object)labelExpressionConstant != null && FindMatchingSwitchCaseLabel(labelExpressionConstant, caseLabelSyntax) != label) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, labelExpressionConstant?.GetValueToDisplay() ?? label.Name); hasErrors = true; } // LabelSymbols for all the switch case labels are created by BuildLabels(). // Fetch the matching switch case label symbols break; case SyntaxKind.CasePatternSwitchLabel: if (!node.HasErrors) { // This should not occur, because it would have been a syntax error throw ExceptionUtilities.UnexpectedValue(node.Kind()); } break; case SyntaxKind.DefaultSwitchLabel: if (GetDefaultLabel() != label) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, label.Name); hasErrors = true; } break; default: throw ExceptionUtilities.UnexpectedValue(node.Kind()); } return new BoundSwitchLabel( syntax: node, label: label, expressionOpt: boundLabelExpressionOpt, constantValueOpt: labelExpressionConstant, hasErrors: hasErrors); }
private IEnumerable<ITypeSymbol> InferTypeInSwitchLabel( SwitchLabelSyntax switchLabel, SyntaxToken? previousToken = null) { if (previousToken.HasValue) { if (previousToken.Value != switchLabel.Keyword || switchLabel.CSharpKind() != SyntaxKind.CaseSwitchLabel) { return SpecializedCollections.EmptyEnumerable<ITypeSymbol>(); } } var switchStatement = (SwitchStatementSyntax)switchLabel.Parent.Parent; return GetTypes(switchStatement.Expression); }
public void VisitSwitchLabel(SwitchLabelSyntax node) { if (node == null) throw new ArgumentNullException("node"); node.Validate(); _writer.WriteIndent(); switch (node.Kind) { case CaseOrDefault.Default: _writer.WriteKeyword(PrinterKeyword.Default); break; case CaseOrDefault.Case: _writer.WriteKeyword(PrinterKeyword.Case); _writer.WriteSpace(); node.Value.Accept(this); break; } if (_writer.Configuration.Spaces.Other.BeforeColonInCaseStatement) _writer.WriteSpace(); _writer.WriteSyntax(Syntax.Colon); }
private BoundSwitchLabel BindSwitchLabel(SwitchLabelSyntax syntax) { BoundExpression boundExpression; switch (syntax.Kind) { case SyntaxKind.CaseSwitchLabel: var caseSwitchLabel = (CaseSwitchLabelSyntax) syntax; boundExpression = Bind(caseSwitchLabel.Value, BindExpression); break; case SyntaxKind.DefaultSwitchLabel: boundExpression = null; break; default: throw new InvalidOperationException(); } return new BoundSwitchLabel(boundExpression); }
private BoundPatternSwitchLabel BindPatternSwitchSectionLabel( Binder sectionBinder, BoundExpression boundSwitchExpression, SwitchLabelSyntax node, LabelSymbol label, ref BoundPatternSwitchLabel defaultLabel, DiagnosticBag diagnostics) { switch (node.Kind()) { case SyntaxKind.CaseSwitchLabel: { var caseLabelSyntax = (CaseSwitchLabelSyntax)node; bool wasExpression; var pattern = sectionBinder.BindConstantPattern( node, boundSwitchExpression, boundSwitchExpression.Type, caseLabelSyntax.Value, node.HasErrors, diagnostics, out wasExpression, wasSwitchCase: true); bool hasErrors = pattern.HasErrors; var constantValue = pattern.ConstantValue; if (!hasErrors && (object)constantValue != null && pattern.Value.Type == SwitchGoverningType && this.FindMatchingSwitchCaseLabel(constantValue, caseLabelSyntax) != label) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, pattern.ConstantValue.GetValueToDisplay() ?? label.Name); hasErrors = true; } if (caseLabelSyntax.Value.Kind() == SyntaxKind.DefaultLiteralExpression) { diagnostics.Add(ErrorCode.WRN_DefaultInSwitch, caseLabelSyntax.Value.Location); } // Until we've determined whether or not the switch label is reachable, we assume it // is. The caller updates isReachable after determining if the label is subsumed. const bool isReachable = true; return(new BoundPatternSwitchLabel(node, label, pattern, null, isReachable, hasErrors)); } case SyntaxKind.DefaultSwitchLabel: { var defaultLabelSyntax = (DefaultSwitchLabelSyntax)node; var pattern = new BoundWildcardPattern(node); bool hasErrors = pattern.HasErrors; if (defaultLabel != null) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, label.Name); hasErrors = true; } // We always treat the default label as reachable, even if the switch is complete. const bool isReachable = true; // Note that this is semantically last! The caller will place it in the decision tree // in the final position. defaultLabel = new BoundPatternSwitchLabel(node, label, pattern, null, isReachable, hasErrors); return(defaultLabel); } case SyntaxKind.CasePatternSwitchLabel: { var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node; var pattern = sectionBinder.BindPattern( matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics, wasSwitchCase: true); return(new BoundPatternSwitchLabel(node, label, pattern, matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null, true, node.HasErrors)); } default: throw ExceptionUtilities.UnexpectedValue(node); } }
public override ILabelSymbol GetDeclaredSymbol(SwitchLabelSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { CheckSyntaxNode(declarationSyntax); var binder = this.GetEnclosingBinder(GetAdjustedNodePosition(declarationSyntax)); while (binder != null && !(binder is SwitchBinder)) { binder = binder.Next; } if (binder != null) { foreach (var label in binder.Labels) { if (label.IdentifierNodeOrToken.IsNode && label.IdentifierNodeOrToken.AsNode() == declarationSyntax) { return label; } } } return null; }
private BoundPatternSwitchLabel BindPatternSwitchSectionLabel( Binder sectionBinder, BoundExpression boundSwitchExpression, SwitchLabelSyntax node, LabelSymbol label, ref BoundPatternSwitchLabel defaultLabel, DiagnosticBag diagnostics) { switch (node.Kind()) { case SyntaxKind.CaseSwitchLabel: { var caseLabelSyntax = (CaseSwitchLabelSyntax)node; bool wasExpression; var pattern = sectionBinder.BindConstantPattern( node, boundSwitchExpression, boundSwitchExpression.Type, caseLabelSyntax.Value, node.HasErrors, diagnostics, out wasExpression, wasSwitchCase: true); bool hasErrors = pattern.HasErrors; var constantValue = pattern.ConstantValue; if (!hasErrors && (object)constantValue != null && pattern.Value.Type == SwitchGoverningType && this.FindMatchingSwitchCaseLabel(constantValue, caseLabelSyntax) != label) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, pattern.ConstantValue.GetValueToDisplay() ?? label.Name); hasErrors = true; } // Until we've determined whether or not the switch label is reachable, we assume it // is. The caller updates isReachable after determining if the label is subsumed. const bool isReachable = true; return new BoundPatternSwitchLabel(node, label, pattern, null, isReachable, hasErrors); } case SyntaxKind.DefaultSwitchLabel: { var defaultLabelSyntax = (DefaultSwitchLabelSyntax)node; var pattern = new BoundWildcardPattern(node); bool hasErrors = pattern.HasErrors; if (defaultLabel != null) { diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, label.Name); hasErrors = true; } // We always treat the default label as reachable, even if the switch is complete. const bool isReachable = true; // Note that this is semantically last! The caller will place it in the decision tree // in the final position. defaultLabel = new BoundPatternSwitchLabel(node, label, pattern, null, isReachable, hasErrors); return defaultLabel; } case SyntaxKind.CasePatternSwitchLabel: { var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node; var pattern = sectionBinder.BindPattern( matchLabelSyntax.Pattern, boundSwitchExpression, boundSwitchExpression.Type, node.HasErrors, diagnostics, wasSwitchCase: true); return new BoundPatternSwitchLabel(node, label, pattern, matchLabelSyntax.WhenClause != null ? sectionBinder.BindBooleanExpression(matchLabelSyntax.WhenClause.Condition, diagnostics) : null, true, node.HasErrors); } default: throw ExceptionUtilities.UnexpectedValue(node); } }
/// <summary> /// Given a switch label syntax, get the corresponding label symbol. /// </summary> /// <param name="declarationSyntax">The syntax node of the switch label.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The label symbol for that label.</returns> public override ILabelSymbol GetDeclaredSymbol(SwitchLabelSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { using (Logger.LogBlock(FunctionId.CSharp_SemanticModel_GetDeclaredSymbol, message: this.SyntaxTree.FilePath, cancellationToken: cancellationToken)) { CheckSyntaxNode(declarationSyntax); var memberModel = this.GetMemberModel(declarationSyntax); return memberModel == null ? null : memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); } }
public static SwitchSectionSyntax Section(SwitchLabelSyntax label, params StatementSyntax[] statements) { return SyntaxFactory.SwitchSection(SyntaxFactory.List(new[] { label }), SyntaxFactory.List(statements)); }
private BoundSwitchLabel BindSwitchSectionLabel(SwitchLabelSyntax node, DiagnosticBag diagnostics) { var switchGoverningType = GetSwitchGoverningType(diagnostics); BoundExpression boundLabelExpressionOpt = null; SourceLabelSymbol boundLabelSymbol = null; ConstantValue labelExpressionConstant = null; List<SourceLabelSymbol> matchedLabelSymbols; // Prevent cascading diagnostics bool hasErrors = node.HasErrors; if (node.Value != null) { Debug.Assert(node.Kind == SyntaxKind.CaseSwitchLabel); // Bind the label case expression boundLabelExpressionOpt = BindValue(node.Value, diagnostics, BindValueKind.RValue); boundLabelExpressionOpt = ConvertCaseExpression(switchGoverningType, node, boundLabelExpressionOpt, ref labelExpressionConstant, diagnostics); // Check for bind errors hasErrors = hasErrors || boundLabelExpressionOpt.HasAnyErrors; // SPEC: The constant expression of each case label must denote a value that // SPEC: is implicitly convertible (§6.1) to the governing type of the switch statement. // Prevent cascading diagnostics if (!hasErrors && labelExpressionConstant == null) { diagnostics.Add(ErrorCode.ERR_ConstantExpected, node.Location); hasErrors = true; } // LabelSymbols for all the switch case labels are created by BuildLabels(). // Fetch the matching switch case label symbols matchedLabelSymbols = FindMatchingSwitchCaseLabels(labelExpressionConstant, node); } else { Debug.Assert(node.Kind == SyntaxKind.DefaultSwitchLabel); matchedLabelSymbols = GetDefaultLabels(); } // Get the corresponding matching label symbol created during BuildLabels() // and also check for duplicate case labels. Debug.Assert(!matchedLabelSymbols.IsEmpty()); bool first = true; bool hasDuplicateErrors = false; foreach (SourceLabelSymbol label in matchedLabelSymbols) { if (node.Equals(label.IdentifierNodeOrToken.AsNode())) { // we must have exactly one matching label created during BuildLabels() boundLabelSymbol = label; // SPEC: A compile-time error occurs if two or more case labels // SPEC: in the same switch statement specify the same constant value. if (!hasErrors && !first) { // Skipping the first label symbol ensures that the errors (if any), // are reported on all but the first duplicate case label. diagnostics.Add(ErrorCode.ERR_DuplicateCaseLabel, node.Location, label.SwitchCaseLabelConstant == null ? label.Name : label.SwitchCaseLabelConstant.Value); hasDuplicateErrors = true; } break; } first = false; } if ((object)boundLabelSymbol == null) { Debug.Assert(hasErrors); boundLabelSymbol = new SourceLabelSymbol(this.Owner, node, labelExpressionConstant); } return new BoundSwitchLabel( syntax: node, label: boundLabelSymbol, expressionOpt: boundLabelExpressionOpt, hasErrors: hasErrors || hasDuplicateErrors); }
/// <summary> /// Given a switch label syntax, get the corresponding label symbol. /// </summary> /// <param name="declarationSyntax">The syntax node of the switch label.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The label symbol for that label.</returns> public override ILabelSymbol GetDeclaredSymbol(SwitchLabelSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken)) { CheckSyntaxNode(declarationSyntax); var memberModel = this.GetMemberModel(declarationSyntax); return memberModel == null ? null : memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken); }
private static void AnalyzeSwitchStatement(SyntaxNodeAnalysisContext context) { var switchStatement = (SwitchStatementSyntax)context.Node; SyntaxList <SwitchSectionSyntax> sections = switchStatement.Sections; if (!sections.Any()) { return; } ExpressionSyntax switchExpression = switchStatement.Expression; SingleLocalDeclarationStatementInfo localInfo = default; string name = GetName(); if (name == null) { return; } ITypeSymbol kindSymbol = context.SemanticModel.GetTypeSymbol(switchExpression, context.CancellationToken); if (kindSymbol?.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_CSharp_SyntaxKind) != true) { return; } foreach (SwitchSectionSyntax section in sections) { SwitchLabelSyntax label = section.Labels.SingleOrDefault(shouldThrow: false); if (label == null) { return; } SyntaxKind labelKind = label.Kind(); if (labelKind == SyntaxKind.DefaultSwitchLabel) { continue; } if (labelKind != SyntaxKind.CaseSwitchLabel) { Debug.Assert(labelKind == SyntaxKind.CasePatternSwitchLabel, labelKind.ToString()); return; } var caseLabel = (CaseSwitchLabelSyntax)label; ExpressionSyntax value = caseLabel.Value; if (!value.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { return; } var memberAccess = (MemberAccessExpressionSyntax)value; if (memberAccess.Name is not IdentifierNameSyntax identifierName) { return; } string kindName = identifierName.Identifier.ValueText; if (!_syntaxKindNames.Contains(kindName)) { return; } SyntaxList <StatementSyntax> statements = section.Statements; StatementSyntax statement = statements.FirstOrDefault(); if (statement == null) { return; } if (statement is BlockSyntax block) { statement = block.Statements.FirstOrDefault(); } if (!statement.IsKind(SyntaxKind.LocalDeclarationStatement)) { return; } SingleLocalDeclarationStatementInfo localStatement = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement); if (!localStatement.Success) { return; } if (localStatement.Value is not CastExpressionSyntax castExpression) { return; } if (castExpression.Expression is not IdentifierNameSyntax localName) { return; } if (name != localName.Identifier.ValueText) { return; } if (!IsFixableSyntaxSymbol(castExpression.Type, kindName, context.SemanticModel, context.CancellationToken)) { return; } } if (localInfo.Success && IsLocalVariableReferenced(context, localInfo, switchStatement)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UsePatternMatching, switchStatement.SwitchKeyword); string GetName() { switch (switchExpression.Kind()) { case SyntaxKind.IdentifierName: { StatementSyntax previousStatement = switchStatement.PreviousStatement(); if (!previousStatement.IsKind(SyntaxKind.LocalDeclarationStatement)) { return(null); } localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)previousStatement); if (!localInfo.Success) { return(null); } if (localInfo.IdentifierText != ((IdentifierNameSyntax)switchExpression).Identifier.ValueText) { return(null); } if (!localInfo.Value.IsKind(SyntaxKind.InvocationExpression)) { return(null); } return(GetName2((InvocationExpressionSyntax)localInfo.Value)); } case SyntaxKind.InvocationExpression: { return(GetName2((InvocationExpressionSyntax)switchExpression)); } default: { return(null); } } }