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,38 @@ 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 ()) bal = o2 .isModule () ? 0 : 1 ; // Place element imports last
248
+ else if (o2 .isModule ()) bal = -1 ; // Place element imports last
249
+ else bal = groups .getGroupId (s1 , o1 .isStatic ()) - groups .getGroupId (s2 , o2 .isStatic ());
217
250
return bal == 0 ? s1 .compareTo (s2 ) : bal ;
218
251
}
219
252
});
220
253
}
221
254
CompilationUnitTree cut = maker .CompilationUnit (cu .getPackageAnnotations (), cu .getPackageName (), imps , cu .getTypeDecls (), cu .getSourceFile ());
222
255
((JCCompilationUnit )cut ).packge = ((JCCompilationUnit )cu ).packge ;
223
- if (starImports != null || staticStarImports != null ) {
224
- ((JCCompilationUnit )cut ).starImportScope = ((JCCompilationUnit )cu ).starImportScope ;
256
+ ((JCCompilationUnit )cut ).starImportScope = ((JCCompilationUnit )cu ).starImportScope ;
257
+ if (!moduleImports .isEmpty ()) {
258
+ ((JCCompilationUnit )cut ).moduleImportScope = ((JCCompilationUnit )cu ).moduleImportScope ;
225
259
}
226
260
CompilationUnitTree ncu = toImport .isEmpty () ? cut : GeneratorUtilities .get (copy ).addImports (cut , toImport );
227
261
copy .rewrite (cu , ncu );
228
262
}
263
+
264
+ private static void collectTransitivelyUsedModules (final ModuleElement importedModule , final ExpressionTree importIdentifier , final Set <Element > usedModules , final CompilationInfo info , final Map <ModuleElement , Pair <ExpressionTree , ModuleElement >> transitiveModulesToImportingIdentifier ) {
265
+ if (importedModule != null ) {
266
+ if (usedModules .contains (importedModule ))
267
+ return ;
268
+ Pair <ExpressionTree , ModuleElement > root = Pair .of (importIdentifier , importedModule );
269
+ for (PackageElement pack : info .getElementUtilities ().transitivelyExportedPackages (importedModule )) {
270
+ if ((pack .getEnclosingElement () instanceof ModuleElement transitiveModule ) && transitiveModule != importedModule && usedModules .contains (transitiveModule )) {
271
+ transitiveModulesToImportingIdentifier .putIfAbsent (transitiveModule , root );
272
+ }
273
+ }
274
+ }
275
+ }
229
276
230
- private static Set <Element > getUsedElements (final CompilationInfo info , final CompilationUnitTree cut , final Set <Element > starImports , final Set <Element > staticStarImports ) {
277
+ private static Set <Element > getUsedElements (final CompilationInfo info , final CompilationUnitTree cut , final Set <Element > starImports , final Set <Element > staticStarImports , final Set < Element > moduleImports ) {
231
278
final Set <Element > ret = new HashSet <Element >();
232
279
final Trees trees = info .getTrees ();
233
280
final Types types = info .getTypes ();
@@ -273,7 +320,7 @@ private void addElement(Element element) {
273
320
case FIELD :
274
321
case METHOD :
275
322
if (element .getModifiers ().contains (Modifier .STATIC )) {
276
- Element glob = global (element , staticStarImports );
323
+ Element glob = global (element , staticStarImports , moduleImports );
277
324
if (glob != null )
278
325
ret .add (glob );
279
326
}
@@ -283,14 +330,14 @@ private void addElement(Element element) {
283
330
case RECORD :
284
331
case ENUM :
285
332
case INTERFACE :
286
- Element glob = global (element , starImports );
333
+ Element glob = global (element , starImports , moduleImports );
287
334
if (glob != null )
288
335
ret .add (glob );
289
336
}
290
337
}
291
338
}
292
339
293
- private Element global (Element element , Set <Element > stars ) {
340
+ private Element global (Element element , Set <Element > stars , Set < Element > modules ) {
294
341
for (Symbol sym : ((JCCompilationUnit )cut ).namedImportScope .getSymbolsByName ((Name )element .getSimpleName ())) {
295
342
if (element == sym || element .asType ().getKind () == TypeKind .ERROR && element .getKind () == sym .getKind ())
296
343
return sym ;
@@ -307,6 +354,14 @@ private Element global(Element element, Set<Element> stars) {
307
354
return sym ;
308
355
}
309
356
}
357
+ for (Symbol sym : ((JCCompilationUnit )cut ).moduleImportScope .getSymbolsByName ((Name )element .getSimpleName ())) {
358
+ if (element == sym || element .asType ().getKind () == TypeKind .ERROR && element .getKind () == sym .getKind ()) {
359
+ if (modules != null ) {
360
+ modules .add (sym .packge ().modle );
361
+ }
362
+ return sym ;
363
+ }
364
+ }
310
365
return null ;
311
366
}
312
367
}.scan (cut , null );
0 commit comments