| /******************************************************************************* |
| * Copyright (c) 2008, 2016 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Stephan Herrmann - Contribution for Bug 403917 - [1.8] Render TYPE_USE annotations in Javadoc hover/view |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.ui.viewsupport; |
| |
| import java.net.MalformedURLException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| |
| import org.eclipse.swt.browser.Browser; |
| import org.eclipse.swt.browser.LocationAdapter; |
| import org.eclipse.swt.browser.LocationEvent; |
| import org.eclipse.swt.browser.LocationListener; |
| import org.eclipse.swt.widgets.Display; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| |
| import org.eclipse.jdt.core.IAnnotation; |
| import org.eclipse.jdt.core.IField; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.ILocalVariable; |
| import org.eclipse.jdt.core.IMember; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.IModuleDescription; |
| import org.eclipse.jdt.core.IPackageDeclaration; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IPackageFragmentRoot; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.ITypeHierarchy; |
| import org.eclipse.jdt.core.ITypeParameter; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.Signature; |
| import org.eclipse.jdt.core.dom.IBinding; |
| |
| import org.eclipse.jdt.internal.core.manipulation.util.Strings; |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| import org.eclipse.jdt.internal.corext.util.SuperTypeHierarchyCache; |
| |
| import org.eclipse.jdt.ui.JavaElementLabels; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.JavaUIMessages; |
| |
| |
| /** |
| * Links inside Javadoc hovers and Javadoc view. |
| * |
| * @since 3.4 |
| */ |
| public class JavaElementLinks { |
| |
| /** |
| * A handler is asked to handle links to targets. |
| * |
| * @see JavaElementLinks#createLocationListener(JavaElementLinks.ILinkHandler) |
| */ |
| public interface ILinkHandler { |
| |
| /** |
| * Handle normal kind of link to given target. |
| * |
| * @param target the target to show |
| */ |
| void handleInlineJavadocLink(IJavaElement target); |
| |
| /** |
| * Handle link to given target to open in javadoc view. |
| * |
| * @param target the target to show |
| */ |
| void handleJavadocViewLink(IJavaElement target); |
| |
| /** |
| * Handle link to given target to open its declaration |
| * |
| * @param target the target to show |
| */ |
| void handleDeclarationLink(IJavaElement target); |
| |
| /** |
| * Handle link to given URL to open in browser. |
| * |
| * @param url the url to show |
| * @param display the current display |
| * @return <code>true</code> if the handler could open the link <code>false</code> if the |
| * browser should follow the link |
| */ |
| boolean handleExternalLink(URL url, Display display); |
| |
| /** |
| * Informs the handler that the text of the browser was set. |
| */ |
| void handleTextSet(); |
| } |
| |
| static class JavaElementLinkedLabelComposer extends JavaElementLabelComposer { |
| private final IJavaElement fElement; |
| |
| public JavaElementLinkedLabelComposer(IJavaElement member, StringBuffer buf) { |
| super(buf); |
| if (member instanceof IPackageDeclaration) { |
| fElement= member.getAncestor(IJavaElement.PACKAGE_FRAGMENT); |
| } else { |
| fElement= member; |
| } |
| } |
| |
| @Override |
| public String getElementName(IJavaElement element) { |
| if (element instanceof IPackageFragment || element instanceof IPackageDeclaration) { |
| return getPackageFragmentElementName(element); |
| } |
| |
| String elementName= element.getElementName(); |
| return getElementName(element, elementName); |
| } |
| |
| private String getElementName(IJavaElement element, String elementName) { |
| if (element.equals(fElement)) { // linking to the member itself would be a no-op |
| return elementName; |
| } |
| if (elementName.length() == 0) { // anonymous or lambda |
| return elementName; |
| } |
| try { |
| String uri= createURI(JAVADOC_SCHEME, element); |
| return createHeaderLink(uri, elementName); |
| } catch (URISyntaxException e) { |
| JavaPlugin.log(e); |
| return elementName; |
| } |
| } |
| |
| private String getPackageFragmentElementName(IJavaElement javaElement) { |
| IPackageFragmentRoot root= (IPackageFragmentRoot) javaElement.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); |
| String javaElementName= javaElement.getElementName(); |
| String packageName= null; |
| StringBuilder strBuffer= new StringBuilder(); |
| |
| for (String lastSegmentName : javaElementName.split("\\.")) { //$NON-NLS-1$ |
| if (packageName != null) { |
| strBuffer.append('.'); |
| packageName= packageName + '.' + lastSegmentName; |
| } else { |
| packageName= lastSegmentName; |
| } |
| IPackageFragment subFragment= root.getPackageFragment(packageName); |
| strBuffer.append(getElementName(subFragment, lastSegmentName)); |
| } |
| |
| return strBuffer.toString(); |
| } |
| |
| @Override |
| protected String getGT() { |
| return ">"; //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected String getLT() { |
| return "<"; //$NON-NLS-1$ |
| } |
| |
| @Override |
| protected String getSimpleTypeName(IJavaElement enclosingElement, String typeSig) { |
| String typeName= super.getSimpleTypeName(enclosingElement, typeSig); |
| |
| String title= ""; //$NON-NLS-1$ |
| String qualifiedName= Signature.toString(Signature.getTypeErasure(typeSig)); |
| int qualifierLength= qualifiedName.length() - typeName.length() - 1; |
| if (qualifierLength > 0) { |
| if (qualifiedName.endsWith(typeName)) { |
| title= qualifiedName.substring(0, qualifierLength); |
| title= Messages.format(JavaUIMessages.JavaElementLinks_title, title); |
| } else { |
| title= qualifiedName; // Not expected. Just show the whole qualifiedName. |
| } |
| } |
| |
| try { |
| String uri= createURI(JAVADOC_SCHEME, enclosingElement, qualifiedName, null, null); |
| return createHeaderLink(uri, typeName, title); |
| } catch (URISyntaxException e) { |
| JavaPlugin.log(e); |
| return typeName; |
| } |
| } |
| |
| @Override |
| protected String getMemberName(IJavaElement enclosingElement, String typeName, String memberName) { |
| try { |
| String uri= createURI(JAVADOC_SCHEME, enclosingElement, typeName, memberName, null); |
| return createHeaderLink(uri, memberName); |
| } catch (URISyntaxException e) { |
| JavaPlugin.log(e); |
| return memberName; |
| } |
| } |
| |
| @Override |
| protected void appendAnnotationLabels(IAnnotation[] annotations, long flags) throws JavaModelException { |
| fBuffer.append("<span style='font-weight:normal;'>"); //$NON-NLS-1$ |
| super.appendAnnotationLabels(annotations, flags); |
| fBuffer.append("</span>"); //$NON-NLS-1$ |
| } |
| } |
| |
| public static final String OPEN_LINK_SCHEME= "eclipse-open"; //$NON-NLS-1$ |
| public static final String JAVADOC_SCHEME= "eclipse-javadoc"; //$NON-NLS-1$ |
| public static final String JAVADOC_VIEW_SCHEME= "eclipse-javadoc-view"; //$NON-NLS-1$ |
| private static final char LINK_BRACKET_REPLACEMENT= '\u2603'; |
| |
| /** |
| * The link is composed of a number of segments, separated by LINK_SEPARATOR: |
| * <p> |
| * segments[0]: ""<br> |
| * segments[1]: baseElementHandle<br> |
| * segments[2]: typeName<br> |
| * segments[3]: memberName<br> |
| * segments[4...]: parameterTypeName (optional) |
| */ |
| private static final char LINK_SEPARATOR= '\u2602'; |
| |
| private JavaElementLinks() { |
| // static only |
| } |
| |
| /** |
| * Creates a location listener which uses the given handler |
| * to handle java element links. |
| * |
| * The location listener can be attached to a {@link Browser} |
| * |
| * @param handler the handler to use to handle links |
| * @return a new {@link LocationListener} |
| */ |
| public static LocationListener createLocationListener(final ILinkHandler handler) { |
| return new LocationAdapter() { |
| @Override |
| public void changing(LocationEvent event) { |
| String loc= event.location; |
| |
| if ("about:blank".equals(loc)) { //$NON-NLS-1$ |
| /* |
| * Using the Browser.setText API triggers a location change to "about:blank". |
| * XXX: remove this code once https://bugs.eclipse.org/bugs/show_bug.cgi?id=130314 is fixed |
| */ |
| //input set with setText |
| handler.handleTextSet(); |
| return; |
| } |
| |
| event.doit= false; |
| |
| if (loc.startsWith("about:")) { //$NON-NLS-1$ |
| // Relative links should be handled via head > base tag. |
| // If no base is available, links just won't work. |
| return; |
| } |
| |
| URI uri= null; |
| try { |
| uri= new URI(loc); |
| } catch (URISyntaxException e) { |
| JavaPlugin.log(e); // log bad URL, but proceed in the hope that handleExternalLink(..) can deal with it |
| } |
| |
| String scheme= uri == null ? null : uri.getScheme(); |
| boolean nomatch= false; |
| if (scheme != null) switch (scheme) { |
| case JavaElementLinks.JAVADOC_VIEW_SCHEME: |
| { |
| IJavaElement linkTarget= JavaElementLinks.parseURI(uri); |
| if (linkTarget == null) |
| return; |
| handler.handleJavadocViewLink(linkTarget); |
| break; |
| } |
| case JavaElementLinks.JAVADOC_SCHEME: |
| { |
| IJavaElement linkTarget= JavaElementLinks.parseURI(uri); |
| if (linkTarget == null) |
| return; |
| handler.handleInlineJavadocLink(linkTarget); |
| break; |
| } |
| case JavaElementLinks.OPEN_LINK_SCHEME: |
| { |
| IJavaElement linkTarget= JavaElementLinks.parseURI(uri); |
| if (linkTarget == null) |
| return; |
| handler.handleDeclarationLink(linkTarget); |
| break; |
| } |
| default: |
| nomatch= true; |
| break; |
| } |
| if (nomatch) { |
| try { |
| if (handler.handleExternalLink(new URL(loc), event.display)) |
| return; |
| event.doit= true; |
| } catch (MalformedURLException e) { |
| JavaPlugin.log(e); |
| } |
| } |
| } |
| }; |
| } |
| |
| /** |
| * Creates an {@link URI} with the given scheme for the given element. |
| * |
| * @param scheme the scheme |
| * @param element the element |
| * @return an {@link URI}, encoded as {@link URI#toASCIIString() ASCII} string, ready to be used |
| * as <code>href</code> attribute in an <code><a></code> tag |
| * @throws URISyntaxException if the arguments were invalid |
| */ |
| public static String createURI(String scheme, IJavaElement element) throws URISyntaxException { |
| return createURI(scheme, element, null, null, null); |
| } |
| |
| /** |
| * Creates an {@link URI} with the given scheme based on the given element. |
| * The additional arguments specify a member referenced from the given element. |
| * |
| * @param scheme a scheme |
| * @param element the declaring element |
| * @param refTypeName a (possibly qualified) type or package name, can be <code>null</code> |
| * @param refMemberName a member name, can be <code>null</code> |
| * @param refParameterTypes a (possibly empty) array of (possibly qualified) parameter type |
| * names, can be <code>null</code> |
| * @return an {@link URI}, encoded as {@link URI#toASCIIString() ASCII} string, ready to be used |
| * as <code>href</code> attribute in an <code><a></code> tag |
| * @throws URISyntaxException if the arguments were invalid |
| */ |
| public static String createURI(String scheme, IJavaElement element, String refTypeName, String refMemberName, String[] refParameterTypes) throws URISyntaxException { |
| /* |
| * We use an opaque URI, not ssp and fragments (to work around Safari bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=212527 (wrongly encodes #)). |
| */ |
| |
| StringBuilder ssp= new StringBuilder(60); |
| ssp.append(LINK_SEPARATOR); // make sure first character is not a / (would be hierarchical URI) |
| |
| // replace '[' manually, since URI confuses it for an IPv6 address as per RFC 2732: |
| ssp.append(element.getHandleIdentifier().replace('[', LINK_BRACKET_REPLACEMENT)); // segments[1] |
| |
| if (refTypeName != null) { |
| ssp.append(LINK_SEPARATOR); |
| ssp.append(refTypeName); // segments[2] |
| |
| if (refMemberName != null) { |
| ssp.append(LINK_SEPARATOR); |
| ssp.append(refMemberName); // segments[3] |
| |
| if (refParameterTypes != null) { |
| ssp.append(LINK_SEPARATOR); |
| for (int i= 0; i < refParameterTypes.length; i++) { |
| ssp.append(refParameterTypes[i]); // segments[4|5|..] |
| if (i != refParameterTypes.length - 1) { |
| ssp.append(LINK_SEPARATOR); |
| } |
| } |
| } |
| } |
| } |
| return new URI(scheme, ssp.toString(), null).toASCIIString(); |
| } |
| |
| public static IJavaElement parseURI(URI uri) { |
| String ssp= uri.getSchemeSpecificPart(); |
| String[] segments= ssp.split(String.valueOf(LINK_SEPARATOR), -1); |
| String refModuleName= null; |
| // replace '[' manually, since URI confuses it for an IPv6 address as per RFC 2732: |
| IJavaElement element= JavaCore.create(segments[1].replace(LINK_BRACKET_REPLACEMENT, '[')); |
| boolean canReferModuleName= canReferModuleName(element); |
| if (segments.length > 2) { |
| String refTypeName= segments[2]; |
| int index= refTypeName.indexOf('/'); |
| if (index != -1 && canReferModuleName) { |
| refModuleName= refTypeName.substring(0, index); |
| refTypeName= refTypeName.substring(index+1); |
| } |
| if ((refTypeName== null || refTypeName.isEmpty()) && |
| (refModuleName != null && !refModuleName.isEmpty())) { |
| return getModule(element, refModuleName); |
| } |
| if (refTypeName.indexOf('/') == -1) { |
| if (refTypeName.indexOf('.') == -1) { |
| try { |
| ITypeParameter resolvedTypeVariable= resolveTypeVariable(element, refTypeName); |
| if (resolvedTypeVariable != null) |
| return resolvedTypeVariable; |
| } catch (JavaModelException e) { |
| JavaPlugin.log(e); |
| } |
| } |
| } |
| if (element instanceof IAnnotation) { |
| element= element.getParent(); |
| } |
| if (element instanceof IModuleDescription) { |
| element = element.getAncestor(IJavaElement.PACKAGE_FRAGMENT); |
| // continue below in branch IPackageFragment... |
| } |
| if (element instanceof ILocalVariable) { |
| element= ((ILocalVariable) element).getDeclaringMember(); |
| } else if (element instanceof ITypeParameter) { |
| element= ((ITypeParameter) element).getDeclaringMember(); |
| } |
| if (element instanceof IMember && !(element instanceof IType)) { |
| element= ((IMember) element).getDeclaringType(); |
| } |
| |
| if (element instanceof IPackageFragment) { |
| try { |
| IPackageFragment root= (IPackageFragment) element; |
| element= resolvePackageInfoType(root, refTypeName); |
| if (element == null) { |
| // find it as package |
| IJavaProject javaProject= root.getJavaProject(); |
| return JavaModelUtil.findTypeContainer(javaProject, refTypeName); |
| } |
| } catch (JavaModelException e) { |
| JavaPlugin.log(e); |
| } |
| } |
| |
| if (element instanceof IType) { |
| try { |
| IType type= (IType) element; |
| if (refTypeName.length() > 0) { |
| type= resolveType(type, refTypeName); |
| if (type == null) { |
| IPackageFragment pack= JavaModelUtil.getPackageFragmentRoot(element).getPackageFragment(refTypeName); |
| if (pack.exists()) |
| return pack; |
| } |
| } |
| if (type != null) { |
| element= type; |
| if (segments.length > 3) { |
| String refMemberName= segments[3]; |
| if (segments.length > 4) { |
| String[] paramSignatures= new String[segments[4].length() == 0 ? 0 : segments.length - 4]; |
| for (int i= 0; i < paramSignatures.length; i++) { |
| paramSignatures[i]= Signature.createTypeSignature(segments[i + 4], false); |
| } |
| IMethod method= type.getMethod(refMemberName, paramSignatures); |
| IMethod[] methods= type.findMethods(method); |
| if (methods != null) { |
| return methods[0]; |
| } else { |
| //TODO: methods whose signature contains type parameters can not be found |
| // easily, since the Javadoc references are erasures |
| |
| //Shortcut: only check name and parameter count: |
| for (IMethod method1 : type.getMethods()) { |
| method= method1; |
| if (method.getElementName().equals(refMemberName) && method.getNumberOfParameters() == paramSignatures.length) |
| return method; |
| } |
| |
| // reference can also point to method from supertype: |
| ITypeHierarchy hierarchy= SuperTypeHierarchyCache.getTypeHierarchy(type); |
| method= JavaModelUtil.findMethodInHierarchy(hierarchy, type, refMemberName, paramSignatures, false); |
| if (method != null) |
| return method; |
| } |
| } else { |
| IField field= type.getField(refMemberName); |
| if (field.exists()) { |
| return field; |
| } else { |
| for (IMethod method : type.getMethods()) { |
| if (method.getElementName().equals(refMemberName)) |
| return method; |
| } |
| } |
| } |
| |
| } |
| } else { |
| // FIXME: either remove or show dialog |
| // JavaPlugin.logErrorMessage("JavaElementLinks could not resolve " + uri); //$NON-NLS-1$ |
| } |
| if (type == null && |
| refModuleName == null && |
| canReferModuleName && |
| segments.length <= 3) { |
| return getModule(element, refTypeName); |
| } |
| return type; |
| } catch (JavaModelException e) { |
| JavaPlugin.log(e); |
| } |
| } |
| } |
| return element; |
| } |
| |
| |
| private static IJavaElement getModule(IJavaElement element, String moduleName) { |
| if (element == null || moduleName == null) { |
| return null; |
| } |
| IJavaProject javaProject= element.getJavaProject(); |
| try { |
| return javaProject.findModule(moduleName, null); |
| } catch (JavaModelException e1) { |
| // do nothing |
| } |
| return null; |
| } |
| |
| private static boolean canReferModuleName(IJavaElement element) { |
| boolean canRefer= false; |
| if (element != null) { |
| IJavaProject javaProject= element.getJavaProject(); |
| if (javaProject != null) { |
| canRefer = JavaModelUtil.is15OrHigher(javaProject); |
| } |
| } |
| return canRefer; |
| } |
| |
| private static IType resolvePackageInfoType(IPackageFragment pack, String refTypeName) throws JavaModelException { |
| // Note: The scoping rules of JLS7 6.3 are broken for package-info.java, see https://bugs.eclipse.org/216451#c4 |
| // We follow the javadoc tool's implementation and only support fully-qualified type references: |
| IJavaProject javaProject= pack.getJavaProject(); |
| return javaProject.findType(refTypeName, (IProgressMonitor) null); |
| |
| // This implementation would make sense, but the javadoc tool doesn't support it: |
| // IClassFile classFile= pack.getClassFile(JavaModelUtil.PACKAGE_INFO_CLASS); |
| // if (classFile.exists()) { |
| // return resolveType(classFile.getType(), refTypeName); |
| // } |
| // |
| // // check if refTypeName is a qualified name |
| // int firstDot= refTypeName.indexOf('.'); |
| // if (firstDot != -1) { |
| // String typeNameRest= refTypeName.substring(firstDot + 1); |
| // String simpleTypeName= refTypeName.substring(0, firstDot); |
| // IType simpleType= resolvePackageInfoType(pack, simpleTypeName); |
| // if (simpleType != null) { |
| // // a type-qualified name |
| // return resolveType(simpleType, typeNameRest); |
| // } else { |
| // // a fully-qualified name |
| // return javaProject.findType(refTypeName, (IProgressMonitor) null); |
| // } |
| // } |
| // |
| // ICompilationUnit cu= pack.getCompilationUnit(JavaModelUtil.PACKAGE_INFO_JAVA); |
| // if (! cu.exists()) { |
| // // refTypeName is a simple name in the package-info.java from the source attachment. Sorry, we give up here... |
| // return null; |
| // } |
| // |
| // // refTypeName is a simple name in a CU. Let's play the shadowing rules of JLS7 6.4.1: |
| // // 1) single-type import |
| // // 2) enclosing package |
| // // 3) java.lang.* (JLS7 7.3) |
| // // 4) on-demand import |
| // IImportDeclaration[] imports= cu.getImports(); |
| // for (int i= 0; i < imports.length; i++) { |
| // IImportDeclaration importDecl= imports[i]; |
| // String name= importDecl.getElementName(); |
| // if (Flags.isStatic(importDecl.getFlags())) { |
| // imports[i]= null; |
| // } else if (! importDecl.isOnDemand()) { |
| // if (name.endsWith('.' + refTypeName)) { |
| // // 1) single-type import |
| // IType type= javaProject.findType(name, (IProgressMonitor) null); |
| // if (type != null) |
| // return type; |
| // } |
| // imports[i]= null; |
| // } |
| // } |
| // |
| // // 2) enclosing package |
| // IType type= javaProject.findType(pack.getElementName() + '.' + refTypeName, (IProgressMonitor) null); |
| // if (type != null) |
| // return type; |
| // |
| // // 3) java.lang.* (JLS7 7.3) |
| // type= javaProject.findType("java.lang." + refTypeName, (IProgressMonitor) null); //$NON-NLS-1$ |
| // if (type != null) |
| // return type; |
| // |
| // // 4) on-demand import |
| // for (int i= 0; i < imports.length; i++) { |
| // IImportDeclaration importDecl= imports[i]; |
| // if (importDecl != null) { |
| // String name= importDecl.getElementName(); |
| // name= name.substring(0, name.length() - 1); //remove the * |
| // type= javaProject.findType(name + refTypeName, (IProgressMonitor) null); |
| // if (type != null) |
| // return type; |
| // } |
| // } |
| // return null; |
| } |
| |
| private static ITypeParameter resolveTypeVariable(IJavaElement baseElement, String typeVariableName) throws JavaModelException { |
| while (baseElement != null) { |
| switch (baseElement.getElementType()) { |
| case IJavaElement.METHOD: |
| for (ITypeParameter typeParameter : ((IMethod)baseElement).getTypeParameters()) { |
| if (typeParameter.getElementName().equals(typeVariableName)) { |
| return typeParameter; |
| } |
| } |
| break; |
| |
| |
| case IJavaElement.TYPE: |
| for (ITypeParameter typeParameter : ((IType)baseElement).getTypeParameters()) { |
| if (typeParameter.getElementName().equals(typeVariableName)) { |
| return typeParameter; |
| } |
| } |
| break; |
| |
| |
| case IJavaElement.JAVA_MODEL: |
| case IJavaElement.JAVA_PROJECT: |
| case IJavaElement.PACKAGE_FRAGMENT: |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT: |
| |
| case IJavaElement.CLASS_FILE: |
| case IJavaElement.COMPILATION_UNIT: |
| |
| case IJavaElement.PACKAGE_DECLARATION: |
| case IJavaElement.IMPORT_CONTAINER: |
| case IJavaElement.IMPORT_DECLARATION: |
| return null; |
| |
| default: |
| break; |
| } |
| // look for type parameters in enclosing members: |
| baseElement= baseElement.getParent(); |
| } |
| return null; |
| } |
| |
| private static IType resolveType(IType baseType, String refTypeName) throws JavaModelException { |
| if (refTypeName.length() == 0) |
| return baseType; |
| |
| String[][] resolvedNames= baseType.resolveType(refTypeName); |
| if (resolvedNames != null && resolvedNames.length > 0) { |
| return baseType.getJavaProject().findType(resolvedNames[0][0], resolvedNames[0][1].replace('$', '.'), (IProgressMonitor) null); |
| |
| } else if (baseType.isBinary()) { |
| // workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=206597 |
| IType type= baseType.getJavaProject().findType(refTypeName, (IProgressMonitor) null); |
| if (type == null) { |
| // could be unqualified reference: |
| type= baseType.getJavaProject().findType(baseType.getPackageFragment().getElementName() + '.' + refTypeName, (IProgressMonitor) null); |
| } |
| return type; |
| |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Creates a link with the given URI and label text. |
| * |
| * @param uri the URI |
| * @param label the label |
| * @return the HTML link |
| * @since 3.6 |
| */ |
| public static String createLink(String uri, String label) { |
| return "<a href='" + uri + "'>" + label + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| /** |
| * Creates a header link with the given URI and label text. |
| * |
| * @param uri the URI |
| * @param label the label |
| * @return the HTML link |
| * @since 3.6 |
| */ |
| public static String createHeaderLink(String uri, String label) { |
| return createHeaderLink(uri, label, ""); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Creates a link with the given URI, label and title text. |
| * |
| * @param uri the URI |
| * @param label the label |
| * @param title the title to be displayed while hovering over the link (can be empty) |
| * @return the HTML link |
| * @since 3.10 |
| */ |
| public static String createHeaderLink(String uri, String label, String title) { |
| if (title.length() > 0) { |
| title= " title='" + title + "'"; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| return "<a class='header' href='" + uri + "'" + title + ">" + label + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| |
| /** |
| * Returns the label for a Java element with the flags as defined by {@link JavaElementLabels}. |
| * Referenced element names in the label (except the given element's name) are rendered as |
| * header links. |
| * |
| * @param element the element to render |
| * @param flags the rendering flags |
| * @return the label of the Java element |
| * @since 3.5 |
| */ |
| public static String getElementLabel(IJavaElement element, long flags) { |
| return getElementLabel(element, flags, false); |
| } |
| |
| /** |
| * Returns the label for a Java element with the flags as defined by {@link JavaElementLabels}. |
| * Referenced element names in the label are rendered as header links. |
| * If <code>linkAllNames</code> is <code>false</code>, don't link the name of the given element |
| * |
| * @param element the element to render |
| * @param flags the rendering flags |
| * @param linkAllNames if <code>true</code>, link all names; if <code>false</code>, link all names except original element's name |
| * @return the label of the Java element |
| * @since 3.6 |
| */ |
| public static String getElementLabel(IJavaElement element, long flags, boolean linkAllNames) { |
| StringBuffer buf= new StringBuffer(); |
| |
| if (!Strings.USE_TEXT_PROCESSOR) { |
| new JavaElementLinkedLabelComposer(linkAllNames ? null : element, buf).appendElementLabel(element, flags); |
| return Strings.markJavaElementLabelLTR(buf.toString()); |
| } else { |
| String label= JavaElementLabels.getElementLabel(element, flags); |
| return label.replaceAll("<", "<").replaceAll(">", ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| } |
| |
| /** |
| * Returns the label for a binding with the flags as defined by {@link JavaElementLabels}. |
| * Referenced element names in the label are rendered as header links. |
| * |
| * @param binding the binding to render |
| * @param element the corresponding Java element, used for javadoc hyperlinks |
| * @param flags the rendering flags |
| * @param haveSource true when looking at an ICompilationUnit which enables the use of short type names |
| * @return the label of the binding |
| * @since 3.11 |
| */ |
| public static String getBindingLabel(IBinding binding, IJavaElement element, long flags, boolean haveSource) { |
| StringBuffer buf= new StringBuffer(); |
| |
| if (!Strings.USE_TEXT_PROCESSOR) { |
| new BindingLinkedLabelComposer(element, buf, haveSource).appendBindingLabel(binding, flags); |
| return Strings.markJavaElementLabelLTR(buf.toString()); |
| } else { |
| String label= JavaElementLabels.getElementLabel(element, flags); |
| return label.replaceAll("<", "<").replaceAll(">", ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| } |
| } |