1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Evgeny Mandrikov - initial API and implementation 10 * 11 *******************************************************************************/ 12 package org.jacoco.core.test.filter.targets; 13 14 import static org.jacoco.core.test.validation.targets.Stubs.f; 15 import static org.jacoco.core.test.validation.targets.Stubs.nop; 16 17 import java.io.Closeable; 18 import java.io.IOException; 19 20 /** 21 * This test target is a try-with-resources statement. 22 */ 23 public class TryWithResources { 24 25 private static class Resource implements Closeable { 26 @Override 27 public void close() { 28 } 29 } 30 31 /** 32 * Closing performed using {@link org.objectweb.asm.Opcodes#INVOKEVIRTUAL} 33 * or {@link org.objectweb.asm.Opcodes#INVOKEINTERFACE} depending on a class 34 * of resource. 35 */ 36 private static Object test() throws Exception { 37 nop(); // $line-test.before$ 38 try ( // $line-test.try$ 39 Resource r1 = new Resource(); // $line-test.open1$ 40 Closeable r2 = new Resource(); // $line-test.open2$ 41 AutoCloseable r3 = new Resource() // $line-test.open3$ 42 ) { 43 return read(r1, r2, r3); // $line-test.body$ 44 } // $line-test.close$ 45 catch (Exception e) { 46 nop(); // $line-test.catch$ 47 throw e; 48 } finally { 49 nop(); // $line-test.finally$ 50 } 51 } 52 53 private static void test2() throws Exception { 54 nop(); // $line-test2.before$ 55 try ( // $line-test2.try$ 56 Resource r1 = new Resource(); // $line-test2.open1$ 57 Closeable r2 = new Resource(); // $line-test2.open2$ 58 AutoCloseable r3 = new Resource() // $line-test2.open3$ 59 ) { 60 read(r1, r2, r3); // $line-test2.body$ 61 } // $line-test2.close$ 62 catch (Exception e) { 63 nop(); // $line-test2.catch$ 64 } finally { 65 nop(); // $line-test2.finally$ 66 } 67 nop(); // $line-test2.after$ 68 } 69 70 private static Object returnInBody() throws IOException { 71 try ( // $line-returnInBody.try$ 72 Closeable r = new Resource() // $line-returnInBody.open$ 73 ) { 74 return read(r); // $line-returnInBody.return$ 75 } // $line-returnInBody.close$ 76 } 77 78 private static void nested() { 79 try ( // $line-nested.try1$ 80 Resource r1 = new Resource() // $line-nested.open1$ 81 ) { 82 83 try ( // $line-nested.try2$ 84 Resource r2 = new Resource() // $line-nested.open2$ 85 ) { 86 nop(r1.toString() + r2.toString()); // $line-nested.body$ 87 } // $line-nested.close2$ 88 catch (Exception e) { 89 nop(); // $line-nested.catch2$ 90 } finally { 91 nop(); // $line-nested.finally2$ 92 } 93 94 } // $line-nested.close1$ 95 catch (Exception e) { 96 nop(); // $line-nested.catch1$ 97 } finally { 98 99 try ( // $line-nested.try3$ 100 Resource r2 = new Resource() // $line-nested.open3$ 101 ) { 102 nop(r2); // $line-nested.body3$ 103 } // $line-nested.close3$ 104 catch (Exception e) { 105 nop(); // $line-nested.catch3$ 106 } finally { 107 nop(); // $line-nested.finally3$ 108 } 109 110 } 111 } 112 113 /** 114 * In this case bytecode will contain 3 copies of <code>finally</code> 115 * block, each containing 2 branches, resulting in 6 branches in total. One 116 * could think that this is artifact of try-with-resources, but the same 117 * happens without it. 118 */ 119 private static Object returnInCatch() { 120 try ( // $line-returnInCatch.try1$ 121 Resource r = new Resource() // $line-returnInCatch.open$ 122 ) { 123 read(r); 124 } // $line-returnInCatch.close$ 125 catch (Exception e) { 126 return null; 127 } finally { 128 nop(!f()); // $line-returnInCatch.finally1$ 129 } 130 131 try { // $line-returnInCatch.try2$ 132 read(new Resource()); 133 } catch (Exception e) { 134 return null; 135 } finally { 136 nop(!f()); // $line-returnInCatch.finally2$ 137 } 138 139 return null; 140 } 141 142 private static Object read(Object r1, Object r2, Object r3) { 143 return r1.toString() + r2.toString() + r3.toString(); 144 } 145 146 private static Object read(Object r1) { 147 return r1.toString(); 148 } 149 150 public static void main(String[] args) throws Exception { 151 test(); 152 test2(); 153 returnInBody(); 154 nested(); 155 156 returnInCatch(); 157 158 empty(); 159 handwritten(); 160 } 161 162 /* 163 * Corner cases 164 */ 165 166 private static void empty() throws Exception { 167 try ( // $line-empty.try$ 168 Closeable r = new Resource() // $line-empty.open$ 169 ) { 170 } // $line-empty.close$ 171 } 172 173 private static void handwritten() throws IOException { 174 Closeable r = new Resource(); 175 Throwable primaryExc = null; 176 try { 177 nop(r); 178 } catch (Throwable t) { 179 primaryExc = t; 180 throw t; 181 } finally { 182 if (r != null) { // $line-handwritten$ 183 if (primaryExc != null) { 184 try { 185 r.close(); 186 } catch (Throwable suppressedExc) { 187 primaryExc.addSuppressed(suppressedExc); 188 } 189 } else { 190 r.close(); 191 } 192 } 193 } 194 } 195 196 private static void throwInBody() throws IOException { 197 try ( // $line-throwInBody.try$ 198 Closeable r = new Resource()) { 199 nop(r); 200 throw new RuntimeException(); 201 } // $line-throwInBody.close$ 202 } 203 204 } 205