/******************************************************************************* * Copyright (c) 2007 Oracle Corporation. * All rights reserved. This program and the accompanying materials * are 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: * Cameron Bateman/Oracle - initial API and implementation * ********************************************************************************/ package org.eclipse.jst.jsf.context.symbol.internal.impl; import java.util.ArrayList; import java.util.List; import org.eclipse.emf.common.util.EList; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jst.jsf.common.JSFCommonPlugin; import org.eclipse.jst.jsf.common.internal.types.TypeConstants; import org.eclipse.jst.jsf.common.internal.types.ValueType; import org.eclipse.jst.jsf.common.util.JDTBeanIntrospector; import org.eclipse.jst.jsf.common.util.TypeUtil; import org.eclipse.jst.jsf.context.symbol.IJavaTypeDescriptor2; import org.eclipse.jst.jsf.context.symbol.IPropertySymbol; import org.eclipse.jst.jsf.context.symbol.ISymbol; import org.eclipse.jst.jsf.context.symbol.ITypeDescriptor; import org.eclipse.jst.jsf.context.symbol.SymbolFactory; final class Util { static ISymbol call(String methodName, EList methodArguments, String symbolName, ITypeDescriptor typeDesc) { // first, see if the type descriptor wants to handle the call ISymbol result = typeDesc.calculateSyntheticCall(methodName, methodArguments, symbolName); final IType type= typeDesc.resolveType(typeDesc.getTypeSignature()); // if the type is resolved and the typeDesc didn't already handle // the call then do this the hard way... if (type != null && result == null) { final JDTBeanIntrospector introspector = new JDTBeanIntrospector(type); final IMethod callMethod = Util.matchMethod(methodName, methodArguments, introspector.getAllMethods(),typeDesc.getTypeParameterSignatures()); if (callMethod != null) { try { // resolve the method's return type; don't erase parameters String retTypeSignature = callMethod.getReturnType(); // if we have a type variable, try to parameter match it if (Signature.getTypeSignatureKind(retTypeSignature) == Signature.TYPE_VARIABLE_SIGNATURE) { retTypeSignature = TypeUtil.matchTypeParameterToArgument (type , retTypeSignature, typeDesc.getTypeParameterSignatures()); if (retTypeSignature == null) { retTypeSignature = TypeConstants.TYPE_JAVAOBJECT; } } // otherwise, try and resolve it in type else { retTypeSignature = TypeUtil.resolveTypeSignature (type, callMethod.getReturnType(), false); } final IPropertySymbol propSymbol = SymbolFactory.eINSTANCE.createIPropertySymbol(); // TODO: there is a possible problem here for non-string keyed maps propSymbol.setName(symbolName); propSymbol.setReadable(true); { IJavaTypeDescriptor2 newTypeDesc = null; if (retTypeSignature.equals(TypeConstants.TYPE_JAVAOBJECT)) { newTypeDesc = SymbolFactory.eINSTANCE.createIBoundedJavaTypeDescriptor(); } else { newTypeDesc = SymbolFactory.eINSTANCE.createIJavaTypeDescriptor2(); } newTypeDesc.setArrayCount(Signature.getArrayCount(retTypeSignature)); // may be null newTypeDesc.setType(typeDesc.resolveType(retTypeSignature)); newTypeDesc.setTypeSignatureDelegate(retTypeSignature); propSymbol.setTypeDescriptor(newTypeDesc); } result = propSymbol; } catch (JavaModelException e) { JSFCommonPlugin.log(e); // fall-through and return null result } } } return result; } static IMethod matchMethod(String methodName, List methodArguments, IMethod[] allMethods, List typeParameterSignatures) { // final List argSigs = convertArgsToSignatures(methodArguments); IMethod matchedMethod = null; for (int i = 0; i < allMethods.length; i++) { final IMethod method = allMethods[i]; // check for names and argument count match if (method.getParameterTypes().length == methodArguments.size() && method.getElementName().equals(methodName)) { List<String> methods = resolveMethodParameters(method, typeParameterSignatures); // need to verify argument matches boolean isMatched = true; CHECK_ARGUMENTS: for (int j = 0; j < methods.size(); j++) { final ValueType valueType = (ValueType) methodArguments.get(j); // if the parameters match, or if the method expects an object // and we have a class // TODO: there are some cases not supported here like: // - method name overloading // - autoboxing primitives // - certain kinds of parameterized args if (!methods.get(j).equals(valueType.getSignature()) && !(methods.get(j).equals(TypeConstants.TYPE_JAVAOBJECT) && Signature.getTypeSignatureKind(valueType.getSignature())==Signature.CLASS_TYPE_SIGNATURE)) { // not a match isMatched = false; break CHECK_ARGUMENTS; } } if (isMatched) { return method; } } } return matchedMethod; } static List<String> resolveMethodParameters(IMethod method, List typeParametersSignatures) { List<String> resolved = new ArrayList<String>(); String[] parameterTypes = method.getParameterTypes(); for (String parameter : parameterTypes) { parameter = TypeUtil.resolveTypeSignature(method.getDeclaringType() , parameter, false); if (Signature.getTypeSignatureKind(parameter) == Signature.TYPE_VARIABLE_SIGNATURE) { parameter = TypeUtil.matchTypeParameterToArgument (method.getDeclaringType(), parameter, typeParametersSignatures); } if (parameter == null) { parameter = TypeConstants.TYPE_JAVAOBJECT; } resolved.add(parameter); } return resolved; } }