001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package org.terracotta.dso;
005:
006: import org.eclipse.core.runtime.IProgressMonitor;
007: import org.eclipse.jdt.core.IClassFile;
008: import org.eclipse.jdt.core.ICodeAssist;
009: import org.eclipse.jdt.core.ICompilationUnit;
010: import org.eclipse.jdt.core.IJavaElement;
011: import org.eclipse.jdt.core.IJavaProject;
012: import org.eclipse.jdt.core.IMethod;
013: import org.eclipse.jdt.core.IPackageFragment;
014: import org.eclipse.jdt.core.IPackageFragmentRoot;
015: import org.eclipse.jdt.core.IType;
016: import org.eclipse.jdt.core.JavaModelException;
017: import org.eclipse.jdt.core.Signature;
018: import org.eclipse.jdt.ui.JavaUI;
019: import org.eclipse.jface.text.Assert;
020: import org.eclipse.jface.text.ITextSelection;
021: import org.eclipse.ui.IEditorInput;
022: import org.eclipse.ui.IEditorPart;
023: import org.eclipse.ui.texteditor.ITextEditor;
024:
025: import java.util.ArrayList;
026:
027: public class JdtUtils {
028: private static final IJavaElement[] EMPTY_RESULT = new IJavaElement[0];
029:
030: /**
031: * Finds a type by its qualified type name (dot separated).
032: * @param jproject The java project to search in
033: * @param fullyQualifiedName The fully qualified name (type name with enclosing type names and package (all separated by dots))
034: * @return The type found, or null if not existing
035: */
036: public static IType findType(IJavaProject jproject,
037: String fullyQualifiedName) throws JavaModelException {
038: //workaround for bug 22883
039: fullyQualifiedName = fullyQualifiedName.replace('$', '.');
040: IType type = jproject.findType(fullyQualifiedName,
041: (IProgressMonitor) null);
042: if (type != null)
043: return type;
044: IPackageFragmentRoot[] roots = jproject
045: .getPackageFragmentRoots();
046: for (int i = 0; i < roots.length; i++) {
047: IPackageFragmentRoot root = roots[i];
048: type = findType(root, fullyQualifiedName);
049: if (type != null && type.exists())
050: return type;
051: }
052: return null;
053: }
054:
055: private static IType findType(IPackageFragmentRoot root,
056: String fullyQualifiedName) throws JavaModelException {
057: IJavaElement[] children = root.getChildren();
058: for (int i = 0; i < children.length; i++) {
059: IJavaElement element = children[i];
060: if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
061: IPackageFragment pack = (IPackageFragment) element;
062: if (!fullyQualifiedName.startsWith(pack
063: .getElementName()))
064: continue;
065: IType type = findType(pack, fullyQualifiedName);
066: if (type != null && type.exists())
067: return type;
068: }
069: }
070: return null;
071: }
072:
073: private static IType findType(IPackageFragment pack,
074: String fullyQualifiedName) throws JavaModelException {
075: ICompilationUnit[] cus = pack.getCompilationUnits();
076: for (int i = 0; i < cus.length; i++) {
077: ICompilationUnit unit = cus[i];
078: IType type = findType(unit, fullyQualifiedName);
079: if (type != null && type.exists())
080: return type;
081: }
082: return null;
083: }
084:
085: public static IMethod[] findMethods(IType type, String name)
086: throws JavaModelException {
087: ArrayList list = new ArrayList();
088: IMethod[] methods = type.getMethods();
089: for (int i = 0; i < methods.length; i++) {
090: if (methods[i].getElementName().equals(name))
091: list.add(methods[i]);
092: }
093: return (IMethod[]) list.toArray(new IMethod[0]);
094: }
095:
096: private static IType findType(ICompilationUnit cu,
097: String fullyQualifiedName) throws JavaModelException {
098: IType[] types = cu.getAllTypes();
099: for (int i = 0; i < types.length; i++) {
100: IType type = types[i];
101: if (getFullyQualifiedName(type).equals(fullyQualifiedName))
102: return type;
103: }
104: return null;
105: }
106:
107: /**
108: * Returns the fully qualified name of the given type using '.' as separators.
109: * This is a replace for IType.getFullyQualifiedTypeName
110: * which uses '$' as separators. As '$' is also a valid character in an id
111: * this is ambiguous. JavaCore PR: 1GCFUNT
112: */
113: public static String getFullyQualifiedName(IType type) {
114: try {
115: if (type.isBinary() && !type.isAnonymous()) {
116: IType declaringType = type.getDeclaringType();
117: if (declaringType != null) {
118: return getFullyQualifiedName(declaringType) + '.'
119: + type.getElementName();
120: }
121: }
122: } catch (JavaModelException e) {
123: // ignore
124: }
125: return type.getFullyQualifiedName('.');
126: }
127:
128: /**
129: * Force a reconcile of a compilation unit.
130: * @param unit
131: */
132: public static void reconcile(ICompilationUnit unit)
133: throws JavaModelException {
134: unit
135: .reconcile(ICompilationUnit.NO_AST,
136: false /* don't force problem detection */,
137: null /* use primary owner */, null /* no progress monitor */);
138: }
139:
140: /**
141: * Returns the package fragment root of <code>IJavaElement</code>. If the given
142: * element is already a package fragment root, the element itself is returned.
143: */
144: public static IPackageFragmentRoot getPackageFragmentRoot(
145: IJavaElement element) {
146: return (IPackageFragmentRoot) element
147: .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
148: }
149:
150: /**
151: * Resolves a type name in the context of the declaring type.
152: *
153: * @param refTypeSig the type name in signature notation (for example 'QVector') this can also be an array type, but dimensions will be ignored.
154: * @param declaringType the context for resolving (type where the reference was made in)
155: * @return returns the fully qualified type name or build-in-type name. if a unresolved type couldn't be resolved null is returned
156: */
157: public static String getResolvedTypeName(String refTypeSig,
158: IType declaringType) throws JavaModelException {
159: int arrayCount = Signature.getArrayCount(refTypeSig);
160: char type = refTypeSig.charAt(arrayCount);
161: if (type == Signature.C_UNRESOLVED) {
162: String name = ""; //$NON-NLS-1$
163: int bracket = refTypeSig.indexOf(Signature.C_GENERIC_START,
164: arrayCount + 1);
165: if (bracket > 0)
166: name = refTypeSig.substring(arrayCount + 1, bracket);
167: else {
168: int semi = refTypeSig.indexOf(Signature.C_SEMICOLON,
169: arrayCount + 1);
170: if (semi == -1) {
171: throw new IllegalArgumentException();
172: }
173: name = refTypeSig.substring(arrayCount + 1, semi);
174: }
175: String[][] resolvedNames = declaringType.resolveType(name);
176: if (resolvedNames != null && resolvedNames.length > 0) {
177: return concatenateName(resolvedNames[0][0],
178: resolvedNames[0][1]);
179: }
180: return null;
181: } else {
182: return Signature.toString(refTypeSig.substring(arrayCount));
183: }
184: }
185:
186: public static String getResolvedTypeFileName(String refTypeSig,
187: IType declaringType) throws JavaModelException {
188: int arrayCount = Signature.getArrayCount(refTypeSig);
189: char type = refTypeSig.charAt(arrayCount);
190: if (type == Signature.C_UNRESOLVED) {
191: String name = ""; //$NON-NLS-1$
192: int bracket = refTypeSig.indexOf(Signature.C_GENERIC_START,
193: arrayCount + 1);
194: if (bracket > 0)
195: name = refTypeSig.substring(arrayCount + 1, bracket);
196: else {
197: int semi = refTypeSig.indexOf(Signature.C_SEMICOLON,
198: arrayCount + 1);
199: if (semi == -1) {
200: throw new IllegalArgumentException();
201: }
202: name = refTypeSig.substring(arrayCount + 1, semi);
203: }
204: String[][] resolvedNames = declaringType.resolveType(name);
205: if (resolvedNames != null && resolvedNames.length > 0) {
206: return concatenateName(resolvedNames[0][0],
207: resolvedNames[0][1].replace('.', '$'));
208: }
209: return "*";
210: } else {
211: return Signature.toString(refTypeSig.substring(arrayCount));
212: }
213: }
214:
215: /**
216: * Determine if refTypeSig is unresolved.
217: */
218: public static boolean isTypeNameUnresolved(String refTypeSig) {
219: return refTypeSig.charAt(Signature.getArrayCount(refTypeSig)) == Signature.C_UNRESOLVED;
220: }
221:
222: /**
223: * Resolve refTypeSig in context of declaringType.
224: */
225: public static String resolveTypeName(String refTypeSig,
226: IType declaringType) {
227: int arrayCount = Signature.getArrayCount(refTypeSig);
228: char type = refTypeSig.charAt(arrayCount);
229: if (type == Signature.C_UNRESOLVED) {
230: String name = ""; //$NON-NLS-1$
231: int bracket = refTypeSig.indexOf(Signature.C_GENERIC_START,
232: arrayCount + 1);
233: if (bracket > 0)
234: name = refTypeSig.substring(arrayCount + 1, bracket);
235: else {
236: int semi = refTypeSig.indexOf(Signature.C_SEMICOLON,
237: arrayCount + 1);
238: if (semi == -1) {
239: throw new IllegalArgumentException();
240: }
241: name = refTypeSig.substring(arrayCount + 1, semi);
242: }
243: try {
244: String[][] resolvedNames = declaringType
245: .resolveType(name);
246: if (resolvedNames != null && resolvedNames.length > 0) {
247: return JdtUtils.concatenateName(
248: resolvedNames[0][0], resolvedNames[0][1]);
249: } else {
250: return "java.lang.Object";
251: }
252: } catch (JavaModelException jme) {
253: return name;
254: }
255: }
256:
257: return refTypeSig;
258: }
259:
260: /**
261: * Resolve refTypeSig in context of declaringType into sb.
262: */
263: public static void resolveTypeName(String refTypeSig,
264: IType declaringType, StringBuffer sb) {
265: if (isTypeNameUnresolved(refTypeSig)) {
266: sb.append(refTypeSig.substring(0, refTypeSig
267: .indexOf(Signature.C_UNRESOLVED)));
268: sb.append('L');
269: sb.append(resolveTypeName(refTypeSig, declaringType));
270: sb.append(';');
271: } else {
272: sb.append(refTypeSig);
273: }
274: }
275:
276: /**
277: * Concatenates two names. Uses a dot for separation.
278: * Both strings can be empty or <code>null</code>.
279: */
280: public static String concatenateName(String name1, String name2) {
281: StringBuffer buf = new StringBuffer();
282: if (name1 != null && name1.length() > 0) {
283: buf.append(name1);
284: }
285: if (name2 != null && name2.length() > 0) {
286: if (buf.length() > 0) {
287: buf.append('.');
288: }
289: buf.append(name2);
290: }
291: return buf.toString();
292: }
293:
294: public static IJavaElement[] codeResolve(ITextEditor editor)
295: throws JavaModelException {
296: return codeResolve(editor, true);
297: }
298:
299: /**
300: * @param primaryOnly if <code>true</code> only primary working copies will be returned
301: * @since 3.2
302: */
303: public static IJavaElement[] codeResolve(ITextEditor editor,
304: boolean primaryOnly) throws JavaModelException {
305: return codeResolve(getInput(editor, primaryOnly),
306: (ITextSelection) editor.getSelectionProvider()
307: .getSelection());
308: }
309:
310: public static IJavaElement getInput(IEditorPart editor) {
311: return getInput(editor, true);
312: }
313:
314: /**
315: * @param primaryOnly if <code>true</code> only primary working copies will be returned
316: * @since 3.2
317: */
318: private static IJavaElement getInput(IEditorPart editor,
319: boolean primaryOnly) {
320: if (editor == null)
321: return null;
322: return getEditorInputJavaElement(editor, primaryOnly);
323: }
324:
325: public static ICompilationUnit getInputAsCompilationUnit(
326: ITextEditor editor) {
327: Object editorInput = getInput(editor);
328: if (editorInput instanceof ICompilationUnit)
329: return (ICompilationUnit) editorInput;
330: return null;
331: }
332:
333: /**
334: * Returns the given editor's input as Java element.
335: *
336: * @param editor the editor
337: * @param primaryOnly if <code>true</code> only primary working copies will be returned
338: * @return the given editor's input as Java element or <code>null</code> if none
339: * @since 3.2
340: */
341: public static IJavaElement getEditorInputJavaElement(
342: IEditorPart editor, boolean primaryOnly) {
343: Assert.isNotNull(editor);
344: IEditorInput editorInput = editor.getEditorInput();
345: if (editorInput == null)
346: return null;
347:
348: IJavaElement je = getEditorInputJavaElement(editorInput);
349: if (je != null || primaryOnly)
350: return je;
351:
352: return JavaUI.getWorkingCopyManager().getWorkingCopy(
353: editorInput);
354: }
355:
356: /**
357: * Returns the Java element wrapped by the given editor input.
358: *
359: * @param editorInput the editor input
360: * @return the Java element wrapped by <code>editorInput</code> or <code>null</code> if none
361: * @since 3.2
362: */
363: public static IJavaElement getEditorInputJavaElement(
364: IEditorInput editorInput) {
365: // Performance: check working copy manager first: this is faster
366: IJavaElement je = JavaUI.getWorkingCopyManager()
367: .getWorkingCopy(editorInput);
368: if (je != null)
369: return je;
370:
371: return (IJavaElement) editorInput
372: .getAdapter(IJavaElement.class);
373: }
374:
375: public static IJavaElement[] codeResolve(IJavaElement input,
376: ITextSelection selection) throws JavaModelException {
377: if (input instanceof ICodeAssist) {
378: if (input instanceof ICompilationUnit) {
379: reconcile((ICompilationUnit) input);
380: }
381: IJavaElement[] elements = ((ICodeAssist) input).codeSelect(
382: selection.getOffset(), selection.getLength());
383: if (elements != null && elements.length > 0)
384: return elements;
385: }
386: return EMPTY_RESULT;
387: }
388:
389: public static IJavaElement getElementAtOffset(ITextEditor editor)
390: throws JavaModelException {
391: return getElementAtOffset(editor, true);
392: }
393:
394: /**
395: * @param primaryOnly if <code>true</code> only primary working copies will be returned
396: * @since 3.2
397: */
398: private static IJavaElement getElementAtOffset(ITextEditor editor,
399: boolean primaryOnly) throws JavaModelException {
400: return getElementAtOffset(getInput(editor, primaryOnly),
401: (ITextSelection) editor.getSelectionProvider()
402: .getSelection());
403: }
404:
405: public static IJavaElement getElementAtOffset(IJavaElement input,
406: ITextSelection selection) throws JavaModelException {
407: if (input instanceof ICompilationUnit) {
408: ICompilationUnit cunit = (ICompilationUnit) input;
409: reconcile(cunit);
410: IJavaElement ref = cunit
411: .getElementAt(selection.getOffset());
412: if (ref == null)
413: return input;
414: else
415: return ref;
416: } else if (input instanceof IClassFile) {
417: IJavaElement ref = ((IClassFile) input)
418: .getElementAt(selection.getOffset());
419: if (ref == null)
420: return input;
421: else
422: return ref;
423: }
424: return null;
425: }
426: }
|