/* Soot - a Java Optimization Framework
 * Copyright (C) 2012 Michael Markert, Frank Hartmann
 *
 * (c) 2012 University of Luxembourg - Interdisciplinary Centre for
 * Security Reliability and Trust (SnT) - All rights reserved
 * Alexandre Bartel
 *
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
package soot.dexpler;


import java.util.ArrayList;
import java.util.List;

import org.jf.dexlib2.iface.Annotation;
import org.jf.dexlib2.iface.AnnotationElement;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.iface.value.EncodedValue;
import org.jf.dexlib2.iface.value.TypeEncodedValue;

import soot.Body;
import soot.G;
import soot.MethodSource;
import soot.Modifier;
import soot.RefType;
import soot.SootClass;
import soot.SootMethod;
import soot.SootResolver;
import soot.Type;
import soot.jimple.Jimple;
import soot.jimple.toolkits.typing.TypeAssigner;
import soot.options.Options;

/**
 * DexMethod is a container for all methods that are declared in a class.
 * It holds information about its name, the class it belongs to, its access flags, thrown exceptions, the return type and parameter types as well as the encoded method itself.
 *
 */
public class DexMethod {

    private DexMethod() {}

    /**
     * Retrieve the SootMethod equivalent of this method
     * @return the SootMethod of this method
     */
    public static SootMethod makeSootMethod(DexFile dexFile, Method method, SootClass declaringClass) {
        int accessFlags = method.getAccessFlags();
        List<Type> parameterTypes = new ArrayList<Type>();

        // get the name of the method
        String name = method.getName();
        Debug.printDbg("processing method '", method.getDefiningClass() ,": ", method.getReturnType(), " ", method.getName(), " p: ", method.getParameters(), "'");

        // the following snippet retrieves all exceptions that this method throws by analyzing its annotations
        List<SootClass> thrownExceptions = new ArrayList<SootClass>();
        for (Annotation a : method.getAnnotations()) {
            Type atype = DexType.toSoot(a.getType());
            String atypes = atype.toString();
            if (!(atypes.equals("dalvik.annotation.Throws")))
                continue;
            for (AnnotationElement ae : a.getElements()) {
                EncodedValue ev = ae.getValue();
                if(ev instanceof ArrayEncodedValue) {
                    for(EncodedValue evSub : ((ArrayEncodedValue) ev).getValue()) {
                        if(evSub instanceof TypeEncodedValue) {
                            TypeEncodedValue valueType = (TypeEncodedValue) evSub;
                            String exceptionName = valueType.getValue();
                            String dottedName = Util.dottedClassName(exceptionName);
                            thrownExceptions.add(SootResolver.v().makeClassRef(dottedName));
                        }
                    }
                }
            }
        }

        // retrieve all parameter types
        if (method.getParameters() != null) {
            List<? extends CharSequence> parameters = method.getParameterTypes();

            for(CharSequence t : parameters) {
                Type type = DexType.toSoot(t.toString());
                parameterTypes.add(type);
            }
        }

        // retrieve the return type of this method
        Type returnType = DexType.toSoot(method.getReturnType());

        //Build soot method by all available parameters
        SootMethod sm = declaringClass.getMethodUnsafe(name, parameterTypes, returnType);
        if (sm == null) {
            sm = new SootMethod(name, parameterTypes, returnType, accessFlags, thrownExceptions);
        }

        // if the method is abstract or native, no code needs to be transformed
        int flags = method.getAccessFlags();
        if (Modifier.isAbstract(flags)|| Modifier.isNative(flags))
            return sm;

        if (Options.v().oaat() && declaringClass.resolvingLevel() <= SootClass.SIGNATURES)
            return sm;

//        // retrieve all local types of the method
//        DebugInfoItem debugInfo = method.g.codeItem.getDebugInfo();
//        if(debugInfo!=null) {
//			for(Item<?> item : debugInfo.getReferencedItems()) {
//	            if (item instanceof TypeIdItem) {
//	                Type type = DexType.toSoot((TypeIdItem) item);
//	                dexClass.types.add(type);
//	            }
//
//	        }
//        }

        // sets the method source by adding its body as the active body
        sm.setSource(new MethodSource() {
            
        	private DexBody dexBody = null;
        	
            public Body getBody(SootMethod m, String phaseName) {
                Body b = Jimple.v().newBody(m);
                try {
                	if (dexBody == null)
                		dexBody = new DexBody(dexFile, method, (RefType) declaringClass.getType());
                	
                    //add the body of this code item
					dexBody.jimplify(b, m);
                } catch (InvalidDalvikBytecodeException e) {
                    String msg = "Warning: Invalid bytecode in method "+ m +": "+ e;
                    G.v().out.println(msg);
                    Util.emptyBody(b);
                    Util.addExceptionAfterUnit(b, "java.lang.RuntimeException", b.getUnits().getLast(), "Soot has detected that this method contains invalid Dalvik bytecode which would have throw an exception at runtime. ["+ msg +"]");
                    TypeAssigner.v().transform(b);
                }
                m.setActiveBody(b);
                
                return m.getActiveBody();
            }
        });

        return sm;
    }
}

@@ -2156,16 +2156,22 @@
 tMethod(
+final 
 DexFile 
@@ -2178,16 +2178,28 @@
 dexFile,
+%0A    %09%09final
  Method 
@@ -2205,16 +2205,22 @@
  method,
+ final
  SootCla

Fix to make the code compatible with less intelligent compilers