@@ -183,6 +183,10 @@ protected void updateReceiver(PointsToAnalysis bb, MethodFlowsGraphInfo calleeFl
183183 if (bb .optimizeReturnedParameter ()) {
184184 int paramIndex = calleeFlows .getMethod ().getTypeFlow ().getReturnedParameterIndex ();
185185 if (actualReturn != null && paramIndex == 0 ) {
186+ /*
187+ * The callee returns `this`. Propagate the receiver state to the actual-return.
188+ * See also InvokeTypeFlow#linkReturn() for more details.
189+ */
186190 actualReturn .addState (bb , receiverTypeState );
187191 }
188192 }
@@ -240,10 +244,21 @@ public void linkReturn(PointsToAnalysis bb, boolean isStatic, MethodFlowsGraphIn
240244 if (isStatic || paramNodeIndex != 0 ) {
241245 TypeFlow <?> actualParam = actualParameters [paramNodeIndex ];
242246 actualParam .addUse (bb , actualReturn );
247+ } else {
248+ /*
249+ * The callee returns `this`. The formal-receiver state is updated in
250+ * InvokeTypeFlow#updateReceiver() for each linked callee and every time
251+ * the formal-receiver is updated then the same update state is
252+ * propagated to the actual-return. One may think that we could simply
253+ * add a direct use link from the formal-receiver in the callee to the
254+ * actual-return in the caller to get the state propagation
255+ * automatically. But that would be wrong because then the actual-return
256+ * would get the state from *all* the other places that callee may be
257+ * called from, and that would defeat the purpose of this optimization:
258+ * we want just the receiver state from the caller of current invoke to
259+ * reach the actual-return.
260+ */
243261 }
244- // else {
245- // receiver object state is transferred in updateReceiver()
246- // }
247262 } else {
248263 /*
249264 * The callee may have a return type, hence the actualReturn is non-null,
0 commit comments