@@ -2188,6 +2188,244 @@ type (
2188
2188
JsxAttributeList = NodeList // NodeList[*JsxAttributeLike]
2189
2189
)
2190
2190
2191
+ func IsWriteOnlyAccess (node * Node ) bool {
2192
+ return accessKind (node ) == AccessKindWrite
2193
+ }
2194
+
2195
+ func IsWriteAccess (node * Node ) bool {
2196
+ return accessKind (node ) != AccessKindRead
2197
+ }
2198
+
2199
+ func IsWriteAccessForReference (node * Node ) bool {
2200
+ decl := getDeclarationFromName (node )
2201
+ return (decl != nil && declarationIsWriteAccess (decl )) || node .Kind == KindDefaultKeyword || IsWriteAccess (node )
2202
+ }
2203
+
2204
+ func getDeclarationFromName (name * Node ) * Declaration {
2205
+ if name == nil || name .Parent == nil {
2206
+ return nil
2207
+ }
2208
+ parent := name .Parent
2209
+ switch name .Kind {
2210
+ case KindStringLiteral , KindNoSubstitutionTemplateLiteral , KindNumericLiteral :
2211
+ if IsComputedPropertyName (parent ) {
2212
+ return parent .Parent
2213
+ }
2214
+ fallthrough
2215
+ case KindIdentifier :
2216
+ if IsDeclaration (parent ) {
2217
+ if parent .Name () == name {
2218
+ return parent
2219
+ }
2220
+ return nil
2221
+ }
2222
+ if IsQualifiedName (parent ) {
2223
+ tag := parent .Parent
2224
+ if IsJSDocParameterTag (tag ) && tag .Name () == parent {
2225
+ return tag
2226
+ }
2227
+ return nil
2228
+ }
2229
+ binExp := parent .Parent
2230
+ if IsBinaryExpression (binExp ) && GetAssignmentDeclarationKind (binExp .AsBinaryExpression ()) != JSDeclarationKindNone {
2231
+ // (binExp.left as BindableStaticNameExpression).symbol || binExp.symbol
2232
+ leftHasSymbol := false
2233
+ if binExp .AsBinaryExpression ().Left != nil && binExp .AsBinaryExpression ().Left .Symbol () != nil {
2234
+ leftHasSymbol = true
2235
+ }
2236
+ if leftHasSymbol || binExp .Symbol () != nil {
2237
+ if GetNameOfDeclaration (binExp .AsNode ()) == name {
2238
+ return binExp .AsNode ()
2239
+ }
2240
+ }
2241
+ }
2242
+ case KindPrivateIdentifier :
2243
+ if IsDeclaration (parent ) && parent .Name () == name {
2244
+ return parent
2245
+ }
2246
+ }
2247
+ return nil
2248
+ }
2249
+
2250
+ func declarationIsWriteAccess (decl * Node ) bool {
2251
+ if decl == nil {
2252
+ return false
2253
+ }
2254
+ // Consider anything in an ambient declaration to be a write access since it may be coming from JS.
2255
+ if decl .Flags & NodeFlagsAmbient != 0 {
2256
+ return true
2257
+ }
2258
+
2259
+ switch decl .Kind {
2260
+ case KindBinaryExpression ,
2261
+ KindBindingElement ,
2262
+ KindClassDeclaration ,
2263
+ KindClassExpression ,
2264
+ KindDefaultKeyword ,
2265
+ KindEnumDeclaration ,
2266
+ KindEnumMember ,
2267
+ KindExportSpecifier ,
2268
+ KindImportClause , // default import
2269
+ KindImportEqualsDeclaration ,
2270
+ KindImportSpecifier ,
2271
+ KindInterfaceDeclaration ,
2272
+ KindJSDocCallbackTag ,
2273
+ KindJSDocTypedefTag ,
2274
+ KindJsxAttribute ,
2275
+ KindModuleDeclaration ,
2276
+ KindNamespaceExportDeclaration ,
2277
+ KindNamespaceImport ,
2278
+ KindNamespaceExport ,
2279
+ KindParameter ,
2280
+ KindShorthandPropertyAssignment ,
2281
+ KindTypeAliasDeclaration ,
2282
+ KindTypeParameter :
2283
+ return true
2284
+
2285
+ case KindPropertyAssignment :
2286
+ // In `({ x: y } = 0);`, `x` is not a write access.
2287
+ return ! IsArrayLiteralOrObjectLiteralDestructuringPattern (decl .Parent )
2288
+
2289
+ case KindFunctionDeclaration , KindFunctionExpression , KindConstructor , KindMethodDeclaration , KindGetAccessor , KindSetAccessor :
2290
+ // functions considered write if they provide a value (have a body)
2291
+ switch decl .Kind {
2292
+ case KindFunctionDeclaration :
2293
+ return decl .AsFunctionDeclaration ().Body != nil
2294
+ case KindFunctionExpression :
2295
+ return decl .AsFunctionExpression ().Body != nil
2296
+ case KindConstructor :
2297
+ // constructor node stores body on the parent? treat same as others
2298
+ return decl .AsConstructorDeclaration ().Body != nil
2299
+ case KindMethodDeclaration :
2300
+ return decl .AsMethodDeclaration ().Body != nil
2301
+ case KindGetAccessor :
2302
+ return decl .AsGetAccessorDeclaration ().Body != nil
2303
+ case KindSetAccessor :
2304
+ return decl .AsSetAccessorDeclaration ().Body != nil
2305
+ }
2306
+ return false
2307
+
2308
+ case KindVariableDeclaration , KindPropertyDeclaration :
2309
+ // variable/property write if initializer present or is in catch clause
2310
+ var hasInit bool
2311
+ switch decl .Kind {
2312
+ case KindVariableDeclaration :
2313
+ hasInit = decl .AsVariableDeclaration ().Initializer != nil
2314
+ case KindPropertyDeclaration :
2315
+ hasInit = decl .AsPropertyDeclaration ().Initializer != nil
2316
+ }
2317
+ return hasInit || IsCatchClause (decl .Parent )
2318
+
2319
+ case KindMethodSignature , KindPropertySignature , KindJSDocPropertyTag , KindJSDocParameterTag :
2320
+ return false
2321
+
2322
+ default :
2323
+ // preserve TS behavior: crash on unexpected kinds
2324
+ panic ("Unhandled case in declarationIsWriteAccess" )
2325
+ }
2326
+ }
2327
+
2328
+ func IsArrayLiteralOrObjectLiteralDestructuringPattern (node * Node ) bool {
2329
+ if ! (IsArrayLiteralExpression (node ) || IsObjectLiteralExpression (node )) {
2330
+ return false
2331
+ }
2332
+ parent := node .Parent
2333
+ // [a,b,c] from:
2334
+ // [a, b, c] = someExpression;
2335
+ if IsBinaryExpression (parent ) && parent .AsBinaryExpression ().Left == node && parent .AsBinaryExpression ().OperatorToken .Kind == KindEqualsToken {
2336
+ return true
2337
+ }
2338
+ // [a, b, c] from:
2339
+ // for([a, b, c] of expression)
2340
+ if IsForOfStatement (parent ) && parent .Initializer () == node {
2341
+ return true
2342
+ }
2343
+ // {x, a: {a, b, c} } = someExpression
2344
+ if IsPropertyAssignment (parent ) {
2345
+ return IsArrayLiteralOrObjectLiteralDestructuringPattern (parent .Parent )
2346
+ }
2347
+ // [a, b, c] of
2348
+ // [x, [a, b, c] ] = someExpression
2349
+ return IsArrayLiteralOrObjectLiteralDestructuringPattern (parent )
2350
+ }
2351
+
2352
+ func accessKind (node * Node ) AccessKind {
2353
+ parent := node .Parent
2354
+ switch parent .Kind {
2355
+ case KindParenthesizedExpression :
2356
+ return accessKind (parent )
2357
+ case KindPrefixUnaryExpression :
2358
+ operator := parent .AsPrefixUnaryExpression ().Operator
2359
+ if operator == KindPlusPlusToken || operator == KindMinusMinusToken {
2360
+ return AccessKindReadWrite
2361
+ }
2362
+ return AccessKindRead
2363
+ case KindPostfixUnaryExpression :
2364
+ operator := parent .AsPostfixUnaryExpression ().Operator
2365
+ if operator == KindPlusPlusToken || operator == KindMinusMinusToken {
2366
+ return AccessKindReadWrite
2367
+ }
2368
+ return AccessKindRead
2369
+ case KindBinaryExpression :
2370
+ if parent .AsBinaryExpression ().Left == node {
2371
+ operator := parent .AsBinaryExpression ().OperatorToken
2372
+ if IsAssignmentOperator (operator .Kind ) {
2373
+ if operator .Kind == KindEqualsToken {
2374
+ return AccessKindWrite
2375
+ }
2376
+ return AccessKindReadWrite
2377
+ }
2378
+ }
2379
+ return AccessKindRead
2380
+ case KindPropertyAccessExpression :
2381
+ if parent .AsPropertyAccessExpression ().Name () != node {
2382
+ return AccessKindRead
2383
+ }
2384
+ return accessKind (parent )
2385
+ case KindPropertyAssignment :
2386
+ parentAccess := accessKind (parent .Parent )
2387
+ // In `({ x: varname }) = { x: 1 }`, the left `x` is a read, the right `x` is a write.
2388
+ if node == parent .AsPropertyAssignment ().Name () {
2389
+ return reverseAccessKind (parentAccess )
2390
+ }
2391
+ return parentAccess
2392
+ case KindShorthandPropertyAssignment :
2393
+ // Assume it's the local variable being accessed, since we don't check public properties for --noUnusedLocals.
2394
+ if node == parent .AsShorthandPropertyAssignment ().ObjectAssignmentInitializer {
2395
+ return AccessKindRead
2396
+ }
2397
+ return accessKind (parent .Parent )
2398
+ case KindArrayLiteralExpression :
2399
+ return accessKind (parent )
2400
+ case KindForInStatement , KindForOfStatement :
2401
+ if node == parent .AsForInOrOfStatement ().Initializer {
2402
+ return AccessKindWrite
2403
+ }
2404
+ return AccessKindRead
2405
+ }
2406
+ return AccessKindRead
2407
+ }
2408
+
2409
+ func reverseAccessKind (a AccessKind ) AccessKind {
2410
+ switch a {
2411
+ case AccessKindRead :
2412
+ return AccessKindWrite
2413
+ case AccessKindWrite :
2414
+ return AccessKindRead
2415
+ case AccessKindReadWrite :
2416
+ return AccessKindReadWrite
2417
+ }
2418
+ panic ("Unhandled case in reverseAccessKind" )
2419
+ }
2420
+
2421
+ type AccessKind int32
2422
+
2423
+ const (
2424
+ AccessKindRead AccessKind = iota // Only reads from a variable
2425
+ AccessKindWrite // Only writes to a variable without ever reading it. E.g.: `x=1;`.
2426
+ AccessKindReadWrite // Reads from and writes to a variable. E.g.: `f(x++);`, `x/=1`.
2427
+ )
2428
+
2191
2429
// DeclarationBase
2192
2430
2193
2431
type DeclarationBase struct {
@@ -3191,6 +3429,10 @@ func (node *ThrowStatement) computeSubtreeFacts() SubtreeFacts {
3191
3429
return propagateSubtreeFacts (node .Expression )
3192
3430
}
3193
3431
3432
+ func IsThrowStatement (node * Node ) bool {
3433
+ return node .Kind == KindThrowStatement
3434
+ }
3435
+
3194
3436
// TryStatement
3195
3437
3196
3438
type TryStatement struct {
@@ -6153,6 +6395,10 @@ func (node *YieldExpression) computeSubtreeFacts() SubtreeFacts {
6153
6395
return propagateSubtreeFacts (node .Expression ) | SubtreeContainsForAwaitOrAsyncGenerator
6154
6396
}
6155
6397
6398
+ func IsYieldExpression (node * Node ) bool {
6399
+ return node .Kind == KindYieldExpression
6400
+ }
6401
+
6156
6402
// ArrowFunction
6157
6403
6158
6404
type ArrowFunction struct {
0 commit comments