com.ibm.wala.ipa.summaries.BypassSyntheticClassLoader Maven / Gradle / Ivy
/*
* Copyright (c) 2002 - 2006 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.ipa.summaries;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IClassLoader;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.Language;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.core.util.strings.Atom;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.config.SetOfClasses;
import java.io.IOException;
import java.io.Reader;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
/**
* This class represents class loaders that introduce classes that do not exist in the actual
* application being analyzed. They may be abstract summaries of unanalyzed library code, wrappers
* that encode J2EE specialized behavior or other invented classes.
*
* The intention is that there be (at most) one such classloader in a given class hierarchy, and
* that it be referenced using the "Synthetic" classloader reference. Furthermore, it is required
* that this synthetic loader be a child loader of the Primordial, Extension and Application
* loaders.
*
*
This special classloader has some interactions with the hierarchy for, while the classes it
* loads are normal-seeming IClass objects, unlike the other loaders, its set of classes is not
* fixed, causing special cases in code that caches hierarchy data. Also note that this causes the
* getNumberfClasses and iterateAllClasses methods to behave differently for those of other
* classloaders.
*
*
Code that wants to introduce synthetic classes uses the registerClass method, giving it an
* Atom which is the class name, and an IClass which is the class to load. Since the synthetic
* loader must be a child of the others, it would be very bad to use an existing name for a new
* synthetic class.
*
*
Class lookup works just as for any other classloader.
*
* @author Julian Dolby ([email protected])
*/
public class BypassSyntheticClassLoader implements IClassLoader {
private final ClassLoaderReference me;
private final IClassLoader parent;
private final IClassHierarchy cha;
private final HashMap syntheticClasses = HashMapFactory.make();
/**
* Don't change my signature! ClassLoaderFactoryImpl calls me by reflection! yuck.
*
* @param me the name of this class loader
* @param parent its parent
* @param exclusions classes to ignore
* @param cha governing class hierarchy
*/
public BypassSyntheticClassLoader(
ClassLoaderReference me, IClassLoader parent, SetOfClasses exclusions, IClassHierarchy cha) {
if (cha == null) {
throw new IllegalArgumentException("null cha");
}
this.me = me;
this.cha = cha;
this.parent = parent;
}
@Override
public String toString() {
return me.getName().toString();
}
@Override
public IClass lookupClass(TypeName className) {
IClass pc = parent.lookupClass(className);
if (pc == null) {
IClass c = syntheticClasses.get(className);
return c;
} else {
return pc;
}
}
/** Register the existence of a new synthetic class */
public void registerClass(TypeName className, IClass theClass) {
cha.addClass(theClass);
syntheticClasses.put(className, theClass);
}
/** Return the ClassLoaderReference for this class loader. */
@Override
public ClassLoaderReference getReference() {
return me;
}
/**
* @return an Iterator of all classes loaded by this loader
*/
@Override
public Iterator iterateAllClasses() {
return syntheticClasses.values().iterator();
}
/**
* @return the number of classes in scope to be loaded by this loader
*/
@Override
public int getNumberOfClasses() {
return syntheticClasses.size();
}
/**
* @return the unique name that identifies this class loader.
*/
@Override
public Atom getName() {
return me.getName();
}
/**
* @return the unique name that identifies the programming language from which this class loader
* loads code.
*/
@Override
public Language getLanguage() {
return parent.getLanguage();
}
@Override
public int getNumberOfMethods() {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getSourceFileName(IClass klass) {
return null;
}
@Override
public IClassLoader getParent() {
return parent;
}
@Override
public void init(List modules) throws IOException {}
@Override
public void removeAll(Collection toRemove) {
if (toRemove == null) {
throw new IllegalArgumentException("toRemove is null");
}
for (IClass c : toRemove) {
syntheticClasses.remove(c.getName());
}
;
}
@Override
public Reader getSource(IClass klass) {
return null;
}
@Override
public SSAInstructionFactory getInstructionFactory() {
return getLanguage().instructionFactory();
}
@Override
public Reader getSource(IMethod method, int offset) {
return null;
}
@Override
public String getSourceFileName(IMethod method, int offset) {
return null;
}
}