improved PHP parser
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / SourceType.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.io.InputStream;
14 import java.util.ArrayList;
15
16 import net.sourceforge.phpdt.core.ICompilationUnit;
17 import net.sourceforge.phpdt.core.IField;
18 import net.sourceforge.phpdt.core.IJavaElement;
19 import net.sourceforge.phpdt.core.IJavaProject;
20 import net.sourceforge.phpdt.core.IMember;
21 import net.sourceforge.phpdt.core.IMethod;
22 import net.sourceforge.phpdt.core.IPackageFragment;
23 import net.sourceforge.phpdt.core.IParent;
24 import net.sourceforge.phpdt.core.IType;
25 import net.sourceforge.phpdt.core.ITypeHierarchy;
26 import net.sourceforge.phpdt.core.IWorkingCopy;
27 import net.sourceforge.phpdt.core.JavaModelException;
28 import net.sourceforge.phpdt.core.WorkingCopyOwner;
29 import net.sourceforge.phpdt.core.jdom.IDOMNode;
30 import net.sourceforge.phpdt.internal.core.util.Util;
31 import net.sourceforge.phpdt.internal.corext.Assert;
32
33 import org.eclipse.core.runtime.IProgressMonitor;
34
35 /**
36  * Handle for a source type. Info object is a SourceTypeElementInfo.
37  * 
38  * Note: Parent is either an IClassFile, an ICompilationUnit or an IType.
39  * 
40  * @see IType
41  */
42
43 public class SourceType extends Member implements IType {
44   /**
45    * An empty list of Strings
46    */
47   protected static final String[] fgEmptyList = new String[] {};
48   protected SourceType(JavaElement parent, String name) {
49     super(parent, name);
50     Assert.isTrue(name.indexOf('.') == -1, Util.bind("sourcetype.invalidName", name)); //$NON-NLS-1$
51   }
52
53   /**
54    * @see IType
55    */
56   //public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][]
57   // localVariableNames,int[] localVariableModifiers,boolean isStatic,ICompletionRequestor requestor) throws JavaModelException {
58   //    if (requestor == null) {
59   //            throw new IllegalArgumentException(ProjectPrefUtil.bind("codeAssist.nullRequestor")); //$NON-NLS-1$
60   //    }
61   //    
62   //    JavaProject project = (JavaProject) getJavaProject();
63   //    SearchableEnvironment environment = (SearchableEnvironment) project.getSearchableNameEnvironment();
64   //    NameLookup nameLookup = project.getNameLookup();
65   //    CompletionEngine engine = new CompletionEngine(environment, new CompletionRequestorWrapper(requestor,nameLookup),
66   // project.getOptions(true), project);
67   //    
68   //    String source = getCompilationUnit().getSource();
69   //    if (source != null && insertion > -1 && insertion < source.length()) {
70   //            String encoding = project.getOption(JavaCore.CORE_ENCODING, true);
71   //            
72   //            char[] prefix = CharOperation.concat(source.substring(0, insertion).toCharArray(), new char[]{'{'});
73   //            char[] suffix = CharOperation.concat(new char[]{'}'}, source.substring(insertion).toCharArray());
74   //            char[] fakeSource = CharOperation.concat(prefix, snippet, suffix);
75   //            
76   //            BasicCompilationUnit cu =
77   //                    new BasicCompilationUnit(
78   //                            fakeSource,
79   //                            null,
80   //                            getElementName(),
81   //                            encoding);
82   //
83   //            engine.complete(cu, prefix.length + position, prefix.length);
84   //    } else {
85   //            engine.complete(this, snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic);
86   //    }
87   //}
88   /**
89    * @see IType
90    */
91   //public IField createField(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws
92   // JavaModelException {
93   //    CreateFieldOperation op = new CreateFieldOperation(this, contents, force);
94   //    if (sibling != null) {
95   //            op.createBefore(sibling);
96   //    }
97   //    runOperation(op, monitor);
98   //    return (IField) op.getResultElements()[0];
99   //}
100   /**
101    * @see IType
102    */
103   //public IInitializer createInitializer(String contents, IJavaElement sibling, IProgressMonitor monitor) throws
104   // JavaModelException {
105   //    CreateInitializerOperation op = new CreateInitializerOperation(this, contents);
106   //    if (sibling != null) {
107   //            op.createBefore(sibling);
108   //    }
109   //    runOperation(op, monitor);
110   //    return (IInitializer) op.getResultElements()[0];
111   //}
112   /**
113    * @see IType
114    */
115   //public IMethod createMethod(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws
116   // JavaModelException {
117   //    CreateMethodOperation op = new CreateMethodOperation(this, contents, force);
118   //    if (sibling != null) {
119   //            op.createBefore(sibling);
120   //    }
121   //    runOperation(op, monitor);
122   //    return (IMethod) op.getResultElements()[0];
123   //}
124   /**
125    * @see IType
126    */
127   //public IType createType(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws
128   // JavaModelException {
129   //    CreateTypeOperation op = new CreateTypeOperation(this, contents, force);
130   //    if (sibling != null) {
131   //            op.createBefore(sibling);
132   //    }
133   //    runOperation(op, monitor);
134   //    return (IType) op.getResultElements()[0];
135   //}
136   /**
137    * @see JavaElement#equalsDOMNode
138    */
139   protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
140     return (node.getNodeType() == IDOMNode.TYPE) && super.equalsDOMNode(node);
141   }
142
143   /*
144    * @see IType
145    */
146   public IMethod[] findMethods(IMethod method) {
147     try {
148       return this.findMethods(method, this.getMethods());
149     } catch (JavaModelException e) {
150       // if type doesn't exist, no matching method can exist
151       return null;
152     }
153   }
154
155   /**
156    * @see IMember
157    */
158   public IType getDeclaringType() {
159     IJavaElement parent = getParent();
160     while (parent != null) {
161       if (parent.getElementType() == IJavaElement.TYPE) {
162         return (IType) parent;
163       } else if (parent instanceof IMember) {
164         parent = parent.getParent();
165       } else {
166         return null;
167       }
168     }
169     return null;
170   }
171
172   /**
173    * @see IJavaElement
174    */
175   public int getElementType() {
176     return TYPE;
177   }
178
179   /**
180    * @see IType#getField
181    */
182   public IField getField(String name) {
183     return new SourceField(this, name);
184   }
185
186   /**
187    * @see IType
188    */
189   public IField[] getFields() throws JavaModelException {
190     ArrayList list = getChildrenOfType(FIELD);
191     IField[] array = new IField[list.size()];
192     list.toArray(array);
193     return array;
194   }
195
196   /**
197    * @see IType#getFullyQualifiedName
198    */
199   public String getFullyQualifiedName() {
200     return this.getFullyQualifiedName('$');
201   }
202
203   /**
204    * @see IType#getFullyQualifiedName(char)
205    */
206   public String getFullyQualifiedName(char enclosingTypeSeparator) {
207     String packageName = getPackageFragment().getElementName();
208     if (packageName.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
209       return getTypeQualifiedName(enclosingTypeSeparator);
210     }
211     return packageName + '.' + getTypeQualifiedName(enclosingTypeSeparator);
212   }
213
214   /**
215    * @see IType
216    */
217   //public IInitializer getInitializer(int occurrenceCount) {
218   //    return new Initializer(this, occurrenceCount);
219   //}
220   /**
221    * @see IType
222    */
223   //public IInitializer[] getInitializers() throws JavaModelException {
224   //    ArrayList list = getChildrenOfType(INITIALIZER);
225   //    IInitializer[] array= new IInitializer[list.size()];
226   //    list.toArray(array);
227   //    return array;
228   //}
229   /**
230    * @see IType#getMethod
231    */
232   public IMethod getMethod(String name, String[] parameterTypeSignatures) {
233     return new SourceMethod(this, name, parameterTypeSignatures);
234   }
235
236   /**
237    * @see IType
238    */
239   public IMethod[] getMethods() throws JavaModelException {
240     ArrayList list = getChildrenOfType(METHOD);
241     IMethod[] array = new IMethod[list.size()];
242     list.toArray(array);
243     return array;
244   }
245
246   /**
247    * @see IType
248    */
249   public IPackageFragment getPackageFragment() {
250     IJavaElement parentElement = this.parent;
251     while (parentElement != null) {
252       if (parentElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
253         return (IPackageFragment) parentElement;
254       } else {
255         parentElement = parentElement.getParent();
256       }
257     }
258     Assert.isTrue(false); // should not happen
259     return null;
260   }
261
262   /**
263    * @see IType
264    */
265   public String getSuperclassName() throws JavaModelException {
266     SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
267     char[] superclassName = info.getSuperclassName();
268     if (superclassName == null) {
269       return null;
270     }
271     return new String(superclassName);
272   }
273
274   /**
275    * @see IType
276    */
277   public String[] getSuperInterfaceNames() throws JavaModelException {
278     SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
279     char[][] names = info.getInterfaceNames();
280     if (names == null) {
281       return fgEmptyList;
282     }
283     String[] strings = new String[names.length];
284     for (int i = 0; i < names.length; i++) {
285       strings[i] = new String(names[i]);
286     }
287     return strings;
288   }
289
290   /**
291    * @see IType
292    */
293   public IType getType(String name) {
294     return new SourceType(this, name);
295   }
296
297   /**
298    * @see IType#getTypeQualifiedName
299    */
300   public String getTypeQualifiedName() {
301     return this.getTypeQualifiedName('$');
302   }
303
304   /**
305    * @see IType#getTypeQualifiedName(char)
306    */
307   public String getTypeQualifiedName(char enclosingTypeSeparator) {
308     if (parent.getElementType() == IJavaElement.COMPILATION_UNIT) {
309       return name;
310     } else {
311       return ((IType) parent).getTypeQualifiedName(enclosingTypeSeparator) + enclosingTypeSeparator + name;
312     }
313   }
314
315   /**
316    * @see IType
317    */
318   public IType[] getTypes() throws JavaModelException {
319     ArrayList list = getChildrenOfType(TYPE);
320     IType[] array = new IType[list.size()];
321     list.toArray(array);
322     return array;
323   }
324
325   /**
326    * @see IParent
327    */
328   public boolean hasChildren() throws JavaModelException {
329     return getChildren().length > 0;
330   }
331
332   /**
333    * @see IType#isAnonymous()
334    */
335   public boolean isAnonymous() throws JavaModelException {
336     return false; // cannot create source handle onto anonymous types
337   }
338
339   /**
340    * @see IType
341    */
342   public boolean isClass() throws JavaModelException {
343     return !isInterface();
344   }
345
346   /**
347    * @see IType
348    */
349   public boolean isInterface() throws JavaModelException {
350     Object obj = getElementInfo(); 
351     if (obj instanceof SourceTypeElementInfo) {
352       SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
353       return info.isInterface();
354     }
355     return false;
356   }
357
358   /**
359    * @see IType#isLocal()
360    */
361   public boolean isLocal() throws JavaModelException {
362     return false; // cannot create source handle onto local types
363   }
364
365   /**
366    * @see IType#isMember()
367    */
368   public boolean isMember() throws JavaModelException {
369     return getDeclaringType() != null;
370   }
371
372   /**
373    * @see IType
374    */
375 //  public ITypeHierarchy loadTypeHierachy(InputStream input, IProgressMonitor monitor) throws JavaModelException {
376 //      return loadTypeHierachy(input, DefaultWorkingCopyOwner.PRIMARY, monitor);
377 //  }
378   /**
379    * NOTE: This method is not part of the API has it is not clear clients would easily use it: they would need to
380    * first make sure all working copies for the given owner exist before calling it. This is especially har at startup 
381    * time.
382    * In case clients want this API, here is how it should be specified:
383    * <p>
384    * Loads a previously saved ITypeHierarchy from an input stream. A type hierarchy can
385    * be stored using ITypeHierachy#store(OutputStream). A compilation unit of a
386    * loaded type has the given owner if such a working copy exists, otherwise the type's 
387    * compilation unit is a primary compilation unit.
388    * 
389    * Only hierarchies originally created by the following methods can be loaded:
390    * <ul>
391    * <li>IType#newSupertypeHierarchy(IProgressMonitor)</li>
392    * <li>IType#newSupertypeHierarchy(WorkingCopyOwner, IProgressMonitor)</li>
393    * <li>IType#newTypeHierarchy(IJavaProject, IProgressMonitor)</li>
394    * <li>IType#newTypeHierarchy(IJavaProject, WorkingCopyOwner, IProgressMonitor)</li>
395    * <li>IType#newTypeHierarchy(IProgressMonitor)</li>
396    * <li>IType#newTypeHierarchy(WorkingCopyOwner, IProgressMonitor)</li>
397    * </u>
398    * 
399    * @param input stream where hierarchy will be read
400    * @param monitor the given progress monitor
401    * @return the stored hierarchy
402    * @exception JavaModelException if the hierarchy could not be restored, reasons include:
403    *      - type is not the focus of the hierarchy or 
404    *            - unable to read the input stream (wrong format, IOException during reading, ...)
405    * @see ITypeHierarchy#store(java.io.OutputStream, IProgressMonitor)
406    * @since 3.0
407    */
408 //  public ITypeHierarchy loadTypeHierachy(InputStream input, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
409 //      // TODO monitor should be passed to TypeHierarchy.load(...)
410 //      return TypeHierarchy.load(this, input, owner);
411 //  }
412   /**
413    * @see IType
414    */
415 //  public ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor) throws JavaModelException {
416 //      return this.newSupertypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, monitor);
417 //  }
418   /*
419    * @see IType#newSupertypeHierarchy(ICompilationUnit[], IProgressMonitor)
420    */
421 //  public ITypeHierarchy newSupertypeHierarchy(
422 //      ICompilationUnit[] workingCopies,
423 //      IProgressMonitor monitor)
424 //      throws JavaModelException {
425 //
426 //      CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), false);
427 //      op.runOperation(monitor);
428 //      return op.getResult();
429 //  }
430   /**
431    * @param workingCopies the working copies that take precedence over their original compilation units
432    * @param monitor the given progress monitor
433    * @return a type hierarchy for this type containing this type and all of its supertypes
434    * @exception JavaModelException if this element does not exist or if an
435    *            exception occurs while accessing its corresponding resource.
436    *
437    * @see IType#newSupertypeHierarchy(IWorkingCopy[], IProgressMonitor)
438    * @deprecated
439    */
440   public ITypeHierarchy newSupertypeHierarchy(
441         IWorkingCopy[] workingCopies,
442         IProgressMonitor monitor)
443         throws JavaModelException {
444
445         ICompilationUnit[] copies;
446         if (workingCopies == null) {
447                 copies = null;
448         } else {
449                 int length = workingCopies.length;
450                 System.arraycopy(workingCopies, 0, copies = new ICompilationUnit[length], 0, length);
451         }
452         return newSupertypeHierarchy(copies, monitor);
453   }
454   /**
455    * @see IType#newSupertypeHierarchy(WorkingCopyOwner, IProgressMonitor)
456    */
457 //  public ITypeHierarchy newSupertypeHierarchy(
458 //      WorkingCopyOwner owner,
459 //      IProgressMonitor monitor)
460 //      throws JavaModelException {
461 //
462 //      ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
463 //      CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), false);
464 //      op.runOperation(monitor);
465 //      return op.getResult();
466 //  }
467   /**
468    * @see IType
469    */
470 //  public ITypeHierarchy newTypeHierarchy(IJavaProject project, IProgressMonitor monitor) throws JavaModelException {
471 //      return newTypeHierarchy(project, DefaultWorkingCopyOwner.PRIMARY, monitor);
472 //  }
473   /**
474    * @see IType#newTypeHierarchy(IJavaProject, WorkingCopyOwner, IProgressMonitor)
475    */
476 //  public ITypeHierarchy newTypeHierarchy(IJavaProject project, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException {
477 //      if (project == null) {
478 //              throw new IllegalArgumentException(Util.bind("hierarchy.nullProject")); //$NON-NLS-1$
479 //      }
480 //      ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
481 //      ICompilationUnit[] projectWCs = null;
482 //      if (workingCopies != null) {
483 //              int length = workingCopies.length;
484 //              projectWCs = new ICompilationUnit[length];
485 //              int index = 0;
486 //              for (int i = 0; i < length; i++) {
487 //                      ICompilationUnit wc = workingCopies[i];
488 //                      if (project.equals(wc.getJavaProject())) {
489 //                              projectWCs[index++] = wc;
490 //                      }
491 //              }
492 //              if (index != length) {
493 //                      System.arraycopy(projectWCs, 0, projectWCs = new ICompilationUnit[index], 0, index);
494 //              }
495 //      }
496 //      CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(
497 //              this, 
498 //              projectWCs,
499 //              project, 
500 //              true);
501 //      op.runOperation(monitor);
502 //      return op.getResult();
503 //  }
504   /**
505    * @see IType
506    */
507 //  public ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor) throws JavaModelException {
508 //      CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, null, SearchEngine.createWorkspaceScope(), true);
509 //      op.runOperation(monitor);
510 //      return op.getResult();
511 //  }
512   /*
513    * @see IType#newTypeHierarchy(ICompilationUnit[], IProgressMonitor)
514    */
515 //  public ITypeHierarchy newTypeHierarchy(
516 //      ICompilationUnit[] workingCopies,
517 //      IProgressMonitor monitor)
518 //      throws JavaModelException {
519 //              
520 //      CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), true);
521 //      op.runOperation(monitor);
522 //      return op.getResult();
523 //  }
524   /**
525    * @see IType#newTypeHierarchy(IWorkingCopy[], IProgressMonitor)
526    * @deprecated
527    */
528   public ITypeHierarchy newTypeHierarchy(
529         IWorkingCopy[] workingCopies,
530         IProgressMonitor monitor)
531         throws JavaModelException {
532                 
533         ICompilationUnit[] copies;
534         if (workingCopies == null) {
535                 copies = null;
536         } else {
537                 int length = workingCopies.length;
538                 System.arraycopy(workingCopies, 0, copies = new ICompilationUnit[length], 0, length);
539         }
540         return newTypeHierarchy(copies, monitor);
541   }
542   /**
543    * @see IType#newTypeHierarchy(WorkingCopyOwner, IProgressMonitor)
544    */
545 //  public ITypeHierarchy newTypeHierarchy(
546 //      WorkingCopyOwner owner,
547 //      IProgressMonitor monitor)
548 //      throws JavaModelException {
549 //              
550 //      ICompilationUnit[] workingCopies = JavaModelManager.getJavaModelManager().getWorkingCopies(owner, true/*add primary working copies*/);
551 //      CreateTypeHierarchyOperation op= new CreateTypeHierarchyOperation(this, workingCopies, SearchEngine.createWorkspaceScope(), true);
552 //      op.runOperation(monitor);
553 //      return op.getResult();  
554 //  }
555
556   // public String[][] resolveType(String typeName) throws JavaModelException {
557   //    ISourceType info = (ISourceType) this.getElementInfo();
558   //    ISearchableNameEnvironment environment = ((JavaProject)getJavaProject()).getSearchableNameEnvironment();
559   //
560   //    class TypeResolveRequestor implements ISelectionRequestor {
561   //            String[][] answers = null;
562   //            void acceptType(String[] answer){
563   //                    if (answers == null) {
564   //                            answers = new String[][]{ answer };
565   //                    } else {
566   //                            // grow
567   //                            int length = answers.length;
568   //                            System.arraycopy(answers, 0, answers = new String[length+1][], 0, length);
569   //                            answers[length] = answer;
570   //                    }
571   //            }
572   //            public void acceptClass(char[] packageName, char[] className, boolean needQualification) {
573   //                    acceptType(new String[] { new String(packageName), new String(className) });
574   //            }
575   //            
576   //            public void acceptInterface(char[] packageName, char[] interfaceName, boolean needQualification) {
577   //                    acceptType(new String[] { new String(packageName), new String(interfaceName) });
578   //            }
579   //
580   //            public void acceptError(IProblem error) {}
581   //            public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] name) {}
582   //            public void acceptMethod(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][]
583   // parameterPackageNames, char[][] parameterTypeNames, boolean isConstructor) {}
584   //            public void acceptPackage(char[] packageName){}
585   //
586   //    }
587   //    TypeResolveRequestor requestor = new TypeResolveRequestor();
588   //    SelectionEngine engine =
589   //            new SelectionEngine(environment, requestor, this.getJavaProject().getOptions(true));
590   //            
591   //    IType[] topLevelTypes = this.getCompilationUnit().getTypes();
592   //    int length = topLevelTypes.length;
593   //    ISourceType[] topLevelInfos = new ISourceType[length];
594   //    for (int i = 0; i < length; i++) {
595   //            topLevelInfos[i] = (ISourceType)((SourceType)topLevelTypes[i]).getElementInfo();
596   //    }
597   //            
598   //    engine.selectType(info, typeName.toCharArray(), topLevelInfos, false);
599   //    return requestor.answers;
600   //}
601   /**
602    * @private Debugging purposes
603    */
604   protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
605     buffer.append(this.tabString(tab));
606     if (info == null) {
607       buffer.append(this.getElementName());
608       buffer.append(" (not open)"); //$NON-NLS-1$
609     } else if (info == NO_INFO) {
610       buffer.append(getElementName());
611     } else {
612       try {
613         if (this.isInterface()) {
614           buffer.append("interface "); //$NON-NLS-1$
615         } else {
616           buffer.append("class "); //$NON-NLS-1$
617         }
618         buffer.append(this.getElementName());
619       } catch (JavaModelException e) {
620         buffer.append("<JavaModelException in toString of " + getElementName()); //$NON-NLS-1$
621       }
622     }
623   }
624 }