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;
34 * Utility methods for the Java Model.
36 public class JavaModelUtil {
39 * Finds a type by its qualified type name (dot separated).
42 * The java project to search in
44 * The fully qualified name (type name with enclosing type names
45 * and package (all separated by dots))
46 * @return The type found, or null if not existing
48 // public static IType findType(IJavaProject jproject, String
49 // fullyQualifiedName) throws JavaModelException {
50 // //workaround for bug 22883
51 // IType type= jproject.findType(fullyQualifiedName);
54 // IPackageFragmentRoot[] roots= jproject.getPackageFragmentRoots();
55 // for (int i= 0; i < roots.length; i++) {
56 // IPackageFragmentRoot root= roots[i];
57 // type= findType(root, fullyQualifiedName);
58 // if (type != null && type.exists())
64 * Returns <code>true</code> if the given package fragment root is
65 * referenced. This means it is own by a different project but is referenced
66 * by the root's parent. Returns <code>false</code> if the given root
67 * doesn't have an underlying resource.
69 public static boolean isReferenced(IPackageFragmentRoot root) {
70 // IResource resource= root.getResource();
71 // if (resource != null) {
72 // IProject jarProject= resource.getProject();
73 // IProject container= root.getJavaProject().getProject();
74 // return !container.equals(jarProject);
79 // private static IType findType(IPackageFragmentRoot root, String
80 // fullyQualifiedName) throws JavaModelException{
81 // IJavaElement[] children= root.getChildren();
82 // for (int i= 0; i < children.length; i++) {
83 // IJavaElement element= children[i];
84 // if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT){
85 // IPackageFragment pack= (IPackageFragment)element;
86 // if (! fullyQualifiedName.startsWith(pack.getElementName()))
88 // IType type= findType(pack, fullyQualifiedName);
89 // if (type != null && type.exists())
96 // private static IType findType(IPackageFragment pack, String
97 // fullyQualifiedName) throws JavaModelException{
98 // ICompilationUnit[] cus= pack.getCompilationUnits();
99 // for (int i= 0; i < cus.length; i++) {
100 // ICompilationUnit unit= cus[i];
101 // ICompilationUnit wc= WorkingCopyUtil.getWorkingCopyIfExists(unit);
102 // IType type= findType(wc, fullyQualifiedName);
103 // if (type != null && type.exists())
109 // private static IType findType(ICompilationUnit cu, String
110 // fullyQualifiedName) throws JavaModelException{
111 // IType[] types= cu.getAllTypes();
112 // for (int i= 0; i < types.length; i++) {
113 // IType type= types[i];
114 // if (getFullyQualifiedName(type).equals(fullyQualifiedName))
121 * Finds a type by package and type name.
124 * the java project to search in
127 * @param typeQualifiedName
128 * the type qualified name (type name with enclosing type names
129 * (separated by dots))
130 * @return the type found, or null if not existing
131 * @deprecated Use IJavaProject.findType(String, String) instead
133 // public static IType findType(IJavaProject jproject, String pack, String
134 // typeQualifiedName) throws JavaModelException {
135 // return jproject.findType(pack, typeQualifiedName);
138 * Finds a type container by container name. The returned element will be of
139 * type <code>IType</code> or a <code>IPackageFragment</code>.
140 * <code>null</code> is returned if the type container could not be found.
143 * The Java project defining the context to search
144 * @param typeContainerName
145 * A dot separarted name of the type container
146 * @see #getTypeContainerName(IType)
148 // public static IJavaElement findTypeContainer(IJavaProject jproject,
149 // String typeContainerName) throws JavaModelException {
150 // // try to find it as type
151 // IJavaElement result= jproject.findType(typeContainerName);
152 // if (result == null) {
153 // // find it as package
154 // IPath path= new Path(typeContainerName.replace('.', '/'));
155 // result= jproject.findElement(path);
156 // if (!(result instanceof IPackageFragment)) {
164 * Finds a type in a compilation unit. Typical usage is to find the
165 * corresponding type in a working copy.
168 * the compilation unit to search in
169 * @param typeQualifiedName
170 * the type qualified name (type name with enclosing type names
171 * (separated by dots))
172 * @return the type found, or null if not existing
174 public static IType findTypeInCompilationUnit(ICompilationUnit cu,
175 String typeQualifiedName) throws JavaModelException {
176 IType[] types = cu.getAllTypes();
177 for (int i = 0; i < types.length; i++) {
178 String currName = getTypeQualifiedName(types[i]);
179 if (typeQualifiedName.equals(currName)) {
187 * Finds a a member in a compilation unit. Typical usage is to find the
188 * corresponding member in a working copy.
191 * the compilation unit (eg. working copy) to search in
193 * the member (eg. from the original)
194 * @return the member found, or null if not existing
196 public static IMember findMemberInCompilationUnit(ICompilationUnit cu,
197 IMember member) throws JavaModelException {
198 IJavaElement[] elements = cu.findElements(member);
199 if (elements != null && elements.length > 0) {
200 return (IMember) elements[0];
206 * Returns the element of the given compilation unit which is "equal" to the
207 * given element. Note that the given element usually has a parent different
208 * from the given compilation unit.
211 * the cu to search in
213 * the element to look for
214 * @return an element of the given cu "equal" to the given element
216 public static IJavaElement findInCompilationUnit(ICompilationUnit cu,
217 IJavaElement element) throws JavaModelException {
218 IJavaElement[] elements = cu.findElements(element);
219 if (elements != null && elements.length > 0) {
226 * Returns the qualified type name of the given type using '.' as
227 * separators. This is a replace for IType.getTypeQualifiedName() which uses
228 * '$' as separators. As '$' is also a valid character in an id this is
229 * ambiguous. JavaCore PR: 1GCFUNT
231 public static String getTypeQualifiedName(IType type) {
232 return type.getTypeQualifiedName('.');
235 private static void getTypeQualifiedName(IType type, StringBuffer buf) {
236 IType outerType = type.getDeclaringType();
237 if (outerType != null) {
238 getTypeQualifiedName(outerType, buf);
241 buf.append(type.getElementName());
245 * Returns the fully qualified name of the given type using '.' as
246 * separators. This is a replace for IType.getFullyQualifiedTypeName which
247 * uses '$' as separators. As '$' is also a valid character in an id this is
248 * ambiguous. JavaCore PR: 1GCFUNT
250 public static String getFullyQualifiedName(IType type) {
251 return type.getFullyQualifiedName('.');
255 * Returns the fully qualified name of a type's container. (package name or
256 * enclosing type name)
258 public static String getTypeContainerName(IType type) {
259 IType outerType = type.getDeclaringType();
260 if (outerType != null) {
261 return outerType.getFullyQualifiedName('.');
263 return type.getPackageFragment().getElementName();
268 * Concatenates two names. Uses a dot for separation. Both strings can be
269 * empty or <code>null</code>.
271 public static String concatenateName(String name1, String name2) {
272 StringBuffer buf = new StringBuffer();
273 if (name1 != null && name1.length() > 0) {
276 if (name2 != null && name2.length() > 0) {
277 if (buf.length() > 0) {
282 return buf.toString();
286 * Concatenates two names. Uses a dot for separation. Both strings can be
287 * empty or <code>null</code>.
289 public static String concatenateName(char[] name1, char[] name2) {
290 StringBuffer buf = new StringBuffer();
291 if (name1 != null && name1.length > 0) {
294 if (name2 != null && name2.length > 0) {
295 if (buf.length() > 0) {
300 return buf.toString();
304 * Evaluates if a member (possible from another package) is visible from
305 * elements in a package.
308 * The member to test the visibility for
310 * The package in focus
312 public static boolean isVisible(IMember member, IPackageFragment pack)
313 throws JavaModelException {
314 int otherflags = member.getFlags();
316 if (Flags.isPublic(otherflags)) {
318 } else if (Flags.isPrivate(otherflags)) {
322 IPackageFragment otherpack = (IPackageFragment) findParentOfKind(
323 member, IJavaElement.PACKAGE_FRAGMENT);
324 return (pack != null && pack.equals(otherpack));
328 * Returns the package fragment root of <code>IJavaElement</code>. If the
329 * given element is already a package fragment root, the element itself is
332 public static IPackageFragmentRoot getPackageFragmentRoot(
333 IJavaElement element) {
334 return (IPackageFragmentRoot) element
335 .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
339 * Returns the parent of the supplied java element that conforms to the
340 * given parent type or <code>null</code>, if such a parent doesn't exit.
342 * @deprecated Use element.getParent().getAncestor(kind);
344 public static IJavaElement findParentOfKind(IJavaElement element, int kind) {
345 if (element != null && element.getParent() != null) {
346 return element.getParent().getAncestor(kind);
352 * Finds a method in a type. This searches for a method with the same name
353 * and signature. Parameter types are only compared by the simple name, no
354 * resolving for the fully qualified type name is done. Constructors are
355 * only compared by parameters, not the name.
358 * The name of the method to find
360 * The type signatures of the parameters e.g.
361 * <code>{"QString;","I"}</code>
362 * @param isConstructor
363 * If the method is a constructor
364 * @return The first found method or <code>null</code>, if nothing found
366 public static IMethod findMethod(String name, String[] paramTypes,
367 boolean isConstructor, IType type) throws JavaModelException {
368 return findMethod(name, paramTypes, isConstructor, type.getMethods());
372 * Finds a method by name. This searches for a method with a name and
373 * signature. Parameter types are only compared by the simple name, no
374 * resolving for the fully qualified type name is done. Constructors are
375 * only compared by parameters, not the name.
378 * The name of the method to find
380 * The type signatures of the parameters e.g.
381 * <code>{"QString;","I"}</code>
382 * @param isConstructor
383 * If the method is a constructor
385 * The methods to search in
386 * @return The found method or <code>null</code>, if nothing found
388 public static IMethod findMethod(String name, String[] paramTypes,
389 boolean isConstructor, IMethod[] methods) throws JavaModelException {
390 for (int i = methods.length - 1; i >= 0; i--) {
391 if (isSameMethodSignature(name, paramTypes, isConstructor,
400 * Finds a method declararion in a type's hierarchy. The search is top down,
401 * so this returns the first declaration of the method in the hierarchy.
402 * This searches for a method with a name and signature. Parameter types are
403 * only compared by the simple name, no resolving for the fully qualified
404 * type name is done. Constructors are only compared by parameters, not the
408 * Searches in this type's supertypes.
410 * The name of the method to find
412 * The type signatures of the parameters e.g.
413 * <code>{"QString;","I"}</code>
414 * @param isConstructor
415 * If the method is a constructor
416 * @return The first method found or null, if nothing found
418 // public static IMethod findMethodDeclarationInHierarchy(ITypeHierarchy
419 // hierarchy, IType type, String name, String[] paramTypes, boolean
420 // isConstructor) throws JavaModelException {
421 // IType[] superTypes= hierarchy.getAllSupertypes(type);
422 // for (int i= superTypes.length - 1; i >= 0; i--) {
423 // IMethod first= findMethod(name, paramTypes, isConstructor,
425 // if (first != null && !Flags.isPrivate(first.getFlags())) {
426 // // the order getAllSupertypes does make assumptions of the order of inner
427 // elements -> search recursivly
428 // IMethod res= findMethodDeclarationInHierarchy(hierarchy,
429 // first.getDeclaringType(), name, paramTypes, isConstructor);
430 // if (res != null) {
439 * Finds a method implementation in a type's classhierarchy. The search is
440 * bottom-up, so this returns the nearest overridden method. Does not find
441 * methods in interfaces or abstract methods. This searches for a method
442 * with a name and signature. Parameter types are only compared by the
443 * simple name, no resolving for the fully qualified type name is done.
444 * Constructors are only compared by parameters, not the name.
447 * Type to search the superclasses
449 * The name of the method to find
451 * The type signatures of the parameters e.g.
452 * <code>{"QString;","I"}</code>
453 * @param isConstructor
454 * If the method is a constructor
455 * @return The first method found or null, if nothing found
457 // public static IMethod findMethodImplementationInHierarchy(ITypeHierarchy
458 // hierarchy, IType type, String name, String[] paramTypes, boolean
459 // isConstructor) throws JavaModelException {
460 // IType[] superTypes= hierarchy.getAllSuperclasses(type);
461 // for (int i= 0; i < superTypes.length; i++) {
462 // IMethod found= findMethod(name, paramTypes, isConstructor,
464 // if (found != null) {
465 // if (Flags.isAbstract(found.getFlags())) {
474 * Tests if a method equals to the given signature. Parameter types are only
475 * compared by the simple name, no resolving for the fully qualified type
476 * name is done. Constructors are only compared by parameters, not the name.
481 * type signatures of the parameters e.g.
482 * <code>{"QString;","I"}</code>
484 * if the method is a constructor
485 * @return Returns <code>true</code> if the method has the given name and
486 * parameter types and constructor state.
488 public static boolean isSameMethodSignature(String name,
489 String[] paramTypes, boolean isConstructor, IMethod curr)
490 throws JavaModelException {
491 if (isConstructor || name.equals(curr.getElementName())) {
492 if (isConstructor == curr.isConstructor()) {
493 String[] currParamTypes = curr.getParameterTypes();
494 if (paramTypes.length == currParamTypes.length) {
495 for (int i = 0; i < paramTypes.length; i++) {
496 String t1 = Signature.getSimpleName(Signature
497 .toString(paramTypes[i]));
498 String t2 = Signature.getSimpleName(Signature
499 .toString(currParamTypes[i]));
500 if (!t1.equals(t2)) {
512 * Checks whether the given type has a valid main method or not.
514 public static boolean hasMainMethod(IType type) throws JavaModelException {
515 IMethod[] methods = type.getMethods();
516 for (int i = 0; i < methods.length; i++) {
517 if (methods[i].isMainMethod()) {
525 * Checks if the field is boolean.
527 public static boolean isBoolean(IField field) throws JavaModelException {
528 return field.getTypeSignature().equals(Signature.SIG_BOOLEAN);
532 * Returns true if the element is on the build path of the given project
534 * @deprecated Use jproject.isOnClasspath(element);
536 // public static boolean isOnBuildPath(IJavaProject jproject, IJavaElement
537 // element) throws JavaModelException {
538 // return jproject.isOnClasspath(element);
541 * Tests if the given element is on the class path of its containing
542 * project. Handles the case that the containing project isn't a Java
545 // public static boolean isOnClasspath(IJavaElement element) {
546 // IJavaProject project= element.getJavaProject();
547 // if (!project.exists())
549 // return project.isOnClasspath(element);
552 * Resolves a type name in the context of the declaring type.
555 * the type name in signature notation (for example 'QVector')
556 * this can also be an array type, but dimensions will be
558 * @param declaringType
559 * the context for resolving (type where the reference was made
561 * @return returns the fully qualified type name or build-in-type name. if a
562 * unresoved type couldn't be resolved null is returned
564 public static String getResolvedTypeName(String refTypeSig,
565 IType declaringType) throws JavaModelException {
566 int arrayCount = Signature.getArrayCount(refTypeSig);
567 char type = refTypeSig.charAt(arrayCount);
568 if (type == Signature.C_UNRESOLVED) {
569 int semi = refTypeSig
570 .indexOf(Signature.C_SEMICOLON, arrayCount + 1);
572 throw new IllegalArgumentException();
574 String name = refTypeSig.substring(arrayCount + 1, semi);
576 // String[][] resolvedNames= declaringType.resolveType(name);
577 // if (resolvedNames != null && resolvedNames.length > 0) {
578 // return JavaModelUtil.concatenateName(resolvedNames[0][0],
579 // resolvedNames[0][1]);
583 return Signature.toString(refTypeSig.substring(arrayCount));
588 * Returns if a CU can be edited.
590 public static boolean isEditable(ICompilationUnit cu) {
591 if (cu.isWorkingCopy()) {
592 cu = (ICompilationUnit) cu.getOriginalElement();
594 IResource resource = cu.getResource();
595 return (resource.exists() && !resource.getResourceAttributes()
600 * Finds a qualified import for a type name.
602 // public static IImportDeclaration findImport(ICompilationUnit cu, String
603 // simpleName) throws JavaModelException {
604 // IImportDeclaration[] existing= cu.getImports();
605 // for (int i= 0; i < existing.length; i++) {
606 // String curr= existing[i].getElementName();
607 // if (curr.endsWith(simpleName)) {
608 // int dotPos= curr.length() - simpleName.length() - 1;
609 // if ((dotPos == -1) || (dotPos > 0 && curr.charAt(dotPos) == '.')) {
610 // return existing[i];
617 * Returns the original if the given member. If the member is already an
618 * original the input is returned. The returned member must not exist
620 public static IMember toOriginal(IMember member) {
621 if (member instanceof IMethod)
622 return toOriginalMethod((IMethod) member);
623 ICompilationUnit cu = member.getCompilationUnit();
624 if (cu != null && cu.isWorkingCopy())
625 return (IMember) cu.getOriginal(member);
630 * XXX workaround for bug 18568
631 * http://bugs.eclipse.org/bugs/show_bug.cgi?id=18568 to be removed once the
634 private static IMethod toOriginalMethod(IMethod method) {
636 ICompilationUnit cu = method.getCompilationUnit();
637 if (cu == null || !cu.isWorkingCopy())
639 // use the workaround only if needed
640 if (!method.getElementName().equals(
641 method.getDeclaringType().getElementName()))
642 return (IMethod) cu.getOriginal(method);
644 IType originalType = (IType) toOriginal(method.getDeclaringType());
645 IMethod[] methods = originalType.findMethods(method);
646 boolean isConstructor = method.isConstructor();
647 for (int i = 0; i < methods.length; i++) {
648 if (methods[i].isConstructor() == isConstructor)
652 } catch (JavaModelException e) {
658 * Returns the original cu if the given cu. If the cu is already an original
659 * the input cu is returned. The returned cu must not exist
661 public static ICompilationUnit toOriginal(ICompilationUnit cu) {
662 if (cu != null && cu.isWorkingCopy())
663 return (ICompilationUnit) cu.getOriginal(cu);
668 * Returns the working copy of the given member. If the member is already in
669 * a working copy or the member does not exist in the working copy the input
672 public static IMember toWorkingCopy(IMember member) {
673 ICompilationUnit cu = member.getCompilationUnit();
674 if (cu != null && !cu.isWorkingCopy()) {
675 ICompilationUnit workingCopy = EditorUtility.getWorkingCopy(cu);
676 if (workingCopy != null) {
677 IJavaElement[] members = workingCopy.findElements(member);
678 if (members != null && members.length > 0) {
679 return (IMember) members[0];
687 * Returns the working copy CU of the given CU. If the CU is already a
688 * working copy or the CU has no working copy the input CU is returned.
690 public static ICompilationUnit toWorkingCopy(ICompilationUnit cu) {
691 if (!cu.isWorkingCopy()) {
692 ICompilationUnit workingCopy = EditorUtility.getWorkingCopy(cu);
693 if (workingCopy != null) {
701 * http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
703 * Reconciling happens in a separate thread. This can cause a situation
704 * where the Java element gets disposed after an exists test has been done.
705 * So we should not log not present exceptions when they happen in working
708 public static boolean filterNotPresentException(CoreException exception) {
709 if (!(exception instanceof JavaModelException))
711 JavaModelException je = (JavaModelException) exception;
712 if (!je.isDoesNotExist())
714 IJavaElement[] elements = je.getJavaModelStatus().getElements();
715 for (int i = 0; i < elements.length; i++) {
716 IJavaElement element = elements[i];
717 ICompilationUnit unit = (ICompilationUnit) element
718 .getAncestor(IJavaElement.COMPILATION_UNIT);
721 if (!unit.isWorkingCopy())
727 // public static IType[] getAllSuperTypes(IType type, IProgressMonitor pm)
728 // throws JavaModelException {
729 // //workaround for bugs 23644 and 23656
731 // pm.beginTask("", 3); //$NON-NLS-1$
732 // ITypeHierarchy hierarchy= type.newSupertypeHierarchy(new
733 // SubProgressMonitor(pm, 1));
735 // IProgressMonitor subPm= new SubProgressMonitor(pm, 2);
736 // List typeList= Arrays.asList(hierarchy.getAllSupertypes(type));
737 // subPm.beginTask("", typeList.size()); //$NON-NLS-1$
738 // Set types= new HashSet(typeList);
739 // for (Iterator iter= typeList.iterator(); iter.hasNext();) {
740 // IType superType= (IType)iter.next();
741 // IType[] superTypes= getAllSuperTypes(superType, new
742 // SubProgressMonitor(subPm, 1));
743 // types.addAll(Arrays.asList(superTypes));
745 // types.add(type.getJavaProject().findType("java.lang.Object"));//$NON-NLS-1$
747 // return (IType[]) types.toArray(new IType[types.size()]);
753 public static boolean isExcludedPath(IPath resourcePath,
754 IPath[] exclusionPatterns) {
755 char[] path = resourcePath.toString().toCharArray();
756 for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
757 char[] pattern = exclusionPatterns[i].toString().toCharArray();
758 if (CharOperation.pathMatch(pattern, path, true, '/')) {
766 * Returns whether the given resource path matches one of the exclusion
769 * @see IClasspathEntry#getExclusionPatterns
771 public final static boolean isExcluded(IPath resourcePath,
772 char[][] exclusionPatterns) {
773 if (exclusionPatterns == null)
775 char[] path = resourcePath.toString().toCharArray();
776 for (int i = 0, length = exclusionPatterns.length; i < length; i++)
777 if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/'))
782 private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
784 private static final String EMPTY_ARGUMENT = " "; //$NON-NLS-1$
787 * Copied from net.sourceforge.phpdt.internal.core.ProjectPrefUtil;
789 public static String[] getProblemArgumentsFromMarker(String argumentsString) {
790 if (argumentsString == null)
792 int index = argumentsString.indexOf(':');
796 int length = argumentsString.length();
799 numberOfArg = Integer.parseInt(argumentsString.substring(0, index));
800 } catch (NumberFormatException e) {
803 argumentsString = argumentsString.substring(index + 1, length);
805 String[] args = new String[length];
808 StringTokenizer tokenizer = new StringTokenizer(argumentsString,
809 ARGUMENTS_DELIMITER);
810 while (tokenizer.hasMoreTokens()) {
811 String argument = tokenizer.nextToken();
812 if (argument.equals(EMPTY_ARGUMENT))
813 argument = ""; //$NON-NLS-1$
814 args[count++] = argument;
817 if (count != numberOfArg)
820 System.arraycopy(args, 0, args = new String[count], 0, count);