Skip to content

Commit

Permalink
fix: improve python analyzer and pattern support (#1597)
Browse files Browse the repository at this point in the history
  • Loading branch information
didroe authored May 16, 2024
1 parent 7ecf89c commit f3237e6
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 19 deletions.
29 changes: 28 additions & 1 deletion internal/languages/python/analyzer/analyzer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package analyzer

import (
"slices"

sitter "github.com/smacker/go-tree-sitter"

"github.com/bearer/bearer/internal/scanner/ast/tree"
Expand Down Expand Up @@ -39,6 +41,8 @@ func (analyzer *analyzer) Analyze(node *sitter.Node, visitChildren func() error)
return analyzer.analyzeGenericOperation(node, visitChildren)
case "parenthesized_expression":
return analyzer.analyzeGenericConstruct(node, visitChildren)
case "parameters":
return analyzer.analyzeParameters(node, visitChildren)
case "keyword_argument":
return analyzer.analyzeKeywordArgument(node, visitChildren)
case "while_statement", "try_statement", "if_statement": // statements don't have results
Expand Down Expand Up @@ -152,6 +156,29 @@ func (analyzer *analyzer) analyzeBoolean(node *sitter.Node, visitChildren func()
return visitChildren()
}

// def f(self, param: Type)
// def f(param: Type = default)
func (analyzer *analyzer) analyzeParameters(node *sitter.Node, visitChildren func() error) error {
err := visitChildren()

for _, parameter := range analyzer.builder.ChildrenFor(node) {
switch parameter.Type() {
case "typed_parameter", "typed_default_parameter", "default_parameter":
name := parameter.NamedChild(0)

analyzer.builder.Alias(parameter, name)
analyzer.scope.Declare(analyzer.builder.ContentFor(name), name)

analyzer.lookupVariable(parameter.ChildByFieldName("type"))
analyzer.lookupVariable(parameter.ChildByFieldName("value"))
case "identifier":
analyzer.scope.Declare(analyzer.builder.ContentFor(parameter), parameter)
}
}

return err
}

func (analyzer *analyzer) analyzeKeywordArgument(node *sitter.Node, visitChildren func() error) error {
value := node.ChildByFieldName("value")

Expand Down Expand Up @@ -217,7 +244,7 @@ func (analyzer *analyzer) withScope(newScope *language.Scope, body func() error)
}

func (analyzer *analyzer) lookupVariable(node *sitter.Node) {
if node == nil || node.Type() != "identifier" {
if node == nil || !slices.Contains([]string{"identifier", "type"}, node.Type()) {
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,6 @@ children:
- type: parameters
id: 9
range: 2:17 - 2:39
dataflow_sources:
- 10
- 11
- 12
- 13
- 14
- 15
- 21
children:
- type: '"("'
id: 10
Expand All @@ -71,6 +63,8 @@ children:
- 16
- 17
- 18
alias_of:
- 16
children:
- type: identifier
id: 16
Expand Down Expand Up @@ -126,6 +120,8 @@ children:
id: 27
range: 3:9 - 3:13
content: self
alias_of:
- 11
- type: '"."'
id: 28
range: 3:13 - 3:14
Expand All @@ -140,6 +136,8 @@ children:
id: 31
range: 3:21 - 3:25
content: name
alias_of:
- 13
- type: expression_statement
id: 32
range: 4:9 - 4:27
Expand All @@ -164,6 +162,8 @@ children:
id: 35
range: 4:9 - 4:13
content: self
alias_of:
- 11
- type: '"."'
id: 36
range: 4:13 - 4:14
Expand All @@ -178,6 +178,8 @@ children:
id: 39
range: 4:22 - 4:27
content: email
alias_of:
- 16
- type: function_definition
id: 40
range: 6:5 - 8:33
Expand All @@ -192,10 +194,6 @@ children:
- type: parameters
id: 43
range: 6:23 - 6:29
dataflow_sources:
- 44
- 45
- 46
children:
- type: '"("'
id: 44
Expand Down Expand Up @@ -269,6 +267,8 @@ children:
id: 58
range: 7:23 - 7:27
content: self
alias_of:
- 45
- type: '"."'
id: 59
range: 7:27 - 7:28
Expand Down Expand Up @@ -334,6 +334,8 @@ children:
id: 70
range: 8:15 - 8:19
content: self
alias_of:
- 45
- type: '"."'
id: 71
range: 8:19 - 8:20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,6 @@ children:
- type: parameters
id: 16
range: 4:13 - 4:19
dataflow_sources:
- 17
- 18
- 19
children:
- type: '"("'
id: 17
Expand Down Expand Up @@ -261,6 +257,8 @@ children:
id: 54
range: 9:15 - 9:19
content: args
alias_of:
- 18
- type: '"["'
id: 55
range: 9:19 - 9:20
Expand Down
28 changes: 26 additions & 2 deletions internal/languages/python/pattern/pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ var (
patternQueryVariableRegex = regexp.MustCompile(`\$<(?P<name>[^>:!\.]+)(?::(?P<types>[^>]+))?>`)
matchNodeRegex = regexp.MustCompile(`\$<!>`)
ellipsisRegex = regexp.MustCompile(`\$<\.\.\.>`)
unanchoredPatternNodeTypes = []string{}
patternMatchNodeContainerTypes = []string{"dotted_name"}
unanchoredPatternNodeTypes = []string{"function_definition"}
patternMatchNodeContainerTypes = []string{
"dotted_name",
"typed_parameter",
"typed_default_parameter",
"default_parameter",
}

allowedPatternQueryTypes = []string{"_"}
)
Expand Down Expand Up @@ -102,6 +107,11 @@ func (*Pattern) IsAnchored(node *tree.Node) (bool, bool) {
return false, false
}

// return type or leading comment
if node.Type() == "block" {
return false, true
}

parent := node.Parent()
if parent == nil {
return true, true
Expand All @@ -121,6 +131,16 @@ func (*Pattern) IsAnchored(node *tree.Node) (bool, bool) {
return false, false
}

// type parameters
if parent.Type() == "function_definition" && node == parent.ChildByFieldName("parameters") {
return false, true
}

// inherited types
if parent.Type() == "argument_list" && parent.Parent() != nil && parent.Parent().Type() == "class_definition" {
return false, false
}

// Associative array elements are unanchored
// eg. array("foo" => 42)
if parent.Type() == "array_creation_expression" &&
Expand All @@ -147,6 +167,10 @@ func (*Pattern) IsRoot(node *tree.Node) bool {
}

func (patternLanguage *Pattern) NodeTypes(node *tree.Node) []string {
if node.Type() == "typed_parameter" {
return []string{"typed_parameter", "typed_default_parameter"}
}

return []string{node.Type()}
}

Expand Down

0 comments on commit f3237e6

Please sign in to comment.