@ttsc/lint 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -43
- package/go.mod +5 -4
- package/internal/rulecode/rulecode.go +88 -0
- package/lib/index.d.ts +10 -1
- package/lib/index.js +45 -17
- package/lib/index.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +3 -0
- package/lib/structures/TtscLintRuleSetting.d.ts +3 -2
- package/lib/structures/format/ITtscLintFormat.d.ts +3 -2
- package/lib/structures/format/ITtscLintFormatSortImports.d.ts +20 -4
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +80 -8
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +6 -8
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +18 -2
- package/lib/structures/rules/ITtscLintCoreRuleOptions.d.ts +347 -0
- package/lib/structures/rules/ITtscLintCoreRuleOptions.js +3 -0
- package/lib/structures/rules/ITtscLintCoreRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +101 -67
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +7 -2
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +53 -7
- package/lib/structures/rules/ITtscLintRules.d.ts +6 -2
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +0 -8
- package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.d.ts +206 -0
- package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.js +8 -0
- package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +55 -42
- package/lib/structures/rules/ITtscLintUnicornRuleOptions.d.ts +276 -0
- package/lib/structures/rules/ITtscLintUnicornRuleOptions.js +3 -0
- package/lib/structures/rules/ITtscLintUnicornRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintUnicornRules.d.ts +44 -36
- package/lib/structures/rules/index.d.ts +3 -0
- package/lib/structures/rules/index.js +3 -0
- package/lib/structures/rules/index.js.map +1 -1
- package/linthost/ast_helpers.go +521 -23
- package/linthost/ast_selector_matcher.go +1628 -0
- package/linthost/ast_selector_parser.go +628 -0
- package/linthost/comment_scan.go +154 -0
- package/linthost/compile.go +129 -79
- package/linthost/config.go +352 -88
- package/linthost/config_format.go +15 -1
- package/linthost/contrib_adapter.go +47 -8
- package/linthost/declaration_rules.go +12 -11
- package/linthost/directives.go +9 -67
- package/linthost/dispatch.go +37 -3
- package/linthost/engine.go +368 -53
- package/linthost/escape_string.go +77 -0
- package/linthost/fix.go +133 -23
- package/linthost/flags_gen.go +18 -17
- package/linthost/format.go +73 -167
- package/linthost/format_editor_settings.go +134 -26
- package/linthost/grapheme_tables_gen.go +1920 -0
- package/linthost/host.go +160 -61
- package/linthost/literal_escape_scan.go +117 -0
- package/linthost/lsp.go +545 -98
- package/linthost/numeric_literal_precision.go +228 -0
- package/linthost/polyfill_browserslist.go +1439 -0
- package/linthost/polyfill_browserslist_config.go +603 -0
- package/linthost/polyfill_corejs.go +750 -0
- package/linthost/polyfill_data.go +113 -0
- package/linthost/polyfill_data_gen.json +39868 -0
- package/linthost/print_nodes_array.go +7 -1
- package/linthost/print_nodes_object.go +7 -1
- package/linthost/project_engine.go +151 -0
- package/linthost/project_rules.go +78 -0
- package/linthost/regex_clean.go +191 -0
- package/linthost/regex_tree.go +1544 -0
- package/linthost/regex_tree_optimizer.go +1685 -0
- package/linthost/regexp_cache.go +44 -0
- package/linthost/rule_codes.go +105 -0
- package/linthost/rule_codes.json +745 -0
- package/linthost/rules_ban_ts_comment.go +312 -0
- package/linthost/rules_boundaries.go +128 -43
- package/linthost/rules_boundaries_dependencies.go +1013 -0
- package/linthost/rules_core_extra.go +62 -92
- package/linthost/rules_cypress.go +1 -1
- package/linthost/rules_default_case.go +87 -11
- package/linthost/rules_dupes.go +38 -13
- package/linthost/rules_empty.go +188 -20
- package/linthost/rules_escape.go +62 -48
- package/linthost/rules_format_arrow_parens.go +19 -5
- package/linthost/rules_format_bracket_spacing.go +1 -1
- package/linthost/rules_format_clause_join.go +1 -1
- package/linthost/rules_format_declaration_header.go +31 -19
- package/linthost/rules_format_indent.go +1 -1
- package/linthost/rules_format_jsdoc.go +1 -1
- package/linthost/rules_format_orphan_semi.go +1 -1
- package/linthost/rules_format_parameter_properties.go +17 -7
- package/linthost/rules_format_print_width.go +1 -1
- package/linthost/rules_format_quote_props.go +1 -1
- package/linthost/rules_format_quotes.go +1 -1
- package/linthost/rules_format_semi.go +106 -79
- package/linthost/rules_format_sort_imports.go +79 -45
- package/linthost/rules_format_statement_split.go +1 -1
- package/linthost/rules_format_ternary_nullish_parens.go +1 -1
- package/linthost/rules_format_trailing_comma.go +64 -1
- package/linthost/rules_format_whitespace.go +1 -1
- package/linthost/rules_functional.go +21 -22
- package/linthost/rules_gap.go +80 -3
- package/linthost/rules_grouped_accessor_pairs.go +84 -25
- package/linthost/rules_guard_for_in.go +64 -147
- package/linthost/rules_jsx_a11y.go +232 -22
- package/linthost/rules_logic.go +84 -38
- package/linthost/rules_nextjs.go +105 -16
- package/linthost/rules_no_class_assign.go +70 -0
- package/linthost/rules_no_duplicate_imports.go +266 -0
- package/linthost/rules_no_else_return.go +156 -38
- package/linthost/rules_no_extend_native.go +113 -17
- package/linthost/rules_no_fallthrough.go +1013 -0
- package/linthost/rules_no_func_assign.go +70 -0
- package/linthost/rules_no_import_assign.go +278 -86
- package/linthost/rules_no_inner_declarations.go +186 -0
- package/linthost/rules_no_loop_func.go +438 -53
- package/linthost/rules_no_mixed_operators.go +208 -52
- package/linthost/rules_no_param_reassign.go +376 -61
- package/linthost/rules_no_promise_executor_return.go +156 -0
- package/linthost/rules_no_restricted_imports.go +1013 -57
- package/linthost/rules_no_restricted_syntax.go +190 -26
- package/linthost/rules_no_useless_constructor.go +6 -36
- package/linthost/rules_problems.go +154 -311
- package/linthost/rules_promise.go +2578 -109
- package/linthost/rules_react_extras.go +71 -45
- package/linthost/rules_react_hooks.go +18 -2
- package/linthost/rules_react_perf.go +1 -0
- package/linthost/rules_react_refresh.go +1 -1
- package/linthost/rules_regexp.go +230 -14
- package/linthost/rules_security.go +45 -19
- package/linthost/rules_self.go +21 -1
- package/linthost/rules_solid.go +13 -7
- package/linthost/rules_storybook.go +1 -1
- package/linthost/rules_suggestions.go +490 -84
- package/linthost/rules_testing_library.go +12 -1
- package/linthost/rules_ts.go +227 -54
- package/linthost/rules_ts_async.go +0 -131
- package/linthost/rules_ts_no_base_to_string.go +3 -4
- package/linthost/rules_ts_no_misused_promises.go +817 -0
- package/linthost/rules_ts_no_restricted_types.go +320 -34
- package/linthost/rules_ts_no_unnecessary_qualifier.go +132 -55
- package/linthost/rules_ts_no_unsafe_assignment.go +608 -60
- package/linthost/rules_ts_require_array_sort_compare.go +5 -5
- package/linthost/rules_ts_switch_exhaustiveness_check.go +556 -86
- package/linthost/rules_unicorn_better_regex.go +224 -16
- package/linthost/rules_unicorn_consistent_destructuring.go +1002 -7
- package/linthost/rules_unicorn_consistent_existence_index_check.go +208 -29
- package/linthost/rules_unicorn_consistent_function_scoping.go +1041 -8
- package/linthost/rules_unicorn_consistent_template_literal_escape.go +178 -7
- package/linthost/rules_unicorn_escape_case.go +30 -19
- package/linthost/rules_unicorn_filename_case.go +763 -16
- package/linthost/rules_unicorn_import_style.go +783 -17
- package/linthost/rules_unicorn_isolated_functions.go +934 -14
- package/linthost/rules_unicorn_no_hex_escape.go +26 -11
- package/linthost/rules_unicorn_no_typeof_undefined.go +234 -25
- package/linthost/rules_unicorn_no_unnecessary_polyfills.go +376 -21
- package/linthost/rules_unicorn_no_unused_properties.go +756 -19
- package/linthost/rules_unicorn_number_literal_case.go +58 -39
- package/linthost/rules_unicorn_prefer_at.go +7 -3
- package/linthost/rules_unicorn_prefer_number_properties.go +381 -48
- package/linthost/rules_unicorn_prefer_optional_catch_binding.go +24 -24
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +597 -19
- package/linthost/rules_unicorn_prefer_string_raw.go +147 -16
- package/linthost/rules_unicorn_prevent_abbreviations.go +1963 -95
- package/linthost/rules_unicorn_string_content.go +611 -15
- package/linthost/rules_unicorn_switch_case_break_position.go +172 -15
- package/linthost/rules_unicorn_template_indent.go +923 -18
- package/linthost/rules_unicorn_text_encoding_identifier_case.go +202 -42
- package/linthost/rules_unicorn_throw_new_error.go +218 -26
- package/linthost/rules_var.go +829 -142
- package/linthost/string_length.go +222 -0
- package/package.json +4 -3
- package/rule/project.go +145 -0
- package/rule/rule.go +58 -1
- package/src/index.ts +58 -17
- package/src/structures/ITtscLintConfig.ts +3 -0
- package/src/structures/TtscLintRuleSetting.ts +3 -2
- package/src/structures/format/ITtscLintFormat.ts +3 -2
- package/src/structures/format/ITtscLintFormatSortImports.ts +21 -4
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +122 -8
- package/src/structures/rules/ITtscLintBoundariesRules.ts +6 -8
- package/src/structures/rules/ITtscLintContributorRules.ts +18 -2
- package/src/structures/rules/ITtscLintCoreRuleOptions.ts +465 -0
- package/src/structures/rules/ITtscLintCoreRules.ts +122 -67
- package/src/structures/rules/ITtscLintRegexpRules.ts +7 -2
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +88 -7
- package/src/structures/rules/ITtscLintRules.ts +7 -2
- package/src/structures/rules/ITtscLintSolidRules.ts +0 -9
- package/src/structures/rules/ITtscLintTypeScriptRuleOptions.ts +248 -0
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +64 -42
- package/src/structures/rules/ITtscLintUnicornRuleOptions.ts +350 -0
- package/src/structures/rules/ITtscLintUnicornRules.ts +60 -36
- package/src/structures/rules/index.ts +3 -0
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
// typescript/no-misused-promises rejects thenables used as booleans and
|
|
2
|
+
// Promise-returning functions supplied to contracts that discard their
|
|
3
|
+
// return value. Every void-return check is driven by the Checker's resolved
|
|
4
|
+
// types; callback syntax and callee spelling are never used as substitutes
|
|
5
|
+
// for the destination contract.
|
|
6
|
+
package linthost
|
|
7
|
+
|
|
8
|
+
import (
|
|
9
|
+
"encoding/json"
|
|
10
|
+
|
|
11
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
12
|
+
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
type noMisusedPromises struct{ optionsRule }
|
|
16
|
+
|
|
17
|
+
type noMisusedPromisesRawOptions struct {
|
|
18
|
+
ChecksConditionals *bool `json:"checksConditionals"`
|
|
19
|
+
ChecksSpreads *bool `json:"checksSpreads"`
|
|
20
|
+
ChecksVoidReturn json.RawMessage `json:"checksVoidReturn"`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type noMisusedPromisesVoidOptions struct {
|
|
24
|
+
Arguments *bool `json:"arguments"`
|
|
25
|
+
Attributes *bool `json:"attributes"`
|
|
26
|
+
InheritedMethods *bool `json:"inheritedMethods"`
|
|
27
|
+
Properties *bool `json:"properties"`
|
|
28
|
+
Returns *bool `json:"returns"`
|
|
29
|
+
Variables *bool `json:"variables"`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type noMisusedPromisesOptions struct {
|
|
33
|
+
checksConditionals bool
|
|
34
|
+
checksSpreads bool
|
|
35
|
+
arguments bool
|
|
36
|
+
attributes bool
|
|
37
|
+
inheritedMethods bool
|
|
38
|
+
properties bool
|
|
39
|
+
returns bool
|
|
40
|
+
variables bool
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
func init() { Register(noMisusedPromises{}) }
|
|
44
|
+
|
|
45
|
+
func (noMisusedPromises) Name() string { return "typescript/no-misused-promises" }
|
|
46
|
+
func (noMisusedPromises) NeedsTypeChecker() bool {
|
|
47
|
+
return true
|
|
48
|
+
}
|
|
49
|
+
func (noMisusedPromises) Visits() []shimast.Kind {
|
|
50
|
+
return []shimast.Kind{
|
|
51
|
+
shimast.KindIfStatement,
|
|
52
|
+
shimast.KindWhileStatement,
|
|
53
|
+
shimast.KindDoStatement,
|
|
54
|
+
shimast.KindForStatement,
|
|
55
|
+
shimast.KindConditionalExpression,
|
|
56
|
+
shimast.KindPrefixUnaryExpression,
|
|
57
|
+
shimast.KindBinaryExpression,
|
|
58
|
+
shimast.KindCallExpression,
|
|
59
|
+
shimast.KindNewExpression,
|
|
60
|
+
shimast.KindSpreadAssignment,
|
|
61
|
+
shimast.KindVariableDeclaration,
|
|
62
|
+
shimast.KindPropertyAssignment,
|
|
63
|
+
shimast.KindShorthandPropertyAssignment,
|
|
64
|
+
shimast.KindMethodDeclaration,
|
|
65
|
+
shimast.KindReturnStatement,
|
|
66
|
+
shimast.KindJsxAttribute,
|
|
67
|
+
shimast.KindClassDeclaration,
|
|
68
|
+
shimast.KindClassExpression,
|
|
69
|
+
shimast.KindInterfaceDeclaration,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
func (noMisusedPromises) Check(ctx *Context, node *shimast.Node) {
|
|
74
|
+
if ctx == nil || ctx.Checker == nil || node == nil {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
options := noMisusedPromisesResolveOptions(ctx)
|
|
78
|
+
switch node.Kind {
|
|
79
|
+
case shimast.KindIfStatement:
|
|
80
|
+
if options.checksConditionals {
|
|
81
|
+
if statement := node.AsIfStatement(); statement != nil {
|
|
82
|
+
noMisusedPromisesCheckConditional(ctx, statement.Expression, true)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
case shimast.KindWhileStatement:
|
|
86
|
+
if options.checksConditionals {
|
|
87
|
+
if statement := node.AsWhileStatement(); statement != nil {
|
|
88
|
+
noMisusedPromisesCheckConditional(ctx, statement.Expression, true)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
case shimast.KindDoStatement:
|
|
92
|
+
if options.checksConditionals {
|
|
93
|
+
if statement := node.AsDoStatement(); statement != nil {
|
|
94
|
+
noMisusedPromisesCheckConditional(ctx, statement.Expression, true)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
case shimast.KindForStatement:
|
|
98
|
+
if options.checksConditionals {
|
|
99
|
+
if statement := node.AsForStatement(); statement != nil {
|
|
100
|
+
noMisusedPromisesCheckConditional(ctx, statement.Condition, true)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
case shimast.KindConditionalExpression:
|
|
104
|
+
if options.checksConditionals {
|
|
105
|
+
if expression := node.AsConditionalExpression(); expression != nil {
|
|
106
|
+
noMisusedPromisesCheckConditional(ctx, expression.Condition, true)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
case shimast.KindPrefixUnaryExpression:
|
|
110
|
+
if options.checksConditionals && !noMisusedPromisesConditionalOwnedByAncestor(node) {
|
|
111
|
+
if expression := node.AsPrefixUnaryExpression(); expression != nil && expression.Operator == shimast.KindExclamationToken {
|
|
112
|
+
noMisusedPromisesCheckConditional(ctx, expression.Operand, true)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
case shimast.KindBinaryExpression:
|
|
116
|
+
noMisusedPromisesCheckBinary(ctx, node, options)
|
|
117
|
+
case shimast.KindCallExpression, shimast.KindNewExpression:
|
|
118
|
+
var predicateArgument *shimast.Node
|
|
119
|
+
if options.checksConditionals {
|
|
120
|
+
predicateArgument = noMisusedPromisesCheckPredicate(ctx, node)
|
|
121
|
+
}
|
|
122
|
+
if options.arguments {
|
|
123
|
+
noMisusedPromisesCheckArguments(ctx, node, predicateArgument)
|
|
124
|
+
}
|
|
125
|
+
case shimast.KindSpreadAssignment:
|
|
126
|
+
if options.checksSpreads {
|
|
127
|
+
noMisusedPromisesCheckSpread(ctx, node)
|
|
128
|
+
}
|
|
129
|
+
case shimast.KindVariableDeclaration:
|
|
130
|
+
if options.variables {
|
|
131
|
+
noMisusedPromisesCheckVariable(ctx, node)
|
|
132
|
+
}
|
|
133
|
+
case shimast.KindPropertyAssignment, shimast.KindShorthandPropertyAssignment, shimast.KindMethodDeclaration:
|
|
134
|
+
if options.properties {
|
|
135
|
+
noMisusedPromisesCheckProperty(ctx, node)
|
|
136
|
+
}
|
|
137
|
+
case shimast.KindReturnStatement:
|
|
138
|
+
if options.returns {
|
|
139
|
+
noMisusedPromisesCheckReturn(ctx, node)
|
|
140
|
+
}
|
|
141
|
+
case shimast.KindJsxAttribute:
|
|
142
|
+
if options.attributes {
|
|
143
|
+
noMisusedPromisesCheckAttribute(ctx, node)
|
|
144
|
+
}
|
|
145
|
+
case shimast.KindClassDeclaration, shimast.KindClassExpression, shimast.KindInterfaceDeclaration:
|
|
146
|
+
if options.inheritedMethods {
|
|
147
|
+
noMisusedPromisesCheckInheritedMethods(ctx, node)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func noMisusedPromisesResolveOptions(ctx *Context) noMisusedPromisesOptions {
|
|
153
|
+
resolved := noMisusedPromisesOptions{
|
|
154
|
+
checksConditionals: true,
|
|
155
|
+
checksSpreads: true,
|
|
156
|
+
arguments: true,
|
|
157
|
+
attributes: true,
|
|
158
|
+
inheritedMethods: true,
|
|
159
|
+
properties: true,
|
|
160
|
+
returns: true,
|
|
161
|
+
variables: true,
|
|
162
|
+
}
|
|
163
|
+
var raw noMisusedPromisesRawOptions
|
|
164
|
+
if ctx.DecodeOptions(&raw) != nil {
|
|
165
|
+
return resolved
|
|
166
|
+
}
|
|
167
|
+
if raw.ChecksConditionals != nil {
|
|
168
|
+
resolved.checksConditionals = *raw.ChecksConditionals
|
|
169
|
+
}
|
|
170
|
+
if raw.ChecksSpreads != nil {
|
|
171
|
+
resolved.checksSpreads = *raw.ChecksSpreads
|
|
172
|
+
}
|
|
173
|
+
if len(raw.ChecksVoidReturn) == 0 {
|
|
174
|
+
return resolved
|
|
175
|
+
}
|
|
176
|
+
var enabled bool
|
|
177
|
+
if json.Unmarshal(raw.ChecksVoidReturn, &enabled) == nil {
|
|
178
|
+
resolved.arguments = enabled
|
|
179
|
+
resolved.attributes = enabled
|
|
180
|
+
resolved.inheritedMethods = enabled
|
|
181
|
+
resolved.properties = enabled
|
|
182
|
+
resolved.returns = enabled
|
|
183
|
+
resolved.variables = enabled
|
|
184
|
+
return resolved
|
|
185
|
+
}
|
|
186
|
+
var positions noMisusedPromisesVoidOptions
|
|
187
|
+
if json.Unmarshal(raw.ChecksVoidReturn, &positions) != nil {
|
|
188
|
+
return resolved
|
|
189
|
+
}
|
|
190
|
+
noMisusedPromisesSetOption(&resolved.arguments, positions.Arguments)
|
|
191
|
+
noMisusedPromisesSetOption(&resolved.attributes, positions.Attributes)
|
|
192
|
+
noMisusedPromisesSetOption(&resolved.inheritedMethods, positions.InheritedMethods)
|
|
193
|
+
noMisusedPromisesSetOption(&resolved.properties, positions.Properties)
|
|
194
|
+
noMisusedPromisesSetOption(&resolved.returns, positions.Returns)
|
|
195
|
+
noMisusedPromisesSetOption(&resolved.variables, positions.Variables)
|
|
196
|
+
return resolved
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
func noMisusedPromisesSetOption(target *bool, configured *bool) {
|
|
200
|
+
if configured != nil {
|
|
201
|
+
*target = *configured
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
func noMisusedPromisesCheckBinary(ctx *Context, node *shimast.Node, options noMisusedPromisesOptions) {
|
|
206
|
+
expression := node.AsBinaryExpression()
|
|
207
|
+
if expression == nil || expression.OperatorToken == nil {
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
switch expression.OperatorToken.Kind {
|
|
211
|
+
case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken, shimast.KindQuestionQuestionToken:
|
|
212
|
+
if options.checksConditionals && !noMisusedPromisesConditionalOwnedByAncestor(node) {
|
|
213
|
+
noMisusedPromisesCheckConditional(ctx, node, false)
|
|
214
|
+
}
|
|
215
|
+
case shimast.KindEqualsToken:
|
|
216
|
+
if options.variables &&
|
|
217
|
+
noMisusedPromisesIsVoidReturningFunctionType(ctx.Checker, expression.Left, ctx.Checker.GetTypeAtLocation(expression.Left)) &&
|
|
218
|
+
noMisusedPromisesReturnsThenable(ctx.Checker, expression.Right) {
|
|
219
|
+
ctx.Report(expression.Right, "Promise-returning function assigned where a void return was expected.")
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
func noMisusedPromisesConditionalOwnedByAncestor(node *shimast.Node) bool {
|
|
225
|
+
owned, _ := noMisusedPromisesConditionalContextFromAncestor(node)
|
|
226
|
+
return owned
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// noMisusedPromisesConditionalContextFromAncestor mirrors the upstream
|
|
230
|
+
// checked-node set without retaining state between Check calls. It reports
|
|
231
|
+
// whether an ancestor's recursive conditional walk reaches node and whether
|
|
232
|
+
// that walk is inside a test expression.
|
|
233
|
+
func noMisusedPromisesConditionalContextFromAncestor(node *shimast.Node) (bool, bool) {
|
|
234
|
+
child := node
|
|
235
|
+
for parent := node.Parent; parent != nil; parent = parent.Parent {
|
|
236
|
+
if parent.Kind == shimast.KindParenthesizedExpression {
|
|
237
|
+
child = parent
|
|
238
|
+
continue
|
|
239
|
+
}
|
|
240
|
+
switch parent.Kind {
|
|
241
|
+
case shimast.KindPrefixUnaryExpression:
|
|
242
|
+
expression := parent.AsPrefixUnaryExpression()
|
|
243
|
+
if expression != nil && expression.Operator == shimast.KindExclamationToken && expression.Operand == child {
|
|
244
|
+
return true, true
|
|
245
|
+
}
|
|
246
|
+
return false, false
|
|
247
|
+
case shimast.KindBinaryExpression:
|
|
248
|
+
expression := parent.AsBinaryExpression()
|
|
249
|
+
if expression == nil || expression.OperatorToken == nil {
|
|
250
|
+
return false, false
|
|
251
|
+
}
|
|
252
|
+
switch expression.OperatorToken.Kind {
|
|
253
|
+
case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken, shimast.KindQuestionQuestionToken:
|
|
254
|
+
parentOwned, testExpression := noMisusedPromisesConditionalContextFromAncestor(parent)
|
|
255
|
+
if !parentOwned {
|
|
256
|
+
testExpression = false
|
|
257
|
+
}
|
|
258
|
+
if expression.Left == child {
|
|
259
|
+
return expression.OperatorToken.Kind != shimast.KindQuestionQuestionToken || testExpression, testExpression
|
|
260
|
+
}
|
|
261
|
+
if expression.Right == child {
|
|
262
|
+
return testExpression, testExpression
|
|
263
|
+
}
|
|
264
|
+
return false, false
|
|
265
|
+
}
|
|
266
|
+
return false, false
|
|
267
|
+
case shimast.KindConditionalExpression:
|
|
268
|
+
expression := parent.AsConditionalExpression()
|
|
269
|
+
return expression != nil && expression.Condition == child, true
|
|
270
|
+
case shimast.KindIfStatement:
|
|
271
|
+
statement := parent.AsIfStatement()
|
|
272
|
+
return statement != nil && statement.Expression == child, true
|
|
273
|
+
case shimast.KindWhileStatement:
|
|
274
|
+
statement := parent.AsWhileStatement()
|
|
275
|
+
return statement != nil && statement.Expression == child, true
|
|
276
|
+
case shimast.KindDoStatement:
|
|
277
|
+
statement := parent.AsDoStatement()
|
|
278
|
+
return statement != nil && statement.Expression == child, true
|
|
279
|
+
case shimast.KindForStatement:
|
|
280
|
+
statement := parent.AsForStatement()
|
|
281
|
+
return statement != nil && statement.Condition == child, true
|
|
282
|
+
}
|
|
283
|
+
return false, false
|
|
284
|
+
}
|
|
285
|
+
return false, false
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
func noMisusedPromisesCheckConditional(ctx *Context, expression *shimast.Node, testExpression bool) {
|
|
289
|
+
expression = stripParens(expression)
|
|
290
|
+
if expression == nil {
|
|
291
|
+
return
|
|
292
|
+
}
|
|
293
|
+
if expression.Kind == shimast.KindBinaryExpression {
|
|
294
|
+
binary := expression.AsBinaryExpression()
|
|
295
|
+
if binary == nil || binary.OperatorToken == nil {
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
switch binary.OperatorToken.Kind {
|
|
299
|
+
case shimast.KindAmpersandAmpersandToken, shimast.KindBarBarToken, shimast.KindQuestionQuestionToken:
|
|
300
|
+
if binary.OperatorToken.Kind != shimast.KindQuestionQuestionToken || testExpression {
|
|
301
|
+
noMisusedPromisesCheckConditional(ctx, binary.Left, testExpression)
|
|
302
|
+
}
|
|
303
|
+
if testExpression {
|
|
304
|
+
noMisusedPromisesCheckConditional(ctx, binary.Right, true)
|
|
305
|
+
}
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if expression.Kind == shimast.KindPrefixUnaryExpression {
|
|
310
|
+
if prefix := expression.AsPrefixUnaryExpression(); prefix != nil && prefix.Operator == shimast.KindExclamationToken {
|
|
311
|
+
noMisusedPromisesCheckConditional(ctx, prefix.Operand, true)
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if noMisusedPromisesIsAlwaysThenable(ctx.Checker, expression) {
|
|
316
|
+
ctx.Report(expression, "Expected a non-Promise value in a boolean conditional.")
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
func noMisusedPromisesIsAlwaysThenable(checker *shimchecker.Checker, node *shimast.Node) bool {
|
|
321
|
+
if checker == nil || node == nil {
|
|
322
|
+
return false
|
|
323
|
+
}
|
|
324
|
+
valueType := constrainedPromiseType(checker, checker.GetTypeAtLocation(node))
|
|
325
|
+
apparent := checker.GetApparentType(valueType)
|
|
326
|
+
parts := promiseUnionParts(apparent)
|
|
327
|
+
if len(parts) == 0 {
|
|
328
|
+
return false
|
|
329
|
+
}
|
|
330
|
+
for _, part := range parts {
|
|
331
|
+
if !isThenableAtLocation(checker, node, part) {
|
|
332
|
+
return false
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return true
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
func noMisusedPromisesCheckPredicate(ctx *Context, node *shimast.Node) *shimast.Node {
|
|
339
|
+
if node.Kind != shimast.KindCallExpression {
|
|
340
|
+
return nil
|
|
341
|
+
}
|
|
342
|
+
call := node.AsCallExpression()
|
|
343
|
+
if call == nil || call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
|
|
344
|
+
return nil
|
|
345
|
+
}
|
|
346
|
+
receiver, method, ok := noMisusedPromisesStaticMemberParts(call.Expression)
|
|
347
|
+
if !ok || !noMisusedPromisesIsArrayPredicate(method) || !noMisusedPromisesHasNativeArrayReceiver(ctx.Checker, receiver) {
|
|
348
|
+
return nil
|
|
349
|
+
}
|
|
350
|
+
callback := call.Arguments.Nodes[0]
|
|
351
|
+
if noMisusedPromisesReturnsThenable(ctx.Checker, callback) {
|
|
352
|
+
ctx.Report(callback, "Expected a non-Promise value to be returned from this predicate.")
|
|
353
|
+
return callback
|
|
354
|
+
}
|
|
355
|
+
return nil
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
func noMisusedPromisesIsArrayPredicate(method string) bool {
|
|
359
|
+
switch method {
|
|
360
|
+
case "every", "filter", "find", "findIndex", "findLast", "findLastIndex", "some":
|
|
361
|
+
return true
|
|
362
|
+
}
|
|
363
|
+
return false
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
func noMisusedPromisesStaticMemberParts(node *shimast.Node) (*shimast.Node, string, bool) {
|
|
367
|
+
node = stripParens(node)
|
|
368
|
+
if node == nil {
|
|
369
|
+
return nil, "", false
|
|
370
|
+
}
|
|
371
|
+
switch node.Kind {
|
|
372
|
+
case shimast.KindPropertyAccessExpression:
|
|
373
|
+
access := node.AsPropertyAccessExpression()
|
|
374
|
+
if access == nil {
|
|
375
|
+
return nil, "", false
|
|
376
|
+
}
|
|
377
|
+
method := identifierText(access.Name())
|
|
378
|
+
return access.Expression, method, method != ""
|
|
379
|
+
case shimast.KindElementAccessExpression:
|
|
380
|
+
access := node.AsElementAccessExpression()
|
|
381
|
+
if access == nil || access.ArgumentExpression == nil {
|
|
382
|
+
return nil, "", false
|
|
383
|
+
}
|
|
384
|
+
argument := stripParens(access.ArgumentExpression)
|
|
385
|
+
if argument == nil {
|
|
386
|
+
return nil, "", false
|
|
387
|
+
}
|
|
388
|
+
switch argument.Kind {
|
|
389
|
+
case shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral:
|
|
390
|
+
method := stringLiteralText(argument)
|
|
391
|
+
return access.Expression, method, method != ""
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return nil, "", false
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
func noMisusedPromisesHasNativeArrayReceiver(checker *shimchecker.Checker, node *shimast.Node) bool {
|
|
398
|
+
if checker == nil || node == nil {
|
|
399
|
+
return false
|
|
400
|
+
}
|
|
401
|
+
return noMisusedPromisesTypeHasNativeArray(
|
|
402
|
+
checker,
|
|
403
|
+
checker.GetTypeAtLocation(node),
|
|
404
|
+
map[*shimchecker.Type]struct{}{},
|
|
405
|
+
)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
func noMisusedPromisesTypeHasNativeArray(
|
|
409
|
+
checker *shimchecker.Checker,
|
|
410
|
+
valueType *shimchecker.Type,
|
|
411
|
+
seen map[*shimchecker.Type]struct{},
|
|
412
|
+
) bool {
|
|
413
|
+
if checker == nil || valueType == nil {
|
|
414
|
+
return false
|
|
415
|
+
}
|
|
416
|
+
if _, ok := seen[valueType]; ok {
|
|
417
|
+
return false
|
|
418
|
+
}
|
|
419
|
+
seen[valueType] = struct{}{}
|
|
420
|
+
defer delete(seen, valueType)
|
|
421
|
+
|
|
422
|
+
flags := valueType.Flags()
|
|
423
|
+
if flags&shimchecker.TypeFlagsTypeParameter != 0 {
|
|
424
|
+
constraint := checker.GetBaseConstraintOfType(valueType)
|
|
425
|
+
return constraint != nil && constraint != valueType &&
|
|
426
|
+
noMisusedPromisesTypeHasNativeArray(checker, constraint, seen)
|
|
427
|
+
}
|
|
428
|
+
if flags&(shimchecker.TypeFlagsUnion|shimchecker.TypeFlagsIntersection) != 0 {
|
|
429
|
+
for _, part := range valueType.Types() {
|
|
430
|
+
if noMisusedPromisesTypeHasNativeArray(checker, part, seen) {
|
|
431
|
+
return true
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return false
|
|
435
|
+
}
|
|
436
|
+
return shimchecker.Checker_isArrayType(checker, valueType) || shimchecker.IsTupleType(valueType)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
func noMisusedPromisesCheckArguments(ctx *Context, node, predicateArgument *shimast.Node) {
|
|
440
|
+
expression, arguments, signatureKind := noMisusedPromisesCallParts(node)
|
|
441
|
+
if expression == nil || len(arguments) == 0 || noMisusedPromisesIsPromiseFinally(ctx.Checker, node, expression) {
|
|
442
|
+
return
|
|
443
|
+
}
|
|
444
|
+
calleeType := ctx.Checker.GetApparentType(ctx.Checker.GetTypeAtLocation(expression))
|
|
445
|
+
for index, argument := range arguments {
|
|
446
|
+
if argument == predicateArgument {
|
|
447
|
+
continue
|
|
448
|
+
}
|
|
449
|
+
acceptsThenable := false
|
|
450
|
+
acceptsVoid := false
|
|
451
|
+
classify := func(target *shimchecker.Type) {
|
|
452
|
+
if target == nil {
|
|
453
|
+
return
|
|
454
|
+
}
|
|
455
|
+
if noMisusedPromisesIsThenableReturningFunctionType(ctx.Checker, node, target) {
|
|
456
|
+
acceptsThenable = true
|
|
457
|
+
} else if noMisusedPromisesIsVoidReturningFunctionType(ctx.Checker, node, target) {
|
|
458
|
+
acceptsVoid = true
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
for _, part := range promiseUnionParts(calleeType) {
|
|
462
|
+
for _, signature := range ctx.Checker.GetSignaturesOfType(part, signatureKind) {
|
|
463
|
+
classify(noMisusedPromisesParameterTypeAt(ctx.Checker, expression, signature, index))
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
// The declared signatures are authoritative. Contextual typing is only a
|
|
467
|
+
// fallback for checker-instantiated positions that are not recoverable
|
|
468
|
+
// from those signatures. Classifying it eagerly would mistake an inferred
|
|
469
|
+
// `T = () => Promise<void>` for permission when the declaration says
|
|
470
|
+
// `T extends () => void`.
|
|
471
|
+
if !acceptsThenable && !acceptsVoid {
|
|
472
|
+
classify(ctx.Checker.GetContextualTypeForArgumentAtIndex(node, index))
|
|
473
|
+
}
|
|
474
|
+
if acceptsVoid && !acceptsThenable && noMisusedPromisesReturnsThenable(ctx.Checker, argument) {
|
|
475
|
+
ctx.Report(argument, "Promise returned in a function argument where a void return was expected.")
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
func noMisusedPromisesCallParts(node *shimast.Node) (*shimast.Node, []*shimast.Node, shimchecker.SignatureKind) {
|
|
481
|
+
if node.Kind == shimast.KindCallExpression {
|
|
482
|
+
call := node.AsCallExpression()
|
|
483
|
+
if call == nil {
|
|
484
|
+
return nil, nil, shimchecker.SignatureKindCall
|
|
485
|
+
}
|
|
486
|
+
if call.Arguments == nil {
|
|
487
|
+
return call.Expression, nil, shimchecker.SignatureKindCall
|
|
488
|
+
}
|
|
489
|
+
return call.Expression, call.Arguments.Nodes, shimchecker.SignatureKindCall
|
|
490
|
+
}
|
|
491
|
+
if node.Kind == shimast.KindNewExpression {
|
|
492
|
+
construct := node.AsNewExpression()
|
|
493
|
+
if construct == nil {
|
|
494
|
+
return nil, nil, shimchecker.SignatureKindConstruct
|
|
495
|
+
}
|
|
496
|
+
if construct.Arguments == nil {
|
|
497
|
+
return construct.Expression, nil, shimchecker.SignatureKindConstruct
|
|
498
|
+
}
|
|
499
|
+
return construct.Expression, construct.Arguments.Nodes, shimchecker.SignatureKindConstruct
|
|
500
|
+
}
|
|
501
|
+
return nil, nil, shimchecker.SignatureKindCall
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
func noMisusedPromisesParameterTypeAt(
|
|
505
|
+
checker *shimchecker.Checker,
|
|
506
|
+
location *shimast.Node,
|
|
507
|
+
signature *shimchecker.Signature,
|
|
508
|
+
index int,
|
|
509
|
+
) *shimchecker.Type {
|
|
510
|
+
parameters := shimchecker.Signature_parameters(signature)
|
|
511
|
+
if len(parameters) == 0 {
|
|
512
|
+
return nil
|
|
513
|
+
}
|
|
514
|
+
last := len(parameters) - 1
|
|
515
|
+
if shimchecker.Signature_hasRestParameter(signature) && index >= last {
|
|
516
|
+
restType := constrainedPromiseType(
|
|
517
|
+
checker,
|
|
518
|
+
shimchecker.Checker_getTypeOfSymbolAtLocation(checker, parameters[last], location),
|
|
519
|
+
)
|
|
520
|
+
if restType != nil && shimchecker.IsTupleType(restType) {
|
|
521
|
+
elements := checker.GetTypeArguments(restType)
|
|
522
|
+
offset := index - last
|
|
523
|
+
if offset >= len(elements) {
|
|
524
|
+
return nil
|
|
525
|
+
}
|
|
526
|
+
return elements[offset]
|
|
527
|
+
}
|
|
528
|
+
return shimchecker.Checker_getRestTypeOfSignature(checker, signature)
|
|
529
|
+
}
|
|
530
|
+
if index >= len(parameters) {
|
|
531
|
+
return nil
|
|
532
|
+
}
|
|
533
|
+
return shimchecker.Checker_getTypeOfSymbolAtLocation(checker, parameters[index], location)
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
func noMisusedPromisesIsPromiseFinally(checker *shimchecker.Checker, node, expression *shimast.Node) bool {
|
|
537
|
+
if node.Kind != shimast.KindCallExpression {
|
|
538
|
+
return false
|
|
539
|
+
}
|
|
540
|
+
receiver, method, ok := promisePropertyAccessParts(expression)
|
|
541
|
+
if !ok || method != "finally" || receiver == nil {
|
|
542
|
+
return false
|
|
543
|
+
}
|
|
544
|
+
return isPromiseTypedExpression(checker, checker.GetTypeAtLocation(receiver))
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
func noMisusedPromisesCheckSpread(ctx *Context, node *shimast.Node) {
|
|
548
|
+
spread := node.AsSpreadAssignment()
|
|
549
|
+
if spread != nil && spread.Expression != nil && noMisusedPromisesIsSometimesThenable(ctx.Checker, spread.Expression) {
|
|
550
|
+
ctx.Report(spread.Expression, "Expected a non-Promise value to be spread in an object.")
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
func noMisusedPromisesIsSometimesThenable(checker *shimchecker.Checker, node *shimast.Node) bool {
|
|
555
|
+
if checker == nil || node == nil {
|
|
556
|
+
return false
|
|
557
|
+
}
|
|
558
|
+
valueType := checker.GetApparentType(constrainedPromiseType(checker, checker.GetTypeAtLocation(node)))
|
|
559
|
+
for _, part := range promiseUnionParts(valueType) {
|
|
560
|
+
if isThenableAtLocation(checker, node, part) {
|
|
561
|
+
return true
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return false
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
func noMisusedPromisesCheckVariable(ctx *Context, node *shimast.Node) {
|
|
568
|
+
declaration := node.AsVariableDeclaration()
|
|
569
|
+
if declaration == nil || declaration.Initializer == nil {
|
|
570
|
+
return
|
|
571
|
+
}
|
|
572
|
+
if noMisusedPromisesIsSyncUsingDeclaration(node) && noMisusedPromisesHasThenableDispose(ctx.Checker, declaration.Initializer) {
|
|
573
|
+
ctx.Report(declaration.Initializer, "Synchronous disposal cannot observe a Promise returned by `Symbol.dispose`.")
|
|
574
|
+
return
|
|
575
|
+
}
|
|
576
|
+
if declaration.Type == nil || declaration.Name() == nil {
|
|
577
|
+
return
|
|
578
|
+
}
|
|
579
|
+
targetType := ctx.Checker.GetTypeAtLocation(declaration.Name())
|
|
580
|
+
if noMisusedPromisesHasVoidDispose(ctx.Checker, declaration.Name(), targetType) &&
|
|
581
|
+
noMisusedPromisesHasThenableDispose(ctx.Checker, declaration.Initializer) {
|
|
582
|
+
ctx.Report(declaration.Initializer, "Promise-returning `Symbol.dispose` assigned where synchronous disposal was expected.")
|
|
583
|
+
return
|
|
584
|
+
}
|
|
585
|
+
if noMisusedPromisesIsVoidReturningFunctionType(ctx.Checker, declaration.Initializer, targetType) &&
|
|
586
|
+
noMisusedPromisesReturnsThenable(ctx.Checker, declaration.Initializer) {
|
|
587
|
+
ctx.Report(declaration.Initializer, "Promise-returning function assigned to a variable where a void return was expected.")
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
func noMisusedPromisesIsSyncUsingDeclaration(node *shimast.Node) bool {
|
|
592
|
+
if node == nil || node.Parent == nil || node.Parent.Kind != shimast.KindVariableDeclarationList {
|
|
593
|
+
return false
|
|
594
|
+
}
|
|
595
|
+
flags := shimast.GetCombinedNodeFlags(node.Parent) & shimast.NodeFlagsBlockScoped
|
|
596
|
+
return flags == shimast.NodeFlagsUsing
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
func noMisusedPromisesHasThenableDispose(checker *shimchecker.Checker, initializer *shimast.Node) bool {
|
|
600
|
+
if checker == nil || initializer == nil {
|
|
601
|
+
return false
|
|
602
|
+
}
|
|
603
|
+
propertyName := shimchecker.Checker_getPropertyNameForKnownSymbolName(checker, "dispose")
|
|
604
|
+
if propertyName == "" {
|
|
605
|
+
return false
|
|
606
|
+
}
|
|
607
|
+
valueType := checker.GetApparentType(checker.GetTypeAtLocation(initializer))
|
|
608
|
+
for _, part := range promiseUnionParts(valueType) {
|
|
609
|
+
property := checker.GetPropertyOfType(part, propertyName)
|
|
610
|
+
if property == nil {
|
|
611
|
+
continue
|
|
612
|
+
}
|
|
613
|
+
propertyType := shimchecker.Checker_getTypeOfSymbolAtLocation(checker, property, initializer)
|
|
614
|
+
if noMisusedPromisesIsThenableReturningFunctionType(checker, initializer, propertyType) {
|
|
615
|
+
return true
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return false
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
func noMisusedPromisesHasVoidDispose(
|
|
622
|
+
checker *shimchecker.Checker,
|
|
623
|
+
location *shimast.Node,
|
|
624
|
+
valueType *shimchecker.Type,
|
|
625
|
+
) bool {
|
|
626
|
+
if checker == nil || location == nil || valueType == nil {
|
|
627
|
+
return false
|
|
628
|
+
}
|
|
629
|
+
propertyName := shimchecker.Checker_getPropertyNameForKnownSymbolName(checker, "dispose")
|
|
630
|
+
if propertyName == "" {
|
|
631
|
+
return false
|
|
632
|
+
}
|
|
633
|
+
valueType = checker.GetApparentType(constrainedPromiseType(checker, valueType))
|
|
634
|
+
for _, part := range promiseUnionParts(valueType) {
|
|
635
|
+
property := checker.GetPropertyOfType(part, propertyName)
|
|
636
|
+
if property == nil {
|
|
637
|
+
continue
|
|
638
|
+
}
|
|
639
|
+
propertyType := shimchecker.Checker_getTypeOfSymbolAtLocation(checker, property, location)
|
|
640
|
+
if noMisusedPromisesIsVoidReturningFunctionType(checker, location, propertyType) {
|
|
641
|
+
return true
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
return false
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
func noMisusedPromisesCheckProperty(ctx *Context, node *shimast.Node) {
|
|
648
|
+
if node.Parent == nil || node.Parent.Kind != shimast.KindObjectLiteralExpression {
|
|
649
|
+
return
|
|
650
|
+
}
|
|
651
|
+
var value *shimast.Node
|
|
652
|
+
switch node.Kind {
|
|
653
|
+
case shimast.KindPropertyAssignment:
|
|
654
|
+
if property := node.AsPropertyAssignment(); property != nil {
|
|
655
|
+
value = property.Initializer
|
|
656
|
+
}
|
|
657
|
+
case shimast.KindShorthandPropertyAssignment:
|
|
658
|
+
if property := node.AsShorthandPropertyAssignment(); property != nil {
|
|
659
|
+
value = property.Name()
|
|
660
|
+
}
|
|
661
|
+
case shimast.KindMethodDeclaration:
|
|
662
|
+
if name := node.Name(); name != nil && name.Kind == shimast.KindComputedPropertyName {
|
|
663
|
+
return
|
|
664
|
+
}
|
|
665
|
+
value = node
|
|
666
|
+
}
|
|
667
|
+
if value == nil {
|
|
668
|
+
return
|
|
669
|
+
}
|
|
670
|
+
targetType := ctx.Checker.GetContextualTypeForObjectLiteralElement(node, 0)
|
|
671
|
+
if noMisusedPromisesIsVoidReturningFunctionType(ctx.Checker, value, targetType) &&
|
|
672
|
+
noMisusedPromisesReturnsThenable(ctx.Checker, value) {
|
|
673
|
+
ctx.Report(value, "Promise-returning function provided to a property where a void return was expected.")
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
func noMisusedPromisesCheckReturn(ctx *Context, node *shimast.Node) {
|
|
678
|
+
statement := node.AsReturnStatement()
|
|
679
|
+
if statement == nil || statement.Expression == nil {
|
|
680
|
+
return
|
|
681
|
+
}
|
|
682
|
+
targetType := ctx.Checker.GetContextualType(statement.Expression, 0)
|
|
683
|
+
if noMisusedPromisesIsVoidReturningFunctionType(ctx.Checker, statement.Expression, targetType) &&
|
|
684
|
+
noMisusedPromisesReturnsThenable(ctx.Checker, statement.Expression) {
|
|
685
|
+
ctx.Report(statement.Expression, "Promise-returning function returned where a void return was expected.")
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
func noMisusedPromisesCheckAttribute(ctx *Context, node *shimast.Node) {
|
|
690
|
+
attribute := node.AsJsxAttribute()
|
|
691
|
+
if attribute == nil || attribute.Initializer == nil || attribute.Initializer.Kind != shimast.KindJsxExpression {
|
|
692
|
+
return
|
|
693
|
+
}
|
|
694
|
+
container := attribute.Initializer.AsJsxExpression()
|
|
695
|
+
if container == nil || container.Expression == nil {
|
|
696
|
+
return
|
|
697
|
+
}
|
|
698
|
+
targetType := ctx.Checker.GetContextualTypeForJsxAttribute(node)
|
|
699
|
+
if noMisusedPromisesIsVoidReturningFunctionType(ctx.Checker, container.Expression, targetType) &&
|
|
700
|
+
noMisusedPromisesReturnsThenable(ctx.Checker, container.Expression) {
|
|
701
|
+
ctx.Report(container.Expression, "Promise-returning function provided to an attribute where a void return was expected.")
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
func noMisusedPromisesCheckInheritedMethods(ctx *Context, node *shimast.Node) {
|
|
706
|
+
members, heritage := noMisusedPromisesClassParts(node)
|
|
707
|
+
for _, member := range members {
|
|
708
|
+
if member == nil || member.Name() == nil || hasModifier(member, shimast.KindStaticKeyword) ||
|
|
709
|
+
!noMisusedPromisesReturnsThenable(ctx.Checker, member) {
|
|
710
|
+
continue
|
|
711
|
+
}
|
|
712
|
+
name, ok := noUnsafeAssignmentPropertyName(member.Name())
|
|
713
|
+
if !ok {
|
|
714
|
+
continue
|
|
715
|
+
}
|
|
716
|
+
for _, typeNode := range heritage {
|
|
717
|
+
baseType := ctx.Checker.GetTypeAtLocation(typeNode)
|
|
718
|
+
property := ctx.Checker.GetPropertyOfType(baseType, name)
|
|
719
|
+
if property == nil {
|
|
720
|
+
continue
|
|
721
|
+
}
|
|
722
|
+
targetType := shimchecker.Checker_getTypeOfSymbolAtLocation(ctx.Checker, property, member)
|
|
723
|
+
if noMisusedPromisesIsVoidReturningFunctionType(ctx.Checker, member, targetType) {
|
|
724
|
+
ctx.Report(member, "Promise-returning method overrides an inherited method where a void return was expected.")
|
|
725
|
+
break
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
func noMisusedPromisesClassParts(node *shimast.Node) ([]*shimast.Node, []*shimast.Node) {
|
|
732
|
+
var members *shimast.NodeList
|
|
733
|
+
var clauses *shimast.NodeList
|
|
734
|
+
switch node.Kind {
|
|
735
|
+
case shimast.KindClassDeclaration:
|
|
736
|
+
if declaration := node.AsClassDeclaration(); declaration != nil {
|
|
737
|
+
members = declaration.Members
|
|
738
|
+
clauses = declaration.HeritageClauses
|
|
739
|
+
}
|
|
740
|
+
case shimast.KindClassExpression:
|
|
741
|
+
if declaration := node.AsClassExpression(); declaration != nil {
|
|
742
|
+
members = declaration.Members
|
|
743
|
+
clauses = declaration.HeritageClauses
|
|
744
|
+
}
|
|
745
|
+
case shimast.KindInterfaceDeclaration:
|
|
746
|
+
if declaration := node.AsInterfaceDeclaration(); declaration != nil {
|
|
747
|
+
members = declaration.Members
|
|
748
|
+
clauses = declaration.HeritageClauses
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
var memberNodes []*shimast.Node
|
|
752
|
+
if members != nil {
|
|
753
|
+
memberNodes = members.Nodes
|
|
754
|
+
}
|
|
755
|
+
heritage := make([]*shimast.Node, 0)
|
|
756
|
+
if clauses != nil {
|
|
757
|
+
for _, clauseNode := range clauses.Nodes {
|
|
758
|
+
clause := clauseNode.AsHeritageClause()
|
|
759
|
+
if clause != nil && clause.Types != nil {
|
|
760
|
+
heritage = append(heritage, clause.Types.Nodes...)
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return memberNodes, heritage
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
func noMisusedPromisesReturnsThenable(checker *shimchecker.Checker, node *shimast.Node) bool {
|
|
768
|
+
if checker == nil || node == nil {
|
|
769
|
+
return false
|
|
770
|
+
}
|
|
771
|
+
valueType := checker.GetApparentType(checker.GetTypeAtLocation(stripParens(node)))
|
|
772
|
+
return noMisusedPromisesIsThenableReturningFunctionType(checker, node, valueType)
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
func noMisusedPromisesIsThenableReturningFunctionType(
|
|
776
|
+
checker *shimchecker.Checker,
|
|
777
|
+
location *shimast.Node,
|
|
778
|
+
valueType *shimchecker.Type,
|
|
779
|
+
) bool {
|
|
780
|
+
if checker == nil || valueType == nil {
|
|
781
|
+
return false
|
|
782
|
+
}
|
|
783
|
+
valueType = constrainedPromiseType(checker, valueType)
|
|
784
|
+
for _, part := range promiseUnionParts(valueType) {
|
|
785
|
+
for _, signature := range checker.GetSignaturesOfType(part, shimchecker.SignatureKindCall) {
|
|
786
|
+
returnType := constrainedPromiseType(checker, checker.GetReturnTypeOfSignature(signature))
|
|
787
|
+
if isThenableAtLocation(checker, location, returnType) {
|
|
788
|
+
return true
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return false
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
func noMisusedPromisesIsVoidReturningFunctionType(
|
|
796
|
+
checker *shimchecker.Checker,
|
|
797
|
+
location *shimast.Node,
|
|
798
|
+
valueType *shimchecker.Type,
|
|
799
|
+
) bool {
|
|
800
|
+
if checker == nil || valueType == nil {
|
|
801
|
+
return false
|
|
802
|
+
}
|
|
803
|
+
valueType = constrainedPromiseType(checker, valueType)
|
|
804
|
+
hadVoid := false
|
|
805
|
+
for _, part := range promiseUnionParts(valueType) {
|
|
806
|
+
for _, signature := range checker.GetSignaturesOfType(part, shimchecker.SignatureKindCall) {
|
|
807
|
+
returnType := constrainedPromiseType(checker, checker.GetReturnTypeOfSignature(signature))
|
|
808
|
+
if isThenableAtLocation(checker, location, returnType) {
|
|
809
|
+
return false
|
|
810
|
+
}
|
|
811
|
+
if returnType != nil && returnType.Flags()&shimchecker.TypeFlagsVoid != 0 {
|
|
812
|
+
hadVoid = true
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return hadVoid
|
|
817
|
+
}
|