### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java,v retrieving revision 1.640 diff -u -r1.640 GenericTypeTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 13 Sep 2007 07:05:55 -0000 1.640 +++ src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java 13 Sep 2007 08:49:44 -0000 @@ -38757,7 +38757,7 @@ } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=202404 - variation public void test1161() { - this.runNegativeTest( + this.runConformTest( new String[] { "X.java", "class Y> {}\n" + @@ -38770,7 +38770,7 @@ } //https://bugs.eclipse.org/bugs/show_bug.cgi?id=202404 - variation public void test1162() { - this.runNegativeTest( + this.runConformTest( new String[] { "X.java", "class Y> {}\n" + @@ -38781,4 +38781,152 @@ }, ""); } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=203061 - variation +public void test1163() { + this.runNegativeTest( + new String[] { + "X.java", + "public final class X {\n" + + " private final Object mObj;\n" + + " private final Object mDependent = new Object() {\n" + + " {\n" + + " Object o1 = mObj;\n" + + " }\n" + + " Object o2 = mObj;\n" + + " void foo() {\n" + + " Object o3 = mObj;\n" + + " }\n" + + " };\n" + + " public X() {\n" + + " mObj = \"\";\n" + + " }\n" + + "}\n", // ================= + }, + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " private final Object mDependent = new Object() {\n" + + " ^^^^^^^^^^\n" + + "The field X.mDependent is never read locally\n" + + "----------\n" + + "2. WARNING in X.java (at line 5)\n" + + " Object o1 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "3. ERROR in X.java (at line 5)\n" + + " Object o1 = mObj;\n" + + " ^^^^\n" + + "The blank final field mObj may not have been initialized\n" + + "----------\n" + + "4. WARNING in X.java (at line 7)\n" + + " Object o2 = mObj;\n" + + " ^^\n" + + "The field new Object(){}.o2 is never read locally\n" + + "----------\n" + + "5. WARNING in X.java (at line 7)\n" + + " Object o2 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "6. ERROR in X.java (at line 7)\n" + + " Object o2 = mObj;\n" + + " ^^^^\n" + + "The blank final field mObj may not have been initialized\n" + + "----------\n" + + "7. WARNING in X.java (at line 8)\n" + + " void foo() {\n" + + " ^^^^^\n" + + "The method foo() from the type new Object(){} is never used locally\n" + + "----------\n" + + "8. WARNING in X.java (at line 9)\n" + + " Object o3 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n"); +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=203061 - variation +public void test1164() { + this.runNegativeTest( + new String[] { + "X.java", + "public final class X {\n" + + " private final Object mObj;\n" + + " private final Object mDependent = new Object() {\n" + + " {\n" + + " Object o1 = mObj;\n" + + " mObj = \"1\";\n" + + " }\n" + + " Object o2 = mObj = \"2\";\n" + + " void foo() {\n" + + " Object o3 = mObj;\n" + + " mObj = \"3\";\n" + + " }\n" + + " };\n" + + " public X() {\n" + + " mObj = \"\";\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " private final Object mDependent = new Object() {\n" + + " ^^^^^^^^^^\n" + + "The field X.mDependent is never read locally\n" + + "----------\n" + + "2. WARNING in X.java (at line 5)\n" + + " Object o1 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "3. ERROR in X.java (at line 5)\n" + + " Object o1 = mObj;\n" + + " ^^^^\n" + + "The blank final field mObj may not have been initialized\n" + + "----------\n" + + "4. WARNING in X.java (at line 6)\n" + + " mObj = \"1\";\n" + + " ^^^^\n" + + "Write access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "5. ERROR in X.java (at line 6)\n" + + " mObj = \"1\";\n" + + " ^^^^\n" + + "The final field X.mObj cannot be assigned\n" + + "----------\n" + + "6. WARNING in X.java (at line 8)\n" + + " Object o2 = mObj = \"2\";\n" + + " ^^\n" + + "The field new Object(){}.o2 is never read locally\n" + + "----------\n" + + "7. WARNING in X.java (at line 8)\n" + + " Object o2 = mObj = \"2\";\n" + + " ^^^^\n" + + "Write access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "8. ERROR in X.java (at line 8)\n" + + " Object o2 = mObj = \"2\";\n" + + " ^^^^\n" + + "The final field X.mObj cannot be assigned\n" + + "----------\n" + + "9. WARNING in X.java (at line 9)\n" + + " void foo() {\n" + + " ^^^^^\n" + + "The method foo() from the type new Object(){} is never used locally\n" + + "----------\n" + + "10. WARNING in X.java (at line 10)\n" + + " Object o3 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "11. WARNING in X.java (at line 11)\n" + + " mObj = \"3\";\n" + + " ^^^^\n" + + "Write access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "12. ERROR in X.java (at line 11)\n" + + " mObj = \"3\";\n" + + " ^^^^\n" + + "The final field X.mObj cannot be assigned\n" + + "----------\n"); +} } #P org.eclipse.jdt.core Index: compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java,v retrieving revision 1.97 diff -u -r1.97 SingleNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 2 May 2007 00:32:25 -0000 1.97 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 13 Sep 2007 08:49:47 -0000 @@ -41,7 +41,7 @@ case Binding.FIELD : // reading a field FieldBinding fieldBinding; if ((fieldBinding = (FieldBinding) binding).isBlankFinal() - && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { + && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); } @@ -152,7 +152,7 @@ } } // check if reading a final blank field - if (fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { + if (fieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); } Index: compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java,v retrieving revision 1.109 diff -u -r1.109 FieldReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 15 Mar 2007 14:04:15 -0000 1.109 +++ compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 13 Sep 2007 08:49:46 -0000 @@ -46,7 +46,7 @@ if (isCompound) { // check the variable part is initialized if blank final if (binding.isBlankFinal() && receiver.isThis() - && currentScope.allowBlankFinalFieldAssignment(binding) + && currentScope.needBlankFinalFieldInitializationCheck(binding) && (!flowInfo.isDefinitelyAssigned(binding))) { currentScope.problemReporter().uninitializedBlankFinalField(binding, this); // we could improve error msg here telling "cannot use compound assignment on final blank field" Index: compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java,v retrieving revision 1.117 diff -u -r1.117 QualifiedNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 15 Jul 2007 00:17:22 -0000 1.117 +++ compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 13 Sep 2007 08:49:46 -0000 @@ -85,7 +85,7 @@ // check if final blank field if (lastFieldBinding.isBlankFinal() && this.otherBindings != null // the last field binding is only assigned - && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { + && currentScope.needBlankFinalFieldInitializationCheck(lastFieldBinding)) { if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) { currentScope.problemReporter().uninitializedBlankFinalField( lastFieldBinding, @@ -134,7 +134,7 @@ if (isCompound) { if (otherBindingsCount == 0 && lastFieldBinding.isBlankFinal() - && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding) + && currentScope.needBlankFinalFieldInitializationCheck(lastFieldBinding) && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) { currentScope.problemReporter().uninitializedBlankFinalField(lastFieldBinding, this); } @@ -237,7 +237,7 @@ } // check if reading a final blank field if (fieldBinding.isBlankFinal() - && currentScope.allowBlankFinalFieldAssignment(fieldBinding) + && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding) && !flowInfo.isDefinitelyAssigned(fieldBinding)) { currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); } Index: compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java,v retrieving revision 1.65 diff -u -r1.65 MethodScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java 29 Aug 2007 18:11:25 -0000 1.65 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java 13 Sep 2007 08:49:47 -0000 @@ -19,7 +19,7 @@ import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; /** - * Particular block scope used for methods, constructors or clinits, representing + * Specific block scope used for methods, constructors or clinits, representing * its outermost blockscope. Note also that such a scope will be provided to enclose * field initializers subscopes as well. */ @@ -49,449 +49,437 @@ // inner-emulation public SyntheticArgumentBinding[] extraSyntheticArguments; - public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) { +public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) { + super(METHOD_SCOPE, parent); + locals = new LocalVariableBinding[5]; + this.referenceContext = context; + this.isStatic = isStatic; + this.startIndex = 0; +} - super(METHOD_SCOPE, parent); - locals = new LocalVariableBinding[5]; - this.referenceContext = context; - this.isStatic = isStatic; - this.startIndex = 0; - } - - /* Spec : 8.4.3 & 9.4 - */ - private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) { - - int modifiers = methodBinding.modifiers; - final ReferenceBinding declaringClass = methodBinding.declaringClass; - if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0) - problemReporter().duplicateModifierForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); - - if ((((ConstructorDeclaration) referenceContext).bits & ASTNode.IsDefaultConstructor) != 0) { - // certain flags are propagated from declaring class onto constructor - final int DECLARING_FLAGS = ClassFileConstants.AccEnum|ClassFileConstants.AccPublic|ClassFileConstants.AccProtected; - final int VISIBILITY_FLAGS = ClassFileConstants.AccPrivate|ClassFileConstants.AccPublic|ClassFileConstants.AccProtected; - int flags; - if ((flags = declaringClass.modifiers & DECLARING_FLAGS) != 0) { - if ((flags & ClassFileConstants.AccEnum) != 0) { - modifiers &= ~VISIBILITY_FLAGS; - modifiers |= ClassFileConstants.AccPrivate; // default constructor is implicitly private in enum - } else { - modifiers &= ~VISIBILITY_FLAGS; - modifiers |= flags; // propagate public/protected - } +String basicToString(int tab) { + String newLine = "\n"; //$NON-NLS-1$ + for (int i = tab; --i >= 0;) + newLine += "\t"; //$NON-NLS-1$ + + String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$ + newLine += "\t"; //$NON-NLS-1$ + s += newLine + "locals:"; //$NON-NLS-1$ + for (int i = 0; i < localIndex; i++) + s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$ + s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$ + s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$ + s += newLine + "initializedField = " + initializedField; //$NON-NLS-1$ + s += newLine + "lastVisibleFieldID = " + lastVisibleFieldID; //$NON-NLS-1$ + s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$ + return s; +} + +/** + * Spec : 8.4.3 & 9.4 + */ +private void checkAndSetModifiersForConstructor(MethodBinding methodBinding) { + int modifiers = methodBinding.modifiers; + final ReferenceBinding declaringClass = methodBinding.declaringClass; + if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); + + if ((((ConstructorDeclaration) referenceContext).bits & ASTNode.IsDefaultConstructor) != 0) { + // certain flags are propagated from declaring class onto constructor + final int DECLARING_FLAGS = ClassFileConstants.AccEnum|ClassFileConstants.AccPublic|ClassFileConstants.AccProtected; + final int VISIBILITY_FLAGS = ClassFileConstants.AccPrivate|ClassFileConstants.AccPublic|ClassFileConstants.AccProtected; + int flags; + if ((flags = declaringClass.modifiers & DECLARING_FLAGS) != 0) { + if ((flags & ClassFileConstants.AccEnum) != 0) { + modifiers &= ~VISIBILITY_FLAGS; + modifiers |= ClassFileConstants.AccPrivate; // default constructor is implicitly private in enum + } else { + modifiers &= ~VISIBILITY_FLAGS; + modifiers |= flags; // propagate public/protected } } + } - // after this point, tests on the 16 bits reserved. - int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag; + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag; - // check for abnormal modifiers - final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected | ClassFileConstants.AccStrictfp); - if (declaringClass.isEnum() && (((ConstructorDeclaration) referenceContext).bits & ASTNode.IsDefaultConstructor) == 0) { - final int UNEXPECTED_ENUM_CONSTR_MODIFIERS = ~(ClassFileConstants.AccPrivate | ClassFileConstants.AccStrictfp); - if ((realModifiers & UNEXPECTED_ENUM_CONSTR_MODIFIERS) != 0) { - problemReporter().illegalModifierForEnumConstructor((AbstractMethodDeclaration) referenceContext); - modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_ENUM_CONSTR_MODIFIERS; - } else if ((((AbstractMethodDeclaration) referenceContext).modifiers & ClassFileConstants.AccStrictfp) != 0) { - // must check the parse node explicitly - problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext); - } - modifiers |= ClassFileConstants.AccPrivate; // enum constructor is implicitly private - } else if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) { - problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext); - modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_MODIFIERS; + // check for abnormal modifiers + final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected | ClassFileConstants.AccStrictfp); + if (declaringClass.isEnum() && (((ConstructorDeclaration) referenceContext).bits & ASTNode.IsDefaultConstructor) == 0) { + final int UNEXPECTED_ENUM_CONSTR_MODIFIERS = ~(ClassFileConstants.AccPrivate | ClassFileConstants.AccStrictfp); + if ((realModifiers & UNEXPECTED_ENUM_CONSTR_MODIFIERS) != 0) { + problemReporter().illegalModifierForEnumConstructor((AbstractMethodDeclaration) referenceContext); + modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_ENUM_CONSTR_MODIFIERS; } else if ((((AbstractMethodDeclaration) referenceContext).modifiers & ClassFileConstants.AccStrictfp) != 0) { // must check the parse node explicitly problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext); } - - // check for incompatible modifiers in the visibility bits, isolate the visibility bits - int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate); - if ((accessorBits & (accessorBits - 1)) != 0) { - problemReporter().illegalVisibilityModifierCombinationForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); - - // need to keep the less restrictive so disable Protected/Private as necessary - if ((accessorBits & ClassFileConstants.AccPublic) != 0) { - if ((accessorBits & ClassFileConstants.AccProtected) != 0) - modifiers &= ~ClassFileConstants.AccProtected; - if ((accessorBits & ClassFileConstants.AccPrivate) != 0) - modifiers &= ~ClassFileConstants.AccPrivate; - } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) { + modifiers |= ClassFileConstants.AccPrivate; // enum constructor is implicitly private + } else if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) { + problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext); + modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_MODIFIERS; + } else if ((((AbstractMethodDeclaration) referenceContext).modifiers & ClassFileConstants.AccStrictfp) != 0) { + // must check the parse node explicitly + problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext); + } + + // check for incompatible modifiers in the visibility bits, isolate the visibility bits + int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate); + if ((accessorBits & (accessorBits - 1)) != 0) { + problemReporter().illegalVisibilityModifierCombinationForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); + + // need to keep the less restrictive so disable Protected/Private as necessary + if ((accessorBits & ClassFileConstants.AccPublic) != 0) { + if ((accessorBits & ClassFileConstants.AccProtected) != 0) + modifiers &= ~ClassFileConstants.AccProtected; + if ((accessorBits & ClassFileConstants.AccPrivate) != 0) modifiers &= ~ClassFileConstants.AccPrivate; - } + } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) { + modifiers &= ~ClassFileConstants.AccPrivate; } + } // // if the receiver's declaring class is a private nested type, then make sure the receiver is not private (causes problems for inner type emulation) // if (declaringClass.isPrivate() && (modifiers & ClassFileConstants.AccPrivate) != 0) // modifiers &= ~ClassFileConstants.AccPrivate; - methodBinding.modifiers = modifiers; - } - - /* Spec : 8.4.3 & 9.4 - */ - private void checkAndSetModifiersForMethod(MethodBinding methodBinding) { - - int modifiers = methodBinding.modifiers; - final ReferenceBinding declaringClass = methodBinding.declaringClass; - if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0) - problemReporter().duplicateModifierForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); - - // after this point, tests on the 16 bits reserved. - int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag; - - // set the requested modifiers for a method in an interface/annotation - if (declaringClass.isInterface()) { - if ((realModifiers & ~(ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract)) != 0) { - if ((declaringClass.modifiers & ClassFileConstants.AccAnnotation) != 0) - problemReporter().illegalModifierForAnnotationMember((AbstractMethodDeclaration) referenceContext); - else - problemReporter().illegalModifierForInterfaceMethod((AbstractMethodDeclaration) referenceContext); - } - return; - } - - // check for abnormal modifiers - final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected - | ClassFileConstants.AccAbstract | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp); - if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) { - problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext); - modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_MODIFIERS; - } + methodBinding.modifiers = modifiers; +} - // check for incompatible modifiers in the visibility bits, isolate the visibility bits - int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate); - if ((accessorBits & (accessorBits - 1)) != 0) { - problemReporter().illegalVisibilityModifierCombinationForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); - - // need to keep the less restrictive so disable Protected/Private as necessary - if ((accessorBits & ClassFileConstants.AccPublic) != 0) { - if ((accessorBits & ClassFileConstants.AccProtected) != 0) - modifiers &= ~ClassFileConstants.AccProtected; - if ((accessorBits & ClassFileConstants.AccPrivate) != 0) - modifiers &= ~ClassFileConstants.AccPrivate; - } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) { +/** + * Spec : 8.4.3 & 9.4 + */ +private void checkAndSetModifiersForMethod(MethodBinding methodBinding) { + int modifiers = methodBinding.modifiers; + final ReferenceBinding declaringClass = methodBinding.declaringClass; + if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0) + problemReporter().duplicateModifierForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); + + // after this point, tests on the 16 bits reserved. + int realModifiers = modifiers & ExtraCompilerModifiers.AccJustFlag; + + // set the requested modifiers for a method in an interface/annotation + if (declaringClass.isInterface()) { + if ((realModifiers & ~(ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract)) != 0) { + if ((declaringClass.modifiers & ClassFileConstants.AccAnnotation) != 0) + problemReporter().illegalModifierForAnnotationMember((AbstractMethodDeclaration) referenceContext); + else + problemReporter().illegalModifierForInterfaceMethod((AbstractMethodDeclaration) referenceContext); + } + return; + } + + // check for abnormal modifiers + final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected + | ClassFileConstants.AccAbstract | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp); + if ((realModifiers & UNEXPECTED_MODIFIERS) != 0) { + problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) referenceContext); + modifiers &= ~ExtraCompilerModifiers.AccJustFlag | ~UNEXPECTED_MODIFIERS; + } + + // check for incompatible modifiers in the visibility bits, isolate the visibility bits + int accessorBits = realModifiers & (ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate); + if ((accessorBits & (accessorBits - 1)) != 0) { + problemReporter().illegalVisibilityModifierCombinationForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); + + // need to keep the less restrictive so disable Protected/Private as necessary + if ((accessorBits & ClassFileConstants.AccPublic) != 0) { + if ((accessorBits & ClassFileConstants.AccProtected) != 0) + modifiers &= ~ClassFileConstants.AccProtected; + if ((accessorBits & ClassFileConstants.AccPrivate) != 0) modifiers &= ~ClassFileConstants.AccPrivate; - } + } else if ((accessorBits & ClassFileConstants.AccProtected) != 0 && (accessorBits & ClassFileConstants.AccPrivate) != 0) { + modifiers &= ~ClassFileConstants.AccPrivate; } + } - // check for modifiers incompatible with abstract modifier - if ((modifiers & ClassFileConstants.AccAbstract) != 0) { - int incompatibleWithAbstract = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp; - if ((modifiers & incompatibleWithAbstract) != 0) - problemReporter().illegalAbstractModifierCombinationForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); - if (!methodBinding.declaringClass.isAbstract()) - problemReporter().abstractMethodInAbstractClass((SourceTypeBinding) declaringClass, (AbstractMethodDeclaration) referenceContext); - } - - /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final) - // methods from a final class are final : 8.4.3.3 - if (methodBinding.declaringClass.isFinal()) - modifiers |= AccFinal; - */ - // native methods cannot also be tagged as strictfp - if ((modifiers & ClassFileConstants.AccNative) != 0 && (modifiers & ClassFileConstants.AccStrictfp) != 0) - problemReporter().nativeMethodsCannotBeStrictfp(declaringClass, (AbstractMethodDeclaration) referenceContext); - - // static members are only authorized in a static member or top level type - if (((realModifiers & ClassFileConstants.AccStatic) != 0) && declaringClass.isNestedType() && !declaringClass.isStatic()) - problemReporter().unexpectedStaticModifierForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); - - methodBinding.modifiers = modifiers; + // check for modifiers incompatible with abstract modifier + if ((modifiers & ClassFileConstants.AccAbstract) != 0) { + int incompatibleWithAbstract = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccSynchronized | ClassFileConstants.AccNative | ClassFileConstants.AccStrictfp; + if ((modifiers & incompatibleWithAbstract) != 0) + problemReporter().illegalAbstractModifierCombinationForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); + if (!methodBinding.declaringClass.isAbstract()) + problemReporter().abstractMethodInAbstractClass((SourceTypeBinding) declaringClass, (AbstractMethodDeclaration) referenceContext); } - - /* Compute variable positions in scopes given an initial position offset - * ignoring unused local variables. - * - * Deal with arguments here, locals and subscopes are processed in BlockScope method - */ - public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) { - - boolean isReportingUnusedArgument = false; - - if (referenceContext instanceof AbstractMethodDeclaration) { - AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext; - MethodBinding method = methodDecl.binding; - if (!(method.isAbstract() - || (method.isImplementing() && !compilerOptions().reportUnusedParameterWhenImplementingAbstract) - || (method.isOverriding() && !method.isImplementing() && !compilerOptions().reportUnusedParameterWhenOverridingConcrete) - || method.isMain())) { - isReportingUnusedArgument = true; - } + + /* DISABLED for backward compatibility with javac (if enabled should also mark private methods as final) + // methods from a final class are final : 8.4.3.3 + if (methodBinding.declaringClass.isFinal()) + modifiers |= AccFinal; + */ + // native methods cannot also be tagged as strictfp + if ((modifiers & ClassFileConstants.AccNative) != 0 && (modifiers & ClassFileConstants.AccStrictfp) != 0) + problemReporter().nativeMethodsCannotBeStrictfp(declaringClass, (AbstractMethodDeclaration) referenceContext); + + // static members are only authorized in a static member or top level type + if (((realModifiers & ClassFileConstants.AccStatic) != 0) && declaringClass.isNestedType() && !declaringClass.isStatic()) + problemReporter().unexpectedStaticModifierForMethod(declaringClass, (AbstractMethodDeclaration) referenceContext); + + methodBinding.modifiers = modifiers; +} + +/** + * Compute variable positions in scopes given an initial position offset + * ignoring unused local variables. + * + * Deal with arguments here, locals and subscopes are processed in BlockScope method + */ +public void computeLocalVariablePositions(int initOffset, CodeStream codeStream) { + + boolean isReportingUnusedArgument = false; + + if (referenceContext instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration)referenceContext; + MethodBinding method = methodDecl.binding; + if (!(method.isAbstract() + || (method.isImplementing() && !compilerOptions().reportUnusedParameterWhenImplementingAbstract) + || (method.isOverriding() && !method.isImplementing() && !compilerOptions().reportUnusedParameterWhenOverridingConcrete) + || method.isMain())) { + isReportingUnusedArgument = true; } - this.offset = initOffset; - this.maxOffset = initOffset; + } + this.offset = initOffset; + this.maxOffset = initOffset; - // manage arguments - int ilocal = 0, maxLocals = this.localIndex; - while (ilocal < maxLocals) { - LocalVariableBinding local = locals[ilocal]; - if (local == null || ((local.tagBits & TagBits.IsArgument) == 0)) break; // done with arguments - - // do not report fake used variable - if (isReportingUnusedArgument - && local.useFlag == LocalVariableBinding.UNUSED - && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0)) { // declaration is reachable - this.problemReporter().unusedArgument(local.declaration); - } + // manage arguments + int ilocal = 0, maxLocals = this.localIndex; + while (ilocal < maxLocals) { + LocalVariableBinding local = locals[ilocal]; + if (local == null || ((local.tagBits & TagBits.IsArgument) == 0)) break; // done with arguments + + // do not report fake used variable + if (isReportingUnusedArgument + && local.useFlag == LocalVariableBinding.UNUSED + && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0)) { // declaration is reachable + this.problemReporter().unusedArgument(local.declaration); + } - // record user-defined argument for attribute generation - codeStream.record(local); + // record user-defined argument for attribute generation + codeStream.record(local); - // assign variable position - local.resolvedPosition = this.offset; + // assign variable position + local.resolvedPosition = this.offset; - if ((local.type == TypeBinding.LONG) || (local.type == TypeBinding.DOUBLE)) { + if ((local.type == TypeBinding.LONG) || (local.type == TypeBinding.DOUBLE)) { + this.offset += 2; + } else { + this.offset++; + } + // check for too many arguments/local variables + if (this.offset > 0xFF) { // no more than 255 words of arguments + this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration); + } + ilocal++; + } + + // sneak in extra argument before other local variables + if (extraSyntheticArguments != null) { + for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){ + SyntheticArgumentBinding argument = extraSyntheticArguments[iarg]; + argument.resolvedPosition = this.offset; + if ((argument.type == TypeBinding.LONG) || (argument.type == TypeBinding.DOUBLE)){ this.offset += 2; } else { this.offset++; } - // check for too many arguments/local variables if (this.offset > 0xFF) { // no more than 255 words of arguments - this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration); + this.problemReporter().noMoreAvailableSpaceForArgument(argument, (ASTNode)this.referenceContext); } - ilocal++; } - - // sneak in extra argument before other local variables - if (extraSyntheticArguments != null) { - for (int iarg = 0, maxArguments = extraSyntheticArguments.length; iarg < maxArguments; iarg++){ - SyntheticArgumentBinding argument = extraSyntheticArguments[iarg]; - argument.resolvedPosition = this.offset; - if ((argument.type == TypeBinding.LONG) || (argument.type == TypeBinding.DOUBLE)){ - this.offset += 2; - } else { - this.offset++; - } - if (this.offset > 0xFF) { // no more than 255 words of arguments - this.problemReporter().noMoreAvailableSpaceForArgument(argument, (ASTNode)this.referenceContext); - } - } - } - this.computeLocalVariablePositions(ilocal, this.offset, codeStream); } + this.computeLocalVariablePositions(ilocal, this.offset, codeStream); +} - /* Error management: - * keep null for all the errors that prevent the method to be created - * otherwise return a correct method binding (but without the element - * that caused the problem) : ie : Incorrect thrown exception - */ - MethodBinding createMethod(AbstractMethodDeclaration method) { - - // is necessary to ensure error reporting - this.referenceContext = method; - method.scope = this; - SourceTypeBinding declaringClass = referenceType().binding; - int modifiers = method.modifiers | ExtraCompilerModifiers.AccUnresolved; - if (method.isConstructor()) { - if (method.isDefaultConstructor()) - modifiers |= ExtraCompilerModifiers.AccIsDefaultConstructor; - method.binding = new MethodBinding(modifiers, null, null, declaringClass); - checkAndSetModifiersForConstructor(method.binding); - } else { - if (declaringClass.isInterface()) // interface or annotation type - modifiers |= ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract; - method.binding = - new MethodBinding(modifiers, method.selector, null, null, null, declaringClass); - checkAndSetModifiersForMethod(method.binding); - } - this.isStatic = method.binding.isStatic(); - - Argument[] argTypes = method.arguments; - int argLength = argTypes == null ? 0 : argTypes.length; - if (argLength > 0 && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { - if (argTypes[--argLength].isVarArgs()) - method.binding.modifiers |= ClassFileConstants.AccVarargs; - while (--argLength >= 0) { - if (argTypes[argLength].isVarArgs()) - problemReporter().illegalVararg(argTypes[argLength], method); - } - } - - TypeParameter[] typeParameters = method.typeParameters(); - // do not construct type variables if source < 1.5 - if (typeParameters == null || compilerOptions().sourceLevel < ClassFileConstants.JDK1_5) { - method.binding.typeVariables = Binding.NO_TYPE_VARIABLES; - } else { - method.binding.typeVariables = createTypeVariables(typeParameters, method.binding); - method.binding.modifiers |= ExtraCompilerModifiers.AccGenericSignature; +/** + * Error management: + * keep null for all the errors that prevent the method to be created + * otherwise return a correct method binding (but without the element + * that caused the problem) : ie : Incorrect thrown exception + */ +MethodBinding createMethod(AbstractMethodDeclaration method) { + // is necessary to ensure error reporting + this.referenceContext = method; + method.scope = this; + SourceTypeBinding declaringClass = referenceType().binding; + int modifiers = method.modifiers | ExtraCompilerModifiers.AccUnresolved; + if (method.isConstructor()) { + if (method.isDefaultConstructor()) + modifiers |= ExtraCompilerModifiers.AccIsDefaultConstructor; + method.binding = new MethodBinding(modifiers, null, null, declaringClass); + checkAndSetModifiersForConstructor(method.binding); + } else { + if (declaringClass.isInterface()) // interface or annotation type + modifiers |= ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract; + method.binding = + new MethodBinding(modifiers, method.selector, null, null, null, declaringClass); + checkAndSetModifiersForMethod(method.binding); + } + this.isStatic = method.binding.isStatic(); + + Argument[] argTypes = method.arguments; + int argLength = argTypes == null ? 0 : argTypes.length; + if (argLength > 0 && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { + if (argTypes[--argLength].isVarArgs()) + method.binding.modifiers |= ClassFileConstants.AccVarargs; + while (--argLength >= 0) { + if (argTypes[argLength].isVarArgs()) + problemReporter().illegalVararg(argTypes[argLength], method); } - return method.binding; } - - /* Overridden to detect the error case inside an explicit constructor call: - class X { - int i; - X myX; - X(X x) { - this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors - } + TypeParameter[] typeParameters = method.typeParameters(); + // do not construct type variables if source < 1.5 + if (typeParameters == null || compilerOptions().sourceLevel < ClassFileConstants.JDK1_5) { + method.binding.typeVariables = Binding.NO_TYPE_VARIABLES; + } else { + method.binding.typeVariables = createTypeVariables(typeParameters, method.binding); + method.binding.modifiers |= ExtraCompilerModifiers.AccGenericSignature; } - */ - public FieldBinding findField( - TypeBinding receiverType, - char[] fieldName, - InvocationSite invocationSite, - boolean needResolve) { - - FieldBinding field = super.findField(receiverType, fieldName, invocationSite, needResolve); - if (field == null) - return null; - if (!field.isValidBinding()) - return field; // answer the error field - if (field.isStatic()) - return field; // static fields are always accessible + return method.binding; +} - if (!isConstructorCall || receiverType != enclosingSourceType()) - return field; +/** + * Overridden to detect the error case inside an explicit constructor call: +class X { + int i; + X myX; + X(X x) { + this(i, myX.i, x.i); // same for super calls... only the first 2 field accesses are errors + } +} + */ +public FieldBinding findField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite, boolean needResolve) { + + FieldBinding field = super.findField(receiverType, fieldName, invocationSite, needResolve); + if (field == null) + return null; + if (!field.isValidBinding()) + return field; // answer the error field + if (field.isStatic()) + return field; // static fields are always accessible + + if (!isConstructorCall || receiverType != enclosingSourceType()) + return field; - if (invocationSite instanceof SingleNameReference) + if (invocationSite instanceof SingleNameReference) + return new ProblemFieldBinding( + field, // closest match + field.declaringClass, + fieldName, + ProblemReasons.NonStaticReferenceInConstructorInvocation); + if (invocationSite instanceof QualifiedNameReference) { + // look to see if the field is the first binding + QualifiedNameReference name = (QualifiedNameReference) invocationSite; + if (name.binding == null) + // only true when the field is the fieldbinding at the beginning of name's tokens return new ProblemFieldBinding( field, // closest match field.declaringClass, fieldName, ProblemReasons.NonStaticReferenceInConstructorInvocation); - if (invocationSite instanceof QualifiedNameReference) { - // look to see if the field is the first binding - QualifiedNameReference name = (QualifiedNameReference) invocationSite; - if (name.binding == null) - // only true when the field is the fieldbinding at the beginning of name's tokens - return new ProblemFieldBinding( - field, // closest match - field.declaringClass, - fieldName, - ProblemReasons.NonStaticReferenceInConstructorInvocation); - } - return field; - } - - public boolean isInsideConstructor() { - - return (referenceContext instanceof ConstructorDeclaration); - } - - public boolean isInsideInitializer() { - - return (referenceContext instanceof TypeDeclaration); } + return field; +} - public boolean isInsideInitializerOrConstructor() { +public boolean isInsideConstructor() { + return (referenceContext instanceof ConstructorDeclaration); +} - return (referenceContext instanceof TypeDeclaration) - || (referenceContext instanceof ConstructorDeclaration); - } +public boolean isInsideInitializer() { + return (referenceContext instanceof TypeDeclaration); +} - /* Answer the problem reporter to use for raising new problems. - * - * Note that as a side-effect, this updates the current reference context - * (unit, type or method) in case the problem handler decides it is necessary - * to abort. - */ - public ProblemReporter problemReporter() { +public boolean isInsideInitializerOrConstructor() { + return (referenceContext instanceof TypeDeclaration) + || (referenceContext instanceof ConstructorDeclaration); +} - MethodScope outerMethodScope; - if ((outerMethodScope = outerMostMethodScope()) == this) { - ProblemReporter problemReporter = referenceCompilationUnit().problemReporter; - problemReporter.referenceContext = referenceContext; - return problemReporter; - } - return outerMethodScope.problemReporter(); +/** + * Answer the problem reporter to use for raising new problems. + * + * Note that as a side-effect, this updates the current reference context + * (unit, type or method) in case the problem handler decides it is necessary + * to abort. + */ +public ProblemReporter problemReporter() { + MethodScope outerMethodScope; + if ((outerMethodScope = outerMostMethodScope()) == this) { + ProblemReporter problemReporter = referenceCompilationUnit().problemReporter; + problemReporter.referenceContext = referenceContext; + return problemReporter; } + return outerMethodScope.problemReporter(); +} - public final int recordInitializationStates(FlowInfo flowInfo) { - - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return -1; - - UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInitsWithoutSideEffect(); - long[] extraInits = unconditionalFlowInfo.extra == null ? - null : unconditionalFlowInfo.extra[0]; - long inits = unconditionalFlowInfo.definiteInits; - checkNextEntry : for (int i = lastIndex; --i >= 0;) { - if (definiteInits[i] == inits) { - long[] otherInits = extraDefiniteInits[i]; - if ((extraInits != null) && (otherInits != null)) { - if (extraInits.length == otherInits.length) { - int j, max; - for (j = 0, max = extraInits.length; j < max; j++) { - if (extraInits[j] != otherInits[j]) { - continue checkNextEntry; - } +public final int recordInitializationStates(FlowInfo flowInfo) { + if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return -1; + UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInitsWithoutSideEffect(); + long[] extraInits = unconditionalFlowInfo.extra == null ? + null : unconditionalFlowInfo.extra[0]; + long inits = unconditionalFlowInfo.definiteInits; + checkNextEntry : for (int i = lastIndex; --i >= 0;) { + if (definiteInits[i] == inits) { + long[] otherInits = extraDefiniteInits[i]; + if ((extraInits != null) && (otherInits != null)) { + if (extraInits.length == otherInits.length) { + int j, max; + for (j = 0, max = extraInits.length; j < max; j++) { + if (extraInits[j] != otherInits[j]) { + continue checkNextEntry; } - return i; - } - } else { - if ((extraInits == null) && (otherInits == null)) { - return i; } + return i; + } + } else { + if ((extraInits == null) && (otherInits == null)) { + return i; } } } - - // add a new entry - if (definiteInits.length == lastIndex) { - // need a resize - System.arraycopy( - definiteInits, - 0, - (definiteInits = new long[lastIndex + 20]), - 0, - lastIndex); - System.arraycopy( - extraDefiniteInits, - 0, - (extraDefiniteInits = new long[lastIndex + 20][]), - 0, - lastIndex); - } - definiteInits[lastIndex] = inits; - if (extraInits != null) { - extraDefiniteInits[lastIndex] = new long[extraInits.length]; - System.arraycopy( - extraInits, - 0, - extraDefiniteInits[lastIndex], - 0, - extraInits.length); - } - return lastIndex++; - } - - /* Answer the reference method of this scope, or null if initialization scoope. - */ - public AbstractMethodDeclaration referenceMethod() { - - if (referenceContext instanceof AbstractMethodDeclaration) return (AbstractMethodDeclaration) referenceContext; - return null; } - /* Answer the reference type of this scope. - * - * It is the nearest enclosing type of this scope. - */ - public TypeDeclaration referenceType() { - - return ((ClassScope) parent).referenceContext; + // add a new entry + if (definiteInits.length == lastIndex) { + // need a resize + System.arraycopy( + definiteInits, + 0, + (definiteInits = new long[lastIndex + 20]), + 0, + lastIndex); + System.arraycopy( + extraDefiniteInits, + 0, + (extraDefiniteInits = new long[lastIndex + 20][]), + 0, + lastIndex); + } + definiteInits[lastIndex] = inits; + if (extraInits != null) { + extraDefiniteInits[lastIndex] = new long[extraInits.length]; + System.arraycopy( + extraInits, + 0, + extraDefiniteInits[lastIndex], + 0, + extraInits.length); } + return lastIndex++; +} - String basicToString(int tab) { - - String newLine = "\n"; //$NON-NLS-1$ - for (int i = tab; --i >= 0;) - newLine += "\t"; //$NON-NLS-1$ - - String s = newLine + "--- Method Scope ---"; //$NON-NLS-1$ - newLine += "\t"; //$NON-NLS-1$ - s += newLine + "locals:"; //$NON-NLS-1$ - for (int i = 0; i < localIndex; i++) - s += newLine + "\t" + locals[i].toString(); //$NON-NLS-1$ - s += newLine + "startIndex = " + startIndex; //$NON-NLS-1$ - s += newLine + "isConstructorCall = " + isConstructorCall; //$NON-NLS-1$ - s += newLine + "initializedField = " + initializedField; //$NON-NLS-1$ - s += newLine + "lastVisibleFieldID = " + lastVisibleFieldID; //$NON-NLS-1$ - s += newLine + "referenceContext = " + referenceContext; //$NON-NLS-1$ - return s; - } +/** + * Answer the reference method of this scope, or null if initialization scoope. + */ +public AbstractMethodDeclaration referenceMethod() { + if (referenceContext instanceof AbstractMethodDeclaration) return (AbstractMethodDeclaration) referenceContext; + return null; +} +/** + * Answer the reference type of this scope. + * It is the nearest enclosing type of this scope. + */ +public TypeDeclaration referenceType() { + return ((ClassScope) parent).referenceContext; +} } Index: compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java,v retrieving revision 1.106 diff -u -r1.106 BlockScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 6 Mar 2007 02:38:50 -0000 1.106 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 13 Sep 2007 08:49:47 -0000 @@ -111,8 +111,8 @@ this.subscopes[this.subscopeCount++] = childScope; } -/* Answer true if the receiver is suitable for assigning final blank fields. - * +/** + * Answer true if the receiver is suitable for assigning final blank fields. * in other words, it is inside an initializer, a constructor or a clinit */ public final boolean allowBlankFinalFieldAssignment(FieldBinding binding) { @@ -125,6 +125,7 @@ return methodScope.isInsideInitializer() // inside initializer || ((AbstractMethodDeclaration) methodScope.referenceContext).isInitializationMethod(); // inside constructor or clinit } + String basicToString(int tab) { String newLine = "\n"; //$NON-NLS-1$ for (int i = tab; --i >= 0;) @@ -822,6 +823,30 @@ return max; } +/** + * Returns true if the context requires to check initialization of final blank fields. + * in other words, it is inside an initializer, a constructor or a clinit + */ +public final boolean needBlankFinalFieldInitializationCheck(FieldBinding binding) { + boolean isStatic = binding.isStatic(); + ReferenceBinding fieldDeclaringClass = binding.declaringClass; + // loop in enclosing context, until reaching the field declaring context + MethodScope methodScope = methodScope(); + while (methodScope != null) { + if (methodScope.isStatic != isStatic) + return false; + if (!methodScope.isInsideInitializer() // inside initializer + && !((AbstractMethodDeclaration) methodScope.referenceContext).isInitializationMethod()) { // inside constructor or clinit + return false; // found some non-initializer context + } + if (fieldDeclaringClass == methodScope.enclosingReceiverType()) { + return true; // found the field context, no need to check any further + } + methodScope = methodScope.enclosingMethodScope(); + } + return false; +} + /* Answer the problem reporter to use for raising new problems. * * Note that as a side-effect, this updates the current reference context Index: eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java,v retrieving revision 1.47 diff -u -r1.47 CodeSnippetSingleNameReference.java --- eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java 29 Mar 2006 02:57:52 -0000 1.47 +++ eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java 13 Sep 2007 08:49:47 -0000 @@ -56,7 +56,7 @@ // check if reading a final blank field FieldBinding fieldBinding; if ((fieldBinding = (FieldBinding) this.binding).isBlankFinal() - && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { + && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { if (!flowInfo.isDefinitelyAssigned(fieldBinding)) { currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); } #P org.eclipse.jdt.core.tests Index: Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java =================================================================== RCS file: /home/cvs/numbat/org.eclipse.jdt.core.tests/Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java,v retrieving revision 1.106 diff -u -r1.106 InitializationTest.java --- Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java 15 Mar 2007 14:04:34 -0000 1.106 +++ Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java 13 Sep 2007 08:49:51 -0000 @@ -5473,6 +5473,154 @@ assertTrue(false); } } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=203061 +public void test192() { + this.runNegativeTest( + new String[] { + "X.java", + "public final class X {\n" + + " private final Object mObj;\n" + + " private final Object mDependent = new Object() {\n" + + " {\n" + + " Object o1 = mObj;\n" + + " }\n" + + " Object o2 = mObj;\n" + + " void foo() {\n" + + " Object o3 = mObj;\n" + + " }\n" + + " };\n" + + " public X() {\n" + + " mObj = \"\";\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " private final Object mDependent = new Object() {\n" + + " ^^^^^^^^^^\n" + + "The field X.mDependent is never read locally\n" + + "----------\n" + + "2. WARNING in X.java (at line 5)\n" + + " Object o1 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "3. ERROR in X.java (at line 5)\n" + + " Object o1 = mObj;\n" + + " ^^^^\n" + + "The blank final field mObj may not have been initialized\n" + + "----------\n" + + "4. WARNING in X.java (at line 7)\n" + + " Object o2 = mObj;\n" + + " ^^\n" + + "The field new Object(){}.o2 is never read locally\n" + + "----------\n" + + "5. WARNING in X.java (at line 7)\n" + + " Object o2 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "6. ERROR in X.java (at line 7)\n" + + " Object o2 = mObj;\n" + + " ^^^^\n" + + "The blank final field mObj may not have been initialized\n" + + "----------\n" + + "7. WARNING in X.java (at line 8)\n" + + " void foo() {\n" + + " ^^^^^\n" + + "The method foo() from the type new Object(){} is never used locally\n" + + "----------\n" + + "8. WARNING in X.java (at line 9)\n" + + " Object o3 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n"); +} +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=203061 - variation +public void test193() { + this.runNegativeTest( + new String[] { + "X.java", + "public final class X {\n" + + " private final Object mObj;\n" + + " private final Object mDependent = new Object() {\n" + + " {\n" + + " Object o1 = mObj;\n" + + " mObj = \"1\";\n" + + " }\n" + + " Object o2 = mObj = \"2\";\n" + + " void foo() {\n" + + " Object o3 = mObj;\n" + + " mObj = \"3\";\n" + + " }\n" + + " };\n" + + " public X() {\n" + + " mObj = \"\";\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " private final Object mDependent = new Object() {\n" + + " ^^^^^^^^^^\n" + + "The field X.mDependent is never read locally\n" + + "----------\n" + + "2. WARNING in X.java (at line 5)\n" + + " Object o1 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "3. ERROR in X.java (at line 5)\n" + + " Object o1 = mObj;\n" + + " ^^^^\n" + + "The blank final field mObj may not have been initialized\n" + + "----------\n" + + "4. WARNING in X.java (at line 6)\n" + + " mObj = \"1\";\n" + + " ^^^^\n" + + "Write access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "5. ERROR in X.java (at line 6)\n" + + " mObj = \"1\";\n" + + " ^^^^\n" + + "The final field X.mObj cannot be assigned\n" + + "----------\n" + + "6. WARNING in X.java (at line 8)\n" + + " Object o2 = mObj = \"2\";\n" + + " ^^\n" + + "The field new Object(){}.o2 is never read locally\n" + + "----------\n" + + "7. WARNING in X.java (at line 8)\n" + + " Object o2 = mObj = \"2\";\n" + + " ^^^^\n" + + "Write access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "8. ERROR in X.java (at line 8)\n" + + " Object o2 = mObj = \"2\";\n" + + " ^^^^\n" + + "The final field X.mObj cannot be assigned\n" + + "----------\n" + + "9. WARNING in X.java (at line 9)\n" + + " void foo() {\n" + + " ^^^^^\n" + + "The method foo() from the type new Object(){} is never used locally\n" + + "----------\n" + + "10. WARNING in X.java (at line 10)\n" + + " Object o3 = mObj;\n" + + " ^^^^\n" + + "Read access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "11. WARNING in X.java (at line 11)\n" + + " mObj = \"3\";\n" + + " ^^^^\n" + + "Write access to enclosing field X.mObj is emulated by a synthetic accessor method. Increasing its visibility will improve your performance\n" + + "----------\n" + + "12. ERROR in X.java (at line 11)\n" + + " mObj = \"3\";\n" + + " ^^^^\n" + + "The final field X.mObj cannot be assigned\n" + + "----------\n"); +} public static Class testClass() { return InitializationTest.class; }