Global Metrics

path: .metrics.nargs.sum
old: 0.0
new: 33.0

path: .metrics.nargs.average
old: null
new: 1.65

path: .metrics.mi.mi_visual_studio
old: 42.09570801977544
new: 15.143763880818527

path: .metrics.mi.mi_sei
old: 73.84669056034508
new: -13.494321778142968

path: .metrics.mi.mi_original
old: 71.98366071381601
new: 25.895836236199685

path: .metrics.cognitive.average
old: null
new: 0.7

path: .metrics.cognitive.sum
old: 0.0
new: 14.0

path: .metrics.nom.total
old: 0.0
new: 20.0

path: .metrics.nom.functions
old: 0.0
new: 20.0

path: .metrics.loc.blank
old: 10.0
new: 46.0

path: .metrics.loc.sloc
old: 63.0
new: 251.0

path: .metrics.loc.lloc
old: 0.0
new: 51.0

path: .metrics.loc.cloc
old: 34.0
new: 19.0

path: .metrics.loc.ploc
old: 19.0
new: 186.0

path: .metrics.nexits.sum
old: 0.0
new: 7.0

path: .metrics.nexits.average
old: null
new: 0.35

path: .metrics.halstead.volume
old: 404.01548851040104
new: 7167.22808333876

path: .metrics.halstead.effort
old: 2168.925254108469
new: 337991.38750902785

path: .metrics.halstead.n2
old: 19.0
new: 95.0

path: .metrics.halstead.length
old: 87.0
new: 1047.0

path: .metrics.halstead.N2
old: 34.0
new: 448.0

path: .metrics.halstead.N1
old: 53.0
new: 599.0

path: .metrics.halstead.estimated_program_length
old: 96.22039775975506
new: 710.5748446891873

path: .metrics.halstead.level
old: 0.18627450980392157
new: 0.021205357142857144

path: .metrics.halstead.vocabulary
old: 25.0
new: 115.0

path: .metrics.halstead.difficulty
old: 5.368421052631579
new: 47.1578947368421

path: .metrics.halstead.bugs
old: 0.0558523951959655
new: 1.6173940257702415

path: .metrics.halstead.purity_ratio
old: 1.1059815834454605
new: 0.6786770245359955

path: .metrics.halstead.time
old: 120.49584745047048
new: 18777.299306057103

path: .metrics.halstead.n1
old: 6.0
new: 20.0

path: .metrics.cyclomatic.average
old: 1.0
new: 1.3666666666666667

path: .metrics.cyclomatic.sum
old: 3.0
new: 41.0

Spaces Data

Minimal test - lines (17, 249)

path: .spaces[0].metrics.nom.total
old: 0.0
new: 20.0

path: .spaces[0].metrics.nom.functions
old: 0.0
new: 20.0

path: .spaces[0].metrics.loc.blank
old: 0.0
new: 43.0

path: .spaces[0].metrics.loc.ploc
old: 6.0
new: 178.0

path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 51.0

path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 12.0

path: .spaces[0].metrics.loc.sloc
old: 6.0
new: 233.0

path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.3793103448275863

path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 40.0

path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 14.0

path: .spaces[0].metrics.cognitive.average
old: null
new: 0.7

path: .spaces[0].metrics.halstead.level
old: 0.25925925925925924
new: 0.02036199095022624

path: .spaces[0].metrics.halstead.estimated_program_length
old: 35.161259458730164
new: 670.705340567418

path: .spaces[0].metrics.halstead.time
old: 23.788541045192737
new: 19260.819716706133

path: .spaces[0].metrics.halstead.difficulty
old: 3.857142857142857
new: 49.111111111111114

path: .spaces[0].metrics.halstead.N1
old: 21.0
new: 599.0

path: .spaces[0].metrics.halstead.N2
old: 9.0
new: 442.0

path: .spaces[0].metrics.halstead.n1
old: 6.0
new: 20.0

path: .spaces[0].metrics.halstead.purity_ratio
old: 1.1720419819576722
new: 0.6442894722069338

path: .spaces[0].metrics.halstead.bugs
old: 0.01893675761448613
new: 1.645041756242558

path: .spaces[0].metrics.halstead.n2
old: 7.0
new: 90.0

path: .spaces[0].metrics.halstead.vocabulary
old: 13.0
new: 110.0

path: .spaces[0].metrics.halstead.effort
old: 428.1937388134693
new: 346694.7549007104

path: .spaces[0].metrics.halstead.volume
old: 111.01319154423275
new: 7059.395461779171

path: .spaces[0].metrics.halstead.length
old: 30.0
new: 1041.0

path: .spaces[0].metrics.nexits.average
old: null
new: 0.35

path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 7.0

path: .spaces[0].metrics.mi.mi_original
old: 117.25332160614748
new: 27.41018062171125

path: .spaces[0].metrics.mi.mi_sei
old: 93.56175347633943
new: -14.86466996308993

path: .spaces[0].metrics.mi.mi_visual_studio
old: 68.56919392172367
new: 16.029345392813596

path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 33.0

path: .spaces[0].metrics.nargs.average
old: null
new: 1.65

Code

namespace mozilla {
namespace jni {

namespace detail {

// Helper class to convert an arbitrary type to a jvalue, e.g. Value(123).val.
struct Value {
  explicit Value(jboolean z) { val.z = z; }
  explicit Value(jbyte b) { val.b = b; }
  explicit Value(jchar c) { val.c = c; }
  explicit Value(jshort s) { val.s = s; }
  explicit Value(jint i) { val.i = i; }
  explicit Value(jlong j) { val.j = j; }
  explicit Value(jfloat f) { val.f = f; }
  explicit Value(jdouble d) { val.d = d; }
  explicit Value(jobject l) { val.l = l; }

  jvalue val;
};

}  // namespace detail

using namespace detail;

// Base class for Method<>, Field<>, and Constructor<>.
class Accessor {
  static void GetNsresult(JNIEnv* env, nsresult* rv) {
    if (env->ExceptionCheck()) {
#ifdef MOZ_CHECK_JNI
      env->ExceptionDescribe();
#endif
      env->ExceptionClear();
      *rv = NS_ERROR_FAILURE;
    } else {
      *rv = NS_OK;
    }
  }

 protected:
  // Called after making a JNIEnv call.
  template 
  static void EndAccess(const typename Traits::Owner::Context& ctx,
                        nsresult* rv) {
    if (Traits::exceptionMode == ExceptionMode::ABORT) {
      MOZ_CATCH_JNI_EXCEPTION(ctx.Env());

    } else if (Traits::exceptionMode == ExceptionMode::NSRESULT) {
      GetNsresult(ctx.Env(), rv);
    }
  }
};

// Member<> is used to call a JNI method given a traits class.
template 
class Method : public Accessor {
  typedef Accessor Base;
  typedef typename Traits::Owner::Context Context;

 protected:
  static jmethodID sID;

  static void BeginAccess(const Context& ctx) {
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
    static_assert(Traits::dispatchTarget == DispatchTarget::CURRENT,
                  "Dispatching not supported for method call");

    if (sID) {
      return;
    }

    if (Traits::isStatic) {
      MOZ_ALWAYS_TRUE(
          sID = AndroidBridge::GetStaticMethodID(
              ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature));
    } else {
      MOZ_ALWAYS_TRUE(
          sID = AndroidBridge::GetMethodID(ctx.Env(), ctx.ClassRef(),
                                           Traits::name, Traits::signature));
    }
  }

  static void EndAccess(const Context& ctx, nsresult* rv) {
    return Base::EndAccess(ctx, rv);
  }

 public:
  template 
  static ReturnType Call(const Context& ctx, nsresult* rv,
                         const Args&... args) {
    JNIEnv* const env = ctx.Env();
    BeginAccess(ctx);

    jvalue jargs[] = {Value(TypeAdapter::FromNative(env, args)).val...};

    auto result = TypeAdapter::ToNative(
        env, Traits::isStatic ? (env->*TypeAdapter::StaticCall)(
                                    ctx.ClassRef(), sID, jargs)
                              : (env->*TypeAdapter::Call)(
                                    ctx.Get(), sID, jargs));

    EndAccess(ctx, rv);
    return result;
  }
};

// Define sID member.
template 
jmethodID Method::sID;

// Specialize void because C++ forbids us from
// using a "void" temporary result variable.
template 
class Method : public Method {
  typedef Method Base;
  typedef typename Traits::Owner::Context Context;

 public:
  template 
  static void Call(const Context& ctx, nsresult* rv, const Args&... args) {
    JNIEnv* const env = ctx.Env();
    Base::BeginAccess(ctx);

    jvalue jargs[] = {Value(TypeAdapter::FromNative(env, args)).val...};

    if (Traits::isStatic) {
      env->CallStaticVoidMethodA(ctx.ClassRef(), Base::sID, jargs);
    } else {
      env->CallVoidMethodA(ctx.Get(), Base::sID, jargs);
    }

    Base::EndAccess(ctx, rv);
  }
};

// Constructor<> is used to construct a JNI instance given a traits class.
template 
class Constructor : protected Method {
  typedef typename Traits::Owner::Context Context;
  typedef typename Traits::ReturnType ReturnType;
  typedef Method Base;

 public:
  template 
  static ReturnType Call(const Context& ctx, nsresult* rv,
                         const Args&... args) {
    JNIEnv* const env = ctx.Env();
    Base::BeginAccess(ctx);

    jvalue jargs[] = {Value(TypeAdapter::FromNative(env, args)).val...};

    auto result = TypeAdapter::ToNative(
        env, env->NewObjectA(ctx.ClassRef(), Base::sID, jargs));

    Base::EndAccess(ctx, rv);
    return result;
  }
};

// Field<> is used to access a JNI field given a traits class.
template 
class Field : public Accessor {
  typedef Accessor Base;
  typedef typename Traits::Owner::Context Context;
  typedef typename Traits::ReturnType GetterType;
  typedef typename Traits::SetterType SetterType;

 private:
  static jfieldID sID;

  static void BeginAccess(const Context& ctx) {
    MOZ_ASSERT_JNI_THREAD(Traits::callingThread);
    static_assert(Traits::dispatchTarget == DispatchTarget::CURRENT,
                  "Dispatching not supported for field access");

    if (sID) {
      return;
    }

    if (Traits::isStatic) {
      MOZ_ALWAYS_TRUE(
          sID = AndroidBridge::GetStaticFieldID(
              ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature));
    } else {
      MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetFieldID(ctx.Env(), ctx.ClassRef(),
                                                      Traits::name,
                                                      Traits::signature));
    }
  }

  static void EndAccess(const Context& ctx, nsresult* rv) {
    return Base::EndAccess(ctx, rv);
  }

 public:
  static GetterType Get(const Context& ctx, nsresult* rv) {
    JNIEnv* const env = ctx.Env();
    BeginAccess(ctx);

    auto result = TypeAdapter::ToNative(
        env, Traits::isStatic
                 ?

                 (env->*TypeAdapter::StaticGet)(ctx.ClassRef(), sID)
                 :

                 (env->*TypeAdapter::Get)(ctx.Get(), sID));

    EndAccess(ctx, rv);
    return result;
  }

  static void Set(const Context& ctx, nsresult* rv, SetterType val) {
    JNIEnv* const env = ctx.Env();
    BeginAccess(ctx);

    if (Traits::isStatic) {
      (env->*TypeAdapter::StaticSet)(
          ctx.ClassRef(), sID, TypeAdapter::FromNative(env, val));
    } else {
      (env->*TypeAdapter::Set)(
          ctx.Get(), sID, TypeAdapter::FromNative(env, val));
    }

    EndAccess(ctx, rv);
  }
};

// Define sID member.
template 
jfieldID Field::sID;

}  // namespace jni
}  // namespace mozilla