diff --git a/docs/codechecker.md b/docs/codechecker.md index 7f4edaa4..5b6ce3f5 100644 --- a/docs/codechecker.md +++ b/docs/codechecker.md @@ -77,15 +77,19 @@ bazel test ... ### Analysis results -You can find the analysis results in the `bazel-bin/` folder, on which you -can run [`CodeChecker store`](https://github.com/Ericsson/codechecker/blob/master/docs/web/user_guide.md#store) -or [`CodeChecker parse`](https://github.com/Ericsson/codechecker/blob/master/docs/analyzer/user_guide.md#parse). -The precise output path to the directory can vary, -but you should look for `your_codechecker_rule_name/codechecker-files/data`. -In simpler cases, something like the following: +Analysis results are written to the bazel-bin/ directory. +The exact output path may vary, but you should find them under: +`bazel-bin/.../your_codechecker_rule_name/codechecker-files/`. +This directory contains: +- result.txt — human-readable results +- result.json — results in structured JSON format +- report/ — results in HTML format +- data/ — the directory containing the raw results + +You can store the results with [`CodeChecker store`](https://github.com/Ericsson/codechecker/blob/master/docs/web/user_guide.md#store). +In simpler cases, with something like the following: ```bash -CodeChecker parse bazel-bin/your_codechecker_rule_name/codechecker-files/data CodeChecker store bazel-bin/your_codechecker_rule_name/codechecker-files/data -n "Run name" ``` diff --git a/src/codechecker_script.py b/src/codechecker_script.py index 95154335..e37603df 100644 --- a/src/codechecker_script.py +++ b/src/codechecker_script.py @@ -246,7 +246,6 @@ def run(args): analyze(args) parse( input_dir=args.output, - output_dir=args.output, codechecker=args.codechecker, config=args.config, env=args.env, diff --git a/src/common.py b/src/common.py index 25bf028f..76977378 100644 --- a/src/common.py +++ b/src/common.py @@ -136,14 +136,13 @@ def stage(title, method="info"): # pylint: disable=too-many-arguments,too-many-positional-arguments def parse( - input_dir, output_dir, codechecker, config, env, log, clang, clang_tidy + input_dir, codechecker, config, env, log, clang, clang_tidy ): """ Run CodeChecker parse commands Args: input_dir (str): Path to the input directory - output_dir (str): Path to the output directory codechecker (str): Path to the CodeChecker binary config (str): Path to the CodeChecker configuration file env (list): Environment variables @@ -160,18 +159,18 @@ def parse( ) # Save results to JSON file command = ( - f"{codechecker_parse} --export=json > " f"{output_dir}/result.json" + f"{codechecker_parse} --export=json > " f"{input_dir}/result.json" ) execute(log, command, env=env, codes=[0, 2]) # Save results as HTML report logging.info("CodeChecker parse -e html") command = ( - codechecker_parse + " --export=html --output=" + output_dir + "/report" + codechecker_parse + " --export=html --output=" + input_dir + "/report" ) execute(log, command, env=env, codes=[0, 2]) # Save results to text file logging.info("CodeChecker parse to text result") - result_file = output_dir + "/result.txt" + result_file = input_dir + "/result.txt" command = codechecker_parse + " > " + result_file execute(log, command, env=env, codes=[0, 2]) logging.info("Result:\n\n%s\n", read_file(log, result_file)) diff --git a/src/per_file.bzl b/src/per_file.bzl index b1c0db57..d8af6a1b 100644 --- a/src/per_file.bzl +++ b/src/per_file.bzl @@ -207,6 +207,7 @@ def _per_file_impl(ctx): info = ctx.attr.toolchain[platform_common.ToolchainInfo].codecheckerinfo else: info = ctx.toolchains["//:toolchain_type"].codecheckerinfo + for target in ctx.attr.targets: if not CcInfo in target: continue @@ -235,6 +236,49 @@ def _per_file_impl(ctx): sources_and_headers, ) all_files += outputs + + # Parse action: collect all plists into a directory and run + # CodeChecker parse to produce result.txt, result.json, HTML report + html_parse_dir = ctx.actions.declare_directory( + ctx.label.name + "/report", + ) + json_parse = ctx.actions.declare_file(ctx.label.name + "/result.json") + txt_parse = ctx.actions.declare_file(ctx.label.name + "/result.txt") + codechecker_parse_log = ctx.actions.declare_file( + ctx.label.name + "/codechecker_parse.log", + ) + + ctx.actions.run( + inputs = all_files + [config_file], + outputs = [html_parse_dir, codechecker_parse_log, json_parse, txt_parse], + executable = per_file_script, + tools = [ + info.runfiles, + ctx.attr._per_file_script[DefaultInfo].files_to_run, + ], + arguments = [ + "--mode", + "Parse", + "--codechecker", + info.codechecker.path, + "--data_dir", + html_parse_dir.path + "/..", + "--log", + codechecker_parse_log.path, + "--config", + config_file.path, + "--clang", + info.clangsa.path, + "--clang_tidy", + info.clang_tidy.path, + ], + mnemonic = "CodeCheckerParse", + use_default_shell_env = True, + progress_message = "CodeChecker parse %s" % str(ctx.label), + ) + + all_files += [html_parse_dir, codechecker_parse_log, json_parse, txt_parse] + ctx.actions.write( output = ctx.outputs.test_script, is_executable = True, diff --git a/src/per_file_script.py b/src/per_file_script.py index adcf316d..9776bb95 100644 --- a/src/per_file_script.py +++ b/src/per_file_script.py @@ -17,12 +17,14 @@ """ import argparse -from dataclasses import dataclass import os import re import shutil import subprocess -from common import fail, setup_logging, build_env +from dataclasses import dataclass +from common import ( + fail, parse, setup_logging, build_env +) @dataclass @@ -52,30 +54,30 @@ def parse_args(argv=None): ) parser.add_argument("--mode", required=True, help="Execution mode") parser.add_argument( - "--codechecker", required=True, help="Path to CodeChecker binary" + "--codechecker", required=False, help="Path to CodeChecker binary" ) parser.add_argument("--verbosity", default="INFO", help="Log level") parser.add_argument( - "--commands", required=True, help="Path to compile_commands.json" + "--commands", required=False, help="Path to compile_commands.json" ) parser.add_argument( "--analyze", default="", help="CodeChecker analyze arguments" ) - parser.add_argument("--config", required=True, help="Path to config file") + parser.add_argument("--config", required=False, help="Path to config file") parser.add_argument( "--data_dir", required=True, help="Output directory for CodeChecker" ) parser.add_argument( - "--file", required=True, help="Path to the file to be analyzed" + "--file", required=False, help="Path to the file to be analyzed" ) - parser.add_argument("--log", required=True, help="Path to the log file") - parser.add_argument("--skip", required=True, help="Path to the skip file") + parser.add_argument("--log", required=False, help="Path to the log file") + parser.add_argument("--skip", required=False, help="Path to the skip file") parser.add_argument( - "--metadata", required=True, help="Path to the metadata file" + "--metadata", required=False, help="Path to the metadata file" ) parser.add_argument( "--analyzer_plists", - required=True, + required=False, help="Semicolon-separated list of analyzer,plist_path pairs", ) parser.add_argument( @@ -89,13 +91,15 @@ def parse_args(argv=None): args = parser.parse_args(argv) - analyzer_plist_paths = [ - item.split(",") for item in args.analyzer_plists.split(";") - ] + analyzer_plist_paths = [] + if args.analyzer_plists: + analyzer_plist_paths = [ + item.split(",") for item in args.analyzer_plists.split(";") + ] return Config( execution_mode=args.mode, - codechecker_bin=os.path.realpath(args.codechecker), + codechecker_bin=os.path.realpath(args.codechecker or "/"), compile_commands=args.commands, codechecker_args=args.analyze, config_file=args.config, @@ -288,6 +292,18 @@ def main(): _create_compile_commands_json_with_absolute_paths(cfg) _run_codechecker(cfg) _move_output_files(cfg) + elif cfg.execution_mode == "Parse": + with open(cfg.log_file, "a", encoding="utf-8"): + pass + parse( + input_dir=cfg.data_dir, + codechecker=cfg.codechecker_bin, + config=cfg.config_file, + env="", + log=cfg.log_file, + clang=cfg.clang, + clang_tidy=cfg.clang_tidy, + ) else: fail( cfg.log_file, diff --git a/test/unit/caching/BUILD b/test/unit/caching/BUILD index c173b56b..79ce3a17 100644 --- a/test/unit/caching/BUILD +++ b/test/unit/caching/BUILD @@ -33,14 +33,14 @@ caching_test( caching_test( name = "caching_per_file_test", - expected_action_count = 1, + expected_action_count = 2, file_to_modify = "secondary.cc", target_name = "per_file_caching", ) caching_test( name = "caching_per_file_ctu_test", - expected_action_count = 2, + expected_action_count = 3, file_to_modify = "secondary.cc", target_name = "per_file_caching_ctu", )