From fca51300c3758a201ecffa522dcc033e3fc5b414 Mon Sep 17 00:00:00 2001 From: Marie Katrine Ekeberg Date: Thu, 11 Apr 2024 08:14:23 +0200 Subject: [PATCH] Fix incorrect calculation issue with nesting (#14) * Tests that verifies current recursion logic and reproduces issue * Test for C verifying part of the same issue as for go with nesting * Fix stupid calculation error in go test * Fix expected Kotlin test case after reading cognitive complexity paper * Fix nesting issue, aka the incorrect calculation defect * Minor stylistic changes in function use and init --- Eask | 4 ++-- codemetrics.el | 35 ++++++++++++++++++++++------------- test/c-test.el | 13 +++++++++++++ test/c/NestedPrints.c | 14 ++++++++++++++ test/go-test.el | 22 ++++++++++++++++++++++ test/go/NestedPrints.go | 18 ++++++++++++++++++ test/go/Recursion.go | 7 +++++++ test/kotlin-test.el | 6 +++--- 8 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 test/c/NestedPrints.c create mode 100644 test/go/NestedPrints.go create mode 100644 test/go/Recursion.go diff --git a/Eask b/Eask index bc71fb1..aaa1bd5 100644 --- a/Eask +++ b/Eask @@ -15,11 +15,11 @@ (depends-on "emacs" "27.1") (depends-on "tree-sitter") (depends-on "s") +(depends-on "dash") (setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432 (development (depends-on "kotlin-mode") (depends-on "go-mode") - (depends-on "tree-sitter-langs") - (depends-on "dash")) + (depends-on "tree-sitter-langs")) diff --git a/codemetrics.el b/codemetrics.el index 0683cb4..c147956 100644 --- a/codemetrics.el +++ b/codemetrics.el @@ -6,7 +6,7 @@ ;; Maintainer: Shen, Jen-Chieh ;; URL: https://github.com/emacs-vs/codemetrics ;; Version: 0.1.0 -;; Package-Requires: ((emacs "27.1") (tree-sitter "0.15.1") (s "1.12.0")) +;; Package-Requires: ((emacs "27.1") (tree-sitter "0.15.1") (s "1.12.0") (dash "2.19.1")) ;; Keywords: convenience complexity ;; This file is not part of GNU Emacs. @@ -35,6 +35,7 @@ (require 'pcase) (require 'rect) +(require 'dash) (require 's) (require 'tree-sitter) @@ -255,10 +256,14 @@ details. Optional argument DEPTH is used for recursive depth calculation." (codemetrics--ensure-ts (let* ((mode (or mode major-mode)) (rules (codemetrics--rules mode)) - (nested-level) ; this is the "starting" nested level + ;; Collection of nesting levels + (nested-depths) (nested 0) (score 0) (data) + ;; Helper for calculating nested value from our collection of nestings + (calculate-nested-value (lambda (nested-depths) + (max 0 (1- (length nested-depths))))) ;; Global Records (codemetrics--recursion-identifier)) (with-temp-buffer @@ -273,10 +278,12 @@ details. Optional argument DEPTH is used for recursive depth calculation." (when (and codemetrics--recursion-identifier (<= depth codemetrics--recursion-identifier-depth)) (setq codemetrics--recursion-identifier nil)) - (when (and nested-level - (<= depth nested-level)) ; decrement out - (setq nested-level nil - nested 0)) + ;; Decrement out if needed + ;; (if we have moved out of the last nesting) + (setq nested-depths (-drop-while (lambda (nested) + (<= depth nested)) + nested-depths) + nested (funcall calculate-nested-value nested-depths)) (when-let* ((type (tsc-node-type node)) (a-rule (assoc type rules)) ; cons (rule (cdr a-rule))) @@ -286,13 +293,15 @@ details. Optional argument DEPTH is used for recursive depth calculation." (weight (nth 0 rules-data)) (inc-nested (nth 1 rules-data))) (when inc-nested - (if (null nested-level) - (setq nested-level depth - nested 0) - (cl-incf nested))) - (codemetrics--log "depth: %s, nested-level: %s, nested: %s" - depth nested-level nested) - (let ((node-score (+ weight nested))) + (let ((last-depth (or (nth 0 nested-depths) + depth))) + (when (or (< last-depth depth) + (zerop (length nested-depths))) + (push depth nested-depths) + (setq nested (funcall calculate-nested-value nested-depths))))) + (codemetrics--log "depth: %s, nested-depths: %s, nested: %s" + depth nested-depths nested) + (let ((node-score (if inc-nested (+ weight nested) weight))) (codemetrics--log "%s" (cons type node-score)) (push (list node depth node-score) data) ;; The first value is plus, second is times. diff --git a/test/c-test.el b/test/c-test.el index cd50edb..5e818c7 100644 --- a/test/c-test.el +++ b/test/c-test.el @@ -73,4 +73,17 @@ ("||" . 1) ("&&" . 0))) +;; Loosely inspired by go nested prints issue +;; (for verifying issue with multiple nested ifs inside a for-loop) +(codemetrics-test c-nested-prints + "test/c/NestedPrints.c" + c-mode + '(5 + (function_definition . 0) + (for_statement . 1) + (if_statement . 2) + (call_expression . 0) + (if_statement . 2) + (call_expression . 0))) + ;;; c-test.el ends here diff --git a/test/c/NestedPrints.c b/test/c/NestedPrints.c new file mode 100644 index 0000000..29f7bf1 --- /dev/null +++ b/test/c/NestedPrints.c @@ -0,0 +1,14 @@ +#include + +int main() { + int i; + for (i = 0; i < 10; i++) { + if(i == 0) { + printf("Hello there\n") + } + + if(i == 9) { + printf("General Kenobi\n"); + } + } +} diff --git a/test/go-test.el b/test/go-test.el index 7c54352..eda20bb 100644 --- a/test/go-test.el +++ b/test/go-test.el @@ -34,4 +34,26 @@ (call_expression . 0) (for_statement . 1))) +(codemetrics-test recursion-go-code + "test/go/Recursion.go" + go-mode + '(2 + (function_declaration . 0) + (if_statement . 1) + (call_expression . 1))) + +;; Test of issue: +;; https://github.com/emacs-vs/codemetrics/issues/7 +(codemetrics-test go-nested-print-calls + "test/go/NestedPrints.go" + go-mode + '(6 + (function_declaration . 0) + (for_statement . 1) + (if_statement . 2) + (call_expression . 0) + (if_statement . 2) + (call_expression . 0) + (for_statement . 1))) + ;;; go-test.el ends here diff --git a/test/go/NestedPrints.go b/test/go/NestedPrints.go new file mode 100644 index 0000000..71d6593 --- /dev/null +++ b/test/go/NestedPrints.go @@ -0,0 +1,18 @@ +import "fmt" + +func main() { + v1 := false + v2 := true + + for { + if v1 { + fmt.Println(v1) + } + + if v2 { + fmt.Println(v2) + } + } + + for {} +} diff --git a/test/go/Recursion.go b/test/go/Recursion.go new file mode 100644 index 0000000..14a8bcf --- /dev/null +++ b/test/go/Recursion.go @@ -0,0 +1,7 @@ +func factorial(n int) int { + if n <= 1 { + return 1 + } + + return n * factorial(n - 1) +} diff --git a/test/kotlin-test.el b/test/kotlin-test.el index 103ece8..e2551e1 100644 --- a/test/kotlin-test.el +++ b/test/kotlin-test.el @@ -44,14 +44,14 @@ (codemetrics-test kotlin-break-continue "test/kotlin/BreakContinue.kt" kotlin-mode - '(8 + '(6 (function_declaration . 0) (call_expression . 0) (for_statement . 1) (if_expression . 2) - ("break" . 1) + ("break" . 0) (for_statement . 1) (if_expression . 2) - ("continue" . 1))) + ("continue" . 0))) ;;; kotlin-test.el ends here