@@ -37,12 +37,15 @@ class PipeCall extends DataFlow::MethodCallNode {
3737 * Gets a reference to a value that is known to not be a Node.js stream.
3838 * This is used to exclude pipe calls on non-stream objects from analysis.
3939 */
40- DataFlow:: Node getNonNodeJsStreamType ( ) {
40+ private DataFlow:: Node getNonNodeJsStreamType ( ) {
4141 result = getNonStreamApi ( ) .getAValueReachableFromSource ( )
4242}
4343
44- //highland, arktype execa
45- API:: Node getNonStreamApi ( ) {
44+ /**
45+ * Gets API nodes from modules that are known to not provide Node.js streams.
46+ * This includes reactive programming libraries, frontend frameworks, and other non-stream APIs.
47+ */
48+ private API:: Node getNonStreamApi ( ) {
4649 exists ( string moduleName |
4750 moduleName
4851 .regexpMatch ( [
@@ -65,12 +68,12 @@ API::Node getNonStreamApi() {
6568 * Gets the method names used to register event handlers on Node.js streams.
6669 * These methods are used to attach handlers for events like `error`.
6770 */
68- string getEventHandlerMethodName ( ) { result = [ "on" , "once" , "addListener" ] }
71+ private string getEventHandlerMethodName ( ) { result = [ "on" , "once" , "addListener" ] }
6972
7073/**
7174 * Gets the method names that are chainable on Node.js streams.
7275 */
73- string getChainableStreamMethodName ( ) {
76+ private string getChainableStreamMethodName ( ) {
7477 result =
7578 [
7679 "setEncoding" , "pause" , "resume" , "unpipe" , "destroy" , "cork" , "uncork" , "setDefaultEncoding" ,
@@ -81,14 +84,14 @@ string getChainableStreamMethodName() {
8184/**
8285 * Gets the method names that are not chainable on Node.js streams.
8386 */
84- string getNonchainableStreamMethodName ( ) {
87+ private string getNonchainableStreamMethodName ( ) {
8588 result = [ "read" , "write" , "end" , "pipe" , "unshift" , "push" , "isPaused" , "wrap" , "emit" ]
8689}
8790
8891/**
8992 * Gets the property names commonly found on Node.js streams.
9093 */
91- string getStreamPropertyName ( ) {
94+ private string getStreamPropertyName ( ) {
9295 result =
9396 [
9497 "readable" , "writable" , "destroyed" , "closed" , "readableHighWaterMark" , "readableLength" ,
@@ -103,7 +106,7 @@ string getStreamPropertyName() {
103106/**
104107 * Gets all method names commonly found on Node.js streams.
105108 */
106- string getStreamMethodName ( ) {
109+ private string getStreamMethodName ( ) {
107110 result = [ getChainableStreamMethodName ( ) , getNonchainableStreamMethodName ( ) ]
108111}
109112
@@ -123,7 +126,7 @@ class ErrorHandlerRegistration extends DataFlow::MethodCallNode {
123126 * Connects destination streams to their corresponding pipe call nodes.
124127 * Connects streams to their chainable methods.
125128 */
126- predicate streamFlowStep ( DataFlow:: Node streamNode , DataFlow:: Node relatedNode ) {
129+ private predicate streamFlowStep ( DataFlow:: Node streamNode , DataFlow:: Node relatedNode ) {
127130 exists ( PipeCall pipe |
128131 streamNode = pipe .getDestinationStream ( ) and
129132 relatedNode = pipe
@@ -139,42 +142,42 @@ predicate streamFlowStep(DataFlow::Node streamNode, DataFlow::Node relatedNode)
139142/**
140143 * Tracks the result of a pipe call as it flows through the program.
141144 */
142- private DataFlow:: SourceNode pipeResultTracker ( DataFlow:: TypeTracker t , PipeCall pipe ) {
145+ private DataFlow:: SourceNode destinationStreamRef ( DataFlow:: TypeTracker t , PipeCall pipe ) {
143146 t .start ( ) and result = pipe .getALocalSource ( )
144147 or
145148 exists ( DataFlow:: SourceNode prev |
146- prev = pipeResultTracker ( t .continue ( ) , pipe ) and
149+ prev = destinationStreamRef ( t .continue ( ) , pipe ) and
147150 streamFlowStep ( result .getALocalUse ( ) , prev )
148151 )
149152 or
150- exists ( DataFlow:: TypeTracker t2 | result = pipeResultTracker ( t2 , pipe ) .track ( t2 , t ) )
153+ exists ( DataFlow:: TypeTracker t2 | result = destinationStreamRef ( t2 , pipe ) .track ( t2 , t ) )
151154}
152155
153156/**
154157 * Gets a reference to the result of a pipe call.
155158 */
156- private DataFlow:: SourceNode pipeResultRef ( PipeCall pipe ) {
157- result = pipeResultTracker ( DataFlow:: TypeTracker:: end ( ) , pipe )
159+ private DataFlow:: SourceNode destinationStreamRef ( PipeCall pipe ) {
160+ result = destinationStreamRef ( DataFlow:: TypeTracker:: end ( ) , pipe )
158161}
159162
160163/**
161164 * Holds if the pipe call result is used to call a non-stream method.
162165 * Since pipe() returns the destination stream, this finds cases where
163166 * the destination stream is used with methods not typical of streams.
164167 */
165- predicate isPipeFollowedByNonStreamMethod ( PipeCall pipeCall ) {
168+ private predicate isPipeFollowedByNonStreamMethod ( PipeCall pipeCall ) {
166169 exists ( DataFlow:: MethodCallNode call |
167- call = pipeResultRef ( pipeCall ) .getAMethodCall ( ) and
170+ call = destinationStreamRef ( pipeCall ) .getAMethodCall ( ) and
168171 not call .getMethodName ( ) = getStreamMethodName ( )
169172 )
170173}
171174
172175/**
173176 * Holds if the pipe call result is used to access a property that is not typical of streams.
174177 */
175- predicate isPipeFollowedByNonStreamProperty ( PipeCall pipeCall ) {
178+ private predicate isPipeFollowedByNonStreamProperty ( PipeCall pipeCall ) {
176179 exists ( DataFlow:: PropRef propRef |
177- propRef = pipeResultRef ( pipeCall ) .getAPropertyRead ( ) and
180+ propRef = destinationStreamRef ( pipeCall ) .getAPropertyRead ( ) and
178181 not propRef .getPropertyName ( ) = [ getStreamPropertyName ( ) , getStreamMethodName ( ) ]
179182 )
180183}
@@ -183,7 +186,7 @@ predicate isPipeFollowedByNonStreamProperty(PipeCall pipeCall) {
183186 * Holds if the pipe call result is used in a non-stream-like way,
184187 * either by calling non-stream methods or accessing non-stream properties.
185188 */
186- predicate isPipeFollowedByNonStreamAccess ( PipeCall pipeCall ) {
189+ private predicate isPipeFollowedByNonStreamAccess ( PipeCall pipeCall ) {
187190 isPipeFollowedByNonStreamMethod ( pipeCall ) or
188191 isPipeFollowedByNonStreamProperty ( pipeCall )
189192}
@@ -192,65 +195,66 @@ predicate isPipeFollowedByNonStreamAccess(PipeCall pipeCall) {
192195 * Gets a reference to a stream that may be the source of the given pipe call.
193196 * Uses type back-tracking to trace stream references in the data flow.
194197 */
195- private DataFlow:: SourceNode streamRef ( DataFlow:: TypeBackTracker t , PipeCall pipeCall ) {
198+ private DataFlow:: SourceNode sourceStreamRef ( DataFlow:: TypeBackTracker t , PipeCall pipeCall ) {
196199 t .start ( ) and
197200 result = pipeCall .getSourceStream ( ) .getALocalSource ( )
198201 or
199202 exists ( DataFlow:: SourceNode prev |
200- prev = streamRef ( t .continue ( ) , pipeCall ) and
203+ prev = sourceStreamRef ( t .continue ( ) , pipeCall ) and
201204 streamFlowStep ( result .getALocalUse ( ) , prev )
202205 )
203206 or
204- exists ( DataFlow:: TypeBackTracker t2 | result = streamRef ( t2 , pipeCall ) .backtrack ( t2 , t ) )
207+ exists ( DataFlow:: TypeBackTracker t2 | result = sourceStreamRef ( t2 , pipeCall ) .backtrack ( t2 , t ) )
205208}
206209
207210/**
208211 * Gets a reference to a stream that may be the source of the given pipe call.
209212 */
210- private DataFlow:: SourceNode streamRef ( PipeCall pipeCall ) {
211- result = streamRef ( DataFlow:: TypeBackTracker:: end ( ) , pipeCall )
213+ private DataFlow:: SourceNode sourceStreamRef ( PipeCall pipeCall ) {
214+ result = sourceStreamRef ( DataFlow:: TypeBackTracker:: end ( ) , pipeCall )
212215}
213216
214217/**
215218 * Holds if the source stream of the given pipe call has an `error` handler registered.
216219 */
217- predicate hasErrorHandlerRegistered ( PipeCall pipeCall ) {
220+ private predicate hasErrorHandlerRegistered ( PipeCall pipeCall ) {
218221 exists ( ErrorHandlerRegistration handler |
219- handler = streamRef ( pipeCall ) .getAMethodCall ( getEventHandlerMethodName ( ) )
222+ handler = sourceStreamRef ( pipeCall ) .getAMethodCall ( getEventHandlerMethodName ( ) )
220223 )
221224 or
222225 hasPlumber ( pipeCall )
223226}
224227
225228/**
226- * Holds if one of the arguments of the pipe call is a `gulp-plumber` monkey patch.
229+ * Holds if the pipe call uses `gulp-plumber`, which automatically handles stream errors.
230+ * Gulp-plumber is a Node.js module that prevents pipe breaking caused by errors from gulp plugins.
227231 */
228- predicate hasPlumber ( PipeCall pipeCall ) {
232+ private predicate hasPlumber ( PipeCall pipeCall ) {
229233 pipeCall .getDestinationStream ( ) .getALocalSource ( ) = API:: moduleImport ( "gulp-plumber" ) .getACall ( )
230234 or
231- streamRef + ( pipeCall ) = API:: moduleImport ( "gulp-plumber" ) .getACall ( )
235+ sourceStreamRef + ( pipeCall ) = API:: moduleImport ( "gulp-plumber" ) .getACall ( )
232236}
233237
234238/**
235239 * Holds if the source or destination of the given pipe call is identified as a non-Node.js stream.
236240 */
237- predicate hasNonNodeJsStreamSource ( PipeCall pipeCall ) {
238- streamRef ( pipeCall ) = getNonNodeJsStreamType ( ) or
239- pipeResultRef ( pipeCall ) = getNonNodeJsStreamType ( )
241+ private predicate hasNonNodeJsStreamSource ( PipeCall pipeCall ) {
242+ sourceStreamRef ( pipeCall ) = getNonNodeJsStreamType ( ) or
243+ destinationStreamRef ( pipeCall ) = getNonNodeJsStreamType ( )
240244}
241245
242246/**
243247 * Holds if the source stream of the given pipe call is used in a non-stream-like way.
244248 */
245249private predicate hasNonStreamSourceLikeUsage ( PipeCall pipeCall ) {
246250 exists ( DataFlow:: MethodCallNode call , string name |
247- call .getReceiver ( ) .getALocalSource ( ) = streamRef ( pipeCall ) and
251+ call .getReceiver ( ) .getALocalSource ( ) = sourceStreamRef ( pipeCall ) and
248252 name = call .getMethodName ( ) and
249253 not name = getStreamMethodName ( )
250254 )
251255 or
252256 exists ( DataFlow:: PropRef propRef , string propName |
253- propRef .getBase ( ) .getALocalSource ( ) = streamRef ( pipeCall ) and
257+ propRef .getBase ( ) .getALocalSource ( ) = sourceStreamRef ( pipeCall ) and
254258 propName = propRef .getPropertyName ( ) and
255259 not propName = [ getStreamPropertyName ( ) , getStreamMethodName ( ) ]
256260 )
@@ -259,9 +263,9 @@ private predicate hasNonStreamSourceLikeUsage(PipeCall pipeCall) {
259263/**
260264 * Holds if the pipe call destination stream has an error handler registered.
261265 */
262- predicate hasErrorHandlerDownstream ( PipeCall pipeCall ) {
266+ private predicate hasErrorHandlerDownstream ( PipeCall pipeCall ) {
263267 exists ( ErrorHandlerRegistration handler |
264- handler .getReceiver ( ) .getALocalSource ( ) = pipeResultRef ( pipeCall )
268+ handler .getReceiver ( ) .getALocalSource ( ) = destinationStreamRef ( pipeCall )
265269 )
266270}
267271
0 commit comments