// Path: instrumenter/src/main/java/com/offbynull/coroutines/instrumenter/asm/ClassInformationRepository.java
// public interface ClassInformationRepository {
// 
//     /**
//      * Get information for a class.
//      * <p>
//      * This method returns class information as if it were encountered in a class file. In a class file, if the class is an interface, then
//      * its superclass is set to {@link Object}. Note that this is different from what {@link Class#getSuperclass() } returns when the class
//      * represents an interface (it returns {@code null}).
//      * @param internalClassName internal class name
//      * @throws NullPointerException if any argument is {@code null}
//      * @return information for that class, or {@code null} if not found
//      */
//     ClassInformation getInformation(String internalClassName);
//     
// }


import static com.offbynull.coroutines.instrumenter.InstrumentationState.ControlFlag.NO_INSTRUMENT;
import com.offbynull.coroutines.instrumenter.asm.ClassInformationRepository;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang3.Validate;
/*
 * Copyright (c) 2017, Kasra Faghihi, All rights reserved.
 * 
 * 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 3.0 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.
 */
package com.offbynull.coroutines.instrumenter;


// Analyze what has been marked for instrumentation (more methods may be filtered out here).
final class AnalyzeInstrumentationPass implements InstrumentationPass {

    @Override
    public void pass(ClassNode classNode, InstrumentationState state) {
        Validate.notNull(classNode);
        Validate.notNull(state);



        // Methods to instrument should be identified, but no method attributes should be assigned yet -- this is what this pass does. There
        // must be atleast 1 method to exist (previous pass should have stopped the instrumentation process if not)
        Validate.validState(!state.methodAttributes().isEmpty());
        Validate.validState(state.methodAttributes().keySet().stream().allMatch(x -> x != null));
        Validate.validState(state.methodAttributes().values().stream().allMatch(x -> x == null));

        // Sanity check to make sure that we're only dealing with methodnodes in the classnode -- this should never trigger unless previous
        // passes mess up
        Validate.validState(classNode.methods.containsAll(state.methodAttributes().keySet()));



        // Analyze each method that needs to be instrumented
// Path: instrumenter/src/main/java/com/offbynull/coroutines/instrumenter/asm/ClassInformationRepository.java
// public interface ClassInformationRepository {
// 
//     /**
//      * Get information for a class.
//      * <p>
//      * This method returns class information as if it were encountered in a class file. In a class file, if the class is an interface, then
//      * its superclass is set to {@link Object}. Note that this is different from what {@link Class#getSuperclass() } returns when the class
//      * represents an interface (it returns {@code null}).
//      * @param internalClassName internal class name
//      * @throws NullPointerException if any argument is {@code null}
//      * @return information for that class, or {@code null} if not found
//      */
//     ClassInformation getInformation(String internalClassName);
//     
// }


// Path: instrumenter/src/main/java/com/offbynull/coroutines/instrumenter/AnalyzeInstrumentationPass.java
import static com.offbynull.coroutines.instrumenter.InstrumentationState.ControlFlag.NO_INSTRUMENT;
import com.offbynull.coroutines.instrumenter.asm.ClassInformationRepository;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang3.Validate;

/*
 * Copyright (c) 2017, Kasra Faghihi, All rights reserved.
 * 
 * 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 3.0 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.
 */
package com.offbynull.coroutines.instrumenter;


// Analyze what has been marked for instrumentation (more methods may be filtered out here).
final class AnalyzeInstrumentationPass implements InstrumentationPass {

    @Override
    public void pass(ClassNode classNode, InstrumentationState state) {
        Validate.notNull(classNode);
        Validate.notNull(state);



        // Methods to instrument should be identified, but no method attributes should be assigned yet -- this is what this pass does. There
        // must be atleast 1 method to exist (previous pass should have stopped the instrumentation process if not)
        Validate.validState(!state.methodAttributes().isEmpty());
        Validate.validState(state.methodAttributes().keySet().stream().allMatch(x -> x != null));
        Validate.validState(state.methodAttributes().values().stream().allMatch(x -> x == null));

        // Sanity check to make sure that we're only dealing with methodnodes in the classnode -- this should never trigger unless previous
        // passes mess up
        Validate.validState(classNode.methods.containsAll(state.methodAttributes().keySet()));



        // Analyze each method that needs to be instrumented
        ClassInformationRepository classRepo = state.classInformationRepository();