use of com.jopdesign.common.graphutils.ClassHierarchyTraverser in project jop by jop-devel.
the class AppInfo method removeClasses.
/**
* Remove a collection of classes and all their nested classes from AppInfo, and update the class hierarchy.
*
* @param classes the classes to remove. Duplicates in this collection will be removed first.
*/
public void removeClasses(Collection<ClassInfo> classes) {
// first, collect all nested classes and remove duplicates.
final Map<String, ClassInfo> map = new LinkedHashMap<String, ClassInfo>(classes.size());
for (ClassInfo classInfo : classes) {
ClassVisitor v = new ClassVisitor() {
@Override
public boolean visitClass(ClassInfo classInfo) {
// we put the visited (nested) class in the map, and descend if it is not already there
return map.put(classInfo.getClassName(), classInfo) == null;
}
@Override
public void finishClass(ClassInfo classInfo) {
}
};
ClassHierarchyTraverser cht = new ClassHierarchyTraverser(v);
cht.setVisitSubclasses(false, false);
cht.setVisitInnerClasses(true);
cht.traverseDown(classInfo);
}
// now we go through all classes and remove them from the class-list and from the class hierarchy
for (ClassInfo classInfo : classes) {
for (AppEventHandler mgr : eventHandlers) {
mgr.onRemoveClass(classInfo);
}
this.classes.remove(classInfo.getClassName());
classInfo.removeFromClassHierarchy();
}
// finally go through all classes once more to update the FullyKnown-flags
for (ClassInfo classInfo : classes) {
// since we already removed the classes from the class hierarchy, this won't descend down
// classes we are removing
classInfo.finishRemoveFromHierarchy();
classInfo.resetHierarchyInfos();
}
}
use of com.jopdesign.common.graphutils.ClassHierarchyTraverser in project jop by jop-devel.
the class AppInfo method findImplementations.
/**
* Find all methods which might get invoked for a given methodRef.
* This does not use the callgraph to eliminate methods. If you want a more precise result,
* use {@link #findImplementations(InvokeSite, CallString)} and use callgraph thinning first.
* <p>
* Note that this method is slightly different from {@link MethodInfo#getImplementations(boolean)}, since
* it returns only methods for subclasses of the invokee class, not of the implementing class.
* </p>
* <p>To handle invocations of super-methods correctly, use {@link #findImplementations(InvokeSite)}
* instead.</p>
*
* @see #findImplementations(InvokeSite)
* @see MethodInfo#overrides(MethodRef, boolean)
* @param invokee the method to resolve.
* @return all possible implementations, including native methods.
*/
public Set<MethodInfo> findImplementations(final MethodRef invokee) {
final Set<MethodInfo> methods = new LinkedHashSet<MethodInfo>();
// 'method' may refer to an inherited MethodInfo or to an interface method if there is no implementation
final MethodInfo method = invokee.getMethodInfo();
if (method != null && (method.isStatic() || method.isPrivate())) {
methods.add(method);
return methods;
}
final String methodSig = invokee.getMethodSignature();
final ClassInfo invokeeClass = invokee.getClassRef().getClassInfo();
if (invokeeClass == null) {
// ok, now, if the target class is unknown, there is not much we can do, so return an empty set
logger.debug("Trying to find implementations of a method in an unknown class " + invokee.toString());
return methods;
}
// Constructors are only called by invokespecial
if ("<init>".equals(invokee.getName())) {
MethodInfo init = invokee.getMethodInfo();
if (init == null) {
throw new JavaClassFormatError("Constructor not found: " + invokee);
}
if (init.isAbstract()) {
throw new JavaClassFormatError("Found abstract constructor, this isn't right..: " + invokee);
}
methods.add(init);
return methods;
}
boolean undefinedBaseMethod = false;
// check if method is defined in the referenced class or in a superclass
if (invokeeClass.getMethodInfo(methodSig) == null) {
// method is inherited, add to implementations
if (method != null && !method.isAbstract()) {
methods.add(method);
} else if (method == null) {
// hm, invoke to an unknown method (maybe excluded or native), what should we do?
if (invokeeClass.isFullyKnown(true)) {
// .. or maybe the method has not been loaded somehow when the MethodRef was created (check!)
throw new JavaClassFormatError("Method implementation not found in superclass: " + invokee.toString());
} else {
// maybe defined in excluded superclass, but we do not know for sure..
// We *must* return an empty set, but lets try to continue for now and
// handle it like an excluded class, and abort only if we find overriding methods
logger.debug("Method implementation not found in incomplete superclass: " + invokee.toString());
undefinedBaseMethod = true;
}
}
}
// now, we have a virtual call on our hands ..
ClassVisitor visitor = new ClassVisitor() {
public boolean visitClass(ClassInfo classInfo) {
// Note: we also handle interface classes here, because they can contain <clinit> methods
MethodInfo m;
if (invokeeClass.isInterface() && !classInfo.isInterface()) {
// If we invoke an interface method, we also need to find inherited methods in implementing
// classes
m = classInfo.getMethodInfoInherited(methodSig, true);
} else {
// If we do not invoke an interface method, 'method' is already the only possible inherited
// method; If the visited class is an interface, it does not inherit implementations.
m = classInfo.getMethodInfo(methodSig);
}
if (m != null) {
if (m.isPrivate() && !classInfo.equals(invokeeClass)) {
// found an overriding method which is private .. this is interesting..
logger.error("Found private method " + m.getMethodSignature() + " in " + classInfo.getClassName() + " overriding non-private method in " + invokee.getClassName());
}
if (!m.isAbstract() && (method == null || m.overrides(method, false))) {
methods.add(m);
}
}
return true;
}
public void finishClass(ClassInfo classInfo) {
}
};
ClassHierarchyTraverser traverser = new ClassHierarchyTraverser(visitor);
traverser.setVisitSubclasses(true, true);
traverser.traverseDown(invokeeClass);
if (undefinedBaseMethod && methods.size() > 0) {
// overriding methods, this we cannot handle for now
throw new JavaClassFormatError("Found overriding methods for " + invokee + " but superclasses are undefined!");
}
return methods;
}
use of com.jopdesign.common.graphutils.ClassHierarchyTraverser in project jop by jop-devel.
the class InlineHelper method makePublic.
private void makePublic(ClassMemberInfo member) {
boolean wasPrivate = member.isPrivate();
// If we need to make it public, check if we need to make the class and all enclosing classes public too
ClassInfo cls = member.getClassInfo();
while (cls != null) {
if (!cls.isPublic()) {
cls.setAccessType(AccessType.ACC_PUBLIC);
}
cls = cls.getEnclosingClassInfo();
}
if (wasPrivate && member instanceof MethodInfo) {
// we are done here. if the method was private, there are no conflicting
// methods or we needed to rename it anyway.
member.setAccessType(AccessType.ACC_PUBLIC);
return;
}
// if we make a non-private method or any field public, need to go down to find all overriding
// members and make them public too
final MemberID memberID = member.getMemberID();
ClassVisitor visitor = new EmptyClassVisitor() {
@Override
public boolean visitClass(ClassInfo classInfo) {
ClassMemberInfo m = classInfo.getMemberInfo(memberID);
if (m == null) {
return true;
}
if (m.isPublic()) {
// we do not need to go further down if we find a public member
return false;
}
m.setAccessType(AccessType.ACC_PUBLIC);
return true;
}
};
new ClassHierarchyTraverser(visitor).traverseDown(member.getClassInfo());
}
use of com.jopdesign.common.graphutils.ClassHierarchyTraverser in project jop by jop-devel.
the class MethodInfo method getImplementations.
/**
* Get all non-abstract methods (including this method if it is not abstract) overriding this method.
* @see AppInfo#findImplementations(CallString)
* @see AppInfo#findImplementations(MethodRef)
* @param checkAccess if false, find all non-abstract methods with same signature even if they do not
* override this method.
* @return a collection of all implementations of this method.
*/
public List<MethodInfo> getImplementations(final boolean checkAccess) {
final List<MethodInfo> implementations = new LinkedList<MethodInfo>();
if (checkAccess && (isPrivate() || isStatic())) {
if (isAbstract()) {
throw new JavaClassFormatError("Method is private or static but abstract!: " + toString());
}
implementations.add(this);
return implementations;
}
if ("<init>".equals(getShortName())) {
if (isAbstract()) {
throw new JavaClassFormatError("Found abstract constructor, this isn't right..: " + toString());
}
implementations.add(this);
return implementations;
}
ClassVisitor visitor = new ClassVisitor() {
public boolean visitClass(ClassInfo classInfo) {
MethodInfo m = classInfo.getMethodInfo(getMethodSignature());
if (m != null) {
if (m.isPrivate() && !isPrivate()) {
// found an overriding method which is private .. this is interesting..
logger.error("Found private method " + m.getMethodSignature() + " in " + classInfo.getClassName() + " overriding non-private method in " + getClassInfo().getClassName());
}
if (!m.isAbstract() && (!checkAccess || m.overrides(MethodInfo.this, false))) {
implementations.add(m);
}
}
return true;
}
public void finishClass(ClassInfo classInfo) {
}
};
new ClassHierarchyTraverser(visitor).traverseDown(getClassInfo());
return implementations;
}
use of com.jopdesign.common.graphutils.ClassHierarchyTraverser in project jop by jop-devel.
the class ClassInfo method finishRemoveFromHierarchy.
protected void finishRemoveFromHierarchy() {
// all extensions and inner classes of this class will now be incomplete
if (fullyKnown == Ternary.TRUE) {
ClassVisitor visitor = new ClassVisitor() {
@SuppressWarnings({ "AccessingNonPublicFieldOfAnotherObject" })
public boolean visitClass(ClassInfo classInfo) {
classInfo.fullyKnown = Ternary.FALSE;
return true;
}
public void finishClass(ClassInfo classInfo) {
}
};
ClassHierarchyTraverser traverser = new ClassHierarchyTraverser(visitor);
traverser.setVisitSubclasses(true, false);
// we do not support nested classes without enclosing class, so no need to visit them
// as they are removed too
traverser.setVisitInnerClasses(false);
traverser.traverseDown(this);
}
}
Aggregations