blob: f78427a48c671f563ab006dd090527e90bcddd45 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.IJavaSearchResultCollector;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.env.*;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.jdt.internal.core.*;
public class PotentialMatch implements ICompilationUnit {
public static final String NO_SOURCE_FILE_NAME = "NO SOURCE FILE NAME"; //$NON-NLS-1$
private MatchLocator2 locator;
public IResource resource;
public Openable openable;
public char[][] compoundName;
MatchingNodeSet matchingNodeSet;
private String sourceFileName;
public PotentialMatch(
MatchLocator2 locator,
IResource resource,
Openable openable) {
this.locator = locator;
this.resource = resource;
this.openable = openable;
this.matchingNodeSet = new MatchingNodeSet(locator);
char[] qualifiedName = getQualifiedName();
if (qualifiedName != null) {
this.compoundName = CharOperation.splitOn('.', qualifiedName);
}
}
public boolean equals(Object obj) {
if (this.compoundName == null) return super.equals(obj);
if (!(obj instanceof PotentialMatch)) return false;
return CharOperation.equals(this.compoundName, ((PotentialMatch)obj).compoundName);
}
/*
* Finds the source of this class file.
* Returns null if not found.
*/
private char[] findClassFileSource() {
String sourceFileName = getSourceFileName();
if (sourceFileName == NO_SOURCE_FILE_NAME) return null;
char[] source = null;
try {
SourceMapper sourceMapper = this.openable.getSourceMapper();
if (sourceMapper != null) {
IType type = ((ClassFile)this.openable).getType();
source = sourceMapper.findSource(type, sourceFileName);
}
} catch (JavaModelException e) {
}
return source;
}
/*
* Returns the source file name of the class file.
* Returns NO_SOURCE_FILE_NAME if not found.
*/
private String getSourceFileName() {
if (this.sourceFileName != null) return this.sourceFileName;
this.sourceFileName = NO_SOURCE_FILE_NAME;
try {
SourceMapper sourceMapper = this.openable.getSourceMapper();
if (sourceMapper != null) {
IType type = ((ClassFile)this.openable).getType();
ClassFileReader reader = this.locator.classFileReader(type);
if (reader != null) {
this.sourceFileName = sourceMapper.findSourceFileName(type, reader);
}
}
} catch (JavaModelException e) {
}
return this.sourceFileName;
}
public char[] getContents() {
char[] source = null;
try {
if (this.openable instanceof WorkingCopy) {
IBuffer buffer = this.openable.getBuffer();
if (buffer == null) return null;
source = buffer.getCharacters();
} else if (this.openable instanceof CompilationUnit) {
source = Util.getResourceContentsAsCharArray((IFile)this.resource);
} else if (this.openable instanceof ClassFile) {
source = findClassFileSource();
}
} catch (JavaModelException e) {
}
if (source == null) return CharOperation.NO_CHAR;
return source;
}
/*
* Returns the fully qualified name of the main type of the compilation unit
* or the main type of the .java file that defined the class file.
*/
private char[] getQualifiedName() {
if (this.openable instanceof CompilationUnit) {
// get file name
String fileName = this.resource.getFullPath().lastSegment();
// get main type name
char[] mainTypeName = fileName.substring(0, fileName.length()-5).toCharArray();
CompilationUnit cu = (CompilationUnit)this.openable;
return cu.getType(new String(mainTypeName)).getFullyQualifiedName().toCharArray();
} else if (this.openable instanceof ClassFile) {
String sourceFileName = getSourceFileName();
if (sourceFileName == NO_SOURCE_FILE_NAME) {
try {
return ((ClassFile)this.openable).getType().getFullyQualifiedName('.').toCharArray();
} catch (JavaModelException e) {
return null;
}
}
String simpleName = sourceFileName.substring(0, sourceFileName.length()-5); // length-".java".length()
String pkgName = this.openable.getParent().getElementName();
if (pkgName.length() == 0) {
return simpleName.toCharArray();
} else {
return (pkgName + '.' + simpleName).toCharArray();
}
} else {
return null;
}
}
public int hashCode() {
if (this.compoundName == null) return super.hashCode();
int hashCode = 0;
for (int i = 0, length = this.compoundName.length; i < length; i++) {
hashCode += CharOperation.hashCode(this.compoundName[i]);
}
return hashCode;
}
public char[] getMainTypeName() {
return null; // cannot know the main type name without opening .java or .class file
// see http://bugs.eclipse.org/bugs/show_bug.cgi?id=32182
}
public char[][] getPackageName() {
int length;
if ((length = this.compoundName.length) > 1) {
return CharOperation.subarray(this.compoundName, 0, length-1);
} else {
return CharOperation.NO_CHAR_CHAR;
}
}
/**
* Locate declaration in the current class file. This class file is always in a jar.
*/
public void locateMatchesInClassFile() throws CoreException {
org.eclipse.jdt.internal.core.ClassFile classFile = (org.eclipse.jdt.internal.core.ClassFile)this.openable;
IBinaryType info = this.locator.getBinaryInfo(classFile, this.resource);
if (info == null)
return; // unable to go further
// check class definition
BinaryType binaryType = (BinaryType)classFile.getType();
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.cacheBinaryType(binaryType);
if (binding != null) {
// filter out element not in hierarchy scope
if (this.locator.hierarchyResolver != null
&& !this.locator.hierarchyResolver.subOrSuperOfFocus(binding)) {
return;
}
// check methods
MethodBinding[] methods = binding.methods();
for (int i = 0; i < methods.length; i++) {
MethodBinding method = methods[i];
int level = this.locator.pattern.matchLevel(method);
switch (level) {
case SearchPattern.IMPOSSIBLE_MATCH:
case SearchPattern.INACCURATE_MATCH:
break;
default:
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
FieldBinding[] fields = binding.fields();
for (int i = 0; i < fields.length; i++) {
FieldBinding field = fields[i];
int level = this.locator.pattern.matchLevel(field);
switch (level) {
case SearchPattern.IMPOSSIBLE_MATCH:
case SearchPattern.INACCURATE_MATCH:
break;
default:
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);
}
}
}
public String toString() {
return this.openable == null ? "Fake PotentialMatch" : this.openable.toString(); //$NON-NLS-1$
}
public char[] getFileName() {
return this.openable.getPath().toString().toCharArray();
}
}