/******************************************************************************* * 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; // } }