sp-05/src/ch/usi/inf/sp/callgraph/ClassType.java

211 lines
5.5 KiB
Java

package ch.usi.inf.sp.callgraph;
import java.util.ArrayList;
import java.util.Collection;
import org.objectweb.asm.Opcodes;
/**
* A ClassType represents a class or an interface.
*
* @author Matthias.Hauswirth@usi.ch
*/
public final class ClassType implements Type {
private final String internalName;
private boolean resolved;
private String location;
private int modifiers;
private ClassType superClass;
private ArrayList<ClassType> interfaces;
private ArrayList<Method> methods;
private ArrayList<ClassType> subTypes;
/**
* Create a ClassType given an internal name (without "L" prefix or ";" suffix).
* @param internalName the internal name of the class,
* e.g. "java/lang/Object" (class Object in package java.lang)
* or "java/awt/geom/Point2D$Double" (class Double in class Point2D in package java.awt.geom)
* or "TypeInDefaultPackage" (class TypeInDefaultPackage in the default package).
*/
public ClassType(final String internalName) {
this.internalName = internalName;
this.interfaces = new ArrayList<ClassType>();
this.methods = new ArrayList<Method>();
this.subTypes = new ArrayList<ClassType>();
}
public String getInternalName() {
return internalName;
}
/**
* Returns the simple name of the underlying class as given in the source code.
* Returns an empty string if the underlying class is anonymous.
* The simple name of an array is the simple name of the component type with "[]" appended.
* In particular the simple name of an array whose component type is anonymous is "[]".
*/
public String getSimpleName() {
final int dollar = internalName.lastIndexOf('$');
if (dollar>-1) {
final String n = internalName.substring(dollar);
if (n.matches("[0-9]+")) {
// anonymous inner classes have numbers as their names
return "";
} else {
// inner/nested class
return n;
}
} else {
final int slash = internalName.lastIndexOf('/');
if (slash>-1) {
// class in package
return internalName.substring(slash).replace('/', '.');
} else {
// class in default package
return internalName;
}
}
}
/**
* Do this after you have completed reading this class
* (classes that were never read, but referenced by other classes, will appear as not resolved)
*/
public void setResolved() {
resolved = true;
}
public boolean isResolved() {
return resolved;
}
/**
* Set the location (e.g. the name of the JAR file) this class was loaded from
* when you read in the class.
* @param location
*/
public void setLocation(final String location) {
this.location = location;
}
/**
* Get the location (e.g. the name of the JAR file) this class was loaded from.
* @return
*/
public String getLocation() {
return location;
}
/**
* Set this class (or interface's) super class
* when you read in the class.
* @param superClass
*/
public void setSuperClass(final ClassType superClass) {
this.superClass = superClass;
// automatically maintain subtypes
superClass.subTypes.add(this);
}
/**
* Get this class (or interface's) super class.
*/
public ClassType getSuperClass() {
return superClass;
}
/**
* Add interfa to the list of this class (or interface's) interfaces
* when you read in the class.
* @param interfa The interface implemented by this class, resp. extended by this interface.
*/
public void addInterface(final ClassType interfa) {
interfaces.add(interfa);
// automatically maintain subtypes
interfa.subTypes.add(this);
}
/**
* Get all the interfaces implemented by this class resp. extended by this interface.
*/
public Collection<ClassType> getInterfaces() {
return interfaces;
}
/**
* Get all the currently known subtypes (interfaces and/or classes) of this interface or class.
*/
public Collection<ClassType> getSubTypes() {
return subTypes;
}
/**
* Add a method to this class
* when you read in the clas.
* The class should contain all the methods it explicitly declares
* (including abstract methods).
*/
public void addMethod(final Method method) {
methods.add(method);
}
/**
* Get all the methods this class declares.
*/
public Collection<Method> getMethods() {
return methods;
}
/**
* Get the method with the given name and descriptor, if such a method is declared in this class.
* @param name e.g. "<init>" or "main"
* @param descriptor E.g. "()V" or "([Ljava/lang/String;)V"
* @return the Method or null
*/
public Method getMethod(final String name, final String descriptor) {
for (final Method method : methods) {
if (method.getName().equals(name) && method.getDescriptor().equals(descriptor)) {
return method;
}
}
// no such method declared in this class
// (one still could be declared in a superclass or interface!)
return null;
}
/**
* Set the modifiers when you read in the class.
* @param modifiers Modifiers coming from ASM's ClassNode.access
*/
public void setModifiers(final int modifiers) {
this.modifiers = modifiers;
}
public int getModifiers() {
return modifiers;
}
public boolean isInterface() {
return (modifiers & Opcodes.ACC_INTERFACE) != 0;
}
public boolean isAbstract() {
return (modifiers & Opcodes.ACC_ABSTRACT) != 0;
}
public boolean isFinal() {
return (modifiers & Opcodes.ACC_FINAL) != 0;
}
public boolean isEnum() {
return (modifiers & Opcodes.ACC_ENUM) != 0;
}
public String toString() {
return (isInterface()?"interface ":(isEnum()?"enum ":"class "))+getInternalName();
}
}