/*******************************************************************************
* Copyright (c) 2006-2014
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
package org.emftext.language.java.extensions.expressions;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.emftext.language.java.arrays.ArrayInstantiationBySize;
import org.emftext.language.java.arrays.ArrayTypeable;
import org.emftext.language.java.expressions.AdditiveExpression;
import org.emftext.language.java.expressions.AndExpression;
import org.emftext.language.java.expressions.AssignmentExpression;
import org.emftext.language.java.expressions.CastExpression;
import org.emftext.language.java.expressions.ConditionalAndExpression;
import org.emftext.language.java.expressions.ConditionalExpression;
import org.emftext.language.java.expressions.ConditionalOrExpression;
import org.emftext.language.java.expressions.EqualityExpression;
import org.emftext.language.java.expressions.ExclusiveOrExpression;
import org.emftext.language.java.expressions.Expression;
import org.emftext.language.java.expressions.InclusiveOrExpression;
import org.emftext.language.java.expressions.InstanceOfExpression;
import org.emftext.language.java.expressions.MultiplicativeExpression;
import org.emftext.language.java.expressions.NestedExpression;
import org.emftext.language.java.expressions.PrimaryExpression;
import org.emftext.language.java.expressions.RelationExpression;
import org.emftext.language.java.expressions.ShiftExpression;
import org.emftext.language.java.expressions.UnaryExpression;
import org.emftext.language.java.literals.Literal;
import org.emftext.language.java.members.AdditionalField;
import org.emftext.language.java.members.Field;
import org.emftext.language.java.members.Method;
import org.emftext.language.java.parameters.VariableLengthParameter;
import org.emftext.language.java.references.ElementReference;
import org.emftext.language.java.references.Reference;
import org.emftext.language.java.references.ReferenceableElement;
import org.emftext.language.java.types.Type;
import org.emftext.language.java.variables.AdditionalLocalVariable;
import org.emftext.language.java.variables.LocalVariable;
public class ExpressionExtension {
/**
* Returns the type of the expression considering all concrete subtypes of
* the Expression.
*
* @return type of expression
*/
public static Type getType(Expression me) {
return me.getOneType(false);
}
public static Type getAlternativeType(Expression me) {
return me.getOneType(true);
}
public static Type getOneType(Expression me, boolean alternative) {
org.emftext.language.java.classifiers.Class stringClass = me.getStringClass();
Type type = null;
if (me instanceof Reference) {
Reference reference = (Reference) me;
//navigate down references
while(reference.getNext() != null) {
reference = reference.getNext();
}
type = reference.getReferencedType();
}
else if (me instanceof Literal) {
type = ((Literal) me).getType();
}
else if (me instanceof CastExpression) {
type = ((CastExpression) me).getTypeReference().getTarget();
}
else if (me instanceof AssignmentExpression) {
type = ((AssignmentExpression) me).getChild().getOneType(alternative);
}
else if (me instanceof ConditionalExpression &&
((ConditionalExpression)me).getExpressionIf() != null) {
if (alternative) {
type = ((ConditionalExpression)me).getExpressionElse().getOneType(alternative);
}
else {
type = ((ConditionalExpression)me).getExpressionIf().getOneType(alternative);
}
}
else if (me instanceof EqualityExpression ||
me instanceof RelationExpression ||
me instanceof ConditionalOrExpression ||
me instanceof ConditionalAndExpression ||
me instanceof InstanceOfExpression) {
type = me.getLibClass("Boolean");
}
else if (me instanceof AdditiveExpression ||
me instanceof MultiplicativeExpression ||
me instanceof InclusiveOrExpression ||
me instanceof ExclusiveOrExpression ||
me instanceof AndExpression ||
me instanceof ShiftExpression) {
if (me instanceof AdditiveExpression) {
AdditiveExpression additiveExpression = (AdditiveExpression) me;
for(Expression subExp : additiveExpression.getChildren()) {
if (stringClass.equals(subExp.getOneType(alternative))) {
//special case: string concatenation
return stringClass;
}
}
}
@SuppressWarnings("unchecked")
Expression subExp = ((EList<Expression>)
me.eGet(me.eClass().getEStructuralFeature("children"))).get(0);
return subExp.getOneType(alternative);
}
else if (me instanceof UnaryExpression) {
Expression subExp = ((UnaryExpression) me).getChild();
return subExp.getOneType(alternative);
}
else for(TreeIterator<EObject> i = me.eAllContents(); i.hasNext(); ) {
EObject next = i.next();
Type nextType = null;
if (next instanceof PrimaryExpression) {
if (next instanceof Reference) {
Reference ref = (Reference) next;
//navigate down references
while(ref.getNext() != null) {
ref = ref.getNext();
}
next = ref;
}
if (next instanceof Literal) {
nextType = ((Literal) next).getType();
}
else if (next instanceof CastExpression) {
nextType = ((CastExpression)next).getTypeReference().getTarget();
}
else {
nextType = ((Reference) next).getReferencedType();
}
i.prune();
}
if (nextType != null) {
type = nextType;
//in the special case that this is an expression with
//some string included, everything is converted to string
if (stringClass.equals(type)) {
break;
}
}
}
//type can be null in cases of unresolved/unresolvable proxies
return type;
}
public static long getArrayDimension(Expression me) {
long size = 0;
ArrayTypeable arrayType = null;
if (me instanceof NestedExpression &&
((NestedExpression)me).getNext() == null) {
return ((NestedExpression) me).getExpression().getArrayDimension()
- ((NestedExpression) me).getArraySelectors().size();
}
if (me instanceof ConditionalExpression &&
((ConditionalExpression)me).getExpressionIf() != null) {
return ((ConditionalExpression)me).getExpressionIf().getArrayDimension();
}
if (me instanceof AssignmentExpression) {
Expression value = ((AssignmentExpression) me).getValue();
if (value == null) {
return 0;
}
return value.getArrayDimension();
}
if (me instanceof InstanceOfExpression) {
return 0;
}
if (me instanceof Reference) {
Reference reference = (Reference) me;
while (reference.getNext() != null) {
reference = reference.getNext();
}
//an array clone? -> dimension defined by cloned array
if (reference instanceof ElementReference &&
reference.getPrevious() != null) {
ReferenceableElement target = ((ElementReference)reference).getTarget();
if (target instanceof Method) {
if("clone".equals(((Method)target).getName())) {
reference = (Reference) reference.eContainer();
}
}
}
if (reference instanceof ElementReference) {
ElementReference elementReference = (ElementReference) reference;
if (elementReference.getTarget() instanceof ArrayTypeable) {
arrayType = (ArrayTypeable) elementReference.getTarget();
}
if (elementReference.getTarget() instanceof AdditionalLocalVariable) {
AdditionalLocalVariable additionalLocalVariable = (AdditionalLocalVariable) elementReference.getTarget();
arrayType = (LocalVariable) additionalLocalVariable.eContainer();
size += additionalLocalVariable.getArrayDimensionsAfter().size();
size -= arrayType.getArrayDimensionsAfter().size();
}
if (elementReference.getTarget() instanceof AdditionalField) {
AdditionalField additionalField = (AdditionalField) elementReference.getTarget();
arrayType = (Field) additionalField.eContainer();
size += additionalField.getArrayDimensionsAfter().size();
size -= arrayType.getArrayDimensionsAfter().size();
}
}
else if (me instanceof ArrayTypeable) {
size += ((ArrayTypeable) me).getArrayDimensionsBefore().size() + ((ArrayTypeable) me).getArrayDimensionsAfter().size();
if (me instanceof VariableLengthParameter) {
size++;
}
}
size -= reference.getArraySelectors().size();
}
else if (me instanceof ArrayTypeable) {
size += ((ArrayTypeable) me).getArrayDimensionsBefore().size() + ((ArrayTypeable) me).getArrayDimensionsAfter().size();
if (me instanceof VariableLengthParameter) {
size++;
}
}
if (me instanceof ArrayInstantiationBySize) {
size += ((ArrayInstantiationBySize) me).getSizes().size();
}
if(arrayType != null) {
size += arrayType.getArrayDimension();
}
return size;
}
}