@@ -36,8 +36,25 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
36
36
result = BodyStmt .super .getAChild ( pred )
37
37
}
38
38
39
+ /**
40
+ * Holds if this method is public.
41
+ * Methods are public by default.
42
+ */
43
+ predicate isPublic ( ) {
44
+ forall ( VisibilityModifier m | m = this .getVisibilityModifier ( ) | m .getVisibility ( ) = "public" )
45
+ }
46
+
39
47
/** Holds if this method is private. */
40
- predicate isPrivate ( ) { none ( ) }
48
+ predicate isPrivate ( ) { this .getVisibilityModifier ( ) .getVisibility ( ) = "private" }
49
+
50
+ /** Holds if this method is protected. */
51
+ predicate isProtected ( ) { this .getVisibilityModifier ( ) .getVisibility ( ) = "protected" }
52
+
53
+ /**
54
+ * Gets the visibility modifier that defines the visibility of this method, if
55
+ * one exists.
56
+ */
57
+ VisibilityModifier getVisibilityModifier ( ) { none ( ) }
41
58
}
42
59
43
60
/**
@@ -47,45 +64,40 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
47
64
private class MethodModifier extends MethodCall {
48
65
/** Gets the name of the method that this call applies to. */
49
66
Expr getMethodArgument ( ) { result = this .getArgument ( 0 ) }
50
-
51
- /** Holds if this call modifies a method with name `name` in namespace `n`. */
52
- pragma [ noinline]
53
- predicate modifiesMethod ( Namespace n , string name ) {
54
- this = n .getAStmt ( ) and
55
- [
56
- this .getMethodArgument ( ) .getConstantValue ( ) .getStringlikeValue ( ) ,
57
- this .getMethodArgument ( ) .( MethodBase ) .getName ( )
58
- ] = name
59
- }
60
67
}
61
68
62
- /** A call to `private` or `private_class_method` . */
63
- private class Private extends MethodModifier {
69
+ /** A method call that sets the visibility of other methods . */
70
+ private class VisibilityModifier extends MethodModifier {
64
71
private Namespace namespace ;
65
72
private int position ;
66
73
67
- Private ( ) { this .getMethodName ( ) = "private" and namespace .getStmt ( position ) = this }
74
+ VisibilityModifier ( ) {
75
+ this .getMethodName ( ) =
76
+ [
77
+ "public" , "private" , "protected" , "public_class_method" , "private_class_method" ,
78
+ "protected_class_method"
79
+ ] and
80
+ namespace .getStmt ( position ) = this
81
+ }
68
82
69
- override predicate modifiesMethod ( Namespace n , string name ) {
70
- n = namespace and
71
- (
72
- // def foo
73
- // ...
74
- // private :foo
75
- super .modifiesMethod ( n , name )
76
- or
77
- // private
78
- // ...
79
- // def foo
80
- not exists ( this .getMethodArgument ( ) ) and
81
- exists ( MethodBase m , int i | n .getStmt ( i ) = m and m .getName ( ) = name and i > position )
82
- )
83
+ /**
84
+ * Holds if this modifier changes the "ambient" visibility - i.e. the default
85
+ * visibility of any subsequent method definitions.
86
+ */
87
+ predicate modifiesAmbientVisibility ( ) {
88
+ this .getMethodName ( ) = [ "public" , "private" , "protected" ] and
89
+ this .getNumberOfArguments ( ) = 0
83
90
}
84
- }
85
91
86
- /** A call to `private_class_method`. */
87
- private class PrivateClassMethod extends MethodModifier {
88
- PrivateClassMethod ( ) { this .getMethodName ( ) = "private_class_method" }
92
+ string getVisibility ( ) {
93
+ this .getMethodName ( ) = [ "public" , "public_class_method" ] and result = "public"
94
+ or
95
+ this .getMethodName ( ) = [ "private" , "private_class_method" ] and
96
+ result = "private"
97
+ or
98
+ this .getMethodName ( ) = [ "protected" , "protected_class_method" ] and
99
+ result = "protected"
100
+ }
89
101
}
90
102
91
103
/** A normal method. */
@@ -140,28 +152,41 @@ class Method extends MethodBase, TMethod {
140
152
* ```
141
153
*/
142
154
override predicate isPrivate ( ) {
143
- exists ( Namespace n , string name |
144
- any ( Private p ) .modifiesMethod ( n , name ) and
145
- isDeclaredIn ( this , n , name )
146
- )
155
+ this .getVisibilityModifier ( ) .getVisibility ( ) = "private"
147
156
or
148
157
// Top-level methods are private members of the Object class
149
158
this .getEnclosingModule ( ) instanceof Toplevel
150
159
}
151
160
161
+ override predicate isPublic ( ) { super .isPublic ( ) and not this .isPrivate ( ) }
162
+
152
163
final override Parameter getParameter ( int n ) {
153
164
toGenerated ( result ) = g .getParameters ( ) .getChild ( n )
154
165
}
155
166
156
167
final override string toString ( ) { result = this .getName ( ) }
157
- }
158
168
159
- /**
160
- * Holds if the method `m` has name `name` and is declared in namespace `n`.
161
- */
162
- pragma [ noinline]
163
- private predicate isDeclaredIn ( MethodBase m , Namespace n , string name ) {
164
- n = m .getEnclosingModule ( ) and name = m .getName ( )
169
+ override VisibilityModifier getVisibilityModifier ( ) {
170
+ result .getEnclosingModule ( ) = this .getEnclosingModule ( ) and
171
+ (
172
+ result .getMethodArgument ( ) = this
173
+ or
174
+ result .getMethodArgument ( ) .getConstantValue ( ) .getStringlikeValue ( ) = this .getName ( )
175
+ )
176
+ or
177
+ exists ( Namespace n , int methodPos | n .getStmt ( methodPos ) = this |
178
+ // The relevant visibility modifier is the closest call that occurs before
179
+ // the definition of `m` (typically this means higher up the file).
180
+ result =
181
+ max ( int modifierPos , VisibilityModifier modifier |
182
+ modifier .modifiesAmbientVisibility ( ) and
183
+ n .getStmt ( modifierPos ) = modifier and
184
+ modifierPos < methodPos
185
+ |
186
+ modifier order by modifierPos
187
+ )
188
+ )
189
+ }
165
190
}
166
191
167
192
/** A singleton method. */
@@ -216,10 +241,14 @@ class SingletonMethod extends MethodBase, TSingletonMethod {
216
241
* end
217
242
* ```
218
243
*/
219
- override predicate isPrivate ( ) {
220
- exists ( Namespace n , string name |
221
- any ( PrivateClassMethod p ) .modifiesMethod ( n , name ) and
222
- isDeclaredIn ( this , n , name )
244
+ override predicate isPrivate ( ) { super .isPrivate ( ) }
245
+
246
+ override VisibilityModifier getVisibilityModifier ( ) {
247
+ result .getEnclosingModule ( ) = this .getEnclosingModule ( ) and
248
+ (
249
+ result .getMethodArgument ( ) = this
250
+ or
251
+ result .getMethodArgument ( ) .getConstantValue ( ) .getStringlikeValue ( ) = this .getName ( )
223
252
)
224
253
}
225
254
}
0 commit comments