blob: ff2c49d341e57fb2f90ca9eea97fc5af861f522b [file] [log] [blame]
/*******************************************************************************
* 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);
}
}