From 1f1a67672efebc390717e595625d6d7b6a46ddca Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Sun, 7 Oct 2012 14:19:20 +0200 Subject: Bug 382188 - NPE in copyRole() when commenting out roles in a nested team / role file - immediate: ensure roles found during complete type bindings are connected, too - secondary: teams w/o a super team always need reflection methods (was regression in OTReconcilerTests.testRoFiNestedTeam) --- .../compiler/lookup/LookupEnvironment.java | 32 +++++++++- .../core/compiler/control/Dependencies.java | 6 +- .../core/compiler/lifting/LiftingEnvironment.java | 10 +-- .../transformer/ReflectionGenerator.java | 12 +++- .../otdt/tests/otmodel/OTReconcilerTests.java | 71 +++++++++++++++++++++- 5 files changed, 117 insertions(+), 14 deletions(-) diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java index b648c490c..04818d3c1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -42,6 +42,7 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.control.StateHelper; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor; import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding; +import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel; import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.TeamMethodGenerator; import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstEdit; import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleFileHelper; @@ -351,9 +352,10 @@ public void completeTypeBindings(CompilationUnitDeclaration parsedUnit) { Dependencies.ensureState(parsedUnit, getDependenciesStateCompleted()); } // for use by Dependiencies only: -public void internalCompleteTypeBindings(CompilationUnitDeclaration parsedUnit) { +public int internalCompleteTypeBindings(CompilationUnitDeclaration parsedUnit) { if (this.unitBeingCompleted == parsedUnit) - return; // avoid re-entrance + return 0; // avoid re-entrance + int todo = this.stepCompleted; //SH} if (this.stepCompleted == BUILD_FIELDS_AND_METHODS) { // This can only happen because the original set of units are completely built and @@ -361,16 +363,42 @@ public void internalCompleteTypeBindings(CompilationUnitDeclaration parsedUnit) // until they too are completely processed. completeTypeBindings(); } else { +//{ObjectTeams: + // add return value: +/* orig: if (parsedUnit.scope == null) return; // parsing errors were too severe + :giro */ + if (parsedUnit.scope == null) return 0; // parsing errors were too severe + // request step from encl. team? + if (parsedUnit.isRoleUnit()) { // this implies types[0] exists + SourceTypeBinding roleBinding = parsedUnit.types[0].binding; + if (roleBinding != null) { + ReferenceBinding enclosingType = roleBinding.enclosingType(); + if (enclosingType != null) { + TeamModel enclosingTeam = enclosingType.getTeamModel(); + if ( enclosingTeam != null + && enclosingTeam._state.getProcessingState() == ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY) + todo = CONNECT_TYPE_HIERARCHY; + } + } + } +// orig: if (this.stepCompleted >= CHECK_AND_SET_IMPORTS) (this.unitBeingCompleted = parsedUnit).scope.checkAndSetImports(); +/* if (this.stepCompleted >= CONNECT_TYPE_HIERARCHY) + :giro */ + if (todo >= CONNECT_TYPE_HIERARCHY) +// SH} (this.unitBeingCompleted = parsedUnit).scope.connectTypeHierarchy(); this.unitBeingCompleted = null; } +//{ObjectTeams: report actual step achieved: + return todo; +// SH} } /* diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java index f5c6f6a93..73fe3b4b8 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/Dependencies.java @@ -66,6 +66,7 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel; import org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel; import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.copyinheritance.CopyInheritance; import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.RecordLocalTypesVisitor; +import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.ReflectionGenerator; import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.RoleSplitter; import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.StandardElementGenerator; import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.TransformStatementsVisitor; @@ -307,8 +308,7 @@ public class Dependencies implements ITranslationStates { checkReadKnownRoles(unit); LookupEnvironment lookupEnvironment= Config.getLookupEnvironment(); if (Config.getBundledCompleteTypeBindingsMode()) { - Config.getLookupEnvironment().internalCompleteTypeBindings(unit); - int stateReached = lookupEnvironment.getDependenciesStateCompleted(); + int stateReached = Config.getLookupEnvironment().internalCompleteTypeBindings(unit); StateHelper.setStateRecursive(unit, stateReached, true); if (stateReached >= state) return new Pair(done, @@ -1458,6 +1458,8 @@ public class Dependencies implements ITranslationStates { roleModel.setState(STATE_FULL_LIFTING); } else { // nothing to do for binary types and role-less teams. + if (teamDeclaration != null && ReflectionGenerator.needToImplementITeamMethods(teamDeclaration)) + ReflectionGenerator.createRoleQueryMethods(teamDeclaration); // need to implement methods from ITeam model.setState(STATE_FULL_LIFTING); model.setMemberState(STATE_FULL_LIFTING); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/LiftingEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/LiftingEnvironment.java index 79b17aaf3..74cd461e9 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/LiftingEnvironment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/lifting/LiftingEnvironment.java @@ -67,7 +67,6 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transfor import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstConverter; import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstEdit; import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator; -import org.eclipse.objectteams.otdt.internal.core.compiler.util.Protections; import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer; /** @@ -154,11 +153,8 @@ public class LiftingEnvironment public void createLiftingInfrastructure(RoleModel lateRole, boolean needMethodBodies) { TreeNode[] boundRoles = getBoundRoles(); if ((boundRoles == null) || (boundRoles.length == 0)) { - if ( lateRole == null - && needMethodBodies - && !TypeAnalyzer.isOrgObjectteamsTeam(this._teamType.binding) - && !Protections.hasClassKindProblem(this._teamType.binding)) - ReflectionGenerator.createRoleQueryMethods(this._teamType); + if (lateRole == null && needMethodBodies) + ReflectionGenerator.createRoleQueryMethods(this._teamType); return; } @@ -190,7 +186,7 @@ public class LiftingEnvironment if (lateRole == null) { generateRoleCaches(this._teamType); // TODO(SH): split into decl and statements (see fillGeneratedMethods()). - if (needMethodBodies && !Protections.hasClassKindProblem(this._teamType.binding)) + if (needMethodBodies) ReflectionGenerator.createRoleQueryMethods(this._teamType); } else { // isTopBound? diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java index bcc962382..93b8b475f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/ReflectionGenerator.java @@ -53,6 +53,7 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstClone; import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstConverter; import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstEdit; import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator; +import org.eclipse.objectteams.otdt.internal.core.compiler.util.Protections; import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer; /** @@ -124,6 +125,9 @@ public class ReflectionGenerator implements IOTConstants, ClassFileConstants { */ public static void createRoleQueryMethods(TypeDeclaration teamDecl) { + if ( TypeAnalyzer.isOrgObjectteamsTeam(teamDecl.binding) + || Protections.hasClassKindProblem(teamDecl.binding)) + return; long sourceLevel = teamDecl.scope.compilerOptions().sourceLevel; AstGenerator gen = new AstGenerator(sourceLevel, teamDecl.sourceStart, teamDecl.sourceEnd); AstGenerator gen2 = gen; @@ -305,8 +309,7 @@ public class ReflectionGenerator implements IOTConstants, ClassFileConstants { getAStats2[g2++] = createFilterValues(gen); else getAStats2[g2++] = createThrowNoSuchRole(gen); // no caches to search - boolean needsAllMethods = !TypeAnalyzer.isOrgObjectteamsTeam(teamDecl.binding) - && !teamDecl.binding.superclass().isTeam(); + boolean needsAllMethods = needToImplementITeamMethods(teamDecl); if (h1 > 0 || needsAllMethods) { System.arraycopy( hasStats1, 0, @@ -379,6 +382,11 @@ public class ReflectionGenerator implements IOTConstants, ClassFileConstants { } } + public static boolean needToImplementITeamMethods(TypeDeclaration teamDecl) { + return !TypeAnalyzer.isOrgObjectteamsTeam(teamDecl.binding) + && !teamDecl.binding.superclass().isTeam(); + } + private static Expression createMTList(AstGenerator gen, TypeBinding elemBinding) { return gen.allocation( gen.sourceLevel >= ClassFileConstants.JDK1_5 ? diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/model/org/eclipse/objectteams/otdt/tests/otmodel/OTReconcilerTests.java b/testplugins/org.eclipse.objectteams.otdt.tests/model/org/eclipse/objectteams/otdt/tests/otmodel/OTReconcilerTests.java index 6576def14..6d2993c44 100644 --- a/testplugins/org.eclipse.objectteams.otdt.tests/model/org/eclipse/objectteams/otdt/tests/otmodel/OTReconcilerTests.java +++ b/testplugins/org.eclipse.objectteams.otdt.tests/model/org/eclipse/objectteams/otdt/tests/otmodel/OTReconcilerTests.java @@ -30,6 +30,7 @@ import junit.framework.Test; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Platform; @@ -89,7 +90,7 @@ public class OTReconcilerTests extends ReconcilerTests { } static { -// TESTS_NAMES = new String[] { "testPlainJava_SyntaxError" }; +// TESTS_NAMES = new String[] { "testEmptyNestedExternalTeam" }; } // ===== Copied all our modifications from AbstractJavaModelTests ===== /* @@ -1562,4 +1563,72 @@ public class OTReconcilerTests extends ReconcilerTests { } } + // Bug 382188 - NPE in copyRole() when commenting out roles in a nested + public void testEmptyNestedExternalTeam() throws CoreException, InterruptedException { + try { + // Resources creation + IJavaProject p = createOTJavaProject("P", new String[] {""}, new String[] {"JCL15_LIB"}, "bin"); + IProject project = p.getProject(); + IProjectDescription prjDesc = project.getDescription(); + prjDesc.setBuildSpec(OTDTPlugin.createProjectBuildCommands(prjDesc)); + project.setDescription(prjDesc, null); + p.setOption(JavaCore.COMPILER_PB_UNUSED_LOCAL, JavaCore.IGNORE); + + OTREContainer.initializeOTJProject(project); + + this.createFolder("/P/p"); + + String superTeamSourceString = + "package p;\n" + + "public team class SuperTeam {\n" + + "}\n"; + this.createFile( + "/P/p/SuperTeam.java", + superTeamSourceString); + + String superMidString = + "team package p.SuperTeam;\n" + + "protected team class Mid {\n" + + " protected class Inner {}\n" + + "}\n"; + this.createFolder( + "/P/p/SuperTeam"); + this.createFile( + "/P/p/SuperTeam/Mid.java", + superMidString); + + String subTeamSourceString = + "package p;\n" + + "public team class SubTeam extends SuperTeam {\n" + + " protected class Mid2 {}\n" + + "}\n"; + this.createFile( + "/P/p/SubTeam.java", + subTeamSourceString); + + this.createFolder( + "/P/p/SubTeam"); + String subMidCompleteSourceString = + "team package p/SubTeam;\n" + + "protected team class Mid {\n" + + " protected class Inner {}\n" + + "}\n"; + this.createFile("/P/p/SubTeam/Mid.java", subMidCompleteSourceString); + + project.build(IncrementalProjectBuilder.FULL_BUILD, null); + + String subMidSourceString = + "team package p.SubTeam;\n" + + "protected team class Mid {\n" + + "}\n"; + + char[] subMidSourceChars = subMidSourceString.toCharArray(); + this.problemRequestor.initialize(subMidSourceChars); + + ICompilationUnit icu = getCompilationUnit("/P/p/SubTeam/Mid.java").getWorkingCopy(this.wcOwner, null); + assertNoProblem(subMidSourceChars, icu); + } finally { + deleteProject("P"); + } + } } -- cgit v1.2.3