Coverage for src / rejuvenation / refactor_with_nested_compositions.py: 94%
50 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 the use of the syntax_tree library to parse and rewrite C code.
2# It specifically showcases nested replacements and multiple patterns.
3import textwrap
5from renaissance.integrations.clang import ClangASTNode, CPatternFactory
6from renaissance.integrations.types import Call
7from renaissance.syntax_tree import ASTFactory, ASTRewriter, ASTShower
8from renaissance.syntax_tree.ast_finder import find_ast_type
9from renaissance.syntax_tree.match_finder import find_all
11example_code = """
12void f1(int a, int b, int c);
13void f2(int a, int c);
14void f(){
15 const int a = 1;
16 const int b = 2;
17 int isAOne = a==1;
18 int c = 0, d=0;
19 if (a==1) {
20 d++;
21 if(a==1){
22 d++;
23 c=d;
24 f1(a,b,c);
25 }
26 }
27 if (a==2) {
28 c++;
29 f1(a,b,c);
30 }
31 f1(a,b,c);
32}
33""".strip()
35expected_result = """
36void f1(int a, int b, int c);
37void f2(int a, int c);
38void f(){
39 const int a = 1;
40 const int b = 2;
41 int isAOne = a==1;
42 int c = 0, d=0;
43 //changed if expr to const
44 if(isAOne){
45 d++;
46 //changed if expr to const
47 if(isAOne){
48 d++;
49 c=d;
50 //changed function f1 to f2
51 f2(a,c);
52 }
53 }
54 if (a==2) {
55 c++;
56 //changed function f1 to f2
57 f2(a,c);
58 }
59 //changed function f1 to f2
60 f2(a,c);
61}
62""".strip()
65def refactor_with_nested_compositions(args):
66 # the first argument is the code to be parsed
67 code = args[1] if len(args) > 1 else ""
69 # Create a factory args from the command line are passed to the factory for example -I/usr/include
70 factory = ASTFactory(ClangASTNode, args if not code else args[1:])
71 # Create a pattern factory (using the factory (hence also its args)
72 # create translation unit
73 atu = factory.create(code) if code else factory.create_from_text(example_code, "example.c")
74 # create a pattern factory atu is passed to the pattern factory for use of all # includes, #defines and declarations
75 pattern_factory = CPatternFactory(factory, atu)
76 # create a pattern that matches an if statement with a==1 as the condition and a block of statements as the body
77 # the type is important so it's declared as const int a
78 pattern1 = pattern_factory.create_statements("if(a==1){$$stmts;}", extra_declarations=["const int a;"])
79 # for pattern 2 we create a fully functional c snippet with a call to f1
80 # note that the f1 declaration is derived from the atu
81 pattern2 = pattern_factory.create("int $a,$b,$c; void fff() {f1($a,$b,$c);}")
82 ASTShower.show_node(pattern1[0], include_properties=True)
84 # we only want to search the call expression as a pattern so it's searched using the kind
85 pattern2 = find_ast_type(pattern2, Call)
87 # the replacement code strip indent is used to be agnostic to the indentation of the replacement
88 pattern1replacement = textwrap.dedent("""
89 //changed if expr to const
90 if(isAOne){
91 $$stmts;
92 }""")
94 pattern2replacement = "\n//changed function f1 to f2\nf2($a,$c);"
96 # show node and patterns enable include properties to show the properties of the nodes
97 include_properties = True
98 ASTShower.show_node(atu, include_properties)
99 ASTShower.show_node(pattern1[0], include_properties)
100 ASTShower.show_node(pattern2[0], include_properties)
102 result1 = None
103 while atu:
104 # create an ASTRewriter
105 rewriter = ASTRewriter(atu)
107 def raw(nodes):
108 res = ""
109 for node in nodes:
110 res += node.text
111 return res + "\n"
113 # create a refactoring that use different replacement code for different patterns
114 def refactor(match1):
115 print(f"peek: f{match1.signature}")
116 if match1.patterns == pattern1:
117 replacement_text = pattern1replacement
118 for repl_snippet in match1.expansions:
119 replacement_text = replacement_text.replace(repl_snippet, raw(match1.expansions[repl_snippet]))
120 else:
121 replacement_text = pattern2replacement
122 for repl_snippet in match1.expansions:
123 replacement_text = replacement_text.replace(repl_snippet, match1.expansions[repl_snippet][0].signature)
124 return rewriter.replace(replacement_text, match1.nodes)
126 # search matches for pattern1 and pattern2 and replace them using the refactor function
127 for match in find_all(atu.children, pattern1, pattern2):
128 refactor(match)
130 # print the rewritten code
131 result1 = rewriter.apply_to_string()
132 atu = factory.create_from_text(result1, "example.c") if rewriter.has_changed() else None
133 return result1
136if __name__ == "__main__":
137 import sys
139 result = refactor_with_nested_compositions(sys.argv)
140 print(result)