Skip to content

Commit d9a81d9

Browse files
authored
Merge pull request #81 from codellm-devkit/issue-79-support-c
Issue 79 support C
2 parents 91322dd + ebaf7d3 commit d9a81d9

File tree

12 files changed

+1095
-5
lines changed

12 files changed

+1095
-5
lines changed

Diff for: cldk/analysis/c/__init__.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
################################################################################
2+
# Copyright IBM Corporation 2024
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
################################################################################
16+
17+
"""
18+
C Analysis
19+
"""
20+
from .c_analysis import CAnalysis

Diff for: cldk/analysis/c/c_analysis.py

+374
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
################################################################################
2+
# Copyright IBM Corporation 2024
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
################################################################################
16+
17+
"""
18+
Analysis model for C projects
19+
"""
20+
21+
from pathlib import Path
22+
from typing import Dict, List, Optional
23+
24+
from networkx import DiGraph
25+
26+
from cldk.analysis.c.clang import ClangAnalyzer
27+
from cldk.models.c import CApplication, CFunction, CTranslationUnit, CMacro, CTypedef, CStruct, CEnum, CVariable
28+
29+
30+
class CAnalysis:
31+
32+
def __init__(self, project_dir: Path) -> None:
33+
"""Initialization method for C Analysis backend."""
34+
if not isinstance(project_dir, Path):
35+
project_dir = Path(project_dir)
36+
self.c_application = self._init_application(project_dir)
37+
38+
def _init_application(self, project_dir: Path) -> CApplication:
39+
"""Initializes the C application object.
40+
41+
Args:
42+
project_dir (Path): Path to the project directory.
43+
44+
Returns:
45+
CApplication: C application object.
46+
"""
47+
analyzer = ClangAnalyzer()
48+
49+
# Analyze each file
50+
translation_units = {}
51+
for source_file in project_dir.rglob("*.c"):
52+
tu = analyzer.analyze_file(source_file)
53+
translation_units[str(source_file)] = tu
54+
55+
# Create application model
56+
return CApplication(translation_units=translation_units)
57+
58+
def get_c_application(self) -> CApplication:
59+
"""Returns the C application object.
60+
61+
Returns:
62+
CApplication: C application object.
63+
"""
64+
return self.c_application
65+
66+
def get_imports(self) -> List[str]:
67+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
68+
69+
def get_variables(self, **kwargs):
70+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
71+
72+
def get_application_view(self) -> CApplication:
73+
return self.c_application
74+
75+
def get_symbol_table(self) -> Dict[str, CTranslationUnit]:
76+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
77+
78+
def get_compilation_units(self) -> List[CTranslationUnit]:
79+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
80+
81+
def is_parsable(self, source_code: str) -> bool:
82+
"""
83+
Check if the code is parsable using clang parser.
84+
Args:
85+
source_code: source code
86+
87+
Returns:
88+
True if the code is parsable, False otherwise
89+
"""
90+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
91+
92+
def get_call_graph(self) -> DiGraph:
93+
"""Returns the call graph of the C code.
94+
95+
Returns:
96+
DiGraph: The call graph of the C code.
97+
"""
98+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
99+
100+
def get_call_graph_json(self) -> str:
101+
"""Returns a serialized call graph in json.
102+
103+
Raises:
104+
NotImplementedError: Raised when this functionality is not suported.
105+
106+
Returns:
107+
str: Call graph in json.
108+
"""
109+
110+
raise NotImplementedError("Producing a call graph over a single file is not implemented yet.")
111+
112+
def get_callers(self, function: CFunction) -> Dict:
113+
"""Returns a dictionary of callers of the target method.
114+
115+
Args:
116+
function (CFunction): A CFunction object.
117+
118+
Raises:
119+
NotImplementedError: Raised when this functionality is not suported.
120+
121+
Returns:
122+
Dict: A dictionary of callers of target function.
123+
"""
124+
125+
raise NotImplementedError("Generating all callers over a single file is not implemented yet.")
126+
127+
def get_callees(self, function: CFunction) -> Dict:
128+
"""Returns a dictionary of callees in a fuction.
129+
130+
Args:
131+
function (CFunction): A CFunction object.
132+
133+
Raises:
134+
NotImplementedError: Raised when this functionality is not suported.
135+
136+
Returns:
137+
Dict: Dictionary with callee details.
138+
"""
139+
raise NotImplementedError("Generating all callees over a single file is not implemented yet.")
140+
141+
def get_functions(self) -> Dict[str, CFunction]:
142+
"""Returns all functions in the project.
143+
144+
Raises:
145+
NotImplementedError: Raised when current AnalysisEngine does not support this function.
146+
147+
Returns:
148+
Dict[str, Dict[str, JCallable]]: Dictionary of dictionaries of all methods in the C code with qualified class name as key and dictionary of methods in that class.
149+
"""
150+
for _, translation_unit in self.c_application.translation_units.items():
151+
return translation_unit.functions
152+
153+
def get_function(self, function_name: str, file_name: Optional[str]) -> CFunction | List[CFunction]:
154+
"""Returns a function object given the function name.
155+
156+
Args:
157+
function_name (str): The name of the function.
158+
file_name (str): The name of the file containing the function.
159+
160+
Returns:
161+
CFunction: A method for the given qualified method name. If multiple functions with the same name exist, a list of functions is returned.
162+
"""
163+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
164+
165+
def get_C_file(self, file_name: str) -> str:
166+
"""Returns a class given qualified class name.
167+
168+
Args:
169+
file_name (str): The name of the file.
170+
171+
Raises:
172+
NotImplementedError: Raised when current AnalysisEngine does not support this function.
173+
174+
Returns:
175+
str: C file name containing the given qualified class.
176+
"""
177+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
178+
179+
def get_C_compilation_unit(self, file_path: str) -> CTranslationUnit:
180+
"""Given the path of a C source file, returns the compilation unit object from the symbol table.
181+
182+
Args:
183+
file_path (str): Absolute path to C source file
184+
185+
Raises:
186+
NotImplementedError: Raised when current AnalysisEngine does not support this function.
187+
188+
Returns:
189+
CTranslationUnit: Compilation unit object for C source file
190+
"""
191+
return self.c_application.translation_units.get(file_path)
192+
193+
def get_functions_in_file(self, file_name: str) -> List[CFunction]:
194+
"""Returns a dictionary of all methods of the given class.
195+
196+
Args:
197+
file_name (str): The name of the file.
198+
199+
Raises:
200+
NotImplementedError: Raised when current AnalysisEngine does not support this function.
201+
202+
Returns:
203+
Dict[str, JCallable]: A dictionary of all constructors of the given class.
204+
"""
205+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
206+
207+
def get_macros(self) -> List[CMacro]:
208+
"""Returns a list of all macros in the C code.
209+
210+
Raises:
211+
NotImplementedError: Raised when current AnalysisEngine does not support this function.
212+
213+
Returns:
214+
List[CMacro]: A list of all macros in the C code.
215+
"""
216+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
217+
218+
def get_macros_in_file(self, file_name: str) -> List[CMacro] | None:
219+
"""Returns a list of all macros in the given file.
220+
221+
Args:
222+
file_name (str): The name of the file.
223+
224+
Raises:
225+
NotImplementedError: Raised when current AnalysisEngine does not support this function.
226+
227+
Returns:
228+
List[CMacro]: A list of all macros in the given file. Returns None if no macros are found.
229+
"""
230+
raise NotImplementedError("Support for this functionality has not been implemented yet.")
231+
232+
233+
def get_includes(self) -> List[str]:
234+
"""Returns a list of all include statements across all files in the C code.
235+
236+
Returns:
237+
List[str]: A list of all include statements. Returns empty list if none found.
238+
"""
239+
all_includes = []
240+
for translation_unit in self.translation_units.values():
241+
all_includes.extend(translation_unit.includes)
242+
return all_includes
243+
244+
245+
def get_includes_in_file(self, file_name: str) -> List[str] | None:
246+
"""Returns a list of all include statements in the given file.
247+
248+
Args:
249+
file_name (str): The name of the file to search in.
250+
251+
Returns:
252+
List[str] | None: List of includes in the file, or None if file not found.
253+
"""
254+
if file_name in self.translation_units:
255+
return self.translation_units[file_name].includes
256+
return None
257+
258+
259+
def get_macros(self) -> List[CMacro]:
260+
"""Returns a list of all macro definitions across all files in the C code.
261+
262+
Returns:
263+
List[CMacro]: A list of all macro definitions. Returns empty list if none found.
264+
"""
265+
all_macros = []
266+
for translation_unit in self.translation_units.values():
267+
all_macros.extend(translation_unit.macros)
268+
return all_macros
269+
270+
271+
def get_macros_in_file(self, file_name: str) -> List[CMacro] | None:
272+
"""Returns a list of all macro definitions in the given file.
273+
274+
Args:
275+
file_name (str): The name of the file to search in.
276+
277+
Returns:
278+
List[CMacro] | None: List of macros in the file, or None if file not found.
279+
"""
280+
if file_name in self.translation_units:
281+
return self.translation_units[file_name].macros
282+
return None
283+
284+
285+
def get_typedefs(self) -> List[CTypedef]:
286+
"""Returns a list of all typedef declarations across all files in the C code.
287+
288+
Returns:
289+
List[CTypedef]: A list of all typedef declarations. Returns empty list if none found.
290+
"""
291+
all_typedefs = []
292+
for translation_unit in self.translation_units.values():
293+
all_typedefs.extend(translation_unit.typedefs)
294+
return all_typedefs
295+
296+
297+
def get_typedefs_in_file(self, file_name: str) -> List[CTypedef] | None:
298+
"""Returns a list of all typedef declarations in the given file.
299+
300+
Args:
301+
file_name (str): The name of the file to search in.
302+
303+
Returns:
304+
List[CTypedef] | None: List of typedefs in the file, or None if file not found.
305+
"""
306+
if file_name in self.translation_units:
307+
return self.translation_units[file_name].typedefs
308+
return None
309+
310+
311+
def get_structs(self) -> List[CStruct]:
312+
"""Returns a list of all struct/union declarations across all files in the C code.
313+
314+
Returns:
315+
List[CStruct]: A list of all struct/union declarations. Returns empty list if none found.
316+
"""
317+
all_structs = []
318+
for translation_unit in self.translation_units.values():
319+
all_structs.extend(translation_unit.structs)
320+
return all_structs
321+
322+
323+
def get_structs_in_file(self, file_name: str) -> List[CStruct] | None:
324+
"""Returns a list of all struct/union declarations in the given file.
325+
326+
Args:
327+
file_name (str): The name of the file to search in.
328+
329+
Returns:
330+
List[CStruct] | None: List of structs in the file, or None if file not found.
331+
"""
332+
if file_name in self.translation_units:
333+
return self.translation_units[file_name].structs
334+
return None
335+
336+
337+
def get_enums(self) -> List[CEnum]:
338+
"""Returns a list of all enum declarations across all files in the C code.
339+
340+
Returns:
341+
List[CEnum]: A list of all enum declarations. Returns empty list if none found.
342+
"""
343+
all_enums = []
344+
for translation_unit in self.translation_units.values():
345+
all_enums.extend(translation_unit.enums)
346+
return all_enums
347+
348+
349+
def get_enums_in_file(self, file_name: str) -> List[CEnum] | None:
350+
"""Returns a list of all enum declarations in the given file.
351+
352+
Args:
353+
file_name (str): The name of the file to search in.
354+
355+
Returns:
356+
List[CEnum] | None: List of enums in the file, or None if file not found.
357+
"""
358+
if file_name in self.translation_units:
359+
return self.translation_units[file_name].enums
360+
return None
361+
362+
363+
def get_globals(self, file_name: str) -> List[CVariable] | None:
364+
"""Returns a list of all global variable declarations in the given file.
365+
366+
Args:
367+
file_name (str): The name of the file to search in.
368+
369+
Returns:
370+
List[CVariable] | None: List of globals in the file, or None if file not found.
371+
"""
372+
if file_name in self.translation_units:
373+
return self.translation_units[file_name].globals
374+
return None

0 commit comments

Comments
 (0)