// of lists that contain methods with the same name
Map<String, List<MethodMirror>> methods = new LinkedHashMap<String, List<MethodMirror>>();
collectMethods(classMirror.getDirectMethods(), methods, isCeylon, isFromJDK);
if(isCeylon && klass instanceof LazyInterface && CodegenUtil.isCompanionClassNeeded(klass)){
ClassMirror companionClass = ((LazyInterface)klass).companionClass;
if(companionClass != null)
collectMethods(companionClass.getDirectMethods(), methods, isCeylon, isFromJDK);
else
logWarning("CompanionClass missing for "+klass);
}
// Add the methods
for(List<MethodMirror> methodMirrors : methods.values()){
boolean isOverloaded = isMethodOverloaded(methodMirrors);
List<Declaration> overloads = (isOverloaded) ? new ArrayList<Declaration>(methodMirrors.size()) : null;
for (MethodMirror methodMirror : methodMirrors) {
String methodName = methodMirror.getName();
// same tests as in isMethodOverloaded()
if(methodMirror.isConstructor() || isInstantiator(methodMirror)) {
break;
} else if(isGetter(methodMirror)) {
// simple attribute
addValue(klass, methodMirror, getJavaAttributeName(methodName), isCeylon);
} else if(isSetter(methodMirror)) {
// We skip setters for now and handle them later
variables.put(methodMirror, methodMirrors);
} else if(isHashAttribute(methodMirror)) {
// ERASURE
// Un-erasing 'hash' attribute from 'hashCode' method
addValue(klass, methodMirror, "hash", isCeylon);
} else if(isStringAttribute(methodMirror)) {
// ERASURE
// Un-erasing 'string' attribute from 'toString' method
addValue(klass, methodMirror, "string", isCeylon);
} else if(!methodMirror.getName().equals("hash")
&& !methodMirror.getName().equals("string")){
// normal method
Method m = addMethod(klass, methodMirror, classMirror, isCeylon, isOverloaded);
if (isOverloaded) {
overloads.add(m);
}
}
}
if (overloads != null && !overloads.isEmpty()) {
// We create an extra "abstraction" method for overloaded methods
Method abstractionMethod = addMethod(klass, methodMirrors.get(0), classMirror, false, false);
abstractionMethod.setAbstraction(true);
abstractionMethod.setOverloads(overloads);
abstractionMethod.setType(newUnknownType());
}
}
for(FieldMirror fieldMirror : classMirror.getDirectFields()){
// We skip members marked with @Ignore
if(fieldMirror.getAnnotation(CEYLON_IGNORE_ANNOTATION) != null)
continue;
if(isCeylon && fieldMirror.isStatic())
continue;
// FIXME: temporary, because some private classes from the jdk are
// referenced in private methods but not available
if(isFromJDK && !fieldMirror.isPublic())
continue;
String name = fieldMirror.getName();
// skip the field if "we've already got one"
boolean conflicts = klass.getDirectMember(name, null, false) != null
|| "equals".equals(name)
|| "string".equals(name)
|| "hash".equals(name);
if (!conflicts) {
addValue(klass, fieldMirror.getName(), fieldMirror, isCeylon);
}
}
// Having loaded methods and values, we can now set the constructor parameters
if(constructor != null
&& (!(klass instanceof LazyClass) || !((LazyClass)klass).isAnonymous()))
setParameters((Class)klass, constructor, isCeylon, klass);
// Now marry-up attributes and parameters)
if (klass instanceof Class) {
for (Declaration m : klass.getMembers()) {
if (Decl.isValue(m)) {
Value v = (Value)m;
Parameter p = ((Class)klass).getParameter(v.getName());
if (p != null) {
p.setHidden(true);
}
}
}
}
// Now mark all Values for which Setters exist as variable
for(Entry<MethodMirror, List<MethodMirror>> setterEntry : variables.entrySet()){
MethodMirror setter = setterEntry.getKey();
String name = getJavaAttributeName(setter.getName());
// make sure we handle private postfixes
name = Util.strip(name, isCeylon, setter.isPublic());
Declaration decl = klass.getMember(name, null, false);
boolean foundGetter = false;
// skip Java fields, which we only get if there is no getter method, in that case just add the setter method
if (decl instanceof Value && decl instanceof FieldValue == false) {
Value value = (Value)decl;
VariableMirror setterParam = setter.getParameters().get(0);
ProducedType paramType = obtainType(setterParam.getType(), setterParam, klass, Decl.getModuleContainer(klass), VarianceLocation.INVARIANT,
"setter '"+setter.getName()+"'", klass);
// only add the setter if it has exactly the same type as the getter
if(paramType.isExactly(value.getType())){
foundGetter = true;
value.setVariable(true);
if(decl instanceof JavaBeanValue)
((JavaBeanValue)decl).setSetterName(setter.getName());
if(value.isTransient()){
// must be a real setter
makeSetter(value, null);
}
}else
logVerbose("Setter parameter type for "+name+" does not match corresponding getter type, adding setter as a method");
}
if(!foundGetter){
// it was not a setter, it was a method, let's add it as such
addMethod(klass, setter, classMirror, isCeylon, false);
}
}
// In some cases, where all constructors are ignored, we can end up with no constructor, so
// pretend we have one which takes no parameters (eg. ceylon.language.String).
if(klass instanceof Class
&& !((Class) klass).isAbstraction()
&& !klass.isAnonymous()
&& ((Class) klass).getParameterList() == null){
((Class) klass).setParameterList(new ParameterList());
}
setExtendedType(klass, classMirror);
setSatisfiedTypes(klass, classMirror);
setCaseTypes(klass, classMirror);
setAnnotations(klass, classMirror);
// local declarations come last, because they need all members to be completed first
if(!klass.isAlias()){
ClassMirror containerMirror = classMirror;
if(klass instanceof LazyInterface){
ClassMirror companionClass = ((LazyInterface) klass).companionClass;
if(companionClass != null)
containerMirror = companionClass;
}
addLocalDeclarations((LazyContainer) klass, containerMirror, classMirror);
}