# Global Metrics

path: .metrics.nargs.average
old: 0.8157894736842105
new: 0.6891891891891891
path: .metrics.nargs.sum
old: 31.0
new: 102.0
path: .metrics.cognitive.average
old: 8.763157894736842
new: 0.10810810810810811
path: .metrics.cognitive.sum
old: 333.0
new: 16.0
path: .metrics.loc.cloc
old: 178.0
new: 98.0
path: .metrics.loc.lloc
old: 440.0
new: 165.0
path: .metrics.loc.blank
old: 159.0
new: 200.0
path: .metrics.loc.sloc
old: 1330.0
new: 1016.0
path: .metrics.loc.ploc
old: 993.0
new: 718.0
path: .metrics.mi.mi_original
old: -51.39169165403017
new: -46.23464614846904
path: .metrics.mi.mi_sei
old: -100.70028528432344
new: -96.8634584270384
path: .metrics.nexits.sum
old: 63.0
new: 81.0
path: .metrics.nexits.average
old: 1.6578947368421053
new: 0.5472972972972973
path: .metrics.nom.functions
old: 38.0
new: 148.0
path: .metrics.nom.total
old: 38.0
new: 148.0
path: .metrics.cyclomatic.average
old: 4.760869565217392
new: 1.1702127659574468
path: .metrics.cyclomatic.sum
old: 219.0
new: 220.0
path: .metrics.halstead.vocabulary
old: 410.0
new: 246.0
path: .metrics.halstead.effort
old: 5180297.318668378
new: 4298536.836314733
path: .metrics.halstead.N1
old: 2867.0
new: 2714.0
path: .metrics.halstead.length
old: 4971.0
new: 4461.0
path: .metrics.halstead.level
old: 0.008328806807894261
new: 0.00824270177447052
path: .metrics.halstead.volume
old: 43145.69557464157
new: 35431.55720831835
path: .metrics.halstead.bugs
old: 9.97964753294615
new: 8.812365748173269
path: .metrics.halstead.time
old: 287794.2954815765
new: 238807.6020174852
path: .metrics.halstead.n1
old: 42.0
new: 30.0
path: .metrics.halstead.estimated_program_length
old: 3363.148131585688
new: 1822.2624183355647
path: .metrics.halstead.difficulty
old: 120.06521739130434
new: 121.31944444444444
path: .metrics.halstead.N2
old: 2104.0
new: 1747.0
path: .metrics.halstead.n2
old: 368.0
new: 216.0
path: .metrics.halstead.purity_ratio
old: 0.6765536374141397
new: 0.408487428454509

# Spaces Data

## Minimal test - lines (19, 1014)

path: .spaces[0].metrics.nargs.average
old: null
new: 0.6891891891891891
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 102.0
path: .spaces[0].metrics.nom.functions
old: 0.0
new: 148.0
path: .spaces[0].metrics.nom.total
old: 0.0
new: 148.0
path: .spaces[0].metrics.mi.mi_visual_studio
old: 73.3099929416517
new: 0.0
path: .spaces[0].metrics.mi.mi_original
old: 125.3600879302244
new: -45.65613729602259
path: .spaces[0].metrics.mi.mi_sei
old: 105.25734504973084
new: -96.8181999773116
path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 219.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.1711229946524064
path: .spaces[0].metrics.cognitive.average
old: null
new: 0.10810810810810811
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 16.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 165.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 90.0
path: .spaces[0].metrics.loc.ploc
old: 5.0
new: 709.0
path: .spaces[0].metrics.loc.sloc
old: 5.0
new: 996.0
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 197.0
path: .spaces[0].metrics.halstead.effort
old: 72.1157937828126
new: 4363051.861823224
path: .spaces[0].metrics.halstead.N2
old: 7.0
new: 1741.0
path: .spaces[0].metrics.halstead.length
old: 13.0
new: 4455.0
path: .spaces[0].metrics.halstead.level
old: 0.5714285714285714
new: 0.008079647712042887
path: .spaces[0].metrics.halstead.bugs
old: 0.005775181940550018
new: 8.90032083409357
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.558820192806954
new: 0.39873370295970184
path: .spaces[0].metrics.halstead.volume
old: 41.209025018750054
new: 35251.92199290448
path: .spaces[0].metrics.halstead.difficulty
old: 1.75
new: 123.76777251184834
path: .spaces[0].metrics.halstead.n2
old: 6.0
new: 211.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: 20.264662506490403
new: 1776.3586466854715
path: .spaces[0].metrics.halstead.n1
old: 3.0
new: 30.0
path: .spaces[0].metrics.halstead.vocabulary
old: 9.0
new: 241.0
path: .spaces[0].metrics.halstead.time
old: 4.0064329879340335
new: 242391.77010129025
path: .spaces[0].metrics.halstead.N1
old: 6.0
new: 2714.0
path: .spaces[0].metrics.nexits.average
old: null
new: 0.5472972972972973
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 81.0

### Code

    namespace mozilla {
    namespace jni {

    // Wrapped object reference (e.g. jobject, jclass, etc...)
    template
    class Ref;
    // Represents a calling context for JNI methods.
    template
    class Context;
    // Wrapped local reference that inherits from Ref.
    template
    class LocalRef;
    // Wrapped global reference that inherits from Ref.
    template
    class GlobalRef;
    // Wrapped weak reference that inherits from Ref.
    template
    class WeakRef;
    // Wrapped dangling reference that's owned by someone else.
    template
    class DependentRef;

    // Class to hold the native types of a method's arguments.
    // For example, if a method has signature (ILjava/lang/String;)V,
    // its arguments class would be jni::Args
    template
    struct Args {};

    class Object;

    // Base class for Ref and its specializations.
    template
    class Ref {
      template
      friend class Ref;

      using Self = Ref;
      using bool_type = void (Self::*)() const;
      void non_null_reference() const {}

      // A Cls-derivative that allows copying
      // (e.g. when acting as a return value).
      struct CopyableCtx : public Context {
        CopyableCtx(JNIEnv* env, Type instance)
            : Context(env, instance) {}

        CopyableCtx(const CopyableCtx& cls)
            : Context(cls.Env(), cls.Get()) {}
      };

      // Private copy constructor so that there's no danger of assigning a
      // temporary LocalRef/GlobalRef to a Ref, and potentially use the Ref
      // after the source had been freed.
      Ref(const Ref&) = default;

     protected:
      static JNIEnv* FindEnv() {
        return Cls::callingThread == CallingThread::GECKO ? GetGeckoThreadEnv()
                                                          : GetEnvForThread();
      }

      Type mInstance;

      // Protected jobject constructor because outside code should be using
      // Ref::From. Using Ref::From makes it very easy to see which code is using
      // raw JNI types for future refactoring.
      explicit Ref(Type instance) : mInstance(instance) {}

     public:
      using JNIType = Type;

      class AutoLock {
        friend class Ref;

        JNIEnv* const mEnv;
        Type mInstance;

        explicit AutoLock(Type aInstance)
            : mEnv(FindEnv()), mInstance(mEnv->NewLocalRef(aInstance)) {
          mEnv->MonitorEnter(mInstance);
          MOZ_CATCH_JNI_EXCEPTION(mEnv);
        }

       public:
        AutoLock(AutoLock&& aOther)
            : mEnv(aOther.mEnv), mInstance(aOther.mInstance) {
          aOther.mInstance = nullptr;
        }

        ~AutoLock() { Unlock(); }

        void Unlock() {
          if (mInstance) {
            mEnv->MonitorExit(mInstance);
            mEnv->DeleteLocalRef(mInstance);
            MOZ_CATCH_JNI_EXCEPTION(mEnv);
            mInstance = nullptr;
          }
        }
      };

      // Construct a Ref form a raw JNI reference.
      static Ref From(JNIType obj) { return Ref(obj); }

      // Construct a Ref form a generic object reference.
      static Ref From(const Ref& obj) {
        return Ref(JNIType(obj.Get()));
      }

      MOZ_IMPLICIT Ref(decltype(nullptr)) : mInstance(nullptr) {}

      // Get the raw JNI reference.
      JNIType Get() const { return mInstance; }

      template
      bool IsInstanceOf() const {
        return FindEnv()->IsInstanceOf(mInstance, typename T::Context().ClassRef());
      }

      template
      typename T::Ref Cast() const {
    #ifdef MOZ_CHECK_JNI
        MOZ_RELEASE_ASSERT(FindEnv()->IsAssignableFrom(
            Context().ClassRef(), typename T::Context().ClassRef()));
    #endif
        return T::Ref::From(*this);
      }

      AutoLock Lock() const { return AutoLock(mInstance); }

      bool operator==(const Ref& other) const {
        // Treat two references of the same object as being the same.
        return mInstance == other.mInstance ||
               JNI_FALSE != FindEnv()->IsSameObject(mInstance, other.mInstance);
      }

      bool operator!=(const Ref& other) const { return !operator==(other); }

      bool operator==(decltype(nullptr)) const { return !mInstance; }

      bool operator!=(decltype(nullptr)) const { return !!mInstance; }

      CopyableCtx operator->() const { return CopyableCtx(FindEnv(), mInstance); }

      CopyableCtx operator*() const { return operator->(); }

      // Any ref can be cast to an object ref.
      operator Ref() const {
        return Ref(mInstance);
      }

      // Null checking (e.g. !!ref) using the safe-bool idiom.
      operator bool_type() const {
        return mInstance ? &Self::non_null_reference : nullptr;
      }

      // We don't allow implicit conversion to jobject because that can lead
      // to easy mistakes such as assigning a temporary LocalRef to a jobject,
      // and using the jobject after the LocalRef has been freed.

      // We don't allow explicit conversion, to make outside code use Ref::Get.
      // Using Ref::Get makes it very easy to see which code is using raw JNI
      // types to make future refactoring easier.

      // operator JNIType() const = delete;
    };

    // Represents a calling context for JNI methods.
    template
    class Context : public Ref {
      using Ref = jni::Ref;

      static jclass sClassRef;  // global reference

     protected:
      JNIEnv* const mEnv;

     public:
      Context() : Ref(nullptr), mEnv(Ref::FindEnv()) {}

      Context(JNIEnv* env, Type instance) : Ref(instance), mEnv(env) {}

      jclass ClassRef() const {
        if (!sClassRef) {
          const jclass cls = GetClassRef(mEnv, Cls::name);
          sClassRef = jclass(mEnv->NewGlobalRef(cls));
          mEnv->DeleteLocalRef(cls);
        }
        return sClassRef;
      }

      JNIEnv* Env() const { return mEnv; }

      template
      bool IsInstanceOf() const {
        return mEnv->IsInstanceOf(Ref::mInstance,
                                  typename T::Context(mEnv, nullptr).ClassRef());
      }

      bool operator==(const Ref& other) const {
        // Treat two references of the same object as being the same.
        return Ref::mInstance == other.Get() ||
               JNI_FALSE != mEnv->IsSameObject(Ref::mInstance, other.Get());
      }

      bool operator!=(const Ref& other) const { return !operator==(other); }

      bool operator==(decltype(nullptr)) const { return !Ref::mInstance; }

      bool operator!=(decltype(nullptr)) const { return !!Ref::mInstance; }

      Cls operator->() const {
        MOZ_ASSERT(Ref::mInstance, "Null jobject");
        return Cls(*this);
      }

      const Context& operator*() const { return *this; }
    };

    template
    jclass Context::sClassRef;

    template
    class ObjectBase {
     protected:
      const jni::Context& mCtx;

      jclass ClassRef() const { return mCtx.ClassRef(); }
      JNIEnv* Env() const { return mCtx.Env(); }
      Type Instance() const { return mCtx.Get(); }

     public:
      using Ref = jni::Ref;
      using Context = jni::Context;
      using LocalRef = jni::LocalRef;
      using GlobalRef = jni::GlobalRef;
      using WeakRef = jni::WeakRef;
      using Param = const Ref&;

      static const CallingThread callingThread = CallingThread::ANY;
      static const char name[];

      explicit ObjectBase(const Context& ctx) : mCtx(ctx) {}

      Cls* operator->() { return static_cast(this); }
    };

    // Binding for a plain jobject.
    class Object : public ObjectBase {
     public:
      explicit Object(const Context& ctx) : ObjectBase(ctx) {}
    };

    // Binding for a built-in object reference other than jobject.
    template
    class TypedObject : public ObjectBase, T> {
     public:
      explicit TypedObject(const Context, T>& ctx)
          : ObjectBase, T>(ctx) {}
    };

    // Binding for a boxed primitive object.
    template
    class BoxedObject : public ObjectBase, jobject> {
     public:
      explicit BoxedObject(const Context, jobject>& ctx)
          : ObjectBase, jobject>(ctx) {}
    };

    template <>
    const char ObjectBase::name[];
    template <>
    const char ObjectBase, jstring>::name[];
    template <>
    const char ObjectBase, jclass>::name[];
    template <>
    const char ObjectBase, jthrowable>::name[];
    template <>
    const char ObjectBase, jobject>::name[];
    template <>
    const char ObjectBase, jobject>::name[];
    template <>
    const char ObjectBase, jobject>::name[];
    template <>
    const char ObjectBase, jobject>::name[];
    template <>
    const char ObjectBase, jobject>::name[];
    template <>
    const char ObjectBase, jobject>::name[];
    template <>
    const char ObjectBase, jobject>::name[];
    template <>
    const char ObjectBase, jobject>::name[];
    template <>
    const char ObjectBase, jbooleanArray>::name[];
    template <>
    const char ObjectBase, jbyteArray>::name[];
    template <>
    const char ObjectBase, jcharArray>::name[];
    template <>
    const char ObjectBase, jshortArray>::name[];
    template <>
    const char ObjectBase, jintArray>::name[];
    template <>
    const char ObjectBase, jlongArray>::name[];
    template <>
    const char ObjectBase, jfloatArray>::name[];
    template <>
    const char ObjectBase, jdoubleArray>::name[];
    template <>
    const char ObjectBase, jobjectArray>::name[];

    // Define bindings for built-in types.
    using String = TypedObject;
    using Class = TypedObject;
    using Throwable = TypedObject;

    using Boolean = BoxedObject;
    using Byte = BoxedObject;
    using Character = BoxedObject;
    using Short = BoxedObject;
    using Integer = BoxedObject;
    using Long = BoxedObject;
    using Float = BoxedObject;
    using Double = BoxedObject;

    using BooleanArray = TypedObject;
    using ByteArray = TypedObject;
    using CharArray = TypedObject;
    using ShortArray = TypedObject;
    using IntArray = TypedObject;
    using LongArray = TypedObject;
    using FloatArray = TypedObject;
    using DoubleArray = TypedObject;
    using ObjectArray = TypedObject;

    namespace detail {

    // See explanation in LocalRef.
    template
    struct GenericObject {
      using Type = Object;
    };
    template <>
    struct GenericObject