Skip to content

Commit 7975c59

Browse files
committed
FDECLS: move global defs and decls to CFileGlobals
1 parent 9ba1590 commit 7975c59

File tree

7 files changed

+399
-321
lines changed

7 files changed

+399
-321
lines changed

chc/app/CFileGlobals.py

Lines changed: 399 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,399 @@
1+
# ------------------------------------------------------------------------------
2+
# CodeHawk C Analyzer
3+
# Author: Henny Sipma
4+
# ------------------------------------------------------------------------------
5+
# The MIT License (MIT)
6+
#
7+
# Copyright (c) 2017-2020 Kestrel Technology LLC
8+
# Copyright (c) 2020-2023 Henny B. Sipma
9+
# Copyright (c) 2024 Aarno Labs LLC
10+
#
11+
# Permission is hereby granted, free of charge, to any person obtaining a copy
12+
# of this software and associated documentation files (the "Software"), to deal
13+
# in the Software without restriction, including without limitation the rights
14+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15+
# copies of the Software, and to permit persons to whom the Software is
16+
# furnished to do so, subject to the following conditions:
17+
#
18+
# The above copyright notice and this permission notice shall be included in all
19+
# copies or substantial portions of the Software.
20+
#
21+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27+
# SOFTWARE.
28+
# ------------------------------------------------------------------------------
29+
"""Global definitions in a c-file.
30+
31+
These definitions are obtained from the file <filename>_cfile.xml.
32+
"""
33+
34+
from dataclasses import dataclass
35+
36+
import xml.etree.ElementTree as ET
37+
38+
from typing import Dict, List, Optional, TYPE_CHECKING
39+
40+
import chc.util.fileutil as UF
41+
from chc.util.loggingutil import chklogger
42+
43+
if TYPE_CHECKING:
44+
from chc.app.CCompInfo import CCompInfo
45+
from chc.app.CEnumInfo import CEnumInfo
46+
from chc.app.CFile import CFile
47+
from chc.app.CFileDeclarations import CFileDeclarations
48+
from chc.app.CInitInfo import CInitInfo
49+
from chc.app.CLocation import CLocation
50+
from chc.app.CTyp import CTyp
51+
from chc.app.CTypeInfo import CTypeInfo
52+
from chc.app.CVarInfo import CVarInfo
53+
54+
55+
@dataclass
56+
57+
class CGCompTag:
58+
"""Definition of a struct."""
59+
60+
location: "CLocation"
61+
compinfo: "CCompInfo"
62+
63+
@property
64+
def name(self) -> str:
65+
return self.compinfo.name
66+
67+
@property
68+
def ckey(self) -> int:
69+
return self.compinfo.ckey
70+
71+
@property
72+
def is_struct(self) -> bool:
73+
return self.compinfo.is_struct
74+
75+
76+
@dataclass
77+
class CGEnumTag:
78+
"""Definition of an enum."""
79+
80+
location: "CLocation"
81+
enuminfo: "CEnumInfo"
82+
83+
84+
@dataclass
85+
class CGFunction:
86+
"""Function declaration."""
87+
88+
location: "CLocation"
89+
varinfo: "CVarInfo"
90+
91+
@property
92+
def vname(self) -> str:
93+
return self.varinfo.vname
94+
95+
@property
96+
def vtype(self) -> "CTyp":
97+
return self.varinfo.vtype
98+
99+
@property
100+
def line(self) -> int:
101+
return self.varinfo.line
102+
103+
def __str__(self) -> str:
104+
return f"{self.vname}: {self.vtype}"
105+
106+
107+
@dataclass
108+
class CGType:
109+
"""Type definition that associates a name with a type."""
110+
111+
location: "CLocation"
112+
typeinfo: "CTypeInfo"
113+
114+
115+
@dataclass
116+
class CGVarDecl:
117+
"""Global variable declaration."""
118+
119+
location: "CLocation"
120+
varinfo: "CVarInfo"
121+
122+
@property
123+
def vname(self) -> str:
124+
return self.varinfo.vname
125+
126+
127+
@dataclass
128+
class CGVarDef:
129+
"""Global variable definition (in this file)."""
130+
131+
location: "CLocation"
132+
varinfo: "CVarInfo"
133+
initializer: Optional["CInitInfo"]
134+
135+
@property
136+
def vname(self) -> str:
137+
return self.varinfo.vname
138+
139+
def has_initializer(self) -> bool:
140+
return self.initializer is not None
141+
142+
def __str__(self) -> str:
143+
if self.initializer is not None:
144+
return f"{self.varinfo} = {self.initializer}"
145+
else:
146+
return f"{self.varinfo}"
147+
148+
149+
class CFileGlobals:
150+
151+
def __init__(self, cfile: "CFile", xnode: ET.Element) -> None:
152+
self._cfile = cfile
153+
self._xnode = xnode
154+
155+
self._gcomptagdefs: Optional[Dict[int, CGCompTag]] = None
156+
self._gcomptagdecls: Optional[Dict[int, CGCompTag]] = None
157+
self._genumtagdecls: Optional[Dict[str, CGEnumTag]] = None
158+
self._genumtagdefs: Optional[Dict[str, CGEnumTag]] = None
159+
self._gfunctions: Optional[Dict[int, CGFunction]] = None
160+
self._gtypes: Optional[Dict[str, CGType]] = None
161+
self._gvardecls: Optional[Dict[int, CGVarDecl]] = None
162+
self._gvardefs: Optional[Dict[int, CGVarDef]] = None
163+
164+
self._globalcompinfockeys: Optional[Dict[int, "CCompInfo"]] = None
165+
self._globalvarinfonames: Optional[Dict[str, "CVarInfo"]] = None
166+
self._globalvarinfovids: Optional[Dict[int, "CVarInfo"]] = None
167+
168+
@property
169+
def cfile(self) -> "CFile":
170+
return self._cfile
171+
172+
@property
173+
def declarations(self) -> "CFileDeclarations":
174+
return self.cfile.declarations
175+
176+
def expand(self, name: str) -> "CTyp":
177+
if name in self.gtypes:
178+
return self.gtypes[name].typeinfo.type.expand()
179+
else:
180+
raise UF.CHCError(f"No type definition found for {name}")
181+
182+
@property
183+
def functioncount(self) -> int:
184+
return len(self.gfunctions)
185+
186+
@property
187+
def gcomptagdecls(self) -> Dict[int, CGCompTag]:
188+
if self._gcomptagdecls is None:
189+
self._gcomptagdecls = {}
190+
xgc = self._xnode.find("global-comptag-declarations")
191+
if xgc is not None:
192+
for xc in xgc.findall("gcomptagdecl"):
193+
xicinfo = xc.get("icinfo")
194+
xiloc = xc.get("iloc")
195+
if xicinfo is not None and xiloc is not None:
196+
cinfo = self.declarations.get_compinfo(int(xicinfo))
197+
loc = self.declarations.get_location(int(xiloc))
198+
gcomp = CGCompTag(loc, cinfo)
199+
self._gcomptagdecls[cinfo.ckey] = gcomp
200+
else:
201+
chklogger.logger.error(
202+
"Invalid comptag definition record in %s",
203+
self.cfile.name)
204+
return self._gcomptagdecls
205+
206+
@property
207+
def gcomptagdefs(self) -> Dict[int, CGCompTag]:
208+
if self._gcomptagdefs is None:
209+
self._gcomptagdefs = {}
210+
xgc = self._xnode.find("global-comptag-definitions")
211+
if xgc is not None:
212+
for xc in xgc.findall("gcomptag"):
213+
xicinfo = xc.get("icinfo")
214+
xiloc = xc.get("iloc")
215+
if xicinfo is not None and xiloc is not None:
216+
cinfo = self.declarations.get_compinfo(int(xicinfo))
217+
loc = self.declarations.get_location(int(xiloc))
218+
gcomp = CGCompTag(loc, cinfo)
219+
self._gcomptagdefs[cinfo.ckey] = gcomp
220+
else:
221+
chklogger.logger.error(
222+
"Invalid comptag definition record in %s",
223+
self.cfile.name)
224+
return self._gcomptagdefs
225+
226+
@property
227+
def genumtagdecls(self) -> Dict[str, CGEnumTag]:
228+
if self._genumtagdecls is None:
229+
self._genumtagdecls = {}
230+
xge = self._xnode.find("global-enumtag-declarations")
231+
if xge is not None:
232+
for xe in xge.findall("genumtagdecl"):
233+
xieinfo = xe.get("ieinfo")
234+
xiloc = xe.get("iloc")
235+
if xieinfo is not None and xiloc is not None:
236+
einfo = self.declarations.get_enuminfo(int(xieinfo))
237+
loc = self.declarations.get_location(int(xiloc))
238+
genum = CGEnumTag(loc, einfo)
239+
self._genumtagdecls[einfo.ename] = genum
240+
else:
241+
chklogger.logger.error(
242+
"Invalid enum declaration record in %s",
243+
self.cfile.name)
244+
return self._genumtagdecls
245+
246+
@property
247+
def genumtagdefs(self) -> Dict[str, CGEnumTag]:
248+
if self._genumtagdefs is None:
249+
self._genumtagdefs = {}
250+
xge = self._xnode.find("global-enumtag-definitions")
251+
if xge is not None:
252+
for xe in xge.findall("genumtag"):
253+
xieinfo = xe.get("ieinfo")
254+
xiloc = xe.get("iloc")
255+
if xieinfo is not None and xiloc is not None:
256+
einfo = self.declarations.get_enuminfo(int(xieinfo))
257+
loc = self.declarations.get_location(int(xiloc))
258+
genum = CGEnumTag(loc, einfo)
259+
self._genumtagdefs[einfo.ename] = genum
260+
else:
261+
chklogger.logger.error(
262+
"Invalid enum declaration record in %s",
263+
self.cfile.name)
264+
return self._genumtagdefs
265+
266+
@property
267+
def gfunctions(self) -> Dict[int, CGFunction]:
268+
if self._gfunctions is None:
269+
self._gfunctions = {}
270+
xgf = self._xnode.find("functions")
271+
if xgf is not None:
272+
for xf in xgf.findall("gfun"):
273+
xivinfo = xf.get("ivinfo")
274+
xiloc = xf.get("iloc")
275+
if xivinfo is not None and xiloc is not None:
276+
vinfo = self.declarations.get_varinfo(int(xivinfo))
277+
loc = self.declarations.get_location(int(xiloc))
278+
gfun = CGFunction(loc, vinfo)
279+
self._gfunctions[vinfo.vid] = gfun
280+
else:
281+
chklogger.logger.error(
282+
"Invalid function declaration record in %s",
283+
self.cfile.name)
284+
return self._gfunctions
285+
286+
@property
287+
def gtypes(self) -> Dict[str, CGType]:
288+
if self._gtypes is None:
289+
self._gtypes = {}
290+
xgt = self._xnode.find("global-type-definitions")
291+
if xgt is not None:
292+
for xt in xgt.findall("gtype"):
293+
xitinfo = xt.get("itinfo")
294+
xiloc = xt.get("iloc")
295+
if xitinfo is not None and xiloc is not None:
296+
tinfo = self.declarations.get_typeinfo(int(xitinfo))
297+
loc = self.declarations.get_location(int(xiloc))
298+
gtype = CGType(loc, tinfo)
299+
self._gtypes[tinfo.name] = gtype
300+
else:
301+
chklogger.logger.error(
302+
"Invalid type definition record in %s",
303+
self.cfile.name)
304+
return self._gtypes
305+
306+
@property
307+
def gvardecls(self) -> Dict[int, CGVarDecl]:
308+
if self._gvardecls is None:
309+
self._gvardecls = {}
310+
xgv = self._xnode.find("global-var-declarations")
311+
if xgv is not None:
312+
for xv in xgv.findall("gvardecl"):
313+
xivinfo = xv.get("ivinfo")
314+
xiloc = xv.get("iloc")
315+
if xivinfo is not None and xiloc is not None:
316+
vinfo = self.declarations.get_varinfo(int(xivinfo))
317+
loc = self.declarations.get_location(int(xiloc))
318+
gvardecl = CGVarDecl(loc, vinfo)
319+
self._gvardecls[vinfo.vid] = gvardecl
320+
else:
321+
chklogger.logger.error(
322+
"Invalid variable declaration record in %s",
323+
self.cfile.name)
324+
return self._gvardecls
325+
326+
@property
327+
def gvardefs(self) -> Dict[int, CGVarDef]:
328+
if self._gvardefs is None:
329+
self._gvardefs = {}
330+
xgv = self._xnode.find("global-var-definitions")
331+
if xgv is not None:
332+
for xv in xgv.findall("gvar"):
333+
xivinfo = xv.get("ivinfo")
334+
xiloc = xv.get("iloc")
335+
xiinit = xv.get("iinit")
336+
if (
337+
xivinfo is not None
338+
and xiloc is not None):
339+
vinfo = self.declarations.get_varinfo(int(xivinfo))
340+
loc = self.declarations.get_location(int(xiloc))
341+
vinit: Optional["CInitInfo"] = None
342+
if xiinit is not None:
343+
vinit = self.declarations.get_initinfo(int(xiinit))
344+
gvar = CGVarDef(loc, vinfo, vinit)
345+
self._gvardefs[vinfo.vid] = gvar
346+
else:
347+
chklogger.logger.error(
348+
"Invalid variable definition record in %s",
349+
self.cfile.name)
350+
return self._gvardefs
351+
352+
@property
353+
def global_varinfo_names(self) -> Dict[str, "CVarInfo"]:
354+
if self._globalvarinfonames is None:
355+
self._globalvarinfonames = {}
356+
for vardef in self.gvardefs.values():
357+
self._globalvarinfonames[vardef.vname] = vardef.varinfo
358+
for vardecl in self.gvardecls.values():
359+
self._globalvarinfonames[vardecl.vname] = vardecl.varinfo
360+
for gfun in self.gfunctions.values():
361+
self._globalvarinfonames[gfun.vname] = gfun.varinfo
362+
return self._globalvarinfonames
363+
364+
@property
365+
def global_varinfo_vids(self) -> Dict[int, "CVarInfo"]:
366+
if self._globalvarinfovids is None:
367+
self._globalvarinfovids = {}
368+
for (vid, vardef) in self.gvardefs.items():
369+
self._globalvarinfovids[vid] = vardef.varinfo
370+
for (vid, vardecl) in self.gvardecls.items():
371+
self._globalvarinfovids[vid] = vardecl.varinfo
372+
for (vid, gfun) in self.gfunctions.items():
373+
self._globalvarinfovids[vid] = gfun.varinfo
374+
return self._globalvarinfovids
375+
376+
def get_global_varinfos(self) -> List["CVarInfo"]:
377+
return list(self.global_varinfo_vids.values())
378+
379+
@property
380+
def global_compinfo_ckeys(self) -> Dict[int, "CCompInfo"]:
381+
if self._globalcompinfockeys is None:
382+
self._globalcompinfockeys = {}
383+
for (ckey, comptag) in self.gcomptagdefs.items():
384+
self._globalcompinfockeys[ckey] = comptag.compinfo
385+
for (ckey, comptag) in self.gcomptagdecls.items():
386+
self._globalcompinfockeys[ckey] = comptag.compinfo
387+
return self._globalcompinfockeys
388+
389+
def get_compinfos(self) -> List["CCompInfo"]:
390+
result: List["CCompInfo"] = []
391+
for gcdef in self.gcomptagdefs.values():
392+
result.append(gcdef.compinfo)
393+
for gcdecl in self.gcomptagdecls.values():
394+
result.append(gcdecl.compinfo)
395+
return result
396+
397+
398+
399+

0 commit comments

Comments
 (0)