| /******************************************************************************* |
| * Copyright (c) 2005, 2016 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 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.ruby.internal.parsers.jruby; |
| |
| import java.util.Stack; |
| |
| import org.eclipse.dltk.ast.ASTNode; |
| import org.eclipse.dltk.ast.ASTVisitor; |
| import org.eclipse.dltk.ast.Modifiers; |
| import org.eclipse.dltk.ast.declarations.MethodDeclaration; |
| import org.eclipse.dltk.ast.declarations.ModuleDeclaration; |
| import org.eclipse.dltk.ast.declarations.TypeDeclaration; |
| import org.eclipse.dltk.ast.expressions.CallExpression; |
| import org.eclipse.dltk.ast.parser.ISourceParser; |
| import org.eclipse.dltk.ast.statements.Block; |
| import org.eclipse.dltk.compiler.env.ModuleSource; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.DLTKLanguageManager; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.SourceParserUtil; |
| import org.eclipse.dltk.ruby.ast.RubyBlock; |
| import org.eclipse.dltk.ruby.ast.RubyForStatement2; |
| import org.eclipse.dltk.ruby.ast.RubyIfStatement; |
| import org.eclipse.dltk.ruby.ast.RubyUnlessStatement; |
| import org.eclipse.dltk.ruby.ast.RubyUntilStatement; |
| import org.eclipse.dltk.ruby.ast.RubyWhileStatement; |
| import org.eclipse.dltk.ruby.core.RubyNature; |
| |
| public class ASTUtils { |
| |
| private ASTUtils() { |
| throw new AssertionError("Cannot instantiate utility class"); //$NON-NLS-1$ |
| } |
| |
| public static void setVisibility(MethodDeclaration methodDeclaration, |
| int newVisibility) { |
| int modifiers = methodDeclaration.getModifiers(); |
| modifiers = modifiers |
| & ~(Modifiers.AccPublic | Modifiers.AccProtected |
| | Modifiers.AccPrivate | Modifiers.AccDefault); |
| methodDeclaration.setModifiers(modifiers | newVisibility); |
| } |
| |
| public static ASTNode[] restoreWayToNode(ModuleDeclaration module, |
| final ASTNode nde) { |
| final Stack<ASTNode> stack = new Stack<ASTNode>(); |
| |
| ASTVisitor visitor = new ASTVisitor() { |
| boolean found = false; |
| |
| @Override |
| public boolean visitGeneral(ASTNode node) throws Exception { |
| if (!found) { |
| stack.push(node); |
| if (node.locationMatches(nde)) { |
| found = true; |
| } |
| } |
| return super.visitGeneral(node); |
| } |
| |
| @Override |
| public void endvisitGeneral(ASTNode node) throws Exception { |
| super.endvisitGeneral(node); |
| if (!found) { |
| stack.pop(); |
| } |
| } |
| }; |
| |
| try { |
| module.traverse(visitor); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| return stack.toArray(new ASTNode[stack.size()]); |
| } |
| |
| public static <E extends ASTNode> E getEnclosingElement(Class<E> element, |
| ASTNode[] wayToNode, ASTNode node, boolean considerGiven) { |
| int pos = -1; |
| for (int i = wayToNode.length; --i >= 0;) { |
| if (wayToNode[i] == node) { |
| pos = i; |
| break; |
| } |
| } |
| if (pos != -1) { |
| if (!considerGiven) |
| pos--; |
| for (int i = pos; i >= 0; i--) { |
| if (element.isInstance(wayToNode[i])) { |
| @SuppressWarnings("unchecked") |
| final E result = (E) wayToNode[i]; |
| return result; |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| public static TypeDeclaration getEnclosingType(ASTNode[] wayToNode, |
| ASTNode node, boolean considerGiven) { |
| return getEnclosingElement(TypeDeclaration.class, wayToNode, node, |
| considerGiven); |
| } |
| |
| public static CallExpression getEnclosingCallNode(ASTNode[] wayToNode, |
| ASTNode node, boolean considerGiven) { |
| return getEnclosingElement(CallExpression.class, wayToNode, node, |
| considerGiven); |
| } |
| |
| public static MethodDeclaration getEnclosingMethod(ASTNode[] wayToNode, |
| ASTNode node, boolean considerGiven) { |
| return getEnclosingElement(MethodDeclaration.class, wayToNode, node, |
| considerGiven); |
| } |
| |
| /** |
| * Finds minimal ast node, that covers given position |
| * |
| * @param unit |
| * @param position |
| * @return |
| */ |
| public static ASTNode findMinimalNode(ModuleDeclaration unit, int start, |
| int end) { |
| |
| class Visitor extends ASTVisitor { |
| ASTNode result = null; |
| final int start, end; |
| |
| public Visitor(int start, int end) { |
| this.start = start; |
| this.end = end; |
| } |
| |
| public ASTNode getResult() { |
| return result; |
| } |
| |
| private int calcLen(ASTNode s) { |
| int realStart = s.sourceStart(); |
| int realEnd = s.sourceEnd(); |
| if (s instanceof TypeDeclaration) { |
| TypeDeclaration declaration = (TypeDeclaration) s; |
| realStart = declaration.getNameStart(); |
| realEnd = declaration.getNameEnd(); |
| } else if (s instanceof MethodDeclaration) { |
| MethodDeclaration declaration = (MethodDeclaration) s; |
| realStart = declaration.getNameStart(); |
| realEnd = declaration.getNameEnd(); |
| } |
| return realEnd - realStart; |
| } |
| |
| @Override |
| public boolean visitGeneral(ASTNode s) throws Exception { |
| int realStart = s.sourceStart(); |
| int realEnd = s.sourceEnd(); |
| if (s instanceof Block) { |
| realStart = realEnd = -42; // never select on blocks |
| // ssanders: BEGIN - Modify narrowing logic |
| } else if (s instanceof TypeDeclaration) { |
| TypeDeclaration declaration = (TypeDeclaration) s; |
| realStart = declaration.sourceStart(); |
| realEnd = declaration.sourceEnd(); |
| } else if (s instanceof MethodDeclaration) { |
| MethodDeclaration declaration = (MethodDeclaration) s; |
| realStart = declaration.sourceStart(); |
| realEnd = declaration.sourceEnd(); |
| } |
| if (realStart <= start && realEnd >= end) { |
| if (result != null) { |
| if ((s.sourceStart() >= result.sourceStart()) |
| && (s.sourceEnd() <= result.sourceEnd())) |
| result = s; |
| } else { |
| result = s; |
| } |
| // ssanders: END |
| if (DLTKCore.DEBUG_SELECTION) |
| System.out.println("Found " + s.getClass().getName()); //$NON-NLS-1$ |
| } |
| return true; |
| } |
| |
| } |
| |
| Visitor visitor = new Visitor(start, end); |
| |
| try { |
| unit.traverse(visitor); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| |
| return visitor.getResult(); |
| } |
| |
| /** |
| * Finds minimal ast node, that covers given position |
| * |
| * @param unit |
| * @param position |
| * @return |
| */ |
| public static ASTNode findMaximalNodeEndingAt(ModuleDeclaration unit, |
| final int boundaryOffset) { |
| |
| class Visitor extends ASTVisitor { |
| ASTNode result = null; |
| |
| public ASTNode getResult() { |
| return result; |
| } |
| |
| @Override |
| public boolean visitGeneral(ASTNode s) throws Exception { |
| if (s.sourceStart() < 0 || s.sourceEnd() < 0) |
| return true; |
| int sourceEnd = s.sourceEnd(); |
| if (Math.abs(sourceEnd - boundaryOffset) <= 0) { // XXX: was |
| // ... <= 1 |
| result = s; |
| if (DLTKCore.DEBUG_SELECTION) |
| System.out.println("Found " + s.getClass().getName()); //$NON-NLS-1$ |
| } |
| return true; |
| } |
| |
| } |
| |
| Visitor visitor = new Visitor(); |
| |
| try { |
| unit.traverse(visitor); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| |
| return visitor.getResult(); |
| } |
| |
| public static ModuleDeclaration getAST(ISourceModule module) { |
| return SourceParserUtil.getModuleDeclaration(module); |
| } |
| |
| public static ModuleDeclaration getAST(char[] cs) { |
| ISourceParser sourceParser = DLTKLanguageManager |
| .getSourceParser(RubyNature.NATURE_ID); |
| ModuleDeclaration declaration = (ModuleDeclaration) sourceParser.parse( |
| new ModuleSource("RawSource" //$NON-NLS-1$ |
| , cs), null); |
| return declaration; |
| } |
| |
| public static boolean isNodeScoping(ASTNode node) { |
| return (node instanceof RubyIfStatement |
| || node instanceof RubyForStatement2 |
| || node instanceof RubyWhileStatement |
| || node instanceof RubyBlock |
| || node instanceof RubyUntilStatement |
| || node instanceof RubyUnlessStatement |
| || node instanceof TypeDeclaration || node instanceof MethodDeclaration); |
| } |
| |
| } |