Skip to content

Commit b55c80c

Browse files
johnfav03gabrittoiisaduan
authored
Document highlights (#1699)
Co-authored-by: Gabriela Araujo Britto <[email protected]> Co-authored-by: Isabel Duan <[email protected]>
1 parent be5de2a commit b55c80c

File tree

226 files changed

+14638
-147
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

226 files changed

+14638
-147
lines changed

internal/ast/ast.go

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,6 +2188,244 @@ type (
21882188
JsxAttributeList = NodeList // NodeList[*JsxAttributeLike]
21892189
)
21902190

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+
21912429
// DeclarationBase
21922430

21932431
type DeclarationBase struct {
@@ -3191,6 +3429,10 @@ func (node *ThrowStatement) computeSubtreeFacts() SubtreeFacts {
31913429
return propagateSubtreeFacts(node.Expression)
31923430
}
31933431

3432+
func IsThrowStatement(node *Node) bool {
3433+
return node.Kind == KindThrowStatement
3434+
}
3435+
31943436
// TryStatement
31953437

31963438
type TryStatement struct {
@@ -6153,6 +6395,10 @@ func (node *YieldExpression) computeSubtreeFacts() SubtreeFacts {
61536395
return propagateSubtreeFacts(node.Expression) | SubtreeContainsForAwaitOrAsyncGenerator
61546396
}
61556397

6398+
func IsYieldExpression(node *Node) bool {
6399+
return node.Kind == KindYieldExpression
6400+
}
6401+
61566402
// ArrowFunction
61576403

61586404
type ArrowFunction struct {

internal/checker/checker.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10873,15 +10873,15 @@ func (c *Checker) checkPropertyAccessExpressionOrQualifiedName(node *ast.Node, l
1087310873
c.checkPropertyNotUsedBeforeDeclaration(prop, node, right)
1087410874
c.markPropertyAsReferenced(prop, node, c.isSelfTypeAccess(left, parentSymbol))
1087510875
c.symbolNodeLinks.Get(node).resolvedSymbol = prop
10876-
c.checkPropertyAccessibility(node, left.Kind == ast.KindSuperKeyword, isWriteAccess(node), apparentType, prop)
10876+
c.checkPropertyAccessibility(node, left.Kind == ast.KindSuperKeyword, ast.IsWriteAccess(node), apparentType, prop)
1087710877
if c.isAssignmentToReadonlyEntity(node, prop, assignmentKind) {
1087810878
c.error(right, diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, right.Text())
1087910879
return c.errorType
1088010880
}
1088110881
switch {
1088210882
case c.isThisPropertyAccessInConstructor(node, prop):
1088310883
propType = c.autoType
10884-
case writeOnly || isWriteOnlyAccess(node):
10884+
case writeOnly || ast.IsWriteOnlyAccess(node):
1088510885
propType = c.getWriteTypeOfSymbol(prop)
1088610886
default:
1088710887
propType = c.getTypeOfSymbol(prop)
@@ -13284,7 +13284,7 @@ func (c *Checker) getResolvedSymbol(node *ast.Node) *ast.Symbol {
1328413284
var symbol *ast.Symbol
1328513285
if !ast.NodeIsMissing(node) {
1328613286
symbol = c.resolveName(node, node.AsIdentifier().Text, ast.SymbolFlagsValue|ast.SymbolFlagsExportValue,
13287-
c.getCannotFindNameDiagnosticForName(node), !isWriteOnlyAccess(node), false /*excludeGlobals*/)
13287+
c.getCannotFindNameDiagnosticForName(node), !ast.IsWriteOnlyAccess(node), false /*excludeGlobals*/)
1328813288
}
1328913289
links.resolvedSymbol = core.OrElse(symbol, c.unknownSymbol)
1329013290
}
@@ -15719,9 +15719,9 @@ func (c *Checker) GetTypeOfSymbolAtLocation(symbol *ast.Symbol, location *ast.No
1571915719
if ast.IsRightSideOfQualifiedNameOrPropertyAccess(location) {
1572015720
location = location.Parent
1572115721
}
15722-
if ast.IsExpressionNode(location) && (!ast.IsAssignmentTarget(location) || isWriteAccess(location)) {
15722+
if ast.IsExpressionNode(location) && (!ast.IsAssignmentTarget(location) || ast.IsWriteAccess(location)) {
1572315723
var t *Type
15724-
if isWriteAccess(location) && location.Kind == ast.KindPropertyAccessExpression {
15724+
if ast.IsWriteAccess(location) && location.Kind == ast.KindPropertyAccessExpression {
1572515725
t = c.checkPropertyAccessExpression(location, CheckModeNormal, true /*writeOnly*/)
1572615726
} else {
1572715727
t = c.getTypeOfExpression(location)
@@ -15739,7 +15739,7 @@ func (c *Checker) GetTypeOfSymbolAtLocation(symbol *ast.Symbol, location *ast.No
1573915739
// to it at the given location. Since we have no control flow information for the
1574015740
// hypothetical reference (control flow information is created and attached by the
1574115741
// binder), we simply return the declared type of the symbol.
15742-
if isRightSideOfAccessExpression(location) && isWriteAccess(location.Parent) {
15742+
if isRightSideOfAccessExpression(location) && ast.IsWriteAccess(location.Parent) {
1574315743
return c.getWriteTypeOfSymbol(symbol)
1574415744
}
1574515745
}
@@ -26711,7 +26711,7 @@ func (c *Checker) markPropertyAsReferenced(prop *ast.Symbol, nodeForCheckWriteOn
2671126711
if !hasPrivateModifier && !hasPrivateIdentifier {
2671226712
return
2671326713
}
26714-
if nodeForCheckWriteOnly != nil && isWriteOnlyAccess(nodeForCheckWriteOnly) && prop.Flags&ast.SymbolFlagsSetAccessor == 0 {
26714+
if nodeForCheckWriteOnly != nil && ast.IsWriteOnlyAccess(nodeForCheckWriteOnly) && prop.Flags&ast.SymbolFlagsSetAccessor == 0 {
2671526715
return
2671626716
}
2671726717
if isSelfTypeAccess {

internal/checker/services.go

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ func (c *Checker) GetPropertySymbolsFromContextualType(node *ast.Node, contextua
762762
//
763763
// [a] = [ property1, property2 ]
764764
func (c *Checker) GetPropertySymbolOfDestructuringAssignment(location *ast.Node) *ast.Symbol {
765-
if isArrayLiteralOrObjectLiteralDestructuringPattern(location.Parent.Parent) {
765+
if ast.IsArrayLiteralOrObjectLiteralDestructuringPattern(location.Parent.Parent) {
766766
// Get the type of the object or array literal and then look for property of given name in the type
767767
if typeOfObjectLiteral := c.getTypeOfAssignmentPattern(location.Parent.Parent); typeOfObjectLiteral != nil {
768768
return c.getPropertyOfType(typeOfObjectLiteral, location.Text())
@@ -809,27 +809,3 @@ func (c *Checker) getTypeOfAssignmentPattern(expr *ast.Node) *Type {
809809
elementType := core.OrElse(c.checkIteratedTypeOrElementType(IterationUseDestructuring, typeOfArrayLiteral, c.undefinedType, expr.Parent), c.errorType)
810810
return c.checkArrayLiteralDestructuringElementAssignment(node, typeOfArrayLiteral, slices.Index(node.AsArrayLiteralExpression().Elements.Nodes, expr), elementType, CheckModeNormal)
811811
}
812-
813-
func isArrayLiteralOrObjectLiteralDestructuringPattern(node *ast.Node) bool {
814-
if !(ast.IsArrayLiteralExpression(node) || ast.IsObjectLiteralExpression(node)) {
815-
return false
816-
}
817-
parent := node.Parent
818-
// [a,b,c] from:
819-
// [a, b, c] = someExpression;
820-
if ast.IsBinaryExpression(parent) && parent.AsBinaryExpression().Left == node && parent.AsBinaryExpression().OperatorToken.Kind == ast.KindEqualsToken {
821-
return true
822-
}
823-
// [a, b, c] from:
824-
// for([a, b, c] of expression)
825-
if ast.IsForOfStatement(parent) && parent.Initializer() == node {
826-
return true
827-
}
828-
// {x, a: {a, b, c} } = someExpression
829-
if ast.IsPropertyAssignment(parent) {
830-
return isArrayLiteralOrObjectLiteralDestructuringPattern(parent.Parent)
831-
}
832-
// [a, b, c] of
833-
// [x, [a, b, c] ] = someExpression
834-
return isArrayLiteralOrObjectLiteralDestructuringPattern(parent)
835-
}

0 commit comments

Comments
 (0)