src/share/classes/com/sun/tools/javac/comp/Flow.java

Print this page

        

@@ -35,10 +35,13 @@
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.tree.JCTree.*;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.*;
 import static com.sun.tools.javac.code.TypeTags.*;
 
 /** This pass implements dataflow analysis for Java programs.

@@ -263,10 +266,14 @@
     /** The list of exceptions that are either caught or declared to be
      *  thrown.
      */
     List<Type> caught;
 
+    /** The list of unreferenced automatic resources.
+     */
+    Set<VarSymbol> unrefdResources;
+
     /** Set when processing a loop body the second time for DU analysis. */
     boolean loopPassTwo = false;
 
     /*-------------------- Environments ----------------------*/
 

@@ -961,10 +968,11 @@
         }
 
     public void visitTry(JCTry tree) {
         List<Type> caughtPrev = caught;
         List<Type> thrownPrev = thrown;
+        Set<VarSymbol> unrefdResourcesPrev = unrefdResources;
         thrown = List.nil();
         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
                     ((JCTypeDisjoint)l.head.param.vartype).components :
                     List.of(l.head.param.vartype);

@@ -975,20 +983,54 @@
         Bits uninitsTryPrev = uninitsTry;
         ListBuffer<PendingExit> prevPendingExits = pendingExits;
         pendingExits = new ListBuffer<PendingExit>();
         Bits initsTry = inits.dup();
         uninitsTry = uninits.dup();
+        unrefdResources = new HashSet<VarSymbol>();
+        for (JCTree resource : tree.resources) {
+            if (resource instanceof JCVariableDecl) {
+                JCVariableDecl vdecl = (JCVariableDecl) resource;
+                visitVarDef(vdecl);
+                unrefdResources.add(vdecl.sym);
+            } else if (resource instanceof JCExpression) {
+                scanExpr((JCExpression) resource);
+            } else {
+                throw new AssertionError(tree);  // parser error
+            }
+        }
+        for (JCTree resource : tree.resources) {
+            MethodSymbol topCloseMethod = (MethodSymbol)syms.autoCloseableType.tsym.members().lookup(names.close).sym;
+            List<Type> closeableSupertypes = resource.type.isCompound() ?
+                types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
+                List.of(resource.type);
+            for (Type sup : closeableSupertypes) {
+                if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
+                    MethodSymbol closeMethod = types.implementation(topCloseMethod, sup.tsym, types, true);
+                    for (Type t : closeMethod.getThrownTypes()) {
+                        markThrown(tree.body, t);
+                    }
+                }
+            }
+        }
         scanStat(tree.body);
         List<Type> thrownInTry = thrown;
         thrown = thrownPrev;
         caught = caughtPrev;
         boolean aliveEnd = alive;
         uninitsTry.andSet(uninits);
         Bits initsEnd = inits;
         Bits uninitsEnd = uninits;
         int nextadrCatch = nextadr;
 
+        if (!unrefdResources.isEmpty() &&
+                lint.isEnabled(Lint.LintCategory.ARM)) {
+            for (VarSymbol v : unrefdResources) {
+                log.warning(v.pos,
+                            "automatic.resource.not.referenced", v);
+            }
+        }
+
         List<Type> caughtInTry = List.nil();
         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
             alive = true;
             JCVariableDecl param = l.head.param;
             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?

@@ -1068,10 +1110,11 @@
             ListBuffer<PendingExit> exits = pendingExits;
             pendingExits = prevPendingExits;
             while (exits.nonEmpty()) pendingExits.append(exits.next());
         }
         uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
+        unrefdResources = unrefdResourcesPrev;
     }
 
     public void visitConditional(JCConditional tree) {
         scanCond(tree.cond);
         Bits initsBeforeElse = initsWhenFalse;

@@ -1291,12 +1334,20 @@
         // annotations don't get scanned
         tree.underlyingType.accept(this);
     }
 
     public void visitIdent(JCIdent tree) {
-        if (tree.sym.kind == VAR)
+        if (tree.sym.kind == VAR) {
             checkInit(tree.pos(), (VarSymbol)tree.sym);
+            referenced(tree.sym);
+        }
+    }
+
+    void referenced(Symbol sym) {
+        if (unrefdResources != null && unrefdResources.contains(sym)) {
+            unrefdResources.remove(sym);
+        }
     }
 
     public void visitTypeCast(JCTypeCast tree) {
         super.visitTypeCast(tree);
         if (!tree.type.isErroneous()