@@ -368,6 +368,36 @@ predicate hasNonlocalValue(FieldRead fr) {
368368 */
369369predicate localFlowStep ( Node node1 , Node node2 ) { simpleLocalFlowStep ( node1 , node2 ) }
370370
371+ /**
372+ * A method or constructor that returns the exact value of one of its parameters or the qualifier.
373+ *
374+ * Extend this class and override `returnsValue` to add additional value-preserving steps through a
375+ * method that should be added to the basic local flow step relation.
376+ *
377+ * These steps will be visible for all global data-flow purposes, as well as via
378+ * `DataFlow::Node.getASuccessor` and other related functions exposing intraprocedural dataflow.
379+ */
380+ abstract class ValuePreservingCallable extends Callable {
381+ /**
382+ * Holds if this callable returns precisely the value passed into argument `arg`.
383+ * `arg` is a parameter index, or is -1 to indicate the qualifier.
384+ */
385+ abstract predicate returnsValue ( int arg ) ;
386+ }
387+
388+ /**
389+ * A method or constructor that returns the exact value of its qualifier (e.g., `return this;`)
390+ *
391+ * Extend this class and override `returnsValue` to add additional value-preserving steps through a
392+ * method that should be added to the basic local flow step relation.
393+ *
394+ * These steps will be visible for all global data-flow purposes, as well as via
395+ * `DataFlow::Node.getASuccessor` and other related functions exposing intraprocedural dataflow.
396+ */
397+ abstract class FluentMethod extends ValuePreservingCallable {
398+ override predicate returnsValue ( int arg ) { arg = - 1 }
399+ }
400+
371401/**
372402 * INTERNAL: do not use.
373403 *
@@ -408,6 +438,17 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
408438 or
409439 summaryStep ( node1 , node2 , "value" )
410440 or
441+ exists ( MethodAccess ma , ValuePreservingCallable c , int argNo |
442+ ma .getCallee ( ) = c and c .returnsValue ( argNo )
443+ |
444+ node2 .asExpr ( ) = ma and
445+ (
446+ node1 .asExpr ( ) = ma .getArgument ( argNo )
447+ or
448+ argNo = - 1 and node1 .asExpr ( ) = ma .getQualifier ( )
449+ )
450+ )
451+ or
411452 exists ( MethodAccess ma , Method m |
412453 ma = node2 .asExpr ( ) and
413454 m = ma .getMethod ( ) and
0 commit comments