Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var NoUnsafeAssignmentRule = rule.CreateRule(rule.Rule{ Name: "no-unsafe-assignment", Run: func(ctx rule.RuleContext, options any) rule.RuleListeners { compilerOptions := ctx.Program.Options() isNoImplicitThis := utils.IsStrictCompilerOptionEnabled( compilerOptions, compilerOptions.NoImplicitThis, ) var checkArrayDestructure func( receiverNode *ast.Node, senderType *checker.Type, senderNode *ast.Node, ) bool var checkObjectDestructure func( receiverNode *ast.Node, senderType *checker.Type, senderNode *ast.Node, ) bool checkObjectDestructure = func( receiverNode *ast.Node, senderType *checker.Type, senderNode *ast.Node, ) bool { propertySymbols := checker.Checker_getPropertiesOfType(ctx.TypeChecker, senderType) if propertySymbols == nil { return false } properties := make(map[string]*checker.Type, len(propertySymbols)) for _, property := range propertySymbols { properties[property.Name] = ctx.TypeChecker.GetTypeOfSymbolAtLocation(property, senderNode) } checkObjectProperty := func(propertyKey *ast.Node, propertyValue *ast.Node) bool { var key string if !ast.IsComputedPropertyName(propertyKey) { key = propertyKey.Text() } else if ast.IsLiteralExpression(propertyKey.Expression()) { key = propertyKey.Expression().Text() } else { return false } senderType, ok := properties[key] if !ok { return false } if utils.IsTypeAnyType(senderType) { ctx.ReportNode(propertyValue, buildUnsafeArrayPatternFromTupleMessage(senderType)) return true } else if ast.IsArrayBindingPattern(propertyValue) || ast.IsArrayLiteralExpression(propertyValue) { return checkArrayDestructure( propertyValue, senderType, senderNode, ) } else if ast.IsObjectBindingPattern(propertyValue) || ast.IsObjectLiteralExpression(propertyValue) { return checkObjectDestructure( propertyValue, senderType, senderNode, ) } return false } didReport := false if ast.IsObjectLiteralExpression(receiverNode) { for _, receiverProperty := range receiverNode.AsObjectLiteralExpression().Properties.Nodes { if ast.IsSpreadAssignment(receiverProperty) { continue } if (ast.IsPropertyAssignment(receiverProperty) && checkObjectProperty(receiverProperty.Name(), receiverProperty.Initializer())) || (ast.IsShorthandPropertyAssignment(receiverProperty) && checkObjectProperty(receiverProperty.Name(), receiverProperty.Name())) { didReport = true } } } else if ast.IsObjectBindingPattern(receiverNode) { for _, receiverProperty := range receiverNode.AsBindingPattern().Elements.Nodes { property := receiverProperty.AsBindingElement() if property.DotDotDotToken != nil { continue } propertyKey := property.PropertyName if propertyKey == nil { propertyKey = property.Name() } if checkObjectProperty(propertyKey, property.Name()) { didReport = true } } } return didReport } checkObjectDestructureHelper := func( receiverNode *ast.Node, senderNode *ast.Node, ) bool { if !ast.IsObjectBindingPattern(receiverNode) && !ast.IsObjectLiteralExpression(receiverNode) { return false } senderType := ctx.TypeChecker.GetTypeAtLocation(senderNode) return checkObjectDestructure(receiverNode, senderType, senderNode) } checkArrayDestructure = func( receiverNode *ast.Node, senderType *checker.Type, senderNode *ast.Node, ) bool { if utils.IsTypeAnyArrayType(senderType, ctx.TypeChecker) { ctx.ReportNode(receiverNode, buildUnsafeArrayPatternMessage(senderType)) return false } if !checker.IsTupleType(senderType) { return true } tupleElements := checker.Checker_getTypeArguments(ctx.TypeChecker, senderType) checkArrayElement := func(receiverElement *ast.Node, receiverIndex int) bool { if receiverElement == nil { return false } if receiverIndex >= len(tupleElements) { return false } senderType := tupleElements[receiverIndex] if utils.IsTypeAnyType(senderType) { ctx.ReportNode(receiverElement, buildUnsafeArrayPatternFromTupleMessage(senderType)) return true } else if ast.IsArrayBindingPattern(receiverElement) || ast.IsArrayLiteralExpression(receiverElement) { return checkArrayDestructure( receiverElement, senderType, senderNode, ) } else if ast.IsObjectBindingPattern(receiverElement) || ast.IsObjectLiteralExpression(receiverElement) { return checkObjectDestructure( receiverElement, senderType, senderNode, ) } return false } didReport := false if ast.IsArrayLiteralExpression(receiverNode) { for receiverIndex, receiverElement := range receiverNode.AsArrayLiteralExpression().Elements.Nodes { if ast.IsSpreadElement(receiverElement) { continue } if checkArrayElement(receiverElement, receiverIndex) { didReport = true } } } else if ast.IsArrayBindingPattern(receiverNode) { for receiverIndex, receiverElement := range receiverNode.AsBindingPattern().Elements.Nodes { elem := receiverElement.AsBindingElement() if elem.DotDotDotToken != nil { continue } if checkArrayElement(receiverElement.Name(), receiverIndex) { didReport = true } } } return didReport } checkArrayDestructureHelper := func( receiverNode *ast.Node, senderNode *ast.Node, ) bool { if !ast.IsArrayBindingPattern(receiverNode) && !ast.IsArrayLiteralExpression(receiverNode) { return false } senderType := ctx.TypeChecker.GetTypeAtLocation(senderNode) return checkArrayDestructure(receiverNode, senderType, senderNode) } checkAssignment := func( receiverNode *ast.Node, senderNode *ast.Node, reportingNode *ast.Node, compType comparisonType, ) bool { var receiverType *checker.Type if compType == comparisonTypeContextual { receiverType = utils.GetContextualType(ctx.TypeChecker, receiverNode) } if receiverType == nil { receiverType = ctx.TypeChecker.GetTypeAtLocation(receiverNode) } senderType := ctx.TypeChecker.GetTypeAtLocation(senderNode) if utils.IsTypeAnyType(senderType) { if utils.IsTypeUnknownType(receiverType) { return false } if !isNoImplicitThis { thisExpression := utils.GetThisExpression(senderNode) if thisExpression != nil && utils.IsTypeAnyType(utils.GetConstrainedTypeAtLocation(ctx.TypeChecker, thisExpression)) { ctx.ReportNode(reportingNode, buildAnyAssignmentThisMessage(senderType)) return true } } ctx.ReportNode(reportingNode, buildAnyAssignmentMessage(senderType)) return true } if compType == comparisonTypeNone { return false } receiver, sender, unsafe := utils.IsUnsafeAssignment( senderType, receiverType, ctx.TypeChecker, senderNode, ) if !unsafe { return false } ctx.ReportNode(reportingNode, buildUnsafeAssignmentMessage(ctx.TypeChecker, sender, receiver)) return true } getComparisonType := func( nodeWithTypeAnnotation *ast.Node, ) comparisonType { if nodeWithTypeAnnotation.Type() != nil { return comparisonTypeBasic } return comparisonTypeNone } checkAssignmentFull := func(id *ast.Node, init *ast.Node, node *ast.Node) { if id == nil || init == nil { return } didReport := checkAssignment( id, init, node, comparisonTypeBasic, ) if !didReport { didReport = checkArrayDestructureHelper(id, init) } if !didReport { checkObjectDestructureHelper(id, init) } } return rule.RuleListeners{ ast.KindPropertyDeclaration: func(node *ast.Node) { initializer := node.Initializer() if initializer == nil { return } checkAssignment(node.Name(), initializer, node, getComparisonType(node)) }, ast.KindBinaryExpression: func(node *ast.Node) { if !ast.IsAssignmentExpression(node, true) { return } expr := node.AsBinaryExpression() checkAssignmentFull(expr.Left, expr.Right, node) }, ast.KindBindingElement: func(node *ast.Node) { checkAssignmentFull(node.Name(), node.Initializer(), node) }, ast.KindParameter: func(node *ast.Node) { checkAssignmentFull(node.Name(), node.Initializer(), node) }, ast.KindShorthandPropertyAssignment: func(node *ast.Node) { assignment := node.AsShorthandPropertyAssignment() checkAssignmentFull(assignment.Name(), assignment.ObjectAssignmentInitializer, node) }, ast.KindVariableDeclaration: func(node *ast.Node) { init := node.Initializer() if init == nil { return } id := node.Name() didReport := checkAssignment( id, init, node, getComparisonType(node), ) if !didReport { didReport = checkArrayDestructureHelper(id, init) } if !didReport { checkObjectDestructureHelper(id, init) } }, rule.ListenerOnNotAllowPattern(ast.KindObjectLiteralExpression): func(node *ast.Node) { for _, node := range node.AsObjectLiteralExpression().Properties.Nodes { var init *ast.Node if ast.IsPropertyAssignment(node) { init = node.Initializer() } else if ast.IsShorthandPropertyAssignment(node) { init = node.Name() } else { continue } if init == nil { return } init = ast.SkipParentheses(init) if ast.IsAssignmentExpression(init, false) { return } checkAssignment(node.Name(), init, node, comparisonTypeContextual) } }, rule.ListenerOnNotAllowPattern(ast.KindArrayLiteralExpression): func(node *ast.Node) { for _, node := range node.AsArrayLiteralExpression().Elements.Nodes { if !ast.IsSpreadElement(node) { continue } restType := ctx.TypeChecker.GetTypeAtLocation(node.Expression()) if utils.IsTypeAnyType(restType) || utils.IsTypeAnyArrayType(restType, ctx.TypeChecker) { ctx.ReportNode(node, buildUnsafeArraySpreadMessage(restType)) } } }, ast.KindJsxAttribute: func(node *ast.Node) { init := node.Initializer() if init == nil || init.Kind != ast.KindJsxExpression { return } expr := init.AsJsxExpression().Expression if expr == nil { return } checkAssignment(node.Name(), expr, expr, comparisonTypeContextual) }, } }, })
Functions ¶
This section is empty.
Types ¶
This section is empty.
Click to show internal directories.
Click to hide internal directories.