package org.eclipse.jdt.internal.core.search.matching; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.core.resources.*; | |
import org.eclipse.core.runtime.CoreException; | |
import org.eclipse.jdt.core.*; | |
import org.eclipse.jdt.core.search.IJavaSearchResultCollector; | |
import org.eclipse.jdt.internal.compiler.*; | |
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; | |
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; | |
import org.eclipse.jdt.internal.compiler.env.*; | |
import org.eclipse.jdt.internal.compiler.lookup.*; | |
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; | |
import org.eclipse.jdt.internal.compiler.util.CharOperation; | |
import org.eclipse.jdt.internal.core.*; | |
import java.io.*; | |
import java.util.zip.ZipFile; | |
public class PotentialMatch { | |
private MatchLocator locator; | |
public IResource resource; | |
public Openable openable; | |
private CompilationUnitDeclaration parsedUnit; | |
private MatchSet matchSet; | |
public PotentialMatch(MatchLocator locator, IResource resource, Openable openable) { | |
this.locator = locator; | |
this.resource = resource; | |
this.openable = openable; | |
if (openable instanceof CompilationUnit) { | |
this.buildTypeBindings(); | |
} | |
} | |
private void buildTypeBindings() { | |
// get main type name | |
String fileName = this.resource.getFullPath().lastSegment(); | |
// remove extension ".java" | |
final char[] mainTypeName = fileName.substring(0, fileName.length()-5).toCharArray(); | |
// get qualified name | |
CompilationUnit cu = (CompilationUnit)this.openable; | |
char[] qualifiedName = cu.getType(new String(mainTypeName)).getFullyQualifiedName().toCharArray(); | |
// create match set | |
this.matchSet = new MatchSet(this.locator); | |
this.locator.parser.matchSet = this.matchSet; | |
this.parsedUnit = (CompilationUnitDeclaration)this.locator.parsedUnits.get(qualifiedName); | |
if (this.parsedUnit == null) { | |
// get source | |
final char[] source = this.getSource(); | |
// source unit | |
ICompilationUnit sourceUnit = new ICompilationUnit() { | |
public char[] getContents() { | |
return source; | |
} | |
public char[] getFileName() { | |
return PotentialMatch.this.resource.getName().toCharArray(); | |
} | |
public char[] getMainTypeName() { | |
return mainTypeName; | |
} | |
}; | |
// diet parse | |
CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0); | |
this.parsedUnit = this.locator.parser.dietParse(sourceUnit, compilationResult); | |
// initial type binding creation | |
this.locator.lookupEnvironment.buildTypeBindings(this.parsedUnit); | |
} else { | |
// free memory | |
this.locator.parsedUnits.put(qualifiedName, null); | |
} | |
} | |
public static char[] getContents(IFile file) { | |
BufferedInputStream input = null; | |
try { | |
input = new BufferedInputStream(file.getContents(true)); | |
StringBuffer buffer= new StringBuffer(); | |
int nextChar = input.read(); | |
while (nextChar != -1) { | |
buffer.append( (char)nextChar ); | |
nextChar = input.read(); | |
} | |
int length = buffer.length(); | |
char[] result = new char[length]; | |
buffer.getChars(0, length, result, 0); | |
return result; | |
} catch (IOException e) { | |
return null; | |
} catch (CoreException e) { | |
return null; | |
} finally { | |
if (input != null) { | |
try { | |
input.close(); | |
} catch (IOException e) { | |
// nothing can be done if the file cannot be closed | |
} | |
} | |
} | |
} | |
public char[] getSource() { | |
return getContents((IFile)this.resource); | |
} | |
public void locateMatches() throws CoreException { | |
if (this.openable instanceof CompilationUnit) { | |
this.locateMatchesInCompilationUnit(); | |
} else if (this.openable instanceof org.eclipse.jdt.internal.core.ClassFile) { | |
this.locateMatchesInClassFile(); | |
} | |
} | |
/** | |
* Locate declaration in the current class file. This class file is always in a jar. | |
*/ | |
private void locateMatchesInClassFile() throws CoreException, JavaModelException { | |
org.eclipse.jdt.internal.core.ClassFile classFile = (org.eclipse.jdt.internal.core.ClassFile)this.openable; | |
BinaryType binaryType = (BinaryType)classFile.getType(); | |
IBinaryType info; | |
if (classFile.isOpen()) { | |
// reuse the info from the java model cache | |
info = (IBinaryType)binaryType.getRawInfo(); | |
} else { | |
// create a temporary info | |
try { | |
IJavaElement pkg = classFile.getParent(); | |
PackageFragmentRoot root = (PackageFragmentRoot)pkg.getParent(); | |
if (root.isArchive()) { | |
// class file in a jar | |
String pkgPath = pkg.getElementName().replace('.', '/'); | |
String classFilePath = | |
(pkgPath.length() > 0) ? | |
pkgPath + "/" + classFile.getElementName() : //$NON-NLS-1$ | |
classFile.getElementName(); | |
ZipFile zipFile = null; | |
try { | |
zipFile = ((JarPackageFragmentRoot)root).getJar(); | |
info = org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader.read( | |
zipFile, | |
classFilePath); | |
} finally { | |
if (zipFile != null) { | |
try { | |
zipFile.close(); | |
} catch (IOException e) { | |
// ignore | |
} | |
} | |
} | |
} else { | |
// class file in a directory | |
String osPath = this.resource.getFullPath().toOSString(); | |
info = org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader.read(osPath); | |
} | |
} catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException e) { | |
e.printStackTrace(); | |
return; | |
} catch (java.io.IOException e) { | |
throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION); | |
} | |
} | |
// check class definition | |
if (this.locator.pattern.matchesBinary(info, null)) { | |
this.locator.reportBinaryMatch(binaryType, info, IJavaSearchResultCollector.EXACT_MATCH); | |
} | |
boolean compilationAborted = false; | |
if (this.locator.pattern.needsResolve) { | |
// resolve | |
BinaryTypeBinding binding = null; | |
try { | |
binding = this.locator.lookupEnvironment.cacheBinaryType(info); | |
if (binding == null) { // it was already cached as a result of a previous query | |
char[][] compoundName = CharOperation.splitOn('.', binaryType.getFullyQualifiedName().toCharArray()); | |
ReferenceBinding referenceBinding = this.locator.lookupEnvironment.getCachedType(compoundName); | |
if (referenceBinding != null && (referenceBinding instanceof BinaryTypeBinding)) { | |
// if the binding could be found and if it comes from a source type, | |
binding = (BinaryTypeBinding)referenceBinding; | |
} | |
} | |
// check methods | |
if (binding != null) { | |
MethodBinding[] methods = binding.methods(); | |
for (int i = 0; i < methods.length; i++) { | |
MethodBinding method = methods[i]; | |
int level = this.locator.pattern.matchLevel(method); | |
if (level != SearchPattern.IMPOSSIBLE_MATCH) { | |
IMethod methodHandle = | |
binaryType.getMethod( | |
new String(method.isConstructor() ? binding.compoundName[binding.compoundName.length-1] : method.selector), | |
Signature.getParameterTypes(new String(method.signature()).replace('/', '.')) | |
); | |
this.locator.reportBinaryMatch( | |
methodHandle, | |
info, | |
level == SearchPattern.ACCURATE_MATCH ? | |
IJavaSearchResultCollector.EXACT_MATCH : | |
IJavaSearchResultCollector.POTENTIAL_MATCH); | |
} | |
} | |
} | |
// check fields | |
if (binding != null) { | |
FieldBinding[] fields = binding.fields(); | |
for (int i = 0; i < fields.length; i++) { | |
FieldBinding field = fields[i]; | |
int level = this.locator.pattern.matchLevel(field); | |
if (level != SearchPattern.IMPOSSIBLE_MATCH) { | |
IField fieldHandle = binaryType.getField(new String(field.name)); | |
this.locator.reportBinaryMatch( | |
fieldHandle, | |
info, | |
level == SearchPattern.ACCURATE_MATCH ? | |
IJavaSearchResultCollector.EXACT_MATCH : | |
IJavaSearchResultCollector.POTENTIAL_MATCH); | |
} | |
} | |
} | |
} catch (AbortCompilation e) { | |
binding = null; | |
} | |
// no need to check binary info if resolve was successful | |
compilationAborted = binding == null; | |
if (!compilationAborted) return; | |
} | |
// if compilation was aborted it is a problem with the class path: | |
// report as a potential match if binary info matches the pattern | |
int accuracy = compilationAborted ? IJavaSearchResultCollector.POTENTIAL_MATCH : IJavaSearchResultCollector.EXACT_MATCH; | |
// check methods | |
IBinaryMethod[] methods = info.getMethods(); | |
int length = methods == null ? 0 : methods.length; | |
for (int i = 0; i < length; i++) { | |
IBinaryMethod method = methods[i]; | |
if (this.locator.pattern.matchesBinary(method, info)) { | |
IMethod methodHandle = | |
binaryType.getMethod( | |
new String(method.isConstructor() ? info.getName() : method.getSelector()), | |
Signature.getParameterTypes(new String(method.getMethodDescriptor()).replace('/', '.')) | |
); | |
this.locator.reportBinaryMatch(methodHandle, info, accuracy); | |
} | |
} | |
// check fields | |
IBinaryField[] fields = info.getFields(); | |
length = fields == null ? 0 : fields.length; | |
for (int i = 0; i < length; i++) { | |
IBinaryField field = fields[i]; | |
if (this.locator.pattern.matchesBinary(field, info)) { | |
IField fieldHandle = binaryType.getField(new String(field.getName())); | |
this.locator.reportBinaryMatch(fieldHandle, info, accuracy); | |
} | |
} | |
} | |
private void locateMatchesInCompilationUnit() throws CoreException { | |
if (this.parsedUnit != null) { | |
this.locator.parser.matchSet = this.matchSet; | |
this.locator.parser.scanner.setSourceBuffer(this.getSource()); | |
this.locator.parser.parseBodies(this.parsedUnit); | |
// report matches that don't need resolve | |
this.matchSet.cuHasBeenResolved = false; | |
this.matchSet.accuracy = IJavaSearchResultCollector.EXACT_MATCH; | |
this.matchSet.reportMatching(parsedUnit); | |
// resolve if needed | |
if (this.matchSet.needsResolve()) { | |
if (this.parsedUnit.types != null) { | |
try { | |
if (this.parsedUnit.scope != null) { | |
this.parsedUnit.scope.faultInTypes(); | |
this.parsedUnit.resolve(); | |
} | |
// report matches that needed resolve | |
this.matchSet.cuHasBeenResolved = true; | |
this.matchSet.accuracy = IJavaSearchResultCollector.EXACT_MATCH; | |
this.matchSet.reportMatching(this.parsedUnit); | |
} catch (AbortCompilation e) { | |
// could not resolve (reasons include "could not find library class") -> ignore and report the unresolved nodes | |
this.matchSet.cuHasBeenResolved = false; | |
this.matchSet.accuracy = IJavaSearchResultCollector.POTENTIAL_MATCH; | |
this.matchSet.reportMatching(this.parsedUnit); | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Free memory. | |
*/ | |
public void reset() { | |
this.parsedUnit = null; | |
this.matchSet = null; | |
} | |
public String toString() { | |
return this.openable.toString(); | |
} | |
} |