/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
* Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for
* bug "inline method - doesn't handle implicit cast" (see
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=24941).
* Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for
* bug Encapsulate field can fail when two variables in one variable declaration (see
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=51540).
*******************************************************************************/
package org.eclipse.che.ide.ext.java.jdt.internal.corext.dom;
import org.eclipse.che.ide.ext.java.jdt.core.compiler.IProblem;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTNode;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTVisitor;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ArrayType;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Assignment;
import org.eclipse.che.ide.ext.java.jdt.core.dom.BodyDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ChildListPropertyDescriptor;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.che.ide.ext.java.jdt.core.dom.CompilationUnit;
import org.eclipse.che.ide.ext.java.jdt.core.dom.DoStatement;
import org.eclipse.che.ide.ext.java.jdt.core.dom.EnhancedForStatement;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Expression;
import org.eclipse.che.ide.ext.java.jdt.core.dom.FieldAccess;
import org.eclipse.che.ide.ext.java.jdt.core.dom.FieldDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ForStatement;
import org.eclipse.che.ide.ext.java.jdt.core.dom.IBinding;
import org.eclipse.che.ide.ext.java.jdt.core.dom.IExtendedModifier;
import org.eclipse.che.ide.ext.java.jdt.core.dom.IMethodBinding;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ITypeBinding;
import org.eclipse.che.ide.ext.java.jdt.core.dom.IVariableBinding;
import org.eclipse.che.ide.ext.java.jdt.core.dom.IfStatement;
import org.eclipse.che.ide.ext.java.jdt.core.dom.InfixExpression;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Message;
import org.eclipse.che.ide.ext.java.jdt.core.dom.MethodDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.MethodInvocation;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Modifier;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Name;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ParameterizedType;
import org.eclipse.che.ide.ext.java.jdt.core.dom.ParenthesizedExpression;
import org.eclipse.che.ide.ext.java.jdt.core.dom.PrimitiveType;
import org.eclipse.che.ide.ext.java.jdt.core.dom.QualifiedName;
import org.eclipse.che.ide.ext.java.jdt.core.dom.QualifiedType;
import org.eclipse.che.ide.ext.java.jdt.core.dom.SimpleName;
import org.eclipse.che.ide.ext.java.jdt.core.dom.SimpleType;
import org.eclipse.che.ide.ext.java.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.StructuralPropertyDescriptor;
import org.eclipse.che.ide.ext.java.jdt.core.dom.Type;
import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclaration;
import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclarationExpression;
import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.che.ide.ext.java.jdt.core.dom.WhileStatement;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.codemanipulation.ASTResolving;
import org.eclipse.che.ide.ext.java.jdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.che.ide.ext.java.jdt.internal.ui.MembersOrderPreferenceCache;
import org.eclipse.che.ide.ext.java.worker.WorkerDocument;
import org.eclipse.che.ide.ext.java.jdt.text.Document;
import org.eclipse.che.ide.ext.java.jdt.text.edits.TextEdit;
import org.eclipse.che.ide.runtime.Assert;
import org.eclipse.che.ide.api.text.BadLocationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
//import org.eclipse.jdt.internal.ui.JavaPlugin;
//import org.eclipse.jdt.internal.ui.preferences.MembersOrderPreferenceCache;
//import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
public class ASTNodes {
public static final int NODE_ONLY = 0;
public static final int INCLUDE_FIRST_PARENT = 1;
public static final int INCLUDE_ALL_PARENTS = 2;
public static final int WARNING = 1 << 0;
public static final int ERROR = 1 << 1;
public static final int PROBLEMS = WARNING | ERROR;
private static final Message[] EMPTY_MESSAGES = new Message[0];
private static final IProblem[] EMPTY_PROBLEMS = new IProblem[0];
private static final int CLEAR_VISIBILITY = ~(Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE);
private ASTNodes() {
// no instance;
}
public static String asString(ASTNode node) {
ASTFlattener flattener = new ASTFlattener();
node.accept(flattener);
return flattener.getResult();
}
public static String asFormattedString(ASTNode node, int indent, String lineDelim, Map<String, String> options) {
String unformatted = asString(node);
TextEdit edit = CodeFormatterUtil.format2(node, unformatted, indent, lineDelim, options);
if (edit != null) {
Document document = new WorkerDocument(unformatted);
try {
edit.apply(document, TextEdit.NONE);
} catch (BadLocationException e) {
//TODO handle exception
e.printStackTrace();
// JavaPlugin.log(e);
}
return document.get();
}
return unformatted; // unknown node
}
// /**
// * Returns the source of the given node from the location where it was parsed.
// * @param node the node to get the source from
// * @param extendedRange if set, the extended ranges of the nodes should ne used
// * @param removeIndent if set, the indentation is removed.
// * @return return the source for the given node or null if accessing the source failed.
// */
// public static String getNodeSource(ASTNode node, boolean extendedRange, boolean removeIndent) {
// ASTNode root= node.getRoot();
// if (root instanceof CompilationUnit) {
// CompilationUnit astRoot= (CompilationUnit) root;
// ITypeRoot typeRoot= astRoot.getTypeRoot();
// try {
// if (typeRoot != null && typeRoot.getBuffer() != null) {
// IBuffer buffer= typeRoot.getBuffer();
// int offset= extendedRange ? astRoot.getExtendedStartPosition(node) : node.getStartPosition();
// int length= extendedRange ? astRoot.getExtendedLength(node) : node.getLength();
// String str= buffer.getText(offset, length);
// if (removeIndent) {
// IJavaProject project= typeRoot.getJavaProject();
// int indent= StubUtility.getIndentUsed(buffer, node.getStartPosition(), project);
// str= Strings.changeIndent(str, indent, project, new String(), typeRoot.findRecommendedLineSeparator());
// }
// return str;
// }
// } catch (JavaModelException e) {
// // ignore
// }
// }
// return null;
// }
/**
* Returns the list that contains the given ASTNode. If the node
* isn't part of any list, <code>null</code> is returned.
*
* @param node
* the node in question
* @return the list that contains the node or <code>null</code>
*/
public static List<? extends ASTNode> getContainingList(ASTNode node) {
StructuralPropertyDescriptor locationInParent = node.getLocationInParent();
if (locationInParent != null && locationInParent.isChildListProperty()) {
return (List<? extends ASTNode>)node.getParent().getStructuralProperty(locationInParent);
}
return null;
}
/**
* Returns a list of the direct children of a node. The siblings are ordered by start offset.
*
* @param node
* the node to get the children for
* @return the children
*/
public static List<ASTNode> getChildren(ASTNode node) {
ChildrenCollector visitor = new ChildrenCollector();
node.accept(visitor);
return visitor.result;
}
private static class ChildrenCollector extends GenericVisitor {
public List<ASTNode> result;
public ChildrenCollector() {
super(true);
result = null;
}
@Override
protected boolean visitNode(ASTNode node) {
if (result == null) { // first visitNode: on the node's parent: do nothing, return true
result = new ArrayList<ASTNode>();
return true;
}
result.add(node);
return false;
}
}
/**
* Returns true if this is an existing node, i.e. it was created as part of
* a parsing process of a source code file. Returns false if this is a newly
* created node which has not yet been given a source position.
*
* @param node
* the node to be tested.
* @return true if this is an existing node, false if not.
*/
public static boolean isExistingNode(ASTNode node) {
return node.getStartPosition() != -1;
}
/**
* Returns the element type. This is a convenience method that returns its
* argument if it is a simple type and the element type if the parameter is an array type.
*
* @param type
* The type to get the element type from.
* @return The element type of the type or the type itself.
*/
public static Type getElementType(Type type) {
if (!type.isArrayType())
return type;
return ((ArrayType)type).getElementType();
}
public static ASTNode findDeclaration(IBinding binding, ASTNode root) {
root = root.getRoot();
if (root instanceof CompilationUnit) {
return ((CompilationUnit)root).findDeclaringNode(binding);
}
return null;
}
public static VariableDeclaration findVariableDeclaration(IVariableBinding binding, ASTNode root) {
if (binding.isField())
return null;
ASTNode result = findDeclaration(binding, root);
if (result instanceof VariableDeclaration)
return (VariableDeclaration)result;
return null;
}
/**
* Returns the type node for the given declaration.
*
* @param declaration
* the declaration
* @return the type node
*/
public static Type getType(VariableDeclaration declaration) {
if (declaration instanceof SingleVariableDeclaration) {
return ((SingleVariableDeclaration)declaration).getType();
} else if (declaration instanceof VariableDeclarationFragment) {
ASTNode parent = ((VariableDeclarationFragment)declaration).getParent();
if (parent instanceof VariableDeclarationExpression)
return ((VariableDeclarationExpression)parent).getType();
else if (parent instanceof VariableDeclarationStatement)
return ((VariableDeclarationStatement)parent).getType();
else if (parent instanceof FieldDeclaration)
return ((FieldDeclaration)parent).getType();
}
Assert.isTrue(false, "Unknown VariableDeclaration"); //$NON-NLS-1$
return null;
}
public static int getDimensions(VariableDeclaration declaration) {
int dim = declaration.getExtraDimensions();
Type type = getType(declaration);
if (type instanceof ArrayType) {
dim += ((ArrayType)type).getDimensions();
}
return dim;
}
public static List<IExtendedModifier> getModifiers(VariableDeclaration declaration) {
Assert.isNotNull(declaration);
if (declaration instanceof SingleVariableDeclaration) {
return ((SingleVariableDeclaration)declaration).modifiers();
} else if (declaration instanceof VariableDeclarationFragment) {
ASTNode parent = declaration.getParent();
if (parent instanceof VariableDeclarationExpression)
return ((VariableDeclarationExpression)parent).modifiers();
else if (parent instanceof VariableDeclarationStatement)
return ((VariableDeclarationStatement)parent).modifiers();
}
return new ArrayList<IExtendedModifier>(0);
}
public static boolean isSingleDeclaration(VariableDeclaration declaration) {
Assert.isNotNull(declaration);
if (declaration instanceof SingleVariableDeclaration) {
return true;
} else if (declaration instanceof VariableDeclarationFragment) {
ASTNode parent = declaration.getParent();
if (parent instanceof VariableDeclarationExpression)
return ((VariableDeclarationExpression)parent).fragments().size() == 1;
else if (parent instanceof VariableDeclarationStatement)
return ((VariableDeclarationStatement)parent).fragments().size() == 1;
}
return false;
}
public static boolean isLiteral(Expression expression) {
int type = expression.getNodeType();
return type == ASTNode.BOOLEAN_LITERAL || type == ASTNode.CHARACTER_LITERAL || type == ASTNode.NULL_LITERAL
|| type == ASTNode.NUMBER_LITERAL || type == ASTNode.STRING_LITERAL || type == ASTNode.TYPE_LITERAL;
}
public static boolean isLabel(SimpleName name) {
int parentType = name.getParent().getNodeType();
return parentType == ASTNode.LABELED_STATEMENT || parentType == ASTNode.BREAK_STATEMENT
|| parentType != ASTNode.CONTINUE_STATEMENT;
}
public static boolean isStatic(BodyDeclaration declaration) {
return Modifier.isStatic(declaration.getModifiers());
}
public static List<BodyDeclaration> getBodyDeclarations(ASTNode node) {
if (node instanceof AbstractTypeDeclaration) {
return ((AbstractTypeDeclaration)node).bodyDeclarations();
} else if (node instanceof AnonymousClassDeclaration) {
return ((AnonymousClassDeclaration)node).bodyDeclarations();
}
// should not happen.
Assert.isTrue(false);
return null;
}
/**
* Returns the structural property descriptor for the "bodyDeclarations" property
* of this node (element type: {@link BodyDeclaration}).
*
* @param node
* the node, either an {@link AbstractTypeDeclaration} or an {@link AnonymousClassDeclaration}
* @return the property descriptor
*/
public static ChildListPropertyDescriptor getBodyDeclarationsProperty(ASTNode node) {
if (node instanceof AbstractTypeDeclaration) {
return ((AbstractTypeDeclaration)node).getBodyDeclarationsProperty();
} else if (node instanceof AnonymousClassDeclaration) {
return AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY;
}
// should not happen.
Assert.isTrue(false);
return null;
}
public static String getTypeName(Type type) {
final StringBuffer buffer = new StringBuffer();
ASTVisitor visitor = new ASTVisitor() {
@Override
public boolean visit(PrimitiveType node) {
buffer.append(node.getPrimitiveTypeCode().toString());
return false;
}
@Override
public boolean visit(SimpleName node) {
buffer.append(node.getIdentifier());
return false;
}
@Override
public boolean visit(QualifiedName node) {
buffer.append(node.getName().getIdentifier());
return false;
}
@Override
public void endVisit(ArrayType node) {
buffer.append("[]"); //$NON-NLS-1$
}
};
type.accept(visitor);
return buffer.toString();
}
public static InfixExpression.Operator convertToInfixOperator(Assignment.Operator operator) {
if (operator.equals(Assignment.Operator.PLUS_ASSIGN))
return InfixExpression.Operator.PLUS;
if (operator.equals(Assignment.Operator.MINUS_ASSIGN))
return InfixExpression.Operator.MINUS;
if (operator.equals(Assignment.Operator.TIMES_ASSIGN))
return InfixExpression.Operator.TIMES;
if (operator.equals(Assignment.Operator.DIVIDE_ASSIGN))
return InfixExpression.Operator.DIVIDE;
if (operator.equals(Assignment.Operator.BIT_AND_ASSIGN))
return InfixExpression.Operator.AND;
if (operator.equals(Assignment.Operator.BIT_OR_ASSIGN))
return InfixExpression.Operator.OR;
if (operator.equals(Assignment.Operator.BIT_XOR_ASSIGN))
return InfixExpression.Operator.XOR;
if (operator.equals(Assignment.Operator.REMAINDER_ASSIGN))
return InfixExpression.Operator.REMAINDER;
if (operator.equals(Assignment.Operator.LEFT_SHIFT_ASSIGN))
return InfixExpression.Operator.LEFT_SHIFT;
if (operator.equals(Assignment.Operator.RIGHT_SHIFT_SIGNED_ASSIGN))
return InfixExpression.Operator.RIGHT_SHIFT_SIGNED;
if (operator.equals(Assignment.Operator.RIGHT_SHIFT_UNSIGNED_ASSIGN))
return InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED;
Assert.isTrue(false, "Cannot convert assignment operator"); //$NON-NLS-1$
return null;
}
/**
* Returns true if a node at a given location is a body of a control statement. Such body nodes are
* interesting as when replacing them, it has to be evaluates if a Block is needed instead.
* E.g. <code> if (x) do(); -> if (x) { do1(); do2() } </code>
*
* @param locationInParent
* Location of the body node
* @return Returns true if the location is a body node location of a control statement.
*/
public static boolean isControlStatementBody(StructuralPropertyDescriptor locationInParent) {
return locationInParent == IfStatement.THEN_STATEMENT_PROPERTY
|| locationInParent == IfStatement.ELSE_STATEMENT_PROPERTY || locationInParent == ForStatement.BODY_PROPERTY
|| locationInParent == EnhancedForStatement.BODY_PROPERTY || locationInParent == WhileStatement.BODY_PROPERTY
|| locationInParent == DoStatement.BODY_PROPERTY;
}
/**
* Returns the type to which an inlined variable initializer should be cast, or
* <code>null</code> if no cast is necessary.
*
* @param initializer
* the initializer expression of the variable to inline
* @param reference
* the reference to the variable (which is to be inlined)
* @return a type binding to which the initializer should be cast, or <code>null</code> iff no cast is necessary
* @since 3.6
*/
public static ITypeBinding getExplicitCast(Expression initializer, Expression reference) {
ITypeBinding initializerType = initializer.resolveTypeBinding();
ITypeBinding referenceType = reference.resolveTypeBinding();
if (initializerType == null || referenceType == null)
return null;
if (initializerType.isPrimitive() && referenceType.isPrimitive() && !referenceType.isEqualTo(initializerType)) {
return referenceType;
} else if (initializerType.isPrimitive() && !referenceType.isPrimitive()) { // initializer is autoboxed
ITypeBinding unboxedReferenceType = Bindings.getUnboxedTypeBinding(referenceType, reference.getAST());
if (!unboxedReferenceType.isEqualTo(initializerType))
return unboxedReferenceType;
else if (needsExplicitBoxing(reference))
return referenceType;
} else if (!initializerType.isPrimitive() && referenceType.isPrimitive()) { // initializer is autounboxed
ITypeBinding unboxedInitializerType = Bindings.getUnboxedTypeBinding(initializerType, reference.getAST());
if (!unboxedInitializerType.isEqualTo(referenceType))
return referenceType;
} else if (initializerType.isRawType() && referenceType.isParameterizedType()) {
return referenceType; // don't lose the unchecked conversion
} else if (!TypeRules.canAssign(initializerType, referenceType)) {
if (!Bindings.containsTypeVariables(referenceType))
return referenceType;
}
return null;
}
/**
* Returns whether an expression at the given location needs explicit boxing.
*
* @param expression
* the expression
* @return <code>true</code> iff an expression at the given location needs explicit boxing
* @since 3.6
*/
private static boolean needsExplicitBoxing(Expression expression) {
StructuralPropertyDescriptor locationInParent = expression.getLocationInParent();
if (locationInParent == ParenthesizedExpression.EXPRESSION_PROPERTY)
return needsExplicitBoxing((ParenthesizedExpression)expression.getParent());
if (locationInParent == ClassInstanceCreation.EXPRESSION_PROPERTY
|| locationInParent == FieldAccess.EXPRESSION_PROPERTY
|| locationInParent == MethodInvocation.EXPRESSION_PROPERTY)
return true;
return false;
}
// /**
// * Returns the closest ancestor of <code>node</code> that is an instance of <code>parentClass</code>, or <code>null</code> if none.
// * <p>
// * <b>Warning:</b> This method does not stop at any boundaries like parentheses, statements, body declarations, etc.
// * The resulting node may be in a totally different scope than the given node.
// * Consider using one of the {@link ASTResolving}<code>.find(..)</code> methods instead.
// * </p>
// * @param node the node
// * @param parentClass the class of the sought ancestor node
// * @return the closest ancestor of <code>node</code> that is an instance of <code>parentClass</code>, or <code>null</code> if none
// */
// public static ASTNode getParent(ASTNode node, Class<? extends ASTNode> parentClass) {
// do {
// node= node.getParent();
// } while (node != null && !parentClass.isInstance(node));
// return node;
// }
/**
* Returns the closest ancestor of <code>node</code> whose type is <code>nodeType</code>, or <code>null</code> if none.
* <p>
* <b>Warning:</b> This method does not stop at any boundaries like parentheses, statements, body declarations, etc.
* The resulting node may be in a totally different scope than the given node.
* Consider using one of the {@link ASTResolving}<code>.find(..)</code> methods instead.
* </p>
*
* @param node
* the node
* @param nodeType
* the node type constant from {@link ASTNode}
* @return the closest ancestor of <code>node</code> whose type is <code>nodeType</code>, or <code>null</code> if none
*/
public static ASTNode getParent(ASTNode node, int nodeType) {
do {
node = node.getParent();
}
while (node != null && node.getNodeType() != nodeType);
return node;
}
public static ASTNode findParent(ASTNode node, StructuralPropertyDescriptor[][] pathes) {
for (int p = 0; p < pathes.length; p++) {
StructuralPropertyDescriptor[] path = pathes[p];
ASTNode current = node;
int d = path.length - 1;
for (; d >= 0 && current != null; d--) {
StructuralPropertyDescriptor descriptor = path[d];
if (!descriptor.equals(current.getLocationInParent()))
break;
current = current.getParent();
}
if (d < 0)
return current;
}
return null;
}
public static ASTNode getNormalizedNode(ASTNode node) {
ASTNode current = node;
// normalize name
if (QualifiedName.NAME_PROPERTY.equals(current.getLocationInParent())) {
current = current.getParent();
}
// normalize type
if (QualifiedType.NAME_PROPERTY.equals(current.getLocationInParent())
|| SimpleType.NAME_PROPERTY.equals(current.getLocationInParent())) {
current = current.getParent();
}
// normalize parameterized types
if (ParameterizedType.TYPE_PROPERTY.equals(current.getLocationInParent())) {
current = current.getParent();
}
return current;
}
/**
* Returns <code>true</code> iff <code>parent</code> is a true ancestor of <code>node</code>
* (i.e. returns <code>false</code> if <code>parent == node</code>).
*
* @param node
* node to test
* @param parent
* assumed parent
* @return <code>true</code> iff <code>parent</code> is a true ancestor of <code>node</code>
*/
public static boolean isParent(ASTNode node, ASTNode parent) {
Assert.isNotNull(parent);
do {
node = node.getParent();
if (node == parent)
return true;
}
while (node != null);
return false;
}
public static int getExclusiveEnd(ASTNode node) {
return node.getStartPosition() + node.getLength();
}
public static int getInclusiveEnd(ASTNode node) {
return node.getStartPosition() + node.getLength() - 1;
}
public static IMethodBinding getMethodBinding(Name node) {
IBinding binding = node.resolveBinding();
if (binding instanceof IMethodBinding)
return (IMethodBinding)binding;
return null;
}
public static IVariableBinding getVariableBinding(Name node) {
IBinding binding = node.resolveBinding();
if (binding instanceof IVariableBinding)
return (IVariableBinding)binding;
return null;
}
public static IVariableBinding getLocalVariableBinding(Name node) {
IVariableBinding result = getVariableBinding(node);
if (result == null || result.isField())
return null;
return result;
}
public static IVariableBinding getFieldBinding(Name node) {
IVariableBinding result = getVariableBinding(node);
if (result == null || !result.isField())
return null;
return result;
}
public static ITypeBinding getTypeBinding(Name node) {
IBinding binding = node.resolveBinding();
if (binding instanceof ITypeBinding)
return (ITypeBinding)binding;
return null;
}
// /**
// * Returns the receiver's type binding of the given method invocation.
// *
// * @param invocation method invocation to resolve type of
// * @return the type binding of the receiver
// */
// public static ITypeBinding getReceiverTypeBinding(MethodInvocation invocation) {
// ITypeBinding result= null;
// Expression exp= invocation.getExpression();
// if(exp != null) {
// return exp.resolveTypeBinding();
// }
// else {
// AbstractTypeDeclaration type= (AbstractTypeDeclaration)getParent(invocation, AbstractTypeDeclaration.class);
// if (type != null)
// return type.resolveBinding();
// }
// return result;
// }
public static ITypeBinding getEnclosingType(ASTNode node) {
while (node != null) {
if (node instanceof AbstractTypeDeclaration) {
return ((AbstractTypeDeclaration)node).resolveBinding();
} else if (node instanceof AnonymousClassDeclaration) {
return ((AnonymousClassDeclaration)node).resolveBinding();
}
node = node.getParent();
}
return null;
}
public static IProblem[] getProblems(ASTNode node, int scope, int severity) {
ASTNode root = node.getRoot();
if (!(root instanceof CompilationUnit))
return EMPTY_PROBLEMS;
IProblem[] problems = ((CompilationUnit)root).getProblems();
if (root == node)
return problems;
final int iterations = computeIterations(scope);
List<IProblem> result = new ArrayList<IProblem>(5);
for (int i = 0; i < problems.length; i++) {
IProblem problem = problems[i];
boolean consider = false;
if ((severity & PROBLEMS) == PROBLEMS)
consider = true;
else if ((severity & WARNING) != 0)
consider = problem.isWarning();
else if ((severity & ERROR) != 0)
consider = problem.isError();
if (consider) {
ASTNode temp = node;
int count = iterations;
do {
int nodeOffset = temp.getStartPosition();
int problemOffset = problem.getSourceStart();
if (nodeOffset <= problemOffset && problemOffset < nodeOffset + temp.getLength()) {
result.add(problem);
count = 0;
} else {
count--;
}
}
while ((temp = temp.getParent()) != null && count > 0);
}
}
return result.toArray(new IProblem[result.size()]);
}
public static Message[] getMessages(ASTNode node, int flags) {
ASTNode root = node.getRoot();
if (!(root instanceof CompilationUnit))
return EMPTY_MESSAGES;
Message[] messages = ((CompilationUnit)root).getMessages();
if (root == node)
return messages;
final int iterations = computeIterations(flags);
List<Message> result = new ArrayList<Message>(5);
for (int i = 0; i < messages.length; i++) {
Message message = messages[i];
ASTNode temp = node;
int count = iterations;
do {
int nodeOffset = temp.getStartPosition();
int messageOffset = message.getStartPosition();
if (nodeOffset <= messageOffset && messageOffset < nodeOffset + temp.getLength()) {
result.add(message);
count = 0;
} else {
count--;
}
}
while ((temp = temp.getParent()) != null && count > 0);
}
return result.toArray(new Message[result.size()]);
}
private static int computeIterations(int flags) {
switch (flags) {
case NODE_ONLY:
return 1;
case INCLUDE_ALL_PARENTS:
return Integer.MAX_VALUE;
case INCLUDE_FIRST_PARENT:
return 2;
default:
return 1;
}
}
private static int getOrderPreference(BodyDeclaration member, MembersOrderPreferenceCache store) {
int memberType = member.getNodeType();
int modifiers = member.getModifiers();
switch (memberType) {
case ASTNode.TYPE_DECLARATION:
case ASTNode.ENUM_DECLARATION:
case ASTNode.ANNOTATION_TYPE_DECLARATION:
return store.getCategoryIndex(MembersOrderPreferenceCache.TYPE_INDEX) * 2;
case ASTNode.FIELD_DECLARATION:
if (Modifier.isStatic(modifiers)) {
int index = store.getCategoryIndex(MembersOrderPreferenceCache.STATIC_FIELDS_INDEX) * 2;
if (Modifier.isFinal(modifiers)) {
return index; // first final static, then static
}
return index + 1;
}
return store.getCategoryIndex(MembersOrderPreferenceCache.FIELDS_INDEX) * 2;
case ASTNode.INITIALIZER:
if (Modifier.isStatic(modifiers)) {
return store.getCategoryIndex(MembersOrderPreferenceCache.STATIC_INIT_INDEX) * 2;
}
return store.getCategoryIndex(MembersOrderPreferenceCache.INIT_INDEX) * 2;
case ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION:
return store.getCategoryIndex(MembersOrderPreferenceCache.METHOD_INDEX) * 2;
case ASTNode.METHOD_DECLARATION:
if (Modifier.isStatic(modifiers)) {
return store.getCategoryIndex(MembersOrderPreferenceCache.STATIC_METHODS_INDEX) * 2;
}
if (((MethodDeclaration)member).isConstructor()) {
return store.getCategoryIndex(MembersOrderPreferenceCache.CONSTRUCTORS_INDEX) * 2;
}
return store.getCategoryIndex(MembersOrderPreferenceCache.METHOD_INDEX) * 2;
default:
return 100;
}
}
/**
* Computes the insertion index to be used to add the given member to the
* the list <code>container</code>.
*
* @param member
* the member to add
* @param container
* a list containing objects of type <code>BodyDeclaration</code>
* @return the insertion index to be used
*/
public static int getInsertionIndex(BodyDeclaration member, List<? extends BodyDeclaration> container) {
int containerSize = container.size();
MembersOrderPreferenceCache orderStore = MembersOrderPreferenceCache.get();
int orderIndex = getOrderPreference(member, orderStore);
int insertPos = containerSize;
int insertPosOrderIndex = -1;
for (int i = containerSize - 1; i >= 0; i--) {
int currOrderIndex = getOrderPreference(container.get(i), orderStore);
if (orderIndex == currOrderIndex) {
if (insertPosOrderIndex != orderIndex) { // no perfect match yet
insertPos = i + 1; // after a same kind
insertPosOrderIndex = orderIndex; // perfect match
}
} else if (insertPosOrderIndex != orderIndex) { // not yet a perfect match
if (currOrderIndex < orderIndex) { // we are bigger
if (insertPosOrderIndex == -1) {
insertPos = i + 1; // after
insertPosOrderIndex = currOrderIndex;
}
} else {
insertPos = i; // before
insertPosOrderIndex = currOrderIndex;
}
}
}
return insertPos;
}
public static SimpleName getLeftMostSimpleName(Name name) {
if (name instanceof SimpleName) {
return (SimpleName)name;
} else {
final SimpleName[] result = new SimpleName[1];
ASTVisitor visitor = new ASTVisitor() {
@Override
public boolean visit(QualifiedName qualifiedName) {
Name left = qualifiedName.getQualifier();
if (left instanceof SimpleName)
result[0] = (SimpleName)left;
else
left.accept(this);
return false;
}
};
name.accept(visitor);
return result[0];
}
}
public static SimpleType getLeftMostSimpleType(QualifiedType type) {
final SimpleType[] result = new SimpleType[1];
ASTVisitor visitor = new ASTVisitor() {
@Override
public boolean visit(QualifiedType qualifiedType) {
Type left = qualifiedType.getQualifier();
if (left instanceof SimpleType)
result[0] = (SimpleType)left;
else
left.accept(this);
return false;
}
};
type.accept(visitor);
return result[0];
}
public static Name getTopMostName(Name name) {
Name result = name;
while (result.getParent() instanceof Name) {
result = (Name)result.getParent();
}
return result;
}
public static Type getTopMostType(Type type) {
Type result = type;
while (result.getParent() instanceof Type) {
result = (Type)result.getParent();
}
return result;
}
public static int changeVisibility(int modifiers, int visibility) {
return (modifiers & CLEAR_VISIBILITY) | visibility;
}
/**
* Adds flags to the given node and all its descendants.
*
* @param root
* The root node
* @param flags
* The flags to set
*/
public static void setFlagsToAST(ASTNode root, final int flags) {
root.accept(new GenericVisitor(true) {
@Override
protected boolean visitNode(ASTNode node) {
node.setFlags(node.getFlags() | flags);
return true;
}
});
}
public static String getQualifier(Name name) {
if (name.isQualifiedName()) {
return ((QualifiedName)name).getQualifier().getFullyQualifiedName();
}
return ""; //$NON-NLS-1$
}
public static String getSimpleNameIdentifier(Name name) {
if (name.isQualifiedName()) {
return ((QualifiedName)name).getName().getIdentifier();
} else {
return ((SimpleName)name).getIdentifier();
}
}
public static boolean isDeclaration(Name name) {
if (name.isQualifiedName()) {
return ((QualifiedName)name).getName().isDeclaration();
} else {
return ((SimpleName)name).isDeclaration();
}
}
public static Modifier findModifierNode(int flag, List<IExtendedModifier> modifiers) {
for (int i = 0; i < modifiers.size(); i++) {
Object curr = modifiers.get(i);
if (curr instanceof Modifier && ((Modifier)curr).getKeyword().toFlagValue() == flag) {
return (Modifier)curr;
}
}
return null;
}
// public static ITypeBinding getTypeBinding(CompilationUnit root, IType type) throws JavaModelException {
// if (type.isAnonymous()) {
// final IJavaElement parent= type.getParent();
// if (parent instanceof IField && Flags.isEnum(((IMember) parent).getFlags())) {
// final EnumConstantDeclaration constant= (EnumConstantDeclaration) NodeFinder.perform(root,
// ((ISourceReference) parent).getSourceRange());
// if (constant != null) {
// final AnonymousClassDeclaration declaration= constant.getAnonymousClassDeclaration();
// if (declaration != null)
// return declaration.resolveBinding();
// }
// } else {
// final ClassInstanceCreation creation= (ClassInstanceCreation) getParent(NodeFinder.perform(root, type.getNameRange()), ClassInstanceCreation.class);
// if (creation != null)
// return creation.resolveTypeBinding();
// }
// } else {
// final AbstractTypeDeclaration declaration= (AbstractTypeDeclaration) getParent(NodeFinder.perform(root, type.getNameRange()), AbstractTypeDeclaration.class);
// if (declaration != null)
// return declaration.resolveBinding();
// }
// return null;
// }
}