public ICollection <ISymbol> TryGetSymbolsForCaseClauses([NotNull] SwitchAnalysisContext analysisContext) { IEnumerable <ISingleValueCaseClauseOperation> caseClauses = analysisContext.SwitchStatement.Cases.SelectMany(@case => @case.Clauses.OfType <ISingleValueCaseClauseOperation>()); foreach (ISingleValueCaseClauseOperation caseClause in caseClauses) { analysisContext.CancellationToken.ThrowIfCancellationRequested(); if (ProcessAsLiteralSyntax(analysisContext, caseClause) || ProcessAsField(caseClause) || ProcessAsConversion(analysisContext, caseClause)) { continue; } #pragma warning disable AV2310 // Code blocks should not contain inline comments // Switch statements with non-constant case expressions are not supported // because they make completion analysis non-trivial. #pragma warning restore AV2310 // Code blocks should not contain inline comments return(null); } return(caseClauseValues); }
public ICollection <ISymbol> TryGetSymbolsForCaseClauses([NotNull] SwitchAnalysisContext analysisContext) { IEnumerable <ISingleValueCaseClauseOperation> caseClauses = analysisContext.SwitchStatement.Cases.SelectMany(@case => @case.Clauses.OfType <ISingleValueCaseClauseOperation>()); foreach (ISingleValueCaseClauseOperation caseClause in caseClauses) { analysisContext.CancellationToken.ThrowIfCancellationRequested(); if (ProcessAsLiteralSyntax(analysisContext, caseClause) || ProcessAsField(caseClause) || ProcessAsConversion(analysisContext, caseClause)) { continue; } // Switch statements with non-constant case expressions are not supported // because they make exhaustiveness analysis non-trivial. #pragma warning disable AV1135 // Do not return null for strings, collections or tasks return(null); #pragma warning restore AV1135 // Do not return null for strings, collections or tasks } return(caseClauseValues); }
private bool?HasCaseClausesFor([NotNull][ItemCanBeNull] ICollection <ISymbol> expectedValues, [NotNull] SwitchAnalysisContext analysisContext) { var collector = new CaseClauseCollector(); ICollection <ISymbol> caseClauseValues = collector.TryGetSymbolsForCaseClauses(analysisContext); return(caseClauseValues == null ? null : HasCaseClauseForExpectedValues(expectedValues, caseClauseValues)); }
private bool ProcessLiteralSyntaxAsFalseKeyword([NotNull] SwitchAnalysisContext analysisContext, [NotNull] LiteralExpressionSyntax literalSyntax) { if (literalSyntax.Token.IsKind(SyntaxKind.FalseKeyword)) { caseClauseValues.Add(analysisContext.BooleanFalse); return(true); } return(false); }
private static void AnalyzeSwitchExhaustiveness([NotNull] ISwitchOperation switchStatement, [NotNull] INamedTypeSymbol systemBoolean, OperationAnalysisContext context) { var analysisContext = new SwitchAnalysisContext(switchStatement, systemBoolean, context); if (IsSwitchExhaustive(analysisContext) == false) { Location location = switchStatement.TryGetLocationForKeyword() ?? switchStatement.Syntax.GetLocation(); context.ReportDiagnostic(Diagnostic.Create(Rule, location)); } }
private bool ProcessAsLiteralSyntax([NotNull] SwitchAnalysisContext analysisContext, [NotNull] ISingleValueCaseClause caseClause) { if (caseClause.Value.Syntax is LiteralExpressionSyntax literalSyntax) { if (ProcessLiteralSyntaxAsTrueKeyword(analysisContext, literalSyntax) || ProcessLiteralSyntaxAsFalseKeyword(analysisContext, literalSyntax) || ProcessLiteralSyntaxAsNullKeyword(literalSyntax)) { return(true); } } return(false); }
private bool ProcessAsConversion([NotNull] SwitchAnalysisContext analysisContext, [NotNull] ISingleValueCaseClause caseClause) { var conversion = caseClause.Value as IConversionExpression; var memberSyntax = conversion?.Syntax as MemberAccessExpressionSyntax; IFieldSymbol field = analysisContext.GetFieldOrNull(memberSyntax); if (field != null) { caseClauseValues.Add(field); return(true); } return(false); }
private bool?IsSwitchCompleteForBooleanTypes([NotNull] IdentifierInfo identifierInfo, [NotNull] SwitchAnalysisContext analysisContext) { bool isBoolean = identifierInfo.Type.SpecialType == SpecialType.System_Boolean; bool isNullableBoolean = identifierInfo.Type.IsNullableBoolean(); if (isBoolean || isNullableBoolean) { ImmutableArray <ISymbol> possibleValues = isBoolean ? ImmutableArray.Create(analysisContext.BooleanTrue, analysisContext.BooleanFalse) : ImmutableArray.Create(analysisContext.BooleanTrue, analysisContext.BooleanFalse, null); return(HasCaseClausesFor(possibleValues, analysisContext)); } return(null); }
private void AnalyzeSwitchStatement(OperationAnalysisContext context, [NotNull] INamedTypeSymbol systemBoolean) { var switchStatement = (ISwitchStatement)context.Operation; if (HasDefaultCase(switchStatement)) { return; } context.CancellationToken.ThrowIfCancellationRequested(); var analysisContext = new SwitchAnalysisContext(switchStatement, systemBoolean, context); if (IsSwitchComplete(analysisContext) == false) { context.ReportDiagnostic(Diagnostic.Create(Rule, switchStatement.Syntax.GetLocation())); } }
private bool?HasCaseClausesFor([NotNull][ItemCanBeNull] ICollection <ISymbol> expectedValues, [NotNull] SwitchAnalysisContext analysisContext) { ICollection <ISymbol> caseClauseValues = TryGetSymbolsForCaseClauses(analysisContext); if (caseClauseValues == null) { return(null); } foreach (ISymbol expectedValue in expectedValues) { if (!caseClauseValues.Contains(expectedValue)) { return(false); } } return(true); }
private bool?IsSwitchCompleteForEnumerationTypes([NotNull] IdentifierInfo identifierInfo, [NotNull] SwitchAnalysisContext analysisContext) { bool isEnumeration = identifierInfo.Type.BaseType != null && identifierInfo.Type.BaseType.SpecialType == SpecialType.System_Enum; bool isNullableEnumeration = identifierInfo.Type.IsNullableEnumeration(); if (isEnumeration || isNullableEnumeration) { ITypeSymbol enumType = isEnumeration ? (INamedTypeSymbol)identifierInfo.Type : ((INamedTypeSymbol)identifierInfo.Type).TypeArguments[0]; ISymbol[] possibleValues = isEnumeration ? enumType.GetMembers().OfType <IFieldSymbol>().Cast <ISymbol>().ToArray() : enumType.GetMembers().OfType <IFieldSymbol>().Concat(NullSymbolArray).ToArray(); return(HasCaseClausesFor(possibleValues, analysisContext)); } return(null); }
private bool?IsSwitchComplete([NotNull] SwitchAnalysisContext analysisContext, [NotNull] IdentifierInfo identifierInfo) { return(IsSwitchCompleteForBooleanTypes(identifierInfo, analysisContext) ?? IsSwitchCompleteForEnumerationTypes(identifierInfo, analysisContext)); }
private bool?IsSwitchComplete([NotNull] SwitchAnalysisContext analysisContext) { IdentifierInfo identifierInfo = analysisContext.SwitchStatement.Value.TryGetIdentifierInfo(); return(identifierInfo != null?IsSwitchComplete(analysisContext, identifierInfo) : null); }
private ICollection <ISymbol> TryGetSymbolsForCaseClauses([NotNull] SwitchAnalysisContext analysisContext) { var caseClauseValues = new HashSet <ISymbol>(); IEnumerable <ISingleValueCaseClause> caseClauses = analysisContext.SwitchStatement.Cases.SelectMany(@case => @case.Clauses.OfType <ISingleValueCaseClause>()); foreach (ISingleValueCaseClause caseClause in caseClauses) { analysisContext.CancellationToken.ThrowIfCancellationRequested(); var literalSyntax = caseClause.Value.Syntax as LiteralExpressionSyntax; if (literalSyntax != null) { if (literalSyntax.Token.IsKind(SyntaxKind.TrueKeyword)) { caseClauseValues.Add(analysisContext.BooleanTrue); continue; } if (literalSyntax.Token.IsKind(SyntaxKind.FalseKeyword)) { caseClauseValues.Add(analysisContext.BooleanFalse); continue; } if (literalSyntax.Token.IsKind(SyntaxKind.NullKeyword)) { caseClauseValues.Add(null); continue; } } var enumField = caseClause.Value as IFieldReferenceExpression; if (enumField != null) { caseClauseValues.Add(enumField.Field); continue; } var conversion = caseClause.Value as IConversionExpression; var memberSyntax = conversion?.Syntax as MemberAccessExpressionSyntax; if (memberSyntax != null) { IFieldSymbol field = analysisContext.GetFieldOrNull(memberSyntax); if (field != null) { caseClauseValues.Add(field); continue; } } #pragma warning disable AV2310 // Code blocks should not contain inline comments // Switch statements with non-constant case expressions are not supported // because they make completion analysis non-trivial. #pragma warning restore AV2310 // Code blocks should not contain inline comments return(null); } return(caseClauseValues); }
private static bool?IsSwitchExhaustive([NotNull] SwitchAnalysisContext analysisContext, [NotNull] IdentifierInfo identifierInfo) { return(IsSwitchExhaustiveForBooleanTypes(identifierInfo, analysisContext) ?? IsSwitchExhaustiveForEnumerationTypes(identifierInfo, analysisContext)); }