@@ -36,8 +36,25 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
3636 result = BodyStmt .super .getAChild ( pred )
3737 }
3838
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+
3947 /** 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 ( ) }
4158}
4259
4360/**
@@ -47,45 +64,40 @@ class MethodBase extends Callable, BodyStmt, Scope, TMethodBase {
4764private class MethodModifier extends MethodCall {
4865 /** Gets the name of the method that this call applies to. */
4966 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- }
6067}
6168
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 {
6471 private Namespace namespace ;
6572 private int position ;
6673
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+ }
6882
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
8390 }
84- }
8591
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+ }
89101}
90102
91103/** A normal method. */
@@ -140,28 +152,41 @@ class Method extends MethodBase, TMethod {
140152 * ```
141153 */
142154 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"
147156 or
148157 // Top-level methods are private members of the Object class
149158 this .getEnclosingModule ( ) instanceof Toplevel
150159 }
151160
161+ override predicate isPublic ( ) { super .isPublic ( ) and not this .isPrivate ( ) }
162+
152163 final override Parameter getParameter ( int n ) {
153164 toGenerated ( result ) = g .getParameters ( ) .getChild ( n )
154165 }
155166
156167 final override string toString ( ) { result = this .getName ( ) }
157- }
158168
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+ }
165190}
166191
167192/** A singleton method. */
@@ -216,10 +241,14 @@ class SingletonMethod extends MethodBase, TSingletonMethod {
216241 * end
217242 * ```
218243 */
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 ( )
223252 )
224253 }
225254}
0 commit comments