Skip to content

Commit

Permalink
support of Type generation and bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
pvojtechovsky committed Nov 13, 2017
1 parent 443159d commit 140a388
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 24 deletions.
102 changes: 79 additions & 23 deletions src/main/java/spoon/pattern/PatternBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import spoon.reflect.factory.Factory;
import spoon.reflect.meta.RoleHandler;
import spoon.reflect.meta.impl.RoleHandlerHelper;
import spoon.reflect.path.CtRole;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.reference.CtVariableReference;
import spoon.reflect.visitor.CtScanner;
Expand Down Expand Up @@ -205,21 +207,41 @@ public PatternBuilder configureAutomaticParameters() {
if (pattern.getSubstitutionRequest(varRef) == null) {
//there is no substitution request registered for this variable reference yet. create one
ParameterInfo pi = pb.parameter(varRef.getSimpleName()).getCurrentParameter();
/*
* the target of substitution is always the parent node of variableReference
* - the expression - CtVariableAccess
* which can be replaced by any other CtVariableAccess.
* For example CtFieldRead can be replaced by CtVariableRead or by CtLiteral
*/
CtVariableAccess<?> varAccess = (CtVariableAccess<?>) varRef.getParent();
pattern.addSubstitutionRequest(pi, varAccess);
pattern.addSubstitutionRequest(pi, getSubstitutedNodeOfVariableReference(varRef));
}
}
});
});
return this;
}

/**
* @return a node, which has to be substituted instead of variable reference `varRef`
*/
private CtElement getSubstitutedNodeOfVariableReference(CtVariableReference<?> varRef) {
/*
* the target of substitution is always the parent node of variableReference
* - the expression - CtVariableAccess
* which can be replaced by any other CtVariableAccess.
* For example CtFieldRead can be replaced by CtVariableRead or by CtLiteral
*/
CtVariableAccess<?> varAccess = (CtVariableAccess<?>) varRef.getParent();
CtElement varAccessParent = varAccess.getParent();
if (varAccessParent instanceof CtInvocation<?>) {
CtInvocation<?> invocation = (CtInvocation<?>) varAccessParent;
CtExecutableReference<?> executableRef = invocation.getExecutable();
if (executableRef.getSimpleName().equals("S")) {
if (TemplateParameter.class.getName().equals(executableRef.getDeclaringType().getQualifiedName())) {
/*
* the invocation of TemplateParameter#S() has to be substituted
*/
return invocation;
}
}
}
return varAccess;
}

public static class TypeView {

private CtType<?> template;
Expand Down Expand Up @@ -334,12 +356,7 @@ public PatternBuilder configureTemplateParameters(CtType<?> templateType, Map<St
/*
* parameter with value type TypeReference or Class, identifies replacement of local type whose name is equal to parameter name
*/
CtTypeReference<?> nestedType = getLocalTypeRefBySimpleName(templateType, stringMarker);
if (nestedType == null) {
throw new SpoonException("Template parameter " + typeMember + " doesn't match to any local type");
}
//There is a local type with such name. Replace it
params.parameter(parameterName).byType(nestedType);
params.parameter(parameterName).byLocalType(templateType, stringMarker);
} else if (paramType.getQualifiedName().equals(String.class.getName())) {
// CtType<?> nestedType = getLocalTypeBySimpleName(templateType, stringMarker);
// if (nestedType != null) {
Expand Down Expand Up @@ -418,6 +435,11 @@ private CtTypeReference<?> getLocalTypeRefBySimpleName(CtType<?> templateType, S
public class ParametersBuilder {
ParameterInfo currentParameter;

/**
* Creates a parameter with name `paramName` and assigns it into context, so next calls on builder will be applied to this parameter
* @param paramName to be build parameter name
* @return this {@link ParametersBuilder} to support fluent API
*/
public ParametersBuilder parameter(String paramName) {
currentParameter = parameters.get(paramName);
if (currentParameter == null) {
Expand All @@ -427,6 +449,17 @@ public ParametersBuilder parameter(String paramName) {
return this;
}

/**
* @return true if parameter `paramName` already contains at least one substitution request
*/
public boolean isSubstituted(String paramName) {
ParameterInfo pi = parameters.get(paramName);
if (pi != null) {
return pi.getSubstitutionRequests().size() > 0;
}
return false;
}

protected ParameterInfo getCurrentParameter() {
if (currentParameter == null) {
throw new SpoonException("Parameter name must be defined first by call of #parameter(String) method.");
Expand Down Expand Up @@ -457,8 +490,38 @@ public ParametersBuilder byType(String typeQualifiedName) {
*/
public ParametersBuilder byType(CtTypeReference<?> type) {
ParameterInfo pi = getCurrentParameter();
//substitute all references to that type
pattern.getModel().filterChildren((CtTypeReference<?> typeRef) -> typeRef.equals(type))
.forEach((CtTypeReference<?> typeRef) -> pattern.addSubstitutionRequest(pi, typeRef));
.forEach((CtTypeReference<?> typeRef) -> {
pattern.addSubstitutionRequest(pi, typeRef);
});
/**
* If Type itself is found part of model, then substitute it's simple name too
*/
String typeQName = type.getQualifiedName();
CtType<?> type2 = pattern.getModel()
.filterChildren((CtType<?> t) -> t.getQualifiedName().equals(typeQName))
.first();
if (type2 != null) {
//Substitute name of template too
pattern.addSubstitutionRequest(pi, type2, CtRole.NAME);
}
return this;
}

/**
* Searches for a type visible in scope `templateType`, whose simple name is equal to `localTypeSimpleName`
* @param searchScope the Type which is searched for local Type
* @param localTypeSimpleName the simple name of to be returned Type
* @return {@link ParametersBuilder} to support fluent API
*/
public ParametersBuilder byLocalType(CtType<?> searchScope, String localTypeSimpleName) {
CtTypeReference<?> nestedType = getLocalTypeRefBySimpleName(searchScope, localTypeSimpleName);
if (nestedType == null) {
throw new SpoonException("Template parameter " + localTypeSimpleName + " doesn't match to any local type");
}
//There is a local type with such name. Replace it
byType(nestedType);
return this;
}

Expand All @@ -471,14 +534,7 @@ public ParametersBuilder byVariableReference(CtVariable<?> variable) {
ParameterInfo pi = getCurrentParameter();
pattern.getModel().map(new VariableReferenceFunction(variable))
.forEach((CtVariableReference<?> varRef) -> {
/*
* the target of substitution is always the parent node of variableReference
* - the expression - CtVariableAccess
* which can be replaced by any other CtVariableAccess.
* For example CtFieldRead can be replaced by CtVariableRead or by CtLiteral
*/
CtVariableAccess<?> varAccess = (CtVariableAccess<?>) varRef.getParent();
pattern.addSubstitutionRequest(pi, varAccess);
pattern.addSubstitutionRequest(pi, getSubstitutedNodeOfVariableReference(varRef));
});
return this;
}
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/spoon/template/Substitution.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,22 @@ public static <T extends CtType<?>> T createTypeFromTemplate(String qualifiedTyp
CtPackage targetPackage = f.Package().getOrCreate(typeRef.getPackage().getSimpleName());
final Map<String, Object> extendedParams = new HashMap<String, Object>(templateParameters);
extendedParams.put(templateOfType.getSimpleName(), typeRef);
List<CtType<?>> generated = PatternBuilder.createPattern(templateOfType).configureTemplateParameters(templateOfType, extendedParams).build().substitute(extendedParams);
List<CtType<?>> generated = PatternBuilder
.createPattern(templateOfType)
.configureTemplateParameters(templateOfType, extendedParams)
.configureParameters(pb -> {
templateParameters.forEach((paramName, paramValue) -> {
if (pb.isSubstituted(paramName) == false) {
if (paramValue instanceof CtTypeReference<?>) {
CtTypeReference<?> typeRefParamValue = (CtTypeReference<?>) paramValue;
pb.parameter(paramName).byLocalType(templateOfType, paramName);
}
pb.parameter(paramName).bySubstring(paramName);
}
});
})
.build()
.substitute(extendedParams);
for (CtType<?> ctType : generated) {
targetPackage.addType(ctType);
}
Expand Down

0 comments on commit 140a388

Please sign in to comment.