diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StaticImportTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StaticImportTest.java index bae6a3c..f1da7df 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StaticImportTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StaticImportTest.java @@ -2484,10 +2484,10 @@ "}\n", }, "----------\n" + - "1. ERROR in p1\\A.java (at line 7)\n" + - " int v2 = b.fooC;\n" + + "1. ERROR in p1\\A.java (at line 6)\n" + + " int v1 = b.fooB;\n" + " ^^^^\n" + - "fooC cannot be resolved or is not a field\n" + + "fooB cannot be resolved or is not a field\n" + "----------\n"); } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=256375 @@ -2720,5 +2720,132 @@ "----------\n" ); } + + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318401 + public void test081() { + this.runConformTest( + new String[] { + "Test.java", + "import static p1.Bar.B;\n" + + "import p3.Foo.*;\n" + + "public class Test {\n" + + " public static void main(String [] args){\n" + + " new Test().beginTest();" + + " }\n" + + " public void beginTest(){\n" + + " System.out.print(\"1 + 1 = \");\n" + + " if(alwaysTrue()) System.out.println(\"2\");\n" + + " else System.out.println(\"3\"); " + + " }\n" + + " public boolean alwaysTrue(){\n" + + " String myB = B.class.getCanonicalName();;\n" + // refers to p1.Bar.B (class) + " String realB = p1.Bar.B.class.getCanonicalName();;\n" + // refers to p1.Bar.B (class) + " B();\n" + // refers to p1.Bar.B() (method) + " return myB.equals(realB);\n" + + " }\n" + + "}\n", + "p1/Bar.java", + "package p1;\n" + + "public class Bar{\n" + + " public static class B{}\n" + + " final public static String B = new String(\"random\");\n" + + " public static void B(){}\n" + + "}\n", + "p3/Foo.java", + "package p3;\n" + + "public class Foo {\n" + + " public class B{\n" + + " public int a;\n" + + " }\n" + + "}\n" + }, + "1 + 1 = 2"); + } + + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318401 + public void test082() { + this.runNegativeTest( + new String[] { + "p1/Bar.java", + "package p1;\n" + + "public class Bar{\n" + + " public static class B{}\n" + + " final public static String B = new String(\"random\");\n" + + " public static void B(){}\n" + + "}\n", + "p3/Foo.java", + "package p3;\n" + + "public class Foo {\n" + + " public class B{\n" + + " public int a;\n" + + " }\n" + + "}\n", + "p2/Test.java", + "package p2;\n" + + "import static p1.Bar.B;\n" + + "import p3.Foo.*;\n" + + "public class Test {\n" + + " public static void main(String [] args){\n" + + " new Test().beginTest();" + + " }\n" + + " public void beginTest(){\n" + + " System.out.print(\"1 + 1 = \");\n" + + " if(alwaysTrue()) System.out.println(\"2\");\n" + + " else System.out.println(\"3\"); " + + " }\n" + + " public boolean alwaysTrue(){\n" + + " B b = null;\n" + // refers to p1.Bar.B (class) + " String realB = B;\n" + // refers to p1.Bar.B (field) + " B();\n" + // refers to p1.Bar.B() (method) + " int abc = b.a;\n;" + // static import for Bar.B overshadows on demand import Foo.B + " }\n" + + "}\n", + }, + "----------\n" + + "1. ERROR in p2\\Test.java (at line 15)\n" + + " int abc = b.a;\n" + + " ^\n" + + "a cannot be resolved or is not a field\n" + + "----------\n"); + } + + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318401 + public void test083() { + this.runConformTest( + new String[] { + "Test.java", + "import static p1.Bar.B;\n" + + "import p3.Foo.*;\n" + + "public class Test {\n" + + " public static void main(String [] args){\n" + + " new Test().test2();" + + " }\n" + + " public void test2(){\n" + + " System.out.println(B.toString());\n" + // Field obscures class B + " System.out.println(p1.Bar.B.toString());\n" + // Field obscures the class B + " System.out.println(B.class.getCanonicalName().toString());\n" + // the class B + " System.out.println(p1.Bar.B.class.getCanonicalName().toString());" + // class B + " }\n" + + "}\n", + "p1/Bar.java", + "package p1;\n" + + "public class Bar{\n" + + " public static class B{}\n" + + " final public static String B = new String(\"random\");\n" + + " public static void B(){}\n" + + "}\n", + "p3/Foo.java", + "package p3;\n" + + "public class Foo {\n" + + " public class B{\n" + + " public int a;\n" + + " }\n" + + "}\n" + }, + "random\n" + + "random\n" + + "p1.Bar.B\n" + + "p1.Bar.B"); + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java index 9ec7e0a..5edad4d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java @@ -2712,7 +2712,62 @@ } } } - + // walk single static imports. A type found here will shadow types with same name in other CU's, or types coming + // from on-demand imports. JLS 7.5.3 + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318401 + if (imports != null) { + boolean foundInImport = false; + ReferenceBinding type = null; + nextImport : for (int i = 0, length = imports.length; i < length; i++) { + ImportBinding importBinding = imports[i]; + if (importBinding.isStatic()) { + ReferenceBinding temp = null; + if (CharOperation.equals(importBinding.compoundName[importBinding.compoundName.length - 1], name)) { + Binding resolvedImport = importBinding.resolvedImport; + if (resolvedImport == null) continue nextImport; + if (resolvedImport instanceof MethodBinding || resolvedImport instanceof FieldBinding) { + // check to see if there are also member types with the same name + // must find the importRef's type again since the method/field can be from an inherited type + char[][] importName = importBinding.reference.tokens; + TypeBinding referencedType = getType(importName, importName.length - 1); + if (referencedType != null && referencedType instanceof ReferenceBinding) { + temp = findMemberType(name, (ReferenceBinding) referencedType); + if (temp != null && !temp.isStatic()) temp = null; + } + } + if (temp != type && temp != null) { + if (temp.isValidBinding()) { + if (!temp.canBeSeenBy(unitScope.fPackage)) { + // Answer error binding - type is not visible + foundType = new ProblemReferenceBinding(new char[][]{name}, type, ProblemReasons.NotVisible); + } else { + ImportReference importReference = importBinding.reference; + if (importReference != null) { + importReference.bits |= ASTNode.Used; + } + if (foundInImport) { + // Answer error binding -- import on demand conflict; name found in two import on demand packages. + temp = new ProblemReferenceBinding(new char[][]{name}, type, ProblemReasons.Ambiguous); + if (typeOrPackageCache != null) + typeOrPackageCache.put(name, temp); + return temp; + } + type = temp; + foundInImport = true; + } + } else if (foundType == null) { + foundType = temp; + } + } + } + } + } + if (type != null) { + if (typeOrPackageCache != null) + typeOrPackageCache.put(name, type); + return type; + } + } // check if the name is in the current package, skip it if its a sub-package PackageBinding currentPackage = unitScope.fPackage; unitScope.recordReference(currentPackage.compoundName, name);