{"id":25777064,"url":"https://github.com/mauricioaniche/ck","last_synced_at":"2025-10-21T05:27:41.518Z","repository":{"id":37677760,"uuid":"43679748","full_name":"mauricioaniche/ck","owner":"mauricioaniche","description":"Code metrics for Java code by means of static analysis","archived":false,"fork":false,"pushed_at":"2024-06-07T14:35:54.000Z","size":878,"stargazers_count":362,"open_issues_count":27,"forks_count":139,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-07-16T14:52:33.366Z","etag":null,"topics":["code-metrics","metrics","software-engineering","static-analysis"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mauricioaniche.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2015-10-05T11:13:34.000Z","updated_at":"2024-06-26T13:58:35.000Z","dependencies_parsed_at":"2024-01-17T16:06:49.948Z","dependency_job_id":"6294ea53-a140-4b00-a6bd-7b20d67c28f9","html_url":"https://github.com/mauricioaniche/ck","commit_stats":{"total_commits":464,"total_committers":26,"mean_commits":"17.846153846153847","dds":0.2737068965517241,"last_synced_commit":"618fa4a24a7e321fa26e310556eafe638c8c3092"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mauricioaniche%2Fck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mauricioaniche%2Fck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mauricioaniche%2Fck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mauricioaniche%2Fck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mauricioaniche","download_url":"https://codeload.github.com/mauricioaniche/ck/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240987435,"owners_count":19889335,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-metrics","metrics","software-engineering","static-analysis"],"created_at":"2025-02-27T06:01:35.837Z","updated_at":"2025-10-21T05:27:41.434Z","avatar_url":"https://github.com/mauricioaniche.png","language":"Java","funding_links":[],"categories":["静态分析","Programming Languages","others"],"sub_categories":[],"readme":"# CK\n\n[![Build Status](https://travis-ci.org/mauricioaniche/ck.svg?branch=master)](https://travis-ci.org/mauricioaniche/ck)\n[![Code Coverage](https://codecov.io/github/mauricioaniche/ck/coverage.svg)](https://codecov.io/gh/mauricioaniche/ck)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.mauricioaniche/ck/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.mauricioaniche/ck)\n\nCK calculates class-level and method-level code metrics in Java projects by means\nof static analysis (i.e. no need for compiled code). Currently, it contains\na large set of metrics, including the famous CK:\n\n- *CBO (Coupling between objects)*: Counts the number of dependencies a class has.\nThe tools checks for any type used in the entire class (field declaration, method\nreturn types, variable declarations, etc). It ignores dependencies to Java itself\n(e.g. java.lang.String).\n\n- *CBO Modified (Coupling between objects)*: Counts the number of dependencies a class has. \nIt is very similar to the CKTool's original CBO. However, this metric considers a dependency \nfrom a class as being both the references the type makes to others and the references that it \nreceives from other types.\n\n- *FAN-IN*: Counts the number of input dependencies a class has, i.e, the number of classes \nthat reference a particular class. For instance, given a class X, the fan-in of X would be the \nnumber of classes that call X by referencing it as an attribute, accessing some of its attributes, \ninvoking some of its methods, etc.\n\n- *FAN-OUT*: Counts the number of output dependencies a class has, i.e, the number of other classes \nreferenced by a particular class. In other words, given a class X, the fan-out of X is the number of \nclasses called by X via attributes reference, method invocations, object instances, etc.\n\n- *DIT (Depth Inheritance Tree)*: It counts the number of \"fathers\" a class has.\nAll classes have DIT at least 1 (everyone inherits java.lang.Object).\nIn order to make it happen, classes must exist in the project (i.e. if a class\ndepends upon X which relies in a jar/dependency file, and X depends upon other\nclasses, DIT is counted as 2). \n\n- *NOC (Number of Children)*: It counts the number of immediate subclasses that a \nparticular class has. \n\n- *Number of fields*: Counts the number of fields. Specific numbers for\ntotal number of fields, static, public, private, protected, default, final, and synchronized fields.\n\n- *Number of methods*: Counts the number of methods. Specific numbers for\ntotal number of methods, static, public, abstract, private, protected, default, final, and synchronized methods.\nConstructor methods also count here.\n\n- *Number of visible methods*: Counts the number of visible methods. A method is visible if it is not private.\n\n- *NOSI (Number of static invocations)*: Counts the number of invocations\nto static methods. It can only count the ones that can be resolved by the\nJDT.\n\n- *RFC (Response for a Class)*: Counts the number of unique method\ninvocations in a class. As invocations are resolved via static analysis,\nthis implementation fails when a method has overloads with same number of parameters,\nbut different types.\n\n- *WMC (Weight Method Class)* or *McCabe's complexity*. It counts the number\nof branch instructions in a class.\n\n- *LOC (Lines of code)*: It counts the lines of count, ignoring\nempty lines and comments (i.e., it's Source Lines of Code, or SLOC).\nThe number of lines here might be a bit different from the original file, as we use JDT's internal representation of the source code to calculate it.\n\n- *LCOM (Lack of Cohesion of Methods)*: Calculates LCOM metric. This is the very first\nversion of metric, which is not reliable. LCOM-HS can be better (hopefully, you will\nsend us a pull request).\n\n- *LCOM\u0026ast; (Lack of Cohesion of Methods)*: This metric is a modified version of the current version \nof LCOM implemented in CK Tool. LCOM\u0026ast; is a normalized metric that computes the lack of cohesion of \nclass within a range of 0 to 1. Then, the closer to 1 the value of LCOM\u0026ast; in a class, the less the cohesion \ndegree of this respective class. The closer to 0 the value of LCOM\u0026ast; in a class, the most the cohesion of \nthis respective class. This implementation follows the third version of LCOM\u0026ast; defined in [1].\n\t- *Reference:* [1] Henderson-Sellers, Brian, Larry L. Constantine and Ian M. Graham. “Coupling and cohesion \n\t(towards a valid metrics suite for object-oriented analysis and design).” Object Oriented Systems 3 (1996): \n\t143-158. \n\n- *TCC (Tight Class Cohesion)*: Measures the cohesion of a class with a value range from 0 to 1. TCC measures the cohesion of a class via direct connections between visible methods, two methods or their invocation trees access the same class variable. \n\n- *LCC (Loose Class Cohesion)*: Similar to TCC but it further includes the number of indirect connections between visible classes for the cohesion calculation. Thus, the constraint LCC \u003e= TCC holds always. \n\n- *Quantity of returns*: The number of `return` instructions.\n\n- *Quantity of loops*: The number of loops (i.e., for, while, do while, enhanced for).\n\n- *Quantity of comparisons*: The number of comparisons (i.e., == and !=). Note: != is only\navailable in 0.4.2+.\n\n- *Quantity of try/catches*: The number of try/catches\n\n- *Quantity of parenthesized expressions*: The number of expressions inside parenthesis.\n\n- *String literals*: The number of string literals (e.g., `\"John Doe\"`). Repeated strings count as many times as they appear. \n\n- *Quantity of Number*: The number of numbers (i.e., int, long, double, float) literals.\n\n- *Quantity of Math Operations*: The number of math operations (times, divide, remainder, plus, minus, left shit, right shift).\n\n- *Quantity of Variables*: Number of declared variables.\n\n- *Max nested blocks*: The highest number of blocks nested together.\n\n- *Quantity of Anonymous classes, inner classes, and lambda expressions*: The name says it all.\nNote that whenever an anonymous class or an inner class is declared, it becomes an\n\"entire new class\", e.g., CK generates A.B and A.B$C, C being an inner class inside A.B.\nHowever, lambda expressions are not considered classes, and thus, are part of the\nclass/method they are embedded into. A class or a method only has the number of inner classes\nthat are declared at its level, e.g., an inner class that is declared inside a method M2,\nthat is inside an anonymous\nclass A, that is declared inside a method M, that finally is declared inside a class C,\nwill not count in class C, but only in method M2 (first-level method it is embodied),\nand anonymous class A (first-level class it is embodied).\n\n- *Number of unique words*: Number of unique words in the source code. At method level, it only uses the method body as input. At class level,\nit uses the entire body of the class as metrics.\nThe algorithm basically counts the number of words in a method/class, after removing Java keywords. Names are split based on camel case and underline (e.g., longName_likeThis becomes four words).\nSee `WordCounter` class for details on the implementation.\n\n- *Number of Log Statements*: Number of log statements in the source code. The counting uses REGEX compatible with SLF4J and Log4J API calls.\nSee `NumberOfLogStatements.java` and the test examples (`NumberOfLogStatementsTest` and `fixtures/logs`) for more info.\n\n- *Has Javadoc*: Boolean indicating whether a method has javadoc. (Only at method-level for now) \n\n- *modifiers*: public/abstract/private/protected/native modifiers of classes/methods. Can be decoded using `org.eclipse.jdt.core.dom.Modifier`.  \n\n- *Usage of each variable*: How often each variable was used inside each method.\n\n- *Usage of each field*: How often each local field was used inside each method, local field are fields within a class (subclasses are not included). Also indirect local field usages are detected, indirect local field usages include all usages of fields within the local invocation tree of a class e.g. A invokes B and B uses field a, then a is indirectly used by A.\n\n- *Method invocations*: All directly invoked methods, variations are local invocations and indirect local invocations.\n      \n\nNote: CK separates classes, inner classes, and anonymous classes. LOC is the only metric that is not completely isolated from the others, e.g., if A has a declaration of an inner class B, then LOC(A) = LOC(class A) + LOC(inner class B).\n\n## Project Structure\n\nCK is a Java code metrics collection tool, streamlined into a simple structure that revolves around three primary packages:\n\n- **ck:** Contains the core classes that drive the metrics collection process.\n- **ck.metrics:** Hosts the metric definitions and implementations.\n- **ck.utils:** Utilities supporting the metrics collection process.\n\nFor brevity, within this documentation, package prefixes such as `com.github.mauricioaniche.ck` are omitted.\n\n## Architecture\n\n### Core Components\n\n- **CK:** The backbone class of the tool, `CK` manages the orchestration of the entire metrics collection process. It initializes metric finders, handles file partitioning based on available memory, sets up AST parsers with appropriate environment settings, and manages execution flow across different directories and JAR dependencies. It dynamically adjusts its behavior based on user inputs like `useJars`, `maxAtOnce`, and `variablesAndFields` to optimize the processing of Java files for metrics collection.\n- **Runner:** The entry point of the application, housed in the `ck` package. This class processes command-line arguments to configure and launch the metrics collection process. It handles user input for the project path, JAR inclusion, file partitioning, metrics detailing, and output directory setup. `Runner` orchestrates the overall execution by initializing and utilizing the `CK` class and handling result output through `ResultWriter`.\n- **MetricsExecutor:** This class extends `FileASTRequestor`, a component of the Eclipse JDT (Java Development Tools) core. It plays a pivotal role in the CK framework by orchestrating the metrics collection process. The `MetricsExecutor` coordinates the creation of the Abstract Syntax Tree (AST) for Java source files, which is essential for analyzing and extracting code metrics.\n\n### Metrics Identification\n\n- **MetricsFinder:** This utility class, located in `ck.utils`, plays a crucial role in the dynamic identification and instantiation of metric collector classes within the CK framework. It targets classes that implement the `ClassLevelMetric` and `MethodLevelMetric` interfaces from the `metrics` package.\n\n  The `MetricsFinder` utilizes the `Reflections` library to scan and load metric collector classes at runtime, which enables the CK system to be extensible and adaptable to new metrics without requiring modifications to the core architecture. This feature is particularly useful for integrating custom metrics into the analysis process seamlessly.\n\n### Metrics Collection\n\n- **CKVisitor:** An integral component of the CK framework, `CKVisitor` extends the `ASTVisitor` class provided by the Eclipse JDT (Java Development Tools) library, enabling detailed analysis and metric collection directly from Java source code's Abstract Syntax Tree (AST).\n\n  The visitor is designed to traverse various nodes of the AST, such as types and methods, and apply specific actions at each node. It effectively manages a stack-based hierarchy of classes and methods, allowing metrics to be calculated and collected in the context of the current node's scope.\n\n- **CKASTVisitor:** Implemented by metric classes in `ck.metrics`, allowing each metric to handle specific AST nodes of interest, such as method invocations and class instance creations.\n- **ClassLevelMetric** and **MethodLevelMetric:** Interfaces defining methods for collecting class-level and method-level metrics, respectively.\n\n### Results Notification and Storage\n\n- **MetricsExecutor:** After collecting metrics, it uses a Notifier design pattern to broadcast the results using the `CKNotifier` interface.\n- **Anonymous class in Runner.main:** Fills the `CKClassResult` and `CKMethodResult` with the collected data.\n- **ResultWriter:** Utilizes the collected data to generate and store results in .CSV format.\n\n## Design Patterns\n\nCK framework incorporates a number of well-established design patterns to enhance modularity, extendibility, and maintainability of its codebase. These patterns enable the framework to efficiently handle complex operations such as traversing abstract syntax trees (AST), collecting metrics, and notifying results. Below are the key design patterns utilized:\n\n- **Visitor Pattern:** The `CKVisitor` and `CKASTVisitor` interfaces implement the Visitor pattern, which is pivotal in handling operations on various AST nodes without altering the classes of the elements on which it operates. This pattern is especially beneficial in scenarios where a component needs to perform distinct and unrelated operations across a class hierarchy of AST nodes. It simplifies code by externalizing operational logic into visitor objects, facilitating easy addition of new operations without modifying existing node classes. This separation of concerns leads to a more maintainable and extensible codebase, where AST node structures and operations on them are decoupled.\n\n- **Notifier Pattern:** CK adopts the Notifier pattern through the use of `CKNotifier`, which acts as a central mechanism to broadcast the results of the metrics collection to all registered observers. This pattern is crucial for creating a loosely coupled architecture where the subject (metric computation process) is independent of its observers (results processors or report generators). This enables CK to notify multiple components about the completion of metric calculations without coupling to specific components, which enhances flexibility and scalability of the system.\n\n- **Factory Pattern:** The instantiation of metric collectors is managed by `MetricsFinder`, which embodies the Factory pattern. This pattern is utilized to encapsulate the logic of instantiating specific metric collector classes based on runtime decisions. The Factory pattern simplifies the process of adding new types of metric collectors without disturbing the existing code, providing a plug-and-play architecture where new metrics can be introduced seamlessly. It also aids in maintaining separation of concerns, as the process of creating metric objects is isolated from the core logic of metric collection.\n\nBy leveraging these design patterns, CK efficiently manages complexity and ensures that the framework remains robust, adaptable, and easy to extend as new requirements and metric types emerge.\n\n## How to use the standalone version\n\nYou need at least Java 8 to be able to compile and run this tool.\n\nTo use the _latest version_ (which you should), clone the project and generate a JAR. A simple\n`mvn clean compile package` generates the single JAR file for you (see your _target_ folder).\n\nThen, just run:\n\n```\njava -jar ck-x.x.x-SNAPSHOT-jar-with-dependencies.jar \\\n\t\u003cproject dir\u003e \\\n\t\u003cuse jars:true|false\u003e \\\n\t\u003cmax files per partition:0=automatic selection\u003e \\\n\t\u003cvariables and fields metrics?:true|false\u003e \\\n\t\u003coutput dir\u003e \\\n\t[ignored directories...]\n```\n\n`Project dir` refers to the directory where CK can find all the source code to be parsed.\nCk will recursively look for .java files. CK can use the dependencies of the project\nas to improve its precision. The `use jars` parameters tells CK to look for any .jar files\nin the directory and use them to better resolve types. `Max files per partition` tells JDT the size\nof the batch to process. Let us decide that for you and start with 0; if problems happen (i.e., \nout of memory) you think of tuning it. `Variables and field metrics` indicates to CK whether\nyou want metrics at variable- and field-levels too. They are highly fine-grained and produce a lot of output;\nyou should skip it if you only need metrics at class or method level. Finally, `output dir` refer to the \ndirectory where CK will export the csv file with metrics from the analyzed project.\nOptionally, you can specify any number ignored directories, separated by spaces (for example, `build/`).\nBy default, `.git` and all other hidden folders are ignored.\n\nThe tool will generate three csv files: class, method, and variable levels.\n\n\n## How to integrate it in my Java app\n\nLearn by example. See `Runner.java` class.\n\n## Maven\n\nSee the most recent version of the library in the badge at the beginning of this README, or at https://mvnrepository.com/artifact/com.github.mauricioaniche/ck.\n\nUse the following snippet in your pom.xml. Update X.Y.Z with the most recent version of the tool (check mvnrepository.com or the badge at the beginning of this README file):\n\n```\n\u003c!-- https://mvnrepository.com/artifact/com.github.mauricioaniche/ck --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.mauricioaniche\u003c/groupId\u003e\n    \u003cartifactId\u003eck\u003c/artifactId\u003e\n    \u003cversion\u003eX.Y.Z\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nYou also may use the CK maven plugin, developed by @jazzmuesli, which automatically runs CK in your project. Very useful to developers: https://github.com/jazzmuesli/ck-mvn-plugin.\n\n\n## Supporting a new version of Java\n\nThis tool uses Eclipse's JDT Core library under the hood for AST\nconstruction. Currently the compliance version is set to Java 11.\n\nNeed support for a newer language version? The process of adding it is\nvery straightforward, considering contributing a PR:\n\n1. Add a failing unit test case showcasing at least one of the syntax\nfeatures present in the new version you want to provide support.\n2. Update the Eclipse JDT Core dependency in the `pom.xml` file. You may\nuse a repository browser like\n[MVN Repository](https://mvnrepository.com/artifact/org.eclipse.jdt/org.eclipse.jdt.core)\nto ease this process.\n3. Also in the `pom.xml` file, update the `source` and `target`\nproperties of the Maven Compiler plugin accordingly.\n4. Adjust the following lines in `CK.java`:\n    ```\n    [...]\n    ASTParser parser = ASTParser.newParser(AST.JLS11);\n    [...]\n    JavaCore.setComplianceOptions(JavaCore.VERSION_11, options);\n    [...]\n    ```\n5. Check if the failing unit test case you added in the first step is\nnow green. Then submit a PR.\n\n\n## Why is it called CK?\n\nBecause the tool was born to just calculate the CK classLevelMetrics, but it grew beyond\nmy expectations... Life is funny!\n\n## How to cite?\n\nPlease, use the following bibtex entry:\n\n```\n@manual{aniche-ck,\n  title={Java code metrics calculator (CK)},\n  author={Maurício Aniche},\n  year={2015},\n  note={Available in https://github.com/mauricioaniche/ck/}\n}\n```\n\n## How to Contribute\n\nJust submit a PR! :)\n\n## License\n\nThis software is licensed under the [Apache 2.0 License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmauricioaniche%2Fck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmauricioaniche%2Fck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmauricioaniche%2Fck/lists"}