Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var NoConfusingVoidExpressionRule = rule.CreateRule(rule.Rule{ Name: "no-confusing-void-expression", Run: func(ctx rule.RuleContext, options any) rule.RuleListeners { opts, ok := options.(NoConfusingVoidExpressionOptions) if !ok { opts = NoConfusingVoidExpressionOptions{} options_array, _ := options.([]interface{}) if len(options_array) > 0 { optsJSON, err := json.Marshal(options_array[0]) if err == nil { json.Unmarshal(optsJSON, &opts) } } } canFix := func(node *ast.Node) bool { t := utils.GetConstrainedTypeAtLocation(ctx.TypeChecker, node) return utils.IsTypeFlagSet(t, checker.TypeFlagsVoidLike) } findInvalidAncestor := func(node *ast.Node) *ast.Node { parent := node for { node = parent parent = parent.Parent switch parent.Kind { case ast.KindParenthesizedExpression: continue case ast.KindBinaryExpression: n := parent.AsBinaryExpression() if ast.IsLogicalOrCoalescingBinaryOperator(n.OperatorToken.Kind) && n.Right == node { continue } if n.OperatorToken.Kind == ast.KindCommaToken { if n.Left == node { return nil } } case ast.KindExpressionStatement: return nil case ast.KindConditionalExpression: n := parent.AsConditionalExpression() if n.WhenTrue == node || n.WhenFalse == node { continue } case ast.KindArrowFunction: if opts.IgnoreArrowShorthand { return nil } case ast.KindVoidExpression: if opts.IgnoreVoidOperator { return nil } } break } return parent } isVoidReturningFunction := func(functionNode *ast.Node) bool { returnTypeNode := functionNode.Type() if returnTypeNode != nil { returnType := checker.Checker_getTypeFromTypeNode(ctx.TypeChecker, returnTypeNode) return utils.Some(utils.UnionTypeParts(returnType), utils.IsIntrinsicVoidType) } if !ast.IsArrowFunction(functionNode) && !ast.IsFunctionExpression(functionNode) { return false } functionType := checker.Checker_getContextualType(ctx.TypeChecker, functionNode, checker.ContextFlagsNone) if functionType == nil { return false } return utils.Some(utils.UnionTypeParts(functionType), func(t *checker.Type) bool { callSignatures := utils.GetCallSignatures(ctx.TypeChecker, t) return utils.Some(callSignatures, func(s *checker.Signature) bool { returnType := checker.Checker_getReturnTypeOfSignature(ctx.TypeChecker, s) return utils.Some(utils.UnionTypeParts(returnType), utils.IsIntrinsicVoidType) }) }) } isFinalReturn := func(node *ast.Node) bool { block := node.Parent if !ast.IsBlock(block) { return false } if !ast.IsFunctionLikeDeclaration(block.Parent) { return false } statements := block.AsBlock().Statements.Nodes return len(statements) > 0 && statements[len(statements)-1] == node } checkExpression := func(node *ast.Node) { t := utils.GetConstrainedTypeAtLocation(ctx.TypeChecker, node) if !utils.IsTypeFlagSet(t, checker.TypeFlagsVoidLike) { return } invalidAncestor := findInvalidAncestor(node) if invalidAncestor == nil { return } insertVoidFix := func() rule.RuleFix { return rule.RuleFixInsertBefore(ctx.SourceFile, node, "void ") } if ast.IsArrowFunction(invalidAncestor) { if opts.IgnoreVoidReturningFunctions && isVoidReturningFunction(invalidAncestor) { return } if opts.IgnoreVoidOperator { ctx.ReportNodeWithFixes(node, buildInvalidVoidExprArrowWrapVoidMessage(), insertVoidFix()) return } var fixes []rule.RuleFix body := invalidAncestor.Body() if !ast.IsBlock(body) && canFix(body) { withoutParens := ast.SkipParentheses(body) fixes = []rule.RuleFix{ rule.RuleFixReplaceRange(body.Loc.WithEnd(withoutParens.Pos()), "{ "), rule.RuleFixReplaceRange(body.Loc.WithPos(withoutParens.End()), "; }"), } } ctx.ReportNodeWithFixes(node, buildInvalidVoidExprArrowMessage(), fixes...) return } if ast.IsReturnStatement(invalidAncestor) { if opts.IgnoreVoidReturningFunctions { functionNode := utils.GetParentFunctionNode(invalidAncestor) if functionNode != nil && isVoidReturningFunction(functionNode) { return } } if opts.IgnoreVoidOperator { ctx.ReportNodeWithFixes(node, buildInvalidVoidExprReturnWrapVoidMessage(), insertVoidFix()) return } if isFinalReturn(invalidAncestor) { expr := invalidAncestor.AsReturnStatement().Expression var fixes []rule.RuleFix if canFix(expr) { replaceText := "" nextToken := scanner.ScanTokenAtPosition(ctx.SourceFile, expr.Pos()) if nextToken == ast.KindOpenParenToken || nextToken == ast.KindOpenBracketToken || nextToken == ast.KindBacktickToken { replaceText = ";" } returnToken := scanner.GetRangeOfTokenAtPosition(ctx.SourceFile, invalidAncestor.Pos()) fixes = append(fixes, rule.RuleFixReplaceRange(returnToken, replaceText)) } ctx.ReportNodeWithFixes(node, buildInvalidVoidExprReturnLastMessage(), fixes...) return } var fixes []rule.RuleFix replaceText := "" nextToken := scanner.ScanTokenAtPosition(ctx.SourceFile, invalidAncestor.AsReturnStatement().Expression.Pos()) if nextToken == ast.KindOpenParenToken || nextToken == ast.KindOpenBracketToken || nextToken == ast.KindBacktickToken { replaceText = ";" } returnToken := scanner.GetRangeOfTokenAtPosition(ctx.SourceFile, invalidAncestor.Pos()) fixes = append(fixes, rule.RuleFixReplaceRange(returnToken, replaceText), rule.RuleFixInsertAfter(invalidAncestor, "; return;")) if !ast.IsBlock(invalidAncestor.Parent) { fixes = append(fixes, rule.RuleFixInsertBefore(ctx.SourceFile, invalidAncestor, "{ "), rule.RuleFixInsertAfter(invalidAncestor, " }"), ) } ctx.ReportNodeWithFixes(node, buildInvalidVoidExprReturnMessage(), fixes...) return } if opts.IgnoreVoidOperator { ctx.ReportNodeWithSuggestions(node, buildInvalidVoidExprWrapVoidMessage(), rule.RuleSuggestion{ Message: buildVoidExprWrapVoidMessage(), FixesArr: []rule.RuleFix{insertVoidFix()}, }) return } ctx.ReportNode(node, buildInvalidVoidExprMessage()) } return rule.RuleListeners{ ast.KindAwaitExpression: checkExpression, ast.KindCallExpression: checkExpression, ast.KindTaggedTemplateExpression: checkExpression, } }, })
Functions ¶
This section is empty.
Types ¶
Click to show internal directories.
Click to hide internal directories.