{"id":27883023,"url":"https://github.com/cqfn/aibolit","last_synced_at":"2025-05-05T06:11:17.074Z","repository":{"id":43384856,"uuid":"237167507","full_name":"cqfn/aibolit","owner":"cqfn","description":"Static Analyzer for Java Code with Machine Learning in Mind","archived":false,"fork":false,"pushed_at":"2024-04-22T19:44:47.000Z","size":109792,"stargazers_count":51,"open_issues_count":65,"forks_count":17,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-09T15:16:06.565Z","etag":null,"topics":["machine-learning","machine-learning-algorithms","quality-control","static-analysis"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/aibolit/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cqfn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2020-01-30T08:13:30.000Z","updated_at":"2024-08-26T13:22:26.000Z","dependencies_parsed_at":"2023-12-20T12:09:29.153Z","dependency_job_id":"42a2c40a-fa49-40c0-afff-c0874dc79ce7","html_url":"https://github.com/cqfn/aibolit","commit_stats":{"total_commits":1561,"total_committers":25,"mean_commits":62.44,"dds":0.7117232543241512,"last_synced_commit":"222277d579a792b48bcbb2de6bd57692d8b582fb"},"previous_names":["yegor256/aibolit"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cqfn%2Faibolit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cqfn%2Faibolit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cqfn%2Faibolit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cqfn%2Faibolit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cqfn","download_url":"https://codeload.github.com/cqfn/aibolit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252448587,"owners_count":21749495,"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":["machine-learning","machine-learning-algorithms","quality-control","static-analysis"],"created_at":"2025-05-05T06:11:16.446Z","updated_at":"2025-05-05T06:11:17.065Z","avatar_url":"https://github.com/cqfn.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"/logo.svg\" height=\"92px\"/\u003e\n\n[![PyPi version](https://img.shields.io/pypi/v/aibolit.svg)](https://pypi.org/project/aibolit/)\n[![Build Status](https://travis-ci.org/cqfn/aibolit.svg)](https://travis-ci.org/cqfn/aibolit)\n[![Build status](https://ci.appveyor.com/api/projects/status/gr3eqxq5pr87kpwg?svg=true)](https://ci.appveyor.com/project/yegor256/aibolit)\n[![Hits-of-Code](https://hitsofcode.com/github/cqfn/aibolit)](https://hitsofcode.com/view/github/cqfn/aibolit)\n[![Test Coverage](https://img.shields.io/codecov/c/github/cqfn/aibolit.svg)](https://codecov.io/github/cqfn/aibolit?branch=master)\n[![Maintainability](https://api.codeclimate.com/v1/badges/fd7e32d8472b4d5e8ecb/maintainability)](https://codeclimate.com/github/cqfn/aibolit/maintainability)\n[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/cqfn/aibolit/blob/master/LICENSE.txt)\n\n\n## How it works?\n\nLearn how Aibolit works in our [White Paper](https://github.com/cqfn/aibolit/releases/download/1.2.5-post.1/aibolit_wp.pdf).\n\n\n\n## How to use ?\n\nFirst, you install it (you must have [Python 3.7.7](https://www.python.org/downloads/)\nand [Pip](https://pip.pypa.io/en/stable/installing/) installed):\n\n\n\n```bash\n$ pip3 install aibolit\n```\n\nTo analyze your Java sources, located at `src/java` (for example), run:\n\n```bash\n$ aibolit check --filenames src/java/File.java src/java/AnotherFile.java\n```\nor\n\n```bash\n$ aibolit recommend --filenames src/java/File.java src/java/AnotherFile.java\n```\n\nAlso, you can set a folder with Java files:\n\n```bash\n$ aibolit recommend --folder src/java\n```\n\nIt will run recommendation function for the model (model is located in [aibolit/binary_files/model.pkl](https://github.com/cqfn/aibolit/blob/master/aibolit/binary_files/model.pkl).\nThe model finds a pattern which contribution is the largest to the Cyclomatic Complexity.\nIf anything is found, you will see all recommendations for the mentioned patterns.\nYou can see the list of all patterns in [Patterns.md](https://github.com/cqfn/aibolit/blob/master/PATTERNS.md).\nThe output of recommendation will be redirected to the stdout.\nIf the program has the `0` exit code, it means that all analyzed files do not have any issues.\nIf the program has the `1` exit code, it means that at least 1 analyzed file has an issue.\nIf the program has the `2` exit code, it means that program crash occurred.\n\n\nYou can suppress certain patterns (comma separated value) and they will be ignored. They won't be included into the report, also their importance will be set to 0.\n```bash\n$ aibolit recommend --folder src/java --suppress=P12,P13\n```\n\nYou can change the format, using the `--format` parameter. The default value is `--format=compact`.\n```bash\n$ aibolit recommend --folder src/java --format=compact --full\n```\n\nIt will output sorted patterns by importance in descending order and grouped by a pattern name:\n\n```\nShow all patterns\n/mnt/d/src/java/Configuration.java score: 127.67642529949538\n/mnt/d/src/java/Configuration.java[3840]: Var in the middle (P21: 30.95612931128819 1/4)\n/mnt/d/src/java/Configuration.java[3844]: Var in the middle (P21: 30.95612931128819 1/4)\n/mnt/d/src/java/Configuration.java[3848]: Var in the middle (P21: 30.95612931128819 1/4)\n/mnt/d/src/java/Configuration.java[2411]: Null Assignment (P28: 10.76 2/4)\n/mnt/d/src/java/Configuration.java[826]: Many primary constructors (P9: 10.76 3/4)\n/mnt/d/src/java/Configuration.java[840]: Many primary constructors (P9: 10.76 3/4)\n/mnt/d/src/java/Configuration.java[829]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[841]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[865]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[2586]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[3230]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[3261]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[3727]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[3956]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/ErrorExample.java: error when calculating patterns: Can't count P1 metric:\nTotal score: 127.67642529949538\n```\n\n`(P21: 30.95612931128819 1/4)` means the following:\n\n\n```\n30.95612931128819 is the score of this pattern\n1 is the position of this pattern in the total list of patterns found in the file\n4 is the total number of found patterns\n```\n\nYou can use `format=long`. In this case all results will be sorted by a line number:\n\n```\nShow all patterns\n/mnt/d/src/java/Configuration.java: some issues found\n/mnt/d/src/java/Configuration.java score: 127.67642529949538\n/mnt/d/src/java/Configuration.java[826]: Many primary constructors (P9: 10.76 3/4)\n/mnt/d/src/java/Configuration.java[829]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[840]: Many primary constructors (P9: 10.76 3/4)\n/mnt/d/src/java/Configuration.java[841]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[865]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[2411]: Null Assignment (P28: 10.76 2/4)\n/mnt/d/src/java/Configuration.java[2586]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[3230]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[3261]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[3727]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/Configuration.java[3840]: Var in the middle (P21: 30.95612931128819 1/4)\n/mnt/d/src/java/Configuration.java[3844]: Var in the middle (P21: 30.95612931128819 1/4)\n/mnt/d/src/java/Configuration.java[3848]: Var in the middle (P21: 30.95612931128819 1/4)\n/mnt/d/src/java/Configuration.java[3956]: Partial synchronized (P14: 0.228 4/4)\n/mnt/d/src/java/ErrorExample.java: error when calculating patterns: Can't count P1 metric:\n/mnt/d/src/java/MavenSlice.java: your code is perfect in aibolit's opinion\nTotal score: 127.67642529949538\n```\n\n\n\nYou can also choose xml format. It will have the same format as `compact` mode, but xml will be created:\n\n```xml\n\u003creport\u003e\n  \u003cscore\u003e127.67642529949538\u003c/score\u003e\n  \u003c!--Show all patterns--\u003e\n  \u003cfiles\u003e\n    \u003cfile\u003e\n      \u003cpath\u003e/mnt/d/src/java/Configuration.java\u003c/path\u003e\n      \u003csummary\u003eSome issues found\u003c/summary\u003e\n      \u003cscore\u003e127.67642529949538\u003c/score\u003e\n      \u003cpatterns\u003e\n        \u003cpattern code=\"P13\"\u003e\n          \u003cdetails\u003eNull check\u003c/details\u003e\n          \u003clines\u003e\n            \u003cnumber\u003e294\u003c/number\u003e\n            \u003cnumber\u003e391\u003c/number\u003e\n          \u003c/lines\u003e\n          \u003cscore\u003e30.95612931128819\u003c/score\u003e\n          \u003corder\u003e1/4\u003c/order\u003e\n        \u003c/pattern\u003e\n        \u003cpattern code=\"P12\"\u003e\n          \u003cdetails\u003eNon final attribute\u003c/details\u003e\n          \u003clines\u003e\n            \u003cnumber\u003e235\u003c/number\u003e\n          \u003c/lines\u003e\n          \u003cscore\u003e10.76\u003c/score\u003e\n          \u003corder\u003e2/4\u003c/order\u003e\n        \u003c/pattern\u003e\n          \u003cpattern code=\"P21\"\u003e\n          \u003cdetails\u003eVar in the middle\u003c/details\u003e\n          \u003clines\u003e\n            \u003cnumber\u003e235\u003c/number\u003e\n          \u003c/lines\u003e\n          \u003cscore\u003e2.056\u003c/score\u003e\n          \u003corder\u003e3/4\u003c/order\u003e\n        \u003c/pattern\u003e\n          \u003cpattern code=\"P28\"\u003e\n          \u003cdetails\u003eNull Assignment\u003c/details\u003e\n          \u003clines\u003e\n            \u003cnumber\u003e2411\u003c/number\u003e\n          \u003c/lines\u003e\n          \u003cscore\u003e0.228\u003c/score\u003e\n          \u003corder\u003e4/4\u003c/order\u003e\n        \u003c/pattern\u003e\n      \u003c/patterns\u003e\n    \u003c/file\u003e\n    \u003cfile\u003e\n      \u003cpath\u003e/mnt/d/src/java/ErrorExample.java\u003c/path\u003e\n      \u003csummary\u003eError when calculating patterns: Can't count P1 metric: \u003c/summary\u003e\n    \u003c/file\u003e\n    \u003cfile\u003e\n      \u003cpath\u003e/mnt/d/src/java/MavenSlice.java\u003c/path\u003e\n      \u003csummary\u003eYour code is perfect in aibolit's opinion\u003c/summary\u003e\n    \u003c/file\u003e\n  \u003c/files\u003e\n\u003c/report\u003e\n\n```\nThe score is the relative importance of the pattern (there is no range for it).\nThe larger score is, the most important pattern is.\nE.g., if you have several patterns, first you need to fix the pattern with the score 5.45:\n\n```\n/mnt/d/src/java/SampleTests.java[43]: Non final attribute (P12: 5.45 1/10)\n/mnt/d/src/java/SampleTests.java[44]: Non final attribute (P12: 5.45 1/10)\n/mnt/d/src/java/SampleTests.java[80]: Var in the middle (P21: 3.71 2/10)\n/mnt/d/src/java/SampleTests.java[121]: Var in the middle (P21: 3.71 2/10)\n/mnt/d/src/java/SampleTests.java[122]: Var declaration distance for 5 lines (P20_5: 2.13 3/10)\n/mnt/d/src/java/SampleTests.java[41]: Non final class (P24: 1.95 4/10)\n/mnt/d/src/java/SampleTests.java[59]: Force Type Casting (P5: 1.45 5/10)\n/mnt/d/src/java/SampleTests.java[122]: Var declaration distance for 7 lines (P20_7: 1.07 6/10)\n/mnt/d/src/java/SampleTests.java[122]: Var declaration distance for 11 lines (P20_11: 0.78 7/10)\n/mnt/d/src/java/SampleTests.java[51]: Protected Method (P30: 0.60 8/10)\n/mnt/d/src/java/SampleTests.java[52]: Super Method (P18: 0.35 9/10)\n/mnt/d/src/java/SampleTests.java[100]: Partial synchronized (P14: 0.08 10/10)\n/mnt/d/src/java/SampleTests.java[106]: Partial synchronized (P14: 0.08 10/10)\n/mnt/d/src/java/SampleTests.java[113]: Partial synchronized (P14: 0.08 10/10)\n```\nThe score per class is the sum of all patterns scores.\n\n```\n/mnt/d/src/java/SampleTests.java score: 17.54698560768407\n```\n\nThe total score is an average among all java files in a project (folder you've set to analyze)\n```\nTotal average score: 4.0801854775508914\n```\n\nIf you have 2 scores of different projects, the worst project is that one which has the highest score.\n\n\n\nModel is automatically installed with *aibolit* package, but you can also try your own model\n\n```bash\n$ aibolit recommend --folder src/java --model /mnt/d/some_folder/model.pkl\n```\n\nYou can get full report with `--full` command, then all patterns will be included to the output:\n\n```bash\n$ aibolit recommend --folder src/java --full\n```\n\nYou can exclude files with `--exclude` command. \nYou to set glob patterns to ignore:\n\n```bash\n$ aibolit recommend --folder src/java --exclude=**/*Test*.java --exclude=**/*Impl*.java\n```\n\nIf you need help, run\n\n```bash\n$ aibolit recommend --help\n```\n\n## How to retrain it?\n\n`Train` command does the following:\n\n - Calculates patterns and metrics\n - Creates a dataset\n - Trains model and save it\n\n Train works only with cloned git repository.\n 1. Clone aibolit repository\n 2. Go to `cloned_aibolit_path`\n 3. Run `pip install .`\n 4. Set env variable `export HOME_AIBOLIT=cloned_aibolit_path` (example for Linux).\n 5. Set env variable `TARGET_FOLDER` if you need to save all dataset files to another directory.\n 6. You have to specify train and test dataset: set the `HOME_TRAIN_DATASET` environment variable \n for train dataset and the `HOME_TEST_DATASET` environment variable for test dataset.\n Usually, these files are in `scripts/target/08` directory after dataset collection (if you have not skipped it).\n But you can use your own datasets. \n \n    Please notice, that if you set `TARGET_FOLDER`, your dataset files will be in `TARGET_FOLDER/target`. \n That is why it is necessary to \n set HOME_TRAIN_DATASET=`TARGET_FOLDER`\\target\\08\\08-train.csv, \n HOME_TEST_DATASET =`TARGET_FOLDER`\\target\\08\\08-test.csv\n 7. If you need to set up own directory where model will be saved, set up also `SAVE_MODEL_FOLDER` environment variable.\n Otherwise model will be saved into `cloned_aibolit_path/aibolit/binary_files/model.pkl`\n 8. If you need to set up own folder with Java files, use `--java_folder parameter`, the default value will be `scripts/target/01` of aibolit cloned repo\n\n Or you can use our docker image (link will be soon here)\n\n Run train pipeline:\n\n```bash\n$ aibolit train --java_folder=src/java [--max_classes=100] [--dataset_file]\n```\n\nIf you need to save the dataset with all calculated metrics to a different directory, you need to use `dataset_file` parameter\n\n```bash\n$ aibolit train --java_folder=src/java --dataset_file /mnt/d/new_dir/dataset.csv\n```\n\nYou can skip dataset collection with `skip_collect_dataset` parameter. In this case\nthe model will be trained with predefined dataset (see 5 point):\n\n```bash\n$ aibolit train --java_folder=src/java --skip_collect_dataset\n```\n\n## How to contribute?\n\nFirst, you need to install:\n\n  * [Python 3+](https://www.python.org/downloads/)\n  * [Pip](https://pip.pypa.io/en/stable/installing/)\n  * Ruby 2.6+\n  * [Xcop](https://github.com/yegor256/xcop)\n\nInstall the following packages if you don't have :\n\n```bash\n$ apt-get install ruby-dev libz-dev libxml2\n```\n\nThen, you fork the repo and make the changes. Then, you make\nsure the build is still clean, by running:\n\n```bash\n$ make\n```\n\nTo build white paper:\n```bash\n$ cd wp\n$ latexmk -c \u0026\u0026 latexmk -pdf wp.tex\n```\n\nIf everything is fine, submit\na [pull request](https://www.yegor256.com/2014/04/15/github-guidelines.html).\n\n\nUsing Docker recommendation pipeline\n```bash\n$ docker run --rm -it \\\n  -v \u003cabsolute_path_to_folder_with_classes\u003e:/in \\\n  -v \u003cabsolute_path_to_out_dir\u003e:/out \\\n  cqfn/aibolit-image\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcqfn%2Faibolit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcqfn%2Faibolit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcqfn%2Faibolit/lists"}