blob: b22bcc9b7bd992135efd076e38975cd354d57355 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2014 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
* Technical University Berlin - extended API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.core.util.Util;
import org.eclipse.objectteams.otdt.core.IMethodSpec;
/**
* @see IMethod
*/
public class SourceMethod extends NamedMember implements IMethod {
/**
* The parameter type signatures of the method - stored locally
* to perform equality test. <code>null</code> indicates no
* parameters.
*/
protected String[] parameterTypes;
//{ObjectTeams: which scope to use for parameters?
public boolean[] parameterBaseclassFlags;
// SH}
protected SourceMethod(JavaElement parent, String name, String[] parameterTypes) {
super(parent, name);
// Assertion disabled since bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=179011
// Assert.isTrue(name.indexOf('.') == -1);
if (parameterTypes == null) {
this.parameterTypes= CharOperation.NO_STRINGS;
} else {
this.parameterTypes= parameterTypes;
}
}
//{ObjectTeams: converting factory method:
public static IMethod createHandle(JavaElement parent, IMethodSpec methodData) {
final String returnType = methodData.getReturnType();
final String[] parameterNames = methodData.getArgumentNames();
// create a handle that can answer some bits without computing infos:
return new SourceMethod(parent, methodData.getSelector(), methodData.getArgumentTypes()) {
@Override
public String getReturnType() {
return returnType;
}
@Override
public String[] getParameterNames() {
return parameterNames;
}
};
}
// SH}
@Override
protected void closing(Object info) throws JavaModelException {
super.closing(info);
SourceMethodElementInfo elementInfo = (SourceMethodElementInfo) info;
ITypeParameter[] typeParameters = elementInfo.typeParameters;
for (int i = 0, length = typeParameters.length; i < length; i++) {
((TypeParameter) typeParameters[i]).close();
}
}
@Override
public boolean equals(Object o) {
if (!(o instanceof SourceMethod)) return false;
return super.equals(o) && Util.equalArraysOrNull(this.parameterTypes, ((SourceMethod)o).parameterTypes);
}
@Override
public IMemberValuePair getDefaultValue() throws JavaModelException {
SourceMethodElementInfo sourceMethodInfo = (SourceMethodElementInfo) getElementInfo();
if (sourceMethodInfo.isAnnotationMethod()) {
return ((SourceAnnotationMethodInfo) sourceMethodInfo).defaultValue;
}
return null;
}
/**
* @see IJavaElement
*/
@Override
public int getElementType() {
return METHOD;
}
/**
* @see IMethod
*/
@Override
public String[] getExceptionTypes() throws JavaModelException {
SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
char[][] exs= info.getExceptionTypeNames();
return CompilationUnitStructureRequestor.convertTypeNamesToSigs(exs);
}
/**
* @see JavaElement#getHandleMemento(StringBuffer)
*/
@Override
protected void getHandleMemento(StringBuffer buff) {
((JavaElement) getParent()).getHandleMemento(buff);
char delimiter = getHandleMementoDelimiter();
buff.append(delimiter);
escapeMementoName(buff, getElementName());
for (int i = 0; i < this.parameterTypes.length; i++) {
buff.append(delimiter);
escapeMementoName(buff, this.parameterTypes[i]);
}
if (this.occurrenceCount > 1) {
buff.append(JEM_COUNT);
buff.append(this.occurrenceCount);
}
}
/**
* @see JavaElement#getHandleMemento()
*/
@Override
protected char getHandleMementoDelimiter() {
return JavaElement.JEM_METHOD;
}
@Override
public String getKey() {
try {
return getKey(this, false/*don't open*/);
} catch (JavaModelException e) {
// happen only if force open is true
return null;
}
}
/**
* @see IMethod
*/
@Override
public int getNumberOfParameters() {
return this.parameterTypes == null ? 0 : this.parameterTypes.length;
}
/**
* @see IMethod
*/
@Override
public String[] getParameterNames() throws JavaModelException {
SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
char[][] names= info.getArgumentNames();
return CharOperation.toStrings(names);
}
/**
* @see IMethod
*/
@Override
public String[] getParameterTypes() {
return this.parameterTypes;
}
@Override
public ITypeParameter getTypeParameter(String typeParameterName) {
return new TypeParameter(this, typeParameterName);
}
@Override
public ITypeParameter[] getTypeParameters() throws JavaModelException {
SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
return info.typeParameters;
}
@Override
public ILocalVariable[] getParameters() throws JavaModelException {
ILocalVariable[] arguments = ((SourceMethodElementInfo) getElementInfo()).arguments;
if (arguments == null)
return LocalVariable.NO_LOCAL_VARIABLES;
return arguments;
}
/**
* @see IMethod#getTypeParameterSignatures()
* @since 3.0
* @deprecated
*/
@Override
public String[] getTypeParameterSignatures() throws JavaModelException {
ITypeParameter[] typeParameters = getTypeParameters();
int length = typeParameters.length;
String[] typeParameterSignatures = new String[length];
for (int i = 0; i < length; i++) {
TypeParameter typeParameter = (TypeParameter) typeParameters[i];
TypeParameterElementInfo info = (TypeParameterElementInfo) typeParameter.getElementInfo();
char[][] bounds = info.bounds;
if (bounds == null) {
typeParameterSignatures[i] = Signature.createTypeParameterSignature(typeParameter.getElementName(), CharOperation.NO_STRINGS);
} else {
int boundsLength = bounds.length;
char[][] boundSignatures = new char[boundsLength][];
for (int j = 0; j < boundsLength; j++) {
boundSignatures[j] = Signature.createCharArrayTypeSignature(bounds[j], false);
}
typeParameterSignatures[i] = new String(Signature.createTypeParameterSignature(typeParameter.getElementName().toCharArray(), boundSignatures));
}
}
return typeParameterSignatures;
}
@Override
public IJavaElement getPrimaryElement(boolean checkOwner) {
if (checkOwner) {
CompilationUnit cu = (CompilationUnit)getAncestor(COMPILATION_UNIT);
if (cu.isPrimary()) return this;
}
IJavaElement primaryParent = this.parent.getPrimaryElement(false);
return ((IType)primaryParent).getMethod(this.name, this.parameterTypes);
}
@Override
public String[] getRawParameterNames() throws JavaModelException {
return getParameterNames();
}
/**
* @see IMethod
*/
@Override
public String getReturnType() throws JavaModelException {
SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
return Signature.createTypeSignature(info.getReturnTypeName(), false);
}
/**
* @see IMethod
*/
@Override
public String getSignature() throws JavaModelException {
SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
return Signature.createMethodSignature(this.parameterTypes, Signature.createTypeSignature(info.getReturnTypeName(), false));
}
/**
* @see org.eclipse.jdt.internal.core.JavaElement#hashCode()
*/
@Override
public int hashCode() {
int hash = super.hashCode();
for (int i = 0, length = this.parameterTypes.length; i < length; i++) {
hash = Util.combineHashCodes(hash, this.parameterTypes[i].hashCode());
}
return hash;
}
/**
* @see IMethod
*/
@Override
public boolean isConstructor() throws JavaModelException {
if (!getElementName().equals(this.parent.getElementName())) {
// faster than reaching the info
return false;
}
SourceMethodElementInfo info = (SourceMethodElementInfo) getElementInfo();
return info.isConstructor();
}
/**
* @see IMethod#isMainMethod()
*/
@Override
public boolean isMainMethod() throws JavaModelException {
return this.isMainMethod(this);
}
/**
* @see IMethod#isLambdaMethod()
*/
@Override
public boolean isLambdaMethod() {
return false;
}
@Override
public boolean isResolved() {
return false;
}
/**
* @see IMethod#isSimilar(IMethod)
*/
@Override
public boolean isSimilar(IMethod method) {
return
areSimilarMethods(
getElementName(), getParameterTypes(),
method.getElementName(), method.getParameterTypes(),
null);
}
/**
*/
@Override
public String readableName() {
StringBuffer buffer = new StringBuffer(super.readableName());
buffer.append('(');
int length;
if (this.parameterTypes != null && (length = this.parameterTypes.length) > 0) {
for (int i = 0; i < length; i++) {
buffer.append(Signature.toString(this.parameterTypes[i]));
if (i < length - 1) {
buffer.append(", "); //$NON-NLS-1$
}
}
}
buffer.append(')');
return buffer.toString();
}
@Override
public JavaElement resolved(Binding binding) {
SourceRefElement resolvedHandle = new ResolvedSourceMethod(this.parent, this.name, this.parameterTypes, new String(binding.computeUniqueKey()));
//{ObjectTeams: propagate this flag array:
((ResolvedSourceMethod)resolvedHandle).parameterBaseclassFlags = this.parameterBaseclassFlags;
// SH}
resolvedHandle.occurrenceCount = this.occurrenceCount;
return resolvedHandle;
}
/**
* @private Debugging purposes
*/
@Override
protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
buffer.append(tabString(tab));
if (info == null) {
toStringName(buffer);
buffer.append(" (not open)"); //$NON-NLS-1$
} else if (info == NO_INFO) {
toStringName(buffer);
} else {
SourceMethodElementInfo methodInfo = (SourceMethodElementInfo) info;
int flags = methodInfo.getModifiers();
if (Flags.isStatic(flags)) {
buffer.append("static "); //$NON-NLS-1$
}
if (!methodInfo.isConstructor()) {
buffer.append(methodInfo.getReturnTypeName());
buffer.append(' ');
}
toStringName(buffer, flags);
}
}
@Override
protected void toStringName(StringBuffer buffer) {
toStringName(buffer, 0);
}
protected void toStringName(StringBuffer buffer, int flags) {
buffer.append(getElementName());
buffer.append('(');
String[] parameters = getParameterTypes();
int length;
if (parameters != null && (length = parameters.length) > 0) {
boolean isVarargs = Flags.isVarargs(flags);
for (int i = 0; i < length; i++) {
try {
if (i < length - 1) {
buffer.append(Signature.toString(parameters[i]));
buffer.append(", "); //$NON-NLS-1$
} else if (isVarargs) {
// remove array from signature
String parameter = parameters[i].substring(1);
buffer.append(Signature.toString(parameter));
buffer.append(" ..."); //$NON-NLS-1$
} else {
buffer.append(Signature.toString(parameters[i]));
}
} catch (IllegalArgumentException e) {
// parameter signature is malformed
buffer.append("*** invalid signature: "); //$NON-NLS-1$
buffer.append(parameters[i]);
}
}
}
buffer.append(')');
if (this.occurrenceCount > 1) {
buffer.append("#"); //$NON-NLS-1$
buffer.append(this.occurrenceCount);
}
}
}