Coverage for lobster/tools/cpp/implementation_builder.py: 100%

28 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-09-22 04:43 +0000

1# LOBSTER - Lightweight Open BMW Software Traceability Evidence Report 

2# Copyright (C) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) 

3# 

4# This program is free software: you can redistribute it and/or modify 

5# it under the terms of the GNU Affero General Public License as 

6# published by the Free Software Foundation, either version 3 of the 

7# License, or (at your option) any later version. 

8# 

9# This program is distributed in the hope that it will be useful, but 

10# WITHOUT ANY WARRANTY; without even the implied warranty of 

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 

12# Affero General Public License for more details. 

13# 

14# You should have received a copy of the GNU Affero General Public 

15# License along with this program. If not, see 

16# <https://www.gnu.org/licenses/>. 

17 

18from os.path import abspath 

19from typing import Dict, Match 

20from lobster.common.file_tag_generator import FileTagGenerator 

21from lobster.common.items import Implementation, Tracing_Tag 

22from lobster.common.location import File_Reference 

23 

24 

25class ImplementationBuilder: 

26 """ 

27 A specialized file tag generator for C/C++ files. 

28 It generates Tracing_Tag and File_Reference objects based on the file name and line 

29 number. 

30 """ 

31 

32 MIN_NUM_GROUPS = 4 

33 REASON_GROUP_NUM = MIN_NUM_GROUPS + 1 

34 REFERENCE_GROUP_NUM = MIN_NUM_GROUPS + 1 

35 

36 def __init__(self) -> None: 

37 self._generator = FileTagGenerator() 

38 

39 def from_match_if_new( 

40 self, 

41 db: Dict[str, Implementation], 

42 match: Match, 

43 ) -> Implementation: 

44 """ 

45 Builds and insert a new Implementation object into the database if it does not 

46 already exist. 

47 Otherwise, it returns the existing Implementation object. 

48 """ 

49 impl = self.from_match(match) 

50 return db.setdefault(impl.tag.key(), impl) 

51 

52 def from_match(self, match: Match) -> Implementation: 

53 """ 

54 Generate an Implementation object from a regex match object. 

55 """ 

56 filename, line_nr, kind, function_name, *_ = match.groups() 

57 try: 

58 line_nr = int(line_nr) 

59 except ValueError as exc: 

60 raise ValueError(f"Invalid line number '{line_nr}' " 

61 f"in regex group '{match.group(2)}'!") from exc 

62 

63 return Implementation( 

64 tag = self._get_tag(filename, function_name, line_nr), 

65 location = self._get_location(filename, line_nr), 

66 language = "C/C++", 

67 kind = kind, 

68 name = function_name, 

69 ) 

70 

71 def _get_tag(self, file: str, function_name: str, line_nr: int) -> Tracing_Tag: 

72 """ 

73 Generate a unique tag for the given file. 

74 """ 

75 file_tag = self._generator.get_tag(file) 

76 function_uid = f"{file_tag}:{function_name}:{line_nr}" 

77 return Tracing_Tag("cpp", function_uid) 

78 

79 @staticmethod 

80 def _get_location(file: str, line_nr: int) -> File_Reference: 

81 """ 

82 Generate a location object for the file using its absolute path. 

83 """ 

84 return File_Reference(abspath(file), line_nr)