Global Metrics
path: .metrics.cyclomatic.average
old: 1.0
new: 3.25
path: .metrics.cyclomatic.sum
old: 6.0
new: 39.0
path: .metrics.loc.ploc
old: 175.0
new: 184.0
path: .metrics.loc.lloc
old: 0.0
new: 72.0
path: .metrics.loc.sloc
old: 254.0
new: 260.0
path: .metrics.loc.blank
old: 10.0
new: 42.0
path: .metrics.loc.cloc
old: 69.0
new: 34.0
path: .metrics.nom.functions
old: 0.0
new: 8.0
path: .metrics.nom.total
old: 0.0
new: 8.0
path: .metrics.halstead.N1
old: 276.0
new: 468.0
path: .metrics.halstead.N2
old: 269.0
new: 325.0
path: .metrics.halstead.volume
old: 4185.316654230468
new: 5356.62578921563
path: .metrics.halstead.n1
old: 12.0
new: 24.0
path: .metrics.halstead.length
old: 545.0
new: 793.0
path: .metrics.halstead.difficulty
old: 8.362694300518134
new: 46.42857142857143
path: .metrics.halstead.bugs
old: 0.356666051511256
new: 1.3182461081405512
path: .metrics.halstead.estimated_program_length
old: 1508.3637582013937
new: 646.9937635307236
path: .metrics.halstead.effort
old: 35000.523730196765
new: 248700.4830707257
path: .metrics.halstead.n2
old: 193.0
new: 84.0
path: .metrics.halstead.vocabulary
old: 205.0
new: 108.0
path: .metrics.halstead.level
old: 0.11957868649318464
new: 0.021538461538461538
path: .metrics.halstead.purity_ratio
old: 2.767639923305309
new: 0.8158811646036868
path: .metrics.halstead.time
old: 1944.473540566487
new: 13816.693503929206
path: .metrics.nexits.average
old: null
new: 2.125
path: .metrics.nexits.sum
old: 0.0
new: 17.0
path: .metrics.mi.mi_visual_studio
old: 21.3746369150271
new: 15.964498231155764
path: .metrics.mi.mi_sei
old: 13.767658759752152
new: -5.776706398536774
path: .metrics.mi.mi_original
old: 36.55062912469634
new: 27.29929197527636
path: .metrics.nargs.average
old: null
new: 1.375
path: .metrics.nargs.sum
old: 0.0
new: 11.0
path: .metrics.cognitive.sum
old: 0.0
new: 37.0
path: .metrics.cognitive.average
old: null
new: 4.625
Spaces Data
Minimal test - lines (16, 260)
path: .spaces[0].metrics.mi.mi_original
old: null
new: 28.66878586436843
path: .spaces[0].metrics.mi.mi_visual_studio
old: null
new: 16.765371850507854
path: .spaces[0].metrics.mi.mi_sei
old: null
new: -5.4660060048984676
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 17.0
path: .spaces[0].metrics.nexits.average
old: null
new: 2.125
path: .spaces[0].metrics.loc.ploc
old: 1.0
new: 177.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 28.0
path: .spaces[0].metrics.loc.sloc
old: 1.0
new: 245.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 71.0
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 40.0
path: .spaces[0].metrics.cognitive.average
old: null
new: 4.625
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 37.0
path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 38.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 3.4545454545454546
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 11.0
path: .spaces[0].metrics.nargs.average
old: null
new: 1.375
path: .spaces[0].metrics.halstead.level
old: null
new: 0.019778481012658226
path: .spaces[0].metrics.halstead.n2
old: 1.0
new: 75.0
path: .spaces[0].metrics.halstead.time
old: 0.0
new: 14543.099523637044
path: .spaces[0].metrics.halstead.volume
old: 0.0
new: 5177.527520282175
path: .spaces[0].metrics.halstead.n1
old: 0.0
new: 24.0
path: .spaces[0].metrics.halstead.vocabulary
old: 1.0
new: 99.0
path: .spaces[0].metrics.halstead.bugs
old: 0.0
new: 1.364054531853209
path: .spaces[0].metrics.halstead.N1
old: 0.0
new: 465.0
path: .spaces[0].metrics.halstead.length
old: 1.0
new: 781.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: null
new: 577.2005018044988
path: .spaces[0].metrics.halstead.N2
old: 1.0
new: 316.0
path: .spaces[0].metrics.halstead.difficulty
old: 0.0
new: 50.56
path: .spaces[0].metrics.halstead.purity_ratio
old: null
new: 0.739053139314339
path: .spaces[0].metrics.halstead.effort
old: 0.0
new: 261775.79142546677
path: .spaces[0].metrics.nom.functions
old: 0.0
new: 8.0
path: .spaces[0].metrics.nom.total
old: 0.0
new: 8.0
Code
namespace mozilla {
namespace {
class AvailableEvent final : public Runnable {
public:
AvailableEvent(nsIInputStream* stream,
const std::function& aCallback)
: Runnable("mozilla::AvailableEvent"),
mStream(stream),
mCallback(aCallback),
mSize(-1) {
mCallbackTarget = GetCurrentSerialEventTarget();
MOZ_ASSERT(NS_IsMainThread());
}
NS_IMETHOD
Run() override {
// ping
if (!NS_IsMainThread()) {
uint64_t size = 0;
if (NS_WARN_IF(NS_FAILED(mStream->Available(&size)))) {
mSize = -1;
} else {
mSize = (int64_t)size;
}
mStream = nullptr;
nsCOMPtr self(this); // overly cute
mCallbackTarget->Dispatch(self.forget(), NS_DISPATCH_NORMAL);
mCallbackTarget = nullptr;
return NS_OK;
}
// pong
std::function callback;
callback.swap(mCallback);
callback(mSize);
return NS_OK;
}
private:
nsCOMPtr mStream;
std::function mCallback;
nsCOMPtr mCallbackTarget;
int64_t mSize;
};
} // namespace
/* static */
bool InputStreamLengthHelper::GetSyncLength(nsIInputStream* aStream,
int64_t* aLength) {
MOZ_ASSERT(aStream);
MOZ_ASSERT(aLength);
*aLength = -1;
// Sync length access.
nsCOMPtr streamLength = do_QueryInterface(aStream);
if (streamLength) {
int64_t length = -1;
nsresult rv = streamLength->Length(&length);
// All good!
if (NS_SUCCEEDED(rv)) {
*aLength = length;
return true;
}
// Already closed stream or an error occurred.
if (rv == NS_BASE_STREAM_CLOSED ||
NS_WARN_IF(rv == NS_ERROR_NOT_AVAILABLE) ||
NS_WARN_IF(rv != NS_BASE_STREAM_WOULD_BLOCK)) {
return true;
}
}
nsCOMPtr asyncStreamLength =
do_QueryInterface(aStream);
if (asyncStreamLength) {
// GetAsyncLength should be used.
return false;
}
// We cannot calculate the length of an async stream.
nsCOMPtr asyncStream = do_QueryInterface(aStream);
if (asyncStream) {
return false;
}
// For main-thread only, we want to avoid calling ::Available() for blocking
// streams.
if (NS_IsMainThread()) {
bool nonBlocking = false;
if (NS_WARN_IF(NS_FAILED(aStream->IsNonBlocking(&nonBlocking)))) {
// Let's return -1. There is nothing else we can do here.
return true;
}
if (!nonBlocking) {
return false;
}
}
// Fallback using available().
uint64_t available = 0;
nsresult rv = aStream->Available(&available);
if (NS_WARN_IF(NS_FAILED(rv))) {
// Let's return -1. There is nothing else we can do here.
return true;
}
*aLength = (int64_t)available;
return true;
}
/* static */
void InputStreamLengthHelper::GetAsyncLength(
nsIInputStream* aStream,
const std::function& aCallback) {
MOZ_ASSERT(aStream);
MOZ_ASSERT(aCallback);
// We don't want to allow this class to be used on workers because we are not
// using the correct Runnable types.
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread() ||
!dom::IsCurrentThreadRunningWorker());
RefPtr helper =
new InputStreamLengthHelper(aStream, aCallback);
// Let's be sure that we don't call ::Available() on main-thread.
if (NS_IsMainThread()) {
nsCOMPtr streamLength = do_QueryInterface(aStream);
nsCOMPtr asyncStreamLength =
do_QueryInterface(aStream);
if (!streamLength && !asyncStreamLength) {
// We cannot calculate the length of an async stream. We must fix the
// caller if this happens.
#ifdef DEBUG
nsCOMPtr asyncStream = do_QueryInterface(aStream);
MOZ_DIAGNOSTIC_ASSERT(!asyncStream);
#endif
bool nonBlocking = false;
if (NS_SUCCEEDED(aStream->IsNonBlocking(&nonBlocking)) && !nonBlocking) {
nsCOMPtr target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
RefPtr event = new AvailableEvent(aStream, aCallback);
target->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
return;
}
}
}
// Let's go async in order to have similar behaviors for sync and async
// nsIInputStreamLength implementations.
GetCurrentSerialEventTarget()->Dispatch(helper, NS_DISPATCH_NORMAL);
}
InputStreamLengthHelper::InputStreamLengthHelper(
nsIInputStream* aStream,
const std::function& aCallback)
: Runnable("InputStreamLengthHelper"),
mStream(aStream),
mCallback(aCallback) {
MOZ_ASSERT(aStream);
MOZ_ASSERT(aCallback);
}
InputStreamLengthHelper::~InputStreamLengthHelper() = default;
NS_IMETHODIMP
InputStreamLengthHelper::Run() {
// Sync length access.
nsCOMPtr streamLength = do_QueryInterface(mStream);
if (streamLength) {
int64_t length = -1;
nsresult rv = streamLength->Length(&length);
// All good!
if (NS_SUCCEEDED(rv)) {
ExecCallback(length);
return NS_OK;
}
// Already closed stream or an error occurred.
if (rv == NS_BASE_STREAM_CLOSED ||
NS_WARN_IF(rv == NS_ERROR_NOT_AVAILABLE) ||
NS_WARN_IF(rv != NS_BASE_STREAM_WOULD_BLOCK)) {
ExecCallback(-1);
return NS_OK;
}
}
// Async length access.
nsCOMPtr asyncStreamLength =
do_QueryInterface(mStream);
if (asyncStreamLength) {
nsresult rv =
asyncStreamLength->AsyncLengthWait(this, GetCurrentSerialEventTarget());
if (NS_WARN_IF(NS_FAILED(rv))) {
ExecCallback(-1);
}
return NS_OK;
}
// Fallback using available().
uint64_t available = 0;
nsresult rv = mStream->Available(&available);
if (NS_WARN_IF(NS_FAILED(rv))) {
ExecCallback(-1);
return NS_OK;
}
ExecCallback((int64_t)available);
return NS_OK;
}
NS_IMETHODIMP
InputStreamLengthHelper::OnInputStreamLengthReady(
nsIAsyncInputStreamLength* aStream, int64_t aLength) {
ExecCallback(aLength);
return NS_OK;
}
void InputStreamLengthHelper::ExecCallback(int64_t aLength) {
MOZ_ASSERT(mCallback);
std::function callback;
callback.swap(mCallback);
callback(aLength);
}
NS_IMPL_ISUPPORTS_INHERITED(InputStreamLengthHelper, Runnable,
nsIInputStreamLengthCallback)
} // namespace mozilla