UnifyAst correctly handles polymorphic overrides with mixed default/public access.

GWT AST now tracks method access.  This is used by UnifyAst to correctly compute overrides.  Before, UnifyAst would allow a public method to override a default-access method in a different package, which is illegal.
http://gwt-code-reviews.appspot.com/1470803/


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10422 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/AccessModifier.java b/dev/core/src/com/google/gwt/dev/jjs/ast/AccessModifier.java
new file mode 100644
index 0000000..11dc785
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/AccessModifier.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.ast;
+
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+
+/**
+ * The Java access modifiers.
+ */
+public enum AccessModifier {
+  /*
+   * DO NOT SORT. Will break ordinal-based serialization in JMethod. If this is
+   * updated, you must bump the AST serialization version.
+   */
+  PUBLIC, PROTECTED, DEFAULT, PRIVATE;
+
+  static {
+    assert PUBLIC.ordinal() == 0;
+    assert PROTECTED.ordinal() == 1;
+    assert DEFAULT.ordinal() == 2;
+    assert PRIVATE.ordinal() == 3;
+  }
+
+  public static AccessModifier fromMethodBinding(MethodBinding b) {
+    if (b.isPublic()) {
+      return PUBLIC;
+    } else if (b.isProtected()) {
+      return PROTECTED;
+    } else if (b.isPrivate()) {
+      return PRIVATE;
+    }
+    assert b.isDefault();
+    return DEFAULT;
+  }
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java
index 0f67ea1..6864453 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java
@@ -50,8 +50,9 @@
   private boolean isEmpty = false;
 
   public JConstructor(SourceInfo info, JClassType enclosingType) {
+    // Access only matters for virtual methods, just use public.
     super(info, enclosingType.getShortName(), enclosingType, JPrimitiveType.VOID, false, false,
-        true, false);
+        true, AccessModifier.PUBLIC);
   }
 
   @Override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index 401ca91..1f23013 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -60,7 +60,7 @@
   }
 
   public static final JMethod NULL_METHOD = new JMethod(SourceOrigin.UNKNOWN, "nullMethod", null,
-      JNullType.INSTANCE, false, false, true, false);
+      JNullType.INSTANCE, false, false, true, AccessModifier.PUBLIC);
 
   private static final String TRACE_METHOD_WILDCARD = "*";
 
@@ -91,13 +91,18 @@
   protected transient String signature;
 
   /**
+   * The access modifier; stored as an int to reduce memory / serialization
+   * footprint.
+   */
+  private int access;
+
+  /**
    * Special serialization treatment.
    */
   private transient JAbstractMethodBody body = null;
   private final JDeclaredType enclosingType;
   private boolean isAbstract;
   private boolean isFinal;
-  private final boolean isPrivate;
   private final boolean isStatic;
   private boolean isSynthetic = false;
   private final String name;
@@ -124,7 +129,7 @@
    * These are only supposed to be constructed by JProgram.
    */
   public JMethod(SourceInfo info, String name, JDeclaredType enclosingType, JType returnType,
-      boolean isAbstract, boolean isStatic, boolean isFinal, boolean isPrivate) {
+      boolean isAbstract, boolean isStatic, boolean isFinal, AccessModifier access) {
     super(info);
     this.name = StringInterner.get().intern(name);
     this.enclosingType = enclosingType;
@@ -132,7 +137,7 @@
     this.isAbstract = isAbstract;
     this.isStatic = isStatic;
     this.isFinal = isFinal;
-    this.isPrivate = isPrivate;
+    this.access = access.ordinal();
   }
 
   /**
@@ -145,7 +150,7 @@
     this.signature = signature;
     this.isAbstract = false;
     this.isStatic = false;
-    this.isPrivate = false;
+    this.access = AccessModifier.PUBLIC.ordinal();
   }
 
   /**
@@ -196,6 +201,10 @@
     setOriginalTypes(returnType, paramTypes);
   }
 
+  public AccessModifier getAccess() {
+    return AccessModifier.values()[access];
+  }
+
   public JAbstractMethodBody getBody() {
     assert !isExternal() : "External types do not have method bodies.";
     return body;
@@ -258,6 +267,10 @@
     return isAbstract;
   }
 
+  public boolean isDefault() {
+    return access == AccessModifier.DEFAULT.ordinal();
+  }
+
   public boolean isExternal() {
     return getEnclosingType() != null && getEnclosingType().isExternal();
   }
@@ -275,7 +288,7 @@
   }
 
   public boolean isPrivate() {
-    return isPrivate;
+    return access == AccessModifier.PRIVATE.ordinal();
   }
 
   public boolean isStatic() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index 3e6765a..1363eb8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -482,21 +482,21 @@
   }
 
   public JMethod createMethod(SourceInfo info, String name, JDeclaredType enclosingType,
-      JType returnType, boolean isAbstract, boolean isStatic, boolean isFinal, boolean isPrivate,
-      boolean isNative) {
+      JType returnType, boolean isAbstract, boolean isStatic, boolean isFinal,
+      AccessModifier access, boolean isNative) {
     assert (name != null);
     assert (enclosingType != null);
     assert (returnType != null);
     assert (!isAbstract || !isNative);
     JMethod x =
-        new JMethod(info, name, enclosingType, returnType, isAbstract, isStatic, isFinal, isPrivate);
+        new JMethod(info, name, enclosingType, returnType, isAbstract, isStatic, isFinal, access);
     if (isNative) {
       x.setBody(new JsniMethodBody(info));
     } else if (!isAbstract) {
       x.setBody(new JMethodBody(info));
     }
 
-    if (!isPrivate && indexedTypes.containsValue(enclosingType)) {
+    if (access != AccessModifier.PRIVATE && indexedTypes.containsValue(enclosingType)) {
       indexedMethods.put(enclosingType.getShortName() + '.' + name, x);
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
index 6b594f7..83bd75d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
@@ -22,6 +22,7 @@
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.SourceOrigin;
+import com.google.gwt.dev.jjs.ast.AccessModifier;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JConstructor;
 import com.google.gwt.dev.jjs.ast.JDeclaredType;
@@ -676,7 +677,7 @@
     SourceInfo child = info.makeChild();
     JMethod clinit =
         program.createMethod(child, "$clinit", newType, program.getTypeVoid(), false, true, true,
-            true, false);
+            AccessModifier.PRIVATE, false);
     clinit.freezeParamTypes();
     clinit.setSynthetic();
     child.addCorrelation(info.getCorrelator().by(clinit));
@@ -685,7 +686,7 @@
       child = info.makeChild();
       JMethod init =
           program.createMethod(child, "$init", newType, program.getTypeVoid(), false, false, true,
-              true, false);
+              AccessModifier.PRIVATE, false);
       init.freezeParamTypes();
       init.setSynthetic();
       child.addCorrelation(info.getCorrelator().by(init));
@@ -767,7 +768,7 @@
         SourceInfo info = type.getSourceInfo().makeChild();
         JMethod getClassMethod =
             program.createMethod(info, "getClass", type, program.getTypeJavaLangClass(), false,
-                false, false, false, false);
+                false, false, AccessModifier.PUBLIC, false);
         assert (type.getMethods().get(2) == getClassMethod);
         getClassMethod.freezeParamTypes();
         getClassMethod.setSynthetic();
@@ -951,7 +952,8 @@
     JType returnType = getType(b.returnType);
     JMethod newMethod =
         program.createMethod(info, String.valueOf(b.selector), enclosingType, returnType, b
-            .isAbstract(), b.isStatic(), b.isFinal(), b.isPrivate(), b.isNative());
+            .isAbstract(), b.isStatic(), b.isFinal(), AccessModifier.fromMethodBinding(b), b
+            .isNative());
     addThrownExceptions(b, newMethod);
     if (b.isSynthetic()) {
       newMethod.setSynthetic();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index d472f40..87a6aa7 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -21,6 +21,7 @@
 import com.google.gwt.dev.jjs.JJSOptions;
 import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.SourceOrigin;
+import com.google.gwt.dev.jjs.ast.AccessModifier;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.JArrayLength;
 import com.google.gwt.dev.jjs.ast.JArrayRef;
@@ -2055,7 +2056,7 @@
       JMethod bridgeMethod =
           program.createMethod(info, String.valueOf(jdtBridgeMethod.selector), clazz,
               (JType) typeMap.get(jdtBridgeMethod.returnType.erasure()), false, false, implmeth
-                  .isFinal(), false, false);
+                  .isFinal(), implmeth.getAccess(), false);
       bridgeMethod.setSynthetic();
       int paramIdx = 0;
       List<JParameter> implParams = implmeth.getParams();
@@ -2742,7 +2743,7 @@
         JDeclarationStatement declStmt = new JDeclarationStatement(methodInfo, mapRef, call);
         JMethod clinit =
             program.createMethod(methodInfo, "$clinit", mapClass, program.getTypeVoid(), false,
-                true, true, true, false);
+                true, true, AccessModifier.PRIVATE, false);
         clinit.freezeParamTypes();
         methodInfo.addCorrelation(methodInfo.getCorrelator().by(clinit));
         JBlock clinitBlock = ((JMethodBody) clinit.getBody()).getBlock();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 483275f..ae2e645 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -21,6 +21,7 @@
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.SourceOrigin;
+import com.google.gwt.dev.jjs.ast.AccessModifier;
 import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
 import com.google.gwt.dev.jjs.ast.JArrayLength;
 import com.google.gwt.dev.jjs.ast.JArrayRef;
@@ -1999,7 +2000,8 @@
       SourceInfo info = implmeth.getSourceInfo();
       JMethod bridgeMethod =
           new JMethod(info, implmeth.getName(), curClass.type, typeMap
-              .get(jdtBridgeMethod.returnType), false, false, implmeth.isFinal(), false);
+              .get(jdtBridgeMethod.returnType), false, false, implmeth.isFinal(), implmeth
+              .getAccess());
       typeMap.setMethod(jdtBridgeMethod, bridgeMethod);
       bridgeMethod.setBody(new JMethodBody(info));
       curClass.type.addMethod(bridgeMethod);
@@ -2684,7 +2686,7 @@
         JDeclarationStatement declStmt = new JDeclarationStatement(info, mapRef, call);
         JMethod clinit =
             createSyntheticMethod(info, "$clinit", mapClass, JPrimitiveType.VOID, false, true,
-                true, true);
+                true, AccessModifier.PRIVATE);
         JBlock clinitBlock = ((JMethodBody) clinit.getBody()).getBlock();
         clinitBlock.addStmt(declStmt);
       }
@@ -2765,7 +2767,7 @@
    * 
    * TODO(zundel): something much more awesome?
    */
-  private static final long AST_VERSION = 1;
+  private static final long AST_VERSION = 2;
 
   private static final char[] _STRING = "_String".toCharArray();
   private static final String ARRAY_LENGTH_FIELD = "length";
@@ -3023,16 +3025,19 @@
        * is always in slot 1.
        */
       assert type.getMethods().size() == 0;
-      createSyntheticMethod(info, "$clinit", type, JPrimitiveType.VOID, false, true, true, true);
+      createSyntheticMethod(info, "$clinit", type, JPrimitiveType.VOID, false, true, true,
+          AccessModifier.PRIVATE);
 
       if (type instanceof JClassType) {
         assert type.getMethods().size() == 1;
-        createSyntheticMethod(info, "$init", type, JPrimitiveType.VOID, false, false, true, true);
+        createSyntheticMethod(info, "$init", type, JPrimitiveType.VOID, false, false, true,
+            AccessModifier.PRIVATE);
 
         // Add a getClass() implementation for all non-Object classes.
         if (type != javaLangObject && !JSORestrictionsChecker.isJsoSubclass(binding)) {
           assert type.getMethods().size() == 2;
-          createSyntheticMethod(info, "getClass", type, javaLangClass, false, false, false, false);
+          createSyntheticMethod(info, "getClass", type, javaLangClass, false, false, false,
+              AccessModifier.PUBLIC);
         }
       }
 
@@ -3125,7 +3130,7 @@
     } else {
       method =
           new JMethod(info, intern(b.selector), enclosingType, typeMap.get(b.returnType), b
-              .isAbstract(), b.isStatic(), b.isFinal(), b.isPrivate());
+              .isAbstract(), b.isStatic(), b.isFinal(), AccessModifier.fromMethodBinding(b));
     }
 
     // User args.
@@ -3182,9 +3187,9 @@
   }
 
   private JMethod createSyntheticMethod(SourceInfo info, String name, JDeclaredType enclosingType,
-      JType returnType, boolean isAbstract, boolean isStatic, boolean isFinal, boolean isPrivate) {
+      JType returnType, boolean isAbstract, boolean isStatic, boolean isFinal, AccessModifier access) {
     JMethod method =
-        new JMethod(info, name, enclosingType, returnType, isAbstract, isStatic, isFinal, isPrivate);
+        new JMethod(info, name, enclosingType, returnType, isAbstract, isStatic, isFinal, access);
     method.freezeParamTypes();
     method.setSynthetic();
     method.setBody(new JMethodBody(info));
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
index ef77843..75b2522 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsoDevirtualizer.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.SourceOrigin;
+import com.google.gwt.dev.jjs.ast.AccessModifier;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JConditional;
@@ -226,7 +227,7 @@
     String name = polyMethod.getName() + "__devirtual$";
     JMethod newMethod =
         program.createMethod(sourceInfo, name, jsoType, polyMethod.getType(), false, true, true,
-            false, false);
+            AccessModifier.PUBLIC, false);
     newMethod.setSynthetic();
 
     // Setup parameters.
@@ -296,4 +297,4 @@
     }
     return staticImpl;
   }
-}
+}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
index 37b2628..3543d4e 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MakeCallsStatic.java
@@ -155,7 +155,7 @@
        */
       JMethod newMethod =
           new JMethod(sourceInfo, newName, enclosingType, returnType, false, true, true, x
-              .isPrivate());
+              .getAccess());
       newMethod.setSynthetic();
       newMethod.addThrownExceptions(x.getThrownExceptions());
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
index e8d863b..f03609f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ReferenceMapper.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.SourceInfo;
 import com.google.gwt.dev.jjs.SourceOrigin;
+import com.google.gwt.dev.jjs.ast.AccessModifier;
 import com.google.gwt.dev.jjs.ast.JArrayType;
 import com.google.gwt.dev.jjs.ast.JClassType;
 import com.google.gwt.dev.jjs.ast.JConstructor;
@@ -168,7 +169,7 @@
       // Emulate clinit method for super clinit calls.
       JMethod clinit =
           new JMethod(SourceOrigin.UNKNOWN, "$clinit", declType, JPrimitiveType.VOID, false, true,
-              true, true);
+              true, AccessModifier.PRIVATE);
       clinit.freezeParamTypes();
       clinit.setSynthetic();
       declType.addMethod(clinit);
@@ -238,7 +239,7 @@
     JDeclaredType enclosingType = (JDeclaredType) get(b.declaringClass);
     JMethod method =
         new JMethod(info, intern(b.selector), enclosingType, get(b.returnType), b.isAbstract(), b
-            .isStatic(), b.isFinal(), b.isPrivate());
+            .isStatic(), b.isFinal(), AccessModifier.fromMethodBinding(b));
     enclosingType.addMethod(method);
     if (paramNames == null) {
       mapParameters(info, method, b, 0);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
index c21fdf9..87d9b98 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ResolveRebinds.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.ast.AccessModifier;
 import com.google.gwt.dev.jjs.ast.Context;
 import com.google.gwt.dev.jjs.ast.JBlock;
 import com.google.gwt.dev.jjs.ast.JCaseStatement;
@@ -199,7 +200,8 @@
     SourceInfo info = program.createSourceInfoSynthetic(getClass());
     toReturn =
         program.createMethod(info, requestType.replace("_", "_1").replace('.', '_'), holderType,
-            program.getTypeJavaLangObject().getNonNull(), false, true, true, false, false);
+            program.getTypeJavaLangObject().getNonNull(), false, true, true,
+            AccessModifier.PUBLIC, false);
     toReturn.freezeParamTypes();
     info.addCorrelation(info.getCorrelator().by(toReturn));
     rebindMethods.put(requestType, toReturn);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
index ac1ae3e..829886f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
@@ -1063,10 +1063,18 @@
 
   protected void printMethodHeader(JMethod x) {
     // Modifiers
-    if (x.isPrivate()) {
-      print(CHARS_PRIVATE);
-    } else {
-      print(CHARS_PUBLIC);
+    switch (x.getAccess()) {
+      case PUBLIC:
+        print(CHARS_PUBLIC);
+        break;
+      case PROTECTED:
+        print(CHARS_PROTECTED);
+        break;
+      case PRIVATE:
+        print(CHARS_PRIVATE);
+        break;
+      case DEFAULT:
+        break;
     }
     printStaticFlag(x);
     printAbstractFlag(x);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
index 65c896b..a46ae10 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/UnifyAst.java
@@ -20,6 +20,7 @@
 import com.google.gwt.dev.javac.CompilationProblemReporter;
 import com.google.gwt.dev.javac.CompilationUnit;
 import com.google.gwt.dev.javac.CompiledClass;
+import com.google.gwt.dev.javac.Shared;
 import com.google.gwt.dev.jdt.RebindPermutationOracle;
 import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.JJSOptions;
@@ -675,6 +676,19 @@
     }
   }
 
+  private boolean canAccessSuperMethod(JDeclaredType type, JMethod method) {
+    if (method.isPrivate()) {
+      return false;
+    }
+    if (method.isDefault()) {
+      // Check package access.
+      String typePackage = Shared.getPackageName(type.getName());
+      String methodPackage = Shared.getPackageName(method.getEnclosingType().getName());
+      return typePackage.equals(methodPackage);
+    }
+    return true;
+  }
+
   private void collectUpRefs(JDeclaredType type, Map<String, Set<JMethod>> collected) {
     if (type == null) {
       return;
@@ -711,8 +725,11 @@
       collectUpRefsInSupers(type, collected);
       for (JMethod method : type.getMethods()) {
         if (method.canBePolymorphic()) {
-          Set<JMethod> uprefs = collected.get(method.getSignature());
-          method.addOverrides(Lists.create(uprefs));
+          for (JMethod upref : collected.get(method.getSignature())) {
+            if (canAccessSuperMethod(type, upref)) {
+              method.addOverride(upref);
+            }
+          }
         }
       }
     }
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/PrunerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/PrunerTest.java
index 7f62988..4a392bd 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/PrunerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/PrunerTest.java
@@ -112,14 +112,14 @@
     assertNull(result.findClass("UninstantiatedClass"));
 
     assertEquals(
-        "public static null returnUninstantiatedClass(){\n" + 
+        "static null returnUninstantiatedClass(){\n" +
         "  return null;\n" +
-        "}", 
+        "}",
         result.findMethod("returnUninstantiatedClass").toSource());
     
     assertEquals(
-        "public static void methodWithUninstantiatedParam(){\n" + 
-        "}", 
+        "static void methodWithUninstantiatedParam(){\n" +
+        "}",
         result.findMethod("methodWithUninstantiatedParam").toSource());
 
     assertEquals(