Coverage for src/rejuvenation/refactor_examples_different_styles.py: 97%
71 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-02 13:12 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-10-02 13:12 +0000
1"""AI: Example script demonstrating multiple C AST refactoring styles: adding comments, replacing types, and finding nodes."""
3# This script demonstrates various techniques for refactoring C code using an abstract syntax tree (AST) approach.
4# It showcases how to add comments, replace types, and find specific nodes in the AST using different methods.
5from renaissance.integrations.clang import ClangASTNode, CPatternFactory
6from renaissance.integrations.clang.predicates import is_clang_type_reference
7from renaissance.syntax_tree import (
8 ASTFactory,
9 ASTFinder,
10 ASTRewriter,
11 ASTShower,
12)
13from renaissance.syntax_tree.ast_finder import find_nodes
14from renaissance.syntax_tree.match_finder import find_all, match_pattern
16example_code = """
17 typedef int fancy_new;
18 typedef int old;
19 void f(){
20 int a = 1;
21 old b = 2;
22 int c = 3;
23 old d = 4;
24 old e;
25 }
26 """
27expected_result_old_fancy_new = """
28 typedef int fancy_new;
29 typedef int old;
30 void f(){
31 int a = 1;
32 fancy_new b = 2;
33 int c = 3;
34 fancy_new d = 4;
35 fancy_new e;
36 }
37 """.strip()
39expected_result_old_with_comment = """
40 typedef int fancy_new;
41 typedef int old;
42 void f(){
43 int a = 1;
44 // old has become obsolete
45 old b = 2;
46 int c = 3;
47 // old has become obsolete
48 old d = 4;
49 // old has become obsolete
50 old e;
51 }
52 """.strip()
55def example_add_comment_and_commit(factory, pattern_factory):
56 """AI: Insert a comment before each obsolete 'old' declaration, commit, and return the rewritten source."""
57 # create a pattern that matches the declaration of old
58 # please note that we need to help by telling the old is a type and $value is a variable
59 pattern1 = pattern_factory.create_declarations(
60 "old $name = $value;",
61 extra_declarations=["typedef int old;"],
62 parameters=["$value"],
63 )
64 pattern2 = pattern_factory.create_declarations("old $name;", extra_declarations=["typedef int old;"], parameters=["$value"])
65 # put the patterns in a matrix because we want to find both statements in one go and not a sequence
66 patterns_list = [pattern1, pattern2]
68 ASTShower.show_node(pattern1[0])
69 # if you want to find both statements in one go, you should pass a list of patterns
70 # if you don't do that a sequence of the patterns is searched for
72 # create translation unit
73 atu = factory.create_from_text(example_code, "test.c")
75 ASTShower.show_node(atu)
77 # create an ASTRewriter
78 rewriter = ASTRewriter(atu)
80 # search matches and replace them
81 for match in find_all(atu.children, *patterns_list):
82 rewriter.insert_before("// old has become obsolete", match)
84 def commit():
85 rewriter.apply_to_string()
86 atu = factory.create_from_text(rewriter.apply_to_string(), rewriter.get_filename())
87 return atu, ASTRewriter(atu)
89 # commit
90 atu, rewriter = commit()
92 # look at the print that marks all old declarations with the provided comment
93 print("results after adding comments to the obsolete types:")
94 result = rewriter.apply_to_string().strip()
95 print(result)
96 return result, expected_result_old_with_comment
99def example_replace_old_by_fancy_new(factory, pattern_factory):
100 """AI: Replace 'old' declarations with 'fancy_new' using pattern matching and filtering."""
101 # using some different techniques to show the possibilities of map and filter
102 pattern1 = pattern_factory.create_declarations("$old $name = $value;", types=["$old"], parameters=["$value"])
103 pattern2 = pattern_factory.create_declarations("$old $name;", types=["$old"], parameters=["$value"])
104 # put the patterns in a matrix because we want to find both statements in one go and not a sequence
105 patterns_list = [pattern1, pattern2]
107 # an example of how to use a function iso of lambda to filter the nodes
108 def matches_old(node):
109 return bool("$old" in node and node["$old"][0].name == "old")
111 atu = factory.create_from_text(example_code, "test.c")
112 rewriter = ASTRewriter(atu)
114 [rewriter.replace("fancy_new", match.nodes) for match in match_pattern(atu.children, *patterns_list) if matches_old(match.expansions)]
116 print("results after replacing the old type by fancy_new using MatchFinder:")
117 result = rewriter.apply_to_string().strip()
118 print(result)
119 return result, expected_result_old_fancy_new
122def example_use_ast_kind_finder(factory, _):
123 """AI: Replace 'old' type references with 'fancy_new' using a Clang node-kind predicate."""
124 # Create the translation unit from the provided code or example code
125 atu = factory.create_from_text(example_code, "test.c")
126 # Create an ASTRewriter for the translation unit
127 rewriter = ASTRewriter(atu)
129 # Find all nodes of kind TYPE_REF (case-insensitive) and filter those with name 'old'
130 [rewriter.replace("fancy_new", node) for node in find_nodes(atu, is_clang_type_reference) if node.name == "old"]
132 # Print the results after replacing the old type by fancy_new
133 print("results after replacing the old type by fancy_new using a Clang predicate")
134 result = rewriter.apply_to_string().strip()
135 print(result)
136 return result, expected_result_old_fancy_new
139def example_use_ast_function_finder(factory, _):
140 """AI: Replace 'old' type references with 'fancy_new' using `ASTFinder.find_all`."""
141 # Create the translation unit from the provided code or example code
142 atu = factory.create_from_text(example_code, "test.c")
143 # Create an ASTRewriter for the translation unit
144 rewriter = ASTRewriter(atu)
146 ASTShower.show_node(atu)
148 # Define a match function to find nodes of kind TYPE_REF with name 'old'
149 def match(node):
150 res = is_clang_type_reference(node) and node.name == "old"
151 return res
153 # Use ASTFinder to find all matching nodes and replace 'old' with 'fancy_new'
154 [rewriter.replace("fancy_new", node) for node in ASTFinder.find_all(atu, match)]
156 # Print the results after replacing the old type by fancy_new
157 print("results after replacing the old type by fancy_new using ASTFinder.find_all")
158 result = rewriter.apply_to_string().strip()
159 print(result)
160 return result, expected_result_old_fancy_new
163def main(args):
164 """AI: Run all four 'old'-to-'fancy_new' refactoring style examples against the parsed args."""
165 # the first argument is the code to be parsed
166 code = args[1] if len(args) > 1 else ""
168 # Create a factory args from the command line are passed to the factory for example -I/usr/include
169 factory = ASTFactory(ClangASTNode, args if not code else args[1:])
170 # Create a pattern factory (using the factory (hence also its args)
171 pattern_factory = CPatternFactory(factory)
173 example_add_comment_and_commit(factory, pattern_factory)
174 example_replace_old_by_fancy_new(factory, pattern_factory)
175 example_use_ast_kind_finder(factory, pattern_factory)
176 example_use_ast_function_finder(factory, pattern_factory)
179if __name__ == "__main__":
180 import sys
182 main(sys.argv)