Coverage for src / rejuvenation / refactor_examples_different_styles.py: 97%
71 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-09-09 14:04 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-09-09 14:04 +0000
1# This script demonstrates various techniques for refactoring C code using an abstract syntax tree (AST) approach.
2# It showcases how to add comments, replace types, and find specific nodes in the AST using different methods.
3from renaissance.integrations.clang import ClangASTNode, CPatternFactory
4from renaissance.integrations.types import TypeReference
5from renaissance.syntax_tree import (
6 ASTFactory,
7 ASTFinder,
8 ASTRewriter,
9 ASTShower,
10)
11from renaissance.syntax_tree.ast_finder import find_ast_type, matches_kind
12from renaissance.syntax_tree.match_finder import find_all, match_pattern
14example_code = """
15 typedef int fancy_new;
16 typedef int old;
17 void f(){
18 int a = 1;
19 old b = 2;
20 int c = 3;
21 old d = 4;
22 old e;
23 }
24 """
25expected_result_old_fancy_new = """
26 typedef int fancy_new;
27 typedef int old;
28 void f(){
29 int a = 1;
30 fancy_new b = 2;
31 int c = 3;
32 fancy_new d = 4;
33 fancy_new e;
34 }
35 """.strip()
37expected_result_old_with_comment = """
38 typedef int fancy_new;
39 typedef int old;
40 void f(){
41 int a = 1;
42 // old has become obsolete
43 old b = 2;
44 int c = 3;
45 // old has become obsolete
46 old d = 4;
47 // old has become obsolete
48 old e;
49 }
50 """.strip()
53def example_add_comment_and_commit(factory, pattern_factory):
54 # create a pattern that matches the declaration of old
55 # please note that we need to help by telling the old is a type and $value is a variable
56 pattern1 = pattern_factory.create_declarations(
57 "old $name = $value;",
58 extra_declarations=["typedef int old;"],
59 parameters=["$value"],
60 )
61 pattern2 = pattern_factory.create_declarations("old $name;", extra_declarations=["typedef int old;"], parameters=["$value"])
62 # put the patterns in a matrix because we want to find both statements in one go and not a sequence
63 patterns_list = [pattern1, pattern2]
65 ASTShower.show_node(pattern1[0])
66 # if you want to find both statements in one go, you should pass a list of patterns
67 # if you don't do that a sequence of the patterns is searched for
69 # create translation unit
70 atu = factory.create_from_text(example_code, "test.c")
72 ASTShower.show_node(atu)
74 # create an ASTRewriter
75 rewriter = ASTRewriter(atu)
77 # search matches and replace them
78 for match in find_all(atu.children, *patterns_list):
79 rewriter.insert_before("// old has become obsolete", match)
81 def commit():
82 rewriter.apply_to_string()
83 atu = factory.create_from_text(rewriter.apply_to_string(), rewriter.get_filename())
84 return atu, ASTRewriter(atu)
86 # commit
87 atu, rewriter = commit()
89 # look at the print that marks all old declarations with the provided comment
90 print("results after adding comments to the obsolete types:")
91 result = rewriter.apply_to_string().strip()
92 print(result)
93 return result, expected_result_old_with_comment
96def example_replace_old_by_fancy_new(factory, pattern_factory):
97 # using some different techniques to show the possibilities of map and filter
98 pattern1 = pattern_factory.create_declarations("$old $name = $value;", types=["$old"], parameters=["$value"])
99 pattern2 = pattern_factory.create_declarations("$old $name;", types=["$old"], parameters=["$value"])
100 # put the patterns in a matrix because we want to find both statements in one go and not a sequence
101 patterns_list = [pattern1, pattern2]
103 # an example of how to use a function iso of lambda to filter the nodes
104 def matches_old(node):
105 return bool("$old" in node and node["$old"][0].name == "old")
107 atu = factory.create_from_text(example_code, "test.c")
108 rewriter = ASTRewriter(atu)
110 [rewriter.replace("fancy_new", match.nodes) for match in match_pattern(atu.children, *patterns_list) if matches_old(match.expansions)]
112 print("results after replacing the old type by fancy_new using MatchFinder:")
113 result = rewriter.apply_to_string().strip()
114 print(result)
115 return result, expected_result_old_fancy_new
118def example_use_ast_kind_finder(factory, _):
119 # Create the translation unit from the provided code or example code
120 atu = factory.create_from_text(example_code, "test.c")
121 # Create an ASTRewriter for the translation unit
122 rewriter = ASTRewriter(atu)
124 # Find all nodes of kind TYPE_REF (case-insensitive) and filter those with name 'old'
125 [rewriter.replace("fancy_new", node) for node in find_ast_type(atu, TypeReference) if node.name == "old"]
127 # Print the results after replacing the old type by fancy_new
128 print("results after replacing the old type by fancy_new using find_ast_type")
129 result = rewriter.apply_to_string().strip()
130 print(result)
131 return result, expected_result_old_fancy_new
134def example_use_ast_function_finder(factory, _):
135 # Create the translation unit from the provided code or example code
136 atu = factory.create_from_text(example_code, "test.c")
137 # Create an ASTRewriter for the translation unit
138 rewriter = ASTRewriter(atu)
140 ASTShower.show_node(atu)
142 # Define a match function to find nodes of kind TYPE_REF with name 'old'
143 def match(node):
144 res = matches_kind(node, TypeReference) and node.name == "old"
145 return res
147 # Use ASTFinder to find all matching nodes and replace 'old' with 'fancy_new'
148 [rewriter.replace("fancy_new", node) for node in ASTFinder.find_all(atu, match)]
150 # Print the results after replacing the old type by fancy_new
151 print("results after replacing the old type by fancy_new using ASTFinder.find_all")
152 result = rewriter.apply_to_string().strip()
153 print(result)
154 return result, expected_result_old_fancy_new
157def main(args):
158 # the first argument is the code to be parsed
159 code = args[1] if len(args) > 1 else ""
161 # Create a factory args from the command line are passed to the factory for example -I/usr/include
162 factory = ASTFactory(ClangASTNode, args if not code else args[1:])
163 # Create a pattern factory (using the factory (hence also its args)
164 pattern_factory = CPatternFactory(factory)
166 example_add_comment_and_commit(factory, pattern_factory)
167 example_replace_old_by_fancy_new(factory, pattern_factory)
168 example_use_ast_kind_finder(factory, pattern_factory)
169 example_use_ast_function_finder(factory, pattern_factory)
172if __name__ == "__main__":
173 import sys
175 main(sys.argv)