(condExpr *ast.Node, condType *Type, body *ast.Node)
| 3814 | } |
| 3815 | |
| 3816 | func (c *Checker) checkTestingKnownTruthyType(condExpr *ast.Node, condType *Type, body *ast.Node) { |
| 3817 | location := condExpr |
| 3818 | if ast.IsLogicalOrCoalescingBinaryExpression(condExpr) { |
| 3819 | location = ast.SkipParentheses(condExpr.AsBinaryExpression().Right) |
| 3820 | } |
| 3821 | if ast.IsModuleExportsAccessExpression(location) { |
| 3822 | return |
| 3823 | } |
| 3824 | if ast.IsLogicalOrCoalescingBinaryExpression(location) { |
| 3825 | c.checkTestingKnownTruthyTypes(location, condType, body) |
| 3826 | return |
| 3827 | } |
| 3828 | t := condType |
| 3829 | if location != condExpr { |
| 3830 | t = c.checkExpression(location) |
| 3831 | } |
| 3832 | if t.flags&TypeFlagsEnumLiteral != 0 && ast.IsPropertyAccessExpression(location) && core.OrElse(c.getResolvedSymbolOrNil(location.Expression()), c.unknownSymbol).Flags&ast.SymbolFlagsEnum != 0 { |
| 3833 | // EnumLiteral type at condition with known value is always truthy or always falsy, likely an error |
| 3834 | c.error(location, diagnostics.This_condition_will_always_return_0, core.IfElse(evaluator.IsTruthy(t.AsLiteralType().value), "true", "false")) |
| 3835 | return |
| 3836 | } |
| 3837 | isPropertyExpressionCast := ast.IsPropertyAccessExpression(location) && isTypeAssertion(location.Expression()) |
| 3838 | if !c.hasTypeFacts(t, TypeFactsTruthy) || isPropertyExpressionCast { |
| 3839 | return |
| 3840 | } |
| 3841 | // While it technically should be invalid for any known-truthy value |
| 3842 | // to be tested, we de-scope to functions and Promises unreferenced in |
| 3843 | // the block as a heuristic to identify the most common bugs. There |
| 3844 | // are too many false positives for values sourced from type |
| 3845 | // definitions without strictNullChecks otherwise. |
| 3846 | callSignatures := c.getSignaturesOfType(t, SignatureKindCall) |
| 3847 | isPromise := c.getAwaitedTypeOfPromise(t) != nil |
| 3848 | if len(callSignatures) == 0 && !isPromise { |
| 3849 | return |
| 3850 | } |
| 3851 | var testedNode *ast.Node |
| 3852 | switch { |
| 3853 | case ast.IsIdentifier(location): |
| 3854 | testedNode = location |
| 3855 | case ast.IsPropertyAccessExpression(location): |
| 3856 | testedNode = location.Name() |
| 3857 | } |
| 3858 | var testedSymbol *ast.Symbol |
| 3859 | if testedNode != nil { |
| 3860 | testedSymbol = c.getSymbolAtLocation(testedNode, false) |
| 3861 | } |
| 3862 | if testedSymbol == nil && !isPromise { |
| 3863 | return |
| 3864 | } |
| 3865 | isUsed := testedSymbol != nil && ast.IsBinaryExpression(condExpr.Parent) && c.isSymbolUsedInBinaryExpressionChain(condExpr.Parent, testedSymbol) || |
| 3866 | testedSymbol != nil && body != nil && c.isSymbolUsedInConditionBody(condExpr, body, testedNode, testedSymbol) |
| 3867 | if !isUsed { |
| 3868 | if isPromise { |
| 3869 | c.errorAndMaybeSuggestAwait(location, true, diagnostics.This_condition_will_always_return_true_since_this_0_is_always_defined, c.getTypeNameForErrorDisplay(t)) |
| 3870 | } else { |
| 3871 | c.error(location, diagnostics.This_condition_will_always_return_true_since_this_function_is_always_defined_Did_you_mean_to_call_it_instead) |
| 3872 | } |
| 3873 | } |
no test coverage detected