/*******************************************************************************
* Copyright (c) 2000, 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.internal.core.search;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.dltk.compiler.CharOperation;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IMethod;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptFolder;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.ScriptModelUtil;
import org.eclipse.dltk.core.search.BasicSearchEngine;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.MethodNameMatchRequestor;
import org.eclipse.dltk.core.search.TypeNameRequestor;
import org.eclipse.dltk.internal.core.Openable;
import org.eclipse.dltk.internal.core.util.HandleFactory;
import org.eclipse.dltk.internal.core.util.HashtableOfArrayToObject;
/**
* Wrapper used to link {@link IRestrictedAccessTypeRequestor} with
* {@link TypeNameRequestor}. This wrapper specifically allows usage of internal
* method
* {@link BasicSearchEngine#searchAllTypeNames(char[] packageName, int packageMatchRule, char[] typeName, int typeMatchRule, int searchFor, org.eclipse.jdt.core.search.IJavaSearchScope scope, IRestrictedAccessTypeRequestor nameRequestor, int waitingPolicy, org.eclipse.core.runtime.IProgressMonitor monitor) }
* . from API method
* {@link org.eclipse.jdt.core.search.SearchEngine#searchAllTypeNames(char[] packageName, int packageMatchRule, char[] typeName, int matchRule, int searchFor, org.eclipse.jdt.core.search.IJavaSearchScope scope, TypeNameRequestor nameRequestor, int waitingPolicy, org.eclipse.core.runtime.IProgressMonitor monitor) }
* .
*/
public class MethodNameMatchRequestorWrapper implements
IRestrictedAccessMethodRequestor {
MethodNameMatchRequestor requestor;
private IDLTKSearchScope scope; // scope is needed to retrieve project path
// for external resource
private HandleFactory handleFactory; // in case of IJavaSearchScope
// defined by clients, use an
// HandleFactory instead
/**
* Cache package fragment root information to optimize speed performance.
*/
private String lastPkgFragmentRootPath;
private IProjectFragment lastProjectFragment;
/**
* Cache package handles to optimize memory.
*/
private HashtableOfArrayToObject packageHandles;
public MethodNameMatchRequestorWrapper(MethodNameMatchRequestor requestor,
IDLTKSearchScope scope) {
this.requestor = requestor;
this.scope = scope;
if (!(scope instanceof DLTKSearchScope)) {
this.handleFactory = new HandleFactory();
}
}
@Override
public void acceptMethod(int modifiers, char[] packageName,
char[] simpleMethodName, char[][] enclosingTypeNames,
char[][] parameterNames, String path) {
try {
IMethod method = null;
if (this.handleFactory != null) {
Openable openable = this.handleFactory.createOpenable(path,
this.scope);
if (openable == null)
return;
switch (openable.getElementType()) {
case IModelElement.SOURCE_MODULE:
ISourceModule cu = (ISourceModule) openable;
method = cu.getMethod(new String(simpleMethodName));
break;
}
} else {
int separatorIndex = path
.indexOf(IDLTKSearchScope.FILE_ENTRY_SEPARATOR);
method = separatorIndex == -1 ? createMethodFromPath(path,
new String(simpleMethodName)) : null/*
* createTypeFrom(
* path ,
* separatorIndex )
*/;
if (DLTKCore.DEBUG) {
System.err.println("TODO: Add types from zips..."); //$NON-NLS-1$
}
}
if (method != null) {
this.requestor
.acceptMethodNameMatch(new DLTKSearchMethodNameMatch(
method, method.getFlags()));
}
} catch (ModelException e) {
// skip
}
}
private IMethod createMethodFromPath(String resourcePath,
String simpleMethodName) throws ModelException {
// path to a file in a directory
// Optimization: cache package fragment root handle and package handles
int rootPathLength = -1;
if (this.lastPkgFragmentRootPath == null
|| !(resourcePath.startsWith(this.lastPkgFragmentRootPath)
&& (rootPathLength = this.lastPkgFragmentRootPath
.length()) > 0 && resourcePath
.charAt(rootPathLength) == '/')) {
IProjectFragment root = ((DLTKSearchScope) this.scope)
.projectFragment(resourcePath);
if (root == null)
return null;
this.lastProjectFragment = root;
this.lastPkgFragmentRootPath = this.lastProjectFragment.getPath()
.toString();
this.packageHandles = new HashtableOfArrayToObject(5);
}
IPath resourcePath2 = new Path(resourcePath);
if (!resourcePath2.toString().startsWith(this.lastPkgFragmentRootPath)) {
return null;
}
// create handle
resourcePath = resourcePath.substring(this.lastPkgFragmentRootPath
.length() + 1);
String[] simpleNames = new Path(resourcePath).segments();
String[] pkgName;
int length = simpleNames.length - 1;
if (length > 0) {
pkgName = new String[length];
System.arraycopy(simpleNames, 0, pkgName, 0, length);
} else {
pkgName = CharOperation.NO_STRINGS;
}
IScriptFolder pkgFragment = (IScriptFolder) this.packageHandles
.get(pkgName);
if (pkgFragment == null) {
pkgFragment = this.lastProjectFragment
.getScriptFolder(ScriptModelUtil.toPath(pkgName));
this.packageHandles.put(pkgName, pkgFragment);
}
String simpleName = simpleNames[length];
ISourceModule unit = pkgFragment.getSourceModule(simpleName);
if (unit == null) {
return null;
}
return findMethod(unit, simpleMethodName);
}
private IMethod findMethod(ISourceModule unit, String simpleMethodName)
throws ModelException {
final IModelElement[] elements = unit.getChildren();
for (int i = 0; i < elements.length; i++) {
if (elements[i].getElementType() == ISourceModule.METHOD) {
IMethod function = (IMethod) elements[i];
if (function.getElementName().equals(simpleMethodName)) {
return function;
}
} else if (elements[i].getElementType() == ISourceModule.TYPE) {
IType type = (IType) elements[i];
final IMethod[] methods = type.getMethods();
for (int j = 0; j < methods.length; j++) {
IMethod method = methods[j];
if (method.getElementName().equals(simpleMethodName)) {
return method;
}
}
}
}
return null;
}
}