All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.org.eclipse.jdt.internal.core.search.matching.MatchLocator Maven / Gradle / Ivy

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2000, 2014 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
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Stephan Herrmann - Contribution for
 *								Bug 377883 - NPE on open Call Hierarchy
 *******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.core.search.matching;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.zip.ZipFile;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.*;
import org.aspectj.org.eclipse.jdt.core.Flags;
import org.aspectj.org.eclipse.jdt.core.IAnnotatable;
import org.aspectj.org.eclipse.jdt.core.IAnnotation;
import org.aspectj.org.eclipse.jdt.core.IClassFile;
import org.aspectj.org.eclipse.jdt.core.IJavaElement;
import org.aspectj.org.eclipse.jdt.core.IJavaModelStatusConstants;
import org.aspectj.org.eclipse.jdt.core.IJavaProject;
import org.aspectj.org.eclipse.jdt.core.IMember;
import org.aspectj.org.eclipse.jdt.core.IMethod;
import org.aspectj.org.eclipse.jdt.core.IPackageFragment;
import org.aspectj.org.eclipse.jdt.core.IPackageFragmentRoot;
import org.aspectj.org.eclipse.jdt.core.ISourceRange;
import org.aspectj.org.eclipse.jdt.core.IType;
import org.aspectj.org.eclipse.jdt.core.JavaModelException;
import org.aspectj.org.eclipse.jdt.core.Signature;
import org.aspectj.org.eclipse.jdt.core.compiler.*;
import org.aspectj.org.eclipse.jdt.core.search.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
import org.aspectj.org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.Messages;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.aspectj.org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver;
import org.aspectj.org.eclipse.jdt.internal.core.BinaryMember;
import org.aspectj.org.eclipse.jdt.internal.core.BinaryType;
import org.aspectj.org.eclipse.jdt.internal.core.ClassFile;
import org.aspectj.org.eclipse.jdt.internal.core.CompilationUnit;
import org.aspectj.org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
import org.aspectj.org.eclipse.jdt.internal.core.JavaElement;
import org.aspectj.org.eclipse.jdt.internal.core.JavaModelManager;
import org.aspectj.org.eclipse.jdt.internal.core.JavaProject;
import org.aspectj.org.eclipse.jdt.internal.core.LambdaFactory;
import org.aspectj.org.eclipse.jdt.internal.core.LocalVariable;
import org.aspectj.org.eclipse.jdt.internal.core.NameLookup;
import org.aspectj.org.eclipse.jdt.internal.core.Openable;
import org.aspectj.org.eclipse.jdt.internal.core.PackageFragment;
import org.aspectj.org.eclipse.jdt.internal.core.PackageFragmentRoot;
import org.aspectj.org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.aspectj.org.eclipse.jdt.internal.core.SourceMapper;
import org.aspectj.org.eclipse.jdt.internal.core.SourceMethod;
import org.aspectj.org.eclipse.jdt.internal.core.SourceType;
import org.aspectj.org.eclipse.jdt.internal.core.SourceTypeElementInfo;
import org.aspectj.org.eclipse.jdt.internal.core.index.Index;
import org.aspectj.org.eclipse.jdt.internal.core.search.*;
import org.aspectj.org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
import org.aspectj.org.eclipse.jdt.internal.core.util.ASTNodeFinder;
import org.aspectj.org.eclipse.jdt.internal.core.util.HandleFactory;
import org.aspectj.org.eclipse.jdt.internal.core.util.Util;

@SuppressWarnings({"rawtypes", "unchecked"})
public class MatchLocator implements ITypeRequestor {

public static final int MAX_AT_ONCE;
static {
	long maxMemory = Runtime.getRuntime().maxMemory();
	int ratio = (int) Math.round(((double) maxMemory) / (64 * 0x100000));
	switch (ratio) {
		case 0:
		case 1:
			MAX_AT_ONCE = 100;
			break;
		case 2:
			MAX_AT_ONCE = 200;
			break;
		case 3:
			MAX_AT_ONCE = 300;
			break;
		default:
			MAX_AT_ONCE = 400;
			break;
	}
}

// permanent state
public SearchPattern pattern;
public PatternLocator patternLocator;
public int matchContainer;
public SearchRequestor requestor;
public IJavaSearchScope scope;
public IProgressMonitor progressMonitor;

public org.aspectj.org.eclipse.jdt.core.ICompilationUnit[] workingCopies;
public HandleFactory handleFactory;

// cache of all super type names if scope is hierarchy scope
public char[][][] allSuperTypeNames;

// the following is valid for the current project
public MatchLocatorParser parser;
private Parser basicParser;
public INameEnvironment nameEnvironment;
public NameLookup nameLookup;
public LookupEnvironment lookupEnvironment;
public HierarchyResolver hierarchyResolver;

public CompilerOptions options;

// management of PossibleMatch to be processed
public int numberOfMatches; // (numberOfMatches - 1) is the last unit in matchesToProcess
public PossibleMatch[] matchesToProcess;
public PossibleMatch currentPossibleMatch;

/*
 * Time spent in the IJavaSearchResultCollector
 */
public long resultCollectorTime = 0;

// Progress information
int progressStep;
int progressWorked;

// Binding resolution and cache
CompilationUnitScope unitScope;
SimpleLookupTable bindings;

// Cache for method handles
HashSet methodHandles;

private final boolean searchPackageDeclaration;
private int sourceStartOfMethodToRetain;
private int sourceEndOfMethodToRetain;

public static class WorkingCopyDocument extends JavaSearchDocument {
	public org.aspectj.org.eclipse.jdt.core.ICompilationUnit workingCopy;
	WorkingCopyDocument(org.aspectj.org.eclipse.jdt.core.ICompilationUnit workingCopy, SearchParticipant participant) {
		super(workingCopy.getPath().toString(), participant);
		this.charContents = ((CompilationUnit)workingCopy).getContents();
		this.workingCopy = workingCopy;
	}
	public String toString() {
		return "WorkingCopyDocument for " + getPath(); //$NON-NLS-1$
	}
}

public static class WrappedCoreException extends RuntimeException {
	private static final long serialVersionUID = 8354329870126121212L; // backward compatible
	public CoreException coreException;
	public WrappedCoreException(CoreException coreException) {
		this.coreException = coreException;
	}
}

public static SearchDocument[] addWorkingCopies(SearchPattern pattern, SearchDocument[] indexMatches, org.aspectj.org.eclipse.jdt.core.ICompilationUnit[] copies, SearchParticipant participant) {
	if (copies == null) return indexMatches;
	// working copies take precedence over corresponding compilation units
	HashMap workingCopyDocuments = workingCopiesThatCanSeeFocus(copies, pattern, participant);
	if (workingCopyDocuments.size() == 0) return indexMatches;
	SearchDocument[] matches = null;
	int length = indexMatches.length;
	for (int i = 0; i < length; i++) {
		SearchDocument searchDocument = indexMatches[i];
		if (searchDocument.getParticipant() == participant) {
			SearchDocument workingCopyDocument = (SearchDocument) workingCopyDocuments.remove(searchDocument.getPath());
			if (workingCopyDocument != null) {
				if (matches == null) {
					System.arraycopy(indexMatches, 0, matches = new SearchDocument[length], 0, length);
				}
				matches[i] = workingCopyDocument;
			}
		}
	}
	if (matches == null) { // no working copy
		matches = indexMatches;
	}
	int remainingWorkingCopiesSize = workingCopyDocuments.size();
	if (remainingWorkingCopiesSize != 0) {
		System.arraycopy(matches, 0, matches = new SearchDocument[length+remainingWorkingCopiesSize], 0, length);
		Iterator iterator = workingCopyDocuments.values().iterator();
		int index = length;
		while (iterator.hasNext()) {
			matches[index++] = (SearchDocument) iterator.next();
		}
	}
	return matches;
}

public static void setFocus(SearchPattern pattern, IJavaElement focus) {
	pattern.focus = focus;
}

/*
 * Returns the working copies that can see the given focus.
 */
private static HashMap workingCopiesThatCanSeeFocus(org.aspectj.org.eclipse.jdt.core.ICompilationUnit[] copies, SearchPattern pattern, SearchParticipant participant) {
	if (copies == null) return new HashMap();
	HashMap result = new HashMap();
	for (int i=0, length = copies.length; i  build compilation unit declarations, their bindings and record their results.
 */
public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) {
	// Switch the current policy and compilation result for this unit to the requested one.
	CompilationResult unitResult = new CompilationResult(sourceUnit, 1, 1, this.options.maxProblemsPerUnit);
	try {
		CompilationUnitDeclaration parsedUnit = basicParser().dietParse(sourceUnit, unitResult);
		this.lookupEnvironment.buildTypeBindings(parsedUnit, accessRestriction);
		this.lookupEnvironment.completeTypeBindings(parsedUnit, true);
	} catch (AbortCompilationUnit e) {
		// at this point, currentCompilationUnitResult may not be sourceUnit, but some other
		// one requested further along to resolve sourceUnit.
		if (unitResult.compilationUnit == sourceUnit) { // only report once
			//requestor.acceptResult(unitResult.tagAsAccepted());
		} else {
			throw e; // want to abort enclosing request to compile
		}
	}
	// Display unit error in debug mode
	if (BasicSearchEngine.VERBOSE) {
		if (unitResult.problemCount > 0) {
			System.out.println(unitResult);
		}
	}
}
/**
 * Add additional source types
 */
public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) {
	// case of SearchableEnvironment of an IJavaProject is used
	ISourceType sourceType = sourceTypes[0];
	while (sourceType.getEnclosingType() != null)
		sourceType = sourceType.getEnclosingType();
	if (sourceType instanceof SourceTypeElementInfo) {
		// get source
		SourceTypeElementInfo elementInfo = (SourceTypeElementInfo) sourceType;
		IType type = elementInfo.getHandle();
		ICompilationUnit sourceUnit = (ICompilationUnit) type.getCompilationUnit();
		accept(sourceUnit, accessRestriction);
	} else {
		CompilationResult result = new CompilationResult(sourceType.getFileName(), 1, 1, 0);
		CompilationUnitDeclaration unit =
			SourceTypeConverter.buildCompilationUnit(
				sourceTypes,
				SourceTypeConverter.FIELD_AND_METHOD // need field and methods
				| SourceTypeConverter.MEMBER_TYPE, // need member types
				// no need for field initialization
				this.lookupEnvironment.problemReporter,
				result);
		this.lookupEnvironment.buildTypeBindings(unit, accessRestriction);
		this.lookupEnvironment.completeTypeBindings(unit, true);
	}
}
protected Parser basicParser() {
	if (this.basicParser == null) {
		ProblemReporter problemReporter =
			new ProblemReporter(
				DefaultErrorHandlingPolicies.proceedWithAllProblems(),
				this.options,
				new DefaultProblemFactory());
		this.basicParser = new Parser(problemReporter, false);
		this.basicParser.reportOnlyOneSyntaxError = true;
	}
	return this.basicParser;
}
/*
 * Caches the given binary type in the lookup environment and returns it.
 * Returns the existing one if already cached.
 * Returns null if source type binding was cached.
 */
protected BinaryTypeBinding cacheBinaryType(IType type, IBinaryType binaryType) throws JavaModelException {
	IType enclosingType = type.getDeclaringType();
	if (enclosingType != null)
		cacheBinaryType(enclosingType, null); // cache enclosing types first, so that binary type can be found in lookup enviroment
	if (binaryType == null) {
		ClassFile classFile = (ClassFile) type.getClassFile();
		try {
			binaryType = getBinaryInfo(classFile, classFile.resource());
		} catch (CoreException e) {
			if (e instanceof JavaModelException) {
				throw (JavaModelException) e;
			} else {
				throw new JavaModelException(e);
			}
		}
	}
	BinaryTypeBinding binding = this.lookupEnvironment.cacheBinaryType(binaryType, null /*no access restriction*/);
	if (binding == null) { // it was already cached as a result of a previous query
		char[][] compoundName = CharOperation.splitOn('.', type.getFullyQualifiedName().toCharArray());
		ReferenceBinding referenceBinding = this.lookupEnvironment.getCachedType(compoundName);
		if (referenceBinding != null && (referenceBinding instanceof BinaryTypeBinding))
			binding = (BinaryTypeBinding) referenceBinding; // if the binding could be found and if it comes from a binary type
	}
	return binding;
}
/*
 * Computes the super type names of the focus type if any.
 */
protected char[][][] computeSuperTypeNames(IType focusType) {
	String fullyQualifiedName = focusType.getFullyQualifiedName();
	int lastDot = fullyQualifiedName.lastIndexOf('.');
	char[] qualification = lastDot == -1 ? CharOperation.NO_CHAR : fullyQualifiedName.substring(0, lastDot).toCharArray();
	char[] simpleName = focusType.getElementName().toCharArray();

	SuperTypeNamesCollector superTypeNamesCollector =
		new SuperTypeNamesCollector(
			this.pattern,
			simpleName,
			qualification,
			new MatchLocator(this.pattern, this.requestor, this.scope, this.progressMonitor), // clone MatchLocator so that it has no side effect
			focusType,
			this.progressMonitor);
	try {
		this.allSuperTypeNames = superTypeNamesCollector.collect();
	} catch (JavaModelException e) {
		// problem collecting super type names: leave it null
	}
	return this.allSuperTypeNames;
}
/**
 * Creates an IMethod from the given lambda declaration and type.
 */
protected IJavaElement createHandle(LambdaExpression lambdaExpression, IJavaElement parent) {
	org.aspectj.org.eclipse.jdt.internal.core.LambdaExpression lambdaElement = LambdaFactory.createLambdaExpression((JavaElement) parent, lambdaExpression);
	IMethod lambdaMethodElement = lambdaElement.getMethod();
	this.methodHandles.add(lambdaMethodElement);
	return lambdaMethodElement;
}
/**
 * Creates an IMethod from the given method declaration and type.
 */
protected IJavaElement createHandle(AbstractMethodDeclaration method, IJavaElement parent) {
	if (!(parent instanceof IType)) return parent;

	IType type = (IType) parent;
	Argument[] arguments = method.arguments;
	int argCount = arguments == null ? 0 : arguments.length;
	if (type.isBinary()) {
		// don't cache the methods of the binary type
		// fall thru if its a constructor with a synthetic argument... find it the slower way
		ClassFileReader reader = classFileReader(type);
		if (reader != null) {
			// build arguments names
			boolean firstIsSynthetic = false;
			if (reader.isMember() && method.isConstructor() && !Flags.isStatic(reader.getModifiers())) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=48261
				firstIsSynthetic = true;
				argCount++;
			}
			char[][] argumentTypeNames = new char[argCount][];
			for (int i = 0; i < argCount; i++) {
				char[] typeName = null;
				if (i == 0 && firstIsSynthetic) {
					typeName = type.getDeclaringType().getFullyQualifiedName().toCharArray();
				} else if (arguments != null) {
					TypeReference typeRef = arguments[firstIsSynthetic ? i - 1 : i].type;
					typeName = CharOperation.concatWith(typeRef.getTypeName(), '.');
					for (int k = 0, dim = typeRef.dimensions(); k < dim; k++)
						typeName = CharOperation.concat(typeName, new char[] {'[', ']'});
				}
				if (typeName == null) {
					// invalid type name
					return null;
				}
				argumentTypeNames[i] = typeName;
			}
			// return binary method
			IMethod binaryMethod = createBinaryMethodHandle(type, method.selector, argumentTypeNames);
			if (binaryMethod == null) {
				// when first attempt fails, try with similar matches if any...
				PossibleMatch similarMatch = this.currentPossibleMatch.getSimilarMatch();
				while (similarMatch != null) {
					type = ((ClassFile)similarMatch.openable).getType();
					binaryMethod = createBinaryMethodHandle(type, method.selector, argumentTypeNames);
					if (binaryMethod != null) {
						return binaryMethod;
					}
					similarMatch = similarMatch.getSimilarMatch();
				}
			}
			return binaryMethod;
		}
		if (BasicSearchEngine.VERBOSE) {
			System.out.println("Not able to createHandle for the method " + //$NON-NLS-1$
					CharOperation.charToString(method.selector) + " May miss some results");  //$NON-NLS-1$
		}
		return null;
	}

	String[] parameterTypeSignatures = new String[argCount];
	if (arguments != null) {
		for (int i = 0; i < argCount; i++) {
			TypeReference typeRef = arguments[i].type;
			char[] typeName = CharOperation.concatWith(typeRef.getParameterizedTypeName(), '.');
			parameterTypeSignatures[i] = Signature.createTypeSignature(typeName, false);
		}
	}

	return createMethodHandle(type, new String(method.selector), parameterTypeSignatures);
}
/*
 * Create binary method handle
 */
IMethod createBinaryMethodHandle(IType type, char[] methodSelector, char[][] argumentTypeNames) {
	ClassFileReader reader = MatchLocator.classFileReader(type);
	if (reader != null) {
		IBinaryMethod[] methods = reader.getMethods();
		if (methods != null) {
			int argCount = argumentTypeNames == null ? 0 : argumentTypeNames.length;
			nextMethod : for (int i = 0, methodsLength = methods.length; i < methodsLength; i++) {
				IBinaryMethod binaryMethod = methods[i];
				char[] selector = binaryMethod.isConstructor() ? type.getElementName().toCharArray() : binaryMethod.getSelector();
				if (CharOperation.equals(selector, methodSelector)) {
					char[] signature = binaryMethod.getGenericSignature();
					if (signature == null) signature = binaryMethod.getMethodDescriptor();
					char[][] parameterTypes = Signature.getParameterTypes(signature);
					if (argCount != parameterTypes.length) continue nextMethod;
					if (argumentTypeNames != null) {
						for (int j = 0; j < argCount; j++) {
							char[] parameterTypeName = ClassFileMatchLocator.convertClassFileFormat(parameterTypes[j]);
							if (!CharOperation.endsWith(Signature.toCharArray(Signature.getTypeErasure(parameterTypeName)), CharOperation.replaceOnCopy(argumentTypeNames[j], '$', '.')))
								continue nextMethod;
							parameterTypes[j] = parameterTypeName;
						}
					}
					return (IMethod) createMethodHandle(type, new String(selector), CharOperation.toStrings(parameterTypes));
				}
			}
		}
	}
	return null;
}
/*
 * Create method handle.
 * Store occurrences for create handle to retrieve possible duplicate ones.
 */
private IJavaElement createMethodHandle(IType type, String methodName, String[] parameterTypeSignatures) {
	IMethod methodHandle = type.getMethod(methodName, parameterTypeSignatures);
	if (methodHandle instanceof SourceMethod) {
		while (this.methodHandles.contains(methodHandle)) {
			((SourceMethod) methodHandle).occurrenceCount++;
		}
	}
	this.methodHandles.add(methodHandle);
	return methodHandle;
}
/**
 * Creates an IField from the given field declaration and type.
 */
protected IJavaElement createHandle(FieldDeclaration fieldDeclaration, TypeDeclaration typeDeclaration, IJavaElement parent) {
	if (!(parent instanceof IType)) return parent;
	IType type = (IType) parent;

	switch (fieldDeclaration.getKind()) {
		case AbstractVariableDeclaration.FIELD :
		case AbstractVariableDeclaration.ENUM_CONSTANT :
			return ((IType) parent).getField(new String(fieldDeclaration.name));
	}
	if (type.isBinary()) {
		// do not return initializer for binary types
		// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=98378
		return type;
	}
	// find occurrence count of the given initializer in its type declaration
	int occurrenceCount = 0;
	FieldDeclaration[] fields = typeDeclaration.fields;
	int length = fields == null ? 0 : fields.length;
	for (int i = 0; i < length; i++) {
		if (fields[i].getKind() == AbstractVariableDeclaration.INITIALIZER) {
			occurrenceCount++;
			if (fields[i].equals(fieldDeclaration)) break;
		}
	}
	return ((IType) parent).getInitializer(occurrenceCount);
}
/**
 * Create an handle for a local variable declaration (may be a local variable or type parameter).
 */
protected IJavaElement createHandle(AbstractVariableDeclaration variableDeclaration, IJavaElement parent) {
	boolean isParameter = true;
	switch (variableDeclaration.getKind()) {
		case AbstractVariableDeclaration.LOCAL_VARIABLE:
			isParameter = false;
			//$FALL-THROUGH$
		case AbstractVariableDeclaration.PARAMETER:
			if (variableDeclaration.type.resolvedType != null) {
				return new LocalVariable((JavaElement)parent,
					new String(variableDeclaration.name),
					variableDeclaration.declarationSourceStart,
					variableDeclaration.declarationSourceEnd,
					variableDeclaration.sourceStart,
					variableDeclaration.sourceEnd,
					new String(variableDeclaration.type.resolvedType.signature()),
					variableDeclaration.annotations,
					variableDeclaration.modifiers,
					isParameter,
					variableDeclaration.type.getAnnotationsOnDimensions()
				);
			}
			break;
		case AbstractVariableDeclaration.TYPE_PARAMETER:
			return new org.aspectj.org.eclipse.jdt.internal.core.TypeParameter((JavaElement)parent, new String(variableDeclaration.name));
	}
	return null;
}
/**
 * Create an handle for a local variable declaration (may be a local variable or type parameter).
 */
protected IJavaElement createHandle(Annotation annotation, IAnnotatable parent) {
	if (parent == null) return null;
	TypeReference typeRef = annotation.type;
	char[][] typeName = typeRef.getTypeName();
	String name = new String(typeName[typeName.length-1]);
	try {
		IAnnotation[] annotations = parent.getAnnotations();
		int length = annotations == null ? 0 : annotations.length;
		for (int i=0; i= ClassFileConstants.JDK1_5)
					return true;
			} else if (this.options.sourceLevel >= ClassFileConstants.JDK1_5) {
				return true;
			}
		}
	}
	return false;
}

/* (non-Javadoc)
 * Return info about last type argument of a parameterized type reference.
 * These info are made of concatenation of 2 int values which are respectively
 *  depth and end position of the last type argument.
 * For example, this method will return 0x300000020 for type ref List>>
 * if end position of type reference "String" equals 32.
 */
private long findLastTypeArgumentInfo(TypeReference typeRef) {
	// Get last list of type arguments for parameterized qualified type reference
	TypeReference lastTypeArgument = typeRef;
	int depth = 0;
	while (true) {
		TypeReference[] lastTypeArguments = null;
		if (lastTypeArgument instanceof ParameterizedQualifiedTypeReference) {
			ParameterizedQualifiedTypeReference pqtRef = (ParameterizedQualifiedTypeReference) lastTypeArgument;
			for (int i=pqtRef.typeArguments.length-1; i>=0 && lastTypeArguments==null; i--) {
				lastTypeArguments = pqtRef.typeArguments[i];
			}
		}
		// Get last type argument for single type reference of last list of argument of parameterized qualified type reference
		TypeReference last = null;
		if (lastTypeArgument instanceof ParameterizedSingleTypeReference || lastTypeArguments != null) {
			if (lastTypeArguments == null) {
				lastTypeArguments = ((ParameterizedSingleTypeReference)lastTypeArgument).typeArguments;
			}
			if (lastTypeArguments != null) {
				for (int i=lastTypeArguments.length-1; i>=0 && last==null; i++) {
					last = lastTypeArguments[i];
				}
			}
		}
		if (last == null) break;
		depth++;
		lastTypeArgument = last;
	}
	// Current type reference is not parameterized. So, it is the last type argument
	return (((long) depth) << 32) + lastTypeArgument.sourceEnd;
}
protected IBinaryType getBinaryInfo(ClassFile classFile, IResource resource) throws CoreException {
	BinaryType binaryType = (BinaryType) classFile.getType();
	if (classFile.isOpen())
		return (IBinaryType) binaryType.getElementInfo(); // reuse the info from the java model cache

	// create a temporary info
	IBinaryType info;
	try {
		PackageFragment pkg = (PackageFragment) classFile.getParent();
		PackageFragmentRoot root = (PackageFragmentRoot) pkg.getParent();
		if (root.isArchive()) {
			// class file in a jar
			String classFileName = classFile.getElementName();
			String classFilePath = Util.concatWith(pkg.names, classFileName, '/');
			ZipFile zipFile = null;
			try {
				zipFile = ((JarPackageFragmentRoot) root).getJar();
				info = ClassFileReader.read(zipFile, classFilePath);
			} finally {
				JavaModelManager.getJavaModelManager().closeZipFile(zipFile);
			}
		} else {
			// class file in a directory
			info = Util.newClassFileReader(resource);
		}
		if (info == null) throw binaryType.newNotPresentException();
		return info;
	} catch (ClassFormatException e) {
		//e.printStackTrace();
		return null;
	} catch (java.io.IOException e) {
		throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
	}
}
protected IType getFocusType() {
	return this.scope instanceof HierarchyScope ? ((HierarchyScope) this.scope).focusType : null;
}
protected void getMethodBodies(CompilationUnitDeclaration unit, MatchingNodeSet nodeSet) {
	if (unit.ignoreMethodBodies) {
		unit.ignoreFurtherInvestigation = true;
		return; // if initial diet parse did not work, no need to dig into method bodies.
	}

	// save existing values to restore them at the end of the parsing process
	// see bug 47079 for more details
	int[] oldLineEnds = this.parser.scanner.lineEnds;
	int oldLinePtr = this.parser.scanner.linePtr;

	try {
		CompilationResult compilationResult = unit.compilationResult;
		this.parser.scanner.setSource(compilationResult);

		if (this.parser.javadocParser.checkDocComment) {
			char[] contents = compilationResult.compilationUnit.getContents();
			this.parser.javadocParser.scanner.setSource(contents);
		}
		this.parser.nodeSet = nodeSet;
		this.parser.parseBodies(unit);
	} finally {
		this.parser.nodeSet = null;
		// this is done to prevent any side effects on the compilation unit result
		// line separator positions array.
		this.parser.scanner.lineEnds = oldLineEnds;
		this.parser.scanner.linePtr = oldLinePtr;
	}
}
protected TypeBinding getType(Object typeKey, char[] typeName) {
	if (this.unitScope == null || typeName == null || typeName.length == 0) return null;
	// Try to get binding from cache
	Binding binding = (Binding) this.bindings.get(typeKey);
	if (binding != null) {
		if (binding instanceof TypeBinding && binding.isValidBinding())
			return (TypeBinding) binding;
		return null;
	}
	// Get binding from unit scope
	char[][] compoundName = CharOperation.splitOn('.', typeName);
	TypeBinding typeBinding = this.unitScope.getType(compoundName, compoundName.length);
	if (typeBinding == null || !typeBinding.isValidBinding()) {
		typeBinding = this.lookupEnvironment.getType(compoundName);
	}
	this.bindings.put(typeKey, typeBinding);
	return typeBinding != null && typeBinding.isValidBinding() ? typeBinding : null;
}
public MethodBinding getMethodBinding(MethodPattern methodPattern) {
    MethodBinding methodBinding = getMethodBinding0(methodPattern);
    if (methodBinding != null)
    	return methodBinding; // known to be valid.
    // special handling for methods of anonymous/local types. Since these cannot be looked up in the environment the usual way ...
    if (methodPattern.focus instanceof SourceMethod) {
    	char[] typeName = PatternLocator.qualifiedPattern(methodPattern.declaringSimpleName, methodPattern.declaringQualification);
    	if (typeName != null && CharOperation.indexOf(IIndexConstants.ONE_STAR, typeName, true) >= 0) { // See org.aspectj.org.eclipse.jdt.core.search.SearchPattern.enclosingTypeNames(IType)
    		IType type = methodPattern.declaringType;
    		IType enclosingType = type.getDeclaringType();
    		while (enclosingType != null) {
    			type = enclosingType;
    			enclosingType = type.getDeclaringType();
    		}
    		typeName = type.getFullyQualifiedName().toCharArray();
    		TypeBinding declaringTypeBinding = getType(typeName, typeName);
    		if (declaringTypeBinding instanceof SourceTypeBinding) {
    			SourceTypeBinding sourceTypeBinding = ((SourceTypeBinding) declaringTypeBinding);
    			ClassScope skope = sourceTypeBinding.scope;
    			if (skope != null) {
    				CompilationUnitDeclaration unit = skope.referenceCompilationUnit();
    				if (unit != null) {
    					AbstractMethodDeclaration amd = new ASTNodeFinder(unit).findMethod((IMethod) methodPattern.focus);
    					if (amd != null && amd.binding != null && amd.binding.isValidBinding()) {
    						this.bindings.put(methodPattern, amd.binding);
    						return amd.binding;
    					}
    				}
    			}
    		}
    	}
    }
	return null;
}
private MethodBinding getMethodBinding0(MethodPattern methodPattern) {
	if (this.unitScope == null) return null;
	// Try to get binding from cache
	Binding binding = (Binding) this.bindings.get(methodPattern);
	if (binding != null) {
		if (binding instanceof MethodBinding && binding.isValidBinding())
			return (MethodBinding) binding;
		return null;
	}
	//	Get binding from unit scope
	char[] typeName = PatternLocator.qualifiedPattern(methodPattern.declaringSimpleName, methodPattern.declaringQualification);
	if (typeName == null) {
		if (methodPattern.declaringType == null) return null;
		typeName = methodPattern.declaringType.getFullyQualifiedName().toCharArray();
	}
	TypeBinding declaringTypeBinding = getType(typeName, typeName);
	if (declaringTypeBinding != null) {
		if (declaringTypeBinding.isArrayType()) {
			declaringTypeBinding = declaringTypeBinding.leafComponentType();
		}
		if (!declaringTypeBinding.isBaseType()) {
			char[][] parameterTypes = methodPattern.parameterSimpleNames;
			if (parameterTypes == null) return null;
			int paramTypeslength = parameterTypes.length;
			ReferenceBinding referenceBinding = (ReferenceBinding) declaringTypeBinding;
			MethodBinding[] methods = referenceBinding.getMethods(methodPattern.selector);
			int methodsLength = methods.length;
			TypeVariableBinding[] refTypeVariables = referenceBinding.typeVariables();
			int typeVarLength = refTypeVariables==null ? 0 : refTypeVariables.length;
			for (int i=0; i= ClassFileConstants.JDK1_5;
	boolean bindingsWereCreated = mustResolve;
	try {
		for (int i = start, maxUnits = start + length; i < maxUnits; i++) {
			PossibleMatch possibleMatch = possibleMatches[i];
			try {
				if (!parseAndBuildBindings(possibleMatch, mustResolvePattern)) continue;
				// Currently we only need to resolve over pattern flag if there's potential parameterized types
				if (this.patternLocator.mayBeGeneric) {
					// If pattern does not resolve then rely on possible match node set resolution
					// which may have been modified while locator was adding possible matches to it
					if (!mustResolvePattern && !mustResolve) {
						mustResolve = possibleMatch.nodeSet.mustResolve;
						bindingsWereCreated = mustResolve;
					}
				} else {
					// Reset matching node resolution with pattern one if there's no potential parameterized type
					// to minimize side effect on previous search behavior
					possibleMatch.nodeSet.mustResolve = mustResolvePattern;
				}
				// possible match node resolution has been merged with pattern one, so rely on it to know
				// whether we need to process compilation unit now or later
				if (!possibleMatch.nodeSet.mustResolve) {
					if (this.progressMonitor != null) {
						this.progressWorked++;
						if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
					}
					process(possibleMatch, bindingsWereCreated);
					if (this.numberOfMatches>0 && this.matchesToProcess[this.numberOfMatches-1] == possibleMatch) {
						// forget last possible match as it was processed
						this.numberOfMatches--;
					}
				}
			} finally {
				if (possibleMatch.hasSimilarMatch()) {
					// If there is similar match, then also process it
					// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=211872
					possibleMatches[i] = possibleMatch.getSimilarMatch();
					i--;
				}
				if (!possibleMatch.nodeSet.mustResolve)
					possibleMatch.cleanUp();
			}
		}
		if (mustResolve)
			this.lookupEnvironment.completeTypeBindings();

		// create hierarchy resolver if needed
		IType focusType = getFocusType();
		if (focusType == null) {
			this.hierarchyResolver = null;
		} else if (!createHierarchyResolver(focusType, possibleMatches)) {
			// focus type is not visible, use the super type names instead of the bindings
			if (computeSuperTypeNames(focusType) == null) return;
		}
	} catch (AbortCompilation e) {
		bindingsWereCreated = false;
	}

	if (!mustResolve) {
		return;
	}

	// possible match resolution
	for (int i = 0; i < this.numberOfMatches; i++) {
		if (this.progressMonitor != null && this.progressMonitor.isCanceled())
			throw new OperationCanceledException();
		PossibleMatch possibleMatch = this.matchesToProcess[i];
		this.matchesToProcess[i] = null; // release reference to processed possible match
		try {
			process(possibleMatch, bindingsWereCreated);
		} catch (AbortCompilation e) {
			// problem with class path: it could not find base classes
			// continue and try next matching openable reporting inaccurate matches (since bindings will be null)
			bindingsWereCreated = false;
		} catch (JavaModelException e) {
			// problem with class path: it could not find base classes
			// continue and try next matching openable reporting inaccurate matches (since bindings will be null)
			bindingsWereCreated = false;
		} finally {
			if (this.progressMonitor != null) {
				this.progressWorked++;
				if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
			}
			if (this.options.verbose)
				System.out.println(
					Messages.bind(Messages.compilation_done,
						new String[] {
							String.valueOf(i + 1),
							String.valueOf(this.numberOfMatches),
							new String(possibleMatch.parsedUnit.getFileName())
						}));
			// cleanup compilation unit result
			possibleMatch.cleanUp();
		}
	}
}
/**
 * Locate the matches amongst the possible matches.
 */
protected void locateMatches(JavaProject javaProject, PossibleMatchSet matchSet, int expected) throws CoreException {
	PossibleMatch[] possibleMatches = matchSet.getPossibleMatches(javaProject.getPackageFragmentRoots());
	int length = possibleMatches.length;
	// increase progress from duplicate matches not stored in matchSet while adding...
	if (this.progressMonitor != null && expected>length) {
		this.progressWorked += expected-length;
		this.progressMonitor.worked( expected-length);
	}
	// locate matches (processed matches are limited to avoid problem while using VM default memory heap size)
	for (int index = 0; index < length;) {
		int max = Math.min(MAX_AT_ONCE, length - index);
		locateMatches(javaProject, possibleMatches, index, max);
		index += max;
	}
	this.patternLocator.clear();
}
/**
 * Locate the matches in the given files and report them using the search requestor.
 */
public void locateMatches(SearchDocument[] searchDocuments) throws CoreException {
	if (this.patternLocator == null) return;
	int docsLength = searchDocuments.length;
	int progressLength = docsLength;
	if (BasicSearchEngine.VERBOSE) {
		System.out.println("Locating matches in documents ["); //$NON-NLS-1$
		for (int i = 0; i < docsLength; i++)
			System.out.println("\t" + searchDocuments[i]); //$NON-NLS-1$
		System.out.println("]"); //$NON-NLS-1$
	}
	IJavaProject[] javaModelProjects = null;
	if (this.searchPackageDeclaration) {
		javaModelProjects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects();
		progressLength += javaModelProjects.length;
	}

	// init infos for progress increasing
	int n = progressLength<1000 ? Math.min(Math.max(progressLength/200+1, 2),4) : 5 *(progressLength/1000);
	this.progressStep = progressLength < n ? 1 : progressLength / n; // step should not be 0
	this.progressWorked = 0;

	// extract working copies
	ArrayList copies = new ArrayList();
	for (int i = 0; i < docsLength; i++) {
		SearchDocument document = searchDocuments[i];
		if (document instanceof WorkingCopyDocument) {
			copies.add(((WorkingCopyDocument)document).workingCopy);
		}
	}
	int copiesLength = copies.size();
	this.workingCopies = new org.aspectj.org.eclipse.jdt.core.ICompilationUnit[copiesLength];
	copies.toArray(this.workingCopies);

	JavaModelManager manager = JavaModelManager.getJavaModelManager();
	this.bindings = new SimpleLookupTable();
	try {
		// optimize access to zip files during search operation
		manager.cacheZipFiles(this);

		// initialize handle factory (used as a cache of handles so as to optimize space)
		if (this.handleFactory == null)
			this.handleFactory = new HandleFactory();

		if (this.progressMonitor != null) {
			this.progressMonitor.beginTask("", searchDocuments.length); //$NON-NLS-1$
		}

		// initialize pattern for polymorphic search (i.e. method reference pattern)
		this.patternLocator.initializePolymorphicSearch(this);

		JavaProject previousJavaProject = null;
		PossibleMatchSet matchSet = new PossibleMatchSet();
		Util.sort(searchDocuments, new Util.Comparer() {
			public int compare(Object a, Object b) {
				return ((SearchDocument)a).getPath().compareTo(((SearchDocument)b).getPath());
			}
		});
		int displayed = 0; // progress worked displayed
		String previousPath = null;
		SearchParticipant searchParticipant = null;
		for (int i = 0; i < docsLength; i++) {
			if (this.progressMonitor != null && this.progressMonitor.isCanceled()) {
				throw new OperationCanceledException();
			}

			// skip duplicate paths
			SearchDocument searchDocument = searchDocuments[i];
			if (searchParticipant == null) {
				searchParticipant = searchDocument.getParticipant();
			}
			searchDocuments[i] = null; // free current document
			String pathString = searchDocument.getPath();
			if (i > 0 && pathString.equals(previousPath)) {
				if (this.progressMonitor != null) {
					this.progressWorked++;
					if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
				}
				displayed++;
				continue;
			}
			previousPath = pathString;

			Openable openable;
			org.aspectj.org.eclipse.jdt.core.ICompilationUnit workingCopy = null;
			if (searchDocument instanceof WorkingCopyDocument) {
				workingCopy = ((WorkingCopyDocument)searchDocument).workingCopy;
				openable = (Openable) workingCopy;
			} else {
				openable = this.handleFactory.createOpenable(pathString, this.scope);
			}
			if (openable == null) {
				if (this.progressMonitor != null) {
					this.progressWorked++;
					if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
				}
				displayed++;
				continue; // match is outside classpath
			}

			// create new parser and lookup environment if this is a new project
			IResource resource = null;
			JavaProject javaProject = (JavaProject) openable.getJavaProject();
			resource = workingCopy != null ? workingCopy.getResource() : openable.getResource();
			if (resource == null)
				resource = javaProject.getProject(); // case of a file in an external jar or external folder
			if (!javaProject.equals(previousJavaProject)) {
				// locate matches in previous project
				if (previousJavaProject != null) {
					try {
						locateMatches(previousJavaProject, matchSet, i-displayed);
						displayed = i;
					} catch (JavaModelException e) {
						// problem with classpath in this project -> skip it
					}
					matchSet.reset();
				}
				previousJavaProject = javaProject;
			}
			matchSet.add(new PossibleMatch(this, resource, openable, searchDocument,this.pattern.mustResolve));
		}

		// last project
		if (previousJavaProject != null) {
			try {
				locateMatches(previousJavaProject, matchSet, docsLength-displayed);
			} catch (JavaModelException e) {
				// problem with classpath in last project -> ignore
			}
		}

		if (this.searchPackageDeclaration) {
			locatePackageDeclarations(searchParticipant, javaModelProjects);
		}

	} finally {
		if (this.progressMonitor != null)
			this.progressMonitor.done();
		if (this.nameEnvironment != null)
			this.nameEnvironment.cleanup();
		this.unitScope = null;
		manager.flushZipFiles(this);
		this.bindings = null;
	}
}
/**
 * Locates the package declarations corresponding to this locator's pattern.
 */
protected void locatePackageDeclarations(SearchParticipant participant, IJavaProject[] projects) throws CoreException {
	locatePackageDeclarations(this.pattern, participant, projects);
}
/**
 * Locates the package declarations corresponding to the search pattern.
 */
protected void locatePackageDeclarations(SearchPattern searchPattern, SearchParticipant participant, IJavaProject[] projects) throws CoreException {
	if (this.progressMonitor != null && this.progressMonitor.isCanceled()) {
		throw new OperationCanceledException();
	}
	if (searchPattern instanceof OrPattern) {
		SearchPattern[] patterns = ((OrPattern) searchPattern).patterns;
		for (int i = 0, length = patterns.length; i < length; i++) {
			locatePackageDeclarations(patterns[i], participant, projects);
		}
	} else if (searchPattern instanceof PackageDeclarationPattern) {
		IJavaElement focus = searchPattern.focus;
		if (focus != null) {
			if (encloses(focus)) {
				SearchMatch match = new PackageDeclarationMatch(focus.getAncestor(IJavaElement.PACKAGE_FRAGMENT), SearchMatch.A_ACCURATE, -1, -1, participant, focus.getResource());
				report(match);
			}
			return;
		}
		PackageDeclarationPattern pkgPattern = (PackageDeclarationPattern) searchPattern;
		boolean isWorkspaceScope = this.scope == JavaModelManager.getJavaModelManager().getWorkspaceScope();
		IPath[] scopeProjectsAndJars =  isWorkspaceScope ? null : this.scope.enclosingProjectsAndJars();
		int scopeLength = isWorkspaceScope ? 0 : scopeProjectsAndJars.length;
		SimpleSet packages = new SimpleSet();
		for (int i = 0, length = projects.length; i < length; i++) {
			IJavaProject javaProject = projects[i];
			if (this.progressMonitor != null) {
				if (this.progressMonitor.isCanceled()) throw new OperationCanceledException();
				this.progressWorked++;
				if ((this.progressWorked%this.progressStep)==0) this.progressMonitor.worked(this.progressStep);
			}
			// Verify that project belongs to the scope
			if (!isWorkspaceScope) {
				boolean found = false;
				for (int j=0; j  build compilation unit declarations, their bindings and record their results.
 */
protected boolean parseAndBuildBindings(PossibleMatch possibleMatch, boolean mustResolve) throws CoreException {
	if (this.progressMonitor != null && this.progressMonitor.isCanceled())
		throw new OperationCanceledException();

	try {
		if (BasicSearchEngine.VERBOSE)
			System.out.println("Parsing " + possibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$

		this.parser.nodeSet = possibleMatch.nodeSet;
		CompilationResult unitResult = new CompilationResult(possibleMatch, 1, 1, this.options.maxProblemsPerUnit);
		CompilationUnitDeclaration parsedUnit = this.parser.dietParse(possibleMatch, unitResult);
		if (parsedUnit != null) {
			if (!parsedUnit.isEmpty()) {
				if (mustResolve) {
					this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
				}
				if (hasAlreadyDefinedType(parsedUnit)) return false; // skip type has it is hidden so not visible
				getMethodBodies(parsedUnit, possibleMatch.nodeSet);
				if (this.patternLocator.mayBeGeneric && !mustResolve && possibleMatch.nodeSet.mustResolve) {
					// special case: possible match node set force resolution although pattern does not
					// => we need to build types for this compilation unit
					this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
				}
			}

			// add the possibleMatch with its parsedUnit to matchesToProcess
			possibleMatch.parsedUnit = parsedUnit;
			int size = this.matchesToProcess.length;
			if (this.numberOfMatches == size)
				System.arraycopy(this.matchesToProcess, 0, this.matchesToProcess = new PossibleMatch[size == 0 ? 1 : size * 2], 0, this.numberOfMatches);
			this.matchesToProcess[this.numberOfMatches++] = possibleMatch;
		}
	} finally {
		this.parser.nodeSet = null;
	}
	return true;
}
/*
 * Process a compilation unit already parsed and build.
 */
protected void process(PossibleMatch possibleMatch, boolean bindingsWereCreated) throws CoreException {
	this.currentPossibleMatch = possibleMatch;
	CompilationUnitDeclaration unit = possibleMatch.parsedUnit;
	try {
		if (unit.isEmpty()) {
			if (this.currentPossibleMatch.openable instanceof ClassFile) {
				ClassFile classFile = (ClassFile) this.currentPossibleMatch.openable;
				IBinaryType info = null;
				try {
					info = getBinaryInfo(classFile, classFile.resource());
				}
				catch (CoreException ce) {
					// Do nothing
				}
				if (info != null) {
					boolean mayBeGeneric = this.patternLocator.mayBeGeneric;
					this.patternLocator.mayBeGeneric = false; // there's no longer generic in class files
					try {
						new ClassFileMatchLocator().locateMatches(this, classFile, info);
					}
					finally {
						this.patternLocator.mayBeGeneric = mayBeGeneric;
					}
				}
			}
			return;
		}
		if (hasAlreadyDefinedType(unit)) return; // skip type has it is hidden so not visible

		// Move getMethodBodies to #parseAndBuildings(...) method to allow possible match resolution management
		//getMethodBodies(unit);

		boolean mustResolve = (this.pattern.mustResolve || possibleMatch.nodeSet.mustResolve);
		if (bindingsWereCreated && mustResolve) {
			if (unit.types != null) {
				if (BasicSearchEngine.VERBOSE)
					System.out.println("Resolving " + this.currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$

				this.lookupEnvironment.unitBeingCompleted = unit;
				reduceParseTree(unit);

				if (unit.scope != null) {
					// fault in fields & methods
					unit.scope.faultInTypes();
				}
				unit.resolve();
			} else if (unit.isPackageInfo()) {
				if (BasicSearchEngine.VERBOSE)
					System.out.println("Resolving " + this.currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
				unit.resolve();
			}
		}
		reportMatching(unit, mustResolve);
	} catch (AbortCompilation e) {
		if (BasicSearchEngine.VERBOSE) {
			System.out.println("AbortCompilation while resolving unit " + String.valueOf(unit.getFileName())); //$NON-NLS-1$
			e.printStackTrace();
		}
		// could not resolve: report inaccurate matches
		reportMatching(unit, false); // do not resolve when cu has errors
		if (!(e instanceof AbortCompilationUnit)) {
			// problem with class path
			throw e;
		}
	} finally {
		this.lookupEnvironment.unitBeingCompleted = null;
		this.currentPossibleMatch = null;
	}
}
protected void purgeMethodStatements(TypeDeclaration type, boolean checkEachMethod) {
	checkEachMethod = checkEachMethod
		&& this.currentPossibleMatch.nodeSet.hasPossibleNodes(type.declarationSourceStart, type.declarationSourceEnd);
	AbstractMethodDeclaration[] methods = type.methods;
	if (methods != null) {
		if (checkEachMethod) {
			for (int j = 0, length = methods.length; j < length; j++) {
				AbstractMethodDeclaration method = methods[j];
				if (!this.currentPossibleMatch.nodeSet.hasPossibleNodes(method.declarationSourceStart, method.declarationSourceEnd)) {
					if (this.sourceStartOfMethodToRetain != method.declarationSourceStart || this.sourceEndOfMethodToRetain != method.declarationSourceEnd) { // approximate, but no big deal
						method.statements = null;
						method.javadoc = null;
					}
				}
			}
		} else {
			for (int j = 0, length = methods.length; j < length; j++) {
				AbstractMethodDeclaration method = methods[j];
				if (this.sourceStartOfMethodToRetain != method.declarationSourceStart || this.sourceEndOfMethodToRetain != method.declarationSourceEnd) { // approximate, but no big deal
					method.statements = null;
					method.javadoc = null;
				}
			}
		}
	}

	TypeDeclaration[] memberTypes = type.memberTypes;
	if (memberTypes != null)
		for (int i = 0, l = memberTypes.length; i < l; i++)
			purgeMethodStatements(memberTypes[i], checkEachMethod);
}
/**
 * Called prior to the unit being resolved. Reduce the parse tree where possible.
 */
protected void reduceParseTree(CompilationUnitDeclaration unit) {
	// remove statements from methods that have no possible matching nodes
	TypeDeclaration[] types = unit.types;
	for (int i = 0, l = types.length; i < l; i++)
		purgeMethodStatements(types[i], true);
}
public SearchParticipant getParticipant() {
	return this.currentPossibleMatch.document.getParticipant();
}

protected void report(SearchMatch match) throws CoreException {
	if (match == null) {
		if (BasicSearchEngine.VERBOSE) {
			System.out.println("Cannot report a null match!!!"); //$NON-NLS-1$
		}
		return;
	}
	if (filterEnum(match)){
		if (BasicSearchEngine.VERBOSE) {
			System.out.println("Filtered package with name enum"); //$NON-NLS-1$
		}
		return;
	}
	long start = -1;
	if (BasicSearchEngine.VERBOSE) {
		start = System.currentTimeMillis();
		System.out.println("Reporting match"); //$NON-NLS-1$
		System.out.println("\tResource: " + match.getResource());//$NON-NLS-1$
		System.out.println("\tPositions: [offset=" + match.getOffset() + ", length=" + match.getLength() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		try {
			if (this.parser != null && match.getOffset() > 0 && match.getLength() > 0 && !(match.getElement() instanceof BinaryMember)) {
				String selection = new String(this.parser.scanner.source, match.getOffset(), match.getLength());
				System.out.println("\tSelection: -->" + selection + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
			}
		} catch (Exception e) {
			// it's just for debug purposes... ignore all exceptions in this area
		}
		try {
			JavaElement javaElement = (JavaElement)match.getElement();
			System.out.println("\tJava element: "+ javaElement.toStringWithAncestors()); //$NON-NLS-1$
			if (!javaElement.exists()) {
				System.out.println("\t\tWARNING: this element does NOT exist!"); //$NON-NLS-1$
			}
		} catch (Exception e) {
			// it's just for debug purposes... ignore all exceptions in this area
		}
		if (match instanceof ReferenceMatch) {
			try {
				ReferenceMatch refMatch = (ReferenceMatch) match;
				JavaElement local = (JavaElement) refMatch.getLocalElement();
				if (local != null) {
					System.out.println("\tLocal element: "+ local.toStringWithAncestors()); //$NON-NLS-1$
				}
				if (match instanceof TypeReferenceMatch) {
					IJavaElement[] others = ((TypeReferenceMatch) refMatch).getOtherElements();
					if (others != null) {
						int length = others.length;
						if (length > 0) {
							System.out.println("\tOther elements:"); //$NON-NLS-1$
							for (int i=0; i') of last one.
	int start = match.getOffset();
	if (typeArguments != null && typeArguments.length > 0) {
		boolean isErasureMatch= (this.pattern instanceof OrPattern) ? ((OrPattern)this.pattern).isErasureMatch() : ((JavaSearchPattern)this.pattern).isErasureMatch();
		if (!isErasureMatch) {

			// Initialize scanner
			Scanner scanner = this.parser.scanner;
			char[] source = this.currentPossibleMatch.getContents();
			scanner.setSource(source);

			// Search previous opening '<'
			start = typeArguments[0].sourceStart;
			int end = statement.sourceEnd;
			scanner.resetTo(start, end);
			int lineStart = start;
			try {
				linesUp: while (true) {
					while (scanner.source[scanner.currentPosition] != '\n') {
						scanner.currentPosition--;
						if (scanner.currentPosition == 0) break linesUp;
					}
					lineStart = scanner.currentPosition+1;
					scanner.resetTo(lineStart, end);
					while (!scanner.atEnd()) {
						if (scanner.getNextToken() == TerminalTokens.TokenNameLESS) {
							start = scanner.getCurrentTokenStartPosition();
							break linesUp;
						}
					}
					end = lineStart - 2;
					scanner.currentPosition = end;
				}
			}
			catch (InvalidInputException ex) {
				// give up
			}
	 	}
	}

	// Report match
	match.setOffset(start);
	match.setLength(statement.sourceEnd-start+1);
	report(match);
}

/**
 * Finds the accurate positions of the sequence of tokens given by qualifiedName
 * in the source and reports a reference to this parameterized type name
 * to the search requestor.
 * @since 3.1
 */
protected void reportAccurateParameterizedTypeReference(SearchMatch match, TypeReference typeRef, int index, TypeReference[] typeArguments) throws CoreException {
	if (match.getRule() == 0) return;
	if (!encloses((IJavaElement)match.getElement())) return;

	// If there's type arguments, look for end (i.e. char '>') of last one.
	int end = typeRef.sourceEnd;
	if (typeArguments != null) {

		boolean shouldMatchErasure= (this.pattern instanceof OrPattern) ? ((OrPattern)this.pattern).isErasureMatch() : ((JavaSearchPattern)this.pattern).isErasureMatch();
		boolean hasSignatures = (this.pattern instanceof OrPattern) ? ((OrPattern)this.pattern).hasSignatures() : ((JavaSearchPattern)this.pattern).hasSignatures();
		if (shouldMatchErasure || !hasSignatures) {
			// if pattern is erasure only, then select the end of the reference
			if (typeRef instanceof QualifiedTypeReference && index >= 0) {
				long[] positions = ((QualifiedTypeReference) typeRef).sourcePositions;
				end = (int) positions[index];
			} else if (typeRef instanceof ArrayTypeReference) {
				end = ((ArrayTypeReference) typeRef).originalSourceEnd;
			}
		}  else {
			// Initialize scanner
			Scanner scanner = this.parser.scanner;
			char[] source = this.currentPossibleMatch.getContents();
			scanner.setSource(source);

			// Set scanner position at end of last type argument
			scanner.resetTo(end, source.length-1);
			int depth = 0;
			for (int i=typeArguments.length-1; i>=0; i--) {
				if (typeArguments[i] != null) {
					long lastTypeArgInfo = findLastTypeArgumentInfo(typeArguments[i]);
					depth = (int) (lastTypeArgInfo >>> 32)+1;
					scanner.resetTo(((int)lastTypeArgInfo)+1, scanner.eofPosition-1);
					break;
				}
			}

			// Now, scan to search next closing '>'
			while (depth-- > 0) {
				while (!scanner.atEnd()) {
					if (scanner.getNextChar() == '>') {
						end = scanner.currentPosition - 1;
						break;
					}
				}
			}
	 	}
	}

	// Report match
	match.setLength(end-match.getOffset()+1);
	report(match);
}
/**
 * Finds the accurate positions of each valid token in the source and
 * reports a reference to this token to the search requestor.
 * A token is valid if it has an accuracy which is not -1.
 */
protected void reportAccurateEnumConstructorReference(SearchMatch match, FieldDeclaration field, AllocationExpression allocation) throws CoreException {
	// Verify that field declaration is really an enum constant
	if (allocation == null || allocation.enumConstant == null) {
		report(match);
		return;
	}

	// Get scan area
	int sourceStart = match.getOffset()+match.getLength();
	if (allocation.arguments != null && allocation.arguments.length > 0) {
		sourceStart = allocation.arguments[allocation.arguments.length-1].sourceEnd+1;
	}
	int sourceEnd = field.declarationSourceEnd;
	if (allocation instanceof QualifiedAllocationExpression) {
		QualifiedAllocationExpression qualifiedAllocation = (QualifiedAllocationExpression) allocation;
		if (qualifiedAllocation.anonymousType != null) {
			sourceEnd = qualifiedAllocation.anonymousType.sourceStart - 1;
		}
	}

	// Scan to find last closing parenthesis
	Scanner scanner = this.parser.scanner;
	scanner.setSource(this.currentPossibleMatch.getContents());
	scanner.resetTo(sourceStart, sourceEnd);
	try {
		int token = scanner.getNextToken();
		while (token != TerminalTokens.TokenNameEOF) {
			if (token == TerminalTokens.TokenNameRPAREN) {
				sourceEnd = scanner.getCurrentTokenEndPosition();
			}
			token = scanner.getNextToken();
		}
	}
	catch (InvalidInputException iie) {
		// give up
	}

	// Report match
	match.setLength(sourceEnd-match.getOffset()+1);
	report(match);
}
/**
 * Finds the accurate positions of each valid token in the source and
 * reports a reference to this token to the search requestor.
 * A token is valid if it has an accuracy which is not -1.
 */
protected void reportAccurateFieldReference(SearchMatch[] matches, QualifiedNameReference qNameRef) throws CoreException {
	if (matches == null) return; // there's nothing to accurate in this case
	int matchesLength = matches.length;

	int sourceStart = qNameRef.sourceStart;
	int sourceEnd = qNameRef.sourceEnd;
	char[][] tokens = qNameRef.tokens;

	// compute source positions of the qualified reference
	Scanner scanner = this.parser.scanner;
	scanner.setSource(this.currentPossibleMatch.getContents());
	scanner.resetTo(sourceStart, sourceEnd);
	int sourceLength = sourceEnd-sourceStart+1;

	int refSourceStart = -1, refSourceEnd = -1;
	int length = tokens.length;
	int token = -1;
	int previousValid = -1;
	int i = 0;
	int index = 0;
	do {
		int currentPosition = scanner.currentPosition;
		// read token
		try {
			token = scanner.getNextToken();
		} catch (InvalidInputException e) {
			//ignore
		}
		if (token != TerminalTokens.TokenNameEOF) {
			char[] currentTokenSource = scanner.getCurrentTokenSource();
			boolean equals = false;
			while (i < length && !(equals = this.pattern.matchesName(tokens[i++], currentTokenSource))){/*empty*/}
			if (equals && (previousValid == -1 || previousValid == i - 2)) {
				previousValid = i - 1;
				if (refSourceStart == -1)
					refSourceStart = currentPosition;
				refSourceEnd = scanner.currentPosition - 1;
			} else {
				i = 0;
				refSourceStart = -1;
				previousValid = -1;
			}
			// read '.'
			try {
				token = scanner.getNextToken();
			} catch (InvalidInputException e) {
				// ignore
			}
		}
		SearchMatch match = matches[index];
		if (match != null && match.getRule() != 0) {
			if (!encloses((IJavaElement)match.getElement())) return;
			// accept reference
			if (refSourceStart != -1) {
				match.setOffset(refSourceStart);
				match.setLength(refSourceEnd-refSourceStart+1);
				report(match);
			} else {
				match.setOffset(sourceStart);
				match.setLength(sourceLength);
				report(match);
			}
			i = 0;
		}
		refSourceStart = -1;
		previousValid = -1;
		if (index < matchesLength - 1) {
			index++;
		}
	} while (token != TerminalTokens.TokenNameEOF);

}
protected void reportBinaryMemberDeclaration(IResource resource, IMember binaryMember, Binding binaryMemberBinding, IBinaryType info, int accuracy) throws CoreException {
	ClassFile classFile = (ClassFile) binaryMember.getClassFile();
	ISourceRange range = classFile.isOpen() ? binaryMember.getNameRange() : SourceMapper.UNKNOWN_RANGE;
	if (range.getOffset() == -1) {
		BinaryType type = (BinaryType) classFile.getType();
		String sourceFileName = type.sourceFileName(info);
		if (sourceFileName != null) {
			SourceMapper mapper = classFile.getSourceMapper();
			if (mapper != null) {
				char[] contents = mapper.findSource(type, sourceFileName);
				if (contents != null)
					range = mapper.mapSource(type, contents, info, binaryMember);
			}
		}
	}
	if (resource == null) resource =  this.currentPossibleMatch.resource;
	SearchMatch match = newDeclarationMatch(binaryMember, binaryMemberBinding, accuracy, range.getOffset(), range.getLength(), getParticipant(), resource);
	report(match);
}

protected void reportMatching(LambdaExpression lambdaExpression,  IJavaElement parent, int accuracy, MatchingNodeSet nodeSet, boolean typeInHierarchy) throws CoreException {
	IJavaElement enclosingElement = null;
	// Report the lambda declaration itself.
	if (accuracy > -1) {
		enclosingElement = createHandle(lambdaExpression, parent);
		if (enclosingElement != null) { // skip if unable to find method
			// compute source positions of the selector
			int nameSourceStart = lambdaExpression.sourceStart;
			if (encloses(enclosingElement)) {
				SearchMatch match = null;
				int length = lambdaExpression.arrowPosition() + 1 - nameSourceStart;
				match = this.patternLocator.newDeclarationMatch(lambdaExpression, enclosingElement, null, accuracy, length, this);
				if (match != null) {
					report(match);
				}
			}
		}
	}
	if (enclosingElement == null) {
		enclosingElement = createHandle(lambdaExpression, parent);
	}
	// Traverse the lambda declaration to report matches inside, these matches if any should see the present lambda as the parent model element.
	ASTNode[] nodes = typeInHierarchy ? nodeSet.matchingNodes(lambdaExpression.sourceStart, lambdaExpression.sourceEnd) : null;
	boolean report = (this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0 && encloses(enclosingElement);
	MemberDeclarationVisitor declarationVisitor = new MemberDeclarationVisitor(enclosingElement, report ? nodes : null, nodeSet, this, typeInHierarchy);
	
	if (lambdaExpression.arguments != null) {
		int argumentsLength = lambdaExpression.arguments.length;
		for (int i = 0; i < argumentsLength; i++)
			lambdaExpression.arguments[i].traverse(declarationVisitor, (BlockScope) null);
	}

	if (lambdaExpression.body != null) {
		lambdaExpression.body.traverse(declarationVisitor, (BlockScope) null);
	}
	
	// Report all nodes and remove them
	if (nodes != null) {
		int length = nodes.length;
		for (int i = 0; i < length; i++) {
			Integer level = (Integer) nodeSet.matchingNodes.removeKey(nodes[i]);
			if (report && level != null) {
				this.patternLocator.matchReportReference(nodes[i], enclosingElement, declarationVisitor.getLocalElement(i), declarationVisitor.getOtherElements(i), lambdaExpression.binding, level.intValue(), this);
			}
		}
	}
}
/**
 * Visit the given method declaration and report the nodes that match exactly the
 * search pattern (i.e. the ones in the matching nodes set)
 * Note that the method declaration has already been checked.
 */
protected void reportMatching(AbstractMethodDeclaration method, TypeDeclaration type, IJavaElement parent, int accuracy, boolean typeInHierarchy, MatchingNodeSet nodeSet) throws CoreException {
	IJavaElement enclosingElement = null;

	// report method declaration itself
	if (accuracy > -1) {
		enclosingElement = createHandle(method, parent);
		if (enclosingElement != null) { // skip if unable to find method
			// compute source positions of the selector
			Scanner scanner = this.parser.scanner;
			int nameSourceStart = method.sourceStart;
			scanner.setSource(this.currentPossibleMatch.getContents());
			scanner.resetTo(nameSourceStart, method.sourceEnd);
			try {
				scanner.getNextToken();
			} catch (InvalidInputException e) {
				// ignore
			}
			if (encloses(enclosingElement)) {
				SearchMatch match = null;
				if (method.isDefaultConstructor()) {
					// Use type for match associated element as default constructor does not exist in source
					int offset = type.sourceStart;
					match = this.patternLocator.newDeclarationMatch(type, parent, type.binding, accuracy, type.sourceEnd-offset+1, this);
				} else {
					int length = scanner.currentPosition - nameSourceStart;
					match = this.patternLocator.newDeclarationMatch(method, enclosingElement, method.binding, accuracy, length, this);
				}
				if (match != null) {
					report(match);
				}
			}
		}
	}

	// handle nodes for the local type first
	if ((method.bits & ASTNode.HasLocalType) != 0) {
		if (enclosingElement == null) {
			enclosingElement = createHandle(method, parent);
		}
		// Traverse method declaration to report matches both in local types declaration
		// and in local variables declaration
		ASTNode[] nodes = typeInHierarchy ? nodeSet.matchingNodes(method.declarationSourceStart, method.declarationSourceEnd) : null;
		boolean report = (this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0 && encloses(enclosingElement);
		MemberDeclarationVisitor declarationVisitor = new MemberDeclarationVisitor(enclosingElement, report ? nodes : null, nodeSet, this, typeInHierarchy);
		try {
			method.traverse(declarationVisitor, (ClassScope) null);
		} catch (WrappedCoreException e) {
			throw e.coreException;
		}
		// Report all nodes and remove them
		if (nodes != null) {
			int length = nodes.length;
			for (int i = 0; i < length; i++) {
				Integer level = (Integer) nodeSet.matchingNodes.removeKey(nodes[i]);
				if (report && level != null) {
	    	        this.patternLocator.matchReportReference(nodes[i], enclosingElement, declarationVisitor.getLocalElement(i), declarationVisitor.getOtherElements(i), method.binding, level.intValue(), this);
				}
			}
		}
	}

	// report the type parameters
	TypeParameter[] typeParameters = method.typeParameters();
	if (typeParameters != null) {
		if (enclosingElement == null) {
			enclosingElement = createHandle(method, parent);
		}
		if (enclosingElement != null) {
			reportMatching(typeParameters, enclosingElement, parent, method.binding, nodeSet);
		}
	}

	// report annotations
	if (method.annotations != null) {
		if (enclosingElement == null) {
			enclosingElement = createHandle(method, parent);
		}
		if (enclosingElement != null) {
			reportMatching(method.annotations, enclosingElement, null, method.binding, nodeSet, true, true);
		}
	}

	// references in this method
	if (typeInHierarchy) {
		ASTNode[] nodes = nodeSet.matchingNodes(method.declarationSourceStart, method.declarationSourceEnd);
		if (nodes != null) {
			if ((this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0) {
				if (enclosingElement == null) {
					enclosingElement = createHandle(method, parent);
				}
				if (encloses(enclosingElement)) {
					if (this.pattern.mustResolve) {
						// Visit only if the pattern must resolve
						MemberDeclarationVisitor declarationVisitor = new MemberDeclarationVisitor(enclosingElement, nodes, nodeSet, this, typeInHierarchy);
						method.traverse(declarationVisitor, (ClassScope) null);
						int length = nodes.length;
						for (int i = 0; i < length; i++) {
							Integer level = (Integer) nodeSet.matchingNodes.removeKey(nodes[i]);
							if (level != null) { // ensure that the reference has not been already reported while visiting
				    	        this.patternLocator.matchReportReference(nodes[i], enclosingElement, declarationVisitor.getLocalElement(i), declarationVisitor.getOtherElements(i), method.binding, level.intValue(), this);
							}
						}
					} else {
						for (int i = 0, l = nodes.length; i < l; i++) {
							ASTNode node = nodes[i];
							Integer level = (Integer) nodeSet.matchingNodes.removeKey(node);
							if (level != null) { // ensure that the reference has not been already reported while visiting
								this.patternLocator.matchReportReference(node, enclosingElement, null, null, method.binding, level.intValue(), this);
							}
						}
					}
					return;
				}
			}
			// Remove all remaining nodes
			for (int i = 0, l = nodes.length; i < l; i++) {
				nodeSet.matchingNodes.removeKey(nodes[i]);
			}
		}
	}
}
/**
 * Report matching in annotations.
 * @param otherElements TODO
 */
protected void reportMatching(Annotation[] annotations, IJavaElement enclosingElement, IJavaElement[] otherElements, Binding elementBinding, MatchingNodeSet nodeSet, boolean matchedContainer, boolean enclosesElement) throws CoreException {
	if (annotations == null)
		return;
	for (int i=0, al=annotations.length; i 0) {
				otherAnnotations = new IJavaElement[length];
				for (int o=0; o 0) {
						otherAnnotations = new IJavaElement[length];
						for (int o=0; o 0) {
								otherAnnotations = new IJavaElement[length];
								for (int o=0; o-->
            
    
            


© 2015 - 2024 Weber Informatics LLC | Privacy Policy