| /******************************************************************************* |
| * Copyright (c) 2008, 2017 xored software, Inc. |
| * |
| * 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: |
| * xored software, Inc. - initial API and Implementation (Alex Panchenko) |
| *******************************************************************************/ |
| package org.eclipse.dltk.ruby.testing.internal; |
| |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Set; |
| import java.util.Stack; |
| |
| import org.eclipse.dltk.ast.ASTNode; |
| import org.eclipse.dltk.ast.ASTVisitor; |
| import org.eclipse.dltk.ast.declarations.MethodDeclaration; |
| import org.eclipse.dltk.ast.expressions.CallExpression; |
| import org.eclipse.dltk.ast.expressions.StringLiteral; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.search.indexing.IIndexConstants; |
| import org.eclipse.dltk.ruby.ast.RubyCallArgument; |
| import org.eclipse.dltk.ruby.ast.RubyClassDeclaration; |
| import org.eclipse.dltk.ruby.core.RubyConstants; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.RubyMixinClass; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.RubyMixinModel; |
| import org.eclipse.dltk.ruby.typeinference.RubyClassType; |
| |
| public class AbstractTestingEngineValidateVisitor extends ASTVisitor { |
| |
| private final Stack<ASTNode> stack = new Stack<>(); |
| |
| /** |
| * @param call |
| * @param methods |
| * @return |
| */ |
| protected boolean isMethodCall(CallExpression call, String[] methods) { |
| if (call.getReceiver() != null) { |
| return false; |
| } |
| final String methodName = call.getName(); |
| for (int i = 0; i < methods.length; ++i) { |
| if (methodName.equals(methods[i])) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * @param nodeClass |
| * @return |
| */ |
| protected boolean isNodeOnStack(Class<?> nodeClass) { |
| for (int i = stack.size(); --i >= 0;) { |
| if (nodeClass.isAssignableFrom(stack.get(i).getClass())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visitGeneral(ASTNode node) throws Exception { |
| stack.push(node); |
| return super.visitGeneral(node); |
| } |
| |
| @Override |
| public void endvisitGeneral(ASTNode node) throws Exception { |
| stack.pop(); |
| super.endvisitGeneral(node); |
| } |
| |
| protected boolean isMethodPrefix(final MethodDeclaration method, final String prefix) { |
| final String methodName = method.getName(); |
| return methodName.startsWith(prefix) && methodName.length() > prefix.length(); |
| } |
| |
| protected boolean isSuperClassOf(ISourceModule module, RubyClassDeclaration declaration, final String className) { |
| if (declaration.getSuperClassNames().contains(className)) |
| return true; |
| else { |
| String classKey = className.replaceAll("::", //$NON-NLS-1$ |
| String.valueOf(IIndexConstants.SEPARATOR)); |
| Set<String> processedKeys = new HashSet<>(); |
| for (Iterator<String> iter = declaration.getSuperClassNames().iterator(); iter.hasNext();) { |
| String superClass = iter.next(); |
| RubyMixinModel model = RubyMixinModel.getInstance(module.getScriptProject()); |
| RubyMixinClass mixinClass = model.createRubyClass(new RubyClassType(superClass.replaceAll("::", String //$NON-NLS-1$ |
| .valueOf(IIndexConstants.SEPARATOR)))); |
| if (mixinClass != null) |
| // ssanders - Already know that it's indirect, because of |
| // contains() above |
| mixinClass = mixinClass.getSuperclass(); |
| while (mixinClass != null) { |
| if (processedKeys.add(mixinClass.getKey()) == true) { |
| if (mixinClass.getKey().equals(classKey)) |
| return true; |
| mixinClass = mixinClass.getSuperclass(); |
| } else { |
| mixinClass = null; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| private boolean isRequire(CallExpression call) { |
| return call.getReceiver() == null && RubyConstants.REQUIRE.equals(call.getName()) |
| && call.getArgs().getChilds().size() == 1; |
| } |
| |
| protected boolean isRequire(CallExpression call, String moduleName) { |
| if (isRequire(call)) { |
| final ASTNode argument = call.getArgs().getChilds().get(0); |
| return isStringLiteralArgument(argument, moduleName); |
| } |
| return false; |
| } |
| |
| protected boolean isStringLiteralArgument(ASTNode argument, String value) { |
| if (argument instanceof RubyCallArgument) { |
| RubyCallArgument callArg = (RubyCallArgument) argument; |
| if (callArg.getValue() instanceof StringLiteral) { |
| StringLiteral literal = (StringLiteral) callArg.getValue(); |
| if (value.equals(literal.getValue())) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| } |