/******************************************************************************* * Copyright (c) 2009 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.java; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.jboss.tools.common.core.CommonCorePlugin; import org.jboss.tools.common.util.EclipseJavaUtil; public class ParametedTypeFactory { // I S J C F D Z static Map<Character,String> primitives = new HashMap<Character, String>(); static { primitives.put(Signature.C_INT, "Ljava.lang.Integer;"); //$NON-NLS-1$ primitives.put(Signature.C_SHORT, "Ljava.lang.Short;"); //$NON-NLS-1$ primitives.put(Signature.C_LONG, "Ljava.lang.Long;"); //$NON-NLS-1$ primitives.put(Signature.C_CHAR, "Ljava.lang.Character;"); //$NON-NLS-1$ primitives.put(Signature.C_FLOAT, "Ljava.lang.Float;"); //$NON-NLS-1$ primitives.put(Signature.C_DOUBLE, "Ljava.lang.Double;"); //$NON-NLS-1$ primitives.put(Signature.C_BOOLEAN, "Ljava.lang.Boolean;"); //$NON-NLS-1$ primitives.put(Signature.C_BYTE, "Ljava.lang.Boolean;"); //$NON-NLS-1$ } //unresolved Object signature public static String OBJECT = "QObject;"; //$NON-NLS-1$ Map<String, ParametedType> cache = new Hashtable<String, ParametedType>(); public ParametedType newParametedType(IType type) { ParametedType parametedType = new ParametedType(); if(type != null && !type.isBinary()) { ISourceRange r = null; try { r = type.getNameRange(); } catch (CoreException e) { CommonCorePlugin.getDefault().logError(e); } if(r != null) { parametedType = new TypeDeclaration(parametedType, type.getResource(), r.getOffset(), r.getLength()); } } parametedType.setFactory(this); parametedType.setType(type); if(type != null) parametedType.setSignature(Signature.C_RESOLVED + type.getFullyQualifiedName() + Signature.C_SEMICOLON); String[] ps = null; try { ps = type.getTypeParameterSignatures(); } catch (JavaModelException e) { CommonCorePlugin.getDefault().logError(e); } if(ps != null && ps.length > 0) { for (int i = 0; i < ps.length; i++) { try { ParametedType p = getParametedTypeForParameter(type, ps[i], null); if(p != null) parametedType.addParameter(p); } catch (JavaModelException e) { CommonCorePlugin.getDefault().logError(e); } } } return parametedType; } public ParametedType getParametedType(IMember context, String typeSignature) throws JavaModelException { return getParametedType(context, null, typeSignature); } public ParametedType getParametedType(IMember context, IParametedType basetype, String typeSignature) throws JavaModelException { if(typeSignature == null) return null; if(basetype != null) { ParametedType param = ((ParametedType)basetype).findParameter(typeSignature); if(param != null) return param; } IType contextType = context instanceof IType ? (IType)context : context.getDeclaringType(); String key = context == null || context.isBinary() || OBJECT.equals(typeSignature) ? typeSignature : contextType.getFullyQualifiedName() + "+" + typeSignature; if(cache.containsKey(key)) return cache.get(key); ParametedType result = new ParametedType(); result.setFactory(this); result.setSignature(typeSignature); typeSignature = typeSignature.substring(result.getArrayIndex()); char c = typeSignature.length() == 0 ? '\0' : typeSignature.charAt(0); if(primitives.containsKey(c) && typeSignature.length() == 1) { typeSignature = primitives.get(c); result.setSignature(result.getArrayPrefix() + typeSignature); result.setPrimitive(true); } else if(c == Signature.C_EXTENDS) { typeSignature = typeSignature.substring(1); result.setUpper(true); } else if(c == Signature.C_SUPER) { typeSignature = typeSignature.substring(1); result.setLower(true); } else if(c == Signature.C_STAR && typeSignature.length() == 1) { result.setUpper(true); return result; } int startToken = typeSignature.indexOf(Signature.C_GENERIC_START); if(startToken < 0) { String resovedTypeName = EclipseJavaUtil.resolveTypeAsString(contextType, typeSignature); if(resovedTypeName == null) return null; if(!context.isBinary() || typeSignature.charAt(0) == Signature.C_TYPE_VARIABLE) { StringBuffer ns = new StringBuffer(); ns.append(result.getArrayPrefix()); if(result.isLower()) ns.append(Signature.C_SUPER); if(result.isUpper()) ns.append(Signature.C_EXTENDS); ns.append(Signature.C_RESOLVED).append(resovedTypeName).append(Signature.C_SEMICOLON); result.setSignature(ns.toString()); } IType type = EclipseJavaUtil.findType(context.getJavaProject(), resovedTypeName); if(type != null) { result.setType(type); cache.put(key, result); return result; } if(context instanceof IMethod) { String[] ps = ((IMethod)context).getTypeParameterSignatures(); for (int i = 0; i < ps.length; i++) { ParametedType st = getParametedTypeForParameter(context, ps[i], result); if(st != null) { if(st.getSignature().indexOf(Signature.C_COLON) >= 0) { CommonCorePlugin.getDefault().logWarning("Wrong signature=" + st.getSignature()); } return st; } } } String[] ps = contextType.getTypeParameterSignatures(); for (int i = 0; i < ps.length; i++) { ParametedType st = getParametedTypeForParameter(contextType, ps[i], result); if(st != null) return st; } } else { int endToken = typeSignature.lastIndexOf(Signature.C_GENERIC_END); if(endToken < startToken) return null; String typeName = typeSignature.substring(0, startToken) + typeSignature.substring(endToken + 1); String resovedTypeName = EclipseJavaUtil.resolveTypeAsString(contextType, typeName); if(resovedTypeName == null) return null; IType type = EclipseJavaUtil.findType(context.getJavaProject(), resovedTypeName); if(type != null) { result.setType(type); cache.put(key, result); StringBuffer newParams = new StringBuffer(); String[] paramSignatures = null; try { paramSignatures = Signature.getTypeArguments(typeSignature); } catch (IllegalArgumentException e) { CommonCorePlugin.getDefault().logError(e); } if(paramSignatures != null) for (String paramSignature: paramSignatures) { ParametedType param = getParametedType(context, basetype, paramSignature); if(param == null) { param = new ParametedType(); param.setSignature(paramSignature); } result.addParameter(param); newParams.append(param.getSignature()); } if(!context.isBinary()) { StringBuffer ns = new StringBuffer(); ns.append(result.getArrayPrefix()); if(result.isLower()) ns.append(Signature.C_SUPER); if(result.isUpper()) ns.append(Signature.C_EXTENDS); ns.append(Signature.C_RESOLVED) .append(resovedTypeName) .append(Signature.C_GENERIC_START) .append(newParams) .append(Signature.C_GENERIC_END) .append(Signature.C_SEMICOLON); result.setSignature(ns.toString()); } return result; } } return null; } public ParametedType getParametedTypeForParameter(IMember context, String typeParameterSignature, ParametedType result) throws JavaModelException { IType contextType = context instanceof IType ? (IType)context : context.getDeclaringType(); String key = context == null ? typeParameterSignature : contextType.getFullyQualifiedName() + "+" + typeParameterSignature; String t = Signature.getTypeVariable(typeParameterSignature); String[] bounds = Signature.getTypeParameterBounds(typeParameterSignature); t = Signature.C_RESOLVED + t + Signature.C_SEMICOLON; if(result == null || t.equals(result.getSignature()) || result.getSignature().endsWith("[" + t)) { if(bounds.length > 0 && bounds[0].length() > 0) { ParametedType st = getParametedType(contextType, bounds[0]); if(st != null) { result = new TypeDeclaration(st, context.getResource(), 0, 0); result.setUpper(true); } } else if(result != null) { result.setSignature(t); } if(result == null) { result = new ParametedType(); result.setFactory(this); result.setSignature(t); } result.setVariable(true); cache.put(key, result); return result; } return null; } public void clean() { cache.clear(); } }