--- old/src/share/classes/com/sun/tools/javac/code/Symbol.java 2013-08-21 16:37:24.906124421 -0400 +++ new/src/share/classes/com/sun/tools/javac/code/Symbol.java 2013-08-21 16:37:24.778123385 -0400 @@ -1223,6 +1223,9 @@ /** The extra (synthetic/mandated) parameters of the method. */ public List extraParams = List.nil(); + /** The captured local variables in an anonymous class */ + public List capturedLocals = List.nil(); + /** The parameters of the method. */ public List params = null; --- old/src/share/classes/com/sun/tools/javac/comp/Lower.java 2013-08-21 16:37:25.402128404 -0400 +++ new/src/share/classes/com/sun/tools/javac/comp/Lower.java 2013-08-21 16:37:25.275127376 -0400 @@ -2713,9 +2713,9 @@ for (List l = fvs; l.nonEmpty(); l = l.tail) { if (TreeInfo.isInitialConstructor(tree)) { final Name pName = proxyName(l.head.name); - m.extraParams = - m.extraParams.append((VarSymbol) - (proxies.lookup(pName).sym)); + m.capturedLocals = + m.capturedLocals.append((VarSymbol) + (proxies.lookup(pName).sym)); added = added.prepend( initField(tree.body.pos, pName)); } --- old/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java 2013-08-21 16:37:25.904132454 -0400 +++ new/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java 2013-08-21 16:37:25.777131426 -0400 @@ -657,6 +657,14 @@ databuf.appendChar(pool.put(s.name)); databuf.appendChar(flags); } + // Now write the captured locals + for (VarSymbol s : m.capturedLocals) { + final int flags = + ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | + ((int) m.flags() & SYNTHETIC); + databuf.appendChar(pool.put(s.name)); + databuf.appendChar(flags); + } endAttr(attrIndex); return 1; } else --- /dev/null 2013-08-19 16:11:23.102823479 -0400 +++ new/test/tools/javac/MethodParameters/CaptureTest.java 2013-08-21 16:37:26.268135371 -0400 @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8015701 + * @summary javac should generate method parameters correctly. + * @compile -parameters CaptureTest.java + * @run main CaptureTest + */ +import java.lang.Class; +import java.lang.reflect.Constructor; +import java.lang.reflect.Parameter; +import java.lang.reflect.Modifier; +import java.util.List; +import java.util.ArrayList; + +public class CaptureTest { + + private static final int SYNTHETIC = 0x1000; + private static final int MANDATED = 0x8000; + + public static void main(String... args) throws Exception { + new CaptureTest().run(); + } + + + private void run() throws Exception { + final ParameterNames pn = new ParameterNames(); + + pn.makeLocal("hello").check(); + pn.makeInner("hello").check(); + pn.makeAnon("hello").check(); + pn.makeAnonExtendsLocal("hello").check(); + pn.makeAnonExtendsInner("hello").check(); + + if(0 != errors) + throw new Exception("MethodParameters test failed with " + + errors + " errors"); + } + + private void error(final String msg) { + System.err.println("Error: " + msg); + errors++; + } + + int errors; + + abstract class Tester { + + final int field; + + public Tester(final int param) { + field = param; + } + + protected abstract String[] names(); + protected abstract int[] modifiers(); + protected abstract Class[] types(); + public abstract String message(); + + public void check() { + final Class cls = this.getClass(); + final Constructor ctor = cls.getDeclaredConstructors()[0]; + final Parameter[] params = ctor.getParameters(); + final String[] names = names(); + final int[] modifiers = modifiers(); + final Class[] types = types(); + + System.err.println("Testing class " + cls); + + if(params.length == names.length) { + for(int i = 0; i < names.length; i++) { + System.err.println("Testing parameter " + params[i].getName()); + if(!params[i].getName().equals(names[i])) + error("Expected parameter name " + names[i] + + " got " + params[i].getName()); + if(params[i].getModifiers() != modifiers[i]) + error("Expected parameter modifiers " + + modifiers[i] + " got " + + params[i].getModifiers()); + if(!params[i].getType().equals(types[i])) + error("Expected parameter type " + types[i] + + " got " + params[i].getType()); + } + } else + error("Expected " + names.length + " parameters"); + + } + + } + + class ParameterNames { + final String message = "hello"; + + private class InnerTester extends Tester { + public InnerTester(final int innerparam) { + super(innerparam); + } + + protected String[] names() { + final String[] names = { + "this$1", + "innerparam" + }; + return names; + } + + protected int[] modifiers() { + final int[] modifiers = { + Modifier.FINAL | SYNTHETIC, + Modifier.FINAL + }; + return modifiers; + } + + protected Class[] types() { + final Class[] types = { + ParameterNames.class, + int.class + }; + return types; + } + + public String message() { + return message; + } + } + + public Tester makeInner(final String message) { + return new InnerTester(2); + } + + public Tester makeLocal(final String message) { + class LocalTester extends Tester { + public LocalTester(final int localparam) { + super(localparam); + } + + protected String[] names() { + final String[] names = { + "this$1", + "localparam", + "val$message" + }; + return names; + } + + protected int[] modifiers() { + final int[] modifiers = { + Modifier.FINAL | MANDATED, + Modifier.FINAL, + Modifier.FINAL | SYNTHETIC + }; + return modifiers; + } + + protected Class[] types() { + final Class[] types = { + ParameterNames.class, + int.class, + String.class + }; + return types; + } + + public String message() { + return message; + } + } + + return new LocalTester(2); + } + + public Tester makeAnonExtendsLocal(final String message) { + abstract class LocalTester extends Tester { + public LocalTester(final int localparam) { + super(localparam); + } + + protected String[] names() { + final String[] names = { + "this$1", + "localparam", + "val$message" + }; + return names; + } + + protected int[] modifiers() { + final int[] modifiers = { + Modifier.FINAL | MANDATED, + Modifier.FINAL, + Modifier.FINAL | SYNTHETIC + }; + return modifiers; + } + + protected Class[] types() { + final Class[] types = { + ParameterNames.class, + int.class, + String.class + }; + return types; + } + + } + + return new LocalTester(2) { + public String message() { + return message; + } + }; + } + + public Tester makeAnonExtendsInner(final String message) { + return new InnerTester(2) { + protected String[] names() { + final String[] names = { + "this$1", + "innerparam", + "val$message" + }; + return names; + } + + protected int[] modifiers() { + final int[] modifiers = { + Modifier.FINAL | MANDATED, + Modifier.FINAL, + Modifier.FINAL | SYNTHETIC + }; + return modifiers; + } + + protected Class[] types() { + final Class[] types = { + ParameterNames.class, + int.class, + String.class + }; + return types; + } + + public String message() { + return message; + } + }; + } + + public Tester makeAnon(final String message) { + return new Tester(2) { + protected String[] names() { + final String[] names = { + "this$1", + "param", + "val$message" + }; + return names; + } + + protected int[] modifiers() { + final int[] modifiers = { + Modifier.FINAL | MANDATED, + Modifier.FINAL, + Modifier.FINAL | SYNTHETIC + }; + return modifiers; + } + + protected Class[] types() { + final Class[] types = { + ParameterNames.class, + int.class, + String.class + }; + return types; + } + + public String message() { + return message; + } + }; + } + } +}