Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var SwitchExhaustivenessCheckRule = rule.CreateRule(rule.Rule{ Name: "switch-exhaustiveness-check", Run: func(ctx rule.RuleContext, options any) rule.RuleListeners { opts, ok := options.(SwitchExhaustivenessCheckOptions) if !ok { opts = SwitchExhaustivenessCheckOptions{} } if opts.AllowDefaultCaseForExhaustiveSwitch == nil { opts.AllowDefaultCaseForExhaustiveSwitch = utils.Ref(true) } if opts.ConsiderDefaultExhaustiveForUnions == nil { opts.ConsiderDefaultExhaustiveForUnions = utils.Ref(false) } if opts.RequireDefaultForNonUnion == nil { opts.RequireDefaultForNonUnion = utils.Ref(false) } isLiteralLikeType := func(t *checker.Type) bool { return utils.IsTypeFlagSet( t, checker.TypeFlagsLiteral|checker.TypeFlagsUndefined|checker.TypeFlagsNull|checker.TypeFlagsUniqueESSymbol, ) } doesTypeContainNonLiteralType := func(t *checker.Type) bool { return utils.Some( utils.UnionTypeParts(t), func(t *checker.Type) bool { return utils.Every( utils.IntersectionTypeParts(t), func(t *checker.Type) bool { return !isLiteralLikeType(t) }, ) }, ) } getSwitchMetadata := func(node *ast.SwitchStatement) *SwitchMetadata { cases := node.CaseBlock.AsCaseBlock().Clauses.Nodes defaultCaseIndex := slices.IndexFunc(cases, func(clause *ast.Node) bool { return clause.Kind == ast.KindDefaultClause }) var defaultCase *ast.CaseOrDefaultClause if defaultCaseIndex > -1 { defaultCase = cases[defaultCaseIndex].AsCaseOrDefaultClause() } discriminantType := utils.GetConstrainedTypeAtLocation(ctx.TypeChecker, node.Expression) caseTypes := make([]*checker.Type, 0, len(cases)) for _, c := range cases { if c.Kind == ast.KindDefaultClause { continue } caseTypes = append(caseTypes, utils.GetConstrainedTypeAtLocation(ctx.TypeChecker, c.AsCaseOrDefaultClause().Expression)) } containsNonLiteralType := doesTypeContainNonLiteralType(discriminantType) missingLiteralBranchTypes := make([]*checker.Type, 0, 10) utils.TypeRecurser(discriminantType, func(t *checker.Type) bool { if slices.Contains(caseTypes, t) || !isLiteralLikeType(t) { return false } if slices.ContainsFunc(caseTypes, func(t *checker.Type) bool { return utils.IsTypeFlagSet(t, checker.TypeFlagsUndefined) }) && utils.IsTypeFlagSet(t, checker.TypeFlagsUndefined) { return false } missingLiteralBranchTypes = append(missingLiteralBranchTypes, t) return false }) return &SwitchMetadata{ ContainsNonLiteralType: containsNonLiteralType, DefaultCase: defaultCase, MissingLiteralBranchTypes: missingLiteralBranchTypes, } } checkSwitchExhaustive := func(node *ast.SwitchStatement, switchMetadata *SwitchMetadata) { if *opts.ConsiderDefaultExhaustiveForUnions && switchMetadata.DefaultCase != nil { return } if len(switchMetadata.MissingLiteralBranchTypes) > 0 { ctx.ReportNode(node.Expression, buildSwitchIsNotExhaustiveMessage("TODO")) } } checkSwitchUnnecessaryDefaultCase := func(switchMetadata *SwitchMetadata) { if *opts.AllowDefaultCaseForExhaustiveSwitch { return } if len(switchMetadata.MissingLiteralBranchTypes) == 0 && switchMetadata.DefaultCase != nil && !switchMetadata.ContainsNonLiteralType { ctx.ReportNode(&switchMetadata.DefaultCase.Node, buildDangerousDefaultCaseMessage()) } } checkSwitchNoUnionDefaultCase := func(node *ast.SwitchStatement, switchMetadata *SwitchMetadata) { if !*opts.RequireDefaultForNonUnion { return } if switchMetadata.ContainsNonLiteralType && switchMetadata.DefaultCase == nil { ctx.ReportNode(node.Expression, buildSwitchIsNotExhaustiveMessage("default")) } } return rule.RuleListeners{ ast.KindSwitchStatement: func(node *ast.Node) { stmt := node.AsSwitchStatement() metadata := getSwitchMetadata(stmt) checkSwitchExhaustive(stmt, metadata) checkSwitchUnnecessaryDefaultCase(metadata) checkSwitchNoUnionDefaultCase(stmt, metadata) }, } }, })
Functions ¶
This section is empty.
Types ¶
type SwitchMetadata ¶
type SwitchMetadata struct {
ContainsNonLiteralType bool
// nil if there is no default case
DefaultCase *ast.CaseOrDefaultClause
MissingLiteralBranchTypes []*checker.Type
}
Click to show internal directories.
Click to hide internal directories.