/******************************************************************************* * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Evgeny Mandrikov - initial API and implementation * *******************************************************************************/ package org.jacoco.core.test.filter.targets; import static org.jacoco.core.test.validation.targets.Stubs.f; import static org.jacoco.core.test.validation.targets.Stubs.nop; import java.io.Closeable; import java.io.IOException; /** * This test target is a try-with-resources statement. */ public class TryWithResources { private static class Resource implements Closeable { @Override public void close() { } } /** * Closing performed using {@link org.objectweb.asm.Opcodes#INVOKEVIRTUAL} * or {@link org.objectweb.asm.Opcodes#INVOKEINTERFACE} depending on a class * of resource. */ private static Object test() throws Exception { nop(); // $line-test.before$ try ( // $line-test.try$ Resource r1 = new Resource(); // $line-test.open1$ Closeable r2 = new Resource(); // $line-test.open2$ AutoCloseable r3 = new Resource() // $line-test.open3$ ) { return read(r1, r2, r3); // $line-test.body$ } // $line-test.close$ catch (Exception e) { nop(); // $line-test.catch$ throw e; } finally { nop(); // $line-test.finally$ } } private static void test2() throws Exception { nop(); // $line-test2.before$ try ( // $line-test2.try$ Resource r1 = new Resource(); // $line-test2.open1$ Closeable r2 = new Resource(); // $line-test2.open2$ AutoCloseable r3 = new Resource() // $line-test2.open3$ ) { read(r1, r2, r3); // $line-test2.body$ } // $line-test2.close$ catch (Exception e) { nop(); // $line-test2.catch$ } finally { nop(); // $line-test2.finally$ } nop(); // $line-test2.after$ } private static Object returnInBody() throws IOException { try ( // $line-returnInBody.try$ Closeable r = new Resource() // $line-returnInBody.open$ ) { return read(r); // $line-returnInBody.return$ } // $line-returnInBody.close$ } private static void nested() { try ( // $line-nested.try1$ Resource r1 = new Resource() // $line-nested.open1$ ) { try ( // $line-nested.try2$ Resource r2 = new Resource() // $line-nested.open2$ ) { nop(r1.toString() + r2.toString()); // $line-nested.body$ } // $line-nested.close2$ catch (Exception e) { nop(); // $line-nested.catch2$ } finally { nop(); // $line-nested.finally2$ } } // $line-nested.close1$ catch (Exception e) { nop(); // $line-nested.catch1$ } finally { try ( // $line-nested.try3$ Resource r2 = new Resource() // $line-nested.open3$ ) { nop(r2); // $line-nested.body3$ } // $line-nested.close3$ catch (Exception e) { nop(); // $line-nested.catch3$ } finally { nop(); // $line-nested.finally3$ } } } /** * In this case bytecode will contain 3 copies of <code>finally</code> * block, each containing 2 branches, resulting in 6 branches in total. One * could think that this is artifact of try-with-resources, but the same * happens without it. */ private static Object returnInCatch() { try ( // $line-returnInCatch.try1$ Resource r = new Resource() // $line-returnInCatch.open$ ) { read(r); } // $line-returnInCatch.close$ catch (Exception e) { return null; } finally { nop(!f()); // $line-returnInCatch.finally1$ } try { // $line-returnInCatch.try2$ read(new Resource()); } catch (Exception e) { return null; } finally { nop(!f()); // $line-returnInCatch.finally2$ } return null; } private static Object read(Object r1, Object r2, Object r3) { return r1.toString() + r2.toString() + r3.toString(); } private static Object read(Object r1) { return r1.toString(); } public static void main(String[] args) throws Exception { test(); test2(); returnInBody(); nested(); returnInCatch(); empty(); handwritten(); } /* * Corner cases */ private static void empty() throws Exception { try ( // $line-empty.try$ Closeable r = new Resource() // $line-empty.open$ ) { } // $line-empty.close$ } private static void handwritten() throws IOException { Closeable r = new Resource(); Throwable primaryExc = null; try { nop(r); } catch (Throwable t) { primaryExc = t; throw t; } finally { if (r != null) { // $line-handwritten$ if (primaryExc != null) { try { r.close(); } catch (Throwable suppressedExc) { primaryExc.addSuppressed(suppressedExc); } } else { r.close(); } } } } private static void throwInBody() throws IOException { try ( // $line-throwInBody.try$ Closeable r = new Resource()) { nop(r); throw new RuntimeException(); } // $line-throwInBody.close$ } }