package accrue.analysis.signatures;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import accrue.analysis.defuse.DefUseAnalysisFactory;
import accrue.analysis.defuse.DefUseLibrarySignature;
import accrue.analysis.interprocvarcontext.SignatureRepository;
import accrue.analysis.notnulldataflow.NotNullAnalysisFactory;
import accrue.analysis.notnulldataflow.NotNullAnalysisUtil;
import accrue.analysis.pointer.PointerAnalysisPass;
import accrue.analysis.pointer.PointsToLibrarySigs;
import accrue.analysis.preciseExceptions.PreciseExAnalysisFactory;
import accrue.analysis.preciseExceptions.PreciseExLibrarySignature;

public class AnalysisSignatures {
    /** 
     * Map from Analysis names to signature repositories for them
     */
    @SuppressWarnings("rawtypes")
    private final Map<String, SignatureRepository> sigrepos =
            new HashMap<String, SignatureRepository>();

//    /** 
//     * Map from Analysis names to list of signatures for static initializers for them
//     */
//    private final Map<String, List> staticinits = new HashMap();

    /**
     * Get a signature repository for a given analysis name.
     */
    @SuppressWarnings("unchecked")
    public <T> SignatureRepository<T> signatureRepository(String analysisName) {
        return sigrepos.get(analysisName);
    }

    /**
     * Get a signature repository for a given analysis name, creating one if requested.
     */
    @SuppressWarnings("rawtypes")
    protected SignatureRepository signatureRepository(String analysisName,
            boolean createIfNeeded) {
        SignatureRepository r = sigrepos.get(analysisName);
        if (r == null && createIfNeeded) {
            r = new SignatureRepository();
            sigrepos.put(analysisName, r);
        }
        return r;
    }

//    /**
//     * Get a list of static inits for a given analysis name
//     */
//    public List staticInits(String analysisName) {
//        List r = staticinits.get(analysisName);
//        if (r == null) {
//            r = Collections.EMPTY_LIST;
//        }
//        return r;
//    }
//    /**
//     * Get a list of static inits for a given analysis name, creating one if requested.
//     */
//    protected List staticInits(String analysisName, boolean createIfNeeded) {
//        List r = staticinits.get(analysisName);
//        if (r == null && createIfNeeded) {
//            r = new ArrayList();
//            staticinits.put(analysisName, r);
//        }
//        return r;
//    }

    /*
     * Utility methods to add signatures
     */
    @SuppressWarnings("unchecked")
    protected <T> void add(String fullClassName, String methodName,
            List<String> argTypes, String analysisName, T sig) {
        signatureRepository(analysisName, true).addSignature(fullClassName,
                                                             methodName,
                                                             argTypes,
                                                             sig);
    }

    @SuppressWarnings("unchecked")
    protected void add(String fullClassName, String methodName,
            List<String> argTypes, String analysisName1, Object sig1,
            String analysisName2, Object sig2) {
        signatureRepository(analysisName1, true).addSignature(fullClassName,
                                                              methodName,
                                                              argTypes,
                                                              sig1);
        signatureRepository(analysisName2, true).addSignature(fullClassName,
                                                              methodName,
                                                              argTypes,
                                                              sig2);
    }

    @SuppressWarnings("unchecked")
    protected void add(String fullClassName, String methodName,
            List<String> argTypes, String analysisName1, Object sig1,
            String analysisName2, Object sig2, String analysisName3, Object sig3) {
        signatureRepository(analysisName1, true).addSignature(fullClassName,
                                                              methodName,
                                                              argTypes,
                                                              sig1);
        signatureRepository(analysisName2, true).addSignature(fullClassName,
                                                              methodName,
                                                              argTypes,
                                                              sig2);
        signatureRepository(analysisName3, true).addSignature(fullClassName,
                                                              methodName,
                                                              argTypes,
                                                              sig3);
    }

    @SuppressWarnings("unchecked")
    protected <T> void addConstructor(String fullClassName,
            List<String> argTypes, String analysisName, T sig) {
        signatureRepository(analysisName, true).addSignatureForConstructor(fullClassName,
                                                                           argTypes,
                                                                           sig);
    }

    @SuppressWarnings("unchecked")
    protected void addConstructor(String fullClassName, List<String> argTypes,
            String analysisName1, Object sig1, String analysisName2, Object sig2) {
        signatureRepository(analysisName1, true).addSignatureForConstructor(fullClassName,
                                                                            argTypes,
                                                                            sig1);
        signatureRepository(analysisName2, true).addSignatureForConstructor(fullClassName,
                                                                            argTypes,
                                                                            sig2);
    }

    @SuppressWarnings("unchecked")
    protected void addConstructor(String fullClassName, List<String> argTypes,
            String analysisName1, Object sig1, String analysisName2,
            Object sig2, String analysisName3, Object sig3) {
        signatureRepository(analysisName1, true).addSignatureForConstructor(fullClassName,
                                                                            argTypes,
                                                                            sig1);
        signatureRepository(analysisName2, true).addSignatureForConstructor(fullClassName,
                                                                            argTypes,
                                                                            sig2);
        signatureRepository(analysisName3, true).addSignatureForConstructor(fullClassName,
                                                                            argTypes,
                                                                            sig3);
    }

    @SuppressWarnings("unchecked")
    protected void addConstructor(String fullClassName, List<String> argTypes,
            String analysisName1, Object sig1, String analysisName2,
            Object sig2, String analysisName3, Object sig3,
            String analysisName4, Object sig4) {
        signatureRepository(analysisName1, true).addSignatureForConstructor(fullClassName,
                                                                            argTypes,
                                                                            sig1);
        signatureRepository(analysisName2, true).addSignatureForConstructor(fullClassName,
                                                                            argTypes,
                                                                            sig2);
        signatureRepository(analysisName3, true).addSignatureForConstructor(fullClassName,
                                                                            argTypes,
                                                                            sig3);
        signatureRepository(analysisName4, true).addSignatureForConstructor(fullClassName,
                                                                            argTypes,
                                                                            sig4);
    }

    @SuppressWarnings("unchecked")
    protected void add(String fullClassName, String methodName,
            List<String> argTypes, String analysisName1, Object sig1,
            String analysisName2, Object sig2, String analysisName3,
            Object sig3, String analysisName4, Object sig4) {
        signatureRepository(analysisName1, true).addSignature(fullClassName,
                                                              methodName,
                                                              argTypes,
                                                              sig1);
        signatureRepository(analysisName2, true).addSignature(fullClassName,
                                                              methodName,
                                                              argTypes,
                                                              sig2);
        signatureRepository(analysisName3, true).addSignature(fullClassName,
                                                              methodName,
                                                              argTypes,
                                                              sig3);
        signatureRepository(analysisName4, true).addSignature(fullClassName,
                                                              methodName,
                                                              argTypes,
                                                              sig4);
    }

//    protected <T> void addStaticIntializer(String analysisName, T sig) {
//        staticInits(analysisName, true).add(sig);
//    }
//    protected void addStaticIntializer(String analysisName1, Object sig1, String analysisName2, Object sig2) {
//        staticInits(analysisName1, true).add(sig1);
//        staticInits(analysisName2, true).add(sig2);
//    }
//    protected void addStaticIntializer(String analysisName1, Object sig1, String analysisName2, Object sig2, String analysisName3, Object sig3) {        
//        staticInits(analysisName1, true).add(sig1);
//        staticInits(analysisName2, true).add(sig2);
//        staticInits(analysisName3, true).add(sig3);
//    }

    protected static List<String> List(String s1) {
        return Collections.singletonList(s1);
    }

    protected static List<String> List(String s1, String s2) {
        List<String> l = new ArrayList<String>(2);
        l.add(s1);
        l.add(s2);
        return l;
    }

    protected static List<String> List(String s1, String s2, String s3) {
        List<String> l = new ArrayList<String>(3);
        l.add(s1);
        l.add(s2);
        l.add(s3);
        return l;
    }

    /* **********************************************
     * 
     * java.lang package signatures
     *  
     */
    {
        // *******************
        // java.lang.Object
        addConstructor("java.lang.Object",
                       Collections.<String> emptyList(),
                       PointerAnalysisPass.ANALYSIS_NAME,
                       PointsToLibrarySigs.NOOP,
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
                       DefUseAnalysisFactory.ANALYSIS_NAME,
                       DefUseLibrarySignature.NOOP);

        add("java.lang.Object",
            "equals",
            List("java.lang.Object"),
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.Object",
            "toString",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.Object",
            "getClass",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.Singleton("java.lang.Object.getClass",
                                              "java.lang.Class",
                                              true),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

        // *******************
        // java.lang.System
//        addStaticInitializer(PointerAnalysisPass.ANALYSIS_NAME, PointsToLibrarySigs.NOOP,
//                             NotNullAnalysisFactory.ANALYSIS_NAME, NotNullAnalysisUtil.NOOP_SIG,
//                             PreciseExAnalysisFactory.ANALYSIS_NAME, PreciseExLibrarySignature.NORM_TERMINATION_ONLY);
        add("java.lang.System",
            "exit",
            Collections.singletonList("int"),
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NO_TERMINATION,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

        add("java.lang.System",
            "nullInputStream",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.Singleton("java.lang.System.nullInputStream",
                                              "java.io.InputStream",
                                              false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.System",
            "nullPrintStream",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.Singleton("java.lang.System.nullPrintStream",
                                              "java.io.PrintStream",
                                              false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

        //        // *******************
//        // java.lang.ClassLoader
//        add("java.lang.ClassLoader",
//            "classContext",

        // *******************
        // java.lang.Thread
        add("java.lang.Thread",
            "currentThread",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.Singleton("java.lang.Thread.currentThread",
                                              "java.lang.Thread",
                                              false), // unsound if user code creates thread! Could make it sound with more effort.
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

        // *******************
        // java.lang.Exception
        addConstructor("java.lang.Exception",
                       Collections.<String> emptyList(),
                       PointerAnalysisPass.ANALYSIS_NAME,
                       PointsToLibrarySigs.NOOP,
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
                       DefUseAnalysisFactory.ANALYSIS_NAME,
                       DefUseLibrarySignature.NOOP);

        // java.lang.IllegalArgumentException
        addConstructor("java.lang.IllegalArgumentException",
                       null, /*Just guessing but I think all constructors will behave about the same */
                       PointerAnalysisPass.ANALYSIS_NAME,
                       PointsToLibrarySigs.NOOP,
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
                       DefUseAnalysisFactory.ANALYSIS_NAME,
                       DefUseLibrarySignature.NOOP);

        // java.util.NoSuchElementException
        addConstructor("java.util.NoSuchElementException",
                       null, /*Just guessing but I think all constructors will behave about the same */
                       PointerAnalysisPass.ANALYSIS_NAME,
                       PointsToLibrarySigs.NOOP,
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
                       DefUseAnalysisFactory.ANALYSIS_NAME,
                       DefUseLibrarySignature.NOOP);

        // java.lang.UnsupportedOperationException
        addConstructor("java.lang.UnsupportedOperationException",
                       null, /*Just guessing but I think all constructors will behave about the same */
                       PointerAnalysisPass.ANALYSIS_NAME,
                       PointsToLibrarySigs.NOOP,
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
                       DefUseAnalysisFactory.ANALYSIS_NAME,
                       DefUseLibrarySignature.NOOP);

        addConstructor("java.lang.RuntimeException",
                       null,
                       PointerAnalysisPass.ANALYSIS_NAME,
                       PointsToLibrarySigs.NOOP,
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
                       DefUseAnalysisFactory.ANALYSIS_NAME,
                       DefUseLibrarySignature.NOOP);

        // *******************
        // java.lang.Throwable
        add("java.lang.Throwable",
            "printStackTrace",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.Throwable",
            "toString",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

        // *******************
        // java.lang.String
        add("java.lang.String",
            "length",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "substring",
            null /*all have the same behavior*/,
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        true),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.ExactExceptions("java.lang.IndexOutOfBoundsException"),
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "startsWith",
            null /* all have the same behavior */,
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "equals",
            List("java.lang.Object"),
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "valueOf",
            List("int"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "valueOf",
            List("long"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "valueOf",
            List("byte"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "valueOf",
            List("boolean"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "valueOf",
            List("char"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "valueOf",
            List("float"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "valueOf",
            List("double"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "valueOf",
            List("java.lang.Object"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        true),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "valueOf",
            List("char[]"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "charAt",
            List("int"),
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.ExactExceptions("java.lang.IndexOutOfBoundsException"),
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
        add("java.lang.String",
            "getBytes",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("byte[]", false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

        // *******************
        // java.lang.Integer
        add("java.lang.Integer",
            "parseInt",
            List("java.lang.String"),
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.ExactExceptions("java.lang.NumberFormatException"),
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

        add("java.lang.Integer",
            "parseInt",
            List("java.lang.String", "int"),
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.ExactExceptions("java.lang.NumberFormatException"),
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

        add("java.lang.Integer",
            "toString",
            List("int"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);
    }

    /* **********************************************
     * 
     * java.io package signatures
     *  
     */
    {
        // *******************
        // java.io.InputStreamReader
        addConstructor("java.io.InputStreamReader",
                       List("java.io.InputStream"),
                       PointerAnalysisPass.ANALYSIS_NAME,
                       new PointsToLibrarySigs.AssignsArgToField("dummy",
                                                                 "java.io.InputStream",
                                                                 0),
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY);

        // *******************
        // java.io.BufferedReader
        addConstructor("java.io.BufferedReader",
                       List("java.io.Reader"),
                       PointerAnalysisPass.ANALYSIS_NAME,
                       new PointsToLibrarySigs.AssignsArgToField("in",
                                                                 "java.io.Reader",
                                                                 0),
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY);

        add("java.io.BufferedReader",
            "readLine",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.AllocatorOrReceiver("java.lang.String",
                                                        false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_MAYBENULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NonexactExceptions("java.io.IOException"));

        // *******************
        // java.io.PrintStream
        addConstructor("java.io.PrintStream",
                       List("java.io.OutputStream"),
                       PointerAnalysisPass.ANALYSIS_NAME,
                       new PointsToLibrarySigs.AssignsArgToField("out",
                                                                 "java.io.OutputStream",
                                                                 0),
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.ExactExceptions("NullPointerException"));

        add("java.io.PrintStream",
            "println",
            null /* all methods behave the same */,
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY);

        add("java.io.PrintStream",
            "print",
            null /* all methods behave the same */,
            PointerAnalysisPass.ANALYSIS_NAME,
            PointsToLibrarySigs.NOOP,
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY);

        // *******************
        // java.io.OutputStream
        addConstructor("java.io.OutputStream",
                       Collections.<String> emptyList(),
                       PointerAnalysisPass.ANALYSIS_NAME,
                       PointsToLibrarySigs.NOOP,
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
                       DefUseAnalysisFactory.ANALYSIS_NAME,
                       DefUseLibrarySignature.NOOP);

        // *******************
        // java.io.InputStream
        addConstructor("java.io.InputStream",
                       Collections.<String> emptyList(),
                       PointerAnalysisPass.ANALYSIS_NAME,
                       PointsToLibrarySigs.NOOP,
                       NotNullAnalysisFactory.ANALYSIS_NAME,
                       NotNullAnalysisUtil.NOOP_SIG,
                       PreciseExAnalysisFactory.ANALYSIS_NAME,
                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
                       DefUseAnalysisFactory.ANALYSIS_NAME,
                       DefUseLibrarySignature.NOOP);

        // *******************
        // java.io.FileSystem
        add("java.io.FileSystem",
            "getFileSystem",
            Collections.<String> emptyList(),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.Singleton("java.io.FileSystem",
                                              "java.io.FileSystem",
                                              false),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

    }

    /* **********************************************
     * 
     * sun package signatures
     *  
     */
    {
        add("sun.reflect.Reflection",
            "getCallerClass",
            Collections.<String> singletonList("int"),
            PointerAnalysisPass.ANALYSIS_NAME,
            new PointsToLibrarySigs.Singleton("java.lang.Class",
                                              "java.lang.Class",
                                              true),
            NotNullAnalysisFactory.ANALYSIS_NAME,
            NotNullAnalysisUtil.NOOP_NONNULL_RESULT_SIG,
            PreciseExAnalysisFactory.ANALYSIS_NAME,
            PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
            DefUseAnalysisFactory.ANALYSIS_NAME,
            DefUseLibrarySignature.NOOP);

    }
    /* **********************************************
     * 
     * java.security package signatures
     *  
     */
    {
        // *******************
        // java.security.AccessController
//        add("java.security.AccessController",
//            "doPrivileged",  Collections.<String> singletonList(),
//                       PointerAnalysisPass.ANALYSIS_NAME,
//                       PointsToLibrarySigs.NOOP,
//                       NotNullAnalysisFactory.ANALYSIS_NAME,
//                       NotNullAnalysisUtil.NOOP_SIG,
//                       PreciseExAnalysisFactory.ANALYSIS_NAME,
//                       PreciseExLibrarySignature.NORM_TERMINATION_ONLY,
//                       DefUseAnalysisFactory.ANALYSIS_NAME,
//                       DefUseLibrarySignature.NOOP);

//  if ("java.security.AccessController".equals(container)) {
//  if ("doPrivileged".equals(name)) {
//      // all this does is call the run method of the first argument.
//      List l = ((ClassType)mi.formalTypes().get(0)).methodsNamed("run");
//      if (l.size() != 1) {
//          throw new InternalCompilerError("No run method! " + mi.formalTypes().get(0));
//      }
//      MethodInstance runMeth = (MethodInstance)l.get(0);
//      return new InvokeMethodOfArg(runMeth, 0);
//  }
//}
    }

//    //***** to modify: precise exceptions
//    private static SignatureRepository<PreciseExLibrarySignature> SIGNATURES;
//    static {
//        SIGNATURES = new SignatureRepository<PreciseExLibrarySignature>();
//        SIGNATURES.addSignatureForConstructor("java.lang.Object", PreciseExLibrarySignature.NONEXCEPTIONAL_TERMINATION);
//        SIGNATURES.addSignatureForConstructor("java.lang.Exception", PreciseExLibrarySignature.NONEXCEPTIONAL_TERMINATION);
//        SIGNATURES.addSignatureForConstructor("java.lang.RuntimeException", PreciseExLibrarySignature.NONEXCEPTIONAL_TERMINATION);
//        SIGNATURES.addSignatureForConstructor("java.lang.IllegalArgumentException", PreciseExLibrarySignature.NONEXCEPTIONAL_TERMINATION);
//        SIGNATURES.addSignatureForConstructor("java.lang.NullPointerException", PreciseExLibrarySignature.NONEXCEPTIONAL_TERMINATION);
//        
//        
//        SIGNATURES.addSignature("java.lang.String", "toString", PreciseExLibrarySignature.NONEXCEPTIONAL_TERMINATION);
//    }
//    
//    //****** not null analysis
//    static final SignatureRepository<LibrarySignature<NotNullDFI>> repository = new SignatureRepository<LibrarySignature<NotNullDFI>>();
//    static {
//        repository.addSignatureForConstructor("java.lang.Object", NOOP_SIG);
//        repository.addSignatureForConstructor("java.lang.NullPointerException", NOOP_SIG);
//        repository.addSignatureForConstructor("java.lang.IllegalArgumentException", NOOP_SIG);
//        repository.addSignatureForConstructor("java.lang.Exception", NOOP_SIG);
//        repository.addSignatureForConstructor("java.lang.RuntimeException", NOOP_SIG);
//        repository.addSignatureForConstructor("java.io.InputStreamReader", NOOP_SIG);
//        repository.addSignatureForConstructor("java.io.BufferedReader", NOOP_SIG);
//        repository.addSignature("java.lang.String", "toString", NOOP_NONNULL_RESULT_SIG);
//        repository.addSignature("java.lang.Object", "toString", NOOP_NONNULL_RESULT_SIG);
//        repository.addSignature("java.lang.Throwable", "printStackTrace", Collections.EMPTY_LIST, NOOP_SIG);
//        repository.addSignature("java.lang.Throwable", "printStackTrace", Collections.EMPTY_LIST, NOOP_SIG);
//        repository.addSignature("java.io.BufferedReader", "readLine", Collections.EMPTY_LIST, NOOP_MAYBENULL_RESULT_SIG);
//    }
//
//
//    //***** to modify: pointer analysis
//    static Map<String, Collection<String>> safeCodeToIgnore = new LinkedHashMap();
//    static Set<String> moreSafeCodeToIgnore = new LinkedHashSet();
//    static {
//        moreSafeCodeToIgnore.add("java.lang.Double.doubleToLongBits");
//        moreSafeCodeToIgnore.add("java.lang.Float.floatToIntBits");
//        moreSafeCodeToIgnore.add("java.io.FileDescriptor.initIDs");
//        moreSafeCodeToIgnore.add("java.io.FileInputStream.close0");        
//        moreSafeCodeToIgnore.add("java.lang.Class.registerNatives");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.sin");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.cos");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.tan");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.asin");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.acos");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.atan");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.exp");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.log");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.sqrt");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.IEEEremainder");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.ceil");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.floor");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.rint");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.atan2");
//        moreSafeCodeToIgnore.add("java.lang.StrictMath.pow");
//        moreSafeCodeToIgnore.add("java.io.FileInputStream.initIDs");
//        moreSafeCodeToIgnore.add("sun.security.util.Debug.isOn");
//        moreSafeCodeToIgnore.add("java.io.ObjectStreamClass.initNative");
//        moreSafeCodeToIgnore.add("java.lang.Class.isAssignableFrom");
//        moreSafeCodeToIgnore.add("java.lang.Object.notifyAll");
//        moreSafeCodeToIgnore.add("java.lang.reflect.Proxy.isProxyClass");
//        moreSafeCodeToIgnore.add("java.io.ObjectStreamClass.hasStaticInitializer");
//        moreSafeCodeToIgnore.add("java.lang.System.identityHashCode");
//        moreSafeCodeToIgnore.add("java.lang.String.endsWith");
//        moreSafeCodeToIgnore.add("java.io.FileOutputStream.initIDs");
//        moreSafeCodeToIgnore.add("java.net.InetAddress.init");
//        moreSafeCodeToIgnore.add("java.lang.Object.wait");
//        moreSafeCodeToIgnore.add("java.net.InetAddressImplFactory.isIPv6Supported");
//        moreSafeCodeToIgnore.add("java.lang.System.registerNatives");
//        moreSafeCodeToIgnore.add("java.lang.System.setIn0");
//        moreSafeCodeToIgnore.add("java.lang.System.setOut0");
//        moreSafeCodeToIgnore.add("java.lang.System.setErr0");
//        moreSafeCodeToIgnore.add("sun.net.InetAddressCachePolicy.setIfNotSet");
//        moreSafeCodeToIgnore.add("java.lang.System.initProperties");
//        moreSafeCodeToIgnore.add("java.lang.System.currentTimeMillis");
//        moreSafeCodeToIgnore.add("sun.misc.Version.init");
//        moreSafeCodeToIgnore.add("sun.misc.VM.maxDirectMemory");
//        moreSafeCodeToIgnore.add("n.misc.VM.booted");
//        moreSafeCodeToIgnore.add("java.lang.String.indexOf");
//        moreSafeCodeToIgnore.add("java.lang.Thread.registerNatives");
//        moreSafeCodeToIgnore.add("java.lang.Thread.sleep");
//        moreSafeCodeToIgnore.add("java.lang.Thread.isInterrupted");
//        moreSafeCodeToIgnore.add("java.lang.String.charAt");
//        moreSafeCodeToIgnore.add("java.lang.Thread.start");
//        moreSafeCodeToIgnore.add("sun.misc.SoftCache.remove");
//        moreSafeCodeToIgnore.add("java.net.Inet4Address.init");
//        moreSafeCodeToIgnore.add("java.net.Inet6Address.init");
//        moreSafeCodeToIgnore.add("java.lang.String.equals");
//        moreSafeCodeToIgnore.add("java.lang.String.equalsIgnoreCase");
//        moreSafeCodeToIgnore.add("java.util.zip.Inflater.initIDs");
//        moreSafeCodeToIgnore.add("java.util.zip.Inflater.init");
//        moreSafeCodeToIgnore.add("java.io.Win32FileSystem.initIDs");
//        moreSafeCodeToIgnore.add("java.util.zip.ZipEntry.initIDs");
//        moreSafeCodeToIgnore.add("sun.misc.VM.isBooted");
//        moreSafeCodeToIgnore.add("java.lang.Shutdown.runAllFinalizers");
//        moreSafeCodeToIgnore.add("java.lang.Shutdown.halt");
//        moreSafeCodeToIgnore.add("java.util.zip.Deflater.initIDs");
//        moreSafeCodeToIgnore.add("java.util.zip.ZipFile.initIDs");
//        moreSafeCodeToIgnore.add("java.lang.Throwable.fillInStackTrace");
//        moreSafeCodeToIgnore.add("java.lang.Throwable.getStackTraceDepth");
//        moreSafeCodeToIgnore.add("sun.reflect.Reflection.quickCheckMemberAccess");
//        moreSafeCodeToIgnore.add("java.lang.ClassLoader.isAncestor");
//        moreSafeCodeToIgnore.add("java.lang.String.lastIndexOf");
//        moreSafeCodeToIgnore.add("java.lang.Class.isArray");
//        moreSafeCodeToIgnore.add("java.lang.Class.isPrimitive");
//        moreSafeCodeToIgnore.add("java.lang.String.hashCode");
//        moreSafeCodeToIgnore.add("java.lang.String.compareTo");
//        moreSafeCodeToIgnore.add("java.lang.String.startsWith");
//        moreSafeCodeToIgnore.add("java.lang.String.indexOf");
//        moreSafeCodeToIgnore.add("java.lang.Runtime.gc");
//        moreSafeCodeToIgnore.add("java.lang.Thread.interrupt0");
//        moreSafeCodeToIgnore.add("java.lang.Thread.setPriority0");
//        moreSafeCodeToIgnore.add("java.lang.Thread.isAlive");
//        moreSafeCodeToIgnore.add("java.lang.String.regionMatches");
//        moreSafeCodeToIgnore.add("java.lang.Runtime.runFinalization0");
//        moreSafeCodeToIgnore.add("java.lang.ClassLoader.loadLibrary");
//        moreSafeCodeToIgnore.add("java.lang.Object.equals");        
//        moreSafeCodeToIgnore.add("sun.security.action.LoadLibraryAction.run");
//        moreSafeCodeToIgnore.add("sun.security.provider.SecureRandom.engineSetSeed");
//        moreSafeCodeToIgnore.add("sun.security.provider.SecureRandom.engineNextBytes");
//        
//        safeCodeToIgnore.put("java.lang.Object",
//                             Arrays.asList(new String[] {
//                                     "Object",
//                                     "hashCode",
//                                     "toString"
//                             }));
//        safeCodeToIgnore.put("java.lang.System",
//                             Arrays.asList(new String[] {
//                                     "exit",
//                             }));
//        safeCodeToIgnore.put("java.lang.Throwable",
//                             Arrays.asList(new String[] {
//                                     "printStackTrace",
//                             }));
//        safeCodeToIgnore.put("java.lang.String",
//                             Arrays.asList(new String[] {
//                                     "length",
//                                     "toString",
//                             }));
//        safeCodeToIgnore.put("java.lang.Math",
//                             Arrays.asList(new String[] {
//                                     "ceil",
//                                     "round",
//                             }));
//        safeCodeToIgnore.put("sun.misc.AtomicLong",
//                             Arrays.asList(new String[] {
//                                     "attemptSet",
//                             }));
//        safeCodeToIgnore.put("java.lang.IllegalArgumentException",
//                             Arrays.asList(new String[] {
//                                     "IllegalArgumentException",
//                             }));
//        safeCodeToIgnore.put("java.lang.NullPointerException",
//                             Arrays.asList(new String[] {
//                                     "NullPointerException",
//                             }));
//        safeCodeToIgnore.put("java.lang.ClassCastException",
//                             Arrays.asList(new String[] {
//                                     "ClassCastException",
//                             }));
//        safeCodeToIgnore.put("java.lang.IndexOutOfBoundsException",
//                             Arrays.asList(new String[] {
//                                     "IndexOutOfBoundsException",
//                             }));
//        safeCodeToIgnore.put("java.lang.RuntimeException",
//                             Arrays.asList(new String[] {
//                                     "RuntimeException",
//                             }));
//        safeCodeToIgnore.put("java.math.BigInteger",
//                             Arrays.asList(new String[] {
//                                     "bitLength",
//                                     "compareTo",
//                             }));
//        safeCodeToIgnore.put("java.util.Vector",
//                             Arrays.asList(new String[] {
//                                     "size",
//                             }));
//    }
//    
//    public static LibraryPointsToSignature getSignatureForMissingCode(MethodInstance mi) {
//        String container = mi.container().toClass().fullName();
//        String name = mi.name();
//        
//        if ("java.io.FileSystem".equals(container)) {
//            if ("getFileSystem".equals(name)) {
//                return new Singleton("java.io.FileSystem.getFileSystem", "java.io.Win32FileSystem");
//            }
//        }
//        if ("java.lang.Thread".equals(container)) {
//            if ("currentThread".equals(name)) {
//                return new Singleton("java.lang.Thread.currentThread", "java.lang.Thread"); // unsound if user code creates thread! Could make it sound with more effort.
//            }
//        }
//        if ("java.lang.Class".equals(container)) {
//            if ("getPrimitiveClass".equals(name)) {
//                return new Singleton("java.lang.Class-primitives", "java.lang.Class");
//            }
//            if ("forName0".equals(name)) {
//                return new Singleton("java.lang.Class", "java.lang.Class");
//            }
//            if ("getClassLoader0".equals(name)) {
//                return new Singleton("java.lang.ClassLoader", "java.lang.ClassLoader");
//            }
//            if ("getName0".equals(name)) {
//                return new Singleton("java.lang.Class.getName0", "java.lang.String");
//            }
//            if ("getDeclaredFields0".equals(name)) {
//                return new SingletonArray("java.lang.Class.getDeclaredFields0", "java.lang.reflect.Field");
//            }
//            if ("getDeclaredMethods0".equals(name)) {
//                return new SingletonArray("java.lang.Class.getDeclaredMethods0", "java.lang.reflect.Method");
//            }
//            if ("getDeclaredConstructors0".equals(name)) {
//                return new SingletonArray("java.lang.Class.getDeclaredConstructors0", "java.lang.reflect.Constructor");
//            }
//            if ("getDeclaredClasses0".equals(name)) {
//                return new SingletonArray("java.lang.Class.getDeclaredClasses0", "java.lang.Class");
//            }
//
//        }
//        if ("java.lang.Object".equals(container)) {
//            if ("getClass".equals(name)) {
//                return new Singleton("java.lang.Class", "java.lang.Class");
//            }
//        }
//        if ("java.lang.String".equals(container)) {
//            if ("replace".equals(name) ||
//                    "trim".equals(name) ||
//                    "toLowerCase".equals(name) ||
//                    "toUpperCase".equals(name) ||
//                    "substring".equals(name)) {
//                return new ReturnsReceiver();
//            }
//            if ("valueOf".equals(name)) {
//                return new AllocatorOrReceiver(mi.typeSystem(), "java.lang.String", true);
//            }
//            if ("toCharArray".equals(name)) {
//                return new AllocatorOrReceiver(mi.typeSystem(), "char[]", false);
//            }
//            //      if ("getBytes".equals(name)) {
//            //          return new ArrayAllocator("byte");
//            //      }
//        }
//        if ("java.lang.ClassLoader".equals(container)) {
//            if ("getCallerClassLoader".equals(name)) {
//                return new Singleton("java.lang.ClassLoader", "java.lang.ClassLoader");
//            }
//            if ("getSystemClassLoader".equals(name)) {
//                return new Singleton("java.lang.ClassLoader", "java.lang.ClassLoader");
//            }
//        }
//        if ("sun.misc.AtomicLong".equals(container)) {
//            if ("newAtomicLong".equals(name)) {
//                return new Singleton("sun.misc.AtomicLong", "sun.misc.AtomicLong");
//            }
//        }
//
//        if ("java.lang.System".equals(container)) {
//            if ("arraycopy".equals(name)) {
//                return new ArrayCopy();
//            }
//        }
//        if ("java.security.AccessController".equals(container)) {
//            if ("doPrivileged".equals(name)) {
//                // all this does is call the run method of the first argument.
//                List l = ((ClassType)mi.formalTypes().get(0)).methodsNamed("run");
//                if (l.size() != 1) {
//                    throw new InternalCompilerError("No run method! " + mi.formalTypes().get(0));
//                }
//                MethodInstance runMeth = (MethodInstance)l.get(0);
//                return new InvokeMethodOfArg(runMeth, 0);
//            }
//        }
//        if ("sun.security.action.GetPropertyAction".equals(container)) {
//            if ("run".equals(name)) {
//                // finds and returns a string
//                return new AllocatorOrReceiver(mi.typeSystem(), "java.lang.String", false);
//            }
//        }
//        if ("sun.security.provider.SecureRandom".equals(container)) {
//            if ("engineGenerateSeed".equals(name)) {
//                // creates a new byte array
//                return new AllocatorOrReceiver(mi.typeSystem(), "byte[]", false);
//            }
//        }
//        
//        if ("java.io.BufferedReader".equals(container)) {
//            if ("readLine".equals(name) && mi.formalTypes().isEmpty()) {
//                return new AllocatorOrReceiver(mi.typeSystem(), "java.lang.String", false);
//            }
//        }
//
//        
//        return null;
//    }
//    
//    public static LibraryPointsToSignature getSignatureForMissingCode(ConstructorInstance ci) {
//        String container = ci.container().toClass().fullName();
//                
//        if ("java.lang.Integer".equals(container)) {
//            return NOOP;
//        }
//        if ("java.lang.String".equals(container)) {
//            return NOOP;
//        }
//        if ("java.lang.Exception".equals(container)) {
//            return NOOP;
//        }
//        if ("sun.security.action.GetBooleanAction".equals(container)) {
//            return NOOP;
//        }
//        if ("sun.security.action.GetPropertyAction".equals(container)) {
//            return NOOP;
//        }
//        if ("sun.security.provider.SecureRandom".equals(container)) {
//            return NOOP;
//        }
//        if ("sun.security.provider.Sun".equals(container)) {
//            return NOOP;
//        }
//        if ("java.io.InputStreamReader".equals(container)) {
//            if (ci.formalTypes().size() == 1) {
//                if (((Type)ci.formalTypes().get(0)).toClass().fullName().equals("java.io.InputStream")) {
//                    // it is new java.io.InputStreamReader(java.io.InputStream)
//                    try {
//                        return new AssignsArgToField("java.io.InputStream", 
//                                                     ci.typeSystem().typeForName("java.io.InputStream"), 
//                                                     0);
//                    }
//                    catch (SemanticException e) {
//                        throw new InternalCompilerError(e);
//                    }
//                }
//            }
//        }
//        if ("java.io.BufferedReader".equals(container)) {
//            if (ci.formalTypes().size() == 1) {
//                if (((Type)ci.formalTypes().get(0)).toClass().fullName().equals("java.io.Reader")) {
//                    try {
//                        return new AssignsArgToField("java.io.Reader", 
//                                                     ci.typeSystem().typeForName("java.io.Reader"), 
//                                                     0);
//                    }
//                    catch (SemanticException e) {
//                        throw new InternalCompilerError(e);
//                    }
//                }
//            }
//        }
//        
//        
//
//        return null;
//    }
//
//    /**
//     * Returns a singleton.
//     */
//    private static class Singleton extends LibraryPointsToSignature {
//        static Map<String, AllocSiteNode> singletons = new HashMap();
//        private final String id;
//        private final String type;
//        
//        public Singleton(String id, String type) {
//            this.id = id;
//            this.type = type;
//        }
//
//        public boolean process(CodeDecl caller, ObjectName callerContext,
//                ProcedureInstance mi, List<PointsToGraphNodeO> args,
//                ObjectName receiver,
//                PointsToGraphNodeO result,
//                List<ExceptionHandlerPointsToGraphNode> handlers,
//                Map<Type, PointsToGraphNodeO> procThrows,
//                StmtRegistrar stmtRegistrar, PointsToGraph g,
//                Position origin) throws SemanticException{
//            
//            AllocSiteNode s = singletons.get(id);
//            if (s == null) {
//                s = new AllocSiteNode(mi.typeSystem().typeForName(type),
//                                      true,
//                                      "singleton-for-"+type);
//                singletons.put(id, s);
//            }
//            if (result == null) return false;
//            return g.addEdge(result, 
//                             callerContext.pushAllocSite(s), origin);
//            
//        }
//    }
//    
//    private static class AssignsArgToField extends LibraryPointsToSignature {
//        public AssignsArgToField(String fieldname, Type fieldType, int argIndex) {
//            this.fieldname = fieldname;
//            this.fieldType = fieldType;
//            this.argIndex = argIndex;
//        }
//
//        final String fieldname;
//        final Type fieldType;
//        final int argIndex;
//        
//        public boolean process(CodeDecl caller, ObjectName callerContext,
//                ProcedureInstance mi, List<PointsToGraphNodeO> args,
//                ObjectName receiver,
//                PointsToGraphNodeO result,
//                List<ExceptionHandlerPointsToGraphNode> handlers,
//                Map<Type, PointsToGraphNodeO> procThrows,
//                StmtRegistrar stmtRegistrar, PointsToGraph g,
//                Position origin) throws SemanticException{
//            
//            PointsToGraphNodeOF node = PointsToGraphNodeOF.create(receiver, fieldname, fieldType);
//
//            // read the node to record a dependency
//            g.pointsTo(node);
//
//            return g.addEdge(node, args.get(argIndex).context, origin);
//            
//        }        
//    }
//    
//    /**
//     * Returns a singleton array, containing an element of the specified type.
//     */
//    private static class SingletonArray extends LibraryPointsToSignature {
//        static Map<String, AllocSiteNode> arraySingletons = new HashMap();
//        static Map<String, AllocSiteNode> arrayContentsSingletons = new HashMap();
//        private final String id;
//        private final String type;
//        
//        public SingletonArray(String id, String type) {
//            this.id = id;
//            this.type = type;
//        }
//
//        public boolean process(CodeDecl caller, ObjectName callerContext,
//                ProcedureInstance mi, List<PointsToGraphNodeO> args,
//                ObjectName receiver,
//                PointsToGraphNodeO result,
//                List<ExceptionHandlerPointsToGraphNode> handlers,
//                Map<Type, PointsToGraphNodeO> procThrows,
//                StmtRegistrar stmtRegistrar, PointsToGraph g,
//                Position origin) throws SemanticException{
//            
//            if (result == null) return false;
//
//            AllocSiteNode s = arraySingletons.get(id);
//            TypeSystem ts = mi.typeSystem();
//            Type baseType = ts.typeForName(type);
//            if (s == null) {
//                s = new AllocSiteNode(ts.arrayOf(baseType),
//                                      true,
//                                      "array-singleton-for-"+type);
//                arraySingletons.put(id, s);
//            }
//            AllocSiteNode t = arrayContentsSingletons.get(id);
//            if (t == null) {
//                t = new AllocSiteNode(baseType,
//                                      true,
//                                      "array-singleton-contents-for-"+type);
//                arrayContentsSingletons.put(id, s);
//            }
//            PointsToGraphNodeOF node = PointsToGraphNodeOF.create(callerContext.pushAllocSite(s), StmtRegistrar.ARRAY_CONTENTS, baseType);
//            boolean changed = g.addEdge(node, 
//                                        callerContext.pushAllocSite(t),
//                                        origin);
//            // read the node to record a dependency
//            g.pointsTo(node);
//            
//            return g.addEdge(result, 
//                             callerContext.pushAllocSite(s), origin) || changed;
//            
//        }
//    }
//    
//
//    /**
//     * Returns a new node, and also the receiver.
//     */
//    private static class AllocatorOrReceiver extends LibraryPointsToSignature {
//        private final String allocatedType;
//        private final boolean mayReturnReceiver;
//        private final AllocSiteNode allocSite;
//        
//        public AllocatorOrReceiver(TypeSystem ts, String allocatedType, boolean mayReturnReceiver) {
//            this.allocatedType = allocatedType;
//            this.mayReturnReceiver = mayReturnReceiver;                 
//            try {
//                this.allocSite = new AllocSiteNode(typeForName(ts, allocatedType),
//                                           false,
//                                           "allcatorOrReceiver");
//            }
//            catch (SemanticException e) {
//                throw new InternalCompilerError("Unexpected", e);
//            }
//        }
//        
//        private static Type typeForName(TypeSystem ts, String s) throws SemanticException {
//            if (s.endsWith("[]")) {
//                Type t = typeForName(ts, s.substring(0, s.length()-2));
//                return ts.arrayOf(t);
//            }
//            if (s.contains(".")) {
//                return ts.typeForName(s);                
//            }
//            else {
//                return ts.primitiveForName(s);
//            }
//        }
//
//        public boolean process(CodeDecl caller, ObjectName callerContext,
//                ProcedureInstance mi, List<PointsToGraphNodeO> args,
//                ObjectName receiver,
//                PointsToGraphNodeO result,
//                List<ExceptionHandlerPointsToGraphNode> handlers,
//                Map<Type, PointsToGraphNodeO> procThrows,
//                StmtRegistrar stmtRegistrar, PointsToGraph g,
//                Position origin) throws SemanticException{
//            
//            if (result == null) return false;
//            boolean changed = g.addEdge(result, 
//                                        callerContext.pushAllocSite(allocSite), origin);
//            if (receiver != null && mayReturnReceiver) {
//                changed = g.addEdge(result, receiver, origin) || changed;
//            }
//            
//            return changed;
//            
//        }
//    }
//
//    /**
//     * Returns a new node, and also the receiver.
//     */
//    private static class ReturnsReceiver extends LibraryPointsToSignature {
//        
//        public ReturnsReceiver() {
//        }
//
//        public boolean process(CodeDecl caller, ObjectName callerContext,
//                ProcedureInstance mi, List<PointsToGraphNodeO> args,
//                ObjectName receiver,
//                PointsToGraphNodeO result,
//                List<ExceptionHandlerPointsToGraphNode> handlers,
//                Map<Type, PointsToGraphNodeO> procThrows,
//                StmtRegistrar stmtRegistrar, PointsToGraph g,
//                Position origin) throws SemanticException{
//            
//            if (result == null) return false;
//            if (receiver != null) {
//                return g.addEdge(result, receiver, origin);
//            }
//            
//            return false;
//            
//        }
//    }
//
//    private static LibraryPointsToSignature NOOP = new LibraryPointsToSignature() {
//        public boolean process(CodeDecl caller, ObjectName callerContext,
//                ProcedureInstance mi, List<PointsToGraphNodeO> args,
//                ObjectName receiver,
//                PointsToGraphNodeO result,
//                List<ExceptionHandlerPointsToGraphNode> handlers,
//                Map<Type, PointsToGraphNodeO> procThrows,
//                StmtRegistrar stmtRegistrar, PointsToGraph g,
//                Position origin) throws SemanticException{
//            
//            return false;            
//        }
//    };
//    
//    private static class InvokeMethodOfArg extends LibraryPointsToSignature {
//        final MethodInstance invokeMethod;
//        final int argNum;
//        InvokeMethodOfArg(MethodInstance invokeMethod, int argNum) {
//            this.invokeMethod = invokeMethod;
//            this.argNum = argNum;
//        }
//        public boolean process(CodeDecl caller, ObjectName callerContext,
//                ProcedureInstance mi, List<PointsToGraphNodeO> args,
//                ObjectName receiver,
//                PointsToGraphNodeO result,
//                List<ExceptionHandlerPointsToGraphNode> handlers,
//                Map<Type, PointsToGraphNodeO> procThrows,
//                StmtRegistrar stmtRegistrar, PointsToGraph g, Position origin)
//                throws SemanticException {
//            
//            
//            
//            return StmtVirtualMethodCall.process(result,
//                                                 args.get(0),
//                                                 invokeMethod,
//                                                 (List<PointsToGraphNodeO>)Collections.EMPTY_LIST,
//                                                 handlers, 
//                                                 procThrows,
//                                                 caller,
//                                                 callerContext,
//                                                 g, 
//                                                 stmtRegistrar, 
//                                                 origin);
//        }
//        
//    }
//    /**
//     * Implements java.lang.System.arrayCopy(Object src,  int  srcPos,
//                                        Object dest, int destPos,
//                                        int length)
//     */
//    private static class ArrayCopy extends LibraryPointsToSignature {
//        public boolean process(CodeDecl caller, ObjectName callerContext,
//                ProcedureInstance mi, List<PointsToGraphNodeO> args,
//                ObjectName receiver,
//                PointsToGraphNodeO result,
//                List<ExceptionHandlerPointsToGraphNode> handlers,
//                Map<Type, PointsToGraphNodeO> procThrows,
//                StmtRegistrar stmtRegistrar, PointsToGraph g, Position origin)
//                throws SemanticException {
//            PointsToGraphNodeO src = args.get(0); 
//            PointsToGraphNodeO dest = args.get(1); // primitives aren't added to the list of args.
//
//            // fake a dest.contents = src.contents
//            // should be like a t = src.contents,  dest.contents = t
//            //
//
//
//            if (Report.should_report(AnalysisTopics.POINTSTO, 3))
//                Report.report(3, "Processing array copy");
//
//            Set<ObjectName> trgs = new HashSet();
//            for (ObjectName j : g.pointsTo(src)) {
//                PointsToGraphNodeOF jn = PointsToGraphNodeOF.create(j, StmtRegistrar.ARRAY_CONTENTS, src.expectedType().toArray().base());
//                for (ObjectName i : g.pointsTo(jn)) {
//                    trgs.add(i);
//                }
//            }
//
//            boolean changed = false;
//            for (ObjectName i : g.pointsTo(dest)) {
//                PointsToGraphNodeOF node = PointsToGraphNodeOF.create(i, StmtRegistrar.ARRAY_CONTENTS, dest.expectedType().toArray().base());
//                changed = g.addEdges(node, trgs, origin) || changed;
//            }
//
//            return changed;
//        }
//    }

}
