File tree 16 files changed +135
-0
lines changed
16 files changed +135
-0
lines changed Original file line number Diff line number Diff line change 2
2
3
3
## Unreleased
4
4
<!-- Add all new changes here. They will be moved under a version at release -->
5
+ ` 2025-3-13 `
6
+ * ` NEW ` ` unnecessary-assert ` diagnostic warns when asserting values that are always truthy
5
7
6
8
## 3.13.9
7
9
` 2025-3-13 `
Original file line number Diff line number Diff line change @@ -36,6 +36,8 @@ DIAG_OVER_MAX_ARGS =
36
36
' This function expects a maximum of {:d} argument(s) but instead it is receiving {:d}.'
37
37
DIAG_MISS_ARGS =
38
38
' This function requires {:d} argument(s) but instead it is receiving {:d}.'
39
+ DIAG_UNNECESSARY_ASSERT =
40
+ ' Unnecessary assert: this expression is always truthy.'
39
41
DIAG_OVER_MAX_VALUES =
40
42
' Only has {} variables, but you set {} values.'
41
43
DIAG_AMBIGUITY_1 =
Original file line number Diff line number Diff line change @@ -406,6 +406,8 @@ config.diagnostics['missing-return-value'] =
406
406
' Enable diagnostics for return statements without values although the containing function declares returns.'
407
407
config .diagnostics [' need-check-nil' ] =
408
408
' Enable diagnostics for variable usages if `nil` or an optional (potentially `nil`) value was assigned to the variable before.'
409
+ config .diagnostics [' unnecessary-assert' ] =
410
+ ' Enable diagnostics for redundant assertions on truthy values.'
409
411
config .diagnostics [' no-unknown' ] =
410
412
' Enable diagnostics for cases in which the type cannot be inferred.'
411
413
config .diagnostics [' not-yieldable' ] =
Original file line number Diff line number Diff line change @@ -36,6 +36,8 @@ DIAG_OVER_MAX_ARGS =
36
36
' この関数は最大で {:d} 個の引数を受け取りますが、{:d} 個の引数が渡されています。'
37
37
DIAG_MISS_ARGS =
38
38
' この関数は少なくとも {:d} 個の引数を必要としますが、{:d} 個しか渡されていません。'
39
+ DIAG_UNNECESSARY_ASSERT =
40
+ ' 不要なアサーション: この式は常に真です。'
39
41
DIAG_OVER_MAX_VALUES =
40
42
' 変数は {} 個しかありませんが、{} 個の値が設定されています。'
41
43
DIAG_AMBIGUITY_1 =
Original file line number Diff line number Diff line change @@ -406,6 +406,8 @@ config.diagnostics['missing-return-value'] = -- TODO: need translate!
406
406
' Enable diagnostics for return statements without values although the containing function declares returns.'
407
407
config .diagnostics [' need-check-nil' ] = -- TODO: need translate!
408
408
' Enable diagnostics for variable usages if `nil` or an optional (potentially `nil`) value was assigned to the variable before.'
409
+ config .diagnostics [' unnecessary-assert' ] = -- TODO: need translate!
410
+ ' Enable diagnostics for redundant assertions on truthy values.'
409
411
config .diagnostics [' no-unknown' ] = -- TODO: need translate!
410
412
' Enable diagnostics for cases in which the type cannot be inferred.'
411
413
config .diagnostics [' not-yieldable' ] = -- TODO: need translate!
Original file line number Diff line number Diff line change @@ -36,6 +36,8 @@ DIAG_OVER_MAX_ARGS =
36
36
' A função aceita apenas os parâmetros {:d}, mas você passou {:d}.'
37
37
DIAG_MISS_ARGS =
38
38
' A função recebe pelo menos {:d} argumentos, mas há {:d}.'
39
+ DIAG_UNNECESSARY_ASSERT =
40
+ ' Asserção desnecessária: esta expressão é sempre verdadeira.'
39
41
DIAG_OVER_MAX_VALUES =
40
42
' Apenas há {} variáveis, mas você declarou {} valores.'
41
43
DIAG_AMBIGUITY_1 =
Original file line number Diff line number Diff line change @@ -406,6 +406,8 @@ config.diagnostics['missing-return-value'] = -- TODO: need translate!
406
406
' Enable diagnostics for return statements without values although the containing function declares returns.'
407
407
config .diagnostics [' need-check-nil' ] = -- TODO: need translate!
408
408
' Enable diagnostics for variable usages if `nil` or an optional (potentially `nil`) value was assigned to the variable before.'
409
+ config .diagnostics [' unnecessary-assert' ] = -- TODO: need translate!
410
+ ' Enable diagnostics for redundant assertions on truthy values.'
409
411
config .diagnostics [' no-unknown' ] = -- TODO: need translate!
410
412
' Enable diagnostics for cases in which the type cannot be inferred.'
411
413
config .diagnostics [' not-yieldable' ] = -- TODO: need translate!
Original file line number Diff line number Diff line change @@ -36,6 +36,8 @@ DIAG_OVER_MAX_ARGS =
36
36
' 函数最多接收 {:d} 个参数,但获得了 {:d} 个。'
37
37
DIAG_MISS_ARGS =
38
38
' 函数最少接收 {:d} 个参数,但获得了 {:d} 个。'
39
+ DIAG_UNNECESSARY_ASSERT =
40
+ ' 不必要的断言:此表达式始终为真值。'
39
41
DIAG_OVER_MAX_VALUES =
40
42
' 只有 {} 个变量,但你设置了 {} 个值。'
41
43
DIAG_AMBIGUITY_1 =
Original file line number Diff line number Diff line change @@ -404,6 +404,8 @@ config.diagnostics['missing-return-value'] =
404
404
' 函数无值返回但函数使用`@return`标记了返回值'
405
405
config .diagnostics [' need-check-nil' ] =
406
406
' 变量之前被赋值为`nil`或可选值(可能为 `nil`)'
407
+ config .diagnostics [' unnecessary-assert' ] =
408
+ ' 启用对冗余断言(针对始终为真值的表达式)的诊断'
407
409
config .diagnostics [' no-unknown' ] =
408
410
' 变量的未知类型无法推断'
409
411
config .diagnostics [' not-yieldable' ] =
Original file line number Diff line number Diff line change @@ -36,6 +36,8 @@ DIAG_OVER_MAX_ARGS =
36
36
' 函式最多接收 {:d} 個引數,但獲得了 {:d} 個。'
37
37
DIAG_MISS_ARGS =
38
38
' 函式最少接收 {:d} 個引數,但獲得了 {:d} 個。'
39
+ DIAG_UNNECESSARY_ASSERT =
40
+ ' 不必要的斷言:此表達式始終為真值。'
39
41
DIAG_OVER_MAX_VALUES =
40
42
' 只有 {} 個變數,但你設定了 {} 個值。'
41
43
DIAG_AMBIGUITY_1 =
Original file line number Diff line number Diff line change @@ -404,6 +404,8 @@ config.diagnostics['missing-return-value'] = -- TODO: need translate!
404
404
' Enable diagnostics for return statements without values although the containing function declares returns.'
405
405
config .diagnostics [' need-check-nil' ] = -- TODO: need translate!
406
406
' Enable diagnostics for variable usages if `nil` or an optional (potentially `nil`) value was assigned to the variable before.'
407
+ config .diagnostics [' unnecessary-assert' ] = -- TODO: need translate!
408
+ ' Enable diagnostics for redundant assertions on truthy values.'
407
409
config .diagnostics [' no-unknown' ] = -- TODO: need translate!
408
410
' Enable diagnostics for cases in which the type cannot be inferred.'
409
411
config .diagnostics [' not-yieldable' ] = -- TODO: need translate!
Original file line number Diff line number Diff line change
1
+ local files = require ' files'
2
+ local guide = require ' parser.guide'
3
+ local vm = require ' vm'
4
+ local lang = require ' language'
5
+ local await = require ' await'
6
+
7
+ --- @async
8
+ return function (uri , callback )
9
+ local state = files .getState (uri )
10
+ if not state then
11
+ return
12
+ end
13
+
14
+ --- @async
15
+ guide .eachSourceType (state .ast , ' call' , function (source )
16
+ await .delay ()
17
+ local currentFunc = guide .getParentFunction (source )
18
+ if currentFunc and source .node .special == ' assert' and source .args [1 ] then
19
+ local argNode = vm .compileNode (source .args [1 ])
20
+ if argNode :alwaysTruthy () then
21
+ callback {
22
+ start = source .node .start ,
23
+ finish = source .node .finish ,
24
+ message = lang .script (' DIAG_UNNECESSARY_ASSERT' ),
25
+ }
26
+ end
27
+ end
28
+ end )
29
+ end
Original file line number Diff line number Diff line change @@ -78,6 +78,7 @@ m.register {
78
78
' cast-type-mismatch' ,
79
79
' return-type-mismatch' ,
80
80
' inject-field' ,
81
+ ' unnecessary-assert' ,
81
82
} {
82
83
group = ' type-check' ,
83
84
severity = ' Warning' ,
Original file line number Diff line number Diff line change @@ -119,6 +119,32 @@ function mt:hasFalsy()
119
119
return false
120
120
end
121
121
122
+ --- Almost an inverse of hasFalsy, but stricter about "any" and "unknown" types.
123
+ --- @return boolean
124
+ function mt :alwaysTruthy ()
125
+ if self .optional then
126
+ return false
127
+ end
128
+ if # self == 0 then
129
+ return false
130
+ end
131
+ for _ , c in ipairs (self ) do
132
+ if c .type == ' nil'
133
+ or (c .type == ' global' and c .cate == ' type' and c .name == ' nil' )
134
+ or (c .type == ' global' and c .cate == ' type' and c .name == ' false' )
135
+ or (c .type == ' global' and c .cate == ' type' and c .name == ' any' )
136
+ or (c .type == ' global' and c .cate == ' type' and c .name == ' boolean' )
137
+ or (c .type == ' global' and c .cate == ' type' and c .name == ' doc.type.boolean' )
138
+ or (c .type == ' global' and c .cate == ' type' and c .name == ' unknown' )
139
+ or not self :hasKnownType ()
140
+ or (c .type == ' boolean' and c [1 ] == false )
141
+ or (c .type == ' doc.type.boolean' and c [1 ] == false ) then
142
+ return false
143
+ end
144
+ end
145
+ return true
146
+ end
147
+
122
148
--- @return boolean
123
149
function mt :hasKnownType ()
124
150
for _ , c in ipairs (self ) do
Original file line number Diff line number Diff line change @@ -100,6 +100,7 @@ check 'missing-parameter'
100
100
check ' missing-return-value'
101
101
check ' missing-return'
102
102
check ' need-check-nil'
103
+ check ' unnecessary-assert'
103
104
check ' newfield-call'
104
105
check ' newline-call'
105
106
check ' not-yieldable'
Original file line number Diff line number Diff line change
1
+ TEST [[
2
+ local a
3
+ assert(a)
4
+
5
+ ---@type boolean
6
+ local b
7
+ assert(b)
8
+
9
+ ---@type any
10
+ local c
11
+ assert(c)
12
+
13
+ ---@type unknown
14
+ local d
15
+ assert(d)
16
+
17
+ ---@type boolean
18
+ local e
19
+ assert(e)
20
+
21
+ ---@type number?
22
+ local f
23
+ assert(f)
24
+
25
+ assert(false)
26
+
27
+ assert(nil and 5)
28
+
29
+ ---@return string?, string?
30
+ local function f() end
31
+
32
+ assert(f())
33
+ ]]
34
+
35
+ TEST [[
36
+ <!assert!>(true)
37
+ ]]
38
+
39
+ TEST [[
40
+ ---@return integer
41
+ local function hi()
42
+ return 1
43
+ end
44
+ <!assert!>(hi(1))
45
+ ]]
46
+
47
+ TEST [[
48
+ <!assert!>({}, 'hi')
49
+ ]]
50
+
51
+ TEST [[
52
+ ---@return string, string?
53
+ local function f() end
54
+
55
+ <!assert!>(f())
56
+ ]]
You can’t perform that action at this time.
0 commit comments