Skip to content

General issue: MetricCallable Kotlin #20259

@BramRampelberg

Description

@BramRampelberg

I'm trying to calculate the maintainability index of my Kotlin files, in the docs of MetricElement it says MetricCallable implements this method, but when I go look inside the code of MetricCallable, this is not the case.
When I query the following, top level functions declared in my Kotlin files are not included in the metrics:

/**
 * @name Get maintainability metrics
 * @description A query that fetches the maintainability index and components of your code
 * @kind problem
 * @id kotlin-diagnostic-get-maintainability-index
 * @problem.severity warning
 */
import java

from MetricElement m
select
  m,
  "MI: " + m.getMaintainabilityIndex() + 
  " HV: " + m.getHalsteadVolume() + 
  " LOC: " + m.getNumberOfLinesOfCode() + 
  " CC: " + m.getCyclomaticComplexity()

Output:
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 97.812158 HV: 201.182514 LOC: 16 CC: 3","/app/src/main/java/com/example/android_2425_gent2/MainActivity.kt","18","1","35","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 111.941369 HV: 159.81495 LOC: 7 CC: 5","/app/src/main/java/com/example/android_2425_gent2/MainApplication.kt","7","1","15","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 138.524322 HV: 3 LOC: 5 CC: 3","/app/src/main/java/com/example/android_2425_gent2/di/AppContainer.kt","17","1","21","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 85.13941 HV: 880.699747 LOC: 20 CC: 9","/app/src/main/java/com/example/android_2425_gent2/di/AppContainer.kt","23","1","45","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 72.692576 HV: 3273.098437 LOC: 21 CC: 30","/app/src/main/java/com/example/android_2425_gent2/data/model/Reservation.kt","7","1","27","1" <---- way too big Halstead Volume and cyclomatic complexity
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 108.437466 HV: 87.569163 LOC: 11 CC: 2","/app/src/main/java/com/example/android_2425_gent2/data/model/Reservation.kt","16","5","26","5"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 86.418802 HV: 3273.098437 LOC: 9 CC: 30","/app/src/main/java/com/example/android_2425_gent2/data/network/model/ReservationDto.kt","6","1","14","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 64.487852 HV: 5317.547419 LOC: 27 CC: 37","/app/src/main/java/com/example/android_2425_gent2/data/model/ReservationDetails.kt","5","1","31","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 102.956126 HV: 118.536422 LOC: 14 CC: 2","/app/src/main/java/com/example/android_2425_gent2/data/model/ReservationDetails.kt","17","5","30","5"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 64.625991 HV: 8260.399788 LOC: 18 CC: 55","/app/src/main/java/com/example/android_2425_gent2/data/network/model/ReservationDetailsDto.kt","3","1","20","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 88.155744 HV: 1384.496329 LOC: 13 CC: 16","/app/src/main/java/com/example/android_2425_gent2/data/model/UserDetails.kt","5","1","17","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 118.691559 HV: 49.828921 LOC: 7 CC: 2","/app/src/main/java/com/example/android_2425_gent2/data/model/UserDetails.kt","10","5","16","5"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 103.635029 HV: 1384.496329 LOC: 5 CC: 16","/app/src/main/java/com/example/android_2425_gent2/data/network/model/UserDetailsDto.kt","3","1","7","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 96.483329 HV: 2277.426939 LOC: 6 CC: 23","/app/src/main/java/com/example/android_2425_gent2/data/network/model/ReservationResponse.kt","3","1","8","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 117.773194 HV: 3 LOC: 18 CC: 3","/app/src/main/java/com/example/android_2425_gent2/data/network/reservation/ReservationApiService.kt","13","1","32","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 148.312031 HV: 1 LOC: 4 CC: 1","/app/src/main/java/com/example/android_2425_gent2/data/network/users/UserApiService.kt","7","1","10","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 105.47577 HV: 320.123578 LOC: 8 CC: 8","/app/src/main/java/com/example/android_2425_gent2/data/repository/APIResource.kt","3","1","10","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 143.843339 HV: 148.603398 LOC: 1 CC: 5","/app/src/main/java/com/example/android_2425_gent2/data/repository/APIResource.kt","7","5","7","60"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 151.619204 HV: 38.0391 LOC: 1 CC: 2","/app/src/main/java/com/example/android_2425_gent2/data/repository/APIResource.kt","8","5","8","53"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 144.904178 HV: 126.659735 LOC: 1 CC: 4","/app/src/main/java/com/example/android_2425_gent2/data/repository/APIResource.kt","9","5","9","84"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 67.814234 HV: 520.023353 LOC: 70 CC: 8","/app/src/main/java/com/example/android_2425_gent2/data/repository/auth/Auth0Repo.kt","21","1","101","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 111.928423 HV: 80 LOC: 9 CC: 3","/app/src/main/java/com/example/android_2425_gent2/data/repository/auth/Auth0Repo.kt","34","55","43","21"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 113.836509 HV: 80 LOC: 8 CC: 3","/app/src/main/java/com/example/android_2425_gent2/data/repository/auth/Auth0Repo.kt","62","36","70","29"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 133.844766 HV: 4 LOC: 6 CC: 4","/app/src/main/java/com/example/android_2425_gent2/data/repository/auth/IAuthRepo.kt","8","1","16","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 113.498982 HV: 78.137812 LOC: 8 CC: 5","/app/src/main/java/com/example/android_2425_gent2/data/repository/reservation/ReservationRepository.kt","8","1","19","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 68.940862 HV: 525.713263 LOC: 66 CC: 7","/app/src/main/java/com/example/android_2425_gent2/data/repository/reservation/ReservationRepositoryImpl.kt","15","1","92","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 102.361147 HV: 153.247254 LOC: 13 CC: 4","/app/src/main/java/com/example/android_2425_gent2/data/repository/user/RemoteUserRepository.kt","9","1","22","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 152.972481 HV: 1 LOC: 3 CC: 1","/app/src/main/java/com/example/android_2425_gent2/data/repository/user/UserRepository.kt","7","1","9","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 80.045858 HV: 625.870881 LOC: 31 CC: 8","/app/src/main/java/com/example/android_2425_gent2/di/module/NetworkModule.kt","78","1","113","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 89.389857 HV: 673.653171 LOC: 18 CC: 4","/app/src/main/java/com/example/android_2425_gent2/di/module/AuthInterceptor.kt","10","1","31","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 94.891525 HV: 337.525776 LOC: 16 CC: 4","/app/src/main/java/com/example/android_2425_gent2/di/module/NetworkModule.kt","23","1","39","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 94.891525 HV: 337.525776 LOC: 16 CC: 4","/app/src/main/java/com/example/android_2425_gent2/di/module/NetworkModule.kt","41","1","57","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 94.891525 HV: 337.525776 LOC: 16 CC: 4","/app/src/main/java/com/example/android_2425_gent2/di/module/NetworkModule.kt","60","1","76","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 91.963143 HV: 191.368733 LOC: 23 CC: 4","/app/src/main/java/com/example/android_2425_gent2/ui/AppViewModelProvider.kt","14","1","40","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 163.561269 HV: 4 LOC: 1 CC: 1","/app/src/main/java/com/example/android_2425_gent2/ui/AppViewModelProvider.kt","15","21","15","73"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 82.259431 HV: 1698.687318 LOC: 141 CC: 14","/app/src/main/java/com/example/android_2425_gent2/ui/screens/reservations_page/ReservationsViewModel.kt","17","1","181","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 49.876481 HV: 2915.984806 LOC: 93 CC: 27","/app/src/main/java/com/example/android_2425_gent2/ui/screens/login_page/LoginViewModel.kt","13","1","125","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 102.662176 HV: 416.257899 LOC: 9 CC: 6","/app/src/main/java/com/example/android_2425_gent2/ui/screens/app_page/AppViewModel.kt","9","1","18","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 71.08921 HV: 580.261835 LOC: 56 CC: 7","/app/src/main/java/com/example/android_2425_gent2/ui/screens/profile_page/ProfilePageViewModel.kt","25","1","87","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 100.977968 HV: 482.156154 LOC: 9 CC: 10","/app/src/main/java/com/example/android_2425_gent2/ui/navigation/BottomNavItem.kt","9","1","17","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 118.675532 HV: 124.864085 LOC: 5 CC: 5","/app/src/main/java/com/example/android_2425_gent2/ui/utils/NoRippleInteractionSource.kt","8","1","12","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 132.920582 HV: 815.445245 LOC: 1 CC: 14","/app/src/main/java/com/example/android_2425_gent2/ui/screens/app_page/AppState.kt","3","1","3","52"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 97.329068 HV: 2023.107929 LOC: 6 CC: 22","/app/src/main/java/com/example/android_2425_gent2/ui/screens/login_page/LoginViewModel.kt","127","1","132","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 100.992916 HV: 1844.634757 LOC: 5 CC: 21","/app/src/main/java/com/example/android_2425_gent2/ui/screens/login_page/LoginViewModel.kt","134","1","138","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 91.628711 HV: 1789.450037 LOC: 9 CC: 21","/app/src/main/java/com/example/android_2425_gent2/ui/screens/profile_page/ProfilePageViewModel.kt","15","1","23","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 95.801923 HV: 2376.489297 LOC: 6 CC: 25","/app/src/main/java/com/example/android_2425_gent2/ui/screens/reservations_page/ReservationsViewModel.kt","183","1","188","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 96.303719 HV: 2357.464307 LOC: 6 CC: 23","/app/src/main/java/com/example/android_2425_gent2/ui/screens/reservations_page/ReservationsViewModel.kt","190","1","195","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 117.650287 HV: 598.635397 LOC: 3 CC: 10","/app/src/main/java/com/example/android_2425_gent2/ui/screens/reservations_page/ReservationsViewModel.kt","197","1","199","1"
"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 115.752227 HV: 209.593286 LOC: 5 CC: 6","/app/src/main/java/com/example/android_2425_gent2/ui/screens/reservations_page/ReservationsPage.kt","94","1","98","1" <---- only line 94 to 98 are considered

Example ReservationsPage.kt:

package com.example.android_2425_gent2.ui.screens.reservations_page

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.android_2425_gent2.R
import com.example.android_2425_gent2.ui.AppViewModelProvider
import com.example.android_2425_gent2.ui.common.ErrorMessage
import com.example.android_2425_gent2.ui.screens.reservations_page.partials.ReservationDetailsBottomModalSheet
import com.example.android_2425_gent2.ui.screens.reservations_page.partials.ReservationList
import com.example.android_2425_gent2.ui.screens.reservations_page.partials.ReservationTypeSelectionDropDownMenu
import kotlinx.coroutines.launch

@Preview
@Composable
fun ReservationsPage(
    modifier: Modifier = Modifier,
    viewModel: ReservationsViewModel = viewModel(factory = AppViewModelProvider.Factory),
) {
    val coroutineScope = rememberCoroutineScope()
    val reservationsUiState by viewModel.reservationsUiState.collectAsState()
    val selectedReservationUiState = viewModel.selectedReservationUiState
    val reservationTypeUiState = viewModel.reservationTypeUiState

    Column(modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
        ReservationTypeSelectionDropDownMenu(
            reservationTypeUiState.reservationType,
            {
                viewModel.setReservationType(it)
            },
            modifier = modifier.testTag("ReservationTypeSelectionDropDownMenu"),
        )

        if (reservationsUiState.hasError) {
            Column(
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
                modifier = modifier.fillMaxSize()
            ) {
                ErrorMessage(stringResource(R.string.the_reservations_could_not_be_loaded))
            }
        } else if (reservationsUiState.loading && reservationsUiState.reservations.isEmpty()) {
            Column(
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
                modifier = modifier.fillMaxSize()
            ) {
                CircularProgressIndicator()
            }
        } else {
            ReservationList(
                reservations = reservationsUiState.reservations,
                onSelectedReservationChange = { reservation ->
                    coroutineScope.launch {
                        viewModel.setSelectedReservation(reservation)
                    }
                },
                modifier = modifier,
            )
        }

        if (selectedReservationUiState.selectedReservation != null) {
            ReservationDetailsBottomModalSheet(
                selectedReservation = selectedReservationUiState.selectedReservation,
                reservationDetails = selectedReservationUiState.details,
                isLoading = selectedReservationUiState.isLoadingDetails,
                onSelectedReservationChange = {
                    coroutineScope.launch {
                        viewModel.setSelectedReservation(it)
                    }
                },
                onCancelReservation = { reservationId ->
                    viewModel.cancelReservation(reservationId)
                },
                modifier = modifier
            )
        }
    }
}

enum class ReservationType(val title: Int) {
    OLD(title = R.string.old_reservations),
    UPCOMING(title = R.string.upcoming_reservations),
    CANCELED(title = R.string.canceled_reservations),
}

Also it seems some calculations are wrong, like the Halstead Volume and cyclomatic complexity of Reservation.kt:

package com.example.android_2425_gent2.data.model

import com.example.android_2425_gent2.data.network.model.ReservationDto
import java.time.LocalDate
import java.time.LocalTime

data class Reservation(
    val start: LocalTime,
    val end: LocalTime,
    val date: LocalDate,
    val boatId: Int,
    val boatPersonalName: String,
    val id: Int,
    val isDeleted: Boolean = false
) {
    companion object {
        fun fromDto(dto: ReservationDto): Reservation = Reservation(
            dto.start,
            dto.end,
            dto.date,
            dto.boatId,
            dto.boatPersonalName,
            dto.id,
            dto.isDeleted
        )
    }
}

"(Diagnostic) Find All Classes","A test query that flags every class as a warning.","warning","MI: 72.692576 HV: 3273.098437 LOC: 21 CC: 30","/app/src/main/java/com/example/android_2425_gent2/data/model/Reservation.kt","7","1","27","1" <---- way too big Halstead Volume and cyclomatic complexity

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions