Loading...
# SPDX-License-Identifier: GPL-2.0
#
# Copyright 2025 Canonical Ltd
#
"""Base classes for source code analysis.

This module provides base classes and data structures for analyzing which lines
in source files are active vs inactive.
"""

import os
from collections import namedtuple

# Named tuple for file analysis results
# Fields:
#   total_lines: Total number of lines in the file
#   active_lines: Number of lines that are active (not removed by
#       preprocessor)
#   inactive_lines: Number of lines that are inactive (removed by
#       preprocessor)
#   line_status: Dict mapping line numbers to status ('active',
#       'inactive', etc.)
FileResult = namedtuple('FileResult',
                        ['total_lines', 'active_lines',
                         'inactive_lines', 'line_status'])


class Analyser:  # pylint: disable=too-few-public-methods
    """Base class for source code analysers.

    This class provides common initialisation for analysers that determine
    which lines in source files are active vs inactive based on various
    methods (preprocessor analysis, debug info, etc.).
    """

    def __init__(self, srcdir, keep_temps=False):
        """Set up the analyser.

        Args:
            srcdir (str): Path to source root directory
            keep_temps (bool): If True, keep temporary files for debugging
        """
        self.srcdir = srcdir
        self.keep_temps = keep_temps

    def find_object_files(self, build_dir):
        """Find all object files in the build directory.

        Args:
            build_dir (str): Build directory to search

        Returns:
            list: List of absolute paths to .o files
        """
        obj_files = []
        for root, _, files in os.walk(build_dir):
            for fname in files:
                if fname.endswith('.o'):
                    obj_files.append(os.path.join(root, fname))
        return obj_files

    @staticmethod
    def count_lines(file_path):
        """Count the number of lines in a file.

        Args:
            file_path (str): Path to file to count lines in

        Returns:
            int: Number of lines in the file, or 0 on error
        """
        try:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                return len(f.readlines())
        except IOError:
            return 0