Merge pull request #16801 from hvitved/ruby/element-reference-block

Ruby: Handle element references with blocks
This commit is contained in:
Tom Hvitved
2024-07-02 13:08:31 +02:00
committed by GitHub
20 changed files with 6214 additions and 3 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Element references with blocks, such as `foo[:bar] { |x| puts x}`, are now parsed correctly.

View File

@@ -112,7 +112,7 @@ class ElementReferenceImpl extends MethodCallImpl, TElementReference {
final override string getMethodNameImpl() { result = "[]" }
final override Block getBlockImpl() { none() }
final override Block getBlockImpl() { toGenerated(result) = g.getBlock() }
}
abstract class SuperCallImpl extends MethodCallImpl, TSuperCall { }

View File

@@ -633,6 +633,9 @@ module Ruby {
/** Gets the name of the primary QL class for this element. */
final override string getAPrimaryQlClass() { result = "ElementReference" }
/** Gets the node corresponding to the field `block`. */
final AstNode getBlock() { ruby_element_reference_block(this, result) }
/** Gets the node corresponding to the field `object`. */
final UnderscorePrimary getObject() { ruby_element_reference_def(this, result) }
@@ -641,7 +644,9 @@ module Ruby {
/** Gets a field or child node of this node. */
final override AstNode getAFieldOrChild() {
ruby_element_reference_def(this, result) or ruby_element_reference_child(this, _, result)
ruby_element_reference_block(this, result) or
ruby_element_reference_def(this, result) or
ruby_element_reference_child(this, _, result)
}
}

View File

@@ -569,6 +569,13 @@ ruby_do_block_def(
unique int id: @ruby_do_block
);
@ruby_element_reference_block_type = @ruby_block | @ruby_do_block
ruby_element_reference_block(
unique int ruby_element_reference: @ruby_element_reference ref,
unique int block: @ruby_element_reference_block_type ref
);
@ruby_element_reference_child_type = @ruby_block_argument | @ruby_hash_splat_argument | @ruby_pair | @ruby_splat_argument | @ruby_token_forward_argument | @ruby_underscore_expression
#keyset[ruby_element_reference, index]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add `ruby_element_reference_block` DB relation
compatibility: backwards

View File

@@ -1,6 +1,10 @@
testFailures
edges
| blocks.rb:14:12:14:20 | call to source | blocks.rb:8:10:8:14 | yield ... | provenance | |
| blocks.rb:17:10:17:10 | x | blocks.rb:18:11:18:11 | x | provenance | |
| blocks.rb:18:11:18:11 | x | blocks.rb:24:18:24:18 | x | provenance | |
| blocks.rb:24:3:24:11 | call to source | blocks.rb:17:10:17:10 | x | provenance | |
| blocks.rb:24:18:24:18 | x | blocks.rb:25:8:25:8 | x | provenance | |
| captured_variables.rb:9:24:9:24 | x | captured_variables.rb:11:5:11:6 | fn [captured x] | provenance | |
| captured_variables.rb:11:5:11:6 | fn [captured x] | captured_variables.rb:10:20:10:20 | x | provenance | |
| captured_variables.rb:13:20:13:29 | call to taint | captured_variables.rb:9:24:9:24 | x | provenance | |
@@ -254,6 +258,11 @@ edges
nodes
| blocks.rb:8:10:8:14 | yield ... | semmle.label | yield ... |
| blocks.rb:14:12:14:20 | call to source | semmle.label | call to source |
| blocks.rb:17:10:17:10 | x | semmle.label | x |
| blocks.rb:18:11:18:11 | x | semmle.label | x |
| blocks.rb:24:3:24:11 | call to source | semmle.label | call to source |
| blocks.rb:24:18:24:18 | x | semmle.label | x |
| blocks.rb:25:8:25:8 | x | semmle.label | x |
| captured_variables.rb:9:24:9:24 | x | semmle.label | x |
| captured_variables.rb:10:20:10:20 | x | semmle.label | x |
| captured_variables.rb:11:5:11:6 | fn [captured x] | semmle.label | fn [captured x] |
@@ -554,6 +563,7 @@ subpaths
| instance_variables.rb:120:6:120:10 | foo16 [@field] | instance_variables.rb:13:5:15:7 | self in get_field [@field] | instance_variables.rb:14:9:14:21 | return | instance_variables.rb:120:6:120:20 | call to get_field |
#select
| blocks.rb:8:10:8:14 | yield ... | blocks.rb:14:12:14:20 | call to source | blocks.rb:8:10:8:14 | yield ... | $@ | blocks.rb:14:12:14:20 | call to source | call to source |
| blocks.rb:25:8:25:8 | x | blocks.rb:24:3:24:11 | call to source | blocks.rb:25:8:25:8 | x | $@ | blocks.rb:24:3:24:11 | call to source | call to source |
| captured_variables.rb:10:20:10:20 | x | captured_variables.rb:13:20:13:29 | call to taint | captured_variables.rb:10:20:10:20 | x | $@ | captured_variables.rb:13:20:13:29 | call to taint | call to taint |
| captured_variables.rb:17:14:17:14 | x | captured_variables.rb:20:25:20:34 | call to taint | captured_variables.rb:17:14:17:14 | x | $@ | captured_variables.rb:20:25:20:34 | call to taint | call to taint |
| captured_variables.rb:24:14:24:14 | x | captured_variables.rb:27:48:27:57 | call to taint | captured_variables.rb:24:14:24:14 | x | $@ | captured_variables.rb:27:48:27:57 | call to taint | call to taint |

View File

@@ -12,3 +12,15 @@ end
A.new.m1 { source(1) }
A.new.m2 { source(2) }
class B
def [](x)
yield x
end
end
b = B.new
b[source(3)] do |x|
sink x # $ hasValueFlow=3
end

View File

@@ -154,6 +154,10 @@ calls.rb:
# 649| CustomNew2
#-----| super -> Object
element_reference.rb:
# 1| ClassWithElementRef
#-----| super -> Object
hello.rb:
# 1| EnglishWords

View File

@@ -257,6 +257,13 @@ getTarget
| calls.rb:659:1:659:23 | call to instance | calls.rb:654:5:656:7 | instance |
| calls.rb:667:2:667:25 | call to capture_parameter | calls.rb:661:1:665:3 | capture_parameter |
| calls.rb:667:20:667:25 | call to new | calls.rb:117:5:117:16 | new |
| element_reference.rb:3:9:3:19 | yield ... | element_reference.rb:9:6:9:19 | { ... } |
| element_reference.rb:3:9:3:19 | yield ... | element_reference.rb:11:6:13:3 | do ... end |
| element_reference.rb:7:5:7:27 | call to new | calls.rb:117:5:117:16 | new |
| element_reference.rb:9:1:9:19 | ...[...] | element_reference.rb:2:5:4:7 | [] |
| element_reference.rb:9:12:9:17 | call to puts | calls.rb:102:5:102:30 | puts |
| element_reference.rb:11:1:13:3 | ...[...] | element_reference.rb:2:5:4:7 | [] |
| element_reference.rb:12:5:12:10 | call to puts | calls.rb:102:5:102:30 | puts |
| hello.rb:12:5:12:24 | call to include | calls.rb:108:5:110:7 | include |
| hello.rb:14:16:14:20 | call to hello | hello.rb:2:5:4:7 | hello |
| hello.rb:20:16:20:20 | super call to message | hello.rb:13:5:15:7 | message |
@@ -385,6 +392,7 @@ unresolvedCall
| calls.rb:662:5:662:11 | call to [] |
| calls.rb:662:5:664:7 | call to each |
| calls.rb:667:1:667:35 | call to instance |
| element_reference.rb:3:15:3:19 | ... + ... |
| hello.rb:20:16:20:26 | ... + ... |
| hello.rb:20:16:20:34 | ... + ... |
| hello.rb:20:16:20:40 | ... + ... |
@@ -512,6 +520,7 @@ publicMethod
| calls.rb:642:5:644:7 | new |
| calls.rb:650:5:652:7 | new |
| calls.rb:654:5:656:7 | instance |
| element_reference.rb:2:5:4:7 | [] |
| hello.rb:2:5:4:7 | hello |
| hello.rb:5:5:7:7 | world |
| hello.rb:13:5:15:7 | message |

View File

@@ -0,0 +1,13 @@
class ClassWithElementRef
def [](x)
yield x + 1
end
end
c = ClassWithElementRef.new
c[1] { |x| puts x }
c[1] do |x|
puts x
end

View File

@@ -51,6 +51,7 @@ getMethod
| calls.rb:626:1:632:3 | Included | foo | calls.rb:627:5:629:7 | foo |
| calls.rb:634:1:639:3 | IncludesIncluded | bar | calls.rb:636:5:638:7 | bar |
| calls.rb:649:1:657:3 | CustomNew2 | instance | calls.rb:654:5:656:7 | instance |
| element_reference.rb:1:1:5:3 | ClassWithElementRef | [] | element_reference.rb:2:5:4:7 | [] |
| hello.rb:1:1:8:3 | EnglishWords | hello | hello.rb:2:5:4:7 | hello |
| hello.rb:1:1:8:3 | EnglishWords | world | hello.rb:5:5:7:7 | world |
| hello.rb:11:1:16:3 | Greeting | message | hello.rb:13:5:15:7 | message |
@@ -561,6 +562,10 @@ lookupMethod
| calls.rb:649:1:657:3 | CustomNew2 | private_on_main | calls.rb:185:1:186:3 | private_on_main |
| calls.rb:649:1:657:3 | CustomNew2 | puts | calls.rb:102:5:102:30 | puts |
| calls.rb:649:1:657:3 | CustomNew2 | to_s | calls.rb:172:5:173:7 | to_s |
| element_reference.rb:1:1:5:3 | ClassWithElementRef | [] | element_reference.rb:2:5:4:7 | [] |
| element_reference.rb:1:1:5:3 | ClassWithElementRef | new | calls.rb:117:5:117:16 | new |
| element_reference.rb:1:1:5:3 | ClassWithElementRef | puts | calls.rb:102:5:102:30 | puts |
| element_reference.rb:1:1:5:3 | ClassWithElementRef | to_s | calls.rb:172:5:173:7 | to_s |
| file://:0:0:0:0 | Class | include | calls.rb:108:5:110:7 | include |
| file://:0:0:0:0 | Class | module_eval | calls.rb:107:5:107:24 | module_eval |
| file://:0:0:0:0 | Class | new | calls.rb:117:5:117:16 | new |
@@ -1080,6 +1085,12 @@ enclosingMethod
| calls.rb:662:10:662:10 | 2 | calls.rb:661:1:665:3 | capture_parameter |
| calls.rb:662:18:664:7 | do ... end | calls.rb:661:1:665:3 | capture_parameter |
| calls.rb:663:9:663:9 | x | calls.rb:661:1:665:3 | capture_parameter |
| element_reference.rb:2:12:2:12 | x | element_reference.rb:2:5:4:7 | [] |
| element_reference.rb:2:12:2:12 | x | element_reference.rb:2:5:4:7 | [] |
| element_reference.rb:3:9:3:19 | yield ... | element_reference.rb:2:5:4:7 | [] |
| element_reference.rb:3:15:3:15 | x | element_reference.rb:2:5:4:7 | [] |
| element_reference.rb:3:15:3:19 | ... + ... | element_reference.rb:2:5:4:7 | [] |
| element_reference.rb:3:19:3:19 | 1 | element_reference.rb:2:5:4:7 | [] |
| hello.rb:3:9:3:22 | return | hello.rb:2:5:4:7 | hello |
| hello.rb:3:16:3:22 | "hello" | hello.rb:2:5:4:7 | hello |
| hello.rb:3:17:3:21 | hello | hello.rb:2:5:4:7 | hello |

View File

@@ -36,6 +36,7 @@ getModule
| calls.rb:634:1:639:3 | IncludesIncluded |
| calls.rb:641:1:645:3 | CustomNew1 |
| calls.rb:649:1:657:3 | CustomNew2 |
| element_reference.rb:1:1:5:3 | ClassWithElementRef |
| file://:0:0:0:0 | BasicObject |
| file://:0:0:0:0 | Class |
| file://:0:0:0:0 | Complex |
@@ -113,6 +114,7 @@ getADeclaration
| calls.rb:105:1:113:3 | Module | calls.rb:105:1:113:3 | Module |
| calls.rb:115:1:118:3 | Object | calls.rb:1:1:667:52 | calls.rb |
| calls.rb:115:1:118:3 | Object | calls.rb:115:1:118:3 | Object |
| calls.rb:115:1:118:3 | Object | element_reference.rb:1:1:13:4 | element_reference.rb |
| calls.rb:115:1:118:3 | Object | hello.rb:1:1:22:3 | hello.rb |
| calls.rb:115:1:118:3 | Object | instance_fields.rb:1:1:29:4 | instance_fields.rb |
| calls.rb:115:1:118:3 | Object | modules.rb:1:1:129:4 | modules.rb |
@@ -153,6 +155,7 @@ getADeclaration
| calls.rb:634:1:639:3 | IncludesIncluded | calls.rb:634:1:639:3 | IncludesIncluded |
| calls.rb:641:1:645:3 | CustomNew1 | calls.rb:641:1:645:3 | CustomNew1 |
| calls.rb:649:1:657:3 | CustomNew2 | calls.rb:649:1:657:3 | CustomNew2 |
| element_reference.rb:1:1:5:3 | ClassWithElementRef | element_reference.rb:1:1:5:3 | ClassWithElementRef |
| hello.rb:1:1:8:3 | EnglishWords | hello.rb:1:1:8:3 | EnglishWords |
| hello.rb:11:1:16:3 | Greeting | hello.rb:11:1:16:3 | Greeting |
| hello.rb:18:1:22:3 | HelloWorld | hello.rb:18:1:22:3 | HelloWorld |
@@ -238,6 +241,7 @@ getSuperClass
| calls.rb:634:1:639:3 | IncludesIncluded | calls.rb:115:1:118:3 | Object |
| calls.rb:641:1:645:3 | CustomNew1 | calls.rb:115:1:118:3 | Object |
| calls.rb:649:1:657:3 | CustomNew2 | calls.rb:115:1:118:3 | Object |
| element_reference.rb:1:1:5:3 | ClassWithElementRef | calls.rb:115:1:118:3 | Object |
| file://:0:0:0:0 | Class | calls.rb:105:1:113:3 | Module |
| file://:0:0:0:0 | Complex | file://:0:0:0:0 | Numeric |
| file://:0:0:0:0 | FalseClass | calls.rb:115:1:118:3 | Object |
@@ -389,6 +393,7 @@ resolveConstantReadAccess
| calls.rb:659:1:659:10 | CustomNew2 | CustomNew2 |
| calls.rb:662:5:662:11 | Array | Array |
| calls.rb:667:20:667:21 | C1 | C1 |
| element_reference.rb:7:5:7:23 | ClassWithElementRef | ClassWithElementRef |
| hello.rb:12:13:12:24 | EnglishWords | EnglishWords |
| hello.rb:18:20:18:27 | Greeting | Greeting |
| instance_fields.rb:4:22:4:31 | A_target | A_target |
@@ -495,6 +500,7 @@ resolveConstantWriteAccess
| calls.rb:634:1:639:3 | IncludesIncluded | IncludesIncluded |
| calls.rb:641:1:645:3 | CustomNew1 | CustomNew1 |
| calls.rb:649:1:657:3 | CustomNew2 | CustomNew2 |
| element_reference.rb:1:1:5:3 | ClassWithElementRef | ClassWithElementRef |
| hello.rb:1:1:8:3 | EnglishWords | EnglishWords |
| hello.rb:11:1:16:3 | Greeting | Greeting |
| hello.rb:18:1:22:3 | HelloWorld | HelloWorld |
@@ -1611,6 +1617,36 @@ enclosingModule
| calls.rb:667:2:667:25 | self | calls.rb:1:1:667:52 | calls.rb |
| calls.rb:667:20:667:21 | C1 | calls.rb:1:1:667:52 | calls.rb |
| calls.rb:667:20:667:25 | call to new | calls.rb:1:1:667:52 | calls.rb |
| element_reference.rb:1:1:5:3 | ClassWithElementRef | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:2:5:4:7 | [] | element_reference.rb:1:1:5:3 | ClassWithElementRef |
| element_reference.rb:2:12:2:12 | x | element_reference.rb:1:1:5:3 | ClassWithElementRef |
| element_reference.rb:2:12:2:12 | x | element_reference.rb:1:1:5:3 | ClassWithElementRef |
| element_reference.rb:3:9:3:19 | yield ... | element_reference.rb:1:1:5:3 | ClassWithElementRef |
| element_reference.rb:3:15:3:15 | x | element_reference.rb:1:1:5:3 | ClassWithElementRef |
| element_reference.rb:3:15:3:19 | ... + ... | element_reference.rb:1:1:5:3 | ClassWithElementRef |
| element_reference.rb:3:19:3:19 | 1 | element_reference.rb:1:1:5:3 | ClassWithElementRef |
| element_reference.rb:7:1:7:1 | c | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:7:1:7:27 | ... = ... | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:7:5:7:23 | ClassWithElementRef | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:7:5:7:27 | call to new | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:9:1:9:1 | c | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:9:1:9:19 | ...[...] | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:9:3:9:3 | 1 | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:9:6:9:19 | { ... } | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:9:9:9:9 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:9:9:9:9 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:9:12:9:17 | call to puts | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:9:12:9:17 | self | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:9:17:9:17 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:11:1:11:1 | c | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:11:1:13:3 | ...[...] | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:11:3:11:3 | 1 | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:11:6:13:3 | do ... end | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:11:10:11:10 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:11:10:11:10 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:12:5:12:10 | call to puts | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:12:5:12:10 | self | element_reference.rb:1:1:13:4 | element_reference.rb |
| element_reference.rb:12:10:12:10 | x | element_reference.rb:1:1:13:4 | element_reference.rb |
| hello.rb:1:1:8:3 | EnglishWords | hello.rb:1:1:22:3 | hello.rb |
| hello.rb:2:5:4:7 | hello | hello.rb:1:1:8:3 | EnglishWords |
| hello.rb:3:9:3:22 | return | hello.rb:1:1:8:3 | EnglishWords |

View File

@@ -148,6 +148,10 @@ calls.rb:
# 649| CustomNew2
#-----| -> Object
element_reference.rb:
# 1| ClassWithElementRef
#-----| -> Object
hello.rb:
# 1| EnglishWords