Skip to content

Commit

Permalink
improve detection of getter and setter
Browse files Browse the repository at this point in the history
  • Loading branch information
pvojtechovsky committed Oct 13, 2017
1 parent 92b3daf commit ee857cf
Showing 1 changed file with 59 additions and 10 deletions.
69 changes: 59 additions & 10 deletions src/main/java/spoon/generating/RoleHandlersGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ class RoleIntefaceMethods {
}
void addRoleMethod(CtMethod m) {
roleMethods.add(m);
getOrCreatte(allRoleMethodsBySignature, m.getSignature(), () -> new ArrayList<>())
getOrCreate(allRoleMethodsBySignature, m.getSignature(), () -> new ArrayList<>())
.add(m);
}
void addSuperType(RoleIntefaceMethods superTypeRIM) {
superTypes.add(superTypeRIM);
for (Map.Entry<String, List<CtMethod<?>>> e : superTypeRIM.allRoleMethodsBySignature.entrySet()) {
getOrCreatte(allRoleMethodsBySignature, e.getKey(), () -> new ArrayList<>()).addAll(e.getValue());
getOrCreate(allRoleMethodsBySignature, e.getKey(), () -> new ArrayList<>()).addAll(e.getValue());
}
}
}
Expand Down Expand Up @@ -133,7 +133,7 @@ public void process() {
*/
private Map<CtRole, RoleIntefaceMethods> collectMethodsOfType(Map<CtType, Map<CtRole, RoleIntefaceMethods>> loadedInterfaces, CtType type) {
//get cached or create new map of RoleIntefaceMethods of `type`
return getOrCreatte(loadedInterfaces, type, () -> {
return getOrCreate(loadedInterfaces, type, () -> {
//collect all RoleIntefaceMethods of `type`
Map<CtRole, RoleIntefaceMethods> rimByRole = new HashMap<>();
type.filterChildren(new TypeFilter<>(CtAnnotation.class))
Expand All @@ -149,7 +149,7 @@ private Map<CtRole, RoleIntefaceMethods> collectMethodsOfType(Map<CtType, Map<Ct
CtMethod m = (CtMethod) a.getParent();
String handlerName = getHandlerName(type, role);
//get or create method holder for the type and role
RoleIntefaceMethods rim = getOrCreatte(rimByRole, role, () -> new RoleIntefaceMethods(role, type));
RoleIntefaceMethods rim = getOrCreate(rimByRole, role, () -> new RoleIntefaceMethods(role, type));
rim.addRoleMethod(m);
}).list();
//for each super interface, collect all RoleIntefaceMethods and link them to RoleIntefaceMethods of `type`
Expand All @@ -158,7 +158,7 @@ private Map<CtRole, RoleIntefaceMethods> collectMethodsOfType(Map<CtType, Map<Ct
Map<CtRole, RoleIntefaceMethods> superRimsByRole = collectMethodsOfType(loadedInterfaces, superIFace);
for (RoleIntefaceMethods superRim : superRimsByRole.values()) {
//get or create RoleIntefaceMethods in this type for the super type role
RoleIntefaceMethods rim = getOrCreatte(rimByRole, superRim.role, () -> new RoleIntefaceMethods(superRim.role, type));
RoleIntefaceMethods rim = getOrCreate(rimByRole, superRim.role, () -> new RoleIntefaceMethods(superRim.role, type));
//and add it
rim.superTypes.add(superRim);
rim.addSuperType(superRim);
Expand Down Expand Up @@ -226,7 +226,7 @@ private Map<CtRole, RoleIntefaceMethods> collectMethodsOfType(Map<CtType, Map<Ct
}
unhandledSignatures.forEach(key -> {
CtMethod<?> representant = rim.allRoleMethodsBySignature.get(key).get(0);
getOrCreatte(allUnhandledMethodSignatures, getDeclaringTypeSignature(representant), () -> representant);
getOrCreate(allUnhandledMethodSignatures, getDeclaringTypeSignature(representant), () -> representant);
});
}
return rimByRole;
Expand All @@ -253,10 +253,12 @@ private BiConsumer<String, List<CtMethod<?>>> createFieldHandler(Set<String> unh
}
unhandledSignatures.remove(k);
if (fieldGetter.get() == null) {
//we do not have method yet for this field
fieldSetter.accept(v.get(0));
} else {
//there is already a method for this field
if (valueType != null) {
//choose the method with more fitting valueType
//1) choose the method with more fitting valueType
boolean oldMatches = valueType.equals(fieldGetter.get().getParameters().get(valueParamIdx).getType());
boolean newMatches = valueType.equals(v.get(0).getParameters().get(valueParamIdx).getType());
if (oldMatches != newMatches) {
Expand All @@ -274,17 +276,56 @@ private BiConsumer<String, List<CtMethod<?>>> createFieldHandler(Set<String> unh
//do report problem. The conflict was resolved
return;
}
} else if (params.isEmpty()) {
//the value type is not known yet and there is no input parameter. We are resolving getter field.
//choose the getter whose return value is a collection of second one
CtTypeReference<?> oldReturnType = fieldGetter.get().getType();
CtTypeReference<?> newReturnType = v.get(0).getType();
boolean isOldIterable = oldReturnType.isSubtypeOf(iterableRef);
boolean isNewIterable = newReturnType.isSubtypeOf(iterableRef);
if (isOldIterable != isNewIterable) {
//they are not some. Only one of them is iterable
if (isOldIterable) {
if (isIterableOf(oldReturnType, newReturnType)) {
//use old method, which is multivalue represantation of new method
//OK - no conflict. Finish
return;
}
} else {
if (isIterableOf(newReturnType, oldReturnType)) {
//use new method, which is multivalue represantation of old method
fieldSetter.accept(v.get(0));
//OK - no conflict. Finish
return;
}
}
//else report ambiguity
}
}

problems.write(rim.iface.getSimpleName() + " has ambiguous " + fieldName + " :").writeln()
.incTab()
.write(getDeclaringTypeSignature(fieldGetter.get())).writeln()
.write(getDeclaringTypeSignature(v.get(0))).writeln()
.write(fieldGetter.get().getType() + "#" + getDeclaringTypeSignature(fieldGetter.get())).writeln()
.write(v.get(0).getType() + "#" + getDeclaringTypeSignature(v.get(0))).writeln()
.decTab();
}
}
};
}

/**
* @param iterableType
* @param itemType
* @return true if itemType can be iterated by iterableType
*/
private boolean isIterableOf(CtTypeReference<?> iterableType, CtTypeReference<?> itemType) {
if (iterableType.getActualTypeArguments().size() == 1) {
CtTypeReference<?> itemTypeOfIterable = iterableType.getActualTypeArguments().get(0);
return itemType.isSubtypeOf(itemTypeOfIterable);
}
return false;
}

/**
* Checks whether expectedType and realType are matching.
* @param expectedType
Expand All @@ -306,6 +347,14 @@ private CtTypeReference<?> typeMatches(CtTypeReference<?> expectedType, CtTypeRe
*/
return statementRef;
}
if (expectedType.isSubtypeOf(realType)) {
/*
* CtFieldReference<T> CtFieldAccess#getVariable()
* CtFieldAccess inherits from CtVariableAccess which has #setVariable(CtVariableReference<T>)
* it is OK to use expected type CtFieldReference<T>, when setter has CtVariableReference<T>
*/
return expectedType;
}
return null;
}

Expand All @@ -332,7 +381,7 @@ private String getHandlerName(CtType<?> type, CtRole role) {
return typeName + "_" + role.name() + "_RoleHandler";
}

private <K, V> V getOrCreatte(Map<K, V> map, K key, Supplier<V> valueCreator) {
private <K, V> V getOrCreate(Map<K, V> map, K key, Supplier<V> valueCreator) {
V value = map.get(key);
if (value == null) {
value = valueCreator.get();
Expand Down

0 comments on commit ee857cf

Please sign in to comment.