Skip to content

Commit

Permalink
feature ArrayItemValueResolver
Browse files Browse the repository at this point in the history
  • Loading branch information
pvojtechovsky committed Nov 21, 2017
1 parent 29cf54a commit f325ef0
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 2 deletions.
40 changes: 38 additions & 2 deletions src/main/java/spoon/pattern/AbstractValueResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtStatementList;
import spoon.reflect.meta.ContainerKind;

Expand All @@ -30,26 +32,44 @@
*/
abstract class AbstractValueResolver implements ValueResolver {

private List<ItemExtractor> itemExtractors;

protected AbstractValueResolver() {
}

protected <T> List<T> getValueAs(ConversionContext<T> context, ParameterInfo parameterInfo, ParameterValueProvider params) {
//get raw parameter value
Object rawValue = params.getValueOf(parameterInfo);
if (itemExtractors != null) {
for (ItemExtractor itemExtractor : itemExtractors) {
rawValue = itemExtractor.getItem(rawValue);
if (rawValue == ItemExtractor.NULL_VALUE) {
if (CtExpression.class.isAssignableFrom(context.getRequiredClass())) {
//the value is null and context needs a Expression
rawValue = context.getCloneHelper().getFactory().createLiteral(null);
} else {
break;
}
}
}
}

ValueConvertor valueConvertor = parameterInfo.getValueConvertor();
//convert raw parameter value to expected type
if (context.getRoleHandler().getContainerKind() == ContainerKind.SINGLE) {
if (rawValue != null) {
T convertedValue = (T) valueConvertor.getValueAs(rawValue, context);
if (convertedValue != null) {
return Collections.singletonList(convertedValue);
return Collections.singletonList(resolveNull(convertedValue));
}
}
return Collections.emptyList();
}
List<T> result = new ArrayList<>();
forEachItem(rawValue, singleValue -> {
if (singleValue != null) {
if (singleValue == ItemExtractor.NULL_VALUE) {
result.add(null);
} else if (singleValue != null) {
T convertedValue = (T) valueConvertor.getValueAs(singleValue, context);
if (convertedValue != null) {
result.add(convertedValue);
Expand All @@ -58,6 +78,14 @@ protected <T> List<T> getValueAs(ConversionContext<T> context, ParameterInfo par
});
return result;
}

private <T> T resolveNull(T value) {
return value == ItemExtractor.NULL_VALUE ? null : value;
}

@Override
public void forEachParameterInfo(BiConsumer<ParameterInfo, ValueResolver> consumer) {
}
/**
* calls consumer.accept(Object) once for each item of the `multipleValues` collection or array.
* If it is not a collection or array then it calls consumer.accept(Object) once with `multipleValues`
Expand Down Expand Up @@ -89,4 +117,12 @@ static void forEachItem(Object multipleValues, Consumer<Object> consumer) {
}
consumer.accept(multipleValues);
}

@Override
public void addExtraValueResolver(ItemExtractor itemExtractor) {
if (itemExtractors == null) {
itemExtractors = new ArrayList<>(1);
}
itemExtractors.add(itemExtractor);
}
}
54 changes: 54 additions & 0 deletions src/main/java/spoon/pattern/ArrayItemValueResolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.pattern;

import java.util.function.Consumer;

/**
* Delivers item of array
*/
public class ArrayItemValueResolver implements ItemExtractor {

final int requiredIndex;

ArrayItemValueResolver(int requiredIndex) {
super();
this.requiredIndex = requiredIndex;
}

@Override
public Object getItem(Object array) {
class Context implements Consumer<Object> {
int idx = 0;
Object foundValue = NULL_VALUE;

@Override
public void accept(Object value) {
if (idx == requiredIndex) {
foundValue = value;
}
idx++;
}
}
Context ctx = new Context();
AbstractValueResolver.forEachItem(array, ctx);
if (ctx.foundValue == NULL_VALUE) {
this.getClass();
}
return ctx.foundValue;
}
}
29 changes: 29 additions & 0 deletions src/main/java/spoon/pattern/ItemExtractor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.pattern;

/**
* Delivers to be substituted value
* Matches value
*/
public interface ItemExtractor {

Object NULL_VALUE = new Object();

<T> T getItem(Object array);
//TODO setItem for matchers
}
1 change: 1 addition & 0 deletions src/main/java/spoon/pattern/MultiValueResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public boolean matches(TemplateMatcher matcher, Object target, Object template)

@Override
public void forEachParameterInfo(BiConsumer<ParameterInfo, ValueResolver> consumer) {
super.forEachParameterInfo(consumer);
consumer.accept(iterableParameter, this);
consumer.accept(localParameter, this);
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/spoon/pattern/ParameterValueResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public boolean matches(TemplateMatcher matcher, Object target, Object template)

@Override
public void forEachParameterInfo(BiConsumer<ParameterInfo, ValueResolver> consumer) {
super.forEachParameterInfo(consumer);
consumer.accept(getParameterInfo(), this);
}

Expand Down
4 changes: 4 additions & 0 deletions src/main/java/spoon/pattern/Pattern.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ static class ModelCloner extends CloneHelper {
this.params = params;
}

public Factory getFactory() {
return pattern.getModel().getFactory();
}

/**
* Handle substitution of single value element.
* Zero or one element can be result of substitution of `element`
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/spoon/pattern/PatternBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.function.Predicate;

import spoon.SpoonException;
import spoon.reflect.code.CtArrayAccess;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtFieldRead;
Expand Down Expand Up @@ -940,12 +941,32 @@ private void addSubstitutionRequest(ParameterInfo parameter, CtElement element,

private CtElement getSubstitutedNodeOfElement(ValueResolver valueResolver, CtElement element) {
element = transformVariableAccessToVariableReference(element);
element = transformArrayAccess(valueResolver, element);
element = transformTemplateParameterInvocationOfS(element);
//if spoon creates an implicit parent (e.g. CtBlock) around the pattern parameter, then replace that implicit parent
element = getLastImplicitParent(element);
return element;
}

private CtElement transformArrayAccess(ValueResolver valueResolver, CtElement element) {
if (element.isParentInitialized()) {
CtElement parent = element.getParent();
if (parent instanceof CtArrayAccess<?, ?>) {
CtArrayAccess<?, ?> arrayAccess = (CtArrayAccess<?, ?>) parent;
CtExpression<?> expr = arrayAccess.getIndexExpression();
if (expr instanceof CtLiteral<?>) {
CtLiteral<?> idxLiteral = (CtLiteral<?>) expr;
Object idx = idxLiteral.getValue();
if (idx instanceof Number) {
valueResolver.addExtraValueResolver(new ArrayItemValueResolver(((Number) idx).intValue()));
element = arrayAccess;
}
}
}
}
return element;
}

/**
* @return a node, which has to be substituted instead of variable reference `varRef`
*/
Expand Down
1 change: 1 addition & 0 deletions src/main/java/spoon/pattern/StringValueResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public <T> List<T> resolveValues(ConversionContext<T> context, ParameterValuePro

@Override
public void forEachParameterInfo(BiConsumer<ParameterInfo, ValueResolver> consumer) {
super.forEachParameterInfo(consumer);
for (ParameterInfo parameterInfo : tobeReplacedSubstrings.keySet()) {
consumer.accept(parameterInfo, this);
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/spoon/pattern/SwitchValueResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ private boolean isCaseSelected(ConversionContext<?> context, Case case1, Paramet

@Override
public void forEachParameterInfo(BiConsumer<ParameterInfo, ValueResolver> consumer) {
super.forEachParameterInfo(consumer);
for (Case case1 : cases) {
if (case1.parameterOfExpression != null) {
consumer.accept(case1.parameterOfExpression, this);
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/spoon/pattern/ValueResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ public interface ValueResolver {
void forEachParameterInfo(BiConsumer<ParameterInfo, ValueResolver> consumer);

boolean matches(TemplateMatcher matcher, Object target, Object template);

void addExtraValueResolver(ItemExtractor itemExtractor);
}

0 comments on commit f325ef0

Please sign in to comment.