Repository: mozilla/bugbug

Issue:
Add parameter count of functions to the complexity metrics
See also #372.
Add number of exit points of functions to the complexity metrics
See also #372.


Discussion:

Resolving patch:
diff --git a/bugbug/commit_features.py b/bugbug/commit_features.py
--- a/bugbug/commit_features.py
+++ b/bugbug/commit_features.py
@@ -144,6 +144,9 @@ def __call__(self, commit, **kwargs):
             "Average number of source loc": commit["average_source_loc"],
             "Average number of instruction loc": commit["average_instruction_loc"],
             "Average number of logical loc": commit["average_logical_loc"],
+            "Average number of comment loc": commit["average_comment_loc"],
+            "Average number of function arguments": commit["average_nargs"],
+            "Average number of function exit points": commit["average_nexit"],
             "Maximum cyclomatic": commit["maximum_cyclomatic"],
             "Maximum number of unique operands": commit["maximum_halstead_n2"],
             "Maximum number of operands": commit["maximum_halstead_N2"],
@@ -152,6 +155,9 @@ def __call__(self, commit, **kwargs):
             "Maximum number of source loc": commit["maximum_source_loc"],
             "Maximum number of instruction loc": commit["maximum_instruction_loc"],
             "Maximum number of logical loc": commit["maximum_logical_loc"],
+            "Maximum number of comment loc": commit["maximum_comment_loc"],
+            "Maximum number of function arguments": commit["maximum_nargs"],
+            "Maximum number of function exit points": commit["maximum_nexit"],
             "Minimum cyclomatic": commit["minimum_cyclomatic"],
             "Minimum number of unique operands": commit["minimum_halstead_n2"],
             "Minimum number of operands": commit["minimum_halstead_N2"],
@@ -160,12 +166,18 @@ def __call__(self, commit, **kwargs):
             "Minimum number of source loc": commit["minimum_source_loc"],
             "Minimum number of instruction loc": commit["minimum_instruction_loc"],
             "Minimum number of logical loc": commit["minimum_logical_loc"],
+            "Minimum number of comment loc": commit["minimum_comment_loc"],
+            "Minimum number of function arguments": commit["minimum_nargs"],
+            "Minimum number of function exit points": commit["minimum_nexit"],
             "Total of number of operands": commit["total_halstead_N2"],
             "Total of number of unique operators": commit["total_halstead_n1"],
             "Total number of operators": commit["total_halstead_N1"],
             "Total number of source loc": commit["total_source_loc"],
             "Total number of instruction loc": commit["total_instruction_loc"],
             "Total number of logical loc": commit["total_logical_loc"],
+            "Total number of comment loc": commit["total_comment_loc"],
+            "Total number of function arguments": commit["total_nargs"],
+            "Total number of function exit points": commit["total_nexit"],
         }
 
 
@@ -570,6 +582,14 @@ def merge_commits(commits: Sequence[repository.CommitDict]) -> repository.Commit
                 commit["average_logical_loc"] for commit in commits
             )
             / len(commits),
+            "average_comment_loc": sum(
+                commit["average_comment_loc"] for commit in commits
+            )
+            / len(commits),
+            "average_nargs": sum(commit["average_nargs"] for commit in commits)
+            / len(commits),
+            "average_nexit": sum(commit["average_nexit"] for commit in commits)
+            / len(commits),
             "maximum_cyclomatic": max(
                 commit["maximum_cyclomatic"] for commit in commits
             ),
@@ -594,6 +614,11 @@ def merge_commits(commits: Sequence[repository.CommitDict]) -> repository.Commit
             "maximum_logical_loc": max(
                 commit["maximum_logical_loc"] for commit in commits
             ),
+            "maximum_comment_loc": max(
+                commit["maximum_comment_loc"] for commit in commits
+            ),
+            "maximum_nargs": max(commit["maximum_nargs"] for commit in commits),
+            "maximum_nexit": max(commit["maximum_nexit"] for commit in commits),
             "minimum_cyclomatic": min(
                 commit["minimum_cyclomatic"] for commit in commits
             ),
@@ -618,6 +643,11 @@ def merge_commits(commits: Sequence[repository.CommitDict]) -> repository.Commit
             "minimum_logical_loc": min(
                 commit["minimum_logical_loc"] for commit in commits
             ),
+            "minimum_comment_loc": min(
+                commit["minimum_comment_loc"] for commit in commits
+            ),
+            "minimum_nargs": min(commit["minimum_nargs"] for commit in commits),
+            "minimum_nexit": min(commit["minimum_nexit"] for commit in commits),
             "total_halstead_n2": sum(commit["total_halstead_n2"] for commit in commits),
             "total_halstead_N2": sum(commit["total_halstead_N2"] for commit in commits),
             "total_halstead_n1": sum(commit["total_halstead_n1"] for commit in commits),
@@ -627,6 +657,9 @@ def merge_commits(commits: Sequence[repository.CommitDict]) -> repository.Commit
                 commit["total_instruction_loc"] for commit in commits
             ),
             "total_logical_loc": sum(commit["total_logical_loc"] for commit in commits),
+            "total_comment_loc": sum(commit["total_comment_loc"] for commit in commits),
+            "total_nargs": sum(commit["total_nargs"] for commit in commits),
+            "total_nexit": sum(commit["total_nexit"] for commit in commits),
         }
     )
 
diff --git a/bugbug/repository.py b/bugbug/repository.py
--- a/bugbug/repository.py
+++ b/bugbug/repository.py
@@ -182,6 +182,9 @@ def __init__(
         self.average_source_loc = 0.0
         self.average_instruction_loc = 0.0
         self.average_logical_loc = 0.0
+        self.average_comment_loc = 0.0
+        self.average_nargs = 0.0
+        self.average_nexit = 0.0
         self.maximum_cyclomatic = 0
         self.maximum_halstead_N2 = 0
         self.maximum_halstead_n2 = 0
@@ -190,6 +193,9 @@ def __init__(
         self.maximum_source_loc = 0
         self.maximum_instruction_loc = 0
         self.maximum_logical_loc = 0
+        self.maximum_comment_loc = 0
+        self.maximum_nargs = 0
+        self.maximum_nexit = 0
         self.minimum_cyclomatic = sys.maxsize
         self.minimum_halstead_N1 = sys.maxsize
         self.minimum_halstead_n1 = sys.maxsize
@@ -198,6 +204,9 @@ def __init__(
         self.minimum_source_loc = sys.maxsize
         self.minimum_instruction_loc = sys.maxsize
         self.minimum_logical_loc = sys.maxsize
+        self.minimum_comment_loc = sys.maxsize
+        self.minimum_nargs = sys.maxsize
+        self.minimum_nexit = sys.maxsize
         self.total_cyclomatic = 0
         self.total_halstead_N1 = 0
         self.total_halstead_n1 = 0
@@ -206,6 +215,9 @@ def __init__(
         self.total_source_loc = 0
         self.total_instruction_loc = 0
         self.total_logical_loc = 0
+        self.total_comment_loc = 0
+        self.total_nargs = 0
+        self.total_nexit = 0
 
     def __eq__(self, other):
         assert isinstance(other, Commit)
@@ -459,6 +471,9 @@ def get_metrics(commit, metrics_space):
         commit.total_source_loc += metrics["loc"]["sloc"]
         commit.total_instruction_loc += metrics["loc"]["ploc"]
         commit.total_logical_loc += metrics["loc"]["lloc"]
+        commit.total_comment_loc += metrics["loc"]["cloc"]
+        commit.total_nargs += metrics["n_args"]
+        commit.total_nexit += metrics["n_exit"]
 
         commit.maximum_cyclomatic = max(
             commit.maximum_cyclomatic, metrics["cyclomatic"]["sum"]
@@ -486,6 +501,11 @@ def get_metrics(commit, metrics_space):
         commit.maximum_logical_loc = max(
             metrics["loc"]["lloc"], commit.maximum_logical_loc
         )
+        commit.maximum_comment_loc = max(
+            metrics["loc"]["cloc"], commit.maximum_comment_loc
+        )
+        commit.maximum_nargs = max(metrics["n_args"], commit.maximum_nargs)
+        commit.maximum_nexit = max(metrics["n_exit"], commit.maximum_nexit)
 
         commit.minimum_cyclomatic = min(
             commit.minimum_cyclomatic, metrics["cyclomatic"]["sum"]
@@ -513,6 +533,11 @@ def get_metrics(commit, metrics_space):
         commit.minimum_logical_loc = min(
             metrics["loc"]["lloc"], commit.minimum_logical_loc
         )
+        commit.minimum_comment_loc = min(
+            metrics["loc"]["cloc"], commit.minimum_comment_loc
+        )
+        commit.minimum_nargs = min(metrics["n_args"], commit.minimum_nargs)
+        commit.minimum_nexit = min(metrics["n_exit"], commit.minimum_nexit)
 
     for space in metrics_space["spaces"]:
         error |= get_metrics(commit, space)
@@ -652,6 +677,9 @@ def transform(hg: hglib.client, repo_dir: str, commit: Commit):
             commit.total_instruction_loc / metrics_file_count
         )
         commit.average_logical_loc = commit.total_logical_loc / metrics_file_count
+        commit.average_comment_loc = commit.total_comment_loc / metrics_file_count
+        commit.average_nargs = commit.total_nargs / metrics_file_count
+        commit.average_nexit = commit.total_nexit / metrics_file_count
     else:
         # these values are initialized with sys.maxsize (because we take the min)
         # if no files, then reset them to 0 (it'd be stupid to have min > max)
@@ -663,6 +691,9 @@ def transform(hg: hglib.client, repo_dir: str, commit: Commit):
         commit.minimum_source_loc = 0
         commit.minimum_instruction_loc = 0
         commit.minimum_logical_loc = 0
+        commit.minimum_comment_loc = 0
+        commit.minimum_nargs = 0
+        commit.minimum_nexit = 0
 
     return commit
 


Test patch: