22
22
import java .awt .event .ActionEvent ;
23
23
import java .util .Collections ;
24
24
import java .util .Comparator ;
25
+ import java .util .HashMap ;
25
26
import java .util .HashSet ;
26
27
import java .util .LinkedList ;
27
28
import java .util .List ;
29
+ import java .util .Map ;
28
30
import java .util .Set ;
29
31
import java .util .concurrent .atomic .AtomicBoolean ;
30
32
31
33
import javax .lang .model .element .Element ;
32
34
import javax .lang .model .element .Modifier ;
35
+ import javax .lang .model .element .ModuleElement ;
36
+ import javax .lang .model .element .PackageElement ;
33
37
import javax .lang .model .type .TypeKind ;
34
38
import javax .lang .model .util .Types ;
35
39
import javax .swing .text .JTextComponent ;
36
40
import javax .tools .Diagnostic ;
37
41
38
42
import com .sun .source .tree .ClassTree ;
39
43
import com .sun .source .tree .CompilationUnitTree ;
44
+ import com .sun .source .tree .ExpressionTree ;
40
45
import com .sun .source .tree .IdentifierTree ;
41
46
import com .sun .source .tree .ImportTree ;
42
47
import com .sun .source .tree .MemberSelectTree ;
80
85
import org .netbeans .spi .java .hints .TriggerTreeKind ;
81
86
import org .openide .util .Exceptions ;
82
87
import org .openide .util .NbBundle ;
88
+ import org .openide .util .Pair ;
83
89
84
90
/**
85
91
*
@@ -160,10 +166,11 @@ public static void doOrganizeImports(WorkingCopy copy, Set<Element> addImports,
160
166
}
161
167
}
162
168
final CodeStyle cs = CodeStyle .getDefault (copy .getFileObject ());
163
- Set <Element > starImports = new HashSet <Element >();
164
- Set <Element > staticStarImports = new HashSet <Element >();
165
- Set <Element > toImport = getUsedElements (copy , cu , starImports , staticStarImports );
166
- List <ImportTree > imps = new LinkedList <ImportTree >();
169
+ final Set <Element > starImports = new HashSet <>();
170
+ final Set <Element > staticStarImports = new HashSet <>();
171
+ final Set <Element > moduleImports = new HashSet <>();
172
+ Set <Element > toImport = getUsedElements (copy , cu , starImports , staticStarImports , moduleImports );
173
+ final List <ImportTree > imps = new LinkedList <>();
167
174
TreeMaker maker = copy .getTreeMaker ();
168
175
169
176
if (addImports != null ) {
@@ -173,6 +180,7 @@ public static void doOrganizeImports(WorkingCopy copy, Set<Element> addImports,
173
180
} else if (!toImport .isEmpty () || isBulkMode ) {
174
181
// track import star import scopes, so only one star import/scope appears in imps - #251977
175
182
Set <Element > starImportScopes = new HashSet <>();
183
+ Map <ModuleElement , Pair <ExpressionTree , ModuleElement >> transitiveScopeToModuleImport = new HashMap <>();
176
184
Trees trees = copy .getTrees ();
177
185
for (ImportTree importTree : cu .getImports ()) {
178
186
Tree qualIdent = importTree .getQualifiedIdentifier ();
@@ -181,13 +189,13 @@ public static void doOrganizeImports(WorkingCopy copy, Set<Element> addImports,
181
189
Element importedScope = trees .getElement (TreePath .getPath (cu , ((MemberSelectTree )qualIdent ).getExpression ()));
182
190
183
191
if (importTree .isStatic ()) {
184
- if (staticStarImports != null &&
192
+ if (! staticStarImports . isEmpty () &&
185
193
staticStarImports .contains (importedScope ) &&
186
194
!starImportScopes .contains (importedScope )) {
187
195
imp = maker .Import (qualIdent , true );
188
196
}
189
197
} else {
190
- if (starImports != null &&
198
+ if (! starImports . isEmpty () &&
191
199
starImports .contains (importedScope ) &&
192
200
!starImportScopes .contains (importedScope )) {
193
201
imp = maker .Import (qualIdent , false );
@@ -197,6 +205,28 @@ public static void doOrganizeImports(WorkingCopy copy, Set<Element> addImports,
197
205
starImportScopes .add (importedScope );
198
206
imps .add (imp );
199
207
}
208
+ } else if (importTree .isModule ()) {
209
+ ModuleElement importedScope = copy .getElements ().getModuleElement (qualIdent .toString ());
210
+ if (qualIdent instanceof ExpressionTree moduleIdentifier ) {
211
+ if (importedScope == null ) {
212
+ //do not mark unresolvable element imports as unused
213
+ imps .add (maker .ImportModule (moduleIdentifier ));
214
+ } else if (!moduleImports .isEmpty () && !starImportScopes .contains (importedScope )) {
215
+ if (moduleImports .contains (importedScope )) {
216
+ imps .add (maker .ImportModule (moduleIdentifier ));
217
+ starImportScopes .add (importedScope );
218
+ } else {
219
+ collectTransitivelyUsedModules (importedScope , moduleIdentifier , moduleImports , copy , transitiveScopeToModuleImport );
220
+ }
221
+ }
222
+ }
223
+ }
224
+ }
225
+ // Add any used modules that are only referred by a transitive import
226
+ for (Map .Entry <ModuleElement , Pair <ExpressionTree , ModuleElement >> t : transitiveScopeToModuleImport .entrySet ()) {
227
+ if (!starImportScopes .contains (t .getKey ()) && !starImportScopes .contains (t .getValue ().second ())) {
228
+ imps .add (maker .ImportModule (t .getValue ().first ()));
229
+ starImportScopes .add (t .getValue ().second ());
200
230
}
201
231
}
202
232
} else {
@@ -213,21 +243,42 @@ public int compare(ImportTree o1, ImportTree o2) {
213
243
return 0 ;
214
244
String s1 = o1 .getQualifiedIdentifier ().toString ();
215
245
String s2 = o2 .getQualifiedIdentifier ().toString ();
216
- int bal = groups .getGroupId (s1 , o1 .isStatic ()) - groups .getGroupId (s2 , o2 .isStatic ());
246
+ int bal ;
247
+ if (o1 .isModule ()) {
248
+ bal = o2 .isModule () ? 0 : 1 ; // Place element imports last
249
+ } else if (o2 .isModule ()) {
250
+ bal = -1 ; // Place element imports last
251
+ } else {
252
+ bal = groups .getGroupId (s1 , o1 .isStatic ()) - groups .getGroupId (s2 , o2 .isStatic ());
253
+ }
217
254
return bal == 0 ? s1 .compareTo (s2 ) : bal ;
218
255
}
219
256
});
220
257
}
221
258
CompilationUnitTree cut = maker .CompilationUnit (cu .getPackageAnnotations (), cu .getPackageName (), imps , cu .getTypeDecls (), cu .getSourceFile ());
222
259
((JCCompilationUnit )cut ).packge = ((JCCompilationUnit )cu ).packge ;
223
- if (starImports != null || staticStarImports != null ) {
224
- ((JCCompilationUnit )cut ).starImportScope = ((JCCompilationUnit )cu ).starImportScope ;
260
+ ((JCCompilationUnit )cut ).starImportScope = ((JCCompilationUnit )cu ).starImportScope ;
261
+ if (!moduleImports .isEmpty ()) {
262
+ ((JCCompilationUnit )cut ).moduleImportScope = ((JCCompilationUnit )cu ).moduleImportScope ;
225
263
}
226
264
CompilationUnitTree ncu = toImport .isEmpty () ? cut : GeneratorUtilities .get (copy ).addImports (cut , toImport );
227
265
copy .rewrite (cu , ncu );
228
266
}
267
+
268
+ private static void collectTransitivelyUsedModules (final ModuleElement importedModule , final ExpressionTree importIdentifier , final Set <Element > usedModules , final CompilationInfo info , final Map <ModuleElement , Pair <ExpressionTree , ModuleElement >> transitiveModulesToImportingIdentifier ) {
269
+ if (importedModule != null ) {
270
+ if (usedModules .contains (importedModule ))
271
+ return ;
272
+ Pair <ExpressionTree , ModuleElement > root = Pair .of (importIdentifier , importedModule );
273
+ for (PackageElement pack : info .getElementUtilities ().transitivelyExportedPackages (importedModule )) {
274
+ if ((pack .getEnclosingElement () instanceof ModuleElement transitiveModule ) && transitiveModule != importedModule && usedModules .contains (transitiveModule )) {
275
+ transitiveModulesToImportingIdentifier .putIfAbsent (transitiveModule , root );
276
+ }
277
+ }
278
+ }
279
+ }
229
280
230
- private static Set <Element > getUsedElements (final CompilationInfo info , final CompilationUnitTree cut , final Set <Element > starImports , final Set <Element > staticStarImports ) {
281
+ private static Set <Element > getUsedElements (final CompilationInfo info , final CompilationUnitTree cut , final Set <Element > starImports , final Set <Element > staticStarImports , final Set < Element > moduleImports ) {
231
282
final Set <Element > ret = new HashSet <Element >();
232
283
final Trees trees = info .getTrees ();
233
284
final Types types = info .getTypes ();
@@ -273,7 +324,7 @@ private void addElement(Element element) {
273
324
case FIELD :
274
325
case METHOD :
275
326
if (element .getModifiers ().contains (Modifier .STATIC )) {
276
- Element glob = global (element , staticStarImports );
327
+ Element glob = global (element , staticStarImports , moduleImports );
277
328
if (glob != null )
278
329
ret .add (glob );
279
330
}
@@ -283,14 +334,14 @@ private void addElement(Element element) {
283
334
case RECORD :
284
335
case ENUM :
285
336
case INTERFACE :
286
- Element glob = global (element , starImports );
337
+ Element glob = global (element , starImports , moduleImports );
287
338
if (glob != null )
288
339
ret .add (glob );
289
340
}
290
341
}
291
342
}
292
343
293
- private Element global (Element element , Set <Element > stars ) {
344
+ private Element global (Element element , Set <Element > stars , Set < Element > modules ) {
294
345
for (Symbol sym : ((JCCompilationUnit )cut ).namedImportScope .getSymbolsByName ((Name )element .getSimpleName ())) {
295
346
if (element == sym || element .asType ().getKind () == TypeKind .ERROR && element .getKind () == sym .getKind ())
296
347
return sym ;
@@ -307,6 +358,14 @@ private Element global(Element element, Set<Element> stars) {
307
358
return sym ;
308
359
}
309
360
}
361
+ for (Symbol sym : ((JCCompilationUnit )cut ).moduleImportScope .getSymbolsByName ((Name )element .getSimpleName ())) {
362
+ if (element == sym || element .asType ().getKind () == TypeKind .ERROR && element .getKind () == sym .getKind ()) {
363
+ if (modules != null ) {
364
+ modules .add (sym .packge ().modle );
365
+ }
366
+ return sym ;
367
+ }
368
+ }
310
369
return null ;
311
370
}
312
371
}.scan (cut , null );
0 commit comments