Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
ContenT
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ximper Linux
ContenT
Commits
857c6c2c
Commit
857c6c2c
authored
Feb 16, 2026
by
Roman Alifanov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add DCE for unused class methods
parent
cb16dd5f
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
103 additions
and
8 deletions
+103
-8
class_codegen.py
bootstrap/class_codegen.py
+15
-0
dce.py
bootstrap/dce.py
+83
-4
expr_codegen.py
bootstrap/expr_codegen.py
+5
-4
No files found.
bootstrap/class_codegen.py
View file @
857c6c2c
...
@@ -38,6 +38,14 @@ class ClassMixin:
...
@@ -38,6 +38,14 @@ class ClassMixin:
self
.
_generate_construct_method
(
cls
)
self
.
_generate_construct_method
(
cls
)
for
method
in
cls
.
methods
:
for
method
in
cls
.
methods
:
if
self
.
used_methods
is
not
None
:
method_used
=
(
cls
.
name
in
self
.
used_methods
and
method
.
name
in
self
.
used_methods
[
cls
.
name
]
)
if
not
method_used
:
continue
has_awk
=
any
(
dec
.
name
==
"awk"
for
dec
in
method
.
decorators
)
has_awk
=
any
(
dec
.
name
==
"awk"
for
dec
in
method
.
decorators
)
if
has_awk
:
if
has_awk
:
self
.
_generate_awk_method
(
cls
,
method
)
self
.
_generate_awk_method
(
cls
,
method
)
...
@@ -51,6 +59,13 @@ class ClassMixin:
...
@@ -51,6 +59,13 @@ class ClassMixin:
own_method_names
=
{
m
.
name
for
m
in
cls
.
methods
}
own_method_names
=
{
m
.
name
for
m
in
cls
.
methods
}
for
parent_method
in
parent_cls
.
methods
:
for
parent_method
in
parent_cls
.
methods
:
if
parent_method
.
name
not
in
own_method_names
:
if
parent_method
.
name
not
in
own_method_names
:
if
self
.
used_methods
is
not
None
:
method_used
=
(
cls
.
name
in
self
.
used_methods
and
parent_method
.
name
in
self
.
used_methods
[
cls
.
name
]
)
if
not
method_used
:
continue
self
.
_generate_inherited_method
(
cls
,
parent_cls
,
parent_method
)
self
.
_generate_inherited_method
(
cls
,
parent_cls
,
parent_method
)
self
.
current_class
=
None
self
.
current_class
=
None
...
...
bootstrap/dce.py
View file @
857c6c2c
...
@@ -19,6 +19,10 @@ class UsageAnalyzer:
...
@@ -19,6 +19,10 @@ class UsageAnalyzer:
self
.
used_classes
:
set
=
set
()
self
.
used_classes
:
set
=
set
()
self
.
used_methods
:
dict
=
{}
self
.
used_methods
:
dict
=
{}
self
.
class_fields
:
dict
=
{}
self
.
class_fields
:
dict
=
{}
self
.
variable_types
:
dict
=
{}
self
.
current_class_name
:
str
=
None
self
.
current_method_name
:
str
=
None
self
.
method_calls
:
dict
=
{}
def
analyze
(
self
,
programs
:
list
)
->
set
:
def
analyze
(
self
,
programs
:
list
)
->
set
:
self
.
used
=
{
'core'
}
self
.
used
=
{
'core'
}
...
@@ -34,6 +38,7 @@ class UsageAnalyzer:
...
@@ -34,6 +38,7 @@ class UsageAnalyzer:
self
.
_analyze_stmt
(
stmt
)
self
.
_analyze_stmt
(
stmt
)
self
.
_resolve_transitive_classes
()
self
.
_resolve_transitive_classes
()
self
.
_resolve_transitive_methods
()
if
self
.
has_classes
:
if
self
.
has_classes
:
self
.
used
.
add
(
'object'
)
self
.
used
.
add
(
'object'
)
...
@@ -59,6 +64,12 @@ class UsageAnalyzer:
...
@@ -59,6 +64,12 @@ class UsageAnalyzer:
while
changed
:
while
changed
:
changed
=
False
changed
=
False
for
cls_name
in
list
(
self
.
used_classes
):
for
cls_name
in
list
(
self
.
used_classes
):
if
cls_name
in
self
.
defined_classes
:
cls_decl
=
self
.
defined_classes
[
cls_name
]
if
cls_decl
.
parent
and
cls_decl
.
parent
not
in
self
.
used_classes
:
if
cls_decl
.
parent
in
self
.
defined_classes
:
self
.
used_classes
.
add
(
cls_decl
.
parent
)
changed
=
True
if
cls_name
in
self
.
class_fields
:
if
cls_name
in
self
.
class_fields
:
for
field_name
,
field_class
in
self
.
class_fields
[
cls_name
]
.
items
():
for
field_name
,
field_class
in
self
.
class_fields
[
cls_name
]
.
items
():
if
field_class
and
field_class
not
in
self
.
used_classes
:
if
field_class
and
field_class
not
in
self
.
used_classes
:
...
@@ -66,6 +77,36 @@ class UsageAnalyzer:
...
@@ -66,6 +77,36 @@ class UsageAnalyzer:
self
.
used_classes
.
add
(
field_class
)
self
.
used_classes
.
add
(
field_class
)
changed
=
True
changed
=
True
def
_resolve_transitive_methods
(
self
):
changed
=
True
while
changed
:
changed
=
False
for
cls_name
,
methods
in
list
(
self
.
used_methods
.
items
()):
for
method_name
in
list
(
methods
):
key
=
(
cls_name
,
method_name
)
if
key
in
self
.
method_calls
:
for
called_cls
,
called_method
in
self
.
method_calls
[
key
]:
if
called_cls
not
in
self
.
used_methods
:
self
.
used_methods
[
called_cls
]
=
set
()
if
called_method
not
in
self
.
used_methods
[
called_cls
]:
self
.
used_methods
[
called_cls
]
.
add
(
called_method
)
changed
=
True
for
cls_name
in
list
(
self
.
used_classes
):
if
cls_name
in
self
.
defined_classes
:
cls_decl
=
self
.
defined_classes
[
cls_name
]
if
cls_decl
.
parent
and
cls_decl
.
parent
in
self
.
defined_classes
:
parent_cls
=
self
.
defined_classes
[
cls_decl
.
parent
]
if
cls_name
in
self
.
used_methods
:
child_methods
=
{
m
.
name
for
m
in
cls_decl
.
methods
}
for
method
in
list
(
self
.
used_methods
[
cls_name
]):
if
method
not
in
child_methods
:
if
cls_decl
.
parent
not
in
self
.
used_methods
:
self
.
used_methods
[
cls_decl
.
parent
]
=
set
()
if
method
not
in
self
.
used_methods
[
cls_decl
.
parent
]:
self
.
used_methods
[
cls_decl
.
parent
]
.
add
(
method
)
changed
=
True
def
get_used_classes
(
self
)
->
set
:
def
get_used_classes
(
self
)
->
set
:
return
self
.
used_classes
return
self
.
used_classes
...
@@ -75,14 +116,18 @@ class UsageAnalyzer:
...
@@ -75,14 +116,18 @@ class UsageAnalyzer:
def
_analyze_stmt
(
self
,
stmt
):
def
_analyze_stmt
(
self
,
stmt
):
if
isinstance
(
stmt
,
ClassDecl
):
if
isinstance
(
stmt
,
ClassDecl
):
self
.
has_classes
=
True
self
.
has_classes
=
True
self
.
current_class_name
=
stmt
.
name
for
method
in
stmt
.
methods
:
for
method
in
stmt
.
methods
:
self
.
current_method_name
=
method
.
name
if
method
.
decorators
:
if
method
.
decorators
:
for
dec
in
method
.
decorators
:
for
dec
in
method
.
decorators
:
if
dec
.
name
==
'awk'
:
if
dec
.
name
==
'awk'
:
self
.
has_awk
=
True
self
.
has_awk
=
True
self
.
_analyze_body
(
method
.
body
)
self
.
_analyze_body
(
method
.
body
)
self
.
current_method_name
=
None
if
stmt
.
constructor
:
if
stmt
.
constructor
:
self
.
_analyze_body
(
stmt
.
constructor
.
body
)
self
.
_analyze_body
(
stmt
.
constructor
.
body
)
self
.
current_class_name
=
None
elif
isinstance
(
stmt
,
FunctionDecl
):
elif
isinstance
(
stmt
,
FunctionDecl
):
if
stmt
.
decorators
:
if
stmt
.
decorators
:
...
@@ -93,6 +138,14 @@ class UsageAnalyzer:
...
@@ -93,6 +138,14 @@ class UsageAnalyzer:
elif
isinstance
(
stmt
,
Assignment
):
elif
isinstance
(
stmt
,
Assignment
):
self
.
_analyze_expr
(
stmt
.
value
)
self
.
_analyze_expr
(
stmt
.
value
)
if
isinstance
(
stmt
.
target
,
Identifier
):
var_name
=
stmt
.
target
.
name
if
isinstance
(
stmt
.
value
,
NewExpr
):
self
.
variable_types
[
var_name
]
=
stmt
.
value
.
class_name
elif
isinstance
(
stmt
.
value
,
CallExpr
)
and
isinstance
(
stmt
.
value
.
callee
,
Identifier
):
callee_name
=
stmt
.
value
.
callee
.
name
if
callee_name
in
self
.
defined_classes
:
self
.
variable_types
[
var_name
]
=
callee_name
elif
isinstance
(
stmt
,
ExpressionStmt
):
elif
isinstance
(
stmt
,
ExpressionStmt
):
self
.
_analyze_expr
(
stmt
.
expression
)
self
.
_analyze_expr
(
stmt
.
expression
)
...
@@ -212,7 +265,17 @@ class UsageAnalyzer:
...
@@ -212,7 +265,17 @@ class UsageAnalyzer:
if
isinstance
(
callee
,
MemberAccess
):
if
isinstance
(
callee
,
MemberAccess
):
if
isinstance
(
callee
.
object
,
ThisExpr
):
if
isinstance
(
callee
.
object
,
ThisExpr
):
pass
method
=
callee
.
member
if
self
.
current_class_name
:
if
self
.
current_class_name
not
in
self
.
used_methods
:
self
.
used_methods
[
self
.
current_class_name
]
=
set
()
self
.
used_methods
[
self
.
current_class_name
]
.
add
(
method
)
if
self
.
current_method_name
:
caller
=
(
self
.
current_class_name
,
self
.
current_method_name
)
callee_key
=
(
self
.
current_class_name
,
method
)
if
caller
not
in
self
.
method_calls
:
self
.
method_calls
[
caller
]
=
set
()
self
.
method_calls
[
caller
]
.
add
(
callee_key
)
elif
isinstance
(
callee
.
object
,
MemberAccess
)
and
isinstance
(
callee
.
object
.
object
,
ThisExpr
):
elif
isinstance
(
callee
.
object
,
MemberAccess
)
and
isinstance
(
callee
.
object
.
object
,
ThisExpr
):
field_name
=
callee
.
object
.
member
field_name
=
callee
.
object
.
member
...
@@ -226,7 +289,13 @@ class UsageAnalyzer:
...
@@ -226,7 +289,13 @@ class UsageAnalyzer:
elif
isinstance
(
callee
.
object
,
Identifier
):
elif
isinstance
(
callee
.
object
,
Identifier
):
ns
=
callee
.
object
.
name
ns
=
callee
.
object
.
name
if
ns
==
'http'
:
method
=
callee
.
member
if
ns
in
self
.
variable_types
:
obj_class
=
self
.
variable_types
[
ns
]
if
obj_class
not
in
self
.
used_methods
:
self
.
used_methods
[
obj_class
]
=
set
()
self
.
used_methods
[
obj_class
]
.
add
(
method
)
elif
ns
==
'http'
:
self
.
used
.
add
(
'http'
)
self
.
used
.
add
(
'http'
)
elif
ns
==
'fs'
:
elif
ns
==
'fs'
:
self
.
used
.
add
(
'fs'
)
self
.
used
.
add
(
'fs'
)
...
@@ -245,8 +314,18 @@ class UsageAnalyzer:
...
@@ -245,8 +314,18 @@ class UsageAnalyzer:
elif
ns
==
'shell'
:
elif
ns
==
'shell'
:
pass
pass
else
:
else
:
method
=
callee
.
member
# Check if this could be a class method (conservative approach)
self
.
_check_method
(
method
)
# Include method in all classes that define it
found_in_class
=
False
for
cls_name
,
cls_decl
in
self
.
defined_classes
.
items
():
for
m
in
cls_decl
.
methods
:
if
m
.
name
==
method
:
if
cls_name
not
in
self
.
used_methods
:
self
.
used_methods
[
cls_name
]
=
set
()
self
.
used_methods
[
cls_name
]
.
add
(
method
)
found_in_class
=
True
if
not
found_in_class
:
self
.
_check_method
(
method
)
def
_analyze_member_access
(
self
,
expr
:
MemberAccess
):
def
_analyze_member_access
(
self
,
expr
:
MemberAccess
):
if
isinstance
(
expr
.
object
,
Identifier
):
if
isinstance
(
expr
.
object
,
Identifier
):
...
...
bootstrap/expr_codegen.py
View file @
857c6c2c
...
@@ -101,7 +101,7 @@ class ExprMixin:
...
@@ -101,7 +101,7 @@ class ExprMixin:
if
parts
[
0
]
==
'this'
:
if
parts
[
0
]
==
'this'
:
return
f
'
\\
$${{__CT_OBJ["$this.{parts[1]}"]}}'
return
f
'
\\
$${{__CT_OBJ["$this.{parts[1]}"]}}'
else
:
else
:
return
f
'
\\
$${{__CT_OBJ["${
parts[0]}.{parts[1]}"]
}}'
return
f
'
\\
$${{__CT_OBJ["${
{{parts[0]}}}.{parts[1]}"]:-
}}'
return
f
'
\\
$${{{content}}}'
return
f
'
\\
$${{{content}}}'
def
replace_interpolation
(
match
):
def
replace_interpolation
(
match
):
...
@@ -115,7 +115,7 @@ class ExprMixin:
...
@@ -115,7 +115,7 @@ class ExprMixin:
if
parts
[
0
]
==
'this'
:
if
parts
[
0
]
==
'this'
:
return
f
'${{__CT_OBJ["$this.{parts[1]}"]}}'
return
f
'${{__CT_OBJ["$this.{parts[1]}"]}}'
else
:
else
:
return
f
'${{__CT_OBJ["${
parts[0]}.{parts[1]}"]
}}'
return
f
'${{__CT_OBJ["${
{{parts[0]}}}.{parts[1]}"]:-
}}'
return
f
'${{{content}}}'
return
f
'${{{content}}}'
value
=
value
.
replace
(
'
\x00
DOLLAR
\x00
{'
,
'
\x01
ESCAPED_DOLLAR_BRACE
\x01
'
)
value
=
value
.
replace
(
'
\x00
DOLLAR
\x00
{'
,
'
\x01
ESCAPED_DOLLAR_BRACE
\x01
'
)
...
@@ -336,8 +336,9 @@ class ExprMixin:
...
@@ -336,8 +336,9 @@ class ExprMixin:
return
f
'${{__CT_OBJ["$this.{expr.member}"]}}'
return
f
'${{__CT_OBJ["$this.{expr.member}"]}}'
obj
=
self
.
generate_expr
(
expr
.
object
)
obj
=
self
.
generate_expr
(
expr
.
object
)
if
obj
.
startswith
(
'${'
)
and
obj
.
endswith
(
'}'
):
if
obj
.
startswith
(
'${'
)
and
obj
.
endswith
(
'}'
):
obj
=
'$'
+
obj
[
2
:
-
1
]
var_name
=
obj
[
2
:
-
1
]
return
f
'${{__CT_OBJ["{obj}.{expr.member}"]}}'
return
f
'${{__CT_OBJ["${{{var_name}}}.{expr.member}"]:-}}'
return
f
'${{__CT_OBJ["{obj}.{expr.member}"]:-}}'
def
_generate_index_access
(
self
,
expr
:
IndexAccess
)
->
str
:
def
_generate_index_access
(
self
,
expr
:
IndexAccess
)
->
str
:
obj
=
self
.
generate_expr
(
expr
.
object
)
obj
=
self
.
generate_expr
(
expr
.
object
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment