/*
 * Copyright (c) 2013 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.classLoader;

import com.ibm.wala.analysis.typeInference.PrimitiveType;
import com.ibm.wala.analysis.typeInference.TypeInference;
import com.ibm.wala.cfg.InducedCFG;
import com.ibm.wala.core.util.strings.Atom;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
import com.ibm.wala.ipa.callgraph.impl.AbstractRootMethod;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ipa.modref.ExtendedHeapModel;
import com.ibm.wala.ipa.modref.ModRef;
import com.ibm.wala.ipa.modref.ModRef.RefVisitor;
import com.ibm.wala.shrike.shrikeCT.InvalidClassFileException;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SSALoadMetadataInstruction;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import java.util.Collection;
import java.util.Set;

/**
 * Main interface for language-specific information. This interface helps build analyses which can
 * operate over multiple languages.
 */
public interface Language {

  /** The canonical {@link Language} implementation for Java */
  JavaLanguage JAVA = new JavaLanguage();

  /** What is the name of the language? */
  Atom getName();

  /** If this language is "derived" from some other langauge, which one? */
  Language getBaseLanguage();

  /** Yuck? Languages are mutable? */
  void registerDerivedLanguage(Language l);

  Set<Language> getDerivedLanguages();

  /** What is the root type in a type hierarchy for this language? e.g. java.lang.Object in Java. */
  TypeReference getRootType();

  /** What is the root type of exceptions in this language? e.g. java.lang.Throwable in Java */
  TypeReference getThrowableType();

  /**
   * Given a Java constant o, return the appropriate language type to associate with the constant.
   * Possible types for o can be language dependent, but typically include Boolean, String, Integer,
   * Float, etc.
   */
  TypeReference getConstantType(Object o);

  /** Is t the type of the language's null value? Should return true if {@code t == null} (?). */
  boolean isNullType(TypeReference t);

  boolean isIntType(TypeReference t);

  boolean isLongType(TypeReference t);

  boolean isVoidType(TypeReference t);

  boolean isFloatType(TypeReference t);

  boolean isDoubleType(TypeReference t);

  boolean isStringType(TypeReference t);

  /**
   * Is t a "metadata" type for the language, i.e., a type describing some other type (e.g.,
   * java.lang.Class for Java)?
   */
  boolean isMetadataType(TypeReference t);

  boolean isCharType(TypeReference t);

  boolean isBooleanType(TypeReference t);

  /**
   * Get the representation of the meta-data corresponding to value. For example, in Java, if value
   * represents some type, the returned object should be the corresponding {@link TypeReference}.
   * The returned object should be appropriate for use as the token in an {@link
   * SSALoadMetadataInstruction} for the language
   */
  Object getMetadataToken(Object value);

  /** get the interfaces implemented by all arrays in the language */
  TypeReference[] getArrayInterfaces();

  /**
   * Given a source-level primitive type name, get the corresponding "low-level" type name, e.g.,
   * the corresponding character to use in a Java method descriptor
   */
  TypeName lookupPrimitiveType(String name);

  SSAInstructionFactory instructionFactory();

  /** determine the set of possible exception types a call to target may throw */
  Collection<TypeReference> inferInvokeExceptions(MethodReference target, IClassHierarchy cha)
      throws InvalidClassFileException;

  TypeReference getStringType();

  TypeReference getPointerType(TypeReference pointee);

  /**
   * get the abstraction of a primitive type to be used for type inference
   *
   * @see TypeInference
   */
  PrimitiveType getPrimitive(TypeReference reference);

  /** do MethodReference objects have declared parameter types? */
  boolean methodsHaveDeclaredParameterTypes();

  AbstractRootMethod getFakeRootMethod(
      IClassHierarchy cha, AnalysisOptions options, IAnalysisCacheView cache);

  InducedCFG makeInducedCFG(SSAInstruction[] instructions, IMethod method, Context context);

  boolean modelConstant(Object o);

  <T extends InstanceKey> RefVisitor<T, ? extends ExtendedHeapModel> makeRefVisitor(
      CGNode n, Collection<PointerKey> result, PointerAnalysis<T> pa, ExtendedHeapModel h);

  <T extends InstanceKey> ModRef.ModVisitor<T, ? extends ExtendedHeapModel> makeModVisitor(
      CGNode n,
      Collection<PointerKey> result,
      PointerAnalysis<T> pa,
      ExtendedHeapModel h,
      boolean ignoreAllocHeapDefs);
}
