{"id":19706219,"url":"https://github.com/llnl/rose-lcom-tools","last_synced_at":"2026-06-09T13:31:19.206Z","repository":{"id":220184245,"uuid":"740577265","full_name":"LLNL/ROSE-LCOM-Tools","owner":"LLNL","description":"Computes LCOM metrics for C++ and Ada code","archived":false,"fork":false,"pushed_at":"2025-08-05T15:03:36.000Z","size":241,"stargazers_count":4,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-05T17:16:57.332Z","etag":null,"topics":["code-metrics","cohesion","lack-of-cohesion","lack-of-cohesion-of-test-methods","lcom","metrics","metrics-gathering","object-oriented","oop","software-engineering","static-analysis","static-analyzer"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LLNL.png","metadata":{"files":{"readme":"README.md","changelog":null,"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,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-01-08T16:20:15.000Z","updated_at":"2025-08-05T15:03:40.000Z","dependencies_parsed_at":"2025-08-05T17:11:02.141Z","dependency_job_id":"8a710256-0fd3-438f-bf65-d1dfb9c3e482","html_url":"https://github.com/LLNL/ROSE-LCOM-Tools","commit_stats":null,"previous_names":["llnl/rose-lcom-tools"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/LLNL/ROSE-LCOM-Tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LLNL%2FROSE-LCOM-Tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LLNL%2FROSE-LCOM-Tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LLNL%2FROSE-LCOM-Tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LLNL%2FROSE-LCOM-Tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LLNL","download_url":"https://codeload.github.com/LLNL/ROSE-LCOM-Tools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LLNL%2FROSE-LCOM-Tools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34110011,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","cohesion","lack-of-cohesion","lack-of-cohesion-of-test-methods","lcom","metrics","metrics-gathering","object-oriented","oop","software-engineering","static-analysis","static-analyzer"],"created_at":"2024-11-11T21:34:40.527Z","updated_at":"2026-06-09T13:31:19.194Z","avatar_url":"https://github.com/LLNL.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LCOM Metric Analyzer\n\n## Description\n\nLCOM Metric Analyzer is a tool that evaluates the quality of object-oriented code by identifying classes that lack cohesion.\nThese classes can be broken down into smaller, more manageable units for improved clarity and maintenance.\nCohesion is measured using the various [LCOM (Lack of Cohesion of Methods) metrics](#lcom-definitions-in-plain-english), and source code is processed using the [ROSE compiler infrastructure](http://rosecompiler.org/).\n\n## Example\n\nGiven the following source code for the class in [`c4.adb`](testcases/simple-cases/c4.adb):\n\n```ada\npackage body c4 is\n    procedure m1 is\n    begin\n        a1 := 1;\n        a2 := 2;\n    end m1;\n    procedure m2 is\n    begin\n        a1 := 1;\n        m3;\n    end m2;\n    procedure m3 is\n    begin\n        a3 := 3;\n    end m3;\n    procedure m4 is\n    begin\n        a4 := 4;\n        m3;\n    end m4;\nend c4;\n```\n\nOur tool converts it into an LCOM graph, where each method is a box, each attribute is an ellipse, and arrows indicate an attribute/method access.\nNote how methods can call other methods, with arrows between boxes indicating the calls.\n\n![An LCOM DOT graph for c4.adb](resources/c4.svg)\n\nThis graph is analyzed by the tool using the [definitions of LCOM](#lcom-definitions-in-plain-english) to compute the lack of cohesion of methods for the class.\n\n| LCOM1 | LCOM2 | LCOM3 | LCOM4 | LCOM5 |\n|-------|-------|-------|-------|-------|\n| 5     | 4     | 3     | 1     | 11/12 |\n\n## Installing\n\nThis tool has been tested to work with **Ubuntu 20.04** and **Ubuntu 22.04**, but in principle, any Linux distribution supported by ROSE should work.\n\nFor ease of use, a `dockerfile` has been provided. It can be built using the following command:\n```bash\ndocker build -t lcom -f dockerfile .\n```\n\nManual installation instructions follow:\n\n### Dependencies\nInstall the required dependencies using your package manager:\n```bash\nsudo apt-get update\nsudo apt-get install -y bison byacc cmake dbus flex fontconfig g++ git gnat gprbuild libtool libx11-xcb1 make python3 wget\n```\n\n### Example environment\nSet up the environment by choosing where to install tools.\nAdd these to your `.bashrc`.\n\n```bash\n# Set these to an install location of your preference for each tool.\nexport GNAT_HOME=\"/GNAT/2019\"\n# Set these based on where you place the associated git repositories.\nexport BOOST_REPO=\"/boost_1_83_0\"\nexport ROSE_REPO=\"/rose\"\nexport GTEST_REPO=\"/gtest-parallel\"\nexport LCOM_HOME=\"/ROSE-LCOM-Tools\"\n\n# These paths make it possible for all tools to be found during the build and run process.\n# They should generally remain unchanged.\nexport PATH=\"$GNAT_HOME/bin:$PATH\"\n# export LD_LIBRARY_PATH=\"$GNAT_HOME/lib64:$GNAT_HOME/lib:$LD_LIBRARY_PATH\"\nexport BOOST_HOME=\"$BOOST_REPO/install\"\nexport LD_LIBRARY_PATH=\"$BOOST_HOME/stage/lib\":$LD_LIBRARY_PATH\nexport BOOST_LIB=\"$BOOST_HOME/stage/libexport\"\nexport ROSE_HOME=\"$ROSE_REPO/install_tree\"\nexport BOOST_ROOT=\"$BOOST_HOME\"\nexport ASIS_ADAPTER=\"$ROSE_REPO/build_tree/src/frontend/Experimental_Ada_ROSE_Connection/parser/asis_adapter\"\n```\n\n### Installing GNAT Community Edition 2019:\nTo install [GNAT](https://blog.adacore.com/gnat-community-2019-is-here), you can one of two methods: (1) an automated install using a community-created tool or (2) manually via a GUI.\n#### Automated install\n```bash\ngit clone --depth 1 https://github.com/AdaCore/gnat_community_install_script.git\npushd gnat_community_install_script\nwget -O gnat-community-2019-20190517-x86_64-linux-bin https://community.download.adacore.com/v1/0cd3e2a668332613b522d9612ffa27ef3eb0815b?filename=gnat-community-2019-20190517-x86_64-linux-bin\nsh install_package.sh ./gnat-community-2019-20190517-x86_64-linux-bin $GNAT_HOME\npopd\n```\n*or*\n#### Manual install\n```bash\nwget -O gnat-community-2019-20190517-x86_64-linux-bin https://community.download.adacore.com/v1/0cd3e2a668332613b522d9612ffa27ef3eb0815b?filename=gnat-community-2019-20190517-x86_64-linux-bin\nchmod +x gnat-community-2019-20190517-x86_64-linux-bin \n./gnat-community-2019-20190517-x86_64-linux-bin\n# Follow the setup instructions, installing to the location specified by $GNAT_HOME.\n```\n\n### Building ASIS\n```bash\nwget -O asis.tar.gz https://community.download.adacore.com/v1/52c69e7295dc301ce670334f8150193ecbec580d?filename=asis-2019-20190517-18AB5-src.tar.gz\ntar -xvzf asis.tar.gz\npushd asis-2019-20190517-18AB5-src\nsed -i 's/for Library_Kind use \\\"static\\\";/for Library_Kind use \\\"dynamic\\\";/g' asis.gpr\nmake all install prefix=$GNAT_HOME\npopd\nrm asis.tar.gz\n```\n\n### Building BOOST\nBuild and install [BOOST](https://www.boost.org/) using the GNAT compiler.\n```bash\nwget https://archives.boost.io/release/1.83.0/source/boost_1_83_0.tar.bz2\ntar -xvf boost_1_83_0.tar.bz2\npushd $BOOST_REPO\nmkdir -p tools/build/src/\necho \"using gcc : 8.3.1 : $GNAT_HOME/bin/g++ ; \" \u003e\u003e tools/build/src/user-config.jam\nbash bootstrap.sh\n./b2 -j$(nproc)\n./b2 install --prefix=$BOOST_HOME\npopd\nrm boost_1_83_0.tar.bz2\n```\n\n### Building ROSE\nBuild [ROSE](https://github.com/rose-compiler/rose) with Ada language support with the following commands.\n\n**NOTE**: The Ada representation in ROSE is not yet finalized, so incompatibilities with newer versions of ROSE may be possible. Our tool is confirmed to work with ROSE version `0.11.145.3`.\n\n```bash\ngit clone --depth 1 https://github.com/rose-compiler/rose.git $ROSE_REPO\ncd $ROSE_REPO\n./build\nmkdir -p build_tree\npushd build_tree\nexport LD_LIBRARY_PATH=\"$GNAT_HOME/lib64:$GNAT_HOME/lib:$LD_LIBRARY_PATH\"\n../configure --prefix=$ROSE_HOME --enable-languages=c,c++ --enable-experimental_ada_frontend --without-swi-prolog --without-cuda --without-java --without-python --with-boost=$BOOST_HOME --verbose --with-DEBUG=-ggdb --with-alloc-memset=2 --with-OPTIMIZE=\"-O0 -march=native -p -DBOOST_TIMER_ENABLE_DEPRECATED\" --with-WARNINGS=\"-Wall -Wextra -Wno-misleading-indentation -Wno-unused-parameter\" CXX=$GNAT_HOME/bin/g++ CC=$GNAT_HOME/bin/gcc\nmake core -j$(nproc)\nmake install-core -j$(nproc)\nmake check-core -j$(nproc)\n# Build the ROSE AST DOT graph generator.\npushd exampleTranslators\nmake -j$(nproc)\npopd\npopd\n# NOTE: Restart your terminal after this to clear the changes to LD_LIBRARY_PATH. Adding GNAT to the path adds out-of-date libraries as well, and may throw errors when running certain commands. However, it is required for the build process.\n```\n\n### Setting up Google Tests Parallel Script\nThis is used by [`allTest.py`](script/allTest.py) to run all test cases in parallel.\n\n```bash\ngit clone --depth 1 https://github.com/google/gtest-parallel.git $GTEST_REPO\n```\n\n## Building and testing the tool\n\nThe recommended process uses [`cmake`](CMakeLists.txt). A [`Makefile`](Makefile) is also provided.\n\nStart by cloning the repo such that it is in the location specified by `$LCOM_HOME`\n```bash\ngit clone --depth 1 https://github.com/LLNL/ROSE-LCOM-Tools.git $LCOM_HOME\ncd $LCOM_HOME\n```\n\nNow choose a build process, either using `cmake` or running the full build command.\n\n### cmake\n\n```bash\nrm -r build/; # Remove the build directory to ensure a fresh build (rarely needed)\ncmake -S . -B build # Create the build directory with autogenerated makefiles\ncmake --build build --parallel $(nproc) # Build all LCOM tools in parallel\npushd build \u0026\u0026 ctest; popd # Run GTests sequentially\n\n# Alternatively run GTests in parallel\n$GTEST_REPO/gtest-parallel build/lcom-unittest\n```\n\n### Full build command\n\nAs an alternative to a proper build system, you can also build directly with the following commands:\n\n```bash\nmkdir -p build\n# Main LCOM tool.\ng++ -o build/lcom.out src/lcom.cpp -Iinclude -I${ROSE_HOME}/include/rose -I${BOOST_HOME}/include -lrose -lboost_date_time -lboost_thread -lboost_filesystem -lboost_program_options -lboost_regex -lboost_system -lboost_serialization -lboost_wave -lboost_iostreams -lboost_chrono -ldl -lm -lquadmath -lasis_adapter -lstdc++fs -pthread -L${ROSE_HOME}/lib -L${BOOST_HOME}/lib -L${ASIS_ADAPTER}/lib -Wl,-rpath ${BOOST_HOME}/lib -Wl,-rpath ${ASIS_ADAPTER}/lib -Wl,-rpath=${ROSE_HOME}/lib\n# LCOM DOT graph generator for visualizations.\ng++ -o build/lcom-dot.out src/lcom-dot.cpp -Iinclude -I${ROSE_HOME}/include/rose -I${BOOST_HOME}/include -lrose -lboost_date_time -lboost_thread -lboost_filesystem -lboost_program_options -lboost_regex -lboost_system -lboost_serialization -lboost_wave -lboost_iostreams -lboost_chrono -ldl -lm -lquadmath -lasis_adapter -lstdc++fs -pthread -L${ROSE_HOME}/lib -L${BOOST_HOME}/lib -L${ASIS_ADAPTER}/lib -Wl,-rpath ${BOOST_HOME}/lib -Wl,-rpath ${ASIS_ADAPTER}/lib -Wl,-rpath=${ROSE_HOME}/lib\n```\n\n### Optional tests\n\nThis tool has been tested with additional sources not included in this repo.\nYou can prepare them for use with this tool using the following commands:\n\n```bash\nbash acats.sh \u0026\nbash osc.sh\n```\n\n#### ACATS\n\nROSE is designed to support Ada 95, so we use the associated ACATS version, 2.6.\n[`acats.sh`](acats.sh) can be used to download and process the source into `testcases/acats`.\n\n#### Open-source code\n\nA collection of open source code that uses the Ada 95 language.\n\n| Project                                                                               | Ada lines of code |\n|---------------------------------------------------------------------------------------|------------------:|\n| [Ada Exploiting](https://github.com/bkungl/AdaExploiting)                             | 1,675             |\n| [Ada Structured Library](https://sourceforge.net/projects/adasl/)                     | 48,258            |\n| [ALIRE: Ada LIbrary REpository](https://github.com/alire-project/alire)               | 50,999            |\n| [Ada 95 Booch Components](https://sourceforge.net/projects/booch95/)                  | 34,073            |\n| [Simple components for Ada](https://sourceforge.net/projects/simplecomponentsforada/) | 463,660           |\n| [Fuzzy sets for Ada](https://sourceforge.net/projects/fuzzysetsforada/)               | 695,430           |\n| [GNAT Studio](https://github.com/AdaCore/gnatstudio)                                  | 845,908           |\n| [Libadalang-tools](https://github.com/AdaCore/libadalang-tools)                       | 140,481           |\n| [LinXtris](https://sourceforge.net/projects/linxtris/)                                | 5,341             |\n| [PHCpack](https://github.com/janverschelde/PHCpack)                                   | 2,492,729         |\n| [PNG_IO](https://sourceforge.net/projects/png-io/)                                    | 4,214             |\n| [SHA-1](https://github.com/UlrikHjort/SHA-1)                                          | 498               |\n| [Ada KALINDA OS](https://sourceforge.net/projects/sx-ada-kalinda/)                    | 20,383            |\n\nTo download the source into `testcases/osc`, run [`osc.sh`](osc.sh)\nThis will download all of the projects in parallel.\n\n#### simple-cpp-programs\n\nSome basic C++ programs.\nThese were used to verify functionality of the LCOM tool on basic C++ code.\n\n```bash\ngit clone https://github.com/amngupta/simple-cpp-programs.git testcases/simple-cpp-programs\n```\n\n## Usage\n\n### Quick start\n\nRun `bash allTest.sh` to run tests.\n\n### Custom run\n\n1. Copy any source code into `testcases/\u003cyour directory here\u003e` for evaluation.\n1. Many options can be specified. View them with `python3 scripts/allTest.py -h`\n1. Run `python3 scripts/allTest.py \u003ctask\u003e`, specifying which tasks you want to run. The following tasks are available:\n- build\n- wipe_output\n- make_dot_graphs\n- gen_lcom\n- make_lcom_dot_graphs\n- combine_csv\n- run_gtests **NOTE**: Will not work without cmake.\n\nMultiple tasks, each separated by a space, can be selected to run in one test.\nIf no task is specified, all of them will run.\n\n### Replacing the compiler\n\nThe ROSE compiler tool is designed to accept source code files using the same syntax as a traditional compiler.\nAs a result, we can replace the existing compiler used in a codebase's build system with a call to our LCOM tool instead.\nThis enables fairly generalized support for existing projects in a variety of build systems such as `make` and `cmake`.\n\nTo accomplish this, we provide a wrapper script, [gcc_replace.sh](LLNL/ROSE-LCOM-Tools/script/gcc_replace.sh), that can be used in lieu of a standard compiler.\nIt will still call `g++` under the hood, but it will additionally call the LCOM tool on the side to generate LCOM metrics reports.\nReports for each source file are placed by default next to each, as a `csv` file.\n\nExample usage for a `cmake` project:\n\n```bash\n# cd \"$LCOM_HOME/testcases/\u003cproject-to-analyze\u003e\"\n# cmake -DCMAKE_CXX_COMPILER=\"$LCOM_HOME/script/gcc_replace.sh\" -S . -B build\n# cmake --build build --parallel $(nproc)\n```\n\n## High-level code overview\n\n### [AST Traversal](include/traverse.hpp)\n\nAbstract syntax tree traversal is the most complex step.\nAt a high level, it works using ROSE's AstTopDownProcessing visitor traversal pattern, a recursive pattern that accesses each node from the top down.\nThis ensures every node is evaluated.\nAn inherited attribute is copied down to child nodes, but all inherited attributes are static in our approach.\nWhenever one of our target node types is seen (e.g., Class=`SgAdaPackageSpec*`, Method=`SgFunctionDeclaration*`, Attribute=`SgInitializedName*`), we process its relationship with the other nodes.\n\n#### Class\n\nThe class is the simplest.\nWhen a class node is seen, it is added to the list of classes.\n\n#### Method\n\nWhen a method is seen, it is added to the list of methods and associated to its parent class.\nThe parent class is identified by traversing up to parent scopes until a matching class type is seen.\n\n#### Attribute\n\nWhen an attribute is seen, it is added to the list of attributes and associated to its parent method.\nThe parent method is identified by traversing up to parent scopes until a matching method type is seen.\n\n#### Called method\n\nWhen a method is called, it is associated to the method that called it by traversing up to parent scopes until a matching method type is seen.\n\n#### Aliases\n\nAttributes and methods can be renamed in Ada and C++, complicating the process of identifying methods that share attributes.\nWhen a renaming, pointer, etc. is seen, it is stored in a renaming map, which can be used to look up the root attribute or method associated with the call.\n\n#### Fields\n\nAda records are used to contain fields, allowing multiple attributes to be tied to a single object.\nIf a record is accessed, it needs to be seen as overlapping with any access to any underlying fields as well.\nSince record fields can themselves be records, it is possible that a field will be created and later accessed several records down.\nTo accommodate this, we use a tree data structure, where each node is an attribute and children are fields.\nEvery method access to a specific attribute is associated with the corresponding node.\nTo find overlapping method accesses, traverse up from each leaf node to the root, connecting all methods found along each leaf-to-root traversal.\n\n### [LCOM](include/lcom.hpp)\n\nOnce the ROSE AST has been traversed and the relationships between classes, methods, and attributes is captured, LCOM1-5 are calculated using the standard approaches [outlined here](http://web.archive.org/web/20220307222105/https://www.ece.rutgers.edu/~marsic/books/SE/instructor/slides/lec-16%20Metrics-Cohesion.ppt).\nAdditional, normalized metrics are computing by taking the LCOM metric divided by lowest possible cohesion for a class with the given number of methods, where 1 is least cohesive and 1/#methods is the most cohesive.\n\n#### LCOM definitions, in plain English\n\n- [LCOM1](https://doi.org/10.1145/118014.117970):\nComputes cohesion in terms of pairwise accesses.\nCounts the number of method pairs that share no attribute accesses and thus may be unrelated to the rest of the class.\n- [LCOM2](https://doi.org/10.1109/32.295895):\nComputes cohesion in terms of pairwise accesses.\nCounts the number of method pairs that share no attribute accesses minus the number of pairs of methods that do share attributes.\nThis approach is simillar to LCOM1, but it better rewards classes with lots of cohesive methods even if some are still unrelated.\n- [LCOM3](https://doi.org/10.1016/0164-1212(93)90077-B):\nUses a graph representation.\nCounts the number of disjoint graphs, where methods are nodes and edges form via shared attribute accesses.\nThe high-level idea is that LCOM3 explicitly identifies the number of method groups that could be separated into distinct classes.\n- [LCOM4](https://doi.org/10.1109/32.491650):\nUses a graph representation.\nCounts the number of disjoint graphs, where methods are nodes and edges form via shared attribute accesses and between a method that calls another method.\nThe high-level idea is that LCOM4 explicitly identifies the number of method groups that could be separated into distinct classes.\nUnlike LCOM3, it also recognizes that the methods that call one another form a dependency that may be hard to split.\n- LCOM5:\nRepresents cohesion in terms of the proportion of attributes shared between methods, using the formula `(a-k*l)/(l-k*l)`, where `a` is the number of attribute accesses, `l` is the number of attributes, and `k` is the number of methods.\nAt a high-level, the numerator represents the difference between the maximum number of unique attribute accesses possible (the case where every method uses every attribute) and the actual number of attribute accesses.\nThe denominator normalizes the value to a range between 0 (where the actual accesses includes all possible accesses) and 1 (where each attribute is only accessed once and thus is never shared between methods).\n- [YALCOM](https://doi.org/10.48550/arXiv.2012.12324):\nA normalized form of LCOM4, dividing LCOM4 by the number of methods in the class, `k` to ensure a cohesiveness between 0 and 1.\nIt additionally distinguishes between a fully cohesive class (0) and a class with no methods (-1).\n\n\n### Ada - What is a class?\n\nAda has no specific class construct in the language, so identifying an object that could be used as a class is non-obvious.\nAnything with a distinct [scope](https://perso.telecom-paristech.fr/pautet/Ada95/chap09.htm) in Ada could reasonably be used as a class.\nWe elected to use the same eligible local program units chosen by [GNATmetric](https://www.adacore.com/static-analysis/gnatmetric) as our class types: packages, functions/procedures/subprograms, and protected objects.\nGNATmetric also evaluates tasks.\nIn this situation, entries are methods.\nHowever, there is no clear way for an entry to reference an attribute, so LCOM is not meaningful here.\n\n### Correctness, assumptions, and limitations\n\nTo determine if our tool produces the correct results, we must first report our assumptions.\n\n- Attributes that are never accessed do not count toward the attribute count used to calculate LCOM5.\n- All methods within a class are considered, even if they have no accessed attributes.\n- If an attribute is accessed multiple times within a method, it is seen as only a single access. This can affect LCOM5. \n- An array is seen as a single attribute for the purposes of LCOM.\n- When DotBehavior is set to LeftOnly, access to a record field counts as an access to the object as a whole. In this situation, we do not track individual fields as unique attributes.\n- When DotBehavior is set to Full, access to a record field counts as a single access to the specific field. If a field access overlaps with another (potentially parent) field or record access, it is counted as a shared access.\n- Attribute accesses and method calls made outside of a method's scope are ignored.\n- Methods outside of a class are ignored.\n- Access to data outside of the currently evaluated file are often inaccessible. What is analyzed by the LCOM tool is limited to the contents of the AST generated by ROSE. For instance, analyzing [point_complex.adb](testcases/other-tests/point_complex.adb) can find the declarations in [gcomplex.ads](testcases/other-tests/gcomplex.ads) but misses the attribute accesses made in the method definitions found in [gcomplex.adb](testcases/other-tests/gcomplex.adb) because they are not in the AST.\n\n## Finding and reporting issues\nThis tool has been tested for functionality with Ada and C++.\nIn principle, it should be compatible with all languages that work with ROSE, although coverage of language features have only been thoroughly investigated for Ada and C++.\n\nIssues with the tool are likely to be reported in the form of warning/error/fatal logs, unexpected program termination, or assertion failure.\nThese can be tracked down in logs using the following RegEx:\n```regex\n\\[(Fatal|Error|Warn)\\]|(terminate called after)|(Assertion )\n```\nIssue reports for this tool should include the relevant logs (at trace level) and source files.\n\n## Remaining work\n\n### Support for additional programming languages\nWork could be done to improve support for other languages.\nWhile other languages are handled by ROSE, this tool has only been tested extensively on Ada and C++ code.\nLanguages are complex and this tool may require significant additional work to handle complex language features in a reasonable way.\nHowever, the extension of this tool to accommodate C++ was relatively straightforward, suggesting additional language support may be as simple as adding special cases for specialized AST node types.\n\n### Experiment with nested access behavior\nCurrently, all attribute and called method accesses are associated only with their immediate scope parent class.\nIt would be interesting to see how LCOM changes if we associated that access with all parent classes, to handle nested classes.\nIn an examination of [other LCOM tools](#related-works-and-resources), there was no clear consensus in whether or not to support this.\nIf this is implemented, an associated test case should be made for [child.adb](testcases/other-tests/child.adb) to ensure it works properly.\n\n### Associate attributes in a called method back to the caller\nWhen a method calls another method, it indirectly accesses all of the attributes within that called method.\nWe should see what happens to LCOM if we recursively identify these attributes and associate them back to the calling method.\nThis should already be handled by LCOM4 but may impact the results of LCOM5.\n\n### Count number of fields within a record\nLCOM5 currently counts the appearance of an attribute node as a single attribute access.\nHowever, when that attribute is a record, it has multiple fields associated with it, each of which can be seen as a separate attribute access for the purposes of LCOM5.\nIt may be worth tracking the number of underlying fields associated with each record access to report a more accurate LCOM5 metric.\n\n### Ada - Handle methods that reference multiple tagged types  \nTagged types are supported by our tool, but they currently only work when a method specifies a single tagged type as a parameter.\nWhile this is the most common configuration, it is also possible to have multiple tagged types as parameters, essentially giving multiple classes ownership of a single method.\nThis situation is not currently supported and may take a significant amount of refactoring to support correctly.\n\n### Ada - Integrate with [Ada Analysis Toolkit](https://rosecompiler2.llnl.gov/gitlab/rose-tools/ada-analysis-toolkit)\nThe Ada analysis toolkit is a useful visualization tool to evaluate a codebase.\nLCOM could be integrated into this tool to color-code methods by LCOM and display their relationships in the code.\n\n### Miscellany\n- Fix NPrint::p() in [node-print.hpp](include/node-print.hpp) to use a hierarchy of supported print functions.\n- Fix Cache in [lcom.hpp](include/lcom.hpp) to improve performance.\n\n## Related works and resources\n\n### Learning materials\n\n- [LCOM Lecture Slides](https://www.ece.rutgers.edu/~marsic/books/SE/instructor/slides/lec-16%20Metrics-Cohesion.ppt) ([archive.org backup](http://web.archive.org/web/20220307222105/https://www.ece.rutgers.edu/~marsic/books/SE/instructor/slides/lec-16%20Metrics-Cohesion.ppt)): Definition of LCOM with visuals and comparisons\n- [Cohesion metrics](https://www.aivosto.com/project/help/pm-oo-cohesion.html): Description of LCOM\n- [Class Cohesion Metrics for Software Engineering: A Critical Review](https://www.math.md/files/csjm/v25-n1/v25-n1-(pp44-74).pdf): Overview of cohesion state of the art\n- [Refactoring Effect on Cohesion Metrics](https://ieeexplore.ieee.org/abstract/document/5328998): Evaluation of how effective cohesion methods are as refactoring aids\n\n### Evaluated tools\n\n- [YALCOM](https://www.tusharma.in/yalcom-yet-another-lcom-metric.html): Yet Another LCOM Metric\n- [LCOM](https://github.com/tushartushar/LCOM): Java LCOM implementation\n- [jpeek](https://github.com/cqfn/jpeek): Alternative Java LCOM implementation\n- [lcom](https://github.com/potfur/lcom): Python-based LCOM implementation\n- [LCOM4go](https://github.com/yahoojapan/lcom4go): Golang-based LCOM4 implementation\n\n### Additional tools (untested)\n- JavaScript: https://github.com/FujiHaruka/eslint-plugin-lcom\n- C#: https://github.com/teo-tsirpanis/lcom-calculator\n- PHP: https://github.com/phpmetrics/PhpMetrics/blob/master/doc/metrics.md\n- Java: https://github.com/rodhilton/jasome/blob/master/src/main/java/org/jasome/metrics/calculators/LackOfCohesionMethodsCalculator.java\n- Java: https://github.com/imgios/DARTS/blob/main/src/main/testSmellDetection/structuralRules/LackOfCohesionOfTestSmellStructural.java\n- Java: https://github.com/mauricioaniche/ck\n\n# Other LCOM tools\n\n## [JPeek](https://github.com/cqfn/jpeek)\n\nInstalling: See README at https://github.com/cqfn/jpeek\n\nRunning:\n```bash\nfind -name \"*.java\" \u003e sources.txt\njavac @sources.txt\njava -jar other-tools/jpeek-0.32.2-jar-with-dependencies.jar --sources testcases/paper --target ./other-tools/jpeek --overwrite --metrics LCOM,LCOM2,LCOM3,LCOM4,LCOM5\n```\n\n## [LCOM Metrics Computation](https://github.com/tushartushar/LCOM)\n\nInstalling:\n```bash\ncd other-tools/LCOM\nsudo apt-get install maven -y\nmvn package\n```\n\nRunning:\n```bash\njava -jar other-tools/LCOM/target/LCOM.jar -i testcases/paper -o other-tools/LCOM-MC\n```\n\n## [LCOM4go](https://github.com/yahoojapan/lcom4go)\n\nInstalling: See README at https://github.com/yahoojapan/lcom4go\n```bash\ngo install --ldflags \"-s -w\" --trimpath github.com/yahoojapan/lcom4go/cmd/lcom4@latest\n```\n\nRunning:\n```bash\n$(go env GOPATH)/bin/lcom4\n```\n\n\n## [PyLCOM](https://github.com/potfur/lcom)\n\nInstalling:\n```bash\n pip3 install lcom\n```\n\nRunning:\n```bash\n~/.local/bin/lcom testcases/paper\n```\n\n## Running all competing tools\n\n```bash\nfind testcases/paper/ -name \"*.java\" -print0 | xargs -0 javac \u0026\u0026 java -jar other-tools/jpeek-0.32.2-jar-with-dependencies.jar --sources testcases/paper --target ./other-tools/jpeek --overwrite --metrics LCOM,LCOM2,LCOM3,LCOM4,LCOM5\n\njava -jar other-tools/LCOM/target/LCOM.jar -i testcases/paper -o other-tools/LCOM-MC\n\ntest=\u003cTest Name Here\u003e\n$(go env GOPATH)/bin/lcom4 testcases/paper/$test/$test.go\n# NOTE: Nothing is returned if LCOM = 1\n\n~/.local/bin/lcom testcases/paper\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllnl%2Frose-lcom-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fllnl%2Frose-lcom-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fllnl%2Frose-lcom-tools/lists"}