Skip to content

Commit

Permalink
Deal with no common type for variables being available.
Browse files Browse the repository at this point in the history
  • Loading branch information
matozoid committed Jan 24, 2018
1 parent 475d14a commit 9a22891
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 54 deletions.
Expand Up @@ -118,7 +118,7 @@ public void propertyChange(Node observedNode, ObservableProperty property, Objec
if (vd.getParentNode().isPresent() && vd.getParentNode().get() instanceof NodeWithVariables) { if (vd.getParentNode().isPresent() && vd.getParentNode().get() instanceof NodeWithVariables) {
NodeWithVariables nodeWithVariables = (NodeWithVariables) vd.getParentNode().get(); NodeWithVariables nodeWithVariables = (NodeWithVariables) vd.getParentNode().get();
// We calculate the value the property will assume after the change will be completed // We calculate the value the property will assume after the change will be completed
Type currentMaxCommonType = nodeWithVariables.getMaximumCommonType(); Optional<Type> currentMaxCommonType = nodeWithVariables.getMaximumCommonType();
List<Type> types = new LinkedList<>(); List<Type> types = new LinkedList<>();
int index = nodeWithVariables.getVariables().indexOf(vd); int index = nodeWithVariables.getVariables().indexOf(vd);
for (int i = 0; i < nodeWithVariables.getVariables().size(); i++) { for (int i = 0; i < nodeWithVariables.getVariables().size(); i++) {
Expand All @@ -128,8 +128,8 @@ public void propertyChange(Node observedNode, ObservableProperty property, Objec
types.add(nodeWithVariables.getVariable(i).getType()); types.add(nodeWithVariables.getVariable(i).getType());
} }
} }
Type newMaxCommonType = NodeWithVariables.calculateMaximumCommonType(types); Optional<Type> newMaxCommonType = NodeWithVariables.calculateMaximumCommonType(types);
((Node) nodeWithVariables).notifyPropertyChange(ObservableProperty.MAXIMUM_COMMON_TYPE, currentMaxCommonType, newMaxCommonType); ((Node) nodeWithVariables).notifyPropertyChange(ObservableProperty.MAXIMUM_COMMON_TYPE, currentMaxCommonType.orElse(null), newMaxCommonType.orElse(null));
} }
} }
} }
Expand Down
Expand Up @@ -29,6 +29,7 @@
import com.github.javaparser.metamodel.DerivedProperty; import com.github.javaparser.metamodel.DerivedProperty;


import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;


/** /**
Expand Down Expand Up @@ -109,28 +110,28 @@ default Type getElementType() {
* <br/>For <code>int[] a[][],b[],c[][];</code> this is int[][]. * <br/>For <code>int[] a[][],b[],c[][];</code> this is int[][].
*/ */
@DerivedProperty @DerivedProperty
default Type getMaximumCommonType() { default Optional<Type> getMaximumCommonType() {
return calculateMaximumCommonType(this.getVariables().stream().map(v -> v.getType()).collect(Collectors.toList())); return calculateMaximumCommonType(getVariables().stream().map(v -> v.getType()).collect(Collectors.toList()));
} }


static Type calculateMaximumCommonType(List<Type> types) { static Optional<Type> calculateMaximumCommonType(List<Type> types) {
// we use a local class because we cannot use an helper static method in an interface // we use a local class because we cannot use an helper static method in an interface
class Helper { class Helper {
// Conceptually: given a type we start from the Element Type and get as many array levels as indicated // Conceptually: given a type we start from the Element Type and get as many array levels as indicated
// From the implementation point of view we start from the actual type and we remove how many array // From the implementation point of view we start from the actual type and we remove how many array
// levels as needed to get the target level of arrays // levels as needed to get the target level of arrays
// It returns null if the type has less array levels then the desired target // It returns null if the type has less array levels then the desired target
private Type toArrayLevel(Type type, int level) { private Optional<Type> toArrayLevel(Type type, int level) {
if (level > type.getArrayLevel()) { if (level > type.getArrayLevel()) {
return null; return Optional.empty();
} }
for (int i = type.getArrayLevel(); i > level; i--) { for (int i = type.getArrayLevel(); i > level; i--) {
if (!(type instanceof ArrayType)) { if (!(type instanceof ArrayType)) {
throw new AssertionError("The variables do not have a common type."); return Optional.empty();
} }
type = ((ArrayType) type).getComponentType(); type = ((ArrayType) type).getComponentType();
} }
return type; return Optional.of(type);
} }
} }


Expand All @@ -145,8 +146,8 @@ private Type toArrayLevel(Type type, int level) {
// the pretty-printed string got for a node. We just check all them are the same and if they // the pretty-printed string got for a node. We just check all them are the same and if they
// are we just just is not null // are we just just is not null
Object[] values = types.stream().map(v -> { Object[] values = types.stream().map(v -> {
Type t = helper.toArrayLevel(v, currentLevel); Optional<Type> t = helper.toArrayLevel(v, currentLevel);
return t == null ? null : t.toString(); return t.map(Node::toString).orElse(null);
}).distinct().toArray(); }).distinct().toArray();
if (values.length == 1 && values[0] != null) { if (values.length == 1 && values[0] != null) {
level++; level++;
Expand Down
Expand Up @@ -482,7 +482,7 @@ public void visit(final FieldDeclaration n, final Void arg) {
printMemberAnnotations(n.getAnnotations(), arg); printMemberAnnotations(n.getAnnotations(), arg);
printModifiers(n.getModifiers()); printModifiers(n.getModifiers());
if (!n.getVariables().isEmpty()) { if (!n.getVariables().isEmpty()) {
n.getMaximumCommonType().accept(this, arg); n.getMaximumCommonType().ifPresent(t -> t.accept(this, arg));
} }


printer.print(" "); printer.print(" ");
Expand All @@ -502,25 +502,25 @@ public void visit(final VariableDeclarator n, final Void arg) {
printComment(n.getComment(), arg); printComment(n.getComment(), arg);
n.getName().accept(this, arg); n.getName().accept(this, arg);


Optional<NodeWithVariables> ancestor = n.getAncestorOfType(NodeWithVariables.class); n.getAncestorOfType(NodeWithVariables.class).ifPresent(ancestor -> {
if (!ancestor.isPresent()) { Optional<Type> maximumCommonType = ancestor.getMaximumCommonType();
throw new RuntimeException("Unable to work with VariableDeclarator not owned by a NodeWithVariables"); maximumCommonType.ifPresent(commonType -> {
}
Type commonType = ancestor.get().getMaximumCommonType();


Type type = n.getType(); Type type = n.getType();


ArrayType arrayType = null; ArrayType arrayType = null;


for (int i = commonType.getArrayLevel(); i < type.getArrayLevel(); i++) { for (int i = commonType.getArrayLevel(); i < type.getArrayLevel(); i++) {
if (arrayType == null) { if (arrayType == null) {
arrayType = (ArrayType) type; arrayType = (ArrayType) type;
} else { } else {
arrayType = (ArrayType) arrayType.getComponentType(); arrayType = (ArrayType) arrayType.getComponentType();
} }
printAnnotations(arrayType.getAnnotations(), true, arg); printAnnotations(arrayType.getAnnotations(), true, arg);
printer.print("[]"); printer.print("[]");
} }
});
});


if (n.getInitializer().isPresent()) { if (n.getInitializer().isPresent()) {
printer.print(" = "); printer.print(" = ");
Expand Down Expand Up @@ -913,7 +913,7 @@ public void visit(final VariableDeclarationExpr n, final Void arg) {
printModifiers(n.getModifiers()); printModifiers(n.getModifiers());


if (!n.getVariables().isEmpty()) { if (!n.getVariables().isEmpty()) {
n.getMaximumCommonType().accept(this, arg); n.getMaximumCommonType().ifPresent(t -> t.accept(this, arg));
} }
printer.print(" "); printer.print(" ");


Expand Down
Expand Up @@ -57,7 +57,7 @@


/** /**
* A Lexical Preserving Printer is used to capture all the lexical information while parsing, update them when * A Lexical Preserving Printer is used to capture all the lexical information while parsing, update them when
* operating on the AST and then used them to reproduce the source code * operating on the AST and then used them to reproduce the source code
* in its original formatting including the AST changes. * in its original formatting including the AST changes.
*/ */
public class LexicalPreservingPrinter { public class LexicalPreservingPrinter {
Expand Down Expand Up @@ -110,7 +110,7 @@ public static <N extends Node> N setup(N node) {
}); });
return node; return node;
} }

// //
// Constructor and setup // Constructor and setup
// //
Expand Down Expand Up @@ -401,16 +401,17 @@ private static NodeText interpret(Node node, CsmElement csm, NodeText nodeText)
// Array brackets are a pain... we do not have a way to represent them explicitly in the AST // Array brackets are a pain... we do not have a way to represent them explicitly in the AST
// so they have to be handled in a special way // so they have to be handled in a special way
if (node instanceof VariableDeclarator) { if (node instanceof VariableDeclarator) {
VariableDeclarator variableDeclarator = (VariableDeclarator)node; VariableDeclarator variableDeclarator = (VariableDeclarator) node;
if (!variableDeclarator.getParentNode().isPresent()) { variableDeclarator.getParentNode().ifPresent(parent -> {
throw new RuntimeException("VariableDeclarator without parent: I cannot handle the array levels"); NodeWithVariables<?> nodeWithVariables = (NodeWithVariables) parent;
} nodeWithVariables.getMaximumCommonType().ifPresent(mct -> {
NodeWithVariables<?> nodeWithVariables = (NodeWithVariables)variableDeclarator.getParentNode().get(); int extraArrayLevels = variableDeclarator.getType().getArrayLevel() - mct.getArrayLevel();
int extraArrayLevels = variableDeclarator.getType().getArrayLevel() - nodeWithVariables.getMaximumCommonType().getArrayLevel(); for (int i = 0; i < extraArrayLevels; i++) {
for (int i=0; i<extraArrayLevels; i++) { nodeText.addElement(new TokenTextElement(LBRACKET));
nodeText.addElement(new TokenTextElement(LBRACKET)); nodeText.addElement(new TokenTextElement(RBRACKET));
nodeText.addElement(new TokenTextElement(RBRACKET)); }
} });
});
} }
return nodeText; return nodeText;
} }
Expand Down
Expand Up @@ -53,7 +53,7 @@ public FieldAccessContext(FieldAccessExpr wrappedNode, TypeSolver typeSolver) {


@Override @Override
public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) { public SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, TypeSolver typeSolver) {
if (wrappedNode.getField().toString().equals(name)) { if (wrappedNode.getName().toString().equals(name)) {
if (wrappedNode.getScope() instanceof ThisExpr) { if (wrappedNode.getScope() instanceof ThisExpr) {
ResolvedType typeOfThis = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode); ResolvedType typeOfThis = JavaParserFacade.get(typeSolver).getTypeOfThisIn(wrappedNode);
return new SymbolSolver(typeSolver).solveSymbolInType(typeOfThis.asReferenceType().getTypeDeclaration(), name); return new SymbolSolver(typeSolver).solveSymbolInType(typeOfThis.asReferenceType().getTypeDeclaration(), name);
Expand All @@ -75,18 +75,14 @@ public SymbolReference<ResolvedMethodDeclaration> solveMethod(String name, List<
@Override @Override
public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) { public Optional<Value> solveSymbolAsValue(String name, TypeSolver typeSolver) {
Expression scope = wrappedNode.getScope(); Expression scope = wrappedNode.getScope();
if (wrappedNode.getField().toString().equals(name)) { if (wrappedNode.getName().toString().equals(name)) {
ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getType(scope); ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getType(scope);
if (typeOfScope.isArray() && name.equals(ARRAY_LENGTH_FIELD_NAME)) { if (typeOfScope.isArray() && name.equals(ARRAY_LENGTH_FIELD_NAME)) {
return Optional.of(new Value(ResolvedPrimitiveType.INT, ARRAY_LENGTH_FIELD_NAME)); return Optional.of(new Value(ResolvedPrimitiveType.INT, ARRAY_LENGTH_FIELD_NAME));
} }
if (typeOfScope.isReferenceType()) { if (typeOfScope.isReferenceType()) {
Optional<ResolvedType> typeUsage = typeOfScope.asReferenceType().getFieldType(name); Optional<ResolvedType> typeUsage = typeOfScope.asReferenceType().getFieldType(name);
if (typeUsage.isPresent()) { return typeUsage.map(resolvedType -> new Value(resolvedType, name));
return Optional.of(new Value(typeUsage.get(), name));
} else {
return Optional.empty();
}
} else { } else {
return Optional.empty(); return Optional.empty();
} }
Expand Down
Expand Up @@ -42,22 +42,22 @@ public class PrettyPrintVisitorTest {
@Test @Test
public void getMaximumCommonTypeWithoutAnnotations() { public void getMaximumCommonTypeWithoutAnnotations() {
VariableDeclarationExpr vde1 = JavaParser.parseVariableDeclarationExpr("int a[], b[]"); VariableDeclarationExpr vde1 = JavaParser.parseVariableDeclarationExpr("int a[], b[]");
assertEquals("int[]", vde1.getMaximumCommonType().toString()); assertEquals("int[]", vde1.getMaximumCommonType().get().toString());


VariableDeclarationExpr vde2 = JavaParser.parseVariableDeclarationExpr("int[][] a[], b[]"); VariableDeclarationExpr vde2 = JavaParser.parseVariableDeclarationExpr("int[][] a[], b[]");
assertEquals("int[][][]", vde2.getMaximumCommonType().toString()); assertEquals("int[][][]", vde2.getMaximumCommonType().get().toString());


VariableDeclarationExpr vde3 = JavaParser.parseVariableDeclarationExpr("int[][] a, b[]"); VariableDeclarationExpr vde3 = JavaParser.parseVariableDeclarationExpr("int[][] a, b[]");
assertEquals("int[][]", vde3.getMaximumCommonType().toString()); assertEquals("int[][]", vde3.getMaximumCommonType().get().toString());
} }


@Test @Test
public void getMaximumCommonTypeWithAnnotations() { public void getMaximumCommonTypeWithAnnotations() {
VariableDeclarationExpr vde1 = JavaParser.parseVariableDeclarationExpr("int a @Foo [], b[]"); VariableDeclarationExpr vde1 = JavaParser.parseVariableDeclarationExpr("int a @Foo [], b[]");
assertEquals("int", vde1.getMaximumCommonType().toString()); assertEquals("int", vde1.getMaximumCommonType().get().toString());


VariableDeclarationExpr vde2 = JavaParser.parseVariableDeclarationExpr("int[]@Foo [] a[], b[]"); VariableDeclarationExpr vde2 = JavaParser.parseVariableDeclarationExpr("int[]@Foo [] a[], b[]");
assertEquals("int[] @Foo [][]", vde2.getMaximumCommonType().toString()); assertEquals("int[] @Foo [][]", vde2.getMaximumCommonType().get().toString());
} }


private String print(Node node) { private String print(Node node) {
Expand Down

0 comments on commit 9a22891

Please sign in to comment.