22
22
import java .util .stream .Stream ;
23
23
24
24
import org .eclipse .core .runtime .CoreException ;
25
+ import org .eclipse .core .runtime .NullProgressMonitor ;
25
26
import org .eclipse .core .runtime .OperationCanceledException ;
27
+ import org .eclipse .core .runtime .jobs .Job ;
26
28
import org .eclipse .jdt .core .ICompilationUnit ;
29
+ import org .eclipse .jdt .core .IJavaProject ;
27
30
import org .eclipse .jdt .core .ISourceRange ;
28
31
import org .eclipse .jdt .core .JavaModelException ;
32
+ import org .eclipse .jdt .core .Signature ;
33
+ import org .eclipse .jdt .core .dom .AST ;
29
34
import org .eclipse .jdt .core .dom .CompilationUnit ;
35
+ import org .eclipse .jdt .core .dom .Name ;
36
+ import org .eclipse .jdt .core .dom .SimpleName ;
37
+ import org .eclipse .jdt .core .dom .rewrite .ASTRewrite ;
38
+ import org .eclipse .jdt .core .dom .rewrite .ImportRewrite ;
39
+ import org .eclipse .jdt .core .manipulation .CodeStyleConfiguration ;
40
+ import org .eclipse .jdt .core .manipulation .ImportReferencesCollector ;
30
41
import org .eclipse .jdt .core .manipulation .OrganizeImportsOperation ;
31
42
import org .eclipse .jdt .core .search .TypeNameMatch ;
43
+ import org .eclipse .jdt .internal .corext .codemanipulation .ContextSensitiveImportRewriteContext ;
32
44
import org .eclipse .jdt .internal .corext .dom .IASTSharedValues ;
33
45
import org .eclipse .jdt .internal .corext .refactoring .util .RefactoringASTParser ;
46
+ import org .eclipse .jdt .internal .corext .util .JavaModelUtil ;
34
47
import org .eclipse .jdt .ls .core .internal .JDTUtils ;
35
48
import org .eclipse .jdt .ls .core .internal .JSONUtility ;
36
49
import org .eclipse .jdt .ls .core .internal .JavaClientConnection ;
37
50
import org .eclipse .jdt .ls .core .internal .JavaLanguageServerPlugin ;
51
+ import org .eclipse .jdt .ls .core .internal .corrections .SimilarElementsRequestor ;
52
+ import org .eclipse .jdt .ls .core .internal .preferences .PreferenceManager ;
38
53
import org .eclipse .jdt .ls .core .internal .text .correction .SourceAssistProcessor ;
39
54
import org .eclipse .lsp4j .CodeActionParams ;
40
55
import org .eclipse .lsp4j .Range ;
41
56
import org .eclipse .lsp4j .WorkspaceEdit ;
57
+ import org .eclipse .text .edits .DeleteEdit ;
58
+ import org .eclipse .text .edits .InsertEdit ;
59
+ import org .eclipse .text .edits .MalformedTreeException ;
42
60
import org .eclipse .text .edits .TextEdit ;
43
61
44
62
import com .google .gson .Gson ;
@@ -50,7 +68,6 @@ public static TextEdit organizeImports(ICompilationUnit unit, Function<ImportSel
50
68
if (unit == null ) {
51
69
return null ;
52
70
}
53
-
54
71
RefactoringASTParser astParser = new RefactoringASTParser (IASTSharedValues .SHARED_AST_LEVEL );
55
72
CompilationUnit astRoot = astParser .parse (unit , true );
56
73
OrganizeImportsOperation op = new OrganizeImportsOperation (unit , astRoot , true , false , true , (TypeNameMatch [][] openChoices , ISourceRange [] ranges ) -> {
@@ -78,16 +95,97 @@ public static TextEdit organizeImports(ICompilationUnit unit, Function<ImportSel
78
95
});
79
96
return Stream .of (chosens ).filter (chosen -> chosen != null && typeMaps .containsKey (chosen .id )).map (chosen -> typeMaps .get (chosen .id )).toArray (TypeNameMatch []::new );
80
97
});
81
-
82
98
try {
83
- return op .createTextEdit (null );
84
- } catch (OperationCanceledException | CoreException e ) {
99
+ Job .getJobManager ().join (BaseDocumentLifeCycleHandler .DOCUMENT_LIFE_CYCLE_JOBS , new NullProgressMonitor ());
100
+ TextEdit edit = op .createTextEdit (null );
101
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=283287
102
+ TextEdit staticEdit = wrapStaticImports (edit , astRoot , unit );
103
+ if (staticEdit .getChildrenSize () == 0 ) {
104
+ return null ;
105
+ }
106
+ return staticEdit ;
107
+ } catch (OperationCanceledException | CoreException | InterruptedException e ) {
85
108
JavaLanguageServerPlugin .logException ("Failed to resolve organize imports source action" , e );
86
109
}
87
-
88
110
return null ;
89
111
}
90
112
113
+ private static TextEdit wrapStaticImports (TextEdit edit , CompilationUnit root , ICompilationUnit unit ) throws MalformedTreeException , CoreException {
114
+ String [] favourites = PreferenceManager .getPrefs (unit .getResource ()).getJavaCompletionFavoriteMembers ();
115
+ if (favourites .length == 0 ) {
116
+ return edit ;
117
+ }
118
+ IJavaProject project = unit .getJavaProject ();
119
+ if (JavaModelUtil .is50OrHigher (project )) {
120
+ List <SimpleName > typeReferences = new ArrayList <>();
121
+ List <SimpleName > staticReferences = new ArrayList <>();
122
+ ImportReferencesCollector .collect (root , project , null , typeReferences , staticReferences );
123
+ if (staticReferences .isEmpty ()) {
124
+ return edit ;
125
+ }
126
+ ImportRewrite importRewrite = CodeStyleConfiguration .createImportRewrite (root , true );
127
+ AST ast = root .getAST ();
128
+ ASTRewrite astRewrite = ASTRewrite .create (ast );
129
+ for (SimpleName node : staticReferences ) {
130
+ addImports (root , unit , favourites , importRewrite , ast , astRewrite , node , true );
131
+ addImports (root , unit , favourites , importRewrite , ast , astRewrite , node , false );
132
+ }
133
+ TextEdit staticEdit = importRewrite .rewriteImports (null );
134
+ if (staticEdit != null && staticEdit .getChildrenSize () > 0 ) {
135
+ TextEdit lastStatic = staticEdit .getChildren ()[staticEdit .getChildrenSize () - 1 ];
136
+ if (lastStatic instanceof DeleteEdit ) {
137
+ if (edit .getChildrenSize () > 0 ) {
138
+ TextEdit last = edit .getChildren ()[edit .getChildrenSize () - 1 ];
139
+ if (last instanceof DeleteEdit && lastStatic .getOffset () == last .getOffset () && lastStatic .getLength () == last .getLength ()) {
140
+ edit .removeChild (last );
141
+ }
142
+ }
143
+ }
144
+ TextEdit firstStatic = staticEdit .getChildren ()[0 ];
145
+ if (firstStatic instanceof InsertEdit ) {
146
+ if (edit .getChildrenSize () > 0 ) {
147
+ TextEdit firstEdit = edit .getChildren ()[0 ];
148
+ if (firstEdit instanceof InsertEdit ) {
149
+ if (isEquals ((InsertEdit ) firstEdit , (InsertEdit ) firstStatic )) {
150
+ edit .removeChild (firstEdit );
151
+ }
152
+ }
153
+ }
154
+ }
155
+ try {
156
+ staticEdit .addChild (edit );
157
+ return staticEdit ;
158
+ } catch (MalformedTreeException e ) {
159
+ JavaLanguageServerPlugin .logException ("Failed to resolve static organize imports source action" , e );
160
+ }
161
+ }
162
+ }
163
+ return edit ;
164
+ }
165
+
166
+ private static boolean isEquals (InsertEdit edit1 , InsertEdit edit2 ) {
167
+ if (edit1 != null && edit2 != null ) {
168
+ return edit1 .getOffset () == edit2 .getOffset () && edit1 .getLength () == edit2 .getLength () && edit1 .getText ().equals (edit2 .getText ());
169
+ }
170
+ return false ;
171
+ }
172
+
173
+ private static void addImports (CompilationUnit root , ICompilationUnit unit , String [] favourites , ImportRewrite importRewrite , AST ast , ASTRewrite astRewrite , SimpleName node , boolean isMethod ) throws JavaModelException {
174
+ String name = node .getIdentifier ();
175
+ String [] imports = SimilarElementsRequestor .getStaticImportFavorites (unit , name , isMethod , favourites );
176
+ for (int i = 0 ; i < imports .length ; i ++) {
177
+ String curr = imports [i ];
178
+ String qualifiedTypeName = Signature .getQualifier (curr );
179
+ String res = importRewrite .addStaticImport (qualifiedTypeName , name , isMethod , new ContextSensitiveImportRewriteContext (root , node .getStartPosition (), importRewrite ));
180
+ int dot = res .lastIndexOf ('.' );
181
+ if (dot != -1 ) {
182
+ String usedTypeName = importRewrite .addImport (qualifiedTypeName );
183
+ Name newName = ast .newQualifiedName (ast .newName (usedTypeName ), ast .newSimpleName (name ));
184
+ astRewrite .replace (node , newName , null );
185
+ }
186
+ }
187
+ }
188
+
91
189
public static WorkspaceEdit organizeImports (JavaClientConnection connection , CodeActionParams params ) {
92
190
String uri = params .getTextDocument ().getUri ();
93
191
final ICompilationUnit unit = JDTUtils .resolveCompilationUnit (params .getTextDocument ().getUri ());
0 commit comments