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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.corext.util;
13 import java.util.StringTokenizer;
15 import net.sourceforge.phpdt.core.Flags;
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.IMember;
20 import net.sourceforge.phpdt.core.IMethod;
21 import net.sourceforge.phpdt.core.IPackageFragment;
22 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
23 import net.sourceforge.phpdt.core.IType;
24 import net.sourceforge.phpdt.core.JavaModelException;
25 import net.sourceforge.phpdt.core.Signature;
26 import net.sourceforge.phpdt.core.compiler.CharOperation;
27 import net.sourceforge.phpeclipse.phpeditor.EditorUtility;
29 import org.eclipse.core.resources.IResource;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IPath;
36 * Utility methods for the Java Model.
38 public class JavaModelUtil {
41 * Finds a type by its qualified type name (dot separated).
42 * @param jproject The java project to search in
43 * @param str The fully qualified name (type name with enclosing type names and package (all separated by dots))
44 * @return The type found, or null if not existing
46 // public static IType findType(IJavaProject jproject, String fullyQualifiedName) throws JavaModelException {
47 // //workaround for bug 22883
48 // IType type= jproject.findType(fullyQualifiedName);
51 // IPackageFragmentRoot[] roots= jproject.getPackageFragmentRoots();
52 // for (int i= 0; i < roots.length; i++) {
53 // IPackageFragmentRoot root= roots[i];
54 // type= findType(root, fullyQualifiedName);
55 // if (type != null && type.exists())
62 * Returns <code>true</code> if the given package fragment root is
63 * referenced. This means it is own by a different project but is referenced
64 * by the root's parent. Returns <code>false</code> if the given root
65 * doesn't have an underlying resource.
67 public static boolean isReferenced(IPackageFragmentRoot root) {
68 // IResource resource= root.getResource();
69 // if (resource != null) {
70 // IProject jarProject= resource.getProject();
71 // IProject container= root.getJavaProject().getProject();
72 // return !container.equals(jarProject);
77 // private static IType findType(IPackageFragmentRoot root, String fullyQualifiedName) throws JavaModelException{
78 // IJavaElement[] children= root.getChildren();
79 // for (int i= 0; i < children.length; i++) {
80 // IJavaElement element= children[i];
81 // if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT){
82 // IPackageFragment pack= (IPackageFragment)element;
83 // if (! fullyQualifiedName.startsWith(pack.getElementName()))
85 // IType type= findType(pack, fullyQualifiedName);
86 // if (type != null && type.exists())
93 // private static IType findType(IPackageFragment pack, String fullyQualifiedName) throws JavaModelException{
94 // ICompilationUnit[] cus= pack.getCompilationUnits();
95 // for (int i= 0; i < cus.length; i++) {
96 // ICompilationUnit unit= cus[i];
97 // ICompilationUnit wc= WorkingCopyUtil.getWorkingCopyIfExists(unit);
98 // IType type= findType(wc, fullyQualifiedName);
99 // if (type != null && type.exists())
105 // private static IType findType(ICompilationUnit cu, String fullyQualifiedName) throws JavaModelException{
106 // IType[] types= cu.getAllTypes();
107 // for (int i= 0; i < types.length; i++) {
108 // IType type= types[i];
109 // if (getFullyQualifiedName(type).equals(fullyQualifiedName))
116 * Finds a type by package and type name.
117 * @param jproject the java project to search in
118 * @param pack The package name
119 * @param typeQualifiedName the type qualified name (type name with enclosing type names (separated by dots))
120 * @return the type found, or null if not existing
121 * @deprecated Use IJavaProject.findType(String, String) instead
123 // public static IType findType(IJavaProject jproject, String pack, String typeQualifiedName) throws JavaModelException {
124 // return jproject.findType(pack, typeQualifiedName);
128 * Finds a type container by container name.
129 * The returned element will be of type <code>IType</code> or a <code>IPackageFragment</code>.
130 * <code>null</code> is returned if the type container could not be found.
131 * @param jproject The Java project defining the context to search
132 * @param typeContainerName A dot separarted name of the type container
133 * @see #getTypeContainerName(IType)
135 // public static IJavaElement findTypeContainer(IJavaProject jproject, String typeContainerName) throws JavaModelException {
136 // // try to find it as type
137 // IJavaElement result= jproject.findType(typeContainerName);
138 // if (result == null) {
139 // // find it as package
140 // IPath path= new Path(typeContainerName.replace('.', '/'));
141 // result= jproject.findElement(path);
142 // if (!(result instanceof IPackageFragment)) {
151 * Finds a type in a compilation unit. Typical usage is to find the corresponding
152 * type in a working copy.
153 * @param cu the compilation unit to search in
154 * @param typeQualifiedName the type qualified name (type name with enclosing type names (separated by dots))
155 * @return the type found, or null if not existing
157 public static IType findTypeInCompilationUnit(ICompilationUnit cu, String typeQualifiedName) throws JavaModelException {
158 IType[] types= cu.getAllTypes();
159 for (int i= 0; i < types.length; i++) {
160 String currName= getTypeQualifiedName(types[i]);
161 if (typeQualifiedName.equals(currName)) {
169 * Finds a a member in a compilation unit. Typical usage is to find the corresponding
170 * member in a working copy.
171 * @param cu the compilation unit (eg. working copy) to search in
172 * @param member the member (eg. from the original)
173 * @return the member found, or null if not existing
175 public static IMember findMemberInCompilationUnit(ICompilationUnit cu, IMember member) throws JavaModelException {
176 IJavaElement[] elements= cu.findElements(member);
177 if (elements != null && elements.length > 0) {
178 return (IMember) elements[0];
185 * Returns the element of the given compilation unit which is "equal" to the
186 * given element. Note that the given element usually has a parent different
187 * from the given compilation unit.
189 * @param cu the cu to search in
190 * @param element the element to look for
191 * @return an element of the given cu "equal" to the given element
193 public static IJavaElement findInCompilationUnit(ICompilationUnit cu, IJavaElement element) throws JavaModelException {
194 IJavaElement[] elements= cu.findElements(element);
195 if (elements != null && elements.length > 0) {
202 * Returns the qualified type name of the given type using '.' as separators.
203 * This is a replace for IType.getTypeQualifiedName()
204 * which uses '$' as separators. As '$' is also a valid character in an id
205 * this is ambiguous. JavaCore PR: 1GCFUNT
207 public static String getTypeQualifiedName(IType type) {
208 return type.getTypeQualifiedName('.');
211 private static void getTypeQualifiedName(IType type, StringBuffer buf) {
212 IType outerType= type.getDeclaringType();
213 if (outerType != null) {
214 getTypeQualifiedName(outerType, buf);
217 buf.append(type.getElementName());
221 * Returns the fully qualified name of the given type using '.' as separators.
222 * This is a replace for IType.getFullyQualifiedTypeName
223 * which uses '$' as separators. As '$' is also a valid character in an id
224 * this is ambiguous. JavaCore PR: 1GCFUNT
226 public static String getFullyQualifiedName(IType type) {
227 return type.getFullyQualifiedName('.');
231 * Returns the fully qualified name of a type's container. (package name or enclosing type name)
233 public static String getTypeContainerName(IType type) {
234 IType outerType= type.getDeclaringType();
235 if (outerType != null) {
236 return outerType.getFullyQualifiedName('.');
238 return type.getPackageFragment().getElementName();
244 * Concatenates two names. Uses a dot for separation.
245 * Both strings can be empty or <code>null</code>.
247 public static String concatenateName(String name1, String name2) {
248 StringBuffer buf= new StringBuffer();
249 if (name1 != null && name1.length() > 0) {
252 if (name2 != null && name2.length() > 0) {
253 if (buf.length() > 0) {
258 return buf.toString();
262 * Concatenates two names. Uses a dot for separation.
263 * Both strings can be empty or <code>null</code>.
265 public static String concatenateName(char[] name1, char[] name2) {
266 StringBuffer buf= new StringBuffer();
267 if (name1 != null && name1.length > 0) {
270 if (name2 != null && name2.length > 0) {
271 if (buf.length() > 0) {
276 return buf.toString();
280 * Evaluates if a member (possible from another package) is visible from
281 * elements in a package.
282 * @param member The member to test the visibility for
283 * @param pack The package in focus
285 public static boolean isVisible(IMember member, IPackageFragment pack) throws JavaModelException {
286 int otherflags= member.getFlags();
288 if (Flags.isPublic(otherflags)) {
290 } else if (Flags.isPrivate(otherflags)) {
294 IPackageFragment otherpack= (IPackageFragment) findParentOfKind(member, IJavaElement.PACKAGE_FRAGMENT);
295 return (pack != null && pack.equals(otherpack));
299 * Returns the package fragment root of <code>IJavaElement</code>. If the given
300 * element is already a package fragment root, the element itself is returned.
302 public static IPackageFragmentRoot getPackageFragmentRoot(IJavaElement element) {
303 return (IPackageFragmentRoot) element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
307 * Returns the parent of the supplied java element that conforms to the given
308 * parent type or <code>null</code>, if such a parent doesn't exit.
309 * @deprecated Use element.getParent().getAncestor(kind);
311 public static IJavaElement findParentOfKind(IJavaElement element, int kind) {
312 if (element != null && element.getParent() != null) {
313 return element.getParent().getAncestor(kind);
319 * Finds a method in a type.
320 * This searches for a method with the same name and signature. Parameter types are only
321 * compared by the simple name, no resolving for the fully qualified type name is done.
322 * Constructors are only compared by parameters, not the name.
323 * @param name The name of the method to find
324 * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
325 * @param isConstructor If the method is a constructor
326 * @return The first found method or <code>null</code>, if nothing found
328 public static IMethod findMethod(String name, String[] paramTypes, boolean isConstructor, IType type) throws JavaModelException {
329 return findMethod(name, paramTypes, isConstructor, type.getMethods());
333 * Finds a method by name.
334 * This searches for a method with a name and signature. Parameter types are only
335 * compared by the simple name, no resolving for the fully qualified type name is done.
336 * Constructors are only compared by parameters, not the name.
337 * @param name The name of the method to find
338 * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
339 * @param isConstructor If the method is a constructor
340 * @param methods The methods to search in
341 * @return The found method or <code>null</code>, if nothing found
343 public static IMethod findMethod(String name, String[] paramTypes, boolean isConstructor, IMethod[] methods) throws JavaModelException {
344 for (int i= methods.length - 1; i >= 0; i--) {
345 if (isSameMethodSignature(name, paramTypes, isConstructor, methods[i])) {
354 * Finds a method declararion in a type's hierarchy. The search is top down, so this
355 * returns the first declaration of the method in the hierarchy.
356 * This searches for a method with a name and signature. Parameter types are only
357 * compared by the simple name, no resolving for the fully qualified type name is done.
358 * Constructors are only compared by parameters, not the name.
359 * @param type Searches in this type's supertypes.
360 * @param name The name of the method to find
361 * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
362 * @param isConstructor If the method is a constructor
363 * @return The first method found or null, if nothing found
365 // public static IMethod findMethodDeclarationInHierarchy(ITypeHierarchy hierarchy, IType type, String name, String[] paramTypes, boolean isConstructor) throws JavaModelException {
366 // IType[] superTypes= hierarchy.getAllSupertypes(type);
367 // for (int i= superTypes.length - 1; i >= 0; i--) {
368 // IMethod first= findMethod(name, paramTypes, isConstructor, superTypes[i]);
369 // if (first != null && !Flags.isPrivate(first.getFlags())) {
370 // // the order getAllSupertypes does make assumptions of the order of inner elements -> search recursivly
371 // IMethod res= findMethodDeclarationInHierarchy(hierarchy, first.getDeclaringType(), name, paramTypes, isConstructor);
372 // if (res != null) {
382 * Finds a method implementation in a type's classhierarchy. The search is bottom-up, so this
383 * returns the nearest overridden method. Does not find methods in interfaces or abstract methods.
384 * This searches for a method with a name and signature. Parameter types are only
385 * compared by the simple name, no resolving for the fully qualified type name is done.
386 * Constructors are only compared by parameters, not the name.
387 * @param type Type to search the superclasses
388 * @param name The name of the method to find
389 * @param paramTypes The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
390 * @param isConstructor If the method is a constructor
391 * @return The first method found or null, if nothing found
393 // public static IMethod findMethodImplementationInHierarchy(ITypeHierarchy hierarchy, IType type, String name, String[] paramTypes, boolean isConstructor) throws JavaModelException {
394 // IType[] superTypes= hierarchy.getAllSuperclasses(type);
395 // for (int i= 0; i < superTypes.length; i++) {
396 // IMethod found= findMethod(name, paramTypes, isConstructor, superTypes[i]);
397 // if (found != null) {
398 // if (Flags.isAbstract(found.getFlags())) {
408 * Tests if a method equals to the given signature.
409 * Parameter types are only compared by the simple name, no resolving for
410 * the fully qualified type name is done. Constructors are only compared by
411 * parameters, not the name.
412 * @param Name of the method
413 * @param The type signatures of the parameters e.g. <code>{"QString;","I"}</code>
414 * @param Specifies if the method is a constructor
415 * @return Returns <code>true</code> if the method has the given name and parameter types and constructor state.
417 public static boolean isSameMethodSignature(String name, String[] paramTypes, boolean isConstructor, IMethod curr) throws JavaModelException {
418 if (isConstructor || name.equals(curr.getElementName())) {
419 if (isConstructor == curr.isConstructor()) {
420 String[] currParamTypes= curr.getParameterTypes();
421 if (paramTypes.length == currParamTypes.length) {
422 for (int i= 0; i < paramTypes.length; i++) {
423 String t1= Signature.getSimpleName(Signature.toString(paramTypes[i]));
424 String t2= Signature.getSimpleName(Signature.toString(currParamTypes[i]));
425 if (!t1.equals(t2)) {
437 * Checks whether the given type has a valid main method or not.
439 public static boolean hasMainMethod(IType type) throws JavaModelException {
440 IMethod[] methods= type.getMethods();
441 for (int i= 0; i < methods.length; i++) {
442 if (methods[i].isMainMethod()) {
450 * Checks if the field is boolean.
452 public static boolean isBoolean(IField field) throws JavaModelException{
453 return field.getTypeSignature().equals(Signature.SIG_BOOLEAN);
457 * Returns true if the element is on the build path of the given project
458 * @deprecated Use jproject.isOnClasspath(element);
460 // public static boolean isOnBuildPath(IJavaProject jproject, IJavaElement element) throws JavaModelException {
461 // return jproject.isOnClasspath(element);
465 * Tests if the given element is on the class path of its containing project. Handles the case
466 * that the containing project isn't a Java project.
468 // public static boolean isOnClasspath(IJavaElement element) {
469 // IJavaProject project= element.getJavaProject();
470 // if (!project.exists())
472 // return project.isOnClasspath(element);
476 * Resolves a type name in the context of the declaring type.
477 * @param refTypeSig the type name in signature notation (for example 'QVector')
478 * this can also be an array type, but dimensions will be ignored.
479 * @param declaringType the context for resolving (type where the reference was made in)
480 * @return returns the fully qualified type name or build-in-type name.
481 * if a unresoved type couldn't be resolved null is returned
483 public static String getResolvedTypeName(String refTypeSig, IType declaringType) throws JavaModelException {
484 int arrayCount= Signature.getArrayCount(refTypeSig);
485 char type= refTypeSig.charAt(arrayCount);
486 if (type == Signature.C_UNRESOLVED) {
487 int semi= refTypeSig.indexOf(Signature.C_SEMICOLON, arrayCount + 1);
489 throw new IllegalArgumentException();
491 String name= refTypeSig.substring(arrayCount + 1, semi);
493 // String[][] resolvedNames= declaringType.resolveType(name);
494 // if (resolvedNames != null && resolvedNames.length > 0) {
495 // return JavaModelUtil.concatenateName(resolvedNames[0][0], resolvedNames[0][1]);
499 return Signature.toString(refTypeSig.substring(arrayCount));
504 * Returns if a CU can be edited.
506 public static boolean isEditable(ICompilationUnit cu) {
507 if (cu.isWorkingCopy()) {
508 cu= (ICompilationUnit) cu.getOriginalElement();
510 IResource resource= cu.getResource();
511 return (resource.exists() && !resource.isReadOnly());
515 * Finds a qualified import for a type name.
517 // public static IImportDeclaration findImport(ICompilationUnit cu, String simpleName) throws JavaModelException {
518 // IImportDeclaration[] existing= cu.getImports();
519 // for (int i= 0; i < existing.length; i++) {
520 // String curr= existing[i].getElementName();
521 // if (curr.endsWith(simpleName)) {
522 // int dotPos= curr.length() - simpleName.length() - 1;
523 // if ((dotPos == -1) || (dotPos > 0 && curr.charAt(dotPos) == '.')) {
524 // return existing[i];
532 * Returns the original if the given member. If the member is already
533 * an original the input is returned. The returned member must not exist
535 public static IMember toOriginal(IMember member) {
536 if (member instanceof IMethod)
537 return toOriginalMethod((IMethod)member);
538 ICompilationUnit cu= member.getCompilationUnit();
539 if (cu != null && cu.isWorkingCopy())
540 return (IMember)cu.getOriginal(member);
545 * XXX workaround for bug 18568
546 * http://bugs.eclipse.org/bugs/show_bug.cgi?id=18568
547 * to be removed once the bug is fixed
549 private static IMethod toOriginalMethod(IMethod method) {
551 ICompilationUnit cu= method.getCompilationUnit();
552 if (cu == null || ! cu.isWorkingCopy())
554 //use the workaround only if needed
555 if (! method.getElementName().equals(method.getDeclaringType().getElementName()))
556 return (IMethod)cu.getOriginal(method);
558 IType originalType = (IType)toOriginal(method.getDeclaringType());
559 IMethod[] methods = originalType.findMethods(method);
560 boolean isConstructor = method.isConstructor();
561 for (int i=0; i < methods.length; i++) {
562 if (methods[i].isConstructor() == isConstructor)
566 } catch(JavaModelException e){
572 * Returns the original cu if the given cu. If the cu is already
573 * an original the input cu is returned. The returned cu must not exist
575 public static ICompilationUnit toOriginal(ICompilationUnit cu) {
576 if (cu != null && cu.isWorkingCopy())
577 return (ICompilationUnit) cu.getOriginal(cu);
582 * Returns the working copy of the given member. If the member is already in a
583 * working copy or the member does not exist in the working copy the input is returned.
585 public static IMember toWorkingCopy(IMember member) {
586 ICompilationUnit cu= member.getCompilationUnit();
587 if (cu != null && !cu.isWorkingCopy()) {
588 ICompilationUnit workingCopy= EditorUtility.getWorkingCopy(cu);
589 if (workingCopy != null) {
590 IJavaElement[] members= workingCopy.findElements(member);
591 if (members != null && members.length > 0) {
592 return (IMember) members[0];
601 * Returns the working copy CU of the given CU. If the CU is already a
602 * working copy or the CU has no working copy the input CU is returned.
604 public static ICompilationUnit toWorkingCopy(ICompilationUnit cu) {
605 if (!cu.isWorkingCopy()) {
606 ICompilationUnit workingCopy= EditorUtility.getWorkingCopy(cu);
607 if (workingCopy != null) {
615 * http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
617 * Reconciling happens in a separate thread. This can cause a situation where the
618 * Java element gets disposed after an exists test has been done. So we should not
619 * log not present exceptions when they happen in working copies.
621 public static boolean filterNotPresentException(CoreException exception) {
622 if (!(exception instanceof JavaModelException))
624 JavaModelException je= (JavaModelException)exception;
625 if (!je.isDoesNotExist())
627 IJavaElement[] elements= je.getJavaModelStatus().getElements();
628 for (int i= 0; i < elements.length; i++) {
629 IJavaElement element= elements[i];
630 ICompilationUnit unit= (ICompilationUnit)element.getAncestor(IJavaElement.COMPILATION_UNIT);
633 if (!unit.isWorkingCopy())
639 // public static IType[] getAllSuperTypes(IType type, IProgressMonitor pm) throws JavaModelException {
640 // //workaround for bugs 23644 and 23656
642 // pm.beginTask("", 3); //$NON-NLS-1$
643 // ITypeHierarchy hierarchy= type.newSupertypeHierarchy(new SubProgressMonitor(pm, 1));
645 // IProgressMonitor subPm= new SubProgressMonitor(pm, 2);
646 // List typeList= Arrays.asList(hierarchy.getAllSupertypes(type));
647 // subPm.beginTask("", typeList.size()); //$NON-NLS-1$
648 // Set types= new HashSet(typeList);
649 // for (Iterator iter= typeList.iterator(); iter.hasNext();) {
650 // IType superType= (IType)iter.next();
651 // IType[] superTypes= getAllSuperTypes(superType, new SubProgressMonitor(subPm, 1));
652 // types.addAll(Arrays.asList(superTypes));
654 // types.add(type.getJavaProject().findType("java.lang.Object"));//$NON-NLS-1$
656 // return (IType[]) types.toArray(new IType[types.size()]);
663 public static boolean isExcludedPath(IPath resourcePath, IPath[] exclusionPatterns) {
664 char[] path = resourcePath.toString().toCharArray();
665 for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
666 char[] pattern= exclusionPatterns[i].toString().toCharArray();
667 if (CharOperation.pathMatch(pattern, path, true, '/')) {
676 * Returns whether the given resource path matches one of the exclusion
679 * @see IClasspathEntry#getExclusionPatterns
681 public final static boolean isExcluded(IPath resourcePath, char[][] exclusionPatterns) {
682 if (exclusionPatterns == null) return false;
683 char[] path = resourcePath.toString().toCharArray();
684 for (int i = 0, length = exclusionPatterns.length; i < length; i++)
685 if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/'))
691 private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
692 private static final String EMPTY_ARGUMENT = " "; //$NON-NLS-1$
695 * Copied from net.sourceforge.phpdt.internal.core.ProjectPrefUtil;
697 public static String[] getProblemArgumentsFromMarker(String argumentsString){
698 if (argumentsString == null) return null;
699 int index = argumentsString.indexOf(':');
703 int length = argumentsString.length();
706 numberOfArg = Integer.parseInt(argumentsString.substring(0 , index));
707 } catch (NumberFormatException e) {
710 argumentsString = argumentsString.substring(index + 1, length);
712 String[] args = new String[length];
715 StringTokenizer tokenizer = new StringTokenizer(argumentsString, ARGUMENTS_DELIMITER);
716 while(tokenizer.hasMoreTokens()) {
717 String argument = tokenizer.nextToken();
718 if(argument.equals(EMPTY_ARGUMENT))
719 argument = ""; //$NON-NLS-1$
720 args[count++] = argument;
723 if(count != numberOfArg)
726 System.arraycopy(args, 0, args = new String[count], 0, count);