/*
 * 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.analysis.reflection;

import com.ibm.wala.cfg.ControlFlowGraph;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterpreter;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.IRView;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.types.FieldReference;
import java.util.Iterator;

/** {@link SSAContextInterpreter} to handle all reflection procession. */
public class ReflectionContextInterpreter {

  public static SSAContextInterpreter createReflectionContextInterpreter(
      IClassHierarchy cha, AnalysisOptions options, IAnalysisCacheView iAnalysisCacheView) {

    if (options == null) {
      throw new IllegalArgumentException("null options");
    }

    // start with a dummy interpreter that understands nothing
    SSAContextInterpreter result =
        new SSAContextInterpreter() {
          @Override
          public boolean understands(CGNode node) {
            return false;
          }

          @Override
          public boolean recordFactoryType(CGNode node, IClass klass) {
            // TODO Auto-generated method stub
            return false;
          }

          @Override
          public Iterator<NewSiteReference> iterateNewSites(CGNode node) {
            // TODO Auto-generated method stub
            return null;
          }

          @Override
          public Iterator<FieldReference> iterateFieldsWritten(CGNode node) {
            // TODO Auto-generated method stub
            return null;
          }

          @Override
          public Iterator<FieldReference> iterateFieldsRead(CGNode node) {
            // TODO Auto-generated method stub
            return null;
          }

          @Override
          public Iterator<CallSiteReference> iterateCallSites(CGNode node) {
            // TODO Auto-generated method stub
            return null;
          }

          @Override
          public int getNumberOfStatements(CGNode node) {
            // TODO Auto-generated method stub
            return 0;
          }

          @Override
          public IR getIR(CGNode node) {
            // TODO Auto-generated method stub
            return null;
          }

          @Override
          public IRView getIRView(CGNode node) {
            return getIR(node);
          }

          @Override
          public DefUse getDU(CGNode node) {
            // TODO Auto-generated method stub
            return null;
          }

          @Override
          public ControlFlowGraph<SSAInstruction, ISSABasicBlock> getCFG(CGNode n) {
            // TODO Auto-generated method stub
            return null;
          }
        };

    if (options.getReflectionOptions().getNumFlowToCastIterations() > 0) {
      // need the factory bypass interpreter
      result =
          new DelegatingSSAContextInterpreter(
              new FactoryBypassInterpreter(options, iAnalysisCacheView), result);
    }
    if (!options.getReflectionOptions().isIgnoreStringConstants()) {
      result =
          new DelegatingSSAContextInterpreter(
              new GetClassContextInterpeter(),
              new DelegatingSSAContextInterpreter(
                  new DelegatingSSAContextInterpreter(
                      new ClassFactoryContextInterpreter(),
                      new ClassNewInstanceContextInterpreter(cha)),
                  result));
    }
    if (!options.getReflectionOptions().isIgnoreMethodInvoke()) {
      result =
          new DelegatingSSAContextInterpreter(
              new ReflectiveInvocationInterpreter(),
              new DelegatingSSAContextInterpreter(new JavaLangClassContextInterpreter(), result));
    }
    // if NEITHER string constants NOR method invocations are ignored
    if (!options.getReflectionOptions().isIgnoreStringConstants()
        && !options.getReflectionOptions().isIgnoreMethodInvoke()) {
      result = new DelegatingSSAContextInterpreter(new GetMethodContextInterpreter(), result);
    }
    return result;
  }
}
