/* https://bugs.eclipse.org/bugs/show_bug.cgi?id=324850, Since a 1.4 project can have a 1.5
type as a super type and the 1.5 type could be generic, we must internalize usages of type
variables properly in order to be able to apply substitutions and thus be able to detect
overriding in the presence of generics. Seeing the erased form is not good enough.
*/
TypeAnnotationWalker walker = getTypeAnnotationWalker(method.getTypeAnnotations());
char[] methodSignature = method.getGenericSignature(); // always use generic signature, even in 1.4
if (methodSignature == null) { // no generics
char[] methodDescriptor = method.getMethodDescriptor(); // of the form (I[Ljava/jang/String;)V
int numOfParams = 0;
char nextChar;
int index = 0; // first character is always '(' so skip it
while ((nextChar = methodDescriptor[++index]) != Util.C_PARAM_END) {
if (nextChar != Util.C_ARRAY) {
numOfParams++;
if (nextChar == Util.C_RESOLVED)
while ((nextChar = methodDescriptor[++index]) != Util.C_NAME_END){/*empty*/}
}
}
// Ignore synthetic argument for member types or enum types.
int startIndex = 0;
if (method.isConstructor()) {
if (isMemberType() && !isStatic()) {
// enclosing type
startIndex++;
}
if (isEnum()) {
// synthetic arguments (String, int)
startIndex += 2;
}
}
int size = numOfParams - startIndex;
if (size > 0) {
parameters = new TypeBinding[size];
if (this.environment.globalOptions.storeAnnotations)
paramAnnotations = new AnnotationBinding[size][];
index = 1;
short visibleIdx = 0;
int end = 0; // first character is always '(' so skip it
for (int i = 0; i < numOfParams; i++) {
while ((nextChar = methodDescriptor[++end]) == Util.C_ARRAY){/*empty*/}
if (nextChar == Util.C_RESOLVED)
while ((nextChar = methodDescriptor[++end]) != Util.C_NAME_END){/*empty*/}
if (i >= startIndex) { // skip the synthetic arg if necessary
parameters[i - startIndex] = this.environment.getTypeFromSignature(methodDescriptor, index, end, false, this, missingTypeNames, walker.toMethodParameter(visibleIdx++));
// 'paramAnnotations' line up with 'parameters'
// int parameter to method.getParameterAnnotations() include the synthetic arg
if (paramAnnotations != null)
paramAnnotations[i - startIndex] = createAnnotations(method.getParameterAnnotations(i - startIndex), this.environment, missingTypeNames);
}
index = end + 1;
}
}
char[][] exceptionTypes = method.getExceptionTypeNames();
if (exceptionTypes != null) {
size = exceptionTypes.length;
if (size > 0) {
exceptions = new ReferenceBinding[size];
for (int i = 0; i < size; i++)
exceptions[i] = this.environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1, false, missingTypeNames, walker.toThrows(i));
}
}
if (!method.isConstructor())
returnType = this.environment.getTypeFromSignature(methodDescriptor, index + 1, -1, false, this, missingTypeNames, walker.toMethodReturn()); // index is currently pointing at the ')'
final int argumentNamesLength = argumentNames == null ? 0 : argumentNames.length;
if (startIndex > 0 && argumentNamesLength > 0) {
// We'll have to slice the starting arguments off
if (startIndex >= argumentNamesLength) {
argumentNames = Binding.NO_PARAMETER_NAMES; // We know nothing about the argument names
} else {
char[][] slicedArgumentNames = new char[argumentNamesLength - startIndex][];
System.arraycopy(argumentNames, startIndex, slicedArgumentNames, 0, argumentNamesLength - startIndex);
argumentNames = slicedArgumentNames;
}
}
} else {
methodModifiers |= ExtraCompilerModifiers.AccGenericSignature;
// MethodTypeSignature = ParameterPart(optional) '(' TypeSignatures ')' return_typeSignature ['^' TypeSignature (optional)]
SignatureWrapper wrapper = new SignatureWrapper(methodSignature, use15specifics);
if (wrapper.signature[wrapper.start] == Util.C_GENERIC_START) {
// <A::Ljava/lang/annotation/Annotation;>(Ljava/lang/Class<TA;>;)TA;
// ParameterPart = '<' ParameterSignature(s) '>'
wrapper.start++; // skip '<'
typeVars = createTypeVariables(wrapper, false, missingTypeNames, walker, false/*class*/);
wrapper.start++; // skip '>'
}
if (wrapper.signature[wrapper.start] == Util.C_PARAM_START) {
wrapper.start++; // skip '('
if (wrapper.signature[wrapper.start] == Util.C_PARAM_END) {
wrapper.start++; // skip ')'
} else {
java.util.ArrayList types = new java.util.ArrayList(2);
short rank = 0;
while (wrapper.signature[wrapper.start] != Util.C_PARAM_END)
types.add(this.environment.getTypeFromTypeSignature(wrapper, typeVars, this, missingTypeNames, walker.toMethodParameter(rank++)));
wrapper.start++; // skip ')'
int numParam = types.size();
parameters = new TypeBinding[numParam];
types.toArray(parameters);
if (this.environment.globalOptions.storeAnnotations) {
paramAnnotations = new AnnotationBinding[numParam][];
for (int i = 0; i < numParam; i++)
paramAnnotations[i] = createAnnotations(method.getParameterAnnotations(i), this.environment, missingTypeNames);
}
}
}
// always retrieve return type (for constructors, its V for void - will be ignored)
returnType = this.environment.getTypeFromTypeSignature(wrapper, typeVars, this, missingTypeNames, walker.toMethodReturn());
if (!wrapper.atEnd() && wrapper.signature[wrapper.start] == Util.C_EXCEPTION_START) {
// attempt to find each exception if it exists in the cache (otherwise - resolve it when requested)
java.util.ArrayList types = new java.util.ArrayList(2);
int excRank = 0;
do {
wrapper.start++; // skip '^'
types.add(this.environment.getTypeFromTypeSignature(wrapper, typeVars, this, missingTypeNames,
walker.toThrows(excRank++)));
} while (!wrapper.atEnd() && wrapper.signature[wrapper.start] == Util.C_EXCEPTION_START);
exceptions = new ReferenceBinding[types.size()];
types.toArray(exceptions);
} else { // get the exceptions the old way
char[][] exceptionTypes = method.getExceptionTypeNames();
if (exceptionTypes != null) {
int size = exceptionTypes.length;
if (size > 0) {
exceptions = new ReferenceBinding[size];
for (int i = 0; i < size; i++)
exceptions[i] = this.environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1, false, missingTypeNames, walker.toThrows(i));
}
}
}
}
MethodBinding result = method.isConstructor()
? new MethodBinding(methodModifiers, parameters, exceptions, this)
: new MethodBinding(methodModifiers, method.getSelector(), returnType, parameters, exceptions, this);
IBinaryAnnotation[] receiverAnnotations = walker.toReceiver().getAnnotationsAtCursor();
if (receiverAnnotations != null && receiverAnnotations.length > 0) {
result.receiver = this.environment.createAnnotatedType(this, createAnnotations(receiverAnnotations, this.environment, missingTypeNames));
}
if (this.environment.globalOptions.storeAnnotations) {
IBinaryAnnotation[] annotations = method.getAnnotations();
if (annotations == null || annotations.length == 0)
if (method.isConstructor())
annotations = walker.toMethodReturn().getAnnotationsAtCursor(); // FIXME: When both exist, order could become an issue.
result.setAnnotations(
createAnnotations(annotations, this.environment, missingTypeNames),
paramAnnotations,
isAnnotationType() ? convertMemberValue(method.getDefaultValue(), this.environment, missingTypeNames, true) : null,
this.environment);