Bug 400360 - [reconciler] fails to resolve callout-to-field with
path-anchored type
Solution: include necessary STATE_ROLES_LINKED into mngmt by lookupEnv
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 04818d3..08976f6 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
@@ -43,6 +43,7 @@
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.RoleSplitter;
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;
@@ -141,6 +142,9 @@
final static int BUILD_TYPE_HIERARCHY = 1;
final static int CHECK_AND_SET_IMPORTS = 2;
final static int CONNECT_TYPE_HIERARCHY = 3;
+//{ObjectTeams: include this step into LookupEnvironment's control:
+ final static int ROLES_LINKED = 5;
+// SH}
static final ProblemPackageBinding TheNotFoundPackage = new ProblemPackageBinding(CharOperation.NO_CHAR, NotFound);
static final ProblemReferenceBinding TheNotFoundType = new ProblemReferenceBinding(CharOperation.NO_CHAR_CHAR, null, NotFound);
@@ -326,10 +330,26 @@
done = true;
}
StateHelper.setStateRecursive(this.units[i], ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS, done);
-// SH}
+/* orig: defer to next loop:
this.units[i] = null; // release unnecessary reference to the parsed unit
+ :giro */
+// SH}
}
this.stepCompleted = BUILD_FIELDS_AND_METHODS;
+
+//{ObjectTeams: one more step to handle here:
+ for (int i = this.lastCompletedUnitIndex + 1; i <= this.lastUnitIndex; i++) {
+ boolean done = false;
+ if (this.units[i].state.getState() < ITranslationStates.STATE_ROLES_LINKED) {
+ RoleSplitter.linkRoles(this.units[i]);
+ done = true;
+ }
+ StateHelper.setStateRecursive(this.units[i], ITranslationStates.STATE_ROLES_LINKED, done);
+ this.units[i] = null; // release unnecessary reference to the parsed unit
+ }
+ this.stepCompleted = ROLES_LINKED;
+// SH}
+
this.lastCompletedUnitIndex = this.lastUnitIndex;
this.unitBeingCompleted = null;
}
@@ -357,7 +377,12 @@
return 0; // avoid re-entrance
int todo = this.stepCompleted;
//SH}
+//{ObjectTeams: different last step:
+/* orig:
if (this.stepCompleted == BUILD_FIELDS_AND_METHODS) {
+ :giro */
+ if (this.stepCompleted == ROLES_LINKED) {
+// SH}
// This can only happen because the original set of units are completely built and
// are now being processed, so we want to treat all the additional units as a group
// until they too are completely processed.
@@ -394,6 +419,10 @@
// SH}
(this.unitBeingCompleted = parsedUnit).scope.connectTypeHierarchy();
+//{ObjectTeams: one more step:
+ if (todo >= ROLES_LINKED)
+ RoleSplitter.linkRoles(this.unitBeingCompleted = parsedUnit);
+
this.unitBeingCompleted = null;
}
//{ObjectTeams: report actual step achieved:
@@ -1848,6 +1877,8 @@
return ITranslationStates.STATE_LENV_CONNECT_TYPE_HIERARCHY;
case BUILD_FIELDS_AND_METHODS:
return ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS;
+ case ROLES_LINKED:
+ return ITranslationStates.STATE_ROLES_LINKED;
}
return ITranslationStates.STATE_NONE;
}
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 73fe3b4..8e9fc4b 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
@@ -305,6 +305,7 @@
case STATE_LENV_CHECK_AND_SET_IMPORTS:
case STATE_LENV_CONNECT_TYPE_HIERARCHY:
case STATE_LENV_DONE_FIELDS_AND_METHODS:
+ case STATE_ROLES_LINKED:
checkReadKnownRoles(unit);
LookupEnvironment lookupEnvironment= Config.getLookupEnvironment();
if (Config.getBundledCompleteTypeBindingsMode()) {
@@ -336,6 +337,8 @@
if (Config.getBuildFieldsAndMethods())
unit.scope.buildFieldsAndMethods();
break;
+ case STATE_ROLES_LINKED:
+ RoleSplitter.linkRoles(unit);
}
break;
case STATE_METHODS_PARSED:
@@ -734,10 +737,15 @@
success &= establishRoleSplit(model);
break;
case STATE_ROLES_LINKED:
- RoleSplitter.linkScopes(model);
- RoleSplitter.linkSuperAndBaseInIfc(model);
- success &= true; // redundant
- model.setState(STATE_ROLES_LINKED);
+ // normally a CUD state, except for late roles
+ if (isLateRole(model, nextState)) {
+ if (model.getAst() != null)
+ RoleSplitter.linkRoles(model.getAst());
+ model.setState(nextState);
+ model.setMemberState(nextState);
+ } else {
+ success &= ensureUnitState(model, nextState);
+ }
break;
case STATE_ROLE_INIT_METHODS:
success &= establishRoleInitializationMethod(model);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/ITranslationStates.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/ITranslationStates.java
index 93ee0e9..0d37de4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/ITranslationStates.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/ITranslationStates.java
@@ -42,7 +42,7 @@
public static final int STATE_LENV_CHECK_AND_SET_IMPORTS= 5;//LookupEnvironment & Deps.
public static final int STATE_LENV_CONNECT_TYPE_HIERARCHY= 6;//LookupEnvironment & Deps. & CopyInheritance
public static final int STATE_LENV_DONE_FIELDS_AND_METHODS= 7;//LookupEnvironment & Deps.
- public static final int STATE_ROLES_LINKED = 8;//CopyInheritance & Deps.
+ public static final int STATE_ROLES_LINKED = 8;//LookupEnvironment & RoleSplitter
public static final int STATE_METHODS_PARSED = 9;//Compiler
public static final int STATE_ROLE_INIT_METHODS = 10;//RoleInitializationMethod
public static final int STATE_ROLE_FEATURES_COPIED = 11;//Copy inheritance
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/StateHelper.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/StateHelper.java
index 156f531..02be601 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/StateHelper.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/StateHelper.java
@@ -78,6 +78,7 @@
case STATE_LENV_CHECK_AND_SET_IMPORTS:
case STATE_LENV_CONNECT_TYPE_HIERARCHY:
case STATE_LENV_DONE_FIELDS_AND_METHODS:
+ case STATE_ROLES_LINKED:
case STATE_ROLE_FILES_LINKED:
case STATE_METHODS_PARSED:
case STATE_METHODS_VERIFIED:
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/StateMemento.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/StateMemento.java
index 2e9f3fb..264172e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/StateMemento.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/control/StateMemento.java
@@ -130,7 +130,7 @@
if (state < this._currentlyProcessingState)
return false;
// FIXME(SH): obsolete after integrating both state models?
- if (state >= ITranslationStates.STATE_LENV_BUILD_TYPE_HIERARCHY && state <= ITranslationStates.STATE_LENV_DONE_FIELDS_AND_METHODS)
+ if (state >= ITranslationStates.STATE_LENV_BUILD_TYPE_HIERARCHY && state <= ITranslationStates.STATE_ROLES_LINKED)
return step < this._completingBindingsStep;
return true;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/RoleSplitter.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/RoleSplitter.java
index 18e5aad..5a21efb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/RoleSplitter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/RoleSplitter.java
@@ -36,6 +36,7 @@
import org.eclipse.jdt.internal.codeassist.complete.CompletionOnSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
@@ -52,9 +53,9 @@
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel;
+import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel.ProblemDetail;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel;
-import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel.ProblemDetail;
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;
@@ -397,7 +398,26 @@
}
+ /**
+ * API for LookupEnvironment:
+ * Establish necessary links between ifc- and class-part of each role in the given unit.
+ */
+ public static void linkRoles(CompilationUnitDeclaration unit) {
+ if (unit.types != null)
+ for (TypeDeclaration type : unit.types)
+ linkRoles(type);
+ }
+ public static void linkRoles(TypeDeclaration type) {
+ if (type.isRole()) {
+ RoleModel model = type.getRoleModel();
+ RoleSplitter.linkScopes(model);
+ RoleSplitter.linkSuperAndBaseInIfc(model);
+ }
+ if (type.memberTypes != null)
+ for (TypeDeclaration member : type.memberTypes)
+ linkRoles(member);
+ }
/**
* After roles have been split and bindings have been completed, transfer
@@ -406,11 +426,12 @@
* Note: tsuper roles are not yet copied. We might need to adjust types from
* super team to current team later (CopyInheritance.TypeLevel.adjustSuperinterfaces).
*/
- public static void linkSuperAndBaseInIfc(RoleModel role) {
+ private static void linkSuperAndBaseInIfc(RoleModel role) {
if (!role.isSourceRole())
return; // local type nested in a proper role
- if (role.getBinding().isBinaryBinding())
- return; // already linked.
+ ReferenceBinding binding = role.getBinding();
+ if (binding == null || binding.isBinaryBinding())
+ return; // no hope or already linked.
ReferenceBinding classPart = role.getClassPartBinding();
ReferenceBinding ifcPart = role.getInterfacePartBinding();
@@ -451,7 +472,7 @@
* which may appear in interface signatures).
* @param model
*/
- public static void linkScopes(RoleModel model) {
+ private static void linkScopes(RoleModel model) {
if (model._classPart != null && model._interfacePart != null) {
// may already have error
// (we observed duplicateNestedType, nestedHidesEnclosing)
@@ -462,8 +483,6 @@
}
}
-
-
public static boolean isClassPartName(char[] typeName) {
return CharOperation.prefixEquals(OT_DELIM_NAME, typeName);
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java
index 458fbda..e596ffc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java
@@ -18,24 +18,26 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
+
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.internal.compiler.*;
import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.jdt.internal.compiler.env.ISourceType;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblem;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.core.util.CommentRecorderParser;
import org.eclipse.jdt.internal.core.util.Util;
-import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
-import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
-import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
+
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
index 5c5175e..32edad8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
@@ -963,10 +963,6 @@
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=145333)
try {
this.lookupEnvironment.completeTypeBindings(parsedUnits, hasLocalType, unitsIndex);
-//{ObjectTeams: additional step: this state creates more hierarchy-related links:
- for (int i=0; i<unitsIndex; i++)
- Dependencies.ensureState(parsedUnits[i], ITranslationStates.STATE_ROLES_LINKED);
-// SH}
// remember type bindings
for (int i = 0; i < unitsIndex; i++) {
CompilationUnitDeclaration parsedUnit = parsedUnits[i];
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 6d2993c..a17f5ec 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
@@ -1631,4 +1631,69 @@
deleteProject("P");
}
}
+
+ // Bug 400360 - [reconciler] fails to resolve callout-to-field with path-anchored type
+ public void testBug400360() 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);
+
+ String allShapesSourceString =
+ "public team class AllShapes {\n" +
+ "\n" +
+ " public abstract class Connector { }\n" +
+ " public abstract class RectangularConnector extends Connector { }\n" +
+ "}\n";
+ this.createFile(
+ "/P/AllShapes.java",
+ allShapesSourceString);
+
+ String chdSourceString =
+ "public team class CompanyHierarchyDisplay {\n" +
+ " \n" +
+ " public final AllShapes _shapes = new AllShapes();\n" +
+ " \n" +
+ " public class Connection {\n" +
+ " Connector<@_shapes> connShape;\n" +
+ " }\n" +
+ "}\n";
+ this.createFile(
+ "/P/CompanyHierarchyDisplay.java",
+ chdSourceString);
+
+ String versionASourceString =
+ "public team class VersionA {\n" +
+ " private final CompanyHierarchyDisplay _chd;\n" +
+ " \n" +
+ " public VersionA(CompanyHierarchyDisplay chd) {\n" +
+ " _chd = chd;\n" +
+ " }\n" +
+ " \n" +
+ " public class RectangularConnections playedBy Connection<@_chd> {\n" +
+ " final AllShapes _shapesX = _chd._shapes;\n" +
+ " @SuppressWarnings(\"decapsulation\")\n" +
+ " void setShape(RectangularConnector<@_shapesX> shape) -> set Connector<@_chd._shapes> connShape;\n" +
+ " }\n" +
+ "}\n";
+ this.createFile(
+ "/P/VersionA.java",
+ versionASourceString);
+
+ char[] versionASourceChars = versionASourceString.toCharArray();
+ this.problemRequestor.initialize(versionASourceChars);
+
+ ICompilationUnit unit = getCompilationUnit("/P/VersionA.java").getWorkingCopy(this.wcOwner, null);
+
+ assertNoProblem(versionASourceChars, unit);
+ } finally {
+ deleteProject("P");
+ }
+ }
}
diff --git a/testplugins/org.eclipse.objectteams.otdt.ui.tests/src/org/eclipse/objectteams/otdt/ui/tests/hierarchy/contentprovider/OTSubHierarchyContentProviderTests.java b/testplugins/org.eclipse.objectteams.otdt.ui.tests/src/org/eclipse/objectteams/otdt/ui/tests/hierarchy/contentprovider/OTSubHierarchyContentProviderTests.java
index 04feb41..cee09fc 100644
--- a/testplugins/org.eclipse.objectteams.otdt.ui.tests/src/org/eclipse/objectteams/otdt/ui/tests/hierarchy/contentprovider/OTSubHierarchyContentProviderTests.java
+++ b/testplugins/org.eclipse.objectteams.otdt.ui.tests/src/org/eclipse/objectteams/otdt/ui/tests/hierarchy/contentprovider/OTSubHierarchyContentProviderTests.java
@@ -61,7 +61,7 @@
private IType _T8;
private IType _T1_R1;
- private IType _T1_R2;
+ // private IType _T1_R2; not within the cone of types reachable from _T1_R1
private IType _T2_R1;
private IType _T2_R2;
@@ -175,14 +175,7 @@
pkg,
"T1",
"R1").getCorrespondingJavaElement();
-
- _T1_R2 = (IType)
- getRole(getTestProjectDir(),
- SRC_FOLDER,
- pkg,
- "T1",
- "R2").getCorrespondingJavaElement();
-
+
_T2_R1 = (IType)
getRole(getTestProjectDir(),
SRC_FOLDER,
@@ -272,7 +265,7 @@
_allTypesInProject = new IType[]
{
_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8,
- _T1_R1, _T1_R2,
+ _T1_R1, //_T1_R2,
_T2_R1, _T2_R2,
_T3_R1, _T3_R2,
_T4_R2,
@@ -310,6 +303,7 @@
for (int idx = 0; idx < _allTypesInProject.length; idx++)
{
IType cur = _allTypesInProject[idx];
+ if (cur == _T2_R2) continue; // skip, cur's parent is outside the visible cone
actual = _testObject.getParent(cur);
assertEquals("Unexpected parent for " + cur.getFullyQualifiedName() + " ", parents.get(cur), actual);
}
diff --git a/testplugins/org.eclipse.objectteams.otdt.ui.tests/src/org/eclipse/objectteams/otdt/ui/tests/hierarchy/contentprovider/TreeNode.java b/testplugins/org.eclipse.objectteams.otdt.ui.tests/src/org/eclipse/objectteams/otdt/ui/tests/hierarchy/contentprovider/TreeNode.java
index 5104585..68d2a43 100644
--- a/testplugins/org.eclipse.objectteams.otdt.ui.tests/src/org/eclipse/objectteams/otdt/ui/tests/hierarchy/contentprovider/TreeNode.java
+++ b/testplugins/org.eclipse.objectteams.otdt.ui.tests/src/org/eclipse/objectteams/otdt/ui/tests/hierarchy/contentprovider/TreeNode.java
@@ -21,7 +21,9 @@
package org.eclipse.objectteams.otdt.ui.tests.hierarchy.contentprovider;
import java.util.HashMap;
+import java.util.Map.Entry;
+import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.objectteams.otdt.tests.FileBasedTest;
@@ -141,4 +143,19 @@
this._children.put(node.getElement(), node);
}
+
+ // facilitate debugging:
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ toString(buf, 0);
+ return buf.toString();
+ }
+
+ private void toString(StringBuffer buf, int indent) {
+ for (int i=0; i<indent; i++) buf.append(' ');
+ IJavaElement element = (IJavaElement)this._element;
+ buf.append(element.getParent().getElementName()).append('.').append(element.getElementName()).append('\n');
+ for (Entry<Object,TreeNode> e : this._children.entrySet())
+ e.getValue().toString(buf, 4);
+ }
}
\ No newline at end of file