changeset 1709:d78663601eb9

Enhancement: add support for 'package' as access modifier Example: class Test { package void test() { ... } }
author mcimadamore
date Mon, 07 Jan 2013 18:45:59 +0100
parents 767ba50fb4b2
children 2e8ccb7ba243
files src/share/classes/com/sun/tools/javac/code/Flags.java src/share/classes/com/sun/tools/javac/code/Source.java src/share/classes/com/sun/tools/javac/comp/Check.java src/share/classes/com/sun/tools/javac/parser/JavacParser.java src/share/classes/com/sun/tools/javac/resources/compiler.properties test/tools/javac/defaultMethods/package/TestPackageAsModifier.java test/tools/javac/diags/examples.not-yet.txt
diffstat 7 files changed, 286 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Flags.java	Mon Jan 07 14:12:17 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Flags.java	Mon Jan 07 18:45:59 2013 +0100
@@ -68,6 +68,7 @@
         if ((mask&INTERFACE) != 0) flags.add(Flag.INTERFACE);
         if ((mask&ABSTRACT) != 0) flags.add(Flag.ABSTRACT);
         if ((mask&DEFAULT) != 0) flags.add(Flag.DEFAULT);
+        if ((mask&PACKAGE_PRIVATE) != 0) flags.add(Flag.PACKAGE);
         if ((mask&STRICTFP) != 0) flags.add(Flag.STRICTFP);
         if ((mask&BRIDGE) != 0) flags.add(Flag.BRIDGE);
         if ((mask&SYNTHETIC) != 0) flags.add(Flag.SYNTHETIC);
@@ -264,23 +265,31 @@
      * the public class in a source file, that could block implicit compilation.
      */
     public static final long AUXILIARY = 1L<<44;
+    
+    /**
+     * Shadow flag for package access.
+     */
+    public static final long PACKAGE_PRIVATE = 1L<<45;
 
     /** Modifier masks.
      */
     public static final int
         AccessFlags           = PUBLIC | PROTECTED | PRIVATE,
-        LocalClassFlags       = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
-        MemberClassFlags      = LocalClassFlags | INTERFACE | AccessFlags,
+        LocalClassFlags       = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,        
         ClassFlags            = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
         InterfaceVarFlags     = FINAL | STATIC | PUBLIC,
-        VarFlags              = AccessFlags | FINAL | STATIC |
-                                VOLATILE | TRANSIENT | ENUM,
-        ConstructorFlags      = AccessFlags,
-        InterfaceMethodFlags  = ABSTRACT | PUBLIC,
-        MethodFlags           = AccessFlags | ABSTRACT | STATIC | NATIVE |
-                                SYNCHRONIZED | FINAL | STRICTFP;
+        InterfaceMethodFlags  = ABSTRACT | PUBLIC;
+        
     public static final long
-        ExtendedStandardFlags       = (long)StandardFlags | DEFAULT,
+        ExtendedAccessFlags         = AccessFlags | PACKAGE_PRIVATE,
+        VarFlags                    = ExtendedAccessFlags | FINAL | STATIC |
+                                           VOLATILE | TRANSIENT | ENUM,
+        ConstructorFlags            = ExtendedAccessFlags,
+        MethodFlags                 = ExtendedAccessFlags | ABSTRACT | STATIC | NATIVE |
+                                      SYNCHRONIZED | FINAL | STRICTFP,
+        ExtendedClassFlags          = ClassFlags | PACKAGE_PRIVATE,
+        MemberClassFlags            = LocalClassFlags | INTERFACE | ExtendedAccessFlags,        
+        ExtendedStandardFlags       = (long)StandardFlags | DEFAULT | PACKAGE_PRIVATE,
         InterfaceMethodMask         = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | SYNCHRONIZED | DEFAULT,
         LocalVarFlags               = FINAL | PARAMETER;
 
--- a/src/share/classes/com/sun/tools/javac/code/Source.java	Mon Jan 07 14:12:17 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Source.java	Mon Jan 07 18:45:59 2013 +0100
@@ -206,6 +206,9 @@
     public boolean allowDefaultMethods() {
         return compareTo(JDK1_8) >= 0;
     }
+    public boolean allowPackageModifier() {
+        return compareTo(JDK1_8) >= 0;
+    }
     public boolean allowStaticInterfaceMethods() {
         return compareTo(JDK1_8) >= 0;
     }
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Mon Jan 07 14:12:17 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Mon Jan 07 18:45:59 2013 +0100
@@ -1097,7 +1097,7 @@
                 // Nested interfaces and enums are always STATIC (Spec ???)
                 if ((flags & (INTERFACE | ENUM)) != 0 ) implicit = STATIC;
             } else {
-                mask = ClassFlags;
+                mask = ExtendedClassFlags;
             }
             // Interfaces are always ABSTRACT
             if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
@@ -1156,6 +1156,10 @@
                                PUBLIC | PROTECTED)
                  &&
                  checkDisjoint(pos, flags,
+                               PACKAGE_PRIVATE,
+                               PUBLIC | PROTECTED | PRIVATE)
+                 &&
+                 checkDisjoint(pos, flags,
                                FINAL,
                                VOLATILE)
                  &&
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Jan 07 14:12:17 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Jan 07 18:45:59 2013 +0100
@@ -126,6 +126,7 @@
         this.allowLambda = source.allowLambda();
         this.allowMethodReferences = source.allowMethodReferences();
         this.allowDefaultMethods = source.allowDefaultMethods();
+        this.allowPackageModifier = source.allowPackageModifier();
         this.allowStaticInterfaceMethods = source.allowStaticInterfaceMethods();
         this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
         this.allowIntersectionTypesInCast =
@@ -203,6 +204,10 @@
      */
     boolean allowDefaultMethods;
     
+    /** Switch: should we allow 'package' as a modifier?
+     */
+    boolean allowPackageModifier;
+    
     /** Switch: should we allow static methods in interfaces?
      */
     boolean allowStaticInterfaceMethods;
@@ -2408,9 +2413,12 @@
      *           | "@" Annotation
      */
     JCModifiers modifiersOpt() {
-        return modifiersOpt(null);
+        return modifiersOpt(null, false);
     }
-    protected JCModifiers modifiersOpt(JCModifiers partial) {
+    JCModifiers modifiersOpt(boolean skipPackage) {
+        return modifiersOpt(null, skipPackage);
+    }
+    protected JCModifiers modifiersOpt(JCModifiers partial, boolean skipPackage) {
         long flags;
         ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>();
         int pos;
@@ -2443,6 +2451,7 @@
             case STRICTFP    : flag = Flags.STRICTFP; break;
             case MONKEYS_AT  : flag = Flags.ANNOTATION; break;
             case DEFAULT     : checkDefaultMethods(); flag = Flags.DEFAULT; break;
+            case PACKAGE     : if (skipPackage) break loop; checkPackageModifier(); flag = Flags.PACKAGE_PRIVATE; break;
             case ERROR       : flag = 0; nextToken(); break;
             default: break loop;
             }
@@ -2676,18 +2685,22 @@
         boolean seenPackage = false;
         List<JCAnnotation> packageAnnotations = List.nil();
         if (token.kind == MONKEYS_AT)
-            mods = modifiersOpt();
+            mods = modifiersOpt(true);
 
         if (token.kind == PACKAGE) {
-            seenPackage = true;
-            if (mods != null) {
-                checkNoMods(mods.flags);
-                packageAnnotations = mods.annotations;
-                mods = null;
+            if (peekToken(IDENTIFIER)) {
+                seenPackage = true;
+                if (mods != null) {
+                    checkNoMods(mods.flags);
+                    packageAnnotations = mods.annotations;
+                    mods = null;
+                }
+                nextToken();
+                pid = qualident();
+                accept(SEMI);
+            } else {
+                mods = modifiersOpt(mods, false);
             }
-            nextToken();
-            pid = qualident();
-            accept(SEMI);
         }
         ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
         boolean checkForImports = true;
@@ -2767,7 +2780,7 @@
             nextToken();
             return toP(F.at(pos).Skip());
         } else {
-            return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
+            return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods, false), docComment);
         }
     }
 
@@ -3496,6 +3509,12 @@
             allowDefaultMethods = true;
         }
     }
+    void checkPackageModifier() {
+        if (!allowPackageModifier) {
+            log.error(token.pos, "pckge.mod.not.supported.in.source", source.name);
+            allowPackageModifier = true;
+        }
+    }
     void checkStaticInterfaceMethods() {
         if (!allowStaticInterfaceMethods) {
             log.error(token.pos, "static.intf.methods.not.supported.in.source", source.name);
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Jan 07 14:12:17 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Jan 07 18:45:59 2013 +0100
@@ -2203,6 +2203,11 @@
     (use -source 8 or higher to enable method references)
 
 # 0: string
+compiler.err.pckge.mod.not.supported.in.source=\
+    ''package'' as a modifier is not supported in -source {0}\n\
+    (use -source 8 or higher to enable ''package'' as a modifier)
+
+# 0: string
 compiler.err.default.methods.not.supported.in.source=\
     default methods are not supported in -source {0}\n\
     (use -source 8 or higher to enable default methods)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defaultMethods/package/TestPackageAsModifier.java	Mon Jan 07 18:45:59 2013 +0100
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2012, 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
+ * @summary Automatic test for checking support for 'package' as modifier
+ */
+
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+
+public class TestPackageAsModifier {
+
+    static int checkCount = 0;
+
+    enum VersionKind {
+        PRE_LAMBDA("7"),
+        LAMBDA("8");
+
+        String versionString;
+
+        VersionKind(String versionString) {
+            this.versionString = versionString;
+        }
+
+        List<String> getOptions() {
+            return Arrays.asList("-source", versionString);
+        }
+    }
+
+    enum ModifierKind {
+        NONE(""),
+        PUBLIC("public"),
+        PROTECTED("protected"),
+        PRIVATE("private"),
+        PACKAGE("package");
+
+        String modStr;
+
+        private ModifierKind(String modStr) {
+            this.modStr = modStr;
+        }
+        
+        static boolean intersect(ModifierKind mk, ModifierKind... mks) {
+            for (ModifierKind mk2 : mks) {
+                if (mk == mk2) return true;
+            }
+            return false;
+        }
+    }
+    
+    enum PackageKind {
+        PACKAGE("package foo;"),
+        NO_PACKAGE("");
+        
+        String packageKind;
+
+        PackageKind(String packageKind) {
+            this.packageKind = packageKind;
+        }
+    }
+    
+    enum AnnotationKind {
+        ANNO("@Anno"),
+        NO_ANNO("");
+        
+        String annoString;
+
+        AnnotationKind(String annoString) {
+            this.annoString = annoString;
+        }
+    }
+
+    enum DeclKind {
+        ABSTRACT_CLASS("abstract class Foo { }"),
+        CLASS("class Foo { }"),
+        ENUM("enum Foo { }"),
+        INTERFACE("interface Foo { }"),
+        ANNOTATION("@interface Foo { }"),
+        VAR("String foo;"),
+        METHOD("String foo() { return null; }");
+
+        String declStr;
+
+        private DeclKind(String declStr) {
+            this.declStr = declStr;
+        }
+    }
+
+    public static void main(String... args) throws Exception {
+
+        //create default shared JavaCompiler - reused across multiple compilations
+        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+        for (VersionKind vk : VersionKind.values()) {
+            for (AnnotationKind ak : AnnotationKind.values()) {
+                for (PackageKind pk : PackageKind.values()) {
+                    for (ModifierKind modk1 : ModifierKind.values()) {
+                        for (ModifierKind modk2 : ModifierKind.values()) {
+                            for (DeclKind dk : DeclKind.values()) {
+                                new TestPackageAsModifier(vk, ak, pk, modk1, modk2, dk).run(comp, fm);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        System.out.println("Total check executed: " + checkCount);
+    }
+
+    VersionKind vk;
+    AnnotationKind ak;
+    PackageKind pk;
+    ModifierKind modk1, modk2;
+    DeclKind dk;
+    JavaSource source;
+    DiagnosticChecker diagChecker;
+
+    public TestPackageAsModifier(VersionKind vk, AnnotationKind ak, PackageKind pk, ModifierKind modk1, ModifierKind modk2, DeclKind dk) {
+        this.vk = vk;
+        this.ak = ak;
+        this.pk = pk;
+        this.modk1 = modk1;
+        this.modk2 = modk2;
+        this.dk = dk;
+        this.source = new JavaSource();
+        this.diagChecker = new DiagnosticChecker();
+    }
+
+    class JavaSource extends SimpleJavaFileObject {
+
+        String template = "#AK\n" +
+                          "#PK\n" +
+                          "class Test {\n" +
+                          "   #MOD1 #MOD2 #DK\n" +
+                          "}\n" +
+                          "@interface Anno { }\n";
+
+        String source;
+
+        public JavaSource() {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            source = template.replaceAll("#AK", ak.annoString)
+                    .replaceAll("#PK", pk.packageKind)
+                    .replaceAll("#MOD1", modk1.modStr)
+                    .replaceAll("#MOD2", modk2.modStr)
+                    .replaceAll("#DK", dk.declStr);
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+
+    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
+        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
+                vk.getOptions(), null, Arrays.asList(source));
+        try {
+            ct.analyze();
+        } catch (Throwable ex) {
+            throw new AssertionError("Error thrown when analyzing the following source:\n" + source.getCharContent(true));
+        }
+        check();
+    }
+
+    void check() {
+        boolean errorExpected = ModifierKind.intersect(ModifierKind.PACKAGE, modk1, modk2) &&
+                vk == VersionKind.PRE_LAMBDA;
+
+        errorExpected |= !ModifierKind.intersect(ModifierKind.NONE, modk1, modk2);
+        
+        errorExpected |= pk == PackageKind.PACKAGE && ak == AnnotationKind.ANNO;
+
+        checkCount++;
+        if (diagChecker.errorFound != errorExpected) {
+            throw new AssertionError("Problem when compiling source:\n" + source.getCharContent(true) +
+                    "\nfound error: " + diagChecker.errorFound);
+        }
+    }
+
+    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+        boolean errorFound;
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+                errorFound = true;
+            }
+        }
+    }
+}
--- a/test/tools/javac/diags/examples.not-yet.txt	Mon Jan 07 14:12:17 2013 +0100
+++ b/test/tools/javac/diags/examples.not-yet.txt	Mon Jan 07 18:45:59 2013 +0100
@@ -109,4 +109,5 @@
 compiler.warn.unknown.enum.constant                     # in bad class file
 compiler.warn.unknown.enum.constant.reason              # in bad class file
 compiler.err.static.intf.methods.not.supported.in.source                         #LAMBDA
-compiler.err.private.intf.methods.not.supported.in.source                        #LAMBDA
\ No newline at end of file
+compiler.err.private.intf.methods.not.supported.in.source                        #LAMBDA
+compiler.err.pckge.mod.not.supported.in.source                                   #LAMBDA