blob: c4086ed7f2ece00b43804671dba213f4cb5ce724 [file] [log] [blame]
cbateman3d52a612006-11-28 20:02:40 +00001/*******************************************************************************
2 * Copyright (c) 2006 Sybase, Inc. and others.
3 *
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Sybase, Inc. - initial API and implementation
11 *******************************************************************************/
12package org.eclipse.jst.jsf.common.ui.internal.utils;
13
14import java.util.Arrays;
15import java.util.HashSet;
16import java.util.Set;
17
18import org.eclipse.core.resources.IProject;
19import org.eclipse.core.resources.IResource;
20import org.eclipse.core.runtime.CoreException;
21import org.eclipse.core.runtime.IPath;
22import org.eclipse.core.runtime.IProgressMonitor;
23import org.eclipse.core.runtime.Path;
24import org.eclipse.jdt.core.ClasspathContainerInitializer;
25import org.eclipse.jdt.core.Flags;
26import org.eclipse.jdt.core.IClasspathContainer;
27import org.eclipse.jdt.core.IClasspathEntry;
28import org.eclipse.jdt.core.ICompilationUnit;
29import org.eclipse.jdt.core.IField;
cbateman3d52a612006-11-28 20:02:40 +000030import org.eclipse.jdt.core.IImportDeclaration;
31import org.eclipse.jdt.core.IJavaElement;
32import org.eclipse.jdt.core.IJavaProject;
33import org.eclipse.jdt.core.IMember;
34import org.eclipse.jdt.core.IMethod;
cbateman3d52a612006-11-28 20:02:40 +000035import org.eclipse.jdt.core.IPackageFragment;
36import org.eclipse.jdt.core.IPackageFragmentRoot;
37import org.eclipse.jdt.core.IType;
38import org.eclipse.jdt.core.ITypeHierarchy;
39import org.eclipse.jdt.core.JavaCore;
40import org.eclipse.jdt.core.JavaModelException;
41import org.eclipse.jdt.core.Signature;
42import org.eclipse.jdt.core.compiler.CharOperation;
43
44/**
45 * Original code is from JDT Utility methods for the Java Model.
46 */
47public final class JavaModelUtil {
48
49 /**
50 * Finds a type by its qualified type name (dot separated).
51 *
52 * @param jproject
53 * The java project to search in
54 * @param fullyQualifiedName
55 * The fully qualified name (type name with enclosing type names
56 * and package (all separated by dots))
57 * @return The type found, or null if not existing
cbateman259f2d62007-10-02 21:51:21 +000058 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +000059 */
60 public static IType findType(IJavaProject jproject,
61 String fullyQualifiedName) throws JavaModelException {
62 // workaround for bug 22883
63 IType type = jproject.findType(fullyQualifiedName);
64 if (type != null) {
65 return type;
66 }
67 IPackageFragmentRoot[] roots = jproject.getPackageFragmentRoots();
68 for (int i = 0; i < roots.length; i++) {
69 IPackageFragmentRoot root = roots[i];
70 type = findType(root, fullyQualifiedName);
71 if (type != null && type.exists()) {
72 return type;
73 }
74 }
75 return null;
76 }
77
78 /**
79 * Returns <code>true</code> if the given package fragment root is
80 * referenced. This means it is own by a different project but is referenced
81 * by the root's parent. Returns <code>false</code> if the given root
82 * doesn't have an underlying resource.
cbateman259f2d62007-10-02 21:51:21 +000083 * @param root
84 * @return true if root is referenced
cbateman3d52a612006-11-28 20:02:40 +000085 */
86 public static boolean isReferenced(IPackageFragmentRoot root) {
87 IResource resource = root.getResource();
88 if (resource != null) {
89 IProject jarProject = resource.getProject();
90 IProject container = root.getJavaProject().getProject();
91 return !container.equals(jarProject);
92 }
93 return false;
94 }
95
96 private static IType findType(IPackageFragmentRoot root,
97 String fullyQualifiedName) throws JavaModelException {
98 IJavaElement[] children = root.getChildren();
99 for (int i = 0; i < children.length; i++) {
100 IJavaElement element = children[i];
101 if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
102 IPackageFragment pack = (IPackageFragment) element;
103 if (!fullyQualifiedName.startsWith(pack.getElementName())) {
104 continue;
105 }
106 IType type = findType(pack, fullyQualifiedName);
107 if (type != null && type.exists()) {
108 return type;
109 }
110 }
111 }
112 return null;
113 }
114
115 private static IType findType(IPackageFragment pack,
116 String fullyQualifiedName) throws JavaModelException {
117 ICompilationUnit[] cus = pack.getCompilationUnits();
118 for (int i = 0; i < cus.length; i++) {
119 ICompilationUnit unit = cus[i];
120 IType type = findType(unit, fullyQualifiedName);
121 if (type != null && type.exists()) {
122 return type;
123 }
124 }
125 return null;
126 }
127
128 private static IType findType(ICompilationUnit cu, String fullyQualifiedName)
129 throws JavaModelException {
130 IType[] types = cu.getAllTypes();
131 for (int i = 0; i < types.length; i++) {
132 IType type = types[i];
133 if (getFullyQualifiedName(type).equals(fullyQualifiedName)) {
134 return type;
135 }
136 }
137 return null;
138 }
139
140 /**
141 * Finds a type by package and type name.
142 *
143 * @param jproject
144 * the java project to search in
145 * @param pack
146 * The package name
147 * @param typeQualifiedName
148 * the type qualified name (type name with enclosing type names
149 * (separated by dots))
150 * @return the type found, or null if not existing
cbateman259f2d62007-10-02 21:51:21 +0000151 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000152 * @deprecated Use IJavaProject.findType(String, String) instead
153 */
154 public static IType findType(IJavaProject jproject, String pack,
155 String typeQualifiedName) throws JavaModelException {
156 return jproject.findType(pack, typeQualifiedName);
157 }
158
159 /**
160 * Finds a type container by container name. The returned element will be of
161 * type <code>IType</code> or a <code>IPackageFragment</code>.
162 * <code>null</code> is returned if the type container could not be found.
163 *
164 * @param jproject
165 * The Java project defining the context to search
166 * @param typeContainerName
167 * A dot separarted name of the type container
cbateman259f2d62007-10-02 21:51:21 +0000168 * @return the java element
169 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000170 * @see #getTypeContainerName(IType)
171 */
172 public static IJavaElement findTypeContainer(IJavaProject jproject,
173 String typeContainerName) throws JavaModelException {
174 // try to find it as type
175 IJavaElement result = jproject.findType(typeContainerName);
176 if (result == null) {
177 // find it as package
178 IPath path = new Path(typeContainerName.replace('.', '/'));
179 result = jproject.findElement(path);
180 if (!(result instanceof IPackageFragment)) {
181 result = null;
182 }
183
184 }
185 return result;
186 }
187
188 /**
189 * Finds a type in a compilation unit. Typical usage is to find the
190 * corresponding type in a working copy.
191 *
192 * @param cu
193 * the compilation unit to search in
194 * @param typeQualifiedName
195 * the type qualified name (type name with enclosing type names
196 * (separated by dots))
197 * @return the type found, or null if not existing
cbateman259f2d62007-10-02 21:51:21 +0000198 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000199 */
200 public static IType findTypeInCompilationUnit(ICompilationUnit cu,
201 String typeQualifiedName) throws JavaModelException {
202 IType[] types = cu.getAllTypes();
203 for (int i = 0; i < types.length; i++) {
204 String currName = getTypeQualifiedName(types[i]);
205 if (typeQualifiedName.equals(currName)) {
206 return types[i];
207 }
208 }
209 return null;
210 }
211
212 /**
213 * Finds a a member in a compilation unit. Typical usage is to find the
214 * corresponding member in a working copy.
215 *
216 * @param cu
217 * the compilation unit (eg. working copy) to search in
218 * @param member
219 * the member (eg. from the original)
220 * @return the member found, or null if not existing
221 */
222 public static IMember findMemberInCompilationUnit(ICompilationUnit cu,
223 IMember member) {
224 IJavaElement[] elements = cu.findElements(member);
225 if (elements != null && elements.length > 0) {
226 return (IMember) elements[0];
227 }
228 return null;
229 }
230
231 /**
232 * Returns the element of the given compilation unit which is "equal" to the
233 * given element. Note that the given element usually has a parent different
234 * from the given compilation unit.
235 *
236 * @param cu
237 * the cu to search in
238 * @param element
239 * the element to look for
240 * @return an element of the given cu "equal" to the given element
241 */
242 public static IJavaElement findInCompilationUnit(ICompilationUnit cu,
243 IJavaElement element) {
244 IJavaElement[] elements = cu.findElements(element);
245 if (elements != null && elements.length > 0) {
246 return elements[0];
247 }
248 return null;
249 }
250
251 /**
252 * Returns the qualified type name of the given type using '.' as
253 * separators. This is a replace for IType.getTypeQualifiedName() which uses
254 * '$' as separators. As '$' is also a valid character in an id this is
255 * ambiguous. JavaCore PR: 1GCFUNT
cbateman259f2d62007-10-02 21:51:21 +0000256 * @param type
257 * @return the type qualified name
cbateman3d52a612006-11-28 20:02:40 +0000258 */
259 public static String getTypeQualifiedName(IType type) {
260 return type.getTypeQualifiedName('.');
261 }
262
263 /**
264 * Returns the fully qualified name of the given type using '.' as
265 * separators. This is a replace for IType.getFullyQualifiedTypeName which
266 * uses '$' as separators. As '$' is also a valid character in an id this is
267 * ambiguous. JavaCore PR: 1GCFUNT
cbateman259f2d62007-10-02 21:51:21 +0000268 * @param type
269 * @return the fully qualified name using . as the separator
cbateman3d52a612006-11-28 20:02:40 +0000270 */
271 public static String getFullyQualifiedName(IType type) {
272 return type.getFullyQualifiedName('.');
273 }
274
275 /**
276 * Returns the fully qualified name of a type's container. (package name or
277 * enclosing type name)
cbateman259f2d62007-10-02 21:51:21 +0000278 * @param type
279 * @return the container name
cbateman3d52a612006-11-28 20:02:40 +0000280 */
281 public static String getTypeContainerName(IType type) {
282 IType outerType = type.getDeclaringType();
283 if (outerType != null) {
284 return outerType.getFullyQualifiedName('.');
285 }
286 return type.getPackageFragment().getElementName();
287 }
288
289 /**
290 * Concatenates two names. Uses a dot for separation. Both strings can be
291 * empty or <code>null</code>.
cbateman259f2d62007-10-02 21:51:21 +0000292 * @param name1
293 * @param name2
294 * @return name1 + name2
cbateman3d52a612006-11-28 20:02:40 +0000295 */
296 public static String concatenateName(String name1, String name2) {
297 StringBuffer buf = new StringBuffer();
298 if (name1 != null && name1.length() > 0) {
299 buf.append(name1);
300 }
301 if (name2 != null && name2.length() > 0) {
302 if (buf.length() > 0) {
303 buf.append('.');
304 }
305 buf.append(name2);
306 }
307 return buf.toString();
308 }
309
310 /**
311 * Concatenates two names. Uses a dot for separation. Both strings can be
312 * empty or <code>null</code>.
cbateman259f2d62007-10-02 21:51:21 +0000313 * @param name1
314 * @param name2
315 * @return name1 + name2
cbateman3d52a612006-11-28 20:02:40 +0000316 */
317 public static String concatenateName(char[] name1, char[] name2) {
318 StringBuffer buf = new StringBuffer();
319 if (name1 != null && name1.length > 0) {
320 buf.append(name1);
321 }
322 if (name2 != null && name2.length > 0) {
323 if (buf.length() > 0) {
324 buf.append('.');
325 }
326 buf.append(name2);
327 }
328 return buf.toString();
329 }
330
331 /**
332 * Evaluates if a member (possible from another package) is visible from
333 * elements in a package.
334 *
335 * @param member
336 * The member to test the visibility for
337 * @param pack
338 * The package in focus
cbateman259f2d62007-10-02 21:51:21 +0000339 * @return true if visible
340 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000341 */
342 public static boolean isVisible(IMember member, IPackageFragment pack)
343 throws JavaModelException {
344
345 int type = member.getElementType();
346 if (type == IJavaElement.INITIALIZER
347 || (type == IJavaElement.METHOD && member.getElementName()
gkesslercfc53082008-11-18 22:25:04 +0000348 .startsWith("<"))) { //$NON-NLS-1$
cbateman3d52a612006-11-28 20:02:40 +0000349 //$NON-NLS-1$
350 return false;
351 }
352
353 int otherflags = member.getFlags();
354 IType declaringType = member.getDeclaringType();
355 if (Flags.isPublic(otherflags)
356 || (declaringType != null && declaringType.isInterface())) {
357 return true;
358 } else if (Flags.isPrivate(otherflags)) {
359 return false;
360 }
361
362 IPackageFragment otherpack = (IPackageFragment) findParentOfKind(
363 member, IJavaElement.PACKAGE_FRAGMENT);
364 return (pack != null && otherpack != null && isSamePackage(pack,
365 otherpack));
366 }
367
368 /**
369 * Evaluates if a member in the focus' element hierarchy is visible from
370 * elements in a package.
371 *
372 * @param member
373 * The member to test the visibility for
374 * @param pack
375 * The package of the focus element focus
cbateman259f2d62007-10-02 21:51:21 +0000376 * @return true if is visible in hiearchy
377 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000378 */
379 public static boolean isVisibleInHierarchy(IMember member,
380 IPackageFragment pack) throws JavaModelException {
381 int type = member.getElementType();
382 if (type == IJavaElement.INITIALIZER
383 || (type == IJavaElement.METHOD && member.getElementName()
gkesslercfc53082008-11-18 22:25:04 +0000384 .startsWith("<"))) { //$NON-NLS-1$
cbateman3d52a612006-11-28 20:02:40 +0000385 //$NON-NLS-1$
386 return false;
387 }
388
389 int otherflags = member.getFlags();
390
391 IType declaringType = member.getDeclaringType();
392 if (Flags.isPublic(otherflags) || Flags.isProtected(otherflags)
393 || (declaringType != null && declaringType.isInterface())) {
394 return true;
395 } else if (Flags.isPrivate(otherflags)) {
396 return false;
397 }
398
399 IPackageFragment otherpack = (IPackageFragment) findParentOfKind(
400 member, IJavaElement.PACKAGE_FRAGMENT);
401 return (pack != null && pack.equals(otherpack));
402 }
403
404 /**
405 * Returns the package fragment root of <code>IJavaElement</code>. If the
406 * given element is already a package fragment root, the element itself is
407 * returned.
cbateman259f2d62007-10-02 21:51:21 +0000408 * @param element
409 * @return the package fragment root
cbateman3d52a612006-11-28 20:02:40 +0000410 */
411 public static IPackageFragmentRoot getPackageFragmentRoot(
412 IJavaElement element) {
413 return (IPackageFragmentRoot) element
414 .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
415 }
416
417 /**
418 * Returns the parent of the supplied java element that conforms to the
419 * given parent type or <code>null</code>, if such a parent doesn't exit.
420 *
421 * @deprecated Use element.getParent().getAncestor(kind);
422 */
cbateman259f2d62007-10-02 21:51:21 +0000423 private static IJavaElement findParentOfKind(IJavaElement element, int kind) {
cbateman3d52a612006-11-28 20:02:40 +0000424 if (element != null && element.getParent() != null) {
425 return element.getParent().getAncestor(kind);
426 }
427 return null;
428 }
429
430 /**
431 * Finds a method in a type. This searches for a method with the same name
432 * and signature. Parameter types are only compared by the simple name, no
433 * resolving for the fully qualified type name is done. Constructors are
434 * only compared by parameters, not the name.
435 *
436 * @param name
437 * The name of the method to find
438 * @param paramTypes
439 * The type signatures of the parameters e.g.
440 * <code>{"QString;","I"}</code>
441 * @param isConstructor
442 * If the method is a constructor
cbateman259f2d62007-10-02 21:51:21 +0000443 * @param type
cbateman3d52a612006-11-28 20:02:40 +0000444 * @return The first found method or <code>null</code>, if nothing found
cbateman259f2d62007-10-02 21:51:21 +0000445 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000446 */
447 public static IMethod findMethod(String name, String[] paramTypes,
448 boolean isConstructor, IType type) throws JavaModelException {
449 return findMethod(name, paramTypes, isConstructor, type.getMethods());
450 }
451
452 /**
453 * Finds a method by name. This searches for a method with a name and
454 * signature. Parameter types are only compared by the simple name, no
455 * resolving for the fully qualified type name is done. Constructors are
456 * only compared by parameters, not the name.
457 *
458 * @param name
459 * The name of the method to find
460 * @param paramTypes
461 * The type signatures of the parameters e.g.
462 * <code>{"QString;","I"}</code>
463 * @param isConstructor
464 * If the method is a constructor
465 * @param methods
466 * The methods to search in
467 * @return The found method or <code>null</code>, if nothing found
cbateman259f2d62007-10-02 21:51:21 +0000468 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000469 */
470 public static IMethod findMethod(String name, String[] paramTypes,
471 boolean isConstructor, IMethod[] methods) throws JavaModelException {
472 for (int i = methods.length - 1; i >= 0; i--) {
473 if (isSameMethodSignature(name, paramTypes, isConstructor,
474 methods[i])) {
475 return methods[i];
476 }
477 }
478 return null;
479 }
480
481 /**
482 * Finds a method declararion in a type's hierarchy. The search is top down,
483 * so this returns the first declaration of the method in the hierarchy.
484 * This searches for a method with a name and signature. Parameter types are
485 * only compared by the simple name, no resolving for the fully qualified
486 * type name is done. Constructors are only compared by parameters, not the
487 * name.
cbateman259f2d62007-10-02 21:51:21 +0000488 * @param hierarchy
cbateman3d52a612006-11-28 20:02:40 +0000489 *
490 * @param type
491 * Searches in this type's supertypes.
492 * @param name
493 * The name of the method to find
494 * @param paramTypes
495 * The type signatures of the parameters e.g.
496 * <code>{"QString;","I"}</code>
497 * @param isConstructor
498 * If the method is a constructor
499 * @return The first method found or null, if nothing found
cbateman259f2d62007-10-02 21:51:21 +0000500 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000501 */
502 public static IMethod findMethodDeclarationInHierarchy(
503 ITypeHierarchy hierarchy, IType type, String name,
504 String[] paramTypes, boolean isConstructor)
505 throws JavaModelException {
506 IType[] superTypes = hierarchy.getAllSupertypes(type);
507 for (int i = superTypes.length - 1; i >= 0; i--) {
508 IMethod first = findMethod(name, paramTypes, isConstructor,
509 superTypes[i]);
510 if (first != null && !Flags.isPrivate(first.getFlags())) {
511 // the order getAllSupertypes does make assumptions of the order
512 // of inner elements -> search recursivly
513 IMethod res = findMethodDeclarationInHierarchy(hierarchy, first
514 .getDeclaringType(), name, paramTypes, isConstructor);
515 if (res != null) {
516 return res;
517 }
518 return first;
519 }
520 }
521 return null;
522 }
523
524 /**
525 * Finds a method implementation in a type's classhierarchy. The search is
526 * bottom-up, so this returns the nearest overridden method. Does not find
527 * methods in interfaces or abstract methods. This searches for a method
528 * with a name and signature. Parameter types are only compared by the
529 * simple name, no resolving for the fully qualified type name is done.
530 * Constructors are only compared by parameters, not the name.
cbateman259f2d62007-10-02 21:51:21 +0000531 * @param hierarchy
cbateman3d52a612006-11-28 20:02:40 +0000532 *
533 * @param type
534 * Type to search the superclasses
535 * @param name
536 * The name of the method to find
537 * @param paramTypes
538 * The type signatures of the parameters e.g.
539 * <code>{"QString;","I"}</code>
540 * @param isConstructor
541 * If the method is a constructor
542 * @return The first method found or null, if nothing found
cbateman259f2d62007-10-02 21:51:21 +0000543 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000544 */
545 public static IMethod findMethodImplementationInHierarchy(
546 ITypeHierarchy hierarchy, IType type, String name,
547 String[] paramTypes, boolean isConstructor)
548 throws JavaModelException {
549 IType[] superTypes = hierarchy.getAllSuperclasses(type);
550 for (int i = 0; i < superTypes.length; i++) {
551 IMethod found = findMethod(name, paramTypes, isConstructor,
552 superTypes[i]);
553 if (found != null) {
554 if (Flags.isAbstract(found.getFlags())) {
555 return null;
556 }
557 return found;
558 }
559 }
560 return null;
561 }
562
563 private static IMethod findMethodInHierarchy(ITypeHierarchy hierarchy,
564 IType type, String name, String[] paramTypes, boolean isConstructor)
565 throws JavaModelException {
566 IMethod method = findMethod(name, paramTypes, isConstructor, type);
567 if (method != null) {
568 return method;
569 }
570 IType superClass = hierarchy.getSuperclass(type);
571 if (superClass != null) {
572 IMethod res = findMethodInHierarchy(hierarchy, superClass, name,
573 paramTypes, isConstructor);
574 if (res != null) {
575 return res;
576 }
577 }
578 if (!isConstructor) {
579 IType[] superInterfaces = hierarchy.getSuperInterfaces(type);
580 for (int i = 0; i < superInterfaces.length; i++) {
581 IMethod res = findMethodInHierarchy(hierarchy,
582 superInterfaces[i], name, paramTypes, false);
583 if (res != null) {
584 return res;
585 }
586 }
587 }
588 return method;
589 }
590
591 /**
592 * Finds the method that is defines/declares the given method. The search is
593 * bottom-up, so this returns the nearest defining/declaring method.
cbateman259f2d62007-10-02 21:51:21 +0000594 * @param typeHierarchy
595 * @param type
596 * @param methodName
597 * @param paramTypes
598 * @param isConstructor
cbateman3d52a612006-11-28 20:02:40 +0000599 *
600 * @param testVisibility
601 * If true the result is tested on visibility. Null is returned
602 * if the method is not visible.
cbateman259f2d62007-10-02 21:51:21 +0000603 * @return the method or null
cbateman3d52a612006-11-28 20:02:40 +0000604 * @throws JavaModelException
605 */
606 public static IMethod findMethodDefininition(ITypeHierarchy typeHierarchy,
607 IType type, String methodName, String[] paramTypes,
608 boolean isConstructor, boolean testVisibility)
609 throws JavaModelException {
610 IType superClass = typeHierarchy.getSuperclass(type);
611 if (superClass != null) {
612 IMethod res = findMethodInHierarchy(typeHierarchy, superClass,
613 methodName, paramTypes, isConstructor);
614 if (res != null && !Flags.isPrivate(res.getFlags())) {
615 if (!testVisibility
616 || isVisibleInHierarchy(res, type.getPackageFragment())) {
617 return res;
618 }
619 }
620 }
621 if (!isConstructor) {
622 IType[] interfaces = typeHierarchy.getSuperInterfaces(type);
623 for (int i = 0; i < interfaces.length; i++) {
624 IMethod res = findMethodInHierarchy(typeHierarchy,
625 interfaces[i], methodName, paramTypes, false);
626 if (res != null) {
627 return res; // methods from interfaces are always public and
628 // therefore visible
629 }
630 }
631 }
632 return null;
633 }
634
635 /**
636 * Tests if a method equals to the given signature. Parameter types are only
637 * compared by the simple name, no resolving for the fully qualified type
638 * name is done. Constructors are only compared by parameters, not the name.
639 *
640 * @param name
641 * Name of the method
642 * @param paramTypes
643 * The type signatures of the parameters e.g.
644 * <code>{"QString;","I"}</code>
645 * @param isConstructor
646 * Specifies if the method is a constructor
cbateman259f2d62007-10-02 21:51:21 +0000647 * @param curr
cbateman3d52a612006-11-28 20:02:40 +0000648 * @return Returns <code>true</code> if the method has the given name and
649 * parameter types and constructor state.
cbateman259f2d62007-10-02 21:51:21 +0000650 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000651 */
652 public static boolean isSameMethodSignature(String name,
653 String[] paramTypes, boolean isConstructor, IMethod curr)
654 throws JavaModelException {
655 if (isConstructor || name.equals(curr.getElementName())) {
656 if (isConstructor == curr.isConstructor()) {
657 String[] currParamTypes = curr.getParameterTypes();
658 if (paramTypes.length == currParamTypes.length) {
659 for (int i = 0; i < paramTypes.length; i++) {
660 String t1 = Signature.getSimpleName(Signature
661 .toString(paramTypes[i]));
662 String t2 = Signature.getSimpleName(Signature
663 .toString(currParamTypes[i]));
664 if (!t1.equals(t2)) {
665 return false;
666 }
667 }
668 return true;
669 }
670 }
671 }
672 return false;
673 }
674
675 /**
676 * Tests if two <code>IPackageFragment</code>s represent the same logical
677 * java package.
cbateman259f2d62007-10-02 21:51:21 +0000678 * @param pack1
679 * @param pack2
cbateman3d52a612006-11-28 20:02:40 +0000680 *
681 * @return <code>true</code> if the package fragments' names are equal.
682 */
683 public static boolean isSamePackage(IPackageFragment pack1,
684 IPackageFragment pack2) {
685 return pack1.getElementName().equals(pack2.getElementName());
686 }
687
688 /**
689 * Checks whether the given type has a valid main method or not.
cbateman259f2d62007-10-02 21:51:21 +0000690 * @param type
691 * @return true if type has a main method
692 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000693 */
694 public static boolean hasMainMethod(IType type) throws JavaModelException {
695 IMethod[] methods = type.getMethods();
696 for (int i = 0; i < methods.length; i++) {
697 if (methods[i].isMainMethod()) {
698 return true;
699 }
700 }
701 return false;
702 }
703
704 /**
705 * Checks if the field is boolean.
cbateman259f2d62007-10-02 21:51:21 +0000706 * @param field
707 * @return true if the file is of primitive boolean type
708 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000709 */
710 public static boolean isBoolean(IField field) throws JavaModelException {
711 return field.getTypeSignature().equals(Signature.SIG_BOOLEAN);
712 }
713
714 /**
cbateman3d52a612006-11-28 20:02:40 +0000715 * Tests if the given element is on the class path of its containing
716 * project. Handles the case that the containing project isn't a Java
717 * project.
cbateman259f2d62007-10-02 21:51:21 +0000718 * @param element
719 * @return true if element in on the class path?
cbateman3d52a612006-11-28 20:02:40 +0000720 */
721 public static boolean isOnClasspath(IJavaElement element) {
722 IJavaProject project = element.getJavaProject();
723 if (!project.exists())
724 return false;
725 return project.isOnClasspath(element);
726 }
727
728 /**
729 * Resolves a type name in the context of the declaring type.
730 *
731 * @param refTypeSig
732 * the type name in signature notation (for example 'QVector')
733 * this can also be an array type, but dimensions will be
734 * ignored.
735 * @param declaringType
736 * the context for resolving (type where the reference was made
737 * in)
738 * @return returns the fully qualified type name or build-in-type name. if a
739 * unresoved type couldn't be resolved null is returned
cbateman259f2d62007-10-02 21:51:21 +0000740 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000741 */
742 public static String getResolvedTypeName(String refTypeSig,
743 IType declaringType) throws JavaModelException {
744 int arrayCount = Signature.getArrayCount(refTypeSig);
745 char type = refTypeSig.charAt(arrayCount);
746 if (type == Signature.C_UNRESOLVED) {
747 int semi = refTypeSig
748 .indexOf(Signature.C_SEMICOLON, arrayCount + 1);
749 if (semi == -1) {
750 throw new IllegalArgumentException();
751 }
752 String name = refTypeSig.substring(arrayCount + 1, semi);
753
754 String[][] resolvedNames = declaringType.resolveType(name);
755 if (resolvedNames != null && resolvedNames.length > 0) {
756 return JavaModelUtil.concatenateName(resolvedNames[0][0],
757 resolvedNames[0][1]);
758 }
759 return null;
760 }
761 return Signature.toString(refTypeSig.substring(arrayCount));
762 }
763
764 /**
765 * Returns if a CU can be edited.
cbateman259f2d62007-10-02 21:51:21 +0000766 * @param cu
767 * @return true if cu is editable
cbateman3d52a612006-11-28 20:02:40 +0000768 */
769 public static boolean isEditable(ICompilationUnit cu) {
770 IResource resource = toOriginal(cu).getResource();
771 return (resource.exists() && !resource.getResourceAttributes()
772 .isReadOnly());
773 }
774
775 /**
776 * Finds a qualified import for a type name.
cbateman259f2d62007-10-02 21:51:21 +0000777 * @param cu
778 * @param simpleName
779 * @return the import declaration or null
780 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +0000781 */
782 public static IImportDeclaration findImport(ICompilationUnit cu,
783 String simpleName) throws JavaModelException {
784 IImportDeclaration[] existing = cu.getImports();
785 for (int i = 0; i < existing.length; i++) {
786 String curr = existing[i].getElementName();
787 if (curr.endsWith(simpleName)) {
788 int dotPos = curr.length() - simpleName.length() - 1;
789 if ((dotPos == -1)
790 || (dotPos > 0 && curr.charAt(dotPos) == '.')) {
791 return existing[i];
792 }
793 }
794 }
795 return null;
796 }
797
798 /**
799 * Returns the original if the given member. If the member is already an
800 * original the input is returned. The returned member might not exist
cbateman259f2d62007-10-02 21:51:21 +0000801 * @param member
802 * @return the original IMember
cbateman3d52a612006-11-28 20:02:40 +0000803 */
804 public static IMember toOriginal(IMember member) {
805 if (member instanceof IMethod) {
806 return toOriginalMethod((IMethod) member);
807 }
808
809 return (IMember) member.getPrimaryElement();
810 /*
811 * ICompilationUnit cu= member.getCompilationUnit(); if (cu != null &&
812 * cu.isWorkingCopy()) return (IMember)cu.getOriginal(member); return
813 * member;
814 */
815 }
816
817 /*
818 * XXX workaround for bug 18568
819 * http://bugs.eclipse.org/bugs/show_bug.cgi?id=18568 to be removed once the
820 * bug is fixed
821 */
822 private static IMethod toOriginalMethod(IMethod method) {
823 ICompilationUnit cu = method.getCompilationUnit();
824 if (cu == null || isPrimary(cu)) {
825 return method;
826 }
827 try {
828 // use the workaround only if needed
829 if (!method.getElementName().equals(
830 method.getDeclaringType().getElementName()))
831 return (IMethod) method.getPrimaryElement();
832
833 IType originalType = (IType) toOriginal(method.getDeclaringType());
834 IMethod[] methods = originalType.findMethods(method);
835 boolean isConstructor = method.isConstructor();
836 for (int i = 0; i < methods.length; i++) {
837 if (methods[i].isConstructor() == isConstructor)
838 return methods[i];
839 }
840 return null;
841 } catch (JavaModelException e) {
842 return null;
843 }
844 }
845
846 // private static boolean PRIMARY_ONLY = false;
847
848 /**
849 * Returns the original cu if the given cu is a working copy. If the cu is
850 * already an original the input cu is returned. The returned cu might not
851 * exist
cbateman259f2d62007-10-02 21:51:21 +0000852 * @param cu
853 * @return the original compiliation unit
cbateman3d52a612006-11-28 20:02:40 +0000854 */
855 public static ICompilationUnit toOriginal(ICompilationUnit cu) {
856 // To stay compatible with old version returned null
857 // if cu is null
858 if (cu == null)
859 return cu;
860 return cu.getPrimary();
861 }
862
863 /**
864 * Returns the original element if the given element is a working copy. If
865 * the cu is already an original the input element is returned. The returned
866 * element might not exist
cbateman259f2d62007-10-02 21:51:21 +0000867 * @param element
868 * @return element's primary element
cbateman3d52a612006-11-28 20:02:40 +0000869 */
870 public static IJavaElement toOriginal(IJavaElement element) {
871 return element.getPrimaryElement();
872 }
873
874 /**
cbateman3d52a612006-11-28 20:02:40 +0000875 * Returns true if a cu is a primary cu (original or shared working copy)
cbateman259f2d62007-10-02 21:51:21 +0000876 * @param cu
877 * @return true if cu is primary
cbateman3d52a612006-11-28 20:02:40 +0000878 */
879 public static boolean isPrimary(ICompilationUnit cu) {
880 return cu.getOwner() == null;
881 }
882
cbateman259f2d62007-10-02 21:51:21 +0000883 /**
cbateman3d52a612006-11-28 20:02:40 +0000884 * http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
885 *
886 * Reconciling happens in a separate thread. This can cause a situation
887 * where the Java element gets disposed after an exists test has been done.
888 * So we should not log not present exceptions when they happen in working
889 * copies.
cbateman259f2d62007-10-02 21:51:21 +0000890 * @param exception
891 * @return true if filter not present
cbateman3d52a612006-11-28 20:02:40 +0000892 */
893 public static boolean filterNotPresentException(CoreException exception) {
894 if (!(exception instanceof JavaModelException)) {
895 return true;
896 }
897 JavaModelException je = (JavaModelException) exception;
898 if (!je.isDoesNotExist()) {
899 return true;
900 }
901 IJavaElement[] elements = je.getJavaModelStatus().getElements();
902 for (int i = 0; i < elements.length; i++) {
903 IJavaElement element = elements[i];
904 ICompilationUnit unit = (ICompilationUnit) element
905 .getAncestor(IJavaElement.COMPILATION_UNIT);
906 if (unit == null) {
907 return true;
908 }
909 if (!unit.isWorkingCopy()) {
910 return true;
911 }
912 }
913 return false;
914 }
915
cbateman259f2d62007-10-02 21:51:21 +0000916 /**
917 * @param type
918 * @param pm
919 * @return all supertypes of type
920 * @throws JavaModelException
921 */
cbateman3d52a612006-11-28 20:02:40 +0000922 public static IType[] getAllSuperTypes(IType type, IProgressMonitor pm)
923 throws JavaModelException {
924 // workaround for 23656
925 Set types = new HashSet(Arrays.asList(type.newSupertypeHierarchy(pm)
926 .getAllSupertypes(type)));
927 IType objekt = type.getJavaProject().findType("java.lang.Object");//$NON-NLS-1$
928 if (objekt != null) {
929 types.add(objekt);
930 }
931 return (IType[]) types.toArray(new IType[types.size()]);
932 }
933
cbateman259f2d62007-10-02 21:51:21 +0000934 /**
935 * @param resourcePath
936 * @param exclusionPatterns
937 * @return true if resourcePath is excluded by exclusion patterns
938 */
cbateman3d52a612006-11-28 20:02:40 +0000939 public static boolean isExcludedPath(IPath resourcePath,
940 IPath[] exclusionPatterns) {
941 char[] path = resourcePath.toString().toCharArray();
942 for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
943 char[] pattern = exclusionPatterns[i].toString().toCharArray();
944 if (CharOperation.pathMatch(pattern, path, true, '/')) {
945 return true;
946 }
947 }
948 return false;
949 }
950
951 /*
cbateman259f2d62007-10-02 21:51:21 +0000952
953 * @see IClasspathEntry#getExclusionPatterns
954 */
955 /**
cbateman3d52a612006-11-28 20:02:40 +0000956 * Returns whether the given resource path matches one of the exclusion
957 * patterns.
958 *
cbateman259f2d62007-10-02 21:51:21 +0000959 * @param resourcePath
960 * @param exclusionPatterns
961 * @return true if resourcePath is excluded
cbateman3d52a612006-11-28 20:02:40 +0000962 */
963 public static boolean isExcluded(IPath resourcePath,
964 char[][] exclusionPatterns) {
965 if (exclusionPatterns == null) {
966 return false;
967 }
968 char[] path = resourcePath.toString().toCharArray();
969 for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
970 if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/')) {
971 return true;
972 }
973 }
974 return false;
975 }
976
977 private static Boolean fgIsJDTCore_1_5 = null;
978
979 /**
cbateman259f2d62007-10-02 21:51:21 +0000980 * @return true if JRE 1.5 in enabled.
cbateman3d52a612006-11-28 20:02:40 +0000981 */
982 public static boolean isJDTCore_1_5() {
983 if (fgIsJDTCore_1_5 == null) {
984 fgIsJDTCore_1_5 = JavaCore
985 .getDefaultOptions()
986 .containsKey(
gkesslercfc53082008-11-18 22:25:04 +0000987 "org.eclipse.jdt.core.compiler.problem.unsafeTypeOperation") ? Boolean.TRUE //$NON-NLS-1$
cbateman3d52a612006-11-28 20:02:40 +0000988 : Boolean.FALSE;
989 }
990 return fgIsJDTCore_1_5.booleanValue();
991 }
992
993 /**
994 * Helper method that tests if an classpath entry can be found in a
995 * container. <code>null</code> is returned if the entry can not be found
996 * or if the container does not allows the configuration of source
997 * attachments
998 *
999 * @param jproject
1000 * The container's parent project
1001 * @param containerPath
1002 * The path of the container
1003 * @param libPath
1004 * The path of the library to be found
1005 * @return IClasspathEntry A classpath entry from the container of
1006 * <code>null</code> if the container can not be modified.
cbateman259f2d62007-10-02 21:51:21 +00001007 * @throws JavaModelException
cbateman3d52a612006-11-28 20:02:40 +00001008 */
1009 public static IClasspathEntry getClasspathEntryToEdit(
1010 IJavaProject jproject, IPath containerPath, IPath libPath)
1011 throws JavaModelException {
1012 IClasspathContainer container = JavaCore.getClasspathContainer(
1013 containerPath, jproject);
1014 ClasspathContainerInitializer initializer = JavaCore
1015 .getClasspathContainerInitializer(containerPath.segment(0));
1016 if (container != null
1017 && initializer != null
1018 && initializer.canUpdateClasspathContainer(containerPath,
1019 jproject)) {
1020 IClasspathEntry[] entries = container.getClasspathEntries();
1021 for (int i = 0; i < entries.length; i++) {
1022 IClasspathEntry curr = entries[i];
1023 IClasspathEntry resolved = JavaCore
1024 .getResolvedClasspathEntry(curr);
1025 if (resolved != null && libPath.equals(resolved.getPath())) {
1026 return curr; // return the real entry
1027 }
1028 }
1029 }
1030 return null; // attachment not possible
1031 }
1032}