blob: b9040e53ca52143de29312a4579042d9b3a5ef34 [file] [log] [blame]
package org.eclipse.jdt.internal.core.builder.impl;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.jdt.internal.compiler.env.*;
import org.eclipse.jdt.internal.core.Assert;
import org.eclipse.jdt.internal.core.builder.IType;
import org.eclipse.jdt.internal.core.lookup.ReferenceInfo;
import org.eclipse.jdt.internal.compiler.util.*;
import org.eclipse.jdt.internal.core.Util;
import java.util.Enumeration;
import java.util.Hashtable;
/**
* Represents a set of indictments that reside on a node
* in the dependency graph. The keys are strings of the form:
* "<indictment name>", values are indictment objects.
*/
public class IndictmentSet {
/* the tables of indictments */
protected HashtableOfObject fTypesTable;
protected HashtableOfObject fMethodsTable;
protected HashtableOfObject fFieldsTable;
protected IType[] fMethodOwnersArray;
protected Hashtable fAbstractMethodTable;
protected Hashtable fMethodOwners;
protected boolean fHasConstructorIndictments;
/* whether there is an upstream hierarchy change */
private boolean fHierarchyChange = false;
public void add(Indictment i) {
// allow null, since certain methods are not indicted (class initializers)
if (i != null) {
switch (i.getKind()) {
case Indictment.K_HIERARCHY:
fHierarchyChange = true;
break;
case Indictment.K_TYPE:
if (fTypesTable == null)
fTypesTable = new HashtableOfObject(11);
fTypesTable.put(i.getKey(), i);
break;
case Indictment.K_METHOD:
if (fMethodsTable == null)
fMethodsTable = new HashtableOfObject(11);
fMethodsTable.put(i.getKey(), i);
IType owner = ((MethodCollaboratorIndictment) i).getOwner();
if (fMethodOwners == null)
fMethodOwners = new Hashtable(11);
fMethodOwners.put(owner, owner);
fMethodOwnersArray = null;
if (i.getName().startsWith("<"/*nonNLS*/)) {
fHasConstructorIndictments = true;
}
break;
case Indictment.K_FIELD:
if (fFieldsTable == null)
fFieldsTable = new HashtableOfObject(11);
fFieldsTable.put(i.getKey(), i);
break;
case Indictment.K_ABSTRACT_METHOD:
if (fAbstractMethodTable == null)
fAbstractMethodTable = new Hashtable(11);
fAbstractMethodTable.put(i.getKey(), i);
break;
default:
Assert.isTrue(false, "Internal Error - Unexpected kind of indictment"/*nonNLS*/);
break;
}
}
}
/**
* Maximum conservatism. Convict all dependents.
*/
public void convictAll() {
// TBD: Should have separate flag for this.
fHierarchyChange = true;
}
/**
* Returns the originators of all abstract method indictments.
* If any of these returned types are direct supertypes of the
* type on trial, it is found guilty.
*/
public IType[] getAbstractMethodOriginators() {
if (fAbstractMethodTable == null) {
return new IType[0];
}
int length = fAbstractMethodTable.size();
if (length == 0) {
return new IType[0];
}
IType[] toReturn = new IType[length];
int i = 0;
for (Enumeration e = fAbstractMethodTable.elements(); e.hasMoreElements(); i++) {
toReturn[i] = ((AbstractMethodCollaboratorIndictment) e.nextElement()).getType();
}
return toReturn;
}
/**
* Returns the types for which method indictments were issued.
*/
public IType[] getMethodIndictmentOwners() {
if (fMethodOwnersArray == null) {
if (fMethodsTable == null) {
fMethodOwnersArray = new IType[0];
}
else {
fMethodOwnersArray = new IType[fMethodOwners.size()];
int count = 0;
for (Enumeration e = fMethodOwners.elements(); e.hasMoreElements();) {
fMethodOwnersArray[count++] = (IType) e.nextElement();
}
}
}
return fMethodOwnersArray;
}
/**
* Returns true if there are any constructor indictments, false otherwise.
*/
public boolean hasConstructorIndictments() {
return fHasConstructorIndictments;
}
/**
* Returns true if there is a type hierarchy indictment, false otherwise.
*/
public boolean hasHierarchyIndictment() {
return fHierarchyChange;
}
/**
* Returns true if the indictment set has no indictments, false otherwise.
*/
public boolean isEmpty() {
return
fMethodsTable == null
&& fFieldsTable == null
&& fTypesTable == null
&& fAbstractMethodTable == null
&& !fHierarchyChange;
}
/**
* Resets the contents of the indictment set. Allows re-use of objects
* and saves on garbage.
*/
public void reset() {
fMethodsTable = null;
fFieldsTable = null;
fTypesTable = null;
fAbstractMethodTable = null;
fHierarchyChange = false;
}
/**
* Returns a string representation of the instance.
*/
public String toString() {
return
"IndictmentSet("/*nonNLS*/
+ "\n hierarchyChange: "/*nonNLS*/ + fHierarchyChange
+ "\n types:\n"/*nonNLS*/ + fTypesTable
+ "\n interfaces:\n"/*nonNLS*/ + fAbstractMethodTable
+ "\n methods:\n"/*nonNLS*/ + fMethodsTable
+ "\n fields:\n"/*nonNLS*/ + fFieldsTable
+ "\n)"/*nonNLS*/;
}
/**
* Tries all the evidence in the given set of references against the indictments.
* Returns true if any evidence matches an indictment, and false otherwise.
*/
public boolean tryAllEvidence(ReferenceInfo references) {
char[][] names = references.getNames();
byte[] kinds = references.getKinds();
int numRefs = names.length;
/* try all references */
for (int i = 0; i < numRefs; i++) {
switch (kinds[i]) {
case ReferenceInfo.REFTYPE_unknown:
case ReferenceInfo.REFTYPE_class:
case ReferenceInfo.REFTYPE_type:
/* try type indictments */
if (fTypesTable != null && fTypesTable.containsKey(names[i])) {
return true;
}
if (kinds[i] != ReferenceInfo.REFTYPE_unknown)
break;
case ReferenceInfo.REFTYPE_var:
/* try field indictments */
if (fFieldsTable != null && fFieldsTable.containsKey(names[i])) {
return true;
}
if (kinds[i] != ReferenceInfo.REFTYPE_unknown)
break;
case ReferenceInfo.REFTYPE_call:
/* try method indictments */
if (fMethodsTable != null && fMethodsTable.containsKey(names[i])) {
return true;
}
if (kinds[i] != ReferenceInfo.REFTYPE_unknown)
break;
}
}
return false;
}
/**
* Tries an ambiguous name against the set of available indictments. Returns
* true if there is a match (guilty), and false if there is no match (not
* guilty).
*/
public boolean tryAmbiguousEvidence(char[] name) {
if (fFieldsTable == null && fTypesTable == null) {
return false;
}
// Try all segments of name
int i = 0;
int j = CharOperation.indexOf('.', name);
while (j >= 0) {
char[] segment = CharOperation.subarray(name, i, j);
if (tryFieldEvidence(segment) || tryTypeEvidence(segment)) {
return true;
}
i = j + 1;
j = CharOperation.indexOf('.', name, i);
}
char[] segment = CharOperation.subarray(name, i, name.length-1);
return tryFieldEvidence(segment) || tryTypeEvidence(segment);
}
/**
* Tries a field name against the set of available indictments. Returns
* true if there is a match (guilty), and false if there is no match (not
* guilty).
*/
public boolean tryFieldEvidence(char[] name) {
return fFieldsTable != null && fFieldsTable.containsKey(name);
}
/**
* Tries a method declaration against the set of available indictments.
* Returns true if there is a match (guilty), and false if there is no match
* (not guilty).
*/
public boolean tryMethodDeclaration(IBinaryMethod method) {
if (fMethodsTable != null) {
char[] key = Indictment.getMethodIndictmentKey(method.getSelector(), Util.getParameterCount(method.getMethodDescriptor()));
if (fMethodsTable.get(key) != null) {
return true;
}
}
return false;
}
/**
* Tries a method name against the set of available indictments. Returns
* true if there is a match (guilty), and false if there is no match (not
* guilty).
* @parm name String of form:
* constructor: "<" + NameOfType + ">/" + NumberOfParameters
* method: NameOfMethod + "/" + NumberOfParameters
*/
public boolean tryMethodEvidence(char[] name) {
return fMethodsTable != null && fMethodsTable.containsKey(name);
}
/**
* Tries a type name against the set of available indictments. Returns
* true if there is a match (guilty), and false if there is no match (not
* guilty).
*/
public boolean tryTypeEvidence(char[] name) {
if (fTypesTable != null) {
if (fTypesTable.containsKey(name)) {
return true;
}
/* it may be a qualified name */
int lastDot = CharOperation.lastIndexOf('.', name);
if (lastDot != -1) {
char[] key = CharOperation.subarray(name, lastDot+1, name.length-1);
if (fTypesTable.containsKey(key)) {
return true;
}
}
}
return false;
}
}