6996914: Diamond inference: problem when accessing protected constructor
authormcimadamore
Wed, 10 Nov 2010 12:37:25 +0000
changeset 7208 5db8147393ec
parent 7207 e68a36c83fd2
child 7209 889e80aa1d2e
6996914: Diamond inference: problem when accessing protected constructor Summary: special resolution scheme for diamond inference needs to open up protected constructors in anon inner class creation Reviewed-by: jjg
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/test/tools/javac/generics/diamond/6996914/T6996914a.java
langtools/test/tools/javac/generics/diamond/6996914/T6996914b.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Nov 09 17:49:24 2010 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Nov 10 12:37:25 2010 +0000
@@ -1552,7 +1552,7 @@
         // Attribute clazz expression and store
         // symbol + type back into the attributed tree.
         Type clazztype = attribType(clazz, env);
-        Pair<Scope,Scope> mapping = getSyntheticScopeMapping(clazztype);
+        Pair<Scope,Scope> mapping = getSyntheticScopeMapping(clazztype, cdef != null);
         if (!TreeInfo.isDiamond(tree)) {
             clazztype = chk.checkClassType(
                 tree.clazz.pos(), clazztype, true);
@@ -1849,7 +1849,7 @@
      *  inference. The inferred return type of the synthetic constructor IS
      *  the inferred type for the diamond operator.
      */
-    private Pair<Scope, Scope> getSyntheticScopeMapping(Type ctype) {
+    private Pair<Scope, Scope> getSyntheticScopeMapping(Type ctype, boolean overrideProtectedAccess) {
         if (ctype.tag != CLASS) {
             return erroneousMapping;
         }
@@ -1860,6 +1860,12 @@
                 e.scope != null;
                 e = e.next()) {
             MethodSymbol newConstr = (MethodSymbol) e.sym.clone(ctype.tsym);
+            if (overrideProtectedAccess && (newConstr.flags() & PROTECTED) != 0) {
+                //make protected constructor public (this is required for
+                //anonymous inner class creation expressions using diamond)
+                newConstr.flags_field |= PUBLIC;
+                newConstr.flags_field &= ~PROTECTED;
+            }
             newConstr.name = names.init;
             List<Type> oldTypeargs = List.nil();
             if (newConstr.type.tag == FORALL) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/diamond/6996914/T6996914a.java	Wed Nov 10 12:37:25 2010 +0000
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2010, 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 6996914
+ * @summary  Diamond inference: problem when accessing protected constructor
+ * @run main T6996914a
+ */
+
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public class T6996914a {
+
+    enum PackageKind {
+        DEFAULT("", ""),
+        A("package a;", "import a.*;");
+
+        String pkgDecl;
+        String importDecl;
+
+        PackageKind(String pkgDecl, String importDecl) {
+            this.pkgDecl = pkgDecl;
+            this.importDecl = importDecl;
+        }
+    }
+
+    enum DiamondKind {
+        STANDARD("new Foo<>();"),
+        ANON("new Foo<>() {};");
+
+        String expr;
+
+        DiamondKind(String expr) {
+            this.expr = expr;
+        }
+    }
+
+    enum ConstructorKind {
+        PACKAGE(""),
+        PROTECTED("protected"),
+        PRIVATE("private"),
+        PUBLIC("public");
+
+        String mod;
+
+        ConstructorKind(String mod) {
+            this.mod = mod;
+        }
+    }
+
+    static class FooClass extends SimpleJavaFileObject {
+
+        final static String sourceStub =
+                        "#P\n" +
+                        "public class Foo<X> {\n" +
+                        "  #M Foo() {}\n" +
+                        "}\n";
+
+        String source;
+
+        public FooClass(PackageKind pk, ConstructorKind ck) {
+            super(URI.create("myfo:/" + (pk != PackageKind.DEFAULT ? "a/Foo.java" : "Foo.java")),
+                    JavaFileObject.Kind.SOURCE);
+            source = sourceStub.replace("#P", pk.pkgDecl).replace("#M", ck.mod);
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+
+    static class ClientClass extends SimpleJavaFileObject {
+
+        final static String sourceStub =
+                        "#I\n" +
+                        "class Test {\n" +
+                        "  Foo<String> fs = #D\n" +
+                        "}\n";
+
+        String source;
+
+        public ClientClass(PackageKind pk, DiamondKind dk) {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            source = sourceStub.replace("#I", pk.importDecl).replace("#D", dk.expr);
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+
+    public static void main(String... args) throws Exception {
+        for (PackageKind pk : PackageKind.values()) {
+            for (ConstructorKind ck : ConstructorKind.values()) {
+                for (DiamondKind dk : DiamondKind.values()) {
+                    compileAndCheck(pk, ck, dk);
+                }
+            }
+        }
+    }
+
+    static void compileAndCheck(PackageKind pk, ConstructorKind ck, DiamondKind dk) throws Exception {
+        FooClass foo = new FooClass(pk, ck);
+        ClientClass client = new ClientClass(pk, dk);
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        ErrorListener el = new ErrorListener();
+        JavacTask ct = (JavacTask)tool.getTask(null, null, el,
+                null, null, Arrays.asList(foo, client));
+        ct.analyze();
+        if (el.errors > 0 == check(pk, ck, dk)) {
+            String msg = el.errors > 0 ?
+                "Error compiling files" :
+                "No error when compiling files";
+            throw new AssertionError(msg + ": \n" + foo.source + "\n" + client.source);
+        }
+    }
+
+    static boolean check(PackageKind pk, ConstructorKind ck, DiamondKind dk) {
+        switch (pk) {
+            case A: return ck == ConstructorKind.PUBLIC ||
+                    (ck  == ConstructorKind.PROTECTED && dk == DiamondKind.ANON);
+            case DEFAULT: return ck != ConstructorKind.PRIVATE;
+            default: throw new AssertionError("Unknown package kind");
+        }
+    }
+
+    /**
+     * DiagnosticListener to count any errors that occur
+     */
+    private static class ErrorListener implements DiagnosticListener<JavaFileObject> {
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            switch (diagnostic.getKind()) {
+                case ERROR:
+                    errors++;
+            }
+        }
+        int errors;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/generics/diamond/6996914/T6996914b.java	Wed Nov 10 12:37:25 2010 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2010, 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 6996914
+ * @summary  Diamond inference: problem when accessing protected constructor
+ * @compile T6996914b.java
+ */
+
+class Super<X,Y> {
+    private Super(Integer i, Y y, X x) {}
+    public Super(Number n, X x, Y y) {}
+}
+
+class Test {
+    Super<String,Integer> ssi1 = new Super<>(1, "", 2);
+    Super<String,Integer> ssi2 = new Super<>(1, "", 2) {};
+}