@@ -233,4 +233,107 @@ public void should_filter_safe_call_chain_followed_by_elvis() {
233233 assertReplacedBranches (m , replacements );
234234 }
235235
236+ /**
237+ * <pre>
238+ * data class B(val c: String)
239+ * fun example(b: B?): String =
240+ * b
241+ * ?.c
242+ * ?: ""
243+ * </pre>
244+ */
245+ @ Test
246+ public void should_filter_unoptimized_safe_call_followed_by_elvis () {
247+ final MethodNode m = new MethodNode (InstrSupport .ASM_API_VERSION , 0 ,
248+ "example" , "(LB;)Ljava/lang/String;" , null , null );
249+ m .visitVarInsn (Opcodes .ALOAD , 0 );
250+ final Label label = new Label ();
251+ m .visitJumpInsn (Opcodes .IFNULL , label );
252+ final AbstractInsnNode ifNullInstruction1 = m .instructions .getLast ();
253+ m .visitVarInsn (Opcodes .ALOAD , 0 );
254+ m .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "B" , "getC" ,
255+ "()Ljava/lang/String;" , false );
256+ m .visitVarInsn (Opcodes .ASTORE , 1 );
257+ m .visitVarInsn (Opcodes .ALOAD , 1 );
258+ m .visitJumpInsn (Opcodes .IFNULL , label );
259+ final AbstractInsnNode ifNullInstruction2 = m .instructions .getLast ();
260+ m .visitVarInsn (Opcodes .ALOAD , 1 );
261+ final Label next = new Label ();
262+ m .visitJumpInsn (Opcodes .GOTO , next );
263+ m .visitLabel (label );
264+ m .visitLdcInsn ("" );
265+ final AbstractInsnNode nullTarget = m .instructions .getLast ();
266+ m .visitLabel (next );
267+ m .visitInsn (Opcodes .ARETURN );
268+
269+ filter .filter (m , context , output );
270+
271+ assertIgnored (m );
272+ final HashMap <AbstractInsnNode , List <Replacement >> replacements = new HashMap <AbstractInsnNode , List <Replacement >>();
273+ replacements .put (ifNullInstruction1 , Arrays .asList ( //
274+ new Replacement (0 , ifNullInstruction1 , 0 ),
275+ new Replacement (1 , nullTarget , 0 )));
276+ replacements .put (ifNullInstruction2 , Arrays .asList ( //
277+ new Replacement (0 , ifNullInstruction2 , 0 ),
278+ new Replacement (1 , nullTarget , 0 )));
279+ assertReplacedBranches (m , replacements );
280+ }
281+
282+ /**
283+ * <pre>
284+ * data class A(val b: B)
285+ * data class B(val c: String)
286+ * fun example(a: A?): String? =
287+ * a
288+ * ?.b
289+ * ?.c
290+ * ?: ""
291+ * </pre>
292+ */
293+ @ Test
294+ public void should_filter_unoptimized_safe_call_chain_followed_by_elvis () {
295+ final MethodNode m = new MethodNode (InstrSupport .ASM_API_VERSION , 0 ,
296+ "example" , "(LA;)Ljava/lang/String;" , null , null );
297+ m .visitVarInsn (Opcodes .ALOAD , 0 );
298+ final Label label = new Label ();
299+ m .visitJumpInsn (Opcodes .IFNULL , label );
300+ final AbstractInsnNode ifNullInstruction1 = m .instructions .getLast ();
301+ m .visitVarInsn (Opcodes .ALOAD , 0 );
302+ m .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "A" , "getB" , "()LB;" , false );
303+ m .visitVarInsn (Opcodes .ASTORE , 1 );
304+ m .visitVarInsn (Opcodes .ALOAD , 1 );
305+ m .visitJumpInsn (Opcodes .IFNULL , label );
306+ final AbstractInsnNode ifNullInstruction2 = m .instructions .getLast ();
307+ m .visitVarInsn (Opcodes .ALOAD , 1 );
308+ m .visitMethodInsn (Opcodes .INVOKEVIRTUAL , "B" , "getC" ,
309+ "()Ljava/lang/String;" , false );
310+ m .visitVarInsn (Opcodes .ASTORE , 2 );
311+ m .visitVarInsn (Opcodes .ALOAD , 2 );
312+ m .visitJumpInsn (Opcodes .IFNULL , label );
313+ final AbstractInsnNode ifNullInstruction3 = m .instructions .getLast ();
314+ m .visitVarInsn (Opcodes .ALOAD , 2 );
315+ final Label next = new Label ();
316+ m .visitJumpInsn (Opcodes .GOTO , next );
317+ m .visitLabel (label );
318+ m .visitLdcInsn ("" );
319+ final AbstractInsnNode nullTarget = m .instructions .getLast ();
320+ m .visitLabel (next );
321+ m .visitInsn (Opcodes .ARETURN );
322+
323+ filter .filter (m , context , output );
324+
325+ assertIgnored (m );
326+ final HashMap <AbstractInsnNode , List <Replacement >> replacements = new HashMap <AbstractInsnNode , List <Replacement >>();
327+ replacements .put (ifNullInstruction1 , Arrays .asList ( //
328+ new Replacement (0 , ifNullInstruction1 , 0 ),
329+ new Replacement (1 , nullTarget , 0 )));
330+ replacements .put (ifNullInstruction2 , Arrays .asList ( //
331+ new Replacement (0 , ifNullInstruction2 , 0 ),
332+ new Replacement (1 , nullTarget , 0 )));
333+ replacements .put (ifNullInstruction3 , Arrays .asList ( //
334+ new Replacement (0 , ifNullInstruction3 , 0 ),
335+ new Replacement (1 , nullTarget , 0 )));
336+ assertReplacedBranches (m , replacements );
337+ }
338+
236339}
0 commit comments