Skip to content

Commit 4df7fd2

Browse files
committed
Ruby: Ensure explicit modifiers take priority
In Ruby, "explicit" visibility modifiers override "implicit" ones. For example, in the following: ```rb class C private def m1 end public m2 end def m3 end public :m3 end ``` `m1` is private whereas `m2` and `m3` are public.
1 parent d90257f commit 4df7fd2

File tree

3 files changed

+70
-46
lines changed

3 files changed

+70
-46
lines changed

ruby/ql/lib/codeql/ruby/ast/Method.qll

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
6060

6161
/**
6262
* Gets the visibility modifier that defines the visibility of this method, if
63-
* one exists.
63+
* any.
6464
*/
6565
VisibilityModifier getVisibilityModifier() { none() }
6666
}
@@ -170,13 +170,10 @@ class Method extends MethodBase, TMethod {
170170
}
171171

172172
override VisibilityModifier getVisibilityModifier() {
173-
result.getEnclosingModule() = this.getEnclosingModule() and
174-
(
175-
result.getMethodArgument() = this
176-
or
177-
result.getMethodArgument().getConstantValue().getStringlikeValue() = this.getName()
178-
)
173+
result = this.getExplicitVisibilityModifier()
179174
or
175+
not exists(this.getExplicitVisibilityModifier()) and
176+
result.getEnclosingModule() = this.getEnclosingModule() and
180177
exists(Namespace n, int methodPos | n.getStmt(methodPos) = this |
181178
// The relevant visibility modifier is the closest call that occurs before
182179
// the definition of `m` (typically this means higher up the file).
@@ -190,6 +187,27 @@ class Method extends MethodBase, TMethod {
190187
)
191188
)
192189
}
190+
191+
/**
192+
* Gets the visibility modifier that explicitly sets the visibility of this
193+
* method.
194+
*
195+
* Examples:
196+
* ```rb
197+
* def f
198+
* end
199+
* private :f
200+
*
201+
* private def g
202+
* end
203+
* ```
204+
*/
205+
VisibilityModifier getExplicitVisibilityModifier() {
206+
result.getMethodArgument() = this
207+
or
208+
result.getEnclosingModule() = this.getEnclosingModule() and
209+
result.getMethodArgument().getConstantValue().getStringlikeValue() = this.getName()
210+
}
193211
}
194212

195213
/** A singleton method. */

ruby/ql/test/library-tests/modules/callgraph.expected

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -196,30 +196,31 @@ getTarget
196196
| private.rb:2:3:3:5 | call to private | calls.rb:109:5:109:20 | private |
197197
| private.rb:10:3:10:19 | call to private | calls.rb:109:5:109:20 | private |
198198
| private.rb:12:3:12:9 | call to private | calls.rb:109:5:109:20 | private |
199-
| private.rb:41:3:41:9 | call to private | calls.rb:109:5:109:20 | private |
200-
| private.rb:50:1:50:5 | call to new | calls.rb:114:5:114:16 | new |
201-
| private.rb:51:1:51:5 | call to new | calls.rb:114:5:114:16 | new |
202-
| private.rb:52:1:52:5 | call to new | calls.rb:114:5:114:16 | new |
203-
| private.rb:53:1:53:5 | call to new | calls.rb:114:5:114:16 | new |
199+
| private.rb:43:3:43:19 | call to private | calls.rb:109:5:109:20 | private |
200+
| private.rb:45:3:45:9 | call to private | calls.rb:109:5:109:20 | private |
204201
| private.rb:54:1:54:5 | call to new | calls.rb:114:5:114:16 | new |
205-
| private.rb:54:1:54:12 | call to public | private.rb:5:3:6:5 | public |
206-
| private.rb:56:1:56:15 | call to private_on_main | private.rb:47:1:48:3 | private_on_main |
207-
| private.rb:59:3:60:5 | call to private | calls.rb:109:5:109:20 | private |
208-
| private.rb:67:3:67:19 | call to private | calls.rb:109:5:109:20 | private |
209-
| private.rb:69:3:69:9 | call to private | calls.rb:109:5:109:20 | private |
210-
| private.rb:79:3:81:5 | call to private | calls.rb:109:5:109:20 | private |
211-
| private.rb:80:7:80:32 | call to puts | calls.rb:102:5:102:30 | puts |
202+
| private.rb:55:1:55:5 | call to new | calls.rb:114:5:114:16 | new |
203+
| private.rb:56:1:56:5 | call to new | calls.rb:114:5:114:16 | new |
204+
| private.rb:57:1:57:5 | call to new | calls.rb:114:5:114:16 | new |
205+
| private.rb:58:1:58:5 | call to new | calls.rb:114:5:114:16 | new |
206+
| private.rb:58:1:58:12 | call to public | private.rb:5:3:6:5 | public |
207+
| private.rb:60:1:60:15 | call to private_on_main | private.rb:51:1:52:3 | private_on_main |
208+
| private.rb:63:3:64:5 | call to private | calls.rb:109:5:109:20 | private |
209+
| private.rb:71:3:71:19 | call to private | calls.rb:109:5:109:20 | private |
210+
| private.rb:73:3:73:9 | call to private | calls.rb:109:5:109:20 | private |
212211
| private.rb:83:3:85:5 | call to private | calls.rb:109:5:109:20 | private |
213212
| private.rb:84:7:84:32 | call to puts | calls.rb:102:5:102:30 | puts |
214-
| private.rb:88:7:88:8 | call to m1 | private.rb:79:11:81:5 | m1 |
215-
| private.rb:88:7:88:8 | call to m1 | private.rb:93:11:97:5 | m1 |
216-
| private.rb:93:3:97:5 | call to private | calls.rb:109:5:109:20 | private |
217-
| private.rb:94:7:94:32 | call to puts | calls.rb:102:5:102:30 | puts |
218-
| private.rb:95:7:95:8 | call to m2 | private.rb:83:11:85:5 | m2 |
219-
| private.rb:96:7:96:26 | call to new | calls.rb:114:5:114:16 | new |
220-
| private.rb:100:1:100:20 | call to new | calls.rb:114:5:114:16 | new |
221-
| private.rb:100:1:100:28 | call to call_m1 | private.rb:87:3:89:5 | call_m1 |
222-
| private.rb:101:1:101:20 | call to new | calls.rb:114:5:114:16 | new |
213+
| private.rb:87:3:89:5 | call to private | calls.rb:109:5:109:20 | private |
214+
| private.rb:88:7:88:32 | call to puts | calls.rb:102:5:102:30 | puts |
215+
| private.rb:92:7:92:8 | call to m1 | private.rb:83:11:85:5 | m1 |
216+
| private.rb:92:7:92:8 | call to m1 | private.rb:97:11:101:5 | m1 |
217+
| private.rb:97:3:101:5 | call to private | calls.rb:109:5:109:20 | private |
218+
| private.rb:98:7:98:32 | call to puts | calls.rb:102:5:102:30 | puts |
219+
| private.rb:99:7:99:8 | call to m2 | private.rb:87:11:89:5 | m2 |
220+
| private.rb:100:7:100:26 | call to new | calls.rb:114:5:114:16 | new |
221+
| private.rb:104:1:104:20 | call to new | calls.rb:114:5:114:16 | new |
222+
| private.rb:104:1:104:28 | call to call_m1 | private.rb:91:3:93:5 | call_m1 |
223+
| private.rb:105:1:105:20 | call to new | calls.rb:114:5:114:16 | new |
223224
unresolvedCall
224225
| calls.rb:26:9:26:18 | call to instance_m |
225226
| calls.rb:29:5:29:14 | call to instance_m |
@@ -292,12 +293,12 @@ unresolvedCall
292293
| private.rb:23:3:24:5 | call to private_class_method |
293294
| private.rb:28:3:28:32 | call to private_class_method |
294295
| private.rb:30:3:30:11 | call to protected |
295-
| private.rb:50:1:50:14 | call to private1 |
296-
| private.rb:51:1:51:14 | call to private2 |
297-
| private.rb:52:1:52:14 | call to private3 |
298-
| private.rb:53:1:53:14 | call to private4 |
299-
| private.rb:96:7:96:29 | call to m1 |
300-
| private.rb:101:1:101:23 | call to m1 |
296+
| private.rb:54:1:54:14 | call to private1 |
297+
| private.rb:55:1:55:14 | call to private2 |
298+
| private.rb:56:1:56:14 | call to private3 |
299+
| private.rb:57:1:57:14 | call to private4 |
300+
| private.rb:100:7:100:29 | call to m1 |
301+
| private.rb:105:1:105:23 | call to m1 |
301302
privateMethod
302303
| calls.rb:1:1:3:3 | foo |
303304
| calls.rb:39:1:41:3 | call_instance_m |
@@ -318,15 +319,16 @@ privateMethod
318319
| private.rb:17:3:18:5 | private4 |
319320
| private.rb:23:24:24:5 | private5 |
320321
| private.rb:26:3:27:5 | private6 |
321-
| private.rb:43:3:44:5 | private7 |
322-
| private.rb:47:1:48:3 | private_on_main |
323-
| private.rb:59:11:60:5 | private1 |
324-
| private.rb:65:3:66:5 | private2 |
325-
| private.rb:71:3:72:5 | private3 |
326-
| private.rb:74:3:75:5 | private4 |
327-
| private.rb:79:11:81:5 | m1 |
328-
| private.rb:83:11:85:5 | m2 |
329-
| private.rb:93:11:97:5 | m1 |
322+
| private.rb:41:3:42:5 | private7 |
323+
| private.rb:47:3:48:5 | private8 |
324+
| private.rb:51:1:52:3 | private_on_main |
325+
| private.rb:63:11:64:5 | private1 |
326+
| private.rb:69:3:70:5 | private2 |
327+
| private.rb:75:3:76:5 | private3 |
328+
| private.rb:78:3:79:5 | private4 |
329+
| private.rb:83:11:85:5 | m1 |
330+
| private.rb:87:11:89:5 | m2 |
331+
| private.rb:97:11:101:5 | m1 |
330332
publicMethod
331333
| calls.rb:7:1:9:3 | bar |
332334
| calls.rb:13:1:15:3 | bar |
@@ -396,8 +398,8 @@ publicMethod
396398
| private.rb:5:3:6:5 | public |
397399
| private.rb:20:3:21:5 | public2 |
398400
| private.rb:38:3:39:5 | public3 |
399-
| private.rb:62:3:63:5 | public |
400-
| private.rb:87:3:89:5 | call_m1 |
401+
| private.rb:66:3:67:5 | public |
402+
| private.rb:91:3:93:5 | call_m1 |
401403
protectedMethod
402404
| private.rb:32:3:33:5 | protected1 |
403405
| private.rb:35:3:36:5 | protected2 |

ruby/ql/test/library-tests/modules/private.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@ def protected2
3838
def self.public3
3939
end
4040

41+
def private7
42+
end
43+
private :private7
44+
4145
private
4246

43-
def private7
47+
def private8
4448
end
4549
end
4650

0 commit comments

Comments
 (0)