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