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; } } } }
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 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 of kind {node.Kind()}"); } }
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); } }
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); } }
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 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 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 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); } }
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); } }
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); }
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); } }
private IEnumerable<ITypeSymbol> InferTypeInSwitchLabel( SwitchLabelSyntax switchLabel, SyntaxToken? previousToken = null) { if (previousToken.HasValue) { if (previousToken.Value != switchLabel.Keyword || switchLabel.Kind() != SyntaxKind.CaseSwitchLabel) { return SpecializedCollections.EmptyEnumerable<ITypeSymbol>(); } } var switchStatement = (SwitchStatementSyntax)switchLabel.Parent.Parent; return GetTypes(switchStatement.Expression); }
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); } } }