590b8dbfe3ce19a136adf09d16e6f317fb55d6f4
[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 net.sourceforge.phpdt.core.IJavaElement;
14 import net.sourceforge.phpdt.core.IJavaModel;
15 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
16 import net.sourceforge.phpdt.core.IOpenable;
17 import net.sourceforge.phpdt.core.IParent;
18 import net.sourceforge.phpdt.core.JavaModelException;
19 import net.sourceforge.phpdt.internal.corext.Assert;
20
21 import org.eclipse.core.resources.IResourceStatus;
22 import org.eclipse.core.resources.ResourcesPlugin;
23 import org.eclipse.core.runtime.CoreException;
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.Path;
26 import org.eclipse.core.runtime.PlatformObject;
27
28 /**
29  * Root of Java element handle hierarchy.
30  *
31  * @see IJavaElement
32  */
33 public abstract class JavaElement extends PlatformObject implements IJavaElement {
34
35         public static final char JEM_JAVAPROJECT= '=';
36         public static final char JEM_PACKAGEFRAGMENTROOT= Path.SEPARATOR;
37         public static final char JEM_PACKAGEFRAGMENT= '<';
38         public static final char JEM_FIELD= '^';
39         public static final char JEM_METHOD= '~';
40         public static final char JEM_INITIALIZER= '|';
41         public static final char JEM_COMPILATIONUNIT= '{';
42         public static final char JEM_CLASSFILE= '(';
43         public static final char JEM_TYPE= '[';
44         public static final char JEM_PACKAGEDECLARATION= '%';
45         public static final char JEM_IMPORTDECLARATION= '#';
46
47         /**
48          * A count to uniquely identify this element in the case
49          * that a duplicate named element exists. For example, if
50          * there are two fields in a compilation unit with the
51          * same name, the occurrence count is used to distinguish
52          * them.  The occurrence count starts at 1 (thus the first 
53          * occurrence is occurrence 1, not occurrence 0).
54          */
55         protected int fOccurrenceCount = 1;
56
57
58         /**
59          * This element's type - one of the constants defined
60          * in IJavaLanguageElementTypes.
61          */
62         protected int fLEType = 0;
63
64         /**
65          * This element's parent, or <code>null</code> if this
66          * element does not have a parent.
67          */
68         protected IJavaElement fParent;
69
70         /**
71          * This element's name, or an empty <code>String</code> if this
72          * element does not have a name.
73          */
74         protected String fName;
75
76         protected static final Object NO_INFO = new Object();
77         
78         /**
79          * Constructs a handle for a java element of the specified type, with
80          * the given parent element and name.
81          *
82          * @param type - one of the constants defined in IJavaLanguageElement
83          *
84          * @exception IllegalArgumentException if the type is not one of the valid
85          *              Java element type constants
86          *
87          */
88         protected JavaElement(int type, IJavaElement parent, String name) throws IllegalArgumentException {
89                 if (type < JAVA_MODEL || type > IMPORT_DECLARATION) {
90                         throw new IllegalArgumentException(Util.bind("element.invalidType")); //$NON-NLS-1$
91                 }
92                 fLEType= type;
93                 fParent= parent;
94                 fName= name;
95         }
96         /**
97          * @see IOpenable
98          */
99 //      public void close() throws JavaModelException {
100 //              Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
101 //              if (info != null) {
102 //                      boolean wasVerbose = false;
103 //                      try {
104 //                              if (JavaModelManager.VERBOSE) {
105 //                                      System.out.println("CLOSING Element ("+ Thread.currentThread()+"): " + this.toStringWithAncestors());  //$NON-NLS-1$//$NON-NLS-2$
106 //                                      wasVerbose = true;
107 //                                      JavaModelManager.VERBOSE = false;
108 //                              }
109 //                              if (this instanceof IParent) {
110 //                                      IJavaElement[] children = ((JavaElementInfo) info).getChildren();
111 //                                      for (int i = 0, size = children.length; i < size; ++i) {
112 //                                              JavaElement child = (JavaElement) children[i];
113 //                                              child.close();
114 //                                      }
115 //                              }
116 //                              closing(info);
117 //                              JavaModelManager.getJavaModelManager().removeInfo(this);
118 //                              if (wasVerbose) {
119 //                                      System.out.println("-> Package cache size = " + JavaModelManager.getJavaModelManager().cache.pkgSize()); //$NON-NLS-1$
120 //                                      System.out.println("-> Openable cache filling ratio = " + JavaModelManager.getJavaModelManager().cache.openableFillingRatio() + "%"); //$NON-NLS-1$//$NON-NLS-2$
121 //                              }
122 //                      } finally {
123 //                              JavaModelManager.VERBOSE = wasVerbose;
124 //                      }
125 //              }
126 //      }
127         /**
128          * This element is being closed.  Do any necessary cleanup.
129          */
130         protected void closing(Object info) throws JavaModelException {
131         }
132         /**
133          * Returns true if this handle represents the same Java element
134          * as the given handle. By default, two handles represent the same
135          * element if they are identical or if they represent the same type
136          * of element, have equal names, parents, and occurrence counts.
137          *
138          * <p>If a subclass has other requirements for equality, this method
139          * must be overridden.
140          *
141          * @see Object#equals
142          */
143         public boolean equals(Object o) {
144                 
145                 if (this == o) return true;
146         
147                 // Java model parent is null
148                 if (fParent == null) return super.equals(o);
149         
150                 if (o instanceof JavaElement) {
151                         JavaElement other = (JavaElement) o;
152                         if (fLEType != other.fLEType) return false;
153                         
154                         return fName.equals(other.fName) &&
155                                         fParent.equals(other.fParent) &&
156                                         fOccurrenceCount == other.fOccurrenceCount;
157                 }
158                 return false;
159         }
160         /**
161          * Returns true if this <code>JavaElement</code> is equivalent to the given
162          * <code>IDOMNode</code>.
163          */
164 //      protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
165 //              return false;
166 //      }
167         /**
168          * @see IJavaElement
169          */
170 //      public boolean exists() {
171 //              
172 //              try {
173 //                      getElementInfo();
174 //                      return true;
175 //              } catch (JavaModelException e) {
176 //              }
177 //              return false;
178 //      }
179         
180         /**
181          * Returns the <code>IDOMNode</code> that corresponds to this <code>JavaElement</code>
182          * or <code>null</code> if there is no corresponding node.
183          */
184 //      public IDOMNode findNode(IDOMCompilationUnit dom) {
185 //              int type = getElementType();
186 //              if (type == IJavaElement.COMPILATION_UNIT || 
187 //                      type == IJavaElement.FIELD || 
188 //                      type == IJavaElement.IMPORT_DECLARATION || 
189 //                      type == IJavaElement.INITIALIZER || 
190 //                      type == IJavaElement.METHOD || 
191 //                      type == IJavaElement.PACKAGE_DECLARATION || 
192 //                      type == IJavaElement.TYPE) {
193 //                      ArrayList path = new ArrayList();
194 //                      IJavaElement element = this;
195 //                      while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
196 //                              if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) {
197 //                                      // the DOM does not have import containers, so skip them
198 //                                      path.add(0, element);
199 //                              }
200 //                              element = element.getParent();
201 //                      }
202 //                      if (path.size() == 0) {
203 //                              try {
204 //                                      if (equalsDOMNode(dom)) {
205 //                                              return dom;
206 //                                      } else {
207 //                                              return null;
208 //                                      }
209 //                              } catch(JavaModelException e) {
210 //                                      return null;
211 //                              }
212 //                      }
213 //                      return ((JavaElement) path.get(0)).followPath(path, 0, dom.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(path, position, node.getFirstChild());
230 //                                      } else {
231 //                                              return null;
232 //                                      }
233 //                              }
234 //                      } else if (node.getNextNode() != null) {
235 //                              return followPath(path, position, node.getNextNode());
236 //                      } else {
237 //                              return null;
238 //                      }
239 //              } catch (JavaModelException e) {
240 //                      return null;
241 //              }
242 //      
243 //      }
244         /**
245          * @see IJavaElement
246          */
247         public IJavaElement getAncestor(int ancestorType) {
248                 
249                 IJavaElement element = this;
250                 while (element != null) {
251                         if (element.getElementType() == ancestorType)  return element;
252                         element= element.getParent();
253                 }
254                 return null;                            
255         }
256         /**
257          * @see IParent 
258          */
259 //      public IJavaElement[] getChildren() throws JavaModelException {
260 //              return ((JavaElementInfo)getElementInfo()).getChildren();
261 //      }
262         /**
263          * Returns a collection of (immediate) children of this node of the
264          * specified type.
265          *
266          * @param type - one of constants defined by IJavaLanguageElementTypes
267          */
268 //      public ArrayList getChildrenOfType(int type) throws JavaModelException {
269 //              IJavaElement[] children = getChildren();
270 //              int size = children.length;
271 //              ArrayList list = new ArrayList(size);
272 //              for (int i = 0; i < size; ++i) {
273 //                      JavaElement elt = (JavaElement)children[i];
274 //                      if (elt.getElementType() == type) {
275 //                              list.add(elt);
276 //                      }
277 //              }
278 //              return list;
279 //      }
280         /**
281          * @see IMember
282          */
283 //      public IClassFile getClassFile() {
284 //              return null;
285 //      }
286 //      /**
287 //       * @see IMember
288 //       */
289 //      public ICompilationUnit getCompilationUnit() {
290 //              return null;
291 //      }
292         /**
293          * Returns the info for this handle.  
294          * If this element is not already open, it and all of its parents are opened.
295          * Does not return null.
296          * NOTE: BinaryType infos are NJOT rooted under JavaElementInfo.
297          * @exception JavaModelException if the element is not present or not accessible
298          */
299 //      public Object getElementInfo() throws JavaModelException {
300 //
301 //              // workaround to ensure parent project resolved classpath is available to avoid triggering initializers
302 //              // while the JavaModelManager lock is acquired (can cause deadlocks in clients)
303 //              IJavaProject project = getJavaProject();
304 //              if (project != null && !project.isOpen()) {
305 //                      // TODO: need to revisit, since deadlock could still occur if perProjectInfo is removed concurrent before entering the lock
306 //                      try {
307 //                              project.getResolvedClasspath(true); // trigger all possible container/variable initialization outside the model lock
308 //                      } catch (JavaModelException e) {
309 //                              // project is not accessible or is not a java project
310 //                      }
311 //              }
312 //
313 //              // element info creation is done inside a lock on the JavaModelManager
314 //              JavaModelManager manager;
315 //              synchronized(manager = JavaModelManager.getJavaModelManager()){
316 //                      Object info = manager.getInfo(this);
317 //                      if (info == null) {
318 //                              openHierarchy();
319 //                              info= manager.getInfo(this);
320 //                              if (info == null) {
321 //                                      throw newNotPresentException();
322 //                              }
323 //                      }
324 //                      return info;
325 //              }
326 //      }
327         /**
328          * @see IAdaptable
329          */
330         public String getElementName() {
331                 return fName;
332         }
333         /**
334          * @see IJavaElement
335          */
336         public int getElementType() {
337                 return fLEType;
338         }
339         /**
340          * @see IJavaElement
341          */
342         public String getHandleIdentifier() {
343                 return getHandleMemento();
344         }
345         /**
346          * @see JavaElement#getHandleMemento()
347          */
348         public String getHandleMemento(){
349                 StringBuffer buff= new StringBuffer(((JavaElement)getParent()).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) return (IJavaModel) current;
366                 } while ((current = current.getParent()) != null);
367                 return null;
368         }
369 //
370 //      /**
371 //       * @see IJavaElement
372 //       */
373 //      public IJavaProject getJavaProject() {
374 //              IJavaElement current = this;
375 //              do {
376 //                      if (current instanceof IJavaProject) return (IJavaProject) current;
377 //              } while ((current = current.getParent()) != null);
378 //              return null;
379 //      }
380         /**
381          * Returns the occurrence count of the handle.
382          */
383         protected int getOccurrenceCount() {
384                 return fOccurrenceCount;
385         }
386         /*
387          * @see IJavaElement
388          */
389         public IOpenable getOpenable() {
390                 return this.getOpenableParent();        
391         }
392         /**
393          * Return the first instance of IOpenable in the parent
394          * hierarchy of this element.
395          *
396          * <p>Subclasses that are not IOpenable's must override this method.
397          */
398         public IOpenable getOpenableParent() {
399                 
400                 return (IOpenable)fParent;
401         }
402         /**
403          * @see IJavaElement
404          */
405         public IJavaElement getParent() {
406                 return fParent;
407         }
408         
409         /**
410          * Returns the element that is located at the given source position
411          * in this element.  This is a helper method for <code>ICompilationUnit#getElementAt</code>,
412          * and only works on compilation units and types. The position given is
413          * known to be within this element's source range already, and if no finer
414          * grained element is found at the position, this element is returned.
415          */
416 //      protected IJavaElement getSourceElementAt(int position) throws JavaModelException {
417 //              if (this instanceof ISourceReference) {
418 //                      IJavaElement[] children = getChildren();
419 //                      int i;
420 //                      for (i = 0; i < children.length; i++) {
421 //                              IJavaElement aChild = children[i];
422 //                              if (aChild instanceof SourceRefElement) {
423 //                                      SourceRefElement child = (SourceRefElement) children[i];
424 //                                      ISourceRange range = child.getSourceRange();
425 //                                      if (position < range.getOffset() + range.getLength() && position >= range.getOffset()) {
426 //                                              if (child instanceof IParent) {
427 //                                                      return child.getSourceElementAt(position);
428 //                                              } else {
429 //                                                      return child;
430 //                                              }
431 //                                      }
432 //                              }
433 //                      }
434 //              } else {
435 //                      // should not happen
436 //                      Assert.isTrue(false);
437 //              }
438 //              return this;
439 //      }
440         /**
441          * Returns the SourceMapper facility for this element, or
442          * <code>null</code> if this element does not have a
443          * SourceMapper.
444          */
445 //      public SourceMapper getSourceMapper() {
446 //              return ((JavaElement)getParent()).getSourceMapper();
447 //      }
448
449         /**
450          * Returns the hash code for this Java element. By default,
451          * the hash code for an element is a combination of its name
452          * and parent's hash code. Elements with other requirements must
453          * override this method.
454          */
455         public int hashCode() {
456                 if (fParent == null) return super.hashCode();
457                 return Util.combineHashCodes(fName.hashCode(), fParent.hashCode());
458         }
459         /**
460          * Returns true if this element is an ancestor of the given element,
461          * otherwise false.
462          */
463         protected boolean isAncestorOf(IJavaElement e) {
464                 IJavaElement parent= e.getParent();
465                 while (parent != null && !parent.equals(this)) {
466                         parent= parent.getParent();
467                 }
468                 return parent != null;
469         }
470         
471         /**
472          * @see IJavaElement
473          */
474         public boolean isReadOnly() {
475                 return false;
476         }
477         /**
478          * @see IJavaElement
479          */
480 //      public boolean isStructureKnown() throws JavaModelException {
481 //              return ((JavaElementInfo)getElementInfo()).isStructureKnown();
482 //      }
483 //      /**
484 //       * Creates and returns and not present exception for this element.
485 //       */
486 //      protected JavaModelException newNotPresentException() {
487 //              return new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
488 //      }
489 //      /**
490 //       * Opens this element and all parents that are not already open.
491 //       *
492 //       * @exception JavaModelException this element is not present or accessible
493 //       */
494 //      protected void openHierarchy() throws JavaModelException {
495 //              if (this instanceof IOpenable) {
496 //                      ((Openable) this).openWhenClosed(null);
497 //              } else {
498 //                      Openable openableParent = (Openable)getOpenableParent();
499 //                      if (openableParent != null) {
500 //                              JavaElementInfo openableParentInfo = (JavaElementInfo) JavaModelManager.getJavaModelManager().getInfo((IJavaElement) openableParent);
501 //                              if (openableParentInfo == null) {
502 //                                      openableParent.openWhenClosed(null);
503 //                              } else {
504 //                                      throw newNotPresentException();
505 //                              }
506 //                      }
507 //              }
508 //      }
509         /**
510          * This element has just been opened.  Do any necessary setup.
511          */
512         protected void opening(Object info) {
513         }
514         /**
515          */
516         public String readableName() {
517                 return this.getElementName();
518         }
519         /**
520          * Removes all cached info from the Java Model, including all children,
521          * but does not close this element.
522          */
523 //      protected void removeInfo() {
524 //              Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
525 //              if (info != null) {
526 //                      if (this instanceof IParent) {
527 //                              IJavaElement[] children = ((JavaElementInfo)info).getChildren();
528 //                              for (int i = 0, size = children.length; i < size; ++i) {
529 //                                      JavaElement child = (JavaElement) children[i];
530 //                                      child.removeInfo();
531 //                              }
532 //                      }
533 //                      JavaModelManager.getJavaModelManager().removeInfo(this);
534 //              }
535 //      }
536 //      /**
537 //       * Returns a copy of this element rooted at the given project.
538 //       */
539 //      public abstract IJavaElement rootedAt(IJavaProject project);
540 //      /**
541 //       * Runs a Java Model Operation
542 //       */
543 //      public static void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException {
544 //              try {
545 //                      if (operation.isReadOnly() || ResourcesPlugin.getWorkspace().isTreeLocked()) {
546 //                              operation.run(monitor);
547 //                      } else {
548 //                              // use IWorkspace.run(...) to ensure that a build will be done in autobuild mode
549 //                              ResourcesPlugin.getWorkspace().run(operation, monitor);
550 //                      }
551 //              } catch (CoreException ce) {
552 //                      if (ce instanceof JavaModelException) {
553 //                              throw (JavaModelException)ce;
554 //                      } else {
555 //                              if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
556 //                                      Throwable e= ce.getStatus().getException();
557 //                                      if (e instanceof JavaModelException) {
558 //                                              throw (JavaModelException) e;
559 //                                      }
560 //                              }
561 //                              throw new JavaModelException(ce);
562 //                      }
563 //              }
564 //      }
565         /**
566          * Sets the occurrence count of the handle.
567          */
568         protected void setOccurrenceCount(int count) {
569                 fOccurrenceCount = count;
570         }
571         protected String tabString(int tab) {
572                 StringBuffer buffer = new StringBuffer();
573                 for (int i = tab; i > 0; i--)
574                         buffer.append("  "); //$NON-NLS-1$
575                 return buffer.toString();
576         }
577         /**
578          * Debugging purposes
579          */
580         public String toDebugString() {
581                 StringBuffer buffer = new StringBuffer();
582                 this.toStringInfo(0, buffer, NO_INFO);
583                 return buffer.toString();
584         }
585         /**
586          *  Debugging purposes
587          */
588         public String toString() {
589                 StringBuffer buffer = new StringBuffer();
590                 toString(0, buffer);
591                 return buffer.toString();
592         }
593         /**
594          *  Debugging purposes
595          */
596         protected void toString(int tab, StringBuffer buffer) {
597         //      Object info = this.toStringInfo(tab, buffer);
598                 Object info = null;
599                 if (tab == 0) {
600                         this.toStringAncestors(buffer);
601                 }
602                 this.toStringChildren(tab, buffer, info);
603         }
604         /**
605          *  Debugging purposes
606          */
607         public String toStringWithAncestors() {
608                 StringBuffer buffer = new StringBuffer();
609                 this.toStringInfo(0, buffer, NO_INFO);
610                 this.toStringAncestors(buffer);
611                 return buffer.toString();
612         }
613         /**
614          *  Debugging purposes
615          */
616         protected void toStringAncestors(StringBuffer buffer) {
617                 JavaElement parent = (JavaElement)this.getParent();
618                 if (parent != null && parent.getParent() != null) {
619                         buffer.append(" [in "); //$NON-NLS-1$
620                         parent.toStringInfo(0, buffer, NO_INFO);
621                         parent.toStringAncestors(buffer);
622                         buffer.append("]"); //$NON-NLS-1$
623                 }
624         }
625         /**
626          *  Debugging purposes
627          */
628         protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
629                 if (info == null || !(info instanceof JavaElementInfo)) return;
630                 IJavaElement[] children = ((JavaElementInfo)info).getChildren();
631                 for (int i = 0; i < children.length; i++) {
632                         buffer.append("\n"); //$NON-NLS-1$
633                         ((JavaElement)children[i]).toString(tab + 1, buffer);
634                 }
635         }
636         /**
637          *  Debugging purposes
638          */
639 //      public Object toStringInfo(int tab, StringBuffer buffer) {
640 //              Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
641 //              this.toStringInfo(tab, buffer, info);
642 //              return info;
643 //      }
644         /**
645          *  Debugging purposes
646          */
647         protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
648                 buffer.append(this.tabString(tab));
649                 buffer.append(getElementName());
650                 if (info == null) {
651                         buffer.append(" (not open)"); //$NON-NLS-1$
652                 }
653         }
654 }