Allow for classes with missing superclasses in class hierarchy (#329)
Fixes #322 We add an option `createPhantomSuperclasses` to `ClassHierarchy`. When set, if a superclass is missing, we create a new `PhantomClass` in its place and allow the subclass to be added. To use, you can create the `ClassHierarchy` with the new `ClassHierarchyFactory.makeWithPhantom` methods.
This commit is contained in:
parent
5edf49254c
commit
aeb17dfca4
|
@ -0,0 +1 @@
|
||||||
|
!/*.class
|
Binary file not shown.
|
@ -0,0 +1,65 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2008 IBM Corporation.
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* IBM Corporation - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package com.ibm.wala.core.tests.cha;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.core.tests.util.TestConstants;
|
||||||
|
import com.ibm.wala.core.tests.util.WalaTestCase;
|
||||||
|
import com.ibm.wala.ipa.callgraph.AnalysisCacheImpl;
|
||||||
|
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||||
|
import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.config.AnalysisScopeReader;
|
||||||
|
import com.ibm.wala.util.io.FileProvider;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class MissingSuperTest extends WalaTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test handling of an invalid class where a non-abstract method has no code.
|
||||||
|
* We want to throw an exception rather than crash.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ClassHierarchyException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testMissingSuper() throws IOException, ClassHierarchyException {
|
||||||
|
AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA,
|
||||||
|
(new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), DupFieldsTest.class.getClassLoader());
|
||||||
|
TypeReference ref = TypeReference.findOrCreate(ClassLoaderReference.Application,
|
||||||
|
"Lmissingsuper/MissingSuper");
|
||||||
|
// without phantom classes, won't be able to resolve
|
||||||
|
ClassHierarchy cha = ClassHierarchyFactory.make(scope);
|
||||||
|
Assert.assertNull("lookup should not work", cha.lookupClass(ref));
|
||||||
|
// with phantom classes, lookup and IR construction should work
|
||||||
|
cha = ClassHierarchyFactory.makeWithPhantom(scope);
|
||||||
|
IClass klass = cha.lookupClass(ref);
|
||||||
|
Assert.assertNotNull("expected class MissingSuper to load", klass);
|
||||||
|
IAnalysisCacheView cache = new AnalysisCacheImpl();
|
||||||
|
Collection<? extends IMethod> declaredMethods = klass.getDeclaredMethods();
|
||||||
|
Assert.assertEquals(declaredMethods.toString(), 2, declaredMethods.size());
|
||||||
|
for (IMethod m : declaredMethods) {
|
||||||
|
// should succeed
|
||||||
|
cache.getIR(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -296,11 +296,16 @@ public abstract class BytecodeClass<T extends IClassLoader> implements IClass {
|
||||||
computeSuperclass();
|
computeSuperclass();
|
||||||
}
|
}
|
||||||
if (superClass == null && !getReference().equals(TypeReference.JavaLangObject)) {
|
if (superClass == null && !getReference().equals(TypeReference.JavaLangObject)) {
|
||||||
throw new IllegalStateException("No superclass found for " + this + " Superclass name " + superName);
|
throw new NoSuperclassFoundException("No superclass found for " + this + " Superclass name " + superName);
|
||||||
}
|
}
|
||||||
return superClass;
|
return superClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TypeName getSuperName() {
|
||||||
|
return TypeName.findOrCreate(superName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @see com.ibm.wala.classLoader.IClass#getAllFields()
|
* @see com.ibm.wala.classLoader.IClass#getAllFields()
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.ibm.wala.classLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates the superclass for a class was not found in the
|
||||||
|
* {@link com.ibm.wala.ipa.callgraph.AnalysisScope}
|
||||||
|
*/
|
||||||
|
public class NoSuperclassFoundException extends RuntimeException {
|
||||||
|
|
||||||
|
static final long serialVersionUID = 333L;
|
||||||
|
|
||||||
|
public NoSuperclassFoundException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package com.ibm.wala.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
||||||
|
import com.ibm.wala.types.Selector;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.strings.Atom;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dummy class representing a missing superclass
|
||||||
|
*/
|
||||||
|
public class PhantomClass extends SyntheticClass {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param T type reference describing this class
|
||||||
|
* @param cha
|
||||||
|
*/
|
||||||
|
public PhantomClass(TypeReference T, IClassHierarchy cha) {
|
||||||
|
super(T, cha);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPublic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModifiers() throws UnsupportedOperationException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IClass getSuperclass() {
|
||||||
|
return getClassHierarchy().getRootClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends IClass> getDirectInterfaces() {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<IClass> getAllImplementedInterfaces() {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IMethod getMethod(Selector selector) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IField getField(Atom name) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IMethod getClassInitializer() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends IMethod> getDeclaredMethods() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<IField> getAllInstanceFields() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<IField> getAllStaticFields() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<IField> getAllFields() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends IMethod> getAllMethods() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<IField> getDeclaredInstanceFields() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<IField> getDeclaredStaticFields() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReferenceType() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,31 +10,23 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package com.ibm.wala.ipa.cha;
|
package com.ibm.wala.ipa.cha;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.ConcurrentModificationException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import com.ibm.wala.classLoader.ArrayClass;
|
import com.ibm.wala.classLoader.ArrayClass;
|
||||||
|
import com.ibm.wala.classLoader.BytecodeClass;
|
||||||
import com.ibm.wala.classLoader.ClassLoaderFactory;
|
import com.ibm.wala.classLoader.ClassLoaderFactory;
|
||||||
import com.ibm.wala.classLoader.IClass;
|
import com.ibm.wala.classLoader.IClass;
|
||||||
import com.ibm.wala.classLoader.IClassLoader;
|
import com.ibm.wala.classLoader.IClassLoader;
|
||||||
import com.ibm.wala.classLoader.IField;
|
import com.ibm.wala.classLoader.IField;
|
||||||
import com.ibm.wala.classLoader.IMethod;
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
import com.ibm.wala.classLoader.Language;
|
import com.ibm.wala.classLoader.Language;
|
||||||
|
import com.ibm.wala.classLoader.NoSuperclassFoundException;
|
||||||
|
import com.ibm.wala.classLoader.PhantomClass;
|
||||||
import com.ibm.wala.classLoader.ShrikeClass;
|
import com.ibm.wala.classLoader.ShrikeClass;
|
||||||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||||
import com.ibm.wala.types.ClassLoaderReference;
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
import com.ibm.wala.types.FieldReference;
|
import com.ibm.wala.types.FieldReference;
|
||||||
import com.ibm.wala.types.MethodReference;
|
import com.ibm.wala.types.MethodReference;
|
||||||
import com.ibm.wala.types.Selector;
|
import com.ibm.wala.types.Selector;
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
import com.ibm.wala.types.TypeReference;
|
import com.ibm.wala.types.TypeReference;
|
||||||
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
||||||
import com.ibm.wala.util.collections.HashMapFactory;
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
@ -51,6 +43,18 @@ import com.ibm.wala.util.strings.Atom;
|
||||||
import com.ibm.wala.util.warnings.Warning;
|
import com.ibm.wala.util.warnings.Warning;
|
||||||
import com.ibm.wala.util.warnings.Warnings;
|
import com.ibm.wala.util.warnings.Warnings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.ConcurrentModificationException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple implementation of a class hierarchy.
|
* Simple implementation of a class hierarchy.
|
||||||
*
|
*
|
||||||
|
@ -132,6 +136,13 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
*/
|
*/
|
||||||
private Collection<TypeReference> runtimeExceptionTypeRefs;
|
private Collection<TypeReference> runtimeExceptionTypeRefs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* when a superclass is missing, should we create a phantom superclass and add the subclass to
|
||||||
|
* the hierarchy? Note that we can only create phantom superclass when the class is a
|
||||||
|
* {@link com.ibm.wala.classLoader.BytecodeClass}
|
||||||
|
*/
|
||||||
|
private final boolean createPhantomSuperclasses;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a set of {@link IClass} that holds all superclasses of klass
|
* Return a set of {@link IClass} that holds all superclasses of klass
|
||||||
*
|
*
|
||||||
|
@ -145,44 +156,60 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
|
|
||||||
Set<IClass> result = HashSetFactory.make(3);
|
Set<IClass> result = HashSetFactory.make(3);
|
||||||
|
|
||||||
klass = klass.getSuperclass();
|
try {
|
||||||
|
|
||||||
while (klass != null) {
|
|
||||||
if (DEBUG) {
|
|
||||||
System.err.println("got superclass " + klass);
|
|
||||||
}
|
|
||||||
boolean added = result.add(klass);
|
|
||||||
if (!added) {
|
|
||||||
// oops. we have A is a sub-class of B and B is a sub-class of A. blow up.
|
|
||||||
throw new IllegalStateException("cycle in the extends relation for class " + klass);
|
|
||||||
}
|
|
||||||
klass = klass.getSuperclass();
|
klass = klass.getSuperclass();
|
||||||
if (klass != null && klass.getReference().getName().equals(rootTypeRef.getName())) {
|
|
||||||
if (!klass.getReference().getClassLoader().equals(rootTypeRef.getClassLoader())) {
|
while (klass != null) {
|
||||||
throw new IllegalStateException("class " + klass + " is invalid, unexpected classloader");
|
if (DEBUG) {
|
||||||
|
System.err.println("got superclass " + klass);
|
||||||
}
|
}
|
||||||
|
boolean added = result.add(klass);
|
||||||
|
if (!added) {
|
||||||
|
// oops. we have A is a sub-class of B and B is a sub-class of A. blow up.
|
||||||
|
throw new IllegalStateException("cycle in the extends relation for class " + klass);
|
||||||
|
}
|
||||||
|
klass = klass.getSuperclass();
|
||||||
|
if (klass != null && klass.getReference().getName().equals(rootTypeRef.getName())) {
|
||||||
|
if (!klass.getReference().getClassLoader().equals(rootTypeRef.getClassLoader())) {
|
||||||
|
throw new IllegalStateException("class " + klass + " is invalid, unexpected classloader");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NoSuperclassFoundException e) {
|
||||||
|
if (createPhantomSuperclasses && klass instanceof BytecodeClass) {
|
||||||
|
// create a phantom superclass. add it and the root class to the result
|
||||||
|
IClass phantom = getPhantomSuperclass((BytecodeClass) klass);
|
||||||
|
result.add(phantom);
|
||||||
|
result.add(getRootClass());
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassHierarchy(AnalysisScope scope, ClassLoaderFactory factory, Language language, IProgressMonitor progressMonitor, Map<TypeReference, Node> map)
|
ClassHierarchy(AnalysisScope scope, ClassLoaderFactory factory, Language language,
|
||||||
|
IProgressMonitor progressMonitor, Map<TypeReference, Node> map, boolean createPhantomSuperclasses)
|
||||||
throws ClassHierarchyException, IllegalArgumentException {
|
throws ClassHierarchyException, IllegalArgumentException {
|
||||||
this(scope, factory, Collections.singleton(language), progressMonitor, map);
|
this(scope, factory, Collections.singleton(language), progressMonitor, map,
|
||||||
|
createPhantomSuperclasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassHierarchy(AnalysisScope scope, ClassLoaderFactory factory, IProgressMonitor progressMonitor, Map<TypeReference, Node> map)
|
ClassHierarchy(AnalysisScope scope, ClassLoaderFactory factory, IProgressMonitor
|
||||||
|
progressMonitor, Map<TypeReference, Node> map, boolean createPhantomSuperclasses)
|
||||||
throws ClassHierarchyException, IllegalArgumentException {
|
throws ClassHierarchyException, IllegalArgumentException {
|
||||||
this(scope, factory, scope.getLanguages(), progressMonitor, map);
|
this(scope, factory, scope.getLanguages(), progressMonitor, map, createPhantomSuperclasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassHierarchy(AnalysisScope scope, ClassLoaderFactory factory, Collection<Language> languages,
|
ClassHierarchy(AnalysisScope scope, ClassLoaderFactory factory, Collection<Language> languages,
|
||||||
IProgressMonitor progressMonitor, Map<TypeReference, Node> map) throws ClassHierarchyException, IllegalArgumentException {
|
IProgressMonitor progressMonitor, Map<TypeReference, Node> map, boolean createPhantomSuperclasses) throws
|
||||||
|
ClassHierarchyException, IllegalArgumentException {
|
||||||
// now is a good time to clear the warnings globally.
|
// now is a good time to clear the warnings globally.
|
||||||
// TODO: think of a better way to guard against warning leaks.
|
// TODO: think of a better way to guard against warning leaks.
|
||||||
Warnings.clear();
|
Warnings.clear();
|
||||||
|
|
||||||
this.map = map;
|
this.map = map;
|
||||||
|
this.createPhantomSuperclasses = createPhantomSuperclasses;
|
||||||
|
|
||||||
if (factory == null) {
|
if (factory == null) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
|
@ -307,20 +334,26 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.err.println(("Attempt to add class " + klass));
|
System.err.println(("Attempt to add class " + klass));
|
||||||
}
|
}
|
||||||
Set<IClass> loadedSuperclasses;
|
Set<IClass> loadedSuperclasses = null;
|
||||||
Collection<IClass> loadedSuperInterfaces;
|
Collection<IClass> loadedSuperInterfaces;
|
||||||
try {
|
try {
|
||||||
loadedSuperclasses = computeSuperclasses(klass);
|
loadedSuperclasses = computeSuperclasses(klass);
|
||||||
loadedSuperInterfaces = klass.getAllImplementedInterfaces();
|
loadedSuperInterfaces = klass.getAllImplementedInterfaces();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// a little cleanup
|
if (createPhantomSuperclasses && e instanceof NoSuperclassFoundException) {
|
||||||
if (klass instanceof ShrikeClass) {
|
// this must have been thrown by the getAllImplementedInterfaces() call.
|
||||||
if (DEBUG) {
|
// for now, just pretend it implements no interfaces
|
||||||
System.err.println(("Exception. Clearing " + klass));
|
loadedSuperInterfaces = Collections.emptySet();
|
||||||
|
} else {
|
||||||
|
// a little cleanup
|
||||||
|
if (klass instanceof ShrikeClass) {
|
||||||
|
if (DEBUG) {
|
||||||
|
System.err.println(("Exception. Clearing " + klass));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Warnings.add(ClassExclusion.create(klass.getReference(), e.getMessage()));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
Warnings.add(ClassExclusion.create(klass.getReference(), e.getMessage()));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
Node node = findOrCreateNode(klass);
|
Node node = findOrCreateNode(klass);
|
||||||
|
|
||||||
|
@ -333,8 +366,13 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
Set workingSuperclasses = HashSetFactory.make(loadedSuperclasses);
|
Set workingSuperclasses = HashSetFactory.make(loadedSuperclasses);
|
||||||
while (node != null) {
|
while (node != null) {
|
||||||
IClass c = node.getJavaClass();
|
IClass c = node.getJavaClass();
|
||||||
IClass superclass = null;
|
IClass superclass;
|
||||||
superclass = c.getSuperclass();
|
try {
|
||||||
|
superclass = c.getSuperclass();
|
||||||
|
} catch (NoSuperclassFoundException e) {
|
||||||
|
assert createPhantomSuperclasses;
|
||||||
|
superclass = getPhantomSuperclass((BytecodeClass) c);
|
||||||
|
}
|
||||||
if (superclass != null) {
|
if (superclass != null) {
|
||||||
workingSuperclasses.remove(superclass);
|
workingSuperclasses.remove(superclass);
|
||||||
Node supernode = findOrCreateNode(superclass);
|
Node supernode = findOrCreateNode(superclass);
|
||||||
|
@ -381,6 +419,18 @@ public class ClassHierarchy implements IClassHierarchy {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IClass getPhantomSuperclass(BytecodeClass klass) {
|
||||||
|
ClassLoaderReference loader = klass.getReference().getClassLoader();
|
||||||
|
TypeName superName = klass.getSuperName();
|
||||||
|
TypeReference superRef = TypeReference.findOrCreate(loader, superName);
|
||||||
|
IClass superClass = lookupClass(superRef);
|
||||||
|
if (superClass == null) {
|
||||||
|
superClass = new PhantomClass(superRef, this);
|
||||||
|
addClass(superClass);
|
||||||
|
}
|
||||||
|
return superClass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record that a klass implements a particular interface
|
* Record that a klass implements a particular interface
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,17 +10,15 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package com.ibm.wala.ipa.cha;
|
package com.ibm.wala.ipa.cha;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import com.ibm.wala.classLoader.ClassLoaderFactory;
|
import com.ibm.wala.classLoader.ClassLoaderFactory;
|
||||||
import com.ibm.wala.classLoader.ClassLoaderFactoryImpl;
|
import com.ibm.wala.classLoader.ClassLoaderFactoryImpl;
|
||||||
import com.ibm.wala.classLoader.Language;
|
import com.ibm.wala.classLoader.Language;
|
||||||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||||
import com.ibm.wala.ipa.cha.ClassHierarchy.Node;
|
|
||||||
import com.ibm.wala.types.TypeReference;
|
|
||||||
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class ClassHierarchyFactory {
|
public class ClassHierarchyFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,6 +32,19 @@ public class ClassHierarchyFactory {
|
||||||
return make(scope, new ClassLoaderFactoryImpl(scope.getExclusions()));
|
return make(scope, new ClassLoaderFactoryImpl(scope.getExclusions()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a ClassHierarchy object representing the analysis scope, where phantom classes are
|
||||||
|
* created when superclasses are missing
|
||||||
|
*
|
||||||
|
* @throws ClassHierarchyException
|
||||||
|
*/
|
||||||
|
public static ClassHierarchy makeWithPhantom(AnalysisScope scope) throws ClassHierarchyException {
|
||||||
|
if (scope == null) {
|
||||||
|
throw new IllegalArgumentException("null scope");
|
||||||
|
}
|
||||||
|
return makeWithPhantom(scope, new ClassLoaderFactoryImpl(scope.getExclusions()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* temporarily marking this internal to avoid infinite sleep with randomly chosen IProgressMonitor.
|
* temporarily marking this internal to avoid infinite sleep with randomly chosen IProgressMonitor.
|
||||||
*/
|
*/
|
||||||
|
@ -45,31 +56,41 @@ public class ClassHierarchyFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory) throws ClassHierarchyException {
|
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory) throws ClassHierarchyException {
|
||||||
|
return make(scope, factory, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, boolean
|
||||||
|
createPhantomSuperclasses) throws ClassHierarchyException {
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
throw new IllegalArgumentException("null scope");
|
throw new IllegalArgumentException("null scope");
|
||||||
}
|
}
|
||||||
if (factory == null) {
|
if (factory == null) {
|
||||||
throw new IllegalArgumentException("null factory");
|
throw new IllegalArgumentException("null factory");
|
||||||
}
|
}
|
||||||
return new ClassHierarchy(scope, factory, null, new ConcurrentHashMap<TypeReference, Node>());
|
return new ClassHierarchy(scope, factory, null, new ConcurrentHashMap<>(),
|
||||||
|
createPhantomSuperclasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ClassHierarchy makeWithPhantom(AnalysisScope scope, ClassLoaderFactory factory)
|
||||||
|
throws ClassHierarchyException {
|
||||||
|
return make(scope, factory, true);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* temporarily marking this internal to avoid infinite sleep with randomly chosen IProgressMonitor.
|
* temporarily marking this internal to avoid infinite sleep with randomly chosen IProgressMonitor.
|
||||||
*/
|
*/
|
||||||
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, IProgressMonitor monitor)
|
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, IProgressMonitor monitor)
|
||||||
throws ClassHierarchyException {
|
throws ClassHierarchyException {
|
||||||
return new ClassHierarchy(scope, factory, monitor, new ConcurrentHashMap<TypeReference, Node>());
|
return new ClassHierarchy(scope, factory, monitor, new ConcurrentHashMap<>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, Set<Language> languages)
|
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, Set<Language> languages)
|
||||||
throws ClassHierarchyException {
|
throws ClassHierarchyException {
|
||||||
return new ClassHierarchy(scope, factory, languages, null, new ConcurrentHashMap<TypeReference, Node>());
|
return new ClassHierarchy(scope, factory, languages, null, new ConcurrentHashMap<>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, Language language)
|
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, Language language)
|
||||||
throws ClassHierarchyException {
|
throws ClassHierarchyException {
|
||||||
return new ClassHierarchy(scope, factory, language, null, new ConcurrentHashMap<TypeReference, Node>());
|
return new ClassHierarchy(scope, factory, language, null, new ConcurrentHashMap<>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,7 +101,7 @@ public class ClassHierarchyFactory {
|
||||||
if (factory == null) {
|
if (factory == null) {
|
||||||
throw new IllegalArgumentException("null factory");
|
throw new IllegalArgumentException("null factory");
|
||||||
}
|
}
|
||||||
return new ClassHierarchy(scope, factory, language, monitor, new ConcurrentHashMap<TypeReference, Node>());
|
return new ClassHierarchy(scope, factory, language, monitor, new ConcurrentHashMap<>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,15 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package com.ibm.wala.ipa.cha;
|
package com.ibm.wala.ipa.cha;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.ibm.wala.classLoader.ClassLoaderFactory;
|
import com.ibm.wala.classLoader.ClassLoaderFactory;
|
||||||
import com.ibm.wala.classLoader.ClassLoaderFactoryImpl;
|
import com.ibm.wala.classLoader.ClassLoaderFactoryImpl;
|
||||||
import com.ibm.wala.classLoader.Language;
|
import com.ibm.wala.classLoader.Language;
|
||||||
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||||
import com.ibm.wala.ipa.cha.ClassHierarchy.Node;
|
|
||||||
import com.ibm.wala.types.TypeReference;
|
|
||||||
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
||||||
import com.ibm.wala.util.collections.HashMapFactory;
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class SeqClassHierarchyFactory {
|
public class SeqClassHierarchyFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +49,8 @@ public class SeqClassHierarchyFactory {
|
||||||
if (factory == null) {
|
if (factory == null) {
|
||||||
throw new IllegalArgumentException("null factory");
|
throw new IllegalArgumentException("null factory");
|
||||||
}
|
}
|
||||||
return new ClassHierarchy(scope, factory, null, HashMapFactory.<TypeReference, Node>make());
|
return new ClassHierarchy(scope, factory, null, HashMapFactory.make(),
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,17 +58,17 @@ public class SeqClassHierarchyFactory {
|
||||||
*/
|
*/
|
||||||
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, IProgressMonitor monitor)
|
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, IProgressMonitor monitor)
|
||||||
throws ClassHierarchyException {
|
throws ClassHierarchyException {
|
||||||
return new ClassHierarchy(scope, factory, monitor, HashMapFactory.<TypeReference, Node>make());
|
return new ClassHierarchy(scope, factory, monitor, HashMapFactory.make(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, Set<Language> languages)
|
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, Set<Language> languages)
|
||||||
throws ClassHierarchyException {
|
throws ClassHierarchyException {
|
||||||
return new ClassHierarchy(scope, factory, languages, null, HashMapFactory.<TypeReference, Node>make());
|
return new ClassHierarchy(scope, factory, languages, null, HashMapFactory.make(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, Language language)
|
public static ClassHierarchy make(AnalysisScope scope, ClassLoaderFactory factory, Language language)
|
||||||
throws ClassHierarchyException {
|
throws ClassHierarchyException {
|
||||||
return new ClassHierarchy(scope, factory, language, null, HashMapFactory.<TypeReference, Node>make());
|
return new ClassHierarchy(scope, factory, language, null, HashMapFactory.make(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,7 +79,7 @@ public class SeqClassHierarchyFactory {
|
||||||
if (factory == null) {
|
if (factory == null) {
|
||||||
throw new IllegalArgumentException("null factory");
|
throw new IllegalArgumentException("null factory");
|
||||||
}
|
}
|
||||||
return new ClassHierarchy(scope, factory, language, monitor, HashMapFactory.<TypeReference, Node>make());
|
return new ClassHierarchy(scope, factory, language, monitor, HashMapFactory.make(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue