-
Notifications
You must be signed in to change notification settings - Fork 86
/
AddUnimplementedConstructorsOperation.java
317 lines (271 loc) · 10.7 KB
/
AddUnimplementedConstructorsOperation.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
/*******************************************************************************
* Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Microsoft Corporation - refactored to jdt.core.manipulation
* Microsoft Corporation - read preferences from the compilation unit
*******************************************************************************/
package org.eclipse.jdt.internal.corext.codemanipulation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.internal.core.manipulation.StubUtility;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
import org.eclipse.jdt.internal.ui.util.Progress;
/**
* Workspace runnable to add unimplemented constructors.
*
* @since 3.1
*/
public final class AddUnimplementedConstructorsOperation implements IWorkspaceRunnable {
/** Should the resulting edit be applied? */
private final boolean fApply;
/** The qualified names of the generated imports */
private String[] fCreatedImports;
/** The method binding keys for which a constructor was generated */
private final List<String> fCreatedMethods= new ArrayList<>();
/** Should the import edits be applied? */
private final boolean fImports;
/** The insertion point, or <code>-1</code> */
private final int fInsertPos;
/** The method bindings to implement */
private final IMethodBinding[] fConstructorsToImplement;
/** Should the call to the super constructor be omitted? */
private boolean fOmitSuper;
/** Should the compilation unit content be saved? */
private final boolean fSave;
/** Specified if comments should be created */
private boolean fCreateComments;
/** The type declaration to add the constructors to */
private final ITypeBinding fType;
/** The compilation unit AST node */
private final CompilationUnit fASTRoot;
/** The visibility flags of the new constructor */
private int fVisibility;
/** The formatter settings of the new constructor */
private Map<String, String> fFormatSettings;
/** The resulting text edit */
private TextEdit fResultingEdit= null;
/**
* Creates a new add unimplemented constructors operation.
*
* @param astRoot the compilation unit AST node
* @param type the type to add the methods to
* @param constructorsToImplement the method binding keys to implement
* @param insertPos the insertion point, or <code>-1</code>
* @param imports <code>true</code> if the import edits should be applied, <code>false</code> otherwise
* @param apply <code>true</code> if the resulting edit should be applied, <code>false</code> otherwise
* @param save <code>true</code> if the changed compilation unit should be saved, <code>false</code> otherwise
* @param formatSettings The settings map to use for formatting with the default code formatter. Recognized options are documented on {@link JavaCore#getDefaultOptions()}. If set to <code>null</code>, then use the current project settings {@link IJavaProject#getOptions(boolean)}.
*/
public AddUnimplementedConstructorsOperation(CompilationUnit astRoot, ITypeBinding type, IMethodBinding[] constructorsToImplement, int insertPos, final boolean imports, final boolean apply, final boolean save, Map<String, String> formatSettings) {
if (astRoot == null || !(astRoot.getJavaElement() instanceof ICompilationUnit)) {
throw new IllegalArgumentException("AST must not be null and has to be created from a ICompilationUnit"); //$NON-NLS-1$
}
if (type == null) {
throw new IllegalArgumentException("The type must not be null"); //$NON-NLS-1$
}
ASTNode node= astRoot.findDeclaringNode(type);
if (!(node instanceof AnonymousClassDeclaration) && !(node instanceof AbstractTypeDeclaration)) {
throw new IllegalArgumentException("type has to map to a type declaration in the AST"); //$NON-NLS-1$
}
fType= type;
fInsertPos= insertPos;
fASTRoot= astRoot;
fConstructorsToImplement= constructorsToImplement;
fSave= save;
fApply= apply;
fImports= imports;
fCreateComments= StubUtility.doAddComments(astRoot.getJavaElement().getJavaProject());
fVisibility= Modifier.PUBLIC;
fOmitSuper= false;
fFormatSettings= formatSettings;
}
/**
* Returns the method binding keys for which a constructor has been generated.
*
* @return the method binding keys
*/
public String[] getCreatedConstructors() {
final String[] keys= new String[fCreatedMethods.size()];
fCreatedMethods.toArray(keys);
return keys;
}
/**
* Returns the qualified names of the generated imports.
*
* @return the generated imports
*/
public String[] getCreatedImports() {
return fCreatedImports;
}
/**
* Returns the scheduling rule for this operation.
*
* @return the scheduling rule
*/
public ISchedulingRule getSchedulingRule() {
return ResourcesPlugin.getWorkspace().getRoot();
}
/**
* Returns the resulting text edit.
*
* @return the resulting text edit
*/
public TextEdit getResultingEdit() {
return fResultingEdit;
}
/**
* Returns the visibility of the constructors.
*
* @return the visibility
*/
public int getVisibility() {
return fVisibility;
}
/**
* Returns whether the super call should be omitted.
*
* @return <code>true</code> to omit the super call, <code>false</code> otherwise
*/
public boolean isOmitSuper() {
return fOmitSuper;
}
/**
* Determines whether to create comments.
* @param comments <code>true</code> to create comments, <code>false</code> otherwise
*/
public void setCreateComments(final boolean comments) {
fCreateComments= comments;
}
/*
* @see org.eclipse.core.resources.IWorkspaceRunnable#run(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public void run(IProgressMonitor monitor) throws CoreException {
if (monitor == null)
monitor= new NullProgressMonitor();
try {
monitor.beginTask("", 2); //$NON-NLS-1$
monitor.setTaskName(CodeGenerationMessages.AddUnimplementedMethodsOperation_description);
fCreatedMethods.clear();
ICompilationUnit cu= (ICompilationUnit) fASTRoot.getJavaElement();
AST ast= fASTRoot.getAST();
ASTRewrite astRewrite= ASTRewrite.create(ast);
ImportRewrite importRewrite= StubUtility.createImportRewrite(fASTRoot, true);
ITypeBinding currTypeBinding= fType;
ListRewrite memberRewriter= null;
ASTNode node= fASTRoot.findDeclaringNode(currTypeBinding);
if (node instanceof AnonymousClassDeclaration) {
memberRewriter= astRewrite.getListRewrite(node, AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY);
} else if (node instanceof AbstractTypeDeclaration) {
ChildListPropertyDescriptor property= ((AbstractTypeDeclaration) node).getBodyDeclarationsProperty();
memberRewriter= astRewrite.getListRewrite(node, property);
} else {
throw new IllegalArgumentException();
// not possible, we checked this in the constructor
}
final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu);
settings.createComments= fCreateComments;
ASTNode insertion= getNodeToInsertBefore(memberRewriter);
IMethodBinding[] toImplement= fConstructorsToImplement;
if (toImplement == null) {
toImplement= StubUtility2Core.getVisibleConstructors(currTypeBinding, true, true);
}
int deprecationCount= 0;
for (IMethodBinding curr : toImplement) {
if (curr.isDeprecated()) {
deprecationCount++;
}
}
boolean createDeprecated= deprecationCount == toImplement.length;
for (IMethodBinding curr : toImplement) {
if (!curr.isDeprecated() || createDeprecated) {
ImportRewriteContext context= new ContextSensitiveImportRewriteContext(node, importRewrite);
MethodDeclaration stub= StubUtility2Core.createConstructorStub(cu, astRewrite, importRewrite, context, curr, currTypeBinding.getName(), fVisibility, fOmitSuper, true, settings, fFormatSettings);
if (stub != null) {
fCreatedMethods.add(curr.getKey());
if (insertion != null)
memberRewriter.insertBefore(stub, insertion, null);
else
memberRewriter.insertLast(stub, null);
}
}
}
fResultingEdit= new MultiTextEdit();
TextEdit importEdits= importRewrite.rewriteImports(Progress.subMonitor(monitor, 1));
fCreatedImports= importRewrite.getCreatedImports();
if (fImports) {
fResultingEdit.addChild(importEdits);
}
fResultingEdit.addChild(astRewrite.rewriteAST());
if (fApply) {
JavaModelUtil.applyEdit(cu, fResultingEdit, fSave, Progress.subMonitor(monitor, 1));
}
} finally {
monitor.done();
}
}
/**
* Determines whether the super call should be omitted.
*
* @param omit <code>true</code> to omit the super call, <code>false</code> otherwise
*/
public void setOmitSuper(final boolean omit) {
fOmitSuper= omit;
}
/**
* Determines the visibility of the constructors.
*
* @param visibility the visibility
*/
public void setVisibility(final int visibility) {
fVisibility= visibility;
}
private ASTNode getNodeToInsertBefore(ListRewrite rewriter) {
if (fInsertPos != -1) {
List<?> members= rewriter.getOriginalList();
for (Object member : members) {
ASTNode curr= (ASTNode) member;
if (curr.getStartPosition() >= fInsertPos) {
return curr;
}
}
}
return null;
}
}