Skip to content

Commit

Permalink
[analyze] Analyze header file with --file option
Browse files Browse the repository at this point in the history
  • Loading branch information
csordasmarton committed Mar 7, 2022
1 parent c1fd053 commit 9d6988c
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 11 deletions.
60 changes: 51 additions & 9 deletions analyzer/codechecker_analyzer/cmd/analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import shutil
import sys

from typing import List

from codechecker_report_converter.util import load_json_or_empty
from tu_collector import tu_collector

from codechecker_analyzer import analyzer, analyzer_context, env
from codechecker_analyzer.analyzers import analyzer_types, clangsa
Expand All @@ -33,6 +36,9 @@

LOG = logger.get_logger('system')

header_file_extensions = (
'.h', '.hh', '.H', '.hp', '.hxx', '.hpp', '.HPP', '.h++', '.tcc')

epilog_env_var = f"""
CC_ANALYZERS_FROM_PATH Set to `yes` or `1` to enforce taking the analyzers
from the `PATH` instead of the given binaries.
Expand Down Expand Up @@ -725,22 +731,58 @@ def add_arguments_to_parser(parser):
func=main, func_process_config_file=cmd_config.process_config_file)


def __get_skip_handlers(args) -> SkipListHandlers:
def get_affected_file_paths(
file_filters: List[str],
compile_commands: tu_collector.CompilationDB
) -> List[str]:
"""
Returns a list of source files for existing header file otherwise returns
with the same file path expression.
"""
file_paths = [] # Use list to keep the order of the file paths.
for file_filter in file_filters:
file_paths.append(file_filter)

if os.path.exists(file_filter) and \
file_filter.endswith(header_file_extensions):
LOG.info("Get dependent source files for '%s'...", file_filter)
dependent_sources = tu_collector.get_dependent_sources(
compile_commands, file_filter)

LOG.info("Get dependent source files for '%s' done.", file_filter)
LOG.debug("Dependent source files: %s",
', '.join(dependent_sources))

file_paths.extend(dependent_sources)

return file_paths


def __get_skip_handlers(args, compile_commands) -> SkipListHandlers:
"""
Initialize and return a list of skiplist handlers if
there is a skip list file in the arguments or files options is provided.
"""
skip_handlers = SkipListHandlers()
if 'files' in args:
source_file_paths = get_affected_file_paths(
args.files, compile_commands)

# Creates a skip file where all source files will be skipped except
# the given source files and all the header files.
skip_files = ['+{0}'.format(f) for f in args.files]
skip_files = ['+{0}'.format(f) for f in source_file_paths]
skip_files.extend(['+/*.h', '+/*.H', '+/*.tcc'])
skip_files.append('-*')
skip_handlers.append(SkipListHandler("\n".join(skip_files)))
content = "\n".join(skip_files)
skip_handlers.append(SkipListHandler(content))
LOG.debug("Skip handler is created for the '--file' option with the "
"following filters:\n%s", content)
if 'skipfile' in args:
with open(args.skipfile, encoding="utf-8", errors="ignore") as f:
skip_handlers.append(SkipListHandler(f.read()))
content = f.read()
skip_handlers.append(SkipListHandler(content))
LOG.debug("Skip handler is created for the '--ignore' option with "
"the following filters:\n%s", content)

return skip_handlers

Expand Down Expand Up @@ -868,8 +910,12 @@ def main(args):
sys.exit(1)
compiler_info_file = args.compiler_info_file

compile_commands = load_json_or_empty(args.logfile)
if compile_commands is None:
sys.exit(1)

# Process the skip list if present.
skip_handlers = __get_skip_handlers(args)
skip_handlers = __get_skip_handlers(args, compile_commands)

ctu_or_stats_enabled = False
# Skip list is applied only in pre-analysis
Expand Down Expand Up @@ -897,10 +943,6 @@ def main(args):
analyzer_env = env.extend(context.path_env_extra,
context.ld_lib_path_extra)

compile_commands = load_json_or_empty(args.logfile)
if compile_commands is None:
sys.exit(1)

# Number of all the compilation commands in the parsed log files,
# logged by the logger.
all_cmp_cmd_count = len(compile_commands)
Expand Down
16 changes: 14 additions & 2 deletions analyzer/tests/functional/skip/test_skip.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def __log_and_analyze_simple(self, analyzer_extra_options=None):
print(err)
errcode = process.returncode
self.assertEqual(errcode, 0)
return out, err

def __run_parse(self, extra_options=None):
""" Run parse command with the given extra options. """
Expand Down Expand Up @@ -226,6 +227,19 @@ def test_analyze_skip_everything(self):
self.assertFalse(
glob.glob(os.path.join(self.report_dir, '*.plist')))

def test_analyze_header_with_file_option(self):
""" Analyze a header file with the --file option. """
header_file = os.path.join(self.test_dir, "simple", "skip.h")
out, _ = self.__log_and_analyze_simple(["--file", header_file])
self.assertIn(
f"Get dependent source files for '{header_file}'...", out)
self.assertIn(
f"Get dependent source files for '{header_file}' done.", out)

plist_files = glob.glob(os.path.join(self.report_dir, '*.plist'))
self.assertTrue(plist_files)
self.assertTrue(all('skip_header.cpp' in f for f in plist_files))

def test_analyze_file_option_skip_everything(self):
"""
Test analyze command --file option when everything is skipped by a
Expand Down Expand Up @@ -295,8 +309,6 @@ def test_analyze_only_file_option(self):
"""
self.__log_and_analyze_simple([
"--file", "*/skip_header.cpp"])
print(glob.glob(
os.path.join(self.report_dir, '*.plist')))
self.assertFalse(
any('skip_header.cpp' not in f for f in glob.glob(
os.path.join(self.report_dir, '*.plist'))))
Expand Down

0 comments on commit 9d6988c

Please sign in to comment.