# HG changeset patch # User mfang # Date 1434042678 25200 # Node ID 54a0b6cae9c5ffbc34e3826a66958c92dcd6bc7f # Parent d4051d4f5daf2a780e7c9c62e515f896d6720206# Parent 380f6c17ea01934ad4caaca5df53917f75f1b772 Merge diff -r d4051d4f5daf -r 54a0b6cae9c5 src/share/classes/com/sun/tools/javac/code/Scope.java --- a/src/share/classes/com/sun/tools/javac/code/Scope.java Wed Jun 10 14:22:04 2015 -0700 +++ b/src/share/classes/com/sun/tools/javac/code/Scope.java Thu Jun 11 10:11:18 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -241,12 +241,16 @@ listeners = listeners.prepend(sl); } - /** Remove symbol from this scope. Used when an inner class - * attribute tells us that the class isn't a package member. + /** Remove symbol from this scope. */ - public void remove(Symbol sym) { + public void remove(final Symbol sym) { Assert.check(shared == 0); - Entry e = lookup(sym.name); + Entry e = lookup(sym.name, new Filter() { + @Override + public boolean accepts(Symbol candidate) { + return candidate == sym; + } + }); if (e.scope == null) return; // remove e from table and shadowed list; diff -r d4051d4f5daf -r 54a0b6cae9c5 src/share/classes/com/sun/tools/javac/code/Types.java --- a/src/share/classes/com/sun/tools/javac/code/Types.java Wed Jun 10 14:22:04 2015 -0700 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Thu Jun 11 10:11:18 2015 -0700 @@ -2694,74 +2694,98 @@ // // - class MembersClosureCache extends SimpleVisitor { - - private WeakHashMap _map = - new WeakHashMap(); - - class Entry { - final boolean skipInterfaces; - final CompoundScope compoundScope; - - public Entry(boolean skipInterfaces, CompoundScope compoundScope) { - this.skipInterfaces = skipInterfaces; - this.compoundScope = compoundScope; + class MembersClosureCache extends SimpleVisitor { + + private Map _map = new HashMap<>(); + + Set seenTypes = new HashSet<>(); + + class MembersScope extends CompoundScope { + + CompoundScope scope; + + public MembersScope(CompoundScope scope) { + super(scope.owner); + this.scope = scope; } - boolean matches(boolean skipInterfaces) { - return this.skipInterfaces == skipInterfaces; + Filter combine(final Filter sf) { + return new Filter() { + @Override + public boolean accepts(Symbol s) { + return !s.owner.isInterface() && (sf == null || sf.accepts(s)); + } + }; + } + + @Override + public Iterable getElements(Filter sf) { + return scope.getElements(combine(sf)); + } + + @Override + public Iterable getElementsByName(Name name, Filter sf) { + return scope.getElementsByName(name, combine(sf)); + } + + @Override + public int getMark() { + return scope.getMark(); } } - List seenTypes = List.nil(); + CompoundScope nilScope; /** members closure visitor methods **/ - public CompoundScope visitType(Type t, Boolean skipInterface) { - return null; + public CompoundScope visitType(Type t, Void _unused) { + if (nilScope == null) { + nilScope = new CompoundScope(syms.noSymbol); + } + return nilScope; } @Override - public CompoundScope visitClassType(ClassType t, Boolean skipInterface) { - if (seenTypes.contains(t.tsym)) { + public CompoundScope visitClassType(ClassType t, Void _unused) { + if (!seenTypes.add(t.tsym)) { //this is possible when an interface is implemented in multiple - //superclasses, or when a classs hierarchy is circular - in such + //superclasses, or when a class hierarchy is circular - in such //cases we don't need to recurse (empty scope is returned) return new CompoundScope(t.tsym); } try { - seenTypes = seenTypes.prepend(t.tsym); + seenTypes.add(t.tsym); ClassSymbol csym = (ClassSymbol)t.tsym; - Entry e = _map.get(csym); - if (e == null || !e.matches(skipInterface)) { - CompoundScope membersClosure = new CompoundScope(csym); - if (!skipInterface) { - for (Type i : interfaces(t)) { - membersClosure.addSubScope(visit(i, skipInterface)); - } + CompoundScope membersClosure = _map.get(csym); + if (membersClosure == null) { + membersClosure = new CompoundScope(csym); + for (Type i : interfaces(t)) { + membersClosure.addSubScope(visit(i, null)); } - membersClosure.addSubScope(visit(supertype(t), skipInterface)); + membersClosure.addSubScope(visit(supertype(t), null)); membersClosure.addSubScope(csym.members()); - e = new Entry(skipInterface, membersClosure); - _map.put(csym, e); + _map.put(csym, membersClosure); } - return e.compoundScope; + return membersClosure; } finally { - seenTypes = seenTypes.tail; + seenTypes.remove(t.tsym); } } @Override - public CompoundScope visitTypeVar(TypeVar t, Boolean skipInterface) { - return visit(t.getUpperBound(), skipInterface); + public CompoundScope visitTypeVar(TypeVar t, Void _unused) { + return visit(t.getUpperBound(), null); } } private MembersClosureCache membersCache = new MembersClosureCache(); public CompoundScope membersClosure(Type site, boolean skipInterface) { - return membersCache.visit(site, skipInterface); + CompoundScope cs = membersCache.visit(site, null); + if (cs == null) + Assert.error("type " + site); + return skipInterface ? membersCache.new MembersScope(cs) : cs; } // diff -r d4051d4f5daf -r 54a0b6cae9c5 src/share/classes/com/sun/tools/javac/comp/Attr.java --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jun 10 14:22:04 2015 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Thu Jun 11 10:11:18 2015 -0700 @@ -825,9 +825,18 @@ } public void visitClassDef(JCClassDecl tree) { - // Local classes have not been entered yet, so we need to do it now: - if ((env.info.scope.owner.kind & (VAR | MTH)) != 0) + // Local and anonymous classes have not been entered yet, so we need to + // do it now. + if ((env.info.scope.owner.kind & (VAR | MTH)) != 0) { enter.classEnter(tree, env); + } else { + // If this class declaration is part of a class level annotation, + // as in @MyAnno(new Object() {}) class MyClass {}, enter it in + // order to simplify later steps and allow for sensible error + // messages. + if (env.tree.hasTag(NEWCLASS) && TreeInfo.isInAnnotation(env, tree)) + enter.classEnter(tree, env); + } ClassSymbol c = tree.sym; if (c == null) { diff -r d4051d4f5daf -r 54a0b6cae9c5 src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java --- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Wed Jun 10 14:22:04 2015 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Jun 11 10:11:18 2015 -0700 @@ -1256,6 +1256,9 @@ return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType); case APPLY: return true; + case NEWCLASS: + JCNewClass nc = (JCNewClass) rec; + return nc.encl == null && nc.def == null && !TreeInfo.isDiamond(nc); default: return false; } @@ -1310,17 +1313,24 @@ Type site; if (rec != null) { - if (rec.hasTag(APPLY)) { - Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec); - if (recSym == null) - return null; - Symbol resolvedReturnType = - analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer); - if (resolvedReturnType == null) - return null; - site = resolvedReturnType.type; - } else { - site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type; + switch (rec.getTag()) { + case APPLY: + Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec); + if (recSym == null) + return null; + Symbol resolvedReturnType = + analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer); + if (resolvedReturnType == null) + return null; + site = resolvedReturnType.type; + break; + case NEWCLASS: + JCNewClass nc = (JCNewClass) rec; + site = attribSpeculative(nc.clazz, env, attr.unknownTypeExprInfo).type; + break; + default: + site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type; + break; } } else { site = env.enclClass.sym.type; diff -r d4051d4f5daf -r 54a0b6cae9c5 src/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Jun 10 14:22:04 2015 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Thu Jun 11 10:11:18 2015 -0700 @@ -271,7 +271,7 @@ * the one of its outer environment */ protected static boolean isStatic(Env env) { - return env.info.staticLevel > env.outer.info.staticLevel; + return env.outer != null && env.info.staticLevel > env.outer.info.staticLevel; } /** An environment is an "initializer" if it is a constructor or diff -r d4051d4f5daf -r 54a0b6cae9c5 src/share/classes/com/sun/tools/javac/tree/TreeInfo.java --- a/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Wed Jun 10 14:22:04 2015 -0700 +++ b/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java Thu Jun 11 10:11:18 2015 -0700 @@ -28,6 +28,7 @@ import com.sun.source.tree.Tree; +import com.sun.source.util.TreePath; import com.sun.tools.javac.code.*; import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; @@ -351,6 +352,18 @@ return (lit.typetag == BOT); } + /** Return true iff this tree is a child of some annotation. */ + public static boolean isInAnnotation(Env env, JCTree tree) { + TreePath tp = TreePath.getPath(env.toplevel, tree); + if (tp != null) { + for (Tree t : tp) { + if (t.getKind() == Tree.Kind.ANNOTATION) + return true; + } + } + return false; + } + public static String getCommentText(Env env, JCTree tree) { DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL)) ? ((JCCompilationUnit) tree).docComments diff -r d4051d4f5daf -r 54a0b6cae9c5 test/tools/javac/annotations/neg/AnonSubclass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/annotations/neg/AnonSubclass.java Thu Jun 11 10:11:18 2015 -0700 @@ -0,0 +1,13 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8028389 + * @summary javac should output a proper error message when given something + * like new Object(){} as annotation argument. + * + * @compile/fail/ref=AnonSubclass.out -XDrawDiagnostics AnonSubclass.java + */ + +@AnonSubclass(new Object(){}) +@interface AnonSubclass { + String value(); +} diff -r d4051d4f5daf -r 54a0b6cae9c5 test/tools/javac/annotations/neg/AnonSubclass.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/annotations/neg/AnonSubclass.out Thu Jun 11 10:11:18 2015 -0700 @@ -0,0 +1,2 @@ +AnonSubclass.java:10:15: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.anonymous.class: java.lang.Object, java.lang.String) +1 error diff -r d4051d4f5daf -r 54a0b6cae9c5 test/tools/javac/annotations/neg/pkg/AnonSubclassOnPkg.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/annotations/neg/pkg/AnonSubclassOnPkg.java Thu Jun 11 10:11:18 2015 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014, 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. + */ + +package pkg; + +@interface AnonSubclassOnPkg { + String value(); +} diff -r d4051d4f5daf -r 54a0b6cae9c5 test/tools/javac/annotations/neg/pkg/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/annotations/neg/pkg/package-info.java Thu Jun 11 10:11:18 2015 -0700 @@ -0,0 +1,12 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8028389 + * @summary javac should output a proper error message when given something + * like new Object(){} as annotation argument. + * + * @compile AnonSubclassOnPkg.java + * @compile/fail/ref=package-info.out -XDrawDiagnostics package-info.java + */ + +@AnonSubclassOnPkg(new Object(){}) +package pkg; diff -r d4051d4f5daf -r 54a0b6cae9c5 test/tools/javac/annotations/neg/pkg/package-info.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/annotations/neg/pkg/package-info.out Thu Jun 11 10:11:18 2015 -0700 @@ -0,0 +1,2 @@ +package-info.java:11:20: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.anonymous.class: java.lang.Object, java.lang.String) +1 error diff -r d4051d4f5daf -r 54a0b6cae9c5 test/tools/javac/expression/DeeplyChainedNonPolyExpressionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/expression/DeeplyChainedNonPolyExpressionTest.java Thu Jun 11 10:11:18 2015 -0700 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2015, 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 8079613 + * @summary Ensure that compiler ascertains a class of patently non-poly expressions as such + * @run main/timeout=10 DeeplyChainedNonPolyExpressionTest + */ + +public class DeeplyChainedNonPolyExpressionTest { + static class JSO { + + JSO put(String s, Object y) { + return null; + } + + JSO put(java.lang.String x, java.util.Collection y) { + return null; + } + + JSO put(java.lang.String x, int y) { + return null; + } + + JSO put(java.lang.String x, long y) { + return null; + } + + JSO put(java.lang.String x, double y) { + return null; + } + + JSO put(java.lang.String x, java.util.Map y) { + return null; + } + + JSO put(java.lang.String x, boolean y) { + return null; + } + } + + static class JSA { + + JSA put(Object o) { + return null; + } + + JSA put(int i, Object x) { + return null; + } + + JSA put(boolean x) { + return null; + } + + JSA put(int x) { + return null; + } + + JSA put(int i, int x) { + return null; + } + + JSA put(int x, boolean y) { + return null; + } + + JSA put(int i, long x) { + return null; + } + + JSA put(long x) { + return null; + } + + JSA put(java.util.Collection x) { + return null; + } + + JSA put(int i, java.util.Collection x) { + return null; + } + + JSA put(int i, java.util.Map x) { + return null; + } + + JSA put(java.util.Map x) { + return null; + } + + JSA put(int i, double x) { + return null; + } + + JSA put(double x) { + return null; + } + } + + public static void main(String [] args) { + } + public static void foo() { + new JSO() + .put("s", new JSA()) + .put("s", new JSA()) + .put("s", new JSO() + .put("s", new JSO() + .put("s", new JSA().put("s")) + .put("s", new JSA()) + .put("s", new JSO() + .put("s", new JSO() + .put("s", new JSA().put("s").put("s")) + .put("s", new JSA()) + .put("s", new JSO() + .put("s", new JSO() + .put("s", new JSA().put("s").put("s").put("s") + .put("s").put("s").put("s") + .put("s").put("s")) + .put("s", new JSA()) + .put("s", new JSO() + .put("s", new JSO() + .put("s", new JSA().put("s")) + .put("s", new JSA()) + ) + ) + ) + ) + ) + .put("s", new JSO() + .put("s", new JSA().put("s")) + .put("s", new JSA()) + .put("s", new JSO() + .put("s", new JSO() + .put("s", new JSA().put("s").put("s")) + .put("s", new JSA()) + .put("s", new JSO() + .put("s", new JSO() + .put("s", new JSA().put("s").put("s").put("s") + .put("s").put("s").put("s") + .put("s").put("s")) + .put("s", new JSA()) + .put("s", new JSO() + .put("s", new JSO() + .put("s", new JSA().put("s")) + .put("s", new JSA())) + ) + ) + ) + ) + ) + ) + ) + ) + ); + } +} diff -r d4051d4f5daf -r 54a0b6cae9c5 test/tools/javac/scope/RemoveSymbolTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/scope/RemoveSymbolTest.java Thu Jun 11 10:11:18 2015 -0700 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, 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 8080842 + * @summary Ensure Scope impl can cope with remove() when a field and method share the name. + * @run main RemoveSymbolTest + */ + +import java.util.Iterator; +import java.util.LinkedList; + +public class RemoveSymbolTest implements Iterable { + static class Widget { + private String name; + Widget(String s) { name = s; } + @Override public String toString() { return name; } + } + + private LinkedList data; + // Instantiate an Iterable instance using a Lambda expression. + // Causes ClassFormatError if a local variable of type Widget is named after one of the methods. + private final Iterable myIterator1 = () -> new Iterator() { + private W hasNext = null; + private int index = 0; + @Override public boolean hasNext() { return index < data.size(); } + @Override public W next() { return data.get(index++); } + }; + + // Instantiate an Iterable instance using an anonymous class. + // Always works fine regardless of the name of the local variable. + private final Iterable myIterator2 = + new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + private W hasNext = null; + private int index = 0; + @Override public boolean hasNext() { return index < data.size(); } + @Override public W next() { return data.get(index++); } + }; + } + }; + public RemoveSymbolTest() { data = new LinkedList<>(); } + public void add(W e) { data.add(e); } + @Override public String toString() { return data.toString(); } + @Override public Iterator iterator() { return myIterator1.iterator(); } + public static void main(String[] args) { + RemoveSymbolTest widgets = new RemoveSymbolTest<>(); + widgets.add(new Widget("W1")); + widgets.add(new Widget("W2")); + widgets.add(new Widget("W3")); + System.out.println(".foreach() call: "); + widgets.forEach(w -> System.out.println(w + " ")); + } +} diff -r d4051d4f5daf -r 54a0b6cae9c5 test/tools/javac/scope/RemoveSymbolUnitTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/scope/RemoveSymbolUnitTest.java Thu Jun 11 10:11:18 2015 -0700 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015 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 8080842 + * @summary Ensure Scope impl can cope with remove() when a field and method share the name. + */ + +import com.sun.tools.javac.util.*; +import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Scope.*; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.file.JavacFileManager; + +public class RemoveSymbolUnitTest { + + Context context; + Names names; + Symtab symtab; + + public static void main(String... args) throws Exception { + new RemoveSymbolUnitTest().run(); + } + + public void run() { + context = new Context(); + JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab + names = Names.instance(context); + symtab = Symtab.instance(context); + + Name hasNext = names.fromString("hasNext"); + ClassSymbol clazz = new ClassSymbol(0, + names.fromString("X"), + Type.noType, + symtab.unnamedPackage); + + VarSymbol v = new VarSymbol(0, hasNext, Type.noType, clazz); + MethodSymbol m = new MethodSymbol(0, hasNext, Type.noType, clazz); + + // Try enter and remove in different shuffled combinations. + // working with fresh scope each time. + Scope cs = new Scope(clazz); + cs.enter(v); + cs.enter(m); + cs.remove(v); + Symbol s = cs.lookup(hasNext).sym; + if (s != m) + throw new AssertionError("Wrong symbol"); + + cs = new Scope(clazz); + cs.enter(m); + cs.enter(v); + cs.remove(v); + s = cs.lookup(hasNext).sym; + if (s != m) + throw new AssertionError("Wrong symbol"); + + cs = new Scope(clazz); + cs.enter(v); + cs.enter(m); + cs.remove(m); + s = cs.lookup(hasNext).sym; + if (s != v) + throw new AssertionError("Wrong symbol"); + + cs = new Scope(clazz); + cs.enter(m); + cs.enter(v); + cs.remove(m); + s = cs.lookup(hasNext).sym; + if (s != v) + throw new AssertionError("Wrong symbol"); + } +} diff -r d4051d4f5daf -r 54a0b6cae9c5 test/tools/javac/types/ScopeListenerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/types/ScopeListenerTest.java Thu Jun 11 10:11:18 2015 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, 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 8039262 + * @summary Ensure that using Types.membersClosure does not increase the number of listeners on the + * class's members Scope. + */ + +import com.sun.tools.javac.code.Scope; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Names; +import java.lang.reflect.Field; +import java.util.Collection; + +public class ScopeListenerTest { + + public static void main(String[] args) throws Exception { + new ScopeListenerTest().run(); + } + + void run() throws Exception { + Context context = new Context(); + JavacFileManager.preRegister(context); + Types types = Types.instance(context); + Symtab syms = Symtab.instance(context); + Names names = Names.instance(context); + types.membersClosure(syms.stringType, true); + types.membersClosure(syms.stringType, false); + + Field listenersField = Scope.class.getDeclaredField("listeners"); + + listenersField.setAccessible(true); + + int listenerCount = + ((Collection) listenersField.get(syms.stringType.tsym.members())).size(); + + for (int i = 0; i < 100; i++) { + types.membersClosure(syms.stringType, true); + types.membersClosure(syms.stringType, false); + } + + int newListenerCount + = ((Collection) listenersField.get(syms.stringType.tsym.members())).size(); + + if (listenerCount != newListenerCount) { + throw new AssertionError("Orig listener count: " + listenerCount + + "; new listener count: " + newListenerCount); + } + + for (Symbol s : types.membersClosure(syms.stringType, true).getElements()) + ; + for (Symbol s : types.membersClosure(syms.stringType, false).getElementsByName(names.fromString("substring"))) + ; + } + +}