blob: 0c2f288e3c3c0bc19599049705a8776eb00a47bf [file] [log] [blame]
/*******************************************************************************
* 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;
}
}