| /******************************************************************************* |
| * 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.typeinference; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.dltk.ast.ASTNode; |
| import org.eclipse.dltk.ast.ASTVisitor; |
| 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.Expression; |
| import org.eclipse.dltk.ast.references.VariableReference; |
| import org.eclipse.dltk.ast.statements.Block; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.DLTKLanguageManager; |
| import org.eclipse.dltk.core.IField; |
| import org.eclipse.dltk.core.IMethod; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IParameter; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.ISourceRange; |
| import org.eclipse.dltk.core.IType; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.core.mixin.MixinModel; |
| import org.eclipse.dltk.core.search.IDLTKSearchConstants; |
| import org.eclipse.dltk.core.search.IDLTKSearchScope; |
| import org.eclipse.dltk.core.search.SearchEngine; |
| import org.eclipse.dltk.core.search.SearchMatch; |
| import org.eclipse.dltk.core.search.SearchParticipant; |
| import org.eclipse.dltk.core.search.SearchPattern; |
| import org.eclipse.dltk.core.search.SearchRequestor; |
| import org.eclipse.dltk.evaluation.types.AmbiguousType; |
| import org.eclipse.dltk.internal.core.MethodParameterInfo; |
| import org.eclipse.dltk.internal.core.ModelElement; |
| import org.eclipse.dltk.ruby.core.RubyLanguageToolkit; |
| import org.eclipse.dltk.ruby.core.RubyPlugin; |
| import org.eclipse.dltk.ruby.core.model.FakeMethod; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.ExactMixinSearchPattern; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.IRubyMixinElement; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.PrefixMixinSearchPattern; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.RubyMixin; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.RubyMixinClass; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.RubyMixinMethod; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.RubyMixinModel; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.RubyMixinVariable; |
| import org.eclipse.dltk.ruby.internal.parser.mixin.RubyObjectMixinClass; |
| import org.eclipse.dltk.ruby.typeinference.BuiltinMethodsDatabase.ClassMetaclass; |
| import org.eclipse.dltk.ruby.typeinference.BuiltinMethodsDatabase.Metaclass; |
| import org.eclipse.dltk.ruby.typeinference.BuiltinMethodsDatabase.MethodInfo; |
| import org.eclipse.dltk.ruby.typeinference.BuiltinMethodsDatabase.ModuleMetaclass; |
| import org.eclipse.dltk.ti.types.IEvaluatedType; |
| |
| public class RubyModelUtils { |
| |
| public static IType getModelTypeByAST(TypeDeclaration astNode, |
| ISourceModule sourceModule) throws ModelException { |
| IType[] types = sourceModule.getAllTypes(); |
| int astStart = astNode.sourceStart(); |
| int astEnd = astNode.sourceEnd(); |
| int bestScore = Integer.MAX_VALUE; |
| IType bestType = null; |
| for (int i = 0; i < types.length; i++) { |
| IType type = types[i]; |
| ISourceRange sourceRange = type.getSourceRange(); |
| int modelStart = sourceRange.getOffset(); |
| int modelEnd = modelStart + sourceRange.getLength(); |
| if (modelStart == astStart && modelEnd == astEnd) |
| // XXX modelEnd == astEnd + 1 currently, so this never happens |
| return type; |
| if (type.getElementName().equals(astNode.getName())) { |
| int diff1 = modelStart - astStart; |
| int diff2 = modelEnd - astEnd; |
| int score = diff1 * diff1 + diff2 * diff2; |
| if (score < bestScore) { |
| bestScore = score; |
| bestType = type; |
| } |
| } |
| } |
| return bestType; |
| } |
| |
| public static MethodDeclaration getNodeByMethod(ModuleDeclaration rootNode, |
| IMethod method) throws ModelException { |
| |
| ISourceRange sourceRange = method.getSourceRange(); |
| final int modelStart = sourceRange.getOffset(); |
| final int modelEnd = modelStart + sourceRange.getLength(); |
| final int modelCutoffStart = modelStart - 100; |
| final int modelCutoffEnd = modelEnd + 100; |
| final String methodName = method.getElementName(); |
| |
| final MethodDeclaration[] bestResult = new MethodDeclaration[1]; |
| |
| ASTVisitor visitor = new ASTVisitor() { |
| |
| int bestScore = Integer.MAX_VALUE; |
| |
| private boolean interesting(ASTNode s) { |
| if (s.sourceStart() < 0 || s.sourceEnd() < s.sourceStart()) |
| return true; |
| if (modelCutoffEnd < s.sourceStart() |
| || modelCutoffStart >= s.sourceEnd()) |
| return false; |
| return true; |
| } |
| |
| @Override |
| public boolean visit(Expression s) throws Exception { |
| if (!interesting(s)) |
| return false; |
| return true; |
| } |
| |
| @Override |
| public boolean visit(MethodDeclaration s) throws Exception { |
| if (!interesting(s)) |
| return false; |
| if (s.getName().equals(methodName)) { |
| int astStart = s.sourceStart(); |
| int astEnd = s.sourceEnd(); |
| int diff1 = modelStart - astStart; |
| int diff2 = modelEnd - astEnd; |
| int score = diff1 * diff1 + diff2 * diff2; |
| if (score < bestScore) { |
| bestScore = score; |
| bestResult[0] = s; |
| } |
| |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean visit(ModuleDeclaration s) throws Exception { |
| if (!interesting(s)) |
| return false; |
| return true; |
| } |
| |
| @Override |
| public boolean visit(TypeDeclaration s) throws Exception { |
| if (!interesting(s)) |
| return false; |
| return true; |
| } |
| |
| @Override |
| public boolean endvisit(TypeDeclaration s) throws Exception { |
| if (!interesting(s)) |
| return false; |
| return false /* dummy */; |
| } |
| |
| @Override |
| public boolean visitGeneral(ASTNode s) throws Exception { |
| if (s instanceof Block) |
| return true; |
| if (!interesting(s)) |
| return false; |
| return true; |
| } |
| |
| }; |
| |
| try { |
| rootNode.traverse(visitor); |
| } catch (Exception e) { |
| RubyPlugin.log(e); |
| } |
| |
| return bestResult[0]; |
| |
| } |
| |
| public static IField[] findFields(RubyMixinModel rubyModel, |
| ISourceModule modelModule, ModuleDeclaration parsedUnit, |
| String prefix, int position) { |
| Assert.isNotNull(prefix); |
| List result = new ArrayList(); |
| |
| String[] keys = RubyTypeInferencingUtils.getModelStaticScopesKeys( |
| rubyModel.getRawModel(), parsedUnit, position); |
| |
| IRubyMixinElement innerElement = null; |
| RubyMixinClass selfClass = new RubyObjectMixinClass(rubyModel, true); |
| |
| if (keys != null && keys.length > 0) { |
| String inner = keys[keys.length - 1]; |
| if (prefix.length() > 0 && !prefix.startsWith("@")) { //$NON-NLS-1$ // locals & constants |
| String varkey = inner + MixinModel.SEPARATOR + prefix; |
| String[] keys2 = rubyModel.getRawModel().findKeys(varkey + "*"); //$NON-NLS-1$ |
| for (int i = 0; i < keys2.length; i++) { |
| IRubyMixinElement element = rubyModel |
| .createRubyElement(keys2[i]); |
| if (element instanceof RubyMixinVariable) { |
| RubyMixinVariable variable = (RubyMixinVariable) element; |
| IField field = variable.getSourceFields()[0]; |
| if (field.getElementName().startsWith(prefix)) |
| result.add(field); |
| } |
| } |
| } else { |
| innerElement = rubyModel.createRubyElement(inner); |
| if (innerElement instanceof RubyMixinMethod) { |
| RubyMixinMethod method = (RubyMixinMethod) innerElement; |
| selfClass = method.getSelfType(); |
| RubyMixinVariable[] fields2 = method.getVariables(); |
| addVariablesFrom(fields2, prefix, result); |
| } else if (innerElement instanceof RubyMixinClass) { |
| selfClass = (RubyMixinClass) innerElement; |
| } |
| } |
| } |
| |
| if (selfClass != null) { |
| RubyMixinVariable[] fields2 = selfClass.getFields(); |
| addVariablesFrom(fields2, prefix, result); |
| if (selfClass.getKey().equals("Object")) { //$NON-NLS-1$ |
| // variables |
| try { |
| IModelElement[] children = modelModule.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| if (children[i] instanceof IField) { |
| IField field = (IField) children[i]; |
| if (field.getElementName().startsWith(prefix)) |
| result.add(field); |
| } |
| } |
| } catch (ModelException e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| return (IField[]) result.toArray(new IField[result.size()]); |
| } |
| |
| /** |
| * Handling for "new" method |
| * |
| * @param method |
| * @param selfKlass |
| * @return |
| */ |
| private static List handleSpecialMethod(RubyMixinMethod method, |
| RubyMixinClass selfKlass) { |
| if (method.getKey().equals("Class%{new")) { //$NON-NLS-1$ |
| RubyMixinMethod init = selfKlass.getInstanceClass() != null ? selfKlass |
| .getInstanceClass().getMethod("initialize") //$NON-NLS-1$ |
| : null; |
| if (init != null) { |
| IMethod[] initMethods = init.getSourceMethods(); |
| List result = new ArrayList(); |
| for (int i = 0; i < initMethods.length; i++) { |
| try { |
| IParameter[] parameters = initMethods[i] |
| .getParameters(); |
| int flags = initMethods[i].getFlags(); |
| ISourceRange sourceRange = initMethods[i] |
| .getSourceRange(); |
| ISourceRange nameRange = initMethods[i].getNameRange(); |
| IModelElement parent = initMethods[i].getParent(); |
| FakeMethod newMethod = new FakeMethod( |
| (ModelElement) parent, |
| "new", //$NON-NLS-1$ |
| sourceRange.getOffset(), sourceRange |
| .getLength(), nameRange.getOffset(), |
| nameRange.getLength()); |
| newMethod.setParameters(parameters); |
| newMethod.setFlags(flags); |
| String receiver = ""; //$NON-NLS-1$ |
| if (parent instanceof IType) { |
| IType type = (IType) parent; |
| receiver = type.getTypeQualifiedName("::"); //$NON-NLS-1$ |
| } |
| newMethod.setReceiver(receiver); |
| result.add(newMethod); |
| } catch (ModelException e) { |
| e.printStackTrace(); |
| } |
| } |
| return result; |
| } |
| } |
| return null; |
| } |
| |
| public static List getAllSourceMethods(RubyMixinMethod[] methods, |
| RubyMixinClass selfKlass) { |
| List result = new ArrayList(); |
| for (int i = 0; i < methods.length; i++) { |
| if (selfKlass != null) { |
| List m = handleSpecialMethod(methods[i], selfKlass); |
| if (m != null) { |
| result.addAll(m); |
| continue; |
| } |
| } |
| IMethod[] sourceMethods = methods[i].getSourceMethods(); |
| for (int j = 0; j < sourceMethods.length; j++) { |
| if (sourceMethods[j] != null/* |
| * && |
| * sourceMethods[j].getElementName() |
| * .startsWith(prefix) |
| */) { |
| result.add(sourceMethods[j]); |
| } |
| } |
| } |
| return result; |
| } |
| |
| public static IMethod[] searchClassMethods(final RubyMixinModel mixinModel, |
| org.eclipse.dltk.core.ISourceModule modelModule, |
| ModuleDeclaration moduleDeclaration, IEvaluatedType type, |
| String prefix) { |
| List result = new ArrayList(); |
| if (type instanceof RubyClassType) { |
| RubyClassType rubyClassType = (RubyClassType) type; |
| RubyMixinClass rubyClass = mixinModel |
| .createRubyClass(rubyClassType); |
| if (rubyClass != null) { |
| RubyMixinMethod[] methods = rubyClass |
| .findMethods(new PrefixMixinSearchPattern(prefix)); |
| result.addAll(getAllSourceMethods(methods, rubyClass)); |
| } |
| |
| } else if (type instanceof AmbiguousType) { |
| AmbiguousType type2 = (AmbiguousType) type; |
| IEvaluatedType[] possibleTypes = type2.getPossibleTypes(); |
| for (int i = 0; i < possibleTypes.length; i++) { |
| IMethod[] m = searchClassMethods(mixinModel, modelModule, |
| moduleDeclaration, possibleTypes[i], prefix); |
| for (int j = 0; j < m.length; j++) { |
| result.add(m[j]); |
| } |
| } |
| } |
| return (IMethod[]) result.toArray(new IMethod[result.size()]); |
| } |
| |
| public static IMethod[] searchClassMethodsExact( |
| final RubyMixinModel mixinModel, |
| org.eclipse.dltk.core.ISourceModule modelModule, |
| ModuleDeclaration moduleDeclaration, IEvaluatedType type, |
| String methodName) { |
| List result = new ArrayList(); |
| if (type instanceof RubyClassType) { |
| RubyClassType rubyClassType = (RubyClassType) type; |
| RubyMixinClass rubyClass = mixinModel |
| .createRubyClass(rubyClassType); |
| if (rubyClass != null) { |
| RubyMixinMethod[] methods = rubyClass |
| .findMethods(new ExactMixinSearchPattern(methodName)); |
| result.addAll(getAllSourceMethods(methods, rubyClass)); |
| } |
| |
| } else if (type instanceof AmbiguousType) { |
| AmbiguousType type2 = (AmbiguousType) type; |
| IEvaluatedType[] possibleTypes = type2.getPossibleTypes(); |
| for (int i = 0; i < possibleTypes.length; i++) { |
| IMethod[] m = searchClassMethodsExact(mixinModel, modelModule, |
| moduleDeclaration, possibleTypes[i], methodName); |
| for (int j = 0; j < m.length; j++) { |
| result.add(m[j]); |
| } |
| } |
| } |
| return (IMethod[]) result.toArray(new IMethod[result.size()]); |
| } |
| |
| private static void addVariablesFrom(RubyMixinVariable[] fields2, |
| String prefix, List resultList) { |
| for (int i = 0; i < fields2.length; i++) { |
| IField[] sourceFields = fields2[i].getSourceFields(); |
| if (sourceFields != null) { |
| for (int j = 0; j < sourceFields.length; j++) { |
| if (sourceFields[j] != null) { |
| if (sourceFields[j].getElementName().startsWith(prefix)) { |
| resultList.add(sourceFields[j]); |
| break; |
| } |
| |
| } |
| |
| } |
| } |
| } |
| } |
| |
| public static IMethod[] getSingletonMethods( |
| final RubyMixinModel mixinModel, VariableReference receiver, |
| ModuleDeclaration parsedUnit, ISourceModule modelModule, |
| String methodName) { |
| IMethod[] res = null; |
| String[] scopesKeys = RubyTypeInferencingUtils |
| .getModelStaticScopesKeys(mixinModel.getRawModel(), parsedUnit, |
| receiver.sourceStart()); |
| if (scopesKeys != null && scopesKeys.length > 0) { |
| String possibleName; |
| if (scopesKeys.length == 1) { |
| possibleName = receiver.getName() + RubyMixin.VIRTUAL_SUFFIX; |
| } else { |
| String last = scopesKeys[scopesKeys.length - 1]; |
| possibleName = last + MixinModel.SEPARATOR + receiver.getName() |
| + RubyMixin.VIRTUAL_SUFFIX; |
| } |
| IRubyMixinElement element = mixinModel |
| .createRubyElement(possibleName); |
| if (element instanceof RubyMixinClass) { |
| RubyMixinClass rubyMixinClass = (RubyMixinClass) element; |
| res = RubyModelUtils.searchClassMethodsExact(mixinModel, |
| modelModule, parsedUnit, new RubyClassType( |
| rubyMixinClass.getKey()), methodName); |
| } |
| } |
| return res; |
| } |
| |
| // public static RubyClassType getSuperType(IType type) { |
| // String[] superClasses; |
| // try { |
| // superClasses = type.getSuperClasses(); |
| // } catch (ModelException e) { |
| // e.printStackTrace(); |
| // return null; |
| // } |
| // if (superClasses != null && superClasses.length == 1) { |
| // String name = superClasses[0]; |
| // IType[] types; |
| // if (name.startsWith("::")) { |
| // types = DLTKModelUtil.getAllTypes(type.getScriptProject(), name, "::"); |
| // } else { |
| // String scopeFQN = type.getTypeQualifiedName("::"); |
| // types = DLTKModelUtil.getAllScopedTypes(type.getScriptProject(), name, |
| // "::", scopeFQN); |
| // } |
| // if (types != null && types.length > 0) { |
| // String typeQualifiedName = |
| // types[0].getTypeQualifiedName("::").substring(2); |
| // String[] FQN = typeQualifiedName.split("::"); |
| // return new RubyClassType(FQN, types, null); |
| // } else { |
| // FakeMethod[] fakeMethods = getFakeMethods((ModelElement) type, name); |
| // if (fakeMethods != null) { |
| // return new RubyClassType(new String[]{name}, null, fakeMethods); |
| // } |
| // } |
| // } |
| // FakeMethod[] fakeMethods = getFakeMethods((ModelElement) type, "Object"); |
| // return new RubyClassType(new String[]{"Object"}, null, fakeMethods); |
| // } |
| |
| public static FakeMethod[] getFakeMethods(ModelElement parent, String klass) { |
| Metaclass metaclass = BuiltinMethodsDatabase.get(klass); |
| if (metaclass != null) { |
| List fakeMethods = new ArrayList(); |
| addFakeMethods(parent, metaclass, fakeMethods); |
| return (FakeMethod[]) fakeMethods |
| .toArray(new FakeMethod[fakeMethods.size()]); |
| } |
| // XXX the following code is legacy |
| String[] names = getBuiltinMethodNames(klass); |
| if (names == null) |
| return new FakeMethod[0]; |
| List methods = new ArrayList(); |
| for (int i = 0; i < names.length; i++) { |
| FakeMethod method = new FakeMethod(parent, names[i]); |
| method.setReceiver(klass); |
| methods.add(method); |
| } |
| return (FakeMethod[]) methods.toArray(new FakeMethod[methods.size()]); |
| } |
| |
| private static void addFakeMethods(ModelElement parent, |
| Metaclass metaclass, List fakeMethods) { |
| // process included modules first, to allow the class to override |
| // some of the methods |
| ModuleMetaclass[] includedModules = metaclass.getIncludedModules(); |
| for (int i = 0; i < includedModules.length; i++) { |
| ModuleMetaclass module = includedModules[i]; |
| addFakeMethods(parent, module, fakeMethods); |
| } |
| MethodInfo[] methods = metaclass.getMethods(); |
| for (int i = 0; i < methods.length; i++) { |
| MethodInfo info = methods[i]; |
| FakeMethod method = createFakeMethod(parent, metaclass, info); |
| fakeMethods.add(method); |
| } |
| if (metaclass instanceof BuiltinMethodsDatabase.ClassMetaclass) { |
| BuiltinMethodsDatabase.ClassMetaclass classMeta = (BuiltinMethodsDatabase.ClassMetaclass) metaclass; |
| ClassMetaclass superClass = classMeta.getSuperClass(); |
| if (superClass != null) |
| addFakeMethods(parent, superClass, fakeMethods); |
| } |
| } |
| |
| private static FakeMethod createFakeMethod(ModelElement parent, |
| Metaclass metaclass, MethodInfo info) { |
| FakeMethod method = new FakeMethod(parent, info.getName()); |
| method.setFlags(info.getFlags()); |
| int arity = info.getArity(); |
| IParameter[] parameters; |
| if (arity > 0) { |
| parameters = new IParameter[arity]; |
| for (int i = 0; i < arity; i++) |
| parameters[i] = new MethodParameterInfo("arg" + (i + 1)); //$NON-NLS-1$ |
| } else if (arity < 0) { |
| parameters = new IParameter[-arity]; |
| for (int i = 0; i < -arity - 1; i++) |
| parameters[i] = new MethodParameterInfo("arg" + (i + 1)); //$NON-NLS-1$ |
| parameters[-arity - 1] = new MethodParameterInfo("..."); //$NON-NLS-1$ |
| } else { |
| parameters = new IParameter[0]; |
| } |
| method.setParameters(parameters); |
| method.setReceiver(metaclass.getName()); |
| return method; |
| } |
| |
| public static FakeMethod[] getFakeMetaMethods(ModelElement parent, |
| String klass) { |
| Metaclass metaclass = BuiltinMethodsDatabase.get(klass); |
| if (metaclass != null) { |
| ClassMetaclass metaMetaclass = metaclass.getMetaClass(); |
| List fakeMethods = new ArrayList(); |
| addFakeMethods(parent, metaMetaclass, fakeMethods); |
| return (FakeMethod[]) fakeMethods |
| .toArray(new FakeMethod[fakeMethods.size()]); |
| } |
| String[] names = getBuiltinMetaMethodNames(klass); |
| if (names == null) |
| return new FakeMethod[0]; |
| List methods = new ArrayList(); |
| for (int i = 0; i < names.length; i++) { |
| FakeMethod method = new FakeMethod(parent, names[i]); |
| method.setReceiver(klass); |
| methods.add(method); |
| } |
| return (FakeMethod[]) methods.toArray(new FakeMethod[methods.size()]); |
| } |
| |
| public static String[] getBuiltinMethodNames(String klass) { |
| if (klass.equals("Object")) { //$NON-NLS-1$ |
| return BuiltinTypeMethods.objectMethods; |
| } else if (klass.equals("String")) { //$NON-NLS-1$ |
| return BuiltinTypeMethods.stringMethods; |
| } else if (klass.equals("Fixnum")) { //$NON-NLS-1$ |
| return BuiltinTypeMethods.fixnumMethods; |
| } else if (klass.equals("Float")) { //$NON-NLS-1$ |
| return BuiltinTypeMethods.floatMethods; |
| } else if (klass.equals("Regexp")) { //$NON-NLS-1$ |
| return BuiltinTypeMethods.regexpMethods; |
| } else if (klass.equals("Array")) { //$NON-NLS-1$ |
| return BuiltinTypeMethods.arrayMethods; |
| } |
| return null; |
| } |
| |
| public static String[] getBuiltinMetaMethodNames(String klass) { |
| if (klass.equals("Object")) { //$NON-NLS-1$ |
| return BuiltinMethodsDatabase.objectMethods; |
| } |
| return null; |
| } |
| |
| public static IType[] findTopLevelTypes(ISourceModule module, |
| String namePrefix) { |
| List result = new ArrayList(); |
| |
| try { |
| // TODO: add handling of "require" |
| IModelElement[] children = module.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| if (children[i] instanceof IType |
| && children[i].getElementName().startsWith(namePrefix)) |
| result.add(children[i]); |
| } |
| } catch (ModelException e) { |
| e.printStackTrace(); |
| } |
| |
| return (IType[]) result.toArray(new IType[result.size()]); |
| } |
| |
| public static IField[] findTopLevelFields(ISourceModule module, |
| String namePrefix) { |
| List result = new ArrayList(); |
| |
| try { |
| IModelElement[] children = module.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| if (children[i] instanceof IField |
| && children[i].getElementName().startsWith(namePrefix)) |
| result.add(children[i]); |
| } |
| } catch (ModelException e) { |
| e.printStackTrace(); |
| } |
| |
| return (IField[]) result.toArray(new IField[result.size()]); |
| } |
| |
| public static IMethod[] findTopLevelMethods(IScriptProject project, |
| String namePattern) { |
| final List result = new ArrayList(); |
| SearchRequestor requestor = new SearchRequestor() { |
| |
| @Override |
| public void acceptSearchMatch(SearchMatch match) |
| throws CoreException { |
| Object element = match.getElement(); |
| if (element instanceof IMethod) { |
| IMethod meth = (IMethod) element; |
| if (meth.getParent() instanceof ISourceModule) { |
| result.add(meth); |
| } |
| } |
| } |
| |
| }; |
| SearchPattern pattern = SearchPattern.createPattern(namePattern, |
| IDLTKSearchConstants.METHOD, IDLTKSearchConstants.DECLARATIONS, |
| SearchPattern.R_PATTERN_MATCH | SearchPattern.R_EXACT_MATCH, |
| DLTKLanguageManager.getLanguageToolkit(project)); |
| IDLTKSearchScope scope; |
| if (project != null) |
| scope = SearchEngine.createSearchScope(project); |
| else |
| scope = SearchEngine.createWorkspaceScope(RubyLanguageToolkit |
| .getDefault()); |
| try { |
| SearchEngine engine = new SearchEngine(); |
| engine.search(pattern, new SearchParticipant[] { SearchEngine |
| .getDefaultSearchParticipant() }, scope, requestor, null); |
| } catch (CoreException e) { |
| if (DLTKCore.DEBUG) |
| e.printStackTrace(); |
| } |
| |
| return (IMethod[]) result.toArray(new IMethod[result.size()]); |
| } |
| |
| /** |
| * Should return mixin-key of superclass |
| * |
| * @param type |
| * @return |
| */ |
| public static String evaluateSuperClass(IType type) { |
| String superclass = null; |
| String[] superClasses; |
| try { |
| superClasses = type.getSuperClasses(); |
| } catch (ModelException e) { |
| e.printStackTrace(); |
| return null; |
| } |
| if (superClasses != null && superClasses.length > 0) { |
| superclass = superClasses[0]; |
| if (superclass.startsWith("::")) //$NON-NLS-1$ |
| superclass = superclass.substring(2); |
| superclass = superclass.replaceAll("::", "{"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| // TODO: add appropriate evaluation here |
| |
| return superclass; |
| } |
| |
| } |