--- old/src/share/classes/com/sun/tools/javac/comp/Resolve.java 2013-05-15 11:17:11.891642662 -0400 +++ new/src/share/classes/com/sun/tools/javac/comp/Resolve.java 2013-05-15 11:17:11.737641345 -0400 @@ -1784,7 +1784,10 @@ } } - /** Find qualified member type. + + /** + * Find a type declared in a scope (not inherited). Return null + * if none is found. * @param env The current environment. * @param site The original type from where the selection takes * place. @@ -1793,12 +1796,10 @@ * always a superclass or implemented interface of * site's class. */ - Symbol findMemberType(Env env, - Type site, - Name name, - TypeSymbol c) { - Symbol bestSoFar = typeNotFound; - Symbol sym; + Symbol findImmediateMemberType(Env env, + Type site, + Name name, + TypeSymbol c) { Scope.Entry e = c.members().lookup(name); while (e.scope != null) { if (e.sym.kind == TYP) { @@ -1808,6 +1809,24 @@ } e = e.next(); } + return null; + } + + /** Find a member type inherited from a superclass or interface. + * @param env The current environment. + * @param site The original type from where the selection takes + * place. + * @param name The type's name. + * @param c The class to search for the member type. This is + * always a superclass or implemented interface of + * site's class. + */ + Symbol findInheritedMemberType(Env env, + Type site, + Name name, + TypeSymbol c) { + Symbol bestSoFar = typeNotFound; + Symbol sym; Type st = types.supertype(c.type); if (st != null && st.hasTag(CLASS)) { sym = findMemberType(env, site, name, st.tsym); @@ -1826,6 +1845,28 @@ return bestSoFar; } + /** Find qualified member type. + * @param env The current environment. + * @param site The original type from where the selection takes + * place. + * @param name The type's name. + * @param c The class to search for the member type. This is + * always a superclass or implemented interface of + * site's class. + */ + Symbol findMemberType(Env env, + Type site, + Name name, + TypeSymbol c) { + Symbol sym = findImmediateMemberType(env, site, name, c); + + if (sym != null) + return sym; + + return findInheritedMemberType(env, site, name, c); + + } + /** Find a global type in given scope and load corresponding class. * @param env The current environment. * @param scope The scope in which to look for the type. @@ -1853,20 +1894,27 @@ Symbol sym; boolean staticOnly = false; for (Env env1 = env; env1.outer != null; env1 = env1.outer) { - if (isStatic(env1)) staticOnly = true; - for (Scope.Entry e = env1.info.scope.lookup(name); - e.scope != null; - e = e.next()) { - if (e.sym.kind == TYP) { - if (staticOnly && - e.sym.type.hasTag(TYPEVAR) && - e.sym.owner.kind == TYP) return new StaticError(e.sym); - return e.sym; + // First, try the members declared in the class + sym = findImmediateMemberType(env1, env1.enclClass.sym.type, + name, env1.enclClass.sym); + // Then try the type parameters + if (sym == null) { + if (isStatic(env1)) staticOnly = true; + for (Scope.Entry e = env1.info.scope.lookup(name); + e.scope != null; + e = e.next()) { + if (e.sym.kind == TYP) { + if (staticOnly && + e.sym.type.hasTag(TYPEVAR) && + e.sym.owner.kind == TYP) + return new StaticError(e.sym); + return e.sym; + } } + sym = findInheritedMemberType(env1, env1.enclClass.sym.type, + name, env1.enclClass.sym); } - sym = findMemberType(env1, env1.enclClass.sym.type, name, - env1.enclClass.sym); if (staticOnly && sym.kind == TYP && sym.type.hasTag(CLASS) && sym.type.getEnclosingType().hasTag(CLASS) && --- /dev/null 2013-05-13 15:31:22.781774405 -0400 +++ new/test/tools/javac/7118412/ShadowingTest.java 2013-05-15 11:17:12.303646174 -0400 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 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 7118412 + * @summary javac should generate method parameters correctly. + */ +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +public class ShadowingTest { + + enum MethodCall { + INNER("inner"), + TYPEVAR("iterator"), + OUTER("outer"); + + public final String methodcall; + + MethodCall(final String methodcall) { + this.methodcall = methodcall; + } + + public boolean succeeds(final MethodContext ctx, + final InsideDef inside, + final TyVar tyvar) { + switch(this) { + case INNER: switch(ctx) { + case STATIC: switch(inside) { + case INSTANCE: + case STATIC: + return true; + default: return false; + } + case INSTANCE: switch(inside) { + case INSTANCE: + case STATIC: return true; + default: return false; + } + } + case TYPEVAR: switch(ctx) { + case INSTANCE: switch(inside) { + case NONE: switch(tyvar) { + case YES: return true; + default: return false; + } + default: return false; + } + default: return false; + } + case OUTER: switch(inside) { + case NONE: switch(tyvar) { + case NO: return true; + default: return false; + } + default: return false; + } + } + return false; + } + } + + enum MethodContext { + STATIC("static "), + INSTANCE(""); + + public final String methodcontext; + + MethodContext(final String methodcontext) { + this.methodcontext = methodcontext; + } + } + + enum InsideDef { + NONE(""), + STATIC("static class T { public void inner() {} }\n"), + INSTANCE("class T { public void inner() {} }\n"); + + public final String instancedef; + + InsideDef(final String instancedef) { + this.instancedef = instancedef; + } + } + + enum TyVar { + NO(""), + YES(""); + + public final String tyvar; + + TyVar(final String tyvar) { + this.tyvar = tyvar; + } + } + + static final File classesdir = new File("7118412"); + + private int errors = 0; + + public static void main(String... args) throws Exception { + new ShadowingTest().run(); + } + + int dirnum = 0; + + private void doTest(final TyVar tyvar, final InsideDef insidedef, + final MethodContext ctx, final MethodCall call) + throws IOException { + final String content = "import java.util.Collection;\n" + + "class Test" + tyvar.tyvar + " {\n" + + " " + insidedef.instancedef + + " " + ctx.methodcontext + "void test(T t) { t." + + call.methodcall + "(); }\n" + + "}\n" + + "class T { void outer() {} }\n"; + final File dir = new File(classesdir, "" + dirnum); + final File Test_java = writeFile(dir, "Test.java", content); + dirnum++; + if(call.succeeds(ctx, insidedef, tyvar)) { + if(!assert_compile_succeed(Test_java)) + System.err.println("Failed file:\n" + content); + } + else { + if(!assert_compile_fail(Test_java)) + System.err.println("Failed file:\n" + content); + } + } + + void run() throws Exception { + classesdir.mkdir(); + for(TyVar tyvar : TyVar.values()) + for(InsideDef insidedef : InsideDef.values()) + for(MethodContext ctx : MethodContext.values()) + for(MethodCall methodcall : MethodCall.values()) + doTest(tyvar, insidedef, ctx, methodcall); + if (errors != 0) + throw new Exception("ShadowingTest test failed with " + + errors + " errors."); + } + + boolean assert_compile_fail(final File file) { + final String filename = file.getPath(); + final String[] args = { filename }; + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + final int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + if (rc == 0) { + System.err.println("Compilation of " + file.getName() + + " didn't fail as expected."); + errors++; + return false; + } else return true; + } + + boolean assert_compile_succeed(final File file) { + final String filename = file.getPath(); + final String[] args = { filename }; + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + final int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + if (rc != 0) { + System.err.println("Compilation of " + file.getName() + + " didn't succeed as expected. Output:"); + System.err.println(sw.toString()); + errors++; + return false; + } else return true; + } + + File writeFile(final File dir, + final String path, + final String body) throws IOException { + final File f = new File(dir, path); + f.getParentFile().mkdirs(); + final FileWriter out = new FileWriter(f); + out.write(body); + out.close(); + return f; + } +}