@@ -104,15 +104,15 @@ class InvokeNode extends DataFlow::SourceNode {
104104 }
105105
106106 /** Gets an abstract value representing possible callees of this call site. */
107- AbstractValue getACalleeValue ( ) { result = InvokeNode :: getACalleeValue ( this ) }
107+ final AbstractValue getACalleeValue ( ) { result = getCalleeNode ( ) . analyze ( ) . getAValue ( ) }
108108
109109 /**
110110 * Gets a potential callee of this call site.
111111 *
112112 * To alter the call graph as seen by the interprocedural data flow libraries, override
113113 * the `getACallee(int imprecision)` predicate instead.
114114 */
115- Function getACallee ( ) { result = InvokeNode :: getACallee ( this ) }
115+ final Function getACallee ( ) { result = getACallee ( _ ) }
116116
117117 /**
118118 * Gets a callee of this call site where `imprecision` is a heuristic measure of how
@@ -125,7 +125,20 @@ class InvokeNode extends DataFlow::SourceNode {
125125 * This predicate can be overridden to alter the call graph used by the interprocedural
126126 * data flow libraries.
127127 */
128- Function getACallee ( int imprecision ) { result = InvokeNode:: getACallee ( this , imprecision ) }
128+ cached
129+ Function getACallee ( int imprecision ) {
130+ result .flow ( ) = getCalleeNode ( ) .getAFunctionValue ( imprecision )
131+ or
132+ imprecision = 0 and
133+ exists ( InvokeExpr expr | expr = this .( DataFlow:: Impl:: ExplicitInvokeNode ) .asExpr ( ) |
134+ result = expr .getResolvedCallee ( )
135+ or
136+ exists ( DataFlow:: ClassNode cls |
137+ expr .( SuperCall ) .getBinder ( ) = cls .getAnInstanceMethodOrConstructor ( ) .getFunction ( ) and
138+ result = cls .getADirectSuperClass ( ) .getConstructor ( ) .getFunction ( )
139+ )
140+ )
141+ }
129142
130143 /**
131144 * Holds if the approximation of possible callees for this call site is
@@ -173,60 +186,6 @@ class InvokeNode extends DataFlow::SourceNode {
173186 }
174187}
175188
176- /** Auxiliary module used to cache a few related predicates together. */
177- cached
178- private module InvokeNode {
179- /** Gets an abstract value representing possible callees of `invk`. */
180- cached
181- AbstractValue getACalleeValue ( InvokeNode invk ) {
182- result = invk .getCalleeNode ( ) .analyze ( ) .getAValue ( )
183- }
184-
185- /** Gets a potential callee of `invk` based on dataflow analysis results. */
186- private Function getACalleeFromDataflow ( InvokeNode invk ) {
187- result = getACalleeValue ( invk ) .( AbstractCallable ) .getFunction ( )
188- }
189-
190- /** Gets a potential callee of `invk`. */
191- cached
192- Function getACallee ( InvokeNode invk ) {
193- result = getACalleeFromDataflow ( invk )
194- or
195- not exists ( getACalleeFromDataflow ( invk ) ) and
196- result = invk .( DataFlow:: Impl:: ExplicitInvokeNode ) .asExpr ( ) .( InvokeExpr ) .getResolvedCallee ( )
197- }
198-
199- /**
200- * Gets a callee of `invk` where `imprecision` is a heuristic measure of how
201- * likely it is that `callee` is only suggested as a potential callee due to
202- * imprecise analysis of global variables and is not, in fact, a viable callee at all.
203- *
204- * Callees with imprecision zero, in particular, have either been derived without
205- * considering global variables, or are calls to a global variable within the same file.
206- */
207- cached
208- Function getACallee ( InvokeNode invk , int imprecision ) {
209- result = getACallee ( invk ) and
210- (
211- // if global flow was used to derive the callee, we may be imprecise
212- if invk .isIndefinite ( "global" )
213- then
214- // callees within the same file are probably genuine
215- result .getFile ( ) = invk .getFile ( ) and imprecision = 0
216- or
217- // calls to global functions declared in an externs file are fairly
218- // safe as well
219- result .inExternsFile ( ) and imprecision = 1
220- or
221- // otherwise we make worst-case assumptions
222- imprecision = 2
223- else
224- // no global flow, so no imprecision
225- imprecision = 0
226- )
227- }
228- }
229-
230189/** A data flow node corresponding to a function call without `new`. */
231190class CallNode extends InvokeNode {
232191 override DataFlow:: Impl:: CallNodeDef impl ;
@@ -657,6 +616,8 @@ class ClassNode extends DataFlow::SourceNode {
657616
658617 /**
659618 * Gets a direct super class of this class.
619+ *
620+ * This predicate can be overridden to customize the class hierarchy.
660621 */
661622 ClassNode getADirectSuperClass ( ) { result .getAClassReference ( ) .flowsTo ( getASuperClassNode ( ) ) }
662623
@@ -686,8 +647,10 @@ class ClassNode extends DataFlow::SourceNode {
686647
687648 /**
688649 * Gets a dataflow node that refers to this class object.
650+ *
651+ * This predicate can be overridden to customize the tracking of class objects.
689652 */
690- private DataFlow:: SourceNode getAClassReference ( DataFlow:: TypeTracker t ) {
653+ DataFlow:: SourceNode getAClassReference ( DataFlow:: TypeTracker t ) {
691654 t .start ( ) and
692655 result .( AnalyzedNode ) .getAValue ( ) = getAbstractClassValue ( )
693656 or
@@ -698,14 +661,16 @@ class ClassNode extends DataFlow::SourceNode {
698661 * Gets a dataflow node that refers to this class object.
699662 */
700663 cached
701- DataFlow:: SourceNode getAClassReference ( ) {
664+ final DataFlow:: SourceNode getAClassReference ( ) {
702665 result = getAClassReference ( DataFlow:: TypeTracker:: end ( ) )
703666 }
704667
705668 /**
706669 * Gets a dataflow node that refers to an instance of this class.
670+ *
671+ * This predicate can be overridden to customize the tracking of class instances.
707672 */
708- private DataFlow:: SourceNode getAnInstanceReference ( DataFlow:: TypeTracker t ) {
673+ DataFlow:: SourceNode getAnInstanceReference ( DataFlow:: TypeTracker t ) {
709674 result = getAClassReference ( t .continue ( ) ) .getAnInstantiation ( )
710675 or
711676 t .start ( ) and
@@ -740,10 +705,34 @@ class ClassNode extends DataFlow::SourceNode {
740705 * Gets a dataflow node that refers to an instance of this class.
741706 */
742707 cached
743- DataFlow:: SourceNode getAnInstanceReference ( ) {
708+ final DataFlow:: SourceNode getAnInstanceReference ( ) {
744709 result = getAnInstanceReference ( DataFlow:: TypeTracker:: end ( ) )
745710 }
746711
712+ /**
713+ * Gets a property read that accesses the property `name` on an instance of this class.
714+ *
715+ * Concretely, this holds when the base is an instance of this class or a subclass thereof.
716+ *
717+ * This predicate may be overridden to customize the class hierarchy analysis.
718+ */
719+ DataFlow:: PropRead getAnInstanceMemberAccess ( string name ) {
720+ result = getAnInstanceReference ( ) .getAPropertyRead ( name )
721+ or
722+ exists ( DataFlow:: ClassNode subclass |
723+ result = subclass .getAnInstanceMemberAccess ( name ) and
724+ not exists ( subclass .getAnInstanceMember ( name ) ) and
725+ subclass = getADirectSubClass ( )
726+ )
727+ }
728+
729+ /**
730+ * Gets an access to a static member of this class.
731+ */
732+ DataFlow:: PropRead getAStaticMemberAccess ( string name ) {
733+ result = getAClassReference ( ) .getAPropertyRead ( name )
734+ }
735+
747736 /**
748737 * Holds if this class is exposed in the global scope through the given qualified name.
749738 */
0 commit comments