4
4
import io .avaje .prism .GeneratePrism ;
5
5
import io .github .digitalsmile .annotation .ArenaType ;
6
6
import io .github .digitalsmile .annotation .NativeMemory ;
7
- import io .github .digitalsmile .annotation .NativeMemoryException ;
8
7
import io .github .digitalsmile .annotation .NativeMemoryOptions ;
9
8
import io .github .digitalsmile .annotation .function .ByAddress ;
10
9
import io .github .digitalsmile .annotation .function .NativeManualFunction ;
11
10
import io .github .digitalsmile .annotation .function .Returns ;
12
- import io .github .digitalsmile .annotation .structure . Enums ;
13
- import io .github .digitalsmile .annotation .structure .Structs ;
14
- import io .github .digitalsmile .annotation .structure .Unions ;
11
+ import io .github .digitalsmile .annotation .library . NativeMemoryLibrary ;
12
+ import io .github .digitalsmile .annotation .structure .* ;
13
+ import io .github .digitalsmile .annotation .structure .Enum ;
15
14
import io .github .digitalsmile .annotation .types .interfaces .NativeMemoryLayout ;
16
15
import io .github .digitalsmile .composers .*;
17
16
import io .github .digitalsmile .functions .FunctionNode ;
25
24
import io .github .digitalsmile .headers .mapping .OriginalType ;
26
25
import io .github .digitalsmile .headers .model .NativeMemoryNode ;
27
26
import io .github .digitalsmile .headers .model .NodeType ;
27
+ import io .github .digitalsmile .validation .NativeProcessorValidator ;
28
+ import io .github .digitalsmile .validation .ValidationException ;
28
29
import org .openjdk .jextract .Declaration ;
29
30
import org .openjdk .jextract .JextractTool ;
30
31
import org .openjdk .jextract .Position ;
50
51
import java .util .regex .Pattern ;
51
52
import java .util .stream .Stream ;
52
53
54
+ import static java .util .Collections .emptyList ;
55
+
53
56
@ GeneratePrism (NativeManualFunction .class )
54
57
@ SupportedSourceVersion (SourceVersion .RELEASE_22 )
55
58
public class NativeProcessor extends AbstractProcessor {
56
59
60
+ private NativeProcessorValidator validator ;
61
+
62
+
57
63
@ Override
58
64
public Set <String > getSupportedAnnotationTypes () {
59
- return Set .of (NativeMemory .class .getName ());
65
+ return Set .of (NativeMemory .class .getName (), NativeMemoryLibrary . class . getName (), NativeManualFunction . class . getName () );
60
66
}
61
67
62
68
@@ -65,75 +71,105 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
65
71
if (roundEnv .processingOver ()) {
66
72
return true ;
67
73
}
68
- for (Element rootElement : roundEnv .getElementsAnnotatedWith (NativeMemory .class )) {
74
+ this .validator = new NativeProcessorValidator (processingEnv .getMessager (), processingEnv .getElementUtils (), processingEnv .getTypeUtils ());
75
+
76
+ for (Element rootElement : roundEnv .getRootElements ()) {
77
+ if (!rootElement .getKind ().isInterface ()) {
78
+ continue ;
79
+ }
80
+ var nativeMemory = rootElement .getAnnotation (NativeMemory .class );
81
+ var manualFunctionElements = rootElement .getEnclosedElements ().stream ().filter (p -> p .getAnnotation (NativeManualFunction .class ) != null ).toList ();
82
+ var automaticFunctionElements = rootElement .getAnnotation (NativeMemoryLibrary .class );
83
+ if (nativeMemory == null && manualFunctionElements .isEmpty () && automaticFunctionElements == null ) {
84
+ continue ;
85
+ }
86
+
69
87
try {
70
- var nativeAnnotation = rootElement .getAnnotation (NativeMemory .class );
71
- var nativeOptions = rootElement .getAnnotation (NativeMemoryOptions .class );
72
- var headerFiles = nativeAnnotation .headers ();
88
+ var parsed = Collections .<NativeMemoryNode >emptyList ();
73
89
var packageName = processingEnv .getElementUtils ().getPackageOf (rootElement ).getQualifiedName ().toString ();
90
+ var nativeOptions = rootElement .getAnnotation (NativeMemoryOptions .class );
74
91
if (nativeOptions != null && !nativeOptions .packageName ().isEmpty ()) {
75
- packageName = nativeOptions .packageName ();
92
+ packageName = validator . validatePackageName ( nativeOptions .packageName () );
76
93
}
77
94
PackageName .setDefaultPackageName (packageName );
78
95
79
- var parsed = processHeaderFiles (rootElement , headerFiles , packageName , nativeOptions );
80
96
81
- List <Element > functionElements = new ArrayList <Element >(roundEnv .getElementsAnnotatedWith (NativeManualFunction .class )).stream ()
82
- .filter (f -> f .getEnclosingElement ().equals (rootElement )).toList ();
83
- processFunctions (rootElement , functionElements , packageName , parsed , nativeOptions );
97
+ if (nativeMemory != null ) {
98
+ var headerFiles = nativeMemory .headers ();
99
+ parsed = processHeaderFiles (rootElement , headerFiles , packageName , nativeOptions );
100
+ }
101
+
102
+ List <Element > manualFunctions = new ArrayList <>();
103
+ for (Element manualFunction : manualFunctionElements ) {
104
+ validator .validateManualFunction (manualFunction );
105
+ manualFunctions .add (manualFunction );
106
+ }
107
+
108
+ if (automaticFunctionElements != null ) {
109
+ validator .validateAutomaticFunctions (parsed , automaticFunctionElements );
110
+ }
84
111
112
+ processFunctions (rootElement , manualFunctions , packageName , parsed , nativeOptions );
113
+ } catch (ValidationException e ) {
114
+ processingEnv .getMessager ().printMessage (Diagnostic .Kind .ERROR , e .getMessage (), e .getElement ());
85
115
} catch (Throwable e ) {
86
116
printStackTrace (e );
87
- processingEnv .getMessager ().printMessage (Diagnostic .Kind .ERROR , e .getMessage ());
117
+ processingEnv .getMessager ().printMessage (Diagnostic .Kind .ERROR , e .getMessage (), rootElement );
88
118
}
89
119
}
90
120
return true ;
91
121
}
92
122
93
- public record Type (String name , String javaName ) {
94
- }
95
-
96
- private List <NativeMemoryNode > processHeaderFiles (Element element , String [] headerFiles , String packageName , NativeMemoryOptions options ) {
123
+ private List <NativeMemoryNode > processHeaderFiles (Element element , String [] headerFiles , String packageName , NativeMemoryOptions options ) throws ValidationException {
97
124
if (headerFiles .length == 0 ) {
98
- return Collections . emptyList ();
125
+ return emptyList ();
99
126
}
100
127
List <Path > headerPaths = getHeaderPaths (headerFiles );
101
128
for (Path path : headerPaths ) {
102
129
if (!path .toFile ().exists ()) {
103
130
processingEnv .getMessager ().printMessage (Diagnostic .Kind .WARNING , "Cannot find header file '" + path + "'! Please, check file location" , element );
104
- return Collections . emptyList ();
131
+ return emptyList ();
105
132
}
106
133
}
107
134
108
135
var structsAnnotation = element .getAnnotation (Structs .class );
109
136
var unionsAnnotation = element .getAnnotation (Unions .class );
110
137
var enumsAnnotation = element .getAnnotation (Enums .class );
111
138
112
- List <Type > structs = null ;
139
+ List <String > structs = null ;
113
140
if (structsAnnotation != null ) {
114
- structs = Arrays .stream (structsAnnotation .value ()).map (struct -> new Type (struct .name (), struct .javaName ())).toList ();
115
- Arrays .stream (structsAnnotation .value ()).forEach (struct -> PrettyName .addName (struct .name (), struct .javaName ()));
141
+ structs = Arrays .stream (structsAnnotation .value ()).map (Struct ::name ).toList ();
142
+ for (Struct struct : structsAnnotation .value ()) {
143
+ var javaName = validator .validateJavaName (struct .javaName ());
144
+ PrettyName .addName (struct .name (), javaName );
145
+ }
116
146
}
117
- List <Type > enums = null ;
147
+ List <String > enums = null ;
118
148
if (enumsAnnotation != null ) {
119
- enums = Arrays .stream (enumsAnnotation .value ()).map (enoom -> new Type (enoom .name (), enoom .javaName ())).toList ();
120
- Arrays .stream (enumsAnnotation .value ()).forEach (enoom -> PrettyName .addName (enoom .name (), enoom .javaName ()));
149
+ enums = Arrays .stream (enumsAnnotation .value ()).map (Enum ::name ).toList ();
150
+ for (Enum enoom : enumsAnnotation .value ()) {
151
+ var javaName = validator .validateJavaName (enoom .javaName ());
152
+ PrettyName .addName (enoom .name (), javaName );
153
+ }
121
154
}
122
- List <Type > unions = null ;
155
+ List <String > unions = null ;
123
156
if (unionsAnnotation != null ) {
124
- unions = Arrays .stream (unionsAnnotation .value ()).map (union -> new Type (union .name (), union .javaName ())).toList ();
125
- Arrays .stream (unionsAnnotation .value ()).forEach (union -> PrettyName .addName (union .name (), union .javaName ()));
157
+ unions = Arrays .stream (unionsAnnotation .value ()).map (Union ::name ).toList ();
158
+ for (Union union : unionsAnnotation .value ()) {
159
+ var javaName = validator .validateJavaName (union .javaName ());
160
+ PrettyName .addName (union .name (), javaName );
161
+ }
126
162
}
127
163
128
164
var rootConstants = false ;
129
165
var debug = false ;
130
166
var systemHeader = false ;
131
- List <String > includes = Collections . emptyList ();
132
- List <String > systemIncludes = Collections . emptyList ();
167
+ List <String > includes = emptyList ();
168
+ List <String > systemIncludes = emptyList ();
133
169
if (options != null ) {
134
170
rootConstants = options .processRootConstants ();
135
171
includes = getHeaderPaths (options .includes ()).stream ().map (p -> "-I" + p .toFile ().getAbsolutePath ()).toList ();
136
- systemIncludes = Arrays . stream (options .systemIncludes ()).map (p -> "-isystem" + p ).toList ();
172
+ systemIncludes = getHeaderPaths (options .systemIncludes ()).stream (). map (p -> "-isystem" + p . toFile (). getAbsolutePath () ).toList ();
137
173
debug = options .debugMode ();
138
174
systemHeader = options .systemHeader ();
139
175
}
@@ -149,7 +185,7 @@ private List<NativeMemoryNode> processHeaderFiles(Element element, String[] head
149
185
printStackTrace (e );
150
186
}
151
187
processingEnv .getMessager ().printMessage (Diagnostic .Kind .ERROR , e .getMessage ());
152
- return Collections . emptyList ();
188
+ return emptyList ();
153
189
}
154
190
}
155
191
var parser = new Parser (packageName , processingEnv .getMessager (), processingEnv .getFiler ());
@@ -167,11 +203,11 @@ private List<NativeMemoryNode> processHeaderFiles(Element element, String[] head
167
203
}
168
204
return parsed ;
169
205
} catch (Throwable e ) {
170
- if (debug ) {
171
- printStackTrace (e );
172
- }
206
+ // if (debug) {
207
+ printStackTrace (e );
208
+ // }
173
209
processingEnv .getMessager ().printMessage (Diagnostic .Kind .ERROR , e .getMessage ());
174
- return Collections . emptyList ();
210
+ return emptyList ();
175
211
}
176
212
}
177
213
@@ -191,9 +227,6 @@ private void processStructs(NativeMemoryNode node) {
191
227
}
192
228
193
229
private void processEnums (NativeMemoryNode node , boolean rootConstants ) {
194
- if (node .nodes ().isEmpty ()) {
195
- return ;
196
- }
197
230
var name = node .getName ();
198
231
if (node .getName ().endsWith ("_constants" )) {
199
232
if (!rootConstants ) {
@@ -225,11 +258,6 @@ private void processFunctions(Element rootElement, List<Element> functionElement
225
258
if (!(element instanceof ExecutableElement functionElement )) {
226
259
continue ;
227
260
}
228
- var throwType = processingEnv .getElementUtils ().getTypeElement (NativeMemoryException .class .getName ()).asType ();
229
- if (!functionElement .getThrownTypes ().contains (throwType )) {
230
- processingEnv .getMessager ().printMessage (Diagnostic .Kind .ERROR , "Method '" + functionElement + "' must throw NativeMemoryException!" , functionElement );
231
- break ;
232
- }
233
261
var instance = NativeManualFunctionPrism .getInstanceOn (functionElement );
234
262
if (instance == null ) {
235
263
break ;
@@ -240,7 +268,7 @@ private void processFunctions(Element rootElement, List<Element> functionElement
240
268
break ;
241
269
}
242
270
List <ParameterNode > parameters = new ArrayList <>();
243
- var returnType = OriginalType .of (processingEnv . getTypeUtils (). erasure ( functionElement .getReturnType () ));
271
+ var returnType = OriginalType .of (functionElement .getReturnType ());
244
272
var returnNode = flatten .stream ().filter (p -> PrettyName .getObjectName (p .getName ()).equals (returnType .typeName ())).findFirst ().orElse (null );
245
273
if (returnNode == null ) {
246
274
var type = functionElement .getReturnType ();
@@ -319,7 +347,7 @@ private OriginalType getBoundsOriginalType(ExecutableElement functionElement) {
319
347
320
348
private FileObject tmpFile ;
321
349
322
- private List <Path > getHeaderPaths (String ... headerFiles ) {
350
+ private List <Path > getHeaderPaths (String ... headerFiles ) throws ValidationException {
323
351
List <Path > paths = new ArrayList <>();
324
352
for (String headerFile : headerFiles ) {
325
353
var beginVariable = headerFile .indexOf ("${" );
@@ -334,6 +362,7 @@ private List<Path> getHeaderPaths(String... headerFiles) {
334
362
continue ;
335
363
}
336
364
}
365
+ headerFile = validator .validatePath (headerFile );
337
366
Path headerPath ;
338
367
if (headerFile .startsWith ("/" )) {
339
368
headerPath = Path .of (headerFile );
0 commit comments