@@ -25,56 +25,75 @@ private predicate gemFileStep(Gem::GemSpec gem, Folder folder, int n) {
25
25
}
26
26
27
27
/**
28
- * A callable method or accessor from either the Ruby Standard Library, a 3rd party library, or from the source .
28
+ * Gets the namespace of an endpoint in `file` .
29
29
*/
30
- class Endpoint extends DataFlow:: MethodNode {
31
- Endpoint ( ) { this .isPublic ( ) and not isUninteresting ( this ) }
30
+ string getNamespace ( File file ) {
31
+ exists ( Folder folder | folder = file .getParentContainer ( ) |
32
+ // The nearest gemspec to this endpoint, if one exists
33
+ result = min ( Gem:: GemSpec g , int n | gemFileStep ( g , folder , n ) | g order by n ) .getName ( )
34
+ or
35
+ not gemFileStep ( _, folder , _) and
36
+ result = ""
37
+ )
38
+ }
32
39
33
- File getFile ( ) { result = this .getLocation ( ) .getFile ( ) }
40
+ abstract class Endpoint instanceof DataFlow:: Node {
41
+ string getNamespace ( ) { result = getNamespace ( super .getLocation ( ) .getFile ( ) ) }
34
42
35
- string getName ( ) { result = this . getMethodName ( ) }
43
+ string getFileName ( ) { result = super . getLocation ( ) . getFile ( ) . getBaseName ( ) }
36
44
37
- /**
38
- * Gets the namespace of this endpoint.
39
- */
40
- bindingset [ this ]
41
- string getNamespace ( ) {
42
- exists ( Folder folder | folder = this .getFile ( ) .getParentContainer ( ) |
43
- // The nearest gemspec to this endpoint, if one exists
44
- result = min ( Gem:: GemSpec g , int n | gemFileStep ( g , folder , n ) | g order by n ) .getName ( )
45
- or
46
- not gemFileStep ( _, folder , _) and
47
- result = ""
48
- )
45
+ string toString ( ) { result = super .toString ( ) }
46
+
47
+ Location getLocation ( ) { result = super .getLocation ( ) }
48
+
49
+ abstract string getType ( ) ;
50
+
51
+ abstract string getName ( ) ;
52
+
53
+ abstract string getParameters ( ) ;
54
+
55
+ abstract boolean getSupportedStatus ( ) ;
56
+
57
+ abstract string getSupportedType ( ) ;
58
+ }
59
+
60
+ /**
61
+ * A callable method or accessor from source code.
62
+ */
63
+ class MethodEndpoint extends Endpoint instanceof DataFlow:: MethodNode {
64
+ MethodEndpoint ( ) {
65
+ this .isPublic ( ) and
66
+ not isUninteresting ( this )
49
67
}
50
68
69
+ DataFlow:: MethodNode getNode ( ) { result = this }
70
+
71
+ override string getName ( ) { result = super .getMethodName ( ) }
72
+
51
73
/**
52
74
* Gets the unbound type name of this endpoint.
53
75
*/
54
- bindingset [ this ]
55
- string getTypeName ( ) {
76
+ override string getType ( ) {
56
77
result =
57
- any ( DataFlow:: ModuleNode m | m .getOwnInstanceMethod ( this .getMethodName ( ) ) = this )
58
- .getQualifiedName ( ) or
78
+ any ( DataFlow:: ModuleNode m | m .getOwnInstanceMethod ( this .getName ( ) ) = this ) .getQualifiedName ( ) or
59
79
result =
60
- any ( DataFlow:: ModuleNode m | m .getOwnSingletonMethod ( this .getMethodName ( ) ) = this )
80
+ any ( DataFlow:: ModuleNode m | m .getOwnSingletonMethod ( this .getName ( ) ) = this )
61
81
.getQualifiedName ( ) + "!"
62
82
}
63
83
64
84
/**
65
85
* Gets the parameter types of this endpoint.
66
86
*/
67
- bindingset [ this ]
68
- string getParameterTypes ( ) {
69
- // For now, return the names of postional and keyword parameters. We don't always have type information, so we can't return type names.
87
+ override string getParameters ( ) {
88
+ // For now, return the names of positional and keyword parameters. We don't always have type information, so we can't return type names.
70
89
// We don't yet handle splat params or block params.
71
90
result =
72
91
"(" +
73
92
concat ( string key , string value |
74
- value = any ( int i | i .toString ( ) = key | this .asCallable ( ) .getParameter ( i ) ) .getName ( )
93
+ value = any ( int i | i .toString ( ) = key | super .asCallable ( ) .getParameter ( i ) ) .getName ( )
75
94
or
76
95
exists ( DataFlow:: ParameterNode param |
77
- param = this .asCallable ( ) .getKeywordParameter ( key )
96
+ param = super .asCallable ( ) .getKeywordParameter ( key )
78
97
|
79
98
value = key + ":"
80
99
)
@@ -89,11 +108,11 @@ class Endpoint extends DataFlow::MethodNode {
89
108
90
109
/** Holds if this API is a known source. */
91
110
pragma [ nomagic]
92
- abstract predicate isSource ( ) ;
111
+ predicate isSource ( ) { this . getNode ( ) instanceof SourceCallable }
93
112
94
113
/** Holds if this API is a known sink. */
95
114
pragma [ nomagic]
96
- abstract predicate isSink ( ) ;
115
+ predicate isSink ( ) { this . getNode ( ) instanceof SinkCallable }
97
116
98
117
/** Holds if this API is a known neutral. */
99
118
pragma [ nomagic]
@@ -107,9 +126,11 @@ class Endpoint extends DataFlow::MethodNode {
107
126
this .hasSummary ( ) or this .isSource ( ) or this .isSink ( ) or this .isNeutral ( )
108
127
}
109
128
110
- boolean getSupportedStatus ( ) { if this .isSupported ( ) then result = true else result = false }
129
+ override boolean getSupportedStatus ( ) {
130
+ if this .isSupported ( ) then result = true else result = false
131
+ }
111
132
112
- string getSupportedType ( ) {
133
+ override string getSupportedType ( ) {
113
134
this .isSink ( ) and result = "sink"
114
135
or
115
136
this .isSource ( ) and result = "source"
@@ -131,7 +152,7 @@ string methodClassification(Call method) {
131
152
132
153
class TestFile extends File {
133
154
TestFile ( ) {
134
- this .getRelativePath ( ) .regexpMatch ( ".*(test|spec).+" ) and
155
+ this .getRelativePath ( ) .regexpMatch ( ".*(test|spec|examples ).+" ) and
135
156
not this .getAbsolutePath ( ) .matches ( "%/ql/test/%" ) // allows our test cases to work
136
157
}
137
158
}
@@ -163,10 +184,32 @@ class SourceCallable extends DataFlow::CallableNode {
163
184
}
164
185
165
186
/**
166
- * A class of effectively public callables from source code.
187
+ * A module defined in source code
167
188
*/
168
- class PublicEndpointFromSource extends Endpoint {
169
- override predicate isSource ( ) { this instanceof SourceCallable }
189
+ class ModuleEndpoint extends Endpoint {
190
+ private DataFlow:: ModuleNode moduleNode ;
191
+
192
+ ModuleEndpoint ( ) {
193
+ this =
194
+ min ( DataFlow:: Node n , Location loc |
195
+ n .asExpr ( ) .getExpr ( ) = moduleNode .getADeclaration ( ) and
196
+ loc = n .getLocation ( )
197
+ |
198
+ n order by loc .getFile ( ) .getAbsolutePath ( ) , loc .getStartLine ( ) , loc .getStartColumn ( )
199
+ ) and
200
+ not moduleNode .( Module ) .isBuiltin ( ) and
201
+ not moduleNode .getLocation ( ) .getFile ( ) instanceof TestFile
202
+ }
203
+
204
+ DataFlow:: ModuleNode getNode ( ) { result = moduleNode }
205
+
206
+ override string getType ( ) { result = this .getNode ( ) .getQualifiedName ( ) }
207
+
208
+ override string getName ( ) { result = "" }
209
+
210
+ override string getParameters ( ) { result = "" }
211
+
212
+ override boolean getSupportedStatus ( ) { result = false }
170
213
171
- override predicate isSink ( ) { this instanceof SinkCallable }
214
+ override string getSupportedType ( ) { result = "" }
172
215
}
0 commit comments