Skip to content

Commit

Permalink
fix: php fixes from writing rules (#1294)
Browse files Browse the repository at this point in the history
* fix: make associative array elements unanchored

* fix: improve variable shape error message

* fix: handle both kinds of strings in patterns

* fix: lookup variables in array element initializers

* fix: adjust input offsets when fixing up input

* fix: use container types to discriminate variables

* chore: clean up

* ci: appease linter

* fix: add argument to pattern container types

* fix: string handling

* fix: lookup variables in require/include

* fix: lookup variables in dynamic variables

* fix: lookup variables in function names

---------

Co-authored-by: Cédric Fabianski <[email protected]>
  • Loading branch information
didroe and cfabianski authored Oct 2, 2023
1 parent 4cf81d2 commit 6f6e6b9
Show file tree
Hide file tree
Showing 15 changed files with 582 additions and 97 deletions.
15 changes: 15 additions & 0 deletions internal/languages/java/detectors/.snapshots/TestJavaString-string
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,21 @@ children:
data:
value: Hello World
isliteral: true
- node: 44
content: s += "!!"
data:
value: Hello World!!!
isliteral: true
- node: 57
content: s2 += args[0]
data:
value: hey *
isliteral: false
- node: 67
content: s2 += " there"
data:
value: hey * there
isliteral: false
- node: 38
content: Greeting + "!"
data:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,21 @@ children:
id: 36
range: 6:8 - 6:9

- node: 11
content: x += "b"
data:
value: ab
isliteral: true
- node: 19
content: x += name
data:
value: ab*
isliteral: false
- node: 30
content: y += "c"
data:
value: '*c'
isliteral: false
- node: 6
content: '"a"'
data:
Expand Down
32 changes: 24 additions & 8 deletions internal/languages/php/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,7 @@ func New(builder *tree.Builder) language.Analyzer {

func (analyzer *analyzer) Analyze(node *sitter.Node, visitChildren func() error) error {
switch node.Type() {
case "declaration_list",
"class_declaration",
"method_declaration",
"anonymous_function_creation_expression",
"for_statement",
"block":
case "declaration_list", "class_declaration", "anonymous_function_creation_expression", "for_statement", "block", "method_declaration":
return analyzer.withScope(language.NewScope(analyzer.scope), func() error {
return visitChildren()
})
Expand All @@ -50,7 +45,19 @@ func (analyzer *analyzer) Analyze(node *sitter.Node, visitChildren func() error)
return analyzer.analyzeGenericConstruct(node, visitChildren)
case "switch_label":
return visitChildren()
case "binary_expression", "unary_op_expression", "argument", "encapsed_string", "sequence_expression":
case "dynamic_variable_name":
return analyzer.analyzeDynamicVariableName(node, visitChildren)
case "binary_expression",
"unary_op_expression",
"argument",
"encapsed_string",
"sequence_expression",
"array_element_initializer",
"formal_parameters",
"include_expression",
"include_once_expression",
"require_expression",
"require_once_expression":
return analyzer.analyzeGenericOperation(node, visitChildren)
case "while_statement", "do_statement", "if_statement", "expression_statement", "compound_statement": // statements don't have results
return visitChildren()
Expand Down Expand Up @@ -126,9 +133,11 @@ func (analyzer *analyzer) analyzeConditional(node *sitter.Node, visitChildren fu
return visitChildren()
}

// foo(1, 2);
// foo->bar(1, 2);
func (analyzer *analyzer) analyzeMethodInvocation(node *sitter.Node, visitChildren func() error) error {
analyzer.lookupVariable(node.ChildByFieldName("object"))
analyzer.lookupVariable(node.ChildByFieldName("object")) // method
analyzer.lookupVariable(node.ChildByFieldName("function")) // function

if arguments := node.ChildByFieldName("arguments"); arguments != nil {
analyzer.builder.Dataflow(node, arguments)
Expand All @@ -152,6 +161,7 @@ func (analyzer *analyzer) analyzeFieldAccess(node *sitter.Node, visitChildren fu
func (analyzer *analyzer) analyzeParameter(node *sitter.Node, visitChildren func() error) error {
name := node.ChildByFieldName("name")
analyzer.builder.Alias(node, name)
analyzer.scope.Declare(analyzer.builder.ContentFor(name), name)

return visitChildren()
}
Expand All @@ -162,6 +172,12 @@ func (analyzer *analyzer) analyzeSwitch(node *sitter.Node, visitChildren func()
return visitChildren()
}

func (analyzer *analyzer) analyzeDynamicVariableName(node *sitter.Node, visitChildren func() error) error {
analyzer.lookupVariable(node.NamedChild(0))

return visitChildren()
}

// default analysis, where the children are assumed to be aliases
func (analyzer *analyzer) analyzeGenericConstruct(node *sitter.Node, visitChildren func() error) error {
analyzer.builder.Alias(node, analyzer.builder.ChildrenFor(node)...)
Expand Down
161 changes: 145 additions & 16 deletions internal/languages/php/detectors/.snapshots/TestPHPString-string
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
type: program
id: 0
range: 1:1 - 15:3
range: 1:1 - 18:1
dataflow_sources:
- 1
- 2
- 100
- 117
children:
- type: php_tag
id: 1
range: 1:1 - 1:6
content: <?php
- type: class_declaration
id: 2
range: 2:1 - 14:2
range: 2:1 - 16:2
queries:
- 1
children:
Expand All @@ -25,7 +25,7 @@ children:
content: Greet
- type: declaration_list
id: 5
range: 2:13 - 14:2
range: 2:13 - 16:2
children:
- type: '"{"'
id: 6
Expand Down Expand Up @@ -79,7 +79,7 @@ children:
range: 3:35 - 3:36
- type: method_declaration
id: 17
range: 5:5 - 13:6
range: 5:5 - 15:6
children:
- type: visibility_modifier
id: 18
Expand Down Expand Up @@ -139,7 +139,7 @@ children:
range: 5:38 - 5:39
- type: compound_statement
id: 31
range: 6:5 - 13:6
range: 6:5 - 15:6
children:
- type: '"{"'
id: 32
Expand Down Expand Up @@ -431,32 +431,151 @@ children:
- type: '";"'
id: 97
range: 12:24 - 12:25
- type: '"}"'
- type: expression_statement
id: 98
range: 13:5 - 13:6
range: 14:9 - 14:33
children:
- type: assignment_expression
id: 99
range: 14:9 - 14:32
alias_of:
- 104
queries:
- 0
children:
- type: variable_name
id: 100
range: 14:9 - 14:12
children:
- type: '"$"'
id: 101
range: 14:9 - 14:10
- type: name
id: 102
range: 14:10 - 14:12
content: s3
- type: '"="'
id: 103
range: 14:13 - 14:14
- type: encapsed_string
id: 104
range: 14:15 - 14:32
dataflow_sources:
- 105
- 106
- 107
- 108
- 111
- 112
- 113
children:
- type: '"""'
id: 105
range: 14:15 - 14:16
- type: string
id: 106
range: 14:16 - 14:21
content: foo '
- type: '"{"'
id: 107
range: 14:21 - 14:22
- type: variable_name
id: 108
range: 14:22 - 14:25
alias_of:
- 88
children:
- type: '"$"'
id: 109
range: 14:22 - 14:23
- type: name
id: 110
range: 14:23 - 14:25
content: s2
- type: '"}"'
id: 111
range: 14:25 - 14:26
- type: string
id: 112
range: 14:26 - 14:31
content: ''' bar'
- type: '"""'
id: 113
range: 14:31 - 14:32
- type: '";"'
id: 114
range: 14:32 - 14:33
- type: '"}"'
id: 115
range: 15:5 - 15:6
- type: '"}"'
id: 99
range: 14:1 - 14:2
id: 116
range: 16:1 - 16:2
- type: text_interpolation
id: 100
range: 15:1 - 15:3
id: 117
range: 17:1 - 17:3
dataflow_sources:
- 101
- 118
children:
- type: '"?>"'
id: 101
range: 15:1 - 15:3
id: 118
range: 17:1 - 17:3

- node: 12
content: '"Hello World"'
data:
value: Hello World
isliteral: true
- node: 14
content: Hello World
data:
value: Hello World
isliteral: true
- node: 52
content: $s .= "!!"
data:
value: '*!!!'
isliteral: false
- node: 74
content: $s2 .= $args[0]
data:
value: hey *
isliteral: false
- node: 88
content: $s2 .= " there"
data:
value: hey * there
isliteral: false
- node: 39
content: self::Greeting . "!"
data:
value: '**'
value: '*!'
isliteral: false
- node: 57
content: '"!!"'
data:
value: '!!'
isliteral: true
- node: 68
content: '"hey "'
data:
value: 'hey '
isliteral: true
- node: 93
content: '" there"'
data:
value: ' there'
isliteral: true
- node: 104
content: '"foo ''{$s2}'' bar"'
data:
value: foo 'hey * there' bar
isliteral: false
- node: 46
content: '"!"'
data:
value: '!'
isliteral: true
- node: 59
content: '!!'
data:
Expand All @@ -472,6 +591,16 @@ children:
data:
value: ' there'
isliteral: true
- node: 106
content: foo '
data:
value: foo '
isliteral: true
- node: 112
content: ''' bar'
data:
value: ''' bar'
isliteral: true
- node: 48
content: '!'
data:
Expand Down
9 changes: 8 additions & 1 deletion internal/languages/php/detectors/string/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,17 @@ func (detector *stringDetector) DetectAt(
) ([]interface{}, error) {
switch node.Type() {
case "string":
value := node.Content()
if node.Parent() != nil && node.Parent().Type() != "encapsed_string" {
value = stringutil.StripQuotes(value)
}

return []interface{}{common.String{
Value: stringutil.StripQuotes(node.Content()),
Value: value,
IsLiteral: true,
}}, nil
case "encapsed_string":
return common.ConcatenateChildStrings(node, detectorContext)
case "binary_expression":
if node.Children()[1].Content() == "." {
return common.ConcatenateChildStrings(node, detectorContext)
Expand Down
4 changes: 3 additions & 1 deletion internal/languages/php/detectors/testdata/string.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public static function main($args)
$s2 = "hey ";
$s2 .= $args[0];
$s2 .= " there";

$s3 = "foo '{$s2}' bar";
}
}
?>
?>
Loading

0 comments on commit 6f6e6b9

Please sign in to comment.