Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c7b07b7

Browse files
authored
Merge pull request #47 from github/aibaars/name-resolution
Name resolution: handle the different types of parameters better
2 parents 7a13e85 + 64ebf5b commit c7b07b7

10 files changed

Lines changed: 322 additions & 51 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import codeql_ruby.Variables
2+
3+
query predicate ambiguousVariable(VariableAccess access, Variable variable) {
4+
access.getVariable() = variable and
5+
count(access.getVariable()) > 1
6+
}

ql/src/codeql_ruby/Variables.qll

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,54 @@ private VariableScope enclosingScope(AstNode node) {
1313
result.getScopeElement() = parent*(node.getParent())
1414
}
1515

16-
/** Holds if `scope` defines `name` as a parameter. */
16+
/** A parameter. */
17+
class Parameter extends AstNode {
18+
private int position;
19+
private VariableScope scope;
20+
21+
Parameter() {
22+
this =
23+
scope.(BlockScope).getScopeElement().getAFieldOrChild().(BlockParameters).getChild(position)
24+
or
25+
this =
26+
scope.(MethodScope).getScopeElement().getAFieldOrChild().(MethodParameters).getChild(position)
27+
}
28+
29+
/** Gets the (zero-based) position of this parameter. */
30+
final int getPosition() { result = position }
31+
32+
/** Gets the scope this parameter is declared in. */
33+
final VariableScope getDeclaringScope() { result = scope }
34+
35+
/** Gets an access to this parameter. */
36+
final ParameterAccess getAnAccess() { result.getParameter() = this }
37+
}
38+
39+
private Identifier parameterIdentifier(Parameter p) {
40+
result = p or
41+
result = p.(SplatParameter).getName() or
42+
result = p.(HashSplatParameter).getName() or
43+
result = p.(BlockParameter).getName() or
44+
result = p.(OptionalParameter).getName() or
45+
result = p.(KeywordParameter).getName() or
46+
result = destructuredIdentifier(p.(DestructuredParameter))
47+
}
48+
49+
private Identifier destructuredIdentifier(AstNode node) {
50+
result = node or
51+
result = destructuredIdentifier(node.(DestructuredParameter).getAFieldOrChild())
52+
}
53+
54+
/** Holds if `scope` defines `name` in its parameter declaration. */
1755
private predicate scopeDefinesParameter(VariableScope scope, string name, Location location) {
18-
exists(Identifier var |
19-
name = var.getValue() and
20-
location = var.getLocation() and
21-
var in [scope
22-
.(BlockScope)
23-
.getScopeElement()
24-
.getAFieldOrChild()
25-
.(BlockParameters)
26-
.getAFieldOrChild+(),
27-
scope
28-
.(MethodScope)
29-
.getScopeElement()
30-
.getAFieldOrChild()
31-
.(MethodParameters)
32-
.getAFieldOrChild+()]
33-
)
56+
location =
57+
min(Parameter p, Identifier i |
58+
scope = p.getDeclaringScope() and
59+
i = parameterIdentifier(p) and
60+
name = i.getValue()
61+
|
62+
i.getLocation() as loc order by loc.getStartLine(), loc.getStartColumn()
63+
)
3464
}
3565

3666
/** Holds if `var` is assigned in `scope`. */
@@ -77,10 +107,9 @@ private module Cached {
77107

78108
cached
79109
newtype TVariable =
80-
TParameter(VariableScope scope, string name, Location location) {
81-
scopeDefinesParameter(scope, name, location)
82-
} or
83110
TLocalVariable(VariableScope scope, string name, Location location) {
111+
scopeDefinesParameter(scope, name, location)
112+
or
84113
not scopeDefinesParameter(scope, name, _) and
85114
not blockScopeInherits(scope, name, _) and
86115
location =
@@ -146,23 +175,6 @@ class Variable extends TVariable {
146175
VariableAccess getAnAccess() { result.getVariable() = this }
147176
}
148177

149-
/** A parameter. */
150-
class Parameter extends Variable {
151-
private VariableScope scope;
152-
private string name;
153-
private Location location;
154-
155-
Parameter() { this = TParameter(scope, name, location) }
156-
157-
final override string getName() { result = name }
158-
159-
final override Location getLocation() { result = location }
160-
161-
final override VariableScope getDeclaringScope() { result = scope }
162-
163-
final override ParameterAccess getAnAccess() { result = super.getAnAccess() }
164-
}
165-
166178
/** A local variable. */
167179
class LocalVariable extends Variable {
168180
private VariableScope scope;
@@ -176,8 +188,6 @@ class LocalVariable extends Variable {
176188
final override Location getLocation() { result = location }
177189

178190
final override VariableScope getDeclaringScope() { result = scope }
179-
180-
final override LocalVariableAccess getAnAccess() { result = super.getAnAccess() }
181191
}
182192

183193
/** An identifier that refers to a variable. */
@@ -194,16 +204,17 @@ class VariableAccess extends Identifier {
194204

195205
/** An identifier that refers to a parameter. */
196206
class ParameterAccess extends VariableAccess {
197-
override Parameter variable;
207+
Parameter parameter;
198208

199-
final override Parameter getVariable() { result = variable }
200-
}
201-
202-
/** An identifier that refers to a local variable. */
203-
class LocalVariableAccess extends VariableAccess {
204-
override LocalVariable variable;
209+
ParameterAccess() {
210+
exists(Identifier i |
211+
i = parameterIdentifier(parameter) and
212+
variable.getDeclaringScope() = parameter.getDeclaringScope() and
213+
variable.getLocation() = i.getLocation()
214+
)
215+
}
205216

206-
final override LocalVariable getVariable() { result = super.getVariable() }
217+
final Parameter getParameter() { result = parameter }
207218
}
208219

209220
/** A top-level scope. */
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
parameter
2+
| nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a |
3+
| nested_scopes.rb:16:26:16:26 | x | nested_scopes.rb:16:26:16:26 | x |
4+
| nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:16:29:16:29 | a |
5+
| nested_scopes.rb:18:26:18:26 | x | nested_scopes.rb:18:26:18:26 | x |
6+
| nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a |
7+
| parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x |
8+
| parameters.rb:1:18:1:18 | y | parameters.rb:1:18:1:18 | y |
9+
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client |
10+
| parameters.rb:7:25:7:31 | SplatParameter | parameters.rb:7:26:7:31 | pizzas |
11+
| parameters.rb:15:15:15:19 | HashSplatParameter | parameters.rb:15:17:15:19 | map |
12+
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key |
13+
| parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value |
14+
| parameters.rb:21:16:21:21 | BlockParameter | parameters.rb:21:17:21:21 | block |
15+
| parameters.rb:25:15:25:30 | OptionalParameter | parameters.rb:25:15:25:18 | name |
16+
| parameters.rb:25:33:25:50 | OptionalParameter | parameters.rb:25:33:25:36 | size |
17+
| parameters.rb:30:15:30:20 | KeywordParameter | parameters.rb:30:15:30:19 | first |
18+
| parameters.rb:30:24:30:33 | KeywordParameter | parameters.rb:30:24:30:29 | middle |
19+
| parameters.rb:30:36:30:40 | KeywordParameter | parameters.rb:30:36:30:39 | last |
20+
| parameters.rb:35:11:35:21 | OptionalParameter | parameters.rb:35:11:35:11 | a |
21+
| parameters.rb:40:12:40:19 | KeywordParameter | parameters.rb:40:12:40:12 | d |
22+
| parameters.rb:45:20:45:20 | _ | parameters.rb:45:20:45:20 | _ |
23+
| parameters.rb:49:12:49:16 | DestructuredParameter | parameters.rb:49:13:49:13 | a |
24+
| parameters.rb:49:12:49:16 | DestructuredParameter | parameters.rb:49:15:49:15 | b |
25+
| parameters.rb:54:14:54:24 | OptionalParameter | parameters.rb:54:14:54:14 | y |
26+
| scopes.rb:2:14:2:14 | x | scopes.rb:2:14:2:14 | x |
27+
| scopes.rb:9:14:9:14 | x | scopes.rb:9:14:9:14 | x |
28+
parameterNoAcess
29+
| parameters.rb:45:22:45:22 | _ |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import codeql_ruby.Variables
2+
3+
query predicate parameter(Parameter p, Variable v) { p.getAnAccess().getVariable() = v }
4+
5+
query predicate parameterNoAcess(Parameter p) { not exists(p.getAnAccess()) }
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
1.times do | x ; y|
2+
y = 5
3+
puts x
4+
puts y
5+
end
6+
7+
def order_pizza(client, *pizzas)
8+
if pizzas.count == 1
9+
puts "1 pizza for #{client}!"
10+
else
11+
puts "#{ pizzas.count} pizzas for #{client}!"
12+
end
13+
end
14+
15+
def print_map(**map)
16+
map.each do |key, value|
17+
puts "#{key} = #{value}"
18+
end
19+
end
20+
21+
def call_block(&block)
22+
block.call
23+
end
24+
25+
def opt_param(name = 'unknown', size = name.length)
26+
puts name
27+
puts size
28+
end
29+
30+
def key_param(first: , middle: '', last:)
31+
puts "#{first} #{middle} #{last}"
32+
end
33+
34+
b = 2
35+
def multi(a = (b = 5))
36+
# `a` is a parameter and `b` is a new variable
37+
puts "#{a} #{b}"
38+
end
39+
40+
def multi2(d: e = 4)
41+
# `d` is a parameter and `e` is a local variable
42+
puts "#{d} #{e}"
43+
end
44+
45+
def dup_underscore(_,_)
46+
puts _ # binds to the first _
47+
end
48+
49+
def tuples((a,b))
50+
puts "#{a} #{b}"
51+
end
52+
53+
x = 10
54+
1.times do | y = (x = 1)|
55+
puts x
56+
puts y
57+
end
58+

0 commit comments

Comments
 (0)