added class fields to outline
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / JavaElement.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16
17 import net.sourceforge.phpdt.core.ICompilationUnit;
18 import net.sourceforge.phpdt.core.IJavaElement;
19 import net.sourceforge.phpdt.core.IJavaModel;
20 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
21 import net.sourceforge.phpdt.core.IJavaProject;
22 import net.sourceforge.phpdt.core.IMember;
23 import net.sourceforge.phpdt.core.IOpenable;
24 import net.sourceforge.phpdt.core.IParent;
25 import net.sourceforge.phpdt.core.ISourceRange;
26 import net.sourceforge.phpdt.core.ISourceReference;
27 import net.sourceforge.phpdt.core.JavaModelException;
28 import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
29 import net.sourceforge.phpdt.core.jdom.IDOMNode;
30 import net.sourceforge.phpdt.internal.corext.Assert;
31
32 import org.eclipse.core.resources.IResource;
33 import org.eclipse.core.resources.IResourceStatus;
34 import org.eclipse.core.resources.ResourcesPlugin;
35 import org.eclipse.core.runtime.CoreException;
36 import org.eclipse.core.runtime.IAdaptable;
37 import org.eclipse.core.runtime.IPath;
38 import org.eclipse.core.runtime.IProgressMonitor;
39 import org.eclipse.core.runtime.Path;
40 import org.eclipse.core.runtime.PlatformObject;
41 import org.eclipse.core.runtime.jobs.ISchedulingRule;
42 import net.sourceforge.phpdt.internal.core.JavaElementInfo;
43
44 import net.sourceforge.phpdt.internal.core.JavaModelManager;
45 import net.sourceforge.phpdt.internal.core.util.Util;
46
47 /**
48  * Root of Java element handle hierarchy.
49  * 
50  * @see IJavaElement
51  */
52 public abstract class JavaElement extends PlatformObject
53                 implements
54                         IJavaElement {
55
56         public static final char JEM_JAVAPROJECT = '=';
57         public static final char JEM_PACKAGEFRAGMENTROOT = Path.SEPARATOR;
58         public static final char JEM_PACKAGEFRAGMENT = '<';
59         public static final char JEM_FIELD = '^';
60         public static final char JEM_METHOD = '~';
61         public static final char JEM_INITIALIZER = '|';
62         public static final char JEM_COMPILATIONUNIT = '{';
63         public static final char JEM_CLASSFILE = '(';
64         public static final char JEM_TYPE = '[';
65         public static final char JEM_PACKAGEDECLARATION = '%';
66         public static final char JEM_IMPORTDECLARATION = '#';
67
68         /**
69          * A count to uniquely identify this element in the case that a duplicate
70          * named element exists. For example, if there are two fields in a
71          * compilation unit with the same name, the occurrence count is used to
72          * distinguish them. The occurrence count starts at 1 (thus the first
73          * occurrence is occurrence 1, not occurrence 0).
74          */
75         protected int occurrenceCount = 1;
76
77         /**
78          * This element's type - one of the constants defined in
79          * IJavaLanguageElementTypes.
80          */
81         //protected int fLEType = 0;
82         /**
83          * This element's parent, or <code>null</code> if this element does not
84          * have a parent.
85          */
86         protected IJavaElement parent;
87
88         /**
89          * This element's name, or an empty <code>String</code> if this element
90          * does not have a name.
91          */
92         protected String name;
93
94         protected static final Object NO_INFO = new Object();
95
96         /**
97          * Constructs a handle for a java element with the given parent element and
98          * name.
99          * 
100          * @param parent
101          *            The parent of java element
102          * @param name
103          *            The name of java element
104          * 
105          * @exception IllegalArgumentException
106          *                if the type is not one of the valid Java element type
107          *                constants
108          *  
109          */
110         protected JavaElement(JavaElement parent, String name)
111                         throws IllegalArgumentException {
112                 this.parent = parent;
113                 this.name = name;
114         }
115         /**
116          * @see IOpenable
117          */
118         public void close() throws JavaModelException {
119                 JavaModelManager.getJavaModelManager().removeInfoAndChildren(this);
120         }
121         /**
122          * This element is being closed. Do any necessary cleanup.
123          */
124         protected abstract void closing(Object info) throws JavaModelException;
125         /*
126          * Returns a new element info for this element.
127          */
128         protected abstract Object createElementInfo();
129         /**
130          * Returns true if this handle represents the same Java element as the given
131          * handle. By default, two handles represent the same element if they are
132          * identical or if they represent the same type of element, have equal
133          * names, parents, and occurrence counts.
134          * 
135          * <p>
136          * If a subclass has other requirements for equality, this method must be
137          * overridden.
138          * 
139          * @see Object#equals
140          */
141         public boolean equals(Object o) {
142
143                 if (this == o)
144                         return true;
145
146                 // Java model parent is null
147                 if (this.parent == null)
148                         return super.equals(o);
149                 if (o instanceof JavaElement) {
150                         // assume instanceof check is done in subclass
151                         JavaElement other = (JavaElement) o;
152                         return this.occurrenceCount == other.occurrenceCount
153                                         && this.name.equals(other.name)
154                                         && this.parent.equals(other.parent);
155                 }
156                 return false;
157         }
158         /**
159          * Returns true if this <code>JavaElement</code> is equivalent to the
160          * given <code>IDOMNode</code>.
161          */
162         protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
163                 return false;
164         }
165         /**
166          * @see IJavaElement
167          */
168         public boolean exists() {
169
170                 try {
171                         getElementInfo();
172                         return true;
173                 } catch (JavaModelException e) {
174                 }
175                 return false;
176         }
177
178         /**
179          * Returns the <code>IDOMNode</code> that corresponds to this
180          * <code>JavaElement</code> or <code>null</code> if there is no
181          * corresponding node.
182          */
183         public IDOMNode findNode(IDOMCompilationUnit dom) {
184                 int type = getElementType();
185                 if (type == IJavaElement.COMPILATION_UNIT || type == IJavaElement.FIELD
186                                 || type == IJavaElement.IMPORT_DECLARATION
187                                 || type == IJavaElement.INITIALIZER
188                                 || type == IJavaElement.METHOD
189                                 || type == IJavaElement.PACKAGE_DECLARATION
190                                 || type == IJavaElement.TYPE) {
191                         ArrayList path = new ArrayList();
192                         IJavaElement element = this;
193                         while (element != null
194                                         && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
195                                 if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) {
196                                         // the DOM does not have import containers, so skip them
197                                         path.add(0, element);
198                                 }
199                                 element = element.getParent();
200                         }
201                         if (path.size() == 0) {
202                                 try {
203                                         if (equalsDOMNode(dom)) {
204                                                 return dom;
205                                         } else {
206                                                 return null;
207                                         }
208                                 } catch (JavaModelException e) {
209                                         return null;
210                                 }
211                         }
212                         return ((JavaElement) path.get(0)).followPath(path, 0, dom
213                                         .getFirstChild());
214                 } else {
215                         return null;
216                 }
217         }
218         /**
219          */
220         protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) {
221
222                 try {
223                         if (equalsDOMNode(node)) {
224                                 if (position == (path.size() - 1)) {
225                                         return node;
226                                 } else {
227                                         if (node.getFirstChild() != null) {
228                                                 position++;
229                                                 return ((JavaElement) path.get(position)).followPath(
230                                                                 path, position, node.getFirstChild());
231                                         } else {
232                                                 return null;
233                                         }
234                                 }
235                         } else if (node.getNextNode() != null) {
236                                 return followPath(path, position, node.getNextNode());
237                         } else {
238                                 return null;
239                         }
240                 } catch (JavaModelException e) {
241                         return null;
242                 }
243
244         }
245         /**
246          * @see IJavaElement
247          */
248         public IJavaElement getAncestor(int ancestorType) {
249
250                 IJavaElement element = this;
251                 while (element != null) {
252                         if (element.getElementType() == ancestorType)
253                                 return element;
254                         element = element.getParent();
255                 }
256                 return null;
257         }
258         /**
259          * Generates the element infos for this element, its ancestors (if they are
260          * not opened) and its children (if it is an Openable). Puts the newly
261          * created element info in the given map.
262          */
263         protected abstract void generateInfos(Object info, HashMap newElements,
264                         IProgressMonitor pm) throws JavaModelException;
265
266         /**
267          * @see IParent
268          */
269         public IJavaElement[] getChildren() throws JavaModelException {
270                 return ((JavaElementInfo) getElementInfo()).getChildren();
271         }
272         /**
273          * Returns a collection of (immediate) children of this node of the
274          * specified type.
275          * 
276          * @param type -
277          *            one of constants defined by IJavaLanguageElementTypes
278          */
279         public ArrayList getChildrenOfType(int type) throws JavaModelException {
280                 IJavaElement[] children = getChildren();
281                 int size = children.length;
282                 ArrayList list = new ArrayList(size);
283                 for (int i = 0; i < size; ++i) {
284                         JavaElement elt = (JavaElement) children[i];
285                         if (elt.getElementType() == type) {
286                                 list.add(elt);
287                         }
288                 }
289                 return list;
290         }
291         /**
292          * @see IMember
293          */
294         //      public IClassFile getClassFile() {
295         //              return null;
296         //      }
297         /**
298          * @see IMember
299          */
300         public ICompilationUnit getCompilationUnit() {
301                 return null;
302         }
303         /**
304          * Returns the info for this handle. If this element is not already open, it
305          * and all of its parents are opened. Does not return null. NOTE: BinaryType
306          * infos are NOT rooted under JavaElementInfo.
307          * 
308          * @exception JavaModelException
309          *                if the element is not present or not accessible
310          */
311         public Object getElementInfo() throws JavaModelException {
312                 return getElementInfo(null);
313         }
314         /**
315          * Returns the info for this handle. If this element is not already open, it
316          * and all of its parents are opened. Does not return null. NOTE: BinaryType
317          * infos are NOT rooted under JavaElementInfo.
318          * 
319          * @exception JavaModelException
320          *                if the element is not present or not accessible
321          */
322         public Object getElementInfo(IProgressMonitor monitor)
323                         throws JavaModelException {
324
325                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
326                 Object info = manager.getInfo(this);
327                 if (info != null)
328                         return info;
329                 return openWhenClosed(createElementInfo(), monitor);
330         }
331         /**
332          * @see IAdaptable
333          */
334         public String getElementName() {
335                 return name;
336         }
337
338         /**
339          * @see IJavaElement
340          */
341         public String getHandleIdentifier() {
342                 return getHandleMemento();
343         }
344         /**
345          * @see JavaElement#getHandleMemento()
346          */
347         public String getHandleMemento() {
348                 StringBuffer buff = new StringBuffer(((JavaElement) getParent())
349                                 .getHandleMemento());
350                 buff.append(getHandleMementoDelimiter());
351                 buff.append(getElementName());
352                 return buff.toString();
353         }
354         /**
355          * Returns the <code>char</code> that marks the start of this handles
356          * contribution to a memento.
357          */
358         protected abstract char getHandleMementoDelimiter();
359         /**
360          * @see IJavaElement
361          */
362         public IJavaModel getJavaModel() {
363                 IJavaElement current = this;
364                 do {
365                         if (current instanceof IJavaModel)
366                                 return (IJavaModel) current;
367                 } while ((current = current.getParent()) != null);
368                 return null;
369         }
370
371         /**
372          * @see IJavaElement
373          */
374         public IJavaProject getJavaProject() {
375                 IJavaElement current = this;
376                 do {
377                         if (current instanceof IJavaProject)
378                                 return (IJavaProject) current;
379                 } while ((current = current.getParent()) != null);
380                 return null;
381         }
382         /**
383          * Returns the occurrence count of the handle.
384          */
385         protected int getOccurrenceCount() {
386                 return occurrenceCount;
387         }
388         /*
389          * @see IJavaElement
390          */
391         public IOpenable getOpenable() {
392                 return this.getOpenableParent();
393         }
394         /**
395          * Return the first instance of IOpenable in the parent hierarchy of this
396          * element.
397          * 
398          * <p>
399          * Subclasses that are not IOpenable's must override this method.
400          */
401         public IOpenable getOpenableParent() {
402
403                 return (IOpenable) parent;
404         }
405         /**
406          * @see IJavaElement
407          */
408         public IJavaElement getParent() {
409                 return parent;
410         }
411
412         /*
413          * @see IJavaElement#getPrimaryElement()
414          */
415         public IJavaElement getPrimaryElement() {
416                 return getPrimaryElement(true);
417         }
418         /*
419          * Returns the primary element. If checkOwner, and the cu owner is primary,
420          * return this element.
421          */
422         public IJavaElement getPrimaryElement(boolean checkOwner) {
423                 return this;
424         }
425         /**
426          * Returns the element that is located at the given source position in this
427          * element. This is a helper method for
428          * <code>ICompilationUnit#getElementAt</code>, and only works on
429          * compilation units and types. The position given is known to be within
430          * this element's source range already, and if no finer grained element is
431          * found at the position, this element is returned.
432          */
433         protected IJavaElement getSourceElementAt(int position)
434                         throws JavaModelException {
435                 if (this instanceof ISourceReference) {
436                         IJavaElement[] children = getChildren();
437                         int i;
438                         for (i = 0; i < children.length; i++) {
439                                 IJavaElement aChild = children[i];
440                                 if (aChild instanceof SourceRefElement) {
441                                         SourceRefElement child = (SourceRefElement) children[i];
442                                         ISourceRange range = child.getSourceRange();
443                                         if (position < range.getOffset() + range.getLength()
444                                                         && position >= range.getOffset()) {
445                                                 if (child instanceof IParent) {
446                                                         return child.getSourceElementAt(position);
447                                                 } else {
448                                                         return child;
449                                                 }
450                                         }
451                                 }
452                         }
453                 } else {
454                         // should not happen
455                         Assert.isTrue(false);
456                 }
457                 return this;
458         }
459         /**
460          * Returns the SourceMapper facility for this element, or <code>null</code>
461          * if this element does not have a SourceMapper.
462          */
463         //      public SourceMapper getSourceMapper() {
464         //              return ((JavaElement)getParent()).getSourceMapper();
465         //      }
466         /*
467          * (non-Javadoc)
468          * 
469          * @see org.eclipse.jdt.core.IJavaElement#getSchedulingRule()
470          */
471         public ISchedulingRule getSchedulingRule() {
472                 IResource resource = getResource();
473                 if (resource == null) {
474                         class NoResourceSchedulingRule implements ISchedulingRule {
475                                 public IPath path;
476                                 public NoResourceSchedulingRule(IPath path) {
477                                         this.path = path;
478                                 }
479                                 public boolean contains(ISchedulingRule rule) {
480                                         if (rule instanceof NoResourceSchedulingRule) {
481                                                 return this.path
482                                                                 .isPrefixOf(((NoResourceSchedulingRule) rule).path);
483                                         } else {
484                                                 return false;
485                                         }
486                                 }
487                                 public boolean isConflicting(ISchedulingRule rule) {
488                                         if (rule instanceof NoResourceSchedulingRule) {
489                                                 IPath otherPath = ((NoResourceSchedulingRule) rule).path;
490                                                 return this.path.isPrefixOf(otherPath)
491                                                                 || otherPath.isPrefixOf(this.path);
492                                         } else {
493                                                 return false;
494                                         }
495                                 }
496                         }
497                         return new NoResourceSchedulingRule(getPath());
498                 } else {
499                         return resource;
500                 }
501         }
502         /**
503          * @see IParent
504          */
505         public boolean hasChildren() throws JavaModelException {
506                 // if I am not open, return true to avoid opening (case of a Java
507                 // project, a compilation unit or a class file).
508                 // also see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52474
509                 Object elementInfo = JavaModelManager.getJavaModelManager().getInfo(
510                                 this);
511                 if (elementInfo instanceof JavaElementInfo) {
512                         return ((JavaElementInfo) elementInfo).getChildren().length > 0;
513                 } else {
514                         return true;
515                 }
516         }
517
518         /**
519          * Returns the hash code for this Java element. By default, the hash code
520          * for an element is a combination of its name and parent's hash code.
521          * Elements with other requirements must override this method.
522          */
523         public int hashCode() {
524                 if (this.parent == null)
525                         return super.hashCode();
526                 return Util.combineHashCodes(this.name.hashCode(), this.parent
527                                 .hashCode());
528         }
529
530         /**
531          * Returns true if this element is an ancestor of the given element,
532          * otherwise false.
533          */
534         protected boolean isAncestorOf(IJavaElement e) {
535                 IJavaElement parent = e.getParent();
536                 while (parent != null && !parent.equals(this)) {
537                         parent = parent.getParent();
538                 }
539                 return parent != null;
540         }
541
542         /**
543          * @see IJavaElement
544          */
545         public boolean isReadOnly() {
546                 return false;
547         }
548         /**
549          * @see IJavaElement
550          */
551         public boolean isStructureKnown() throws JavaModelException {
552                 return ((JavaElementInfo) getElementInfo()).isStructureKnown();
553         }
554         /**
555          * Creates and returns and not present exception for this element.
556          */
557         protected JavaModelException newNotPresentException() {
558                 return new JavaModelException(new JavaModelStatus(
559                                 IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
560         }
561         /**
562          * Opens this element and all parents that are not already open.
563          * 
564          * @exception JavaModelException
565          *                this element is not present or accessible
566          */
567         //      protected void openHierarchy() throws JavaModelException {
568         //              if (this instanceof IOpenable) {
569         //                      ((Openable) this).openWhenClosed(null);
570         //              } else {
571         //                      Openable openableParent = (Openable)getOpenableParent();
572         //                      if (openableParent != null) {
573         //                              JavaElementInfo openableParentInfo = (JavaElementInfo)
574         // JavaModelManager.getJavaModelManager().getInfo((IJavaElement)
575         // openableParent);
576         //                              if (openableParentInfo == null) {
577         //                                      openableParent.openWhenClosed(null);
578         //                              } else {
579         //                                      throw newNotPresentException();
580         //                              }
581         //                      }
582         //              }
583         //      }
584         /**
585          * This element has just been opened. Do any necessary setup.
586          */
587         protected void opening(Object info) {
588         }
589         /*
590          * Opens an <code> Openable </code> that is known to be closed (no check for
591          * <code> isOpen() </code> ). Returns the created element info.
592          */
593         protected Object openWhenClosed(Object info, IProgressMonitor monitor)
594                         throws JavaModelException {
595                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
596                 boolean hadTemporaryCache = manager.hasTemporaryCache();
597                 try {
598                         HashMap newElements = manager.getTemporaryCache();
599                         generateInfos(info, newElements, monitor);
600                         if (info == null) {
601                                 info = newElements.get(this);
602                         }
603                         if (info == null) { // a source ref element could not be opened
604                                 // close any buffer that was opened for the openable parent
605                                 Iterator iterator = newElements.keySet().iterator();
606                                 while (iterator.hasNext()) {
607                                         IJavaElement element = (IJavaElement) iterator.next();
608                                         if (element instanceof Openable) {
609                                                 ((Openable) element).closeBuffer();
610                                         }
611                                 }
612                                 throw newNotPresentException();
613                         }
614                         if (!hadTemporaryCache) {
615                                 manager.putInfos(this, newElements);
616                         }
617                 } finally {
618                         if (!hadTemporaryCache) {
619                                 manager.resetTemporaryCache();
620                         }
621                 }
622                 return info;
623         }
624         /**
625          */
626         public String readableName() {
627                 return this.getElementName();
628         }
629         /**
630          * Removes all cached info from the Java Model, including all children, but
631          * does not close this element.
632          */
633         //      protected void removeInfo() {
634         //              Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
635         //              if (info != null) {
636         //                      if (this instanceof IParent) {
637         //                              IJavaElement[] children = ((JavaElementInfo)info).getChildren();
638         //                              for (int i = 0, size = children.length; i < size; ++i) {
639         //                                      JavaElement child = (JavaElement) children[i];
640         //                                      child.removeInfo();
641         //                              }
642         //                      }
643         //                      JavaModelManager.getJavaModelManager().removeInfo(this);
644         //              }
645         //      }
646         //      /**
647         //       * Returns a copy of this element rooted at the given project.
648         //       */
649         //      public abstract IJavaElement rootedAt(IJavaProject project);
650         /**
651          * Runs a Java Model Operation
652          */
653         public static void runOperation(JavaModelOperation operation,
654                         IProgressMonitor monitor) throws JavaModelException {
655                 try {
656                         if (operation.isReadOnly()
657                                         || ResourcesPlugin.getWorkspace().isTreeLocked()) {
658                                 operation.run(monitor);
659                         } else {
660                                 // use IWorkspace.run(...) to ensure that a build will be done
661                                 // in autobuild mode
662                                 ResourcesPlugin.getWorkspace().run(operation, monitor);
663                         }
664                 } catch (CoreException ce) {
665                         if (ce instanceof JavaModelException) {
666                                 throw (JavaModelException) ce;
667                         } else {
668                                 if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
669                                         Throwable e = ce.getStatus().getException();
670                                         if (e instanceof JavaModelException) {
671                                                 throw (JavaModelException) e;
672                                         }
673                                 }
674                                 throw new JavaModelException(ce);
675                         }
676                 }
677         }
678         /**
679          * Sets the occurrence count of the handle.
680          */
681         protected void setOccurrenceCount(int count) {
682                 occurrenceCount = count;
683         }
684         protected String tabString(int tab) {
685                 StringBuffer buffer = new StringBuffer();
686                 for (int i = tab; i > 0; i--)
687                         buffer.append("  "); //$NON-NLS-1$
688                 return buffer.toString();
689         }
690         /**
691          * Debugging purposes
692          */
693         public String toDebugString() {
694                 StringBuffer buffer = new StringBuffer();
695                 this.toStringInfo(0, buffer, NO_INFO);
696                 return buffer.toString();
697         }
698         /**
699          * Debugging purposes
700          */
701         public String toString() {
702                 StringBuffer buffer = new StringBuffer();
703                 toString(0, buffer);
704                 return buffer.toString();
705         }
706         /**
707          *  Debugging purposes
708          */
709         protected void toStringName(StringBuffer buffer) {
710                 buffer.append(getElementName());
711                 if (this.occurrenceCount > 1) {
712                         buffer.append("#"); //$NON-NLS-1$
713                         buffer.append(this.occurrenceCount);
714                 }
715         }
716         /**
717          * Debugging purposes
718          */
719         protected void toString(int tab, StringBuffer buffer) {
720                 //      Object info = this.toStringInfo(tab, buffer);
721                 Object info = null;
722                 if (tab == 0) {
723                         this.toStringAncestors(buffer);
724                 }
725                 this.toStringChildren(tab, buffer, info);
726         }
727         /**
728          * Debugging purposes
729          */
730         public String toStringWithAncestors() {
731                 StringBuffer buffer = new StringBuffer();
732                 this.toStringInfo(0, buffer, NO_INFO);
733                 this.toStringAncestors(buffer);
734                 return buffer.toString();
735         }
736         /**
737          * Debugging purposes
738          */
739         protected void toStringAncestors(StringBuffer buffer) {
740                 JavaElement parent = (JavaElement) this.getParent();
741                 if (parent != null && parent.getParent() != null) {
742                         buffer.append(" [in "); //$NON-NLS-1$
743                         parent.toStringInfo(0, buffer, NO_INFO);
744                         parent.toStringAncestors(buffer);
745                         buffer.append("]"); //$NON-NLS-1$
746                 }
747         }
748         /**
749          * Debugging purposes
750          */
751         protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
752                 if (info == null || !(info instanceof JavaElementInfo))
753                         return;
754                 IJavaElement[] children = ((JavaElementInfo) info).getChildren();
755                 for (int i = 0; i < children.length; i++) {
756                         buffer.append("\n"); //$NON-NLS-1$
757                         ((JavaElement) children[i]).toString(tab + 1, buffer);
758                 }
759         }
760         /**
761          * Debugging purposes
762          */
763         //      public Object toStringInfo(int tab, StringBuffer buffer) {
764         //              Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
765         //              this.toStringInfo(tab, buffer, info);
766         //              return info;
767         //      }
768         /**
769          * Debugging purposes
770          */
771         protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
772                 buffer.append(this.tabString(tab));
773                 buffer.append(getElementName());
774                 if (info == null) {
775                         buffer.append(" (not open)"); //$NON-NLS-1$
776                 }
777         }
778 }