42 import com.sun.tools.jextract.tree.TreePhase;
43 import com.sun.tools.jextract.tree.TreePrinter;
44 import com.sun.tools.jextract.tree.TypedefTree;
45 import jdk.internal.clang.Cursor;
46 import jdk.internal.clang.SourceLocation;
47
48 /**
49 * This visitor handles certain typedef declarations.
50 *
51 * 1. Remove redundant typedefs.
52 * 2. Rename typedef'ed anonymous type definitions like
53 * typedef struct { int x; int y; } Point;
54 * 3. Remove redundant struct/union/enum forward/backward declarations
55 */
56 final class TypedefHandler extends SimpleTreeVisitor<Void, Void>
57 implements TreePhase {
58 private final TreeMaker treeMaker = new TreeMaker();
59
60 // Potential Tree instances that will go into transformed HeaderTree
61 // are collected in this list.
62 private final List<Tree> decls = new ArrayList<>();
63
64 // Tree instances that are to be replaced from "decls" list are
65 // saved in the following Map.
66 private final Map<Cursor, Tree> replacements = new HashMap<>();
67
68 private Path headerPath;
69
70 private static boolean isFromPath(Tree tree, Path path) {
71 SourceLocation loc = tree.location();
72 return loc != null? Objects.equals(path, loc.getFileLocation().path()) : false;
73 }
74
75 private boolean isFromThisHeader(Tree tree) {
76 return isFromPath(tree, headerPath);
77 }
78
79 @Override
80 public HeaderTree transform(HeaderTree ht) {
81 this.headerPath = ht.path();
82 // Process all header declarations are collect potential
83 // declarations that will go into transformed HeaderTree
84 // into the this.decls field.
85 ht.accept(this, null);
86
87 // Replace trees from this.decls with Trees found in this.replacements.
88 // We need this two step process so that named StructTree instances
89 // will replace with original unnamed StructTree instances.
90 List<Tree> newDecls = decls.stream().map(tx -> {
91 if (replacements.containsKey(tx.cursor())) {
92 return replacements.get(tx.cursor());
93 } else {
94 return tx;
95 }
96 }).collect(Collectors.toList());
97
98 return treeMaker.createHeader(ht.cursor(), ht.path(), newDecls);
99 }
100
101 @Override
110 * If we're seeing a forward/backward declaration of an
111 * enum which is definied elsewhere in this compilation
112 * unit, ignore it. If no definition is found, we want to
113 * leave the declaration so that dummy definition will be
114 * generated.
115 *
116 * Example:
117 *
118 * enum Color ; // <-- forward declaration
119 * struct Point { int i; int j; };
120 * struct Point3D { int i; int j; int k; };
121 * struct Point3D; // <-- backward declaration
122 */
123
124 // include this only if this is a definition or a declaration
125 // for which no definition is found elsewhere in this header.
126 if (e.isDefinition()) {
127 decls.add(e);
128 } else {
129 Optional<Tree> def = e.definition();
130 if (!def.isPresent() || !isFromThisHeader(def.get())) {
131 decls.add(e);
132 }
133 }
134 return null;
135 }
136
137 @Override
138 public Void visitHeader(HeaderTree ht, Void v) {
139 ht.declarations().forEach(decl -> decl.accept(this, null));
140 return null;
141 }
142
143 @Override
144 public Void visitStruct(StructTree s, Void v) {
145 /*
146 * If we're seeing a forward/backward declaration of
147 * a struct which is definied elsewhere in this compilation
148 * unit, ignore it. If no definition is found, we want to
149 * leave the declaration so that dummy definition will be
150 * generated.
151 *
152 * Example:
153 *
154 * struct Point; // <-- forward declaration
155 * struct Point { int i; int j; };
156 * struct Point3D { int i; int j; int k; };
157 * struct Point3D; // <-- backward declaration
158 */
159
160 // include this only if this is a definition or a declaration
161 // for which no definition is found elsewhere in this header.
162 if (s.isDefinition()) {
163 decls.add(s);
164 } else {
165 Optional<Tree> def = s.definition();
166 if (!def.isPresent() || !isFromThisHeader(def.get())) {
167 decls.add(s);
168 }
169 }
170 return null;
171 }
172
173 @Override
174 public Void visitTypedef(TypedefTree tt, Void v) {
175 Optional<Tree> def = tt.typeDefinition();
176 if (def.isPresent()) {
177 Tree defTree = def.get();
178 if (defTree instanceof StructTree && defTree.name().isEmpty()) {
179 /*
180 * typedef struct { int x; int y; } Point
181 *
182 * is mapped to two Cursors by clang. First one for anonymous struct decl.
183 * and second one for typedef decl. We map it as a single named struct
184 * declaration.
185 */
186 replacements.put(defTree.cursor(), ((StructTree)defTree).withName(tt.name()));
187 return null;
191 *
192 * typedef struct Point { int x; int y; } Point
193 * typedef enum Color { R, G, B} Color
194 * typedef struct Undef Undef
195 */
196 return null;
197 }
198 }
199
200 decls.add(tt);
201 return null;
202 }
203
204 // test main to manually check this visitor
205 public static void main(String[] args) {
206 if (args.length == 0) {
207 System.err.println("Expected a header file");
208 return;
209 }
210
211 Parser p = new Parser(true);
212 List<Path> paths = Arrays.stream(args).map(Paths::get).collect(Collectors.toList());
213 Path builtinInc = Paths.get(System.getProperty("java.home"), "conf", "jextract");
214 List<String> clangArgs = List.of("-I" + builtinInc);
215 List<HeaderTree> headers = p.parse(paths, clangArgs);
216 TreePrinter printer = new TreePrinter();
217 TypedefHandler handler = new TypedefHandler();
218 for (HeaderTree ht : headers) {
219 handler.transform(ht).accept(printer, null);
220 }
221 }
222 }
|
42 import com.sun.tools.jextract.tree.TreePhase;
43 import com.sun.tools.jextract.tree.TreePrinter;
44 import com.sun.tools.jextract.tree.TypedefTree;
45 import jdk.internal.clang.Cursor;
46 import jdk.internal.clang.SourceLocation;
47
48 /**
49 * This visitor handles certain typedef declarations.
50 *
51 * 1. Remove redundant typedefs.
52 * 2. Rename typedef'ed anonymous type definitions like
53 * typedef struct { int x; int y; } Point;
54 * 3. Remove redundant struct/union/enum forward/backward declarations
55 */
56 final class TypedefHandler extends SimpleTreeVisitor<Void, Void>
57 implements TreePhase {
58 private final TreeMaker treeMaker = new TreeMaker();
59
60 // Potential Tree instances that will go into transformed HeaderTree
61 // are collected in this list.
62 private List<Tree> decls = new ArrayList<>();
63
64 // Tree instances that are to be replaced from "decls" list are
65 // saved in the following Map.
66 private final Map<Cursor, Tree> replacements = new HashMap<>();
67
68 private boolean isFromSameHeader(Tree def, Tree decl) {
69 SourceLocation locDef = def.location();
70 SourceLocation locDecl = decl.location();
71 return locDef != null && locDecl != null &&
72 Objects.equals(locDecl.getFileLocation().path(), locDef.getFileLocation().path());
73 }
74
75 @Override
76 public HeaderTree transform(HeaderTree ht) {
77 // Process all header declarations are collect potential
78 // declarations that will go into transformed HeaderTree
79 // into the this.decls field.
80 ht.accept(this, null);
81
82 // Replace trees from this.decls with Trees found in this.replacements.
83 // We need this two step process so that named StructTree instances
84 // will replace with original unnamed StructTree instances.
85 List<Tree> newDecls = decls.stream().map(tx -> {
86 if (replacements.containsKey(tx.cursor())) {
87 return replacements.get(tx.cursor());
88 } else {
89 return tx;
90 }
91 }).collect(Collectors.toList());
92
93 return treeMaker.createHeader(ht.cursor(), ht.path(), newDecls);
94 }
95
96 @Override
105 * If we're seeing a forward/backward declaration of an
106 * enum which is definied elsewhere in this compilation
107 * unit, ignore it. If no definition is found, we want to
108 * leave the declaration so that dummy definition will be
109 * generated.
110 *
111 * Example:
112 *
113 * enum Color ; // <-- forward declaration
114 * struct Point { int i; int j; };
115 * struct Point3D { int i; int j; int k; };
116 * struct Point3D; // <-- backward declaration
117 */
118
119 // include this only if this is a definition or a declaration
120 // for which no definition is found elsewhere in this header.
121 if (e.isDefinition()) {
122 decls.add(e);
123 } else {
124 Optional<Tree> def = e.definition();
125 if (!def.isPresent() || !isFromSameHeader(def.get(), e)) {
126 decls.add(e);
127 }
128 }
129 return null;
130 }
131
132 @Override
133 public Void visitHeader(HeaderTree ht, Void v) {
134 ht.declarations().forEach(decl -> decl.accept(this, null));
135 return null;
136 }
137
138 @Override
139 public Void visitStruct(StructTree s, Void v) {
140 List<Tree> oldDecls = decls;
141 List<Tree> structDecls = new ArrayList<>();
142 try {
143 decls = structDecls;
144 s.declarations().forEach(t -> t.accept(this, null));
145 } finally {
146 decls = oldDecls;
147 }
148
149 /*
150 * If we're seeing a forward/backward declaration of
151 * a struct which is definied elsewhere in this compilation
152 * unit, ignore it. If no definition is found, we want to
153 * leave the declaration so that dummy definition will be
154 * generated.
155 *
156 * Example:
157 *
158 * struct Point; // <-- forward declaration
159 * struct Point { int i; int j; };
160 * struct Point3D { int i; int j; int k; };
161 * struct Point3D; // <-- backward declaration
162 */
163
164 // include this only if this is a definition or a declaration
165 // for which no definition is found elsewhere in this header.
166 if (s.isDefinition()) {
167 decls.add(s.withNameAndDecls(s.name(), structDecls));
168 } else {
169 Optional<Tree> def = s.definition();
170 if (!def.isPresent() || !isFromSameHeader(def.get(), s)) {
171 decls.add(s.withNameAndDecls(s.name(), structDecls));
172 }
173 }
174 return null;
175 }
176
177 @Override
178 public Void visitTypedef(TypedefTree tt, Void v) {
179 Optional<Tree> def = tt.typeDefinition();
180 if (def.isPresent()) {
181 Tree defTree = def.get();
182 if (defTree instanceof StructTree && defTree.name().isEmpty()) {
183 /*
184 * typedef struct { int x; int y; } Point
185 *
186 * is mapped to two Cursors by clang. First one for anonymous struct decl.
187 * and second one for typedef decl. We map it as a single named struct
188 * declaration.
189 */
190 replacements.put(defTree.cursor(), ((StructTree)defTree).withName(tt.name()));
191 return null;
195 *
196 * typedef struct Point { int x; int y; } Point
197 * typedef enum Color { R, G, B} Color
198 * typedef struct Undef Undef
199 */
200 return null;
201 }
202 }
203
204 decls.add(tt);
205 return null;
206 }
207
208 // test main to manually check this visitor
209 public static void main(String[] args) {
210 if (args.length == 0) {
211 System.err.println("Expected a header file");
212 return;
213 }
214
215 Context context = new Context();
216 Parser p = new Parser(context, true);
217 List<Path> paths = Arrays.stream(args).map(Paths::get).collect(Collectors.toList());
218 Path builtinInc = Paths.get(System.getProperty("java.home"), "conf", "jextract");
219 List<String> clangArgs = List.of("-I" + builtinInc);
220 List<HeaderTree> headers = p.parse(paths, clangArgs);
221 TreePrinter printer = new TreePrinter();
222 TypedefHandler handler = new TypedefHandler();
223 for (HeaderTree ht : headers) {
224 handler.transform(ht).accept(printer, null);
225 }
226 }
227 }
|