1 /*******************************************************************************
2  * Copyright (c) 2018, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Red Hat Inc. - copied and pared down to methods needed by jdt.core.manipulation
14  *     Microsoft Corporation - copied methods needed by jdt.core.manipulation
15  *******************************************************************************/
16 package org.eclipse.jdt.internal.corext.codemanipulation;
17 
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.EnumSet;
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 
26 import org.eclipse.core.runtime.Assert;
27 import org.eclipse.core.runtime.CoreException;
28 
29 import org.eclipse.text.edits.TextEditGroup;
30 
31 import org.eclipse.jdt.core.Flags;
32 import org.eclipse.jdt.core.ICompilationUnit;
33 import org.eclipse.jdt.core.IJavaElement;
34 import org.eclipse.jdt.core.IJavaProject;
35 import org.eclipse.jdt.core.IMember;
36 import org.eclipse.jdt.core.IMethod;
37 import org.eclipse.jdt.core.ISourceRange;
38 import org.eclipse.jdt.core.JavaCore;
39 import org.eclipse.jdt.core.JavaModelException;
40 import org.eclipse.jdt.core.dom.AST;
41 import org.eclipse.jdt.core.dom.ASTNode;
42 import org.eclipse.jdt.core.dom.ASTParser;
43 import org.eclipse.jdt.core.dom.Annotation;
44 import org.eclipse.jdt.core.dom.ArrayType;
45 import org.eclipse.jdt.core.dom.Assignment;
46 import org.eclipse.jdt.core.dom.Block;
47 import org.eclipse.jdt.core.dom.CompilationUnit;
48 import org.eclipse.jdt.core.dom.Dimension;
49 import org.eclipse.jdt.core.dom.Expression;
50 import org.eclipse.jdt.core.dom.FieldAccess;
51 import org.eclipse.jdt.core.dom.IAnnotationBinding;
52 import org.eclipse.jdt.core.dom.IExtendedModifier;
53 import org.eclipse.jdt.core.dom.IMethodBinding;
54 import org.eclipse.jdt.core.dom.IPackageBinding;
55 import org.eclipse.jdt.core.dom.ITypeBinding;
56 import org.eclipse.jdt.core.dom.IVariableBinding;
57 import org.eclipse.jdt.core.dom.Javadoc;
58 import org.eclipse.jdt.core.dom.MethodDeclaration;
59 import org.eclipse.jdt.core.dom.MethodInvocation;
60 import org.eclipse.jdt.core.dom.Modifier;
61 import org.eclipse.jdt.core.dom.Name;
62 import org.eclipse.jdt.core.dom.NodeFinder;
63 import org.eclipse.jdt.core.dom.PrimitiveType;
64 import org.eclipse.jdt.core.dom.ReturnStatement;
65 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
66 import org.eclipse.jdt.core.dom.Statement;
67 import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
68 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
69 import org.eclipse.jdt.core.dom.Type;
70 import org.eclipse.jdt.core.dom.TypeParameter;
71 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
72 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
73 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
74 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation;
75 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
76 import org.eclipse.jdt.core.manipulation.CodeGeneration;
77 
78 import org.eclipse.jdt.internal.core.manipulation.StubUtility;
79 import org.eclipse.jdt.internal.corext.codemanipulation.AddDelegateMethodsOperation.DelegateEntry;
80 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
81 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
82 import org.eclipse.jdt.internal.corext.dom.Bindings;
83 import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
84 import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
85 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
86 
87 /**
88  * Utilities for code generation based on AST rewrite.
89  *
90  * @since 1.10
91  */
92 public final class StubUtility2Core {
93 
94 	/* This method should work with all AST levels. */
createConstructorStub(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context, IMethodBinding binding, String type, int modifiers, boolean omitSuperForDefConst, boolean todo, CodeGenerationSettings settings, Map<String, String> formatSettings)95 	public static MethodDeclaration createConstructorStub(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context, IMethodBinding binding, String type, int modifiers, boolean omitSuperForDefConst, boolean todo, CodeGenerationSettings settings, Map<String, String> formatSettings) throws CoreException {
96 		AST ast= rewrite.getAST();
97 		MethodDeclaration decl= ast.newMethodDeclaration();
98 		decl.modifiers().addAll(ASTNodeFactory.newModifiers(ast, modifiers & ~Modifier.ABSTRACT & ~Modifier.NATIVE));
99 		decl.setName(ast.newSimpleName(type));
100 		decl.setConstructor(true);
101 
102 		StubUtility2Core.createTypeParameters(imports, context, ast, binding, decl);
103 
104 		List<SingleVariableDeclaration> parameters= StubUtility2Core.createParameters(unit.getJavaProject(), imports, context, ast, binding, null, decl);
105 
106 		StubUtility2Core.createThrownExceptions(decl, binding, imports, context, ast);
107 
108 		Block body= ast.newBlock();
109 		decl.setBody(body);
110 
111 		String delimiter= StubUtility.getLineDelimiterUsed(unit);
112 		String bodyStatement= ""; //$NON-NLS-1$
113 		if (!omitSuperForDefConst || !parameters.isEmpty()) {
114 			SuperConstructorInvocation invocation= ast.newSuperConstructorInvocation();
115 			SingleVariableDeclaration varDecl= null;
116 			for (Iterator<SingleVariableDeclaration> iterator= parameters.iterator(); iterator.hasNext();) {
117 				varDecl= iterator.next();
118 				invocation.arguments().add(ast.newSimpleName(varDecl.getName().getIdentifier()));
119 			}
120 			bodyStatement= ASTNodes.asFormattedString(invocation, 0, delimiter, formatSettings == null ? unit.getJavaProject().getOptions(true) : formatSettings);
121 		}
122 
123 		if (todo) {
124 			String placeHolder= CodeGeneration.getMethodBodyContent(unit, type, binding.getName(), true, bodyStatement, delimiter);
125 			if (placeHolder != null) {
126 				ReturnStatement todoNode= (ReturnStatement) rewrite.createStringPlaceholder(placeHolder, ASTNode.RETURN_STATEMENT);
127 				body.statements().add(todoNode);
128 			}
129 		} else {
130 			ReturnStatement statementNode= (ReturnStatement) rewrite.createStringPlaceholder(bodyStatement, ASTNode.RETURN_STATEMENT);
131 			body.statements().add(statementNode);
132 		}
133 
134 		if (settings != null && settings.createComments) {
135 			String string= CodeGeneration.getMethodComment(unit, type, decl, binding, delimiter);
136 			if (string != null) {
137 				Javadoc javadoc= (Javadoc) rewrite.createStringPlaceholder(string, ASTNode.JAVADOC);
138 				decl.setJavadoc(javadoc);
139 			}
140 		}
141 		return decl;
142 	}
143 
createConstructorStub(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context, ITypeBinding typeBinding, IMethodBinding superConstructor, IVariableBinding[] variableBindings, int modifiers, CodeGenerationSettings settings)144 	public static MethodDeclaration createConstructorStub(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context, ITypeBinding typeBinding, IMethodBinding superConstructor, IVariableBinding[] variableBindings, int modifiers, CodeGenerationSettings settings) throws CoreException {
145 		AST ast= rewrite.getAST();
146 
147 		MethodDeclaration decl= ast.newMethodDeclaration();
148 		decl.modifiers().addAll(ASTNodeFactory.newModifiers(ast, modifiers & ~Modifier.ABSTRACT & ~Modifier.NATIVE));
149 		decl.setName(ast.newSimpleName(typeBinding.getName()));
150 		decl.setConstructor(true);
151 
152 		List<SingleVariableDeclaration> parameters= decl.parameters();
153 		if (superConstructor != null) {
154 			createTypeParameters(imports, context, ast, superConstructor, decl);
155 
156 			createParameters(unit.getJavaProject(), imports, context, ast, superConstructor, null, decl);
157 
158 			createThrownExceptions(decl, superConstructor, imports, context, ast);
159 		}
160 
161 		Block body= ast.newBlock();
162 		decl.setBody(body);
163 
164 		String delimiter= StubUtility.getLineDelimiterUsed(unit);
165 
166 		if (superConstructor != null) {
167 			SuperConstructorInvocation invocation= ast.newSuperConstructorInvocation();
168 			SingleVariableDeclaration varDecl= null;
169 			for (Iterator<SingleVariableDeclaration> iterator= parameters.iterator(); iterator.hasNext();) {
170 				varDecl= iterator.next();
171 				invocation.arguments().add(ast.newSimpleName(varDecl.getName().getIdentifier()));
172 			}
173 			body.statements().add(invocation);
174 		}
175 
176 		List<String> prohibited= new ArrayList<>();
177 		for (SingleVariableDeclaration singleVariableDeclaration : parameters)
178 			prohibited.add(singleVariableDeclaration.getName().getIdentifier());
179 		String param= null;
180 		List<String> list= new ArrayList<>(prohibited);
181 		String[] excluded= null;
182 		for (IVariableBinding variableBinding : variableBindings) {
183 			SingleVariableDeclaration var= ast.newSingleVariableDeclaration();
184 			var.setType(imports.addImport(variableBinding.getType(), ast, context, TypeLocation.PARAMETER));
185 			excluded= new String[list.size()];
186 			list.toArray(excluded);
187 			param= suggestParameterName(unit, variableBinding, excluded);
188 			list.add(param);
189 			var.setName(ast.newSimpleName(param));
190 			parameters.add(var);
191 		}
192 
193 		list= new ArrayList<>(prohibited);
194 		for (IVariableBinding variableBinding : variableBindings) {
195 			excluded= new String[list.size()];
196 			list.toArray(excluded);
197 			final String paramName= suggestParameterName(unit, variableBinding, excluded);
198 			list.add(paramName);
199 			final String fieldName= variableBinding.getName();
200 			Expression expression= null;
201 			if (paramName.equals(fieldName) || settings.useKeywordThis) {
202 				FieldAccess access= ast.newFieldAccess();
203 				access.setExpression(ast.newThisExpression());
204 				access.setName(ast.newSimpleName(fieldName));
205 				expression= access;
206 			} else
207 				expression= ast.newSimpleName(fieldName);
208 			Assignment assignment= ast.newAssignment();
209 			assignment.setLeftHandSide(expression);
210 			assignment.setRightHandSide(ast.newSimpleName(paramName));
211 			assignment.setOperator(Assignment.Operator.ASSIGN);
212 			body.statements().add(ast.newExpressionStatement(assignment));
213 		}
214 
215 		if (settings != null && settings.createComments) {
216 			String string= CodeGeneration.getMethodComment(unit, typeBinding.getName(), decl, superConstructor, delimiter);
217 			if (string != null) {
218 				Javadoc javadoc= (Javadoc) rewrite.createStringPlaceholder(string, ASTNode.JAVADOC);
219 				decl.setJavadoc(javadoc);
220 			}
221 		}
222 		return decl;
223 	}
224 
createDelegationStub(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context, IMethodBinding delegate, IVariableBinding delegatingField, CodeGenerationSettings settings)225 	public static MethodDeclaration createDelegationStub(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context, IMethodBinding delegate, IVariableBinding delegatingField, CodeGenerationSettings settings) throws CoreException {
226 		Assert.isNotNull(delegate);
227 		Assert.isNotNull(delegatingField);
228 		Assert.isNotNull(settings);
229 
230 		AST ast= rewrite.getAST();
231 
232 		MethodDeclaration decl= ast.newMethodDeclaration();
233 		decl.modifiers().addAll(ASTNodeFactory.newModifiers(ast, delegate.getModifiers() & ~Modifier.DEFAULT & ~Modifier.SYNCHRONIZED & ~Modifier.ABSTRACT & ~Modifier.NATIVE));
234 
235 		decl.setName(ast.newSimpleName(delegate.getName()));
236 		decl.setConstructor(false);
237 
238 		createTypeParameters(imports, context, ast, delegate, decl);
239 
240 		decl.setReturnType2(imports.addImport(delegate.getReturnType(), ast, context, TypeLocation.RETURN_TYPE));
241 
242 		List<SingleVariableDeclaration> params= createParameters(unit.getJavaProject(), imports, context, ast, delegate, null, decl);
243 
244 		createThrownExceptions(decl, delegate, imports, context, ast);
245 
246 		Block body= ast.newBlock();
247 		decl.setBody(body);
248 
249 		String delimiter= StubUtility.getLineDelimiterUsed(unit);
250 
251 		Statement statement= null;
252 		MethodInvocation invocation= ast.newMethodInvocation();
253 		invocation.setName(ast.newSimpleName(delegate.getName()));
254 		List<Expression> arguments= invocation.arguments();
255 		for (SingleVariableDeclaration param : params)
256 			arguments.add(ast.newSimpleName(param.getName().getIdentifier()));
257 		if (settings.useKeywordThis) {
258 			FieldAccess access= ast.newFieldAccess();
259 			access.setExpression(ast.newThisExpression());
260 			access.setName(ast.newSimpleName(delegatingField.getName()));
261 			invocation.setExpression(access);
262 		} else
263 			invocation.setExpression(ast.newSimpleName(delegatingField.getName()));
264 		if (delegate.getReturnType().isPrimitive() && delegate.getReturnType().getName().equals("void")) {//$NON-NLS-1$
265 			statement= ast.newExpressionStatement(invocation);
266 		} else {
267 			ReturnStatement returnStatement= ast.newReturnStatement();
268 			returnStatement.setExpression(invocation);
269 			statement= returnStatement;
270 		}
271 		body.statements().add(statement);
272 
273 		ITypeBinding declaringType= delegatingField.getDeclaringClass();
274 		if (declaringType == null) { // can be null for
275 			return decl;
276 		}
277 
278 		String qualifiedName= declaringType.getQualifiedName();
279 		IPackageBinding packageBinding= declaringType.getPackage();
280 		if (packageBinding != null) {
281 			if (packageBinding.getName().length() > 0 && qualifiedName.startsWith(packageBinding.getName()))
282 				qualifiedName= qualifiedName.substring(packageBinding.getName().length());
283 		}
284 
285 		if (settings.createComments) {
286 			/*
287 			 * TODO: have API for delegate method comments This is an inlined
288 			 * version of
289 			 * {@link CodeGeneration#getMethodComment(ICompilationUnit, String, MethodDeclaration, IMethodBinding, String)}
290 			 */
291 			delegate= delegate.getMethodDeclaration();
292 			String declaringClassQualifiedName= delegate.getDeclaringClass().getQualifiedName();
293 			String linkToMethodName= delegate.getName();
294 			String[] parameterTypesQualifiedNames= StubUtility.getParameterTypeNamesForSeeTag(delegate);
295 			String string= StubUtility.getMethodComment(unit, qualifiedName, decl, delegate.isDeprecated(), linkToMethodName, declaringClassQualifiedName, parameterTypesQualifiedNames, true, delimiter);
296 			if (string != null) {
297 				Javadoc javadoc= (Javadoc) rewrite.createStringPlaceholder(string, ASTNode.JAVADOC);
298 				decl.setJavadoc(javadoc);
299 			}
300 		}
301 		return decl;
302 	}
303 
createImplementationStubCore(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context, IMethodBinding binding, ITypeBinding targetType, CodeGenerationSettings settings, boolean inInterface, ASTNode astNode, boolean snippetStringSupport)304 	public static MethodDeclaration createImplementationStubCore(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context,
305 			IMethodBinding binding, ITypeBinding targetType, CodeGenerationSettings settings, boolean inInterface,
306 			ASTNode astNode, boolean snippetStringSupport) throws CoreException {
307 		return createImplementationStubCore(unit, rewrite, imports, context, binding, null, targetType, settings,
308 				inInterface, astNode, snippetStringSupport);
309 	}
310 
createImplementationStubCore(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context, IMethodBinding binding, String[] parameterNames, ITypeBinding targetType, CodeGenerationSettings settings, boolean inInterface, ASTNode astNode, boolean snippetStringSupport)311 	public static MethodDeclaration createImplementationStubCore(ICompilationUnit unit, ASTRewrite rewrite, ImportRewrite imports, ImportRewriteContext context,
312 			IMethodBinding binding, String[] parameterNames, ITypeBinding targetType, CodeGenerationSettings settings, boolean inInterface, ASTNode astNode, boolean snippetStringSupport) throws CoreException {
313 		Assert.isNotNull(imports);
314 		Assert.isNotNull(rewrite);
315 
316 		AST ast= rewrite.getAST();
317 		String type= Bindings.getTypeQualifiedName(targetType);
318 
319 		IJavaProject javaProject= unit.getJavaProject();
320 		EnumSet<TypeLocation> nullnessDefault= null;
321 		if (astNode != null && JavaCore.ENABLED.equals(javaProject.getOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, true))) {
322 			nullnessDefault= RedundantNullnessTypeAnnotationsFilter.determineNonNullByDefaultLocations(astNode, RedundantNullnessTypeAnnotationsFilter.determineNonNullByDefaultNames(javaProject));
323 		}
324 
325 		MethodDeclaration decl= ast.newMethodDeclaration();
326 		decl.modifiers().addAll(StubUtility2Core.getImplementationModifiers(ast, binding, inInterface, imports, context, nullnessDefault));
327 
328 		decl.setName(ast.newSimpleName(binding.getName()));
329 		decl.setConstructor(false);
330 
331 		ITypeBinding bindingReturnType= binding.getReturnType();
332 		bindingReturnType= StubUtility2Core.replaceWildcardsAndCaptures(bindingReturnType);
333 
334 		if (JavaModelUtil.is50OrHigher(javaProject)) {
335 			StubUtility2Core.createTypeParameters(imports, context, ast, binding, decl);
336 
337 		} else {
338 			bindingReturnType= bindingReturnType.getErasure();
339 		}
340 
341 		decl.setReturnType2(imports.addImport(bindingReturnType, ast, context, TypeLocation.RETURN_TYPE));
342 
343 		List<SingleVariableDeclaration> parameters= StubUtility2Core.createParameters(javaProject, imports, context, ast, binding, parameterNames, decl, nullnessDefault);
344 
345 		StubUtility2Core.createThrownExceptions(decl, binding, imports, context, ast);
346 
347 		String delimiter= unit.findRecommendedLineSeparator();
348 		int modifiers= binding.getModifiers();
349 		ITypeBinding declaringType= binding.getDeclaringClass();
350 		ITypeBinding typeObject= ast.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
351 		if (!inInterface || (declaringType != typeObject && JavaModelUtil.is18OrHigher(javaProject))) {
352 			// generate a method body
353 
354 			Map<String, String> options= javaProject.getOptions(true);
355 
356 			Block body= ast.newBlock();
357 			decl.setBody(body);
358 
359 			String bodyStatement= ""; //$NON-NLS-1$
360 			if (Modifier.isAbstract(modifiers)) {
361 				Expression expression= ASTNodeFactory.newDefaultExpression(ast, decl.getReturnType2(), decl.getExtraDimensions());
362 				if (expression != null) {
363 					ReturnStatement returnStatement= ast.newReturnStatement();
364 					returnStatement.setExpression(expression);
365 					bodyStatement= ASTNodes.asFormattedString(returnStatement, 0, delimiter, options);
366 				}
367 			} else {
368 				SuperMethodInvocation invocation= ast.newSuperMethodInvocation();
369 				if (declaringType.isInterface()) {
370 					ITypeBinding supertype= Bindings.findImmediateSuperTypeInHierarchy(targetType, declaringType.getTypeDeclaration().getQualifiedName());
371 					if (supertype == null) { // should not happen, but better use the type we have rather than failing
372 						supertype= declaringType;
373 					}
374 					if (supertype.isInterface()) {
375 						String qualifier= imports.addImport(supertype.getTypeDeclaration(), context);
376 						Name name= ASTNodeFactory.newName(ast, qualifier);
377 						invocation.setQualifier(name);
378 					}
379 				}
380 				invocation.setName(ast.newSimpleName(binding.getName()));
381 
382 				for (SingleVariableDeclaration varDecl : parameters) {
383 					invocation.arguments().add(ast.newSimpleName(varDecl.getName().getIdentifier()));
384 				}
385 				Expression expression= invocation;
386 				Type returnType= decl.getReturnType2();
387 				if (returnType instanceof PrimitiveType && ((PrimitiveType) returnType).getPrimitiveTypeCode().equals(PrimitiveType.VOID)) {
388 					bodyStatement= ASTNodes.asFormattedString(ast.newExpressionStatement(expression), 0, delimiter, options);
389 				} else {
390 					ReturnStatement returnStatement= ast.newReturnStatement();
391 					returnStatement.setExpression(expression);
392 					bodyStatement= ASTNodes.asFormattedString(returnStatement, 0, delimiter, options);
393 				}
394 			}
395 
396 			if (bodyStatement != null) {
397 				StringBuilder placeHolder= new StringBuilder();
398 				if (snippetStringSupport) {
399 					final String ESCAPE_DOLLAR= "\\\\\\$"; //$NON-NLS-1$
400 					final String DOLLAR= "\\$"; //$NON-NLS-1$
401 					bodyStatement= bodyStatement.replaceAll(DOLLAR, ESCAPE_DOLLAR);
402 				}
403 				String bodyContent= CodeGeneration.getMethodBodyContent(unit, type, binding.getName(), false, bodyStatement, delimiter);
404 
405 				if (snippetStringSupport) {
406 					placeHolder.append("${0"); //$NON-NLS-1$
407 					if (bodyContent != null) {
408 						placeHolder.append(":"); //$NON-NLS-1$
409 						placeHolder.append(bodyContent);
410 					}
411 					placeHolder.append("}"); //$NON-NLS-1$
412 				} else {
413 					if (bodyContent != null) {
414 						placeHolder.append(bodyContent);
415 					}
416 				}
417 
418 				if (bodyContent != null || snippetStringSupport) {
419 					ReturnStatement todoNode= (ReturnStatement) rewrite.createStringPlaceholder(placeHolder.toString(), ASTNode.RETURN_STATEMENT);
420 					body.statements().add(todoNode);
421 				}
422 			}
423 		}
424 
425 		if (settings != null && settings.createComments) {
426 			String string= CodeGeneration.getMethodComment(unit, type, decl, binding, delimiter);
427 			if (string != null) {
428 				Javadoc javadoc= (Javadoc) rewrite.createStringPlaceholder(string, ASTNode.JAVADOC);
429 				decl.setJavadoc(javadoc);
430 			}
431 		}
432 
433 		// According to JLS8 9.2, an interface doesn't implicitly declare non-public members of Object,
434 		// and JLS8 9.6.4.4 doesn't allow @Override for these methods (clone and finalize).
435 		boolean skipOverride= inInterface && declaringType == typeObject && !Modifier.isPublic(modifiers);
436 
437 		if (!skipOverride) {
438 			StubUtility2Core.addOverrideAnnotation(settings, javaProject, rewrite, imports, decl, binding.getDeclaringClass().isInterface(), null);
439 		}
440 		return decl;
441 	}
442 
createTypeParameters(ImportRewrite imports, ImportRewriteContext context, AST ast, IMethodBinding binding, MethodDeclaration decl)443 	public static void createTypeParameters(ImportRewrite imports, ImportRewriteContext context, AST ast, IMethodBinding binding, MethodDeclaration decl) {
444 		List<TypeParameter> typeParameters= decl.typeParameters();
445 		for (ITypeBinding curr : binding.getTypeParameters()) {
446 			TypeParameter newTypeParam= ast.newTypeParameter();
447 			newTypeParam.setName(ast.newSimpleName(curr.getName()));
448 			ITypeBinding[] typeBounds= curr.getTypeBounds();
449 			if (typeBounds.length != 1 || !"java.lang.Object".equals(typeBounds[0].getQualifiedName())) { //$NON-NLS-1$
450 				List<Type> newTypeBounds= newTypeParam.typeBounds();
451 				for (ITypeBinding typeBound : typeBounds) {
452 					newTypeBounds.add(imports.addImport(typeBound, ast, context, TypeLocation.TYPE_BOUND));
453 				}
454 			}
455 			typeParameters.add(newTypeParam);
456 		}
457 	}
458 
createParameters(IJavaProject project, ImportRewrite imports, ImportRewriteContext context, AST ast, IMethodBinding binding, String[] paramNames, MethodDeclaration decl)459 	public static List<SingleVariableDeclaration> createParameters(IJavaProject project, ImportRewrite imports, ImportRewriteContext context, AST ast, IMethodBinding binding, String[] paramNames, MethodDeclaration decl) {
460 		return createParameters(project, imports, context, ast, binding, paramNames, decl, null);
461 	}
createParameters(IJavaProject project, ImportRewrite imports, ImportRewriteContext context, AST ast, IMethodBinding binding, String[] paramNames, MethodDeclaration decl, EnumSet<TypeLocation> nullnessDefault)462 	public static List<SingleVariableDeclaration> createParameters(IJavaProject project, ImportRewrite imports, ImportRewriteContext context, AST ast,
463 			IMethodBinding binding, String[] paramNames, MethodDeclaration decl, EnumSet<TypeLocation> nullnessDefault) {
464 		boolean is50OrHigher= JavaModelUtil.is50OrHigher(project);
465 		List<SingleVariableDeclaration> parameters= decl.parameters();
466 		ITypeBinding[] params= binding.getParameterTypes();
467 		if (paramNames == null || paramNames.length < params.length) {
468 			paramNames= StubUtility.suggestArgumentNames(project, binding);
469 		}
470 		for (int i= 0; i < params.length; i++) {
471 			SingleVariableDeclaration var= ast.newSingleVariableDeclaration();
472 			ITypeBinding type= params[i];
473 			type=replaceWildcardsAndCaptures(type);
474 			if (!is50OrHigher) {
475 				type= type.getErasure();
476 				var.setType(imports.addImport(type, ast, context, TypeLocation.PARAMETER));
477 			} else if (binding.isVarargs() && type.isArray() && i == params.length - 1) {
478 				var.setVarargs(true);
479 				/*
480 				 * Varargs annotations are special.
481 				 * Example:
482 				 *     foo(@O Object @A [] @B ... arg)
483 				 * => @B is not an annotation on the array dimension that constitutes the vararg.
484 				 * It's the type annotation of the *innermost* array dimension.
485 				 */
486 				int dimensions= type.getDimensions();
487 				@SuppressWarnings("unchecked")
488 				List<Annotation>[] dimensionAnnotations= (List<Annotation>[]) new List<?>[dimensions];
489 				for (int dim= 0; dim < dimensions; dim++) {
490 					dimensionAnnotations[dim]= new ArrayList<>();
491 					for (IAnnotationBinding annotation : type.getTypeAnnotations()) {
492 						dimensionAnnotations[dim].add(imports.addAnnotation(annotation, ast, context));
493 					}
494 					type= type.getComponentType();
495 				}
496 
497 				Type elementType= imports.addImport(type, ast, context);
498 				if (dimensions == 1) {
499 					var.setType(elementType);
500 				} else {
501 					ArrayType arrayType= ast.newArrayType(elementType, dimensions - 1);
502 					List<Dimension> dimensionNodes= arrayType.dimensions();
503 					for (int dim= 0; dim < dimensions - 1; dim++) { // all except the innermost dimension
504 						Dimension dimension= dimensionNodes.get(dim);
505 						dimension.annotations().addAll(dimensionAnnotations[dim]);
506 					}
507 					var.setType(arrayType);
508 				}
509 				List<Annotation> varargTypeAnnotations= dimensionAnnotations[dimensions - 1];
510 				var.varargsAnnotations().addAll(varargTypeAnnotations);
511 			} else {
512 				var.setType(imports.addImport(type, ast, context, TypeLocation.PARAMETER));
513 			}
514 			var.setName(ast.newSimpleName(paramNames[i]));
515 			IAnnotationBinding[] annotations= binding.getParameterAnnotations(i);
516 			for (IAnnotationBinding annotation : annotations) {
517 				if (StubUtility2Core.isCopyOnInheritAnnotation(annotation.getAnnotationType(), project, nullnessDefault, TypeLocation.PARAMETER))
518 					var.modifiers().add(imports.addAnnotation(annotation, ast, context));
519 			}
520 			parameters.add(var);
521 		}
522 		return parameters;
523 	}
524 
createThrownExceptions(MethodDeclaration decl, IMethodBinding method, ImportRewrite imports, ImportRewriteContext context, AST ast)525 	public static void createThrownExceptions(MethodDeclaration decl, IMethodBinding method, ImportRewrite imports, ImportRewriteContext context, AST ast) {
526 		ITypeBinding[] excTypes= method.getExceptionTypes();
527 		if (ast.apiLevel() >= AST.JLS8) {
528 			List<Type> thrownExceptions= decl.thrownExceptionTypes();
529 			for (ITypeBinding t : excTypes) {
530 				Type excType= imports.addImport(t, ast, context, TypeLocation.EXCEPTION);
531 				thrownExceptions.add(excType);
532 			}
533 		} else {
534 			List<Name> thrownExceptions= getThrownExceptions(decl);
535 			for (ITypeBinding excType : excTypes) {
536 				String excTypeName= imports.addImport(excType, context);
537 				thrownExceptions.add(ASTNodeFactory.newName(ast, excTypeName));
538 			}
539 		}
540 	}
541 
542 	/**
543 	 * @param decl method declaration
544 	 * @return thrown exception names
545 	 * @deprecated to avoid deprecation warnings
546 	 */
547 	@Deprecated
getThrownExceptions(MethodDeclaration decl)548 	private static List<Name> getThrownExceptions(MethodDeclaration decl) {
549 		return decl.thrownExceptions();
550 	}
551 
findMethodBinding(IMethodBinding method, List<IMethodBinding> allMethods)552 	private static IMethodBinding findMethodBinding(IMethodBinding method, List<IMethodBinding> allMethods) {
553 		for (IMethodBinding curr : allMethods) {
554 			if (Bindings.isSubsignature(method, curr)) {
555 				return curr;
556 			}
557 		}
558 		return null;
559 	}
560 
findOverridingMethod(IMethodBinding method, List<IMethodBinding> allMethods)561 	private static IMethodBinding findOverridingMethod(IMethodBinding method, List<IMethodBinding> allMethods) {
562 		for (IMethodBinding curr : allMethods) {
563 			if (Bindings.areOverriddenMethods(curr, method) || Bindings.isSubsignature(curr, method))
564 				return curr;
565 		}
566 		return null;
567 	}
568 
findUnimplementedInterfaceMethods(ITypeBinding typeBinding, HashSet<ITypeBinding> visited, ArrayList<IMethodBinding> allMethods, IPackageBinding currPack, ArrayList<IMethodBinding> toImplement)569 	private static void findUnimplementedInterfaceMethods(ITypeBinding typeBinding, HashSet<ITypeBinding> visited,
570 			ArrayList<IMethodBinding> allMethods, IPackageBinding currPack, ArrayList<IMethodBinding> toImplement) {
571 
572 		if (visited.add(typeBinding)) {
573 			nextMethod: for (IMethodBinding curr : typeBinding.getDeclaredMethods()) {
574 				for (Iterator<IMethodBinding> allIter= allMethods.iterator(); allIter.hasNext();) {
575 					IMethodBinding oneMethod= allIter.next();
576 					if (Bindings.isSubsignature(oneMethod, curr)) {
577 						// We've already seen a method that is a subsignature of curr.
578 						if (!Bindings.isSubsignature(curr, oneMethod)) {
579 							// oneMethod is a true subsignature of curr; let's go with oneMethod
580 							continue nextMethod;
581 						}
582 						// Subsignatures are equivalent.
583 						// Check visibility and return types ('getErasure()' tries to achieve effect of "rename type variables")
584 						if (Bindings.isVisibleInHierarchy(oneMethod, currPack)
585 							&& oneMethod.getReturnType().getErasure().isSubTypeCompatible(curr.getReturnType().getErasure())) {
586 							// oneMethod is visible and curr doesn't have a stricter return type; let's go with oneMethod
587 							continue nextMethod;
588 						}
589 						// curr is stricter than oneMethod, so let's remove oneMethod
590 						allIter.remove();
591 						toImplement.remove(oneMethod);
592 					} else if (Bindings.isSubsignature(curr, oneMethod)) {
593 						// curr is a true subsignature of oneMethod. Let's remove oneMethod.
594 						allIter.remove();
595 						toImplement.remove(oneMethod);
596 					}
597 				}
598 				int modifiers= curr.getModifiers();
599 				if (!Modifier.isStatic(modifiers)) {
600 					allMethods.add(curr);
601 					if (Modifier.isAbstract(modifiers)) {
602 						toImplement.add(curr);
603 					}
604 				}
605 			}
606 			for (ITypeBinding superInterface : typeBinding.getInterfaces()) {
607 				findUnimplementedInterfaceMethods(superInterface, visited, allMethods, currPack, toImplement);
608 			}
609 		}
610 	}
611 
getImplementationModifiers(AST ast, IMethodBinding method, boolean inInterface, ImportRewrite importRewrite, ImportRewriteContext context, EnumSet<TypeLocation> nullnessDefault)612 	public static List<IExtendedModifier> getImplementationModifiers(AST ast, IMethodBinding method, boolean inInterface, ImportRewrite importRewrite, ImportRewriteContext context, EnumSet<TypeLocation> nullnessDefault) throws JavaModelException {
613 		IJavaProject javaProject= importRewrite.getCompilationUnit().getJavaProject();
614 		int modifiers= method.getModifiers();
615 		if (inInterface) {
616 			modifiers= modifiers & ~Modifier.PROTECTED & ~Modifier.PUBLIC;
617 			if (Modifier.isAbstract(modifiers) && JavaModelUtil.is18OrHigher(javaProject)) {
618 				modifiers= modifiers | Modifier.DEFAULT;
619 			}
620 		} else {
621 			modifiers= modifiers & ~Modifier.DEFAULT;
622 		}
623 		modifiers= modifiers & ~Modifier.ABSTRACT & ~Modifier.NATIVE & ~Modifier.PRIVATE;
624 		IAnnotationBinding[] annotations= method.getAnnotations();
625 
626 		if (modifiers != Modifier.NONE && annotations.length > 0) {
627 			// need an AST of the source method to preserve order of modifiers
628 			IMethod iMethod= (IMethod) method.getJavaElement();
629 			if (iMethod != null && JavaElementUtil.isSourceAvailable(iMethod)) {
630 				ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL);
631 				parser.setSource(iMethod.getTypeRoot());
632 				parser.setIgnoreMethodBodies(true);
633 				CompilationUnit otherCU= (CompilationUnit) parser.createAST(null);
634 				ASTNode otherMethod= NodeFinder.perform(otherCU, iMethod.getSourceRange());
635 				if (otherMethod instanceof MethodDeclaration) {
636 					MethodDeclaration otherMD= (MethodDeclaration) otherMethod;
637 					ArrayList<IExtendedModifier> result= new ArrayList<>();
638 					List<IExtendedModifier> otherModifiers= otherMD.modifiers();
639 					for (IExtendedModifier otherModifier : otherModifiers) {
640 						if (otherModifier instanceof Modifier) {
641 							int otherFlag= ((Modifier) otherModifier).getKeyword().toFlagValue();
642 							if ((otherFlag & modifiers) != 0) {
643 								modifiers= ~otherFlag & modifiers;
644 								result.addAll(ast.newModifiers(otherFlag));
645 							}
646 						} else {
647 							Annotation otherAnnotation= (Annotation) otherModifier;
648 							String n= otherAnnotation.getTypeName().getFullyQualifiedName();
649 							for (IAnnotationBinding annotation : annotations) {
650 								ITypeBinding otherAnnotationType= annotation.getAnnotationType();
651 								String qn= otherAnnotationType.getQualifiedName();
652 								if (qn.endsWith(n) && (qn.length() == n.length() || qn.charAt(qn.length() - n.length() - 1) == '.')) {
653 									if (StubUtility2Core.isCopyOnInheritAnnotation(otherAnnotationType, javaProject, nullnessDefault, TypeLocation.RETURN_TYPE))
654 										result.add(importRewrite.addAnnotation(annotation, ast, context));
655 									break;
656 								}
657 							}
658 						}
659 					}
660 					result.addAll(ASTNodeFactory.newModifiers(ast, modifiers));
661 					return result;
662 				}
663 			}
664 		}
665 
666 		ArrayList<IExtendedModifier> result= new ArrayList<>();
667 
668 		for (IAnnotationBinding annotation : annotations) {
669 			if (StubUtility2Core.isCopyOnInheritAnnotation(annotation.getAnnotationType(), javaProject, nullnessDefault, TypeLocation.RETURN_TYPE))
670 				result.add(importRewrite.addAnnotation(annotation, ast, context));
671 		}
672 
673 		result.addAll(ASTNodeFactory.newModifiers(ast, modifiers));
674 
675 		return result;
676 	}
677 
getDelegatableMethods(ITypeBinding binding)678 	public static DelegateEntry[] getDelegatableMethods(ITypeBinding binding) {
679 		final List<DelegateEntry> tuples= new ArrayList<>();
680 		final List<IMethodBinding> declared= new ArrayList<>();
681 		IMethodBinding[] typeMethods= binding.getDeclaredMethods();
682 		declared.addAll(Arrays.asList(typeMethods));
683 		for (IVariableBinding fieldBinding : binding.getDeclaredFields()) {
684 			if (fieldBinding.isField() && !fieldBinding.isEnumConstant() && !fieldBinding.isSynthetic())
685 				getDelegatableMethods(new ArrayList<>(declared), fieldBinding, fieldBinding.getType(), binding, tuples);
686 		}
687 		// list of tuple<IVariableBinding, IMethodBinding>
688 		return tuples.toArray(new DelegateEntry[tuples.size()]);
689 	}
690 
getDelegatableMethods(List<IMethodBinding> methods, IVariableBinding fieldBinding, ITypeBinding typeBinding, ITypeBinding binding, List<DelegateEntry> result)691 	private static void getDelegatableMethods(List<IMethodBinding> methods, IVariableBinding fieldBinding, ITypeBinding typeBinding, ITypeBinding binding, List<DelegateEntry> result) {
692 		boolean match= false;
693 		if (typeBinding.isTypeVariable()) {
694 			ITypeBinding[] typeBounds= typeBinding.getTypeBounds();
695 			if (typeBounds.length > 0) {
696 				for (ITypeBinding typeBound : typeBounds) {
697 					getDelegatableMethods(methods, fieldBinding, typeBound, binding, result);
698 				}
699 			} else {
700 				ITypeBinding objectBinding= Bindings.findTypeInHierarchy(binding, "java.lang.Object"); //$NON-NLS-1$
701 				if (objectBinding != null) {
702 					getDelegatableMethods(methods, fieldBinding, objectBinding, binding, result);
703 				}
704 			}
705 		} else {
706 			for (IMethodBinding candidate : getDelegateCandidates(typeBinding, binding)) {
707 				match= false;
708 				final IMethodBinding methodBinding= candidate;
709 				for (int offset= 0; offset < methods.size() && !match; offset++) {
710 					if (Bindings.areOverriddenMethods(methods.get(offset), methodBinding))
711 						match= true;
712 				}
713 				if (!match) {
714 					result.add(new DelegateEntry(methodBinding, fieldBinding));
715 					methods.add(methodBinding);
716 				}
717 			}
718 			final ITypeBinding superclass= typeBinding.getSuperclass();
719 			if (superclass != null)
720 				getDelegatableMethods(methods, fieldBinding, superclass, binding, result);
721 			for (ITypeBinding superInterface : typeBinding.getInterfaces()) {
722 				getDelegatableMethods(methods, fieldBinding, superInterface, binding, result);
723 			}
724 		}
725 	}
726 
getDelegateCandidates(ITypeBinding binding, ITypeBinding hierarchy)727 	private static IMethodBinding[] getDelegateCandidates(ITypeBinding binding, ITypeBinding hierarchy) {
728 		List<IMethodBinding> allMethods= new ArrayList<>();
729 		boolean isInterface= binding.isInterface();
730 		for (IMethodBinding typeMethod : binding.getDeclaredMethods()) {
731 			final int modifiers= typeMethod.getModifiers();
732 			if (!typeMethod.isConstructor() && !Modifier.isStatic(modifiers) && (isInterface || Modifier.isPublic(modifiers))) {
733 				IMethodBinding result= Bindings.findOverriddenMethodInHierarchy(hierarchy, typeMethod);
734 				if (result != null && Flags.isFinal(result.getModifiers()))
735 					continue;
736 				ITypeBinding[] parameterBindings= typeMethod.getParameterTypes();
737 				boolean upper= false;
738 				for (ITypeBinding parameterBinding : parameterBindings) {
739 					if (parameterBinding.isWildcardType() && parameterBinding.isUpperbound()) {
740 						upper= true;
741 					}
742 				}
743 				if (!upper) {
744 					allMethods.add(typeMethod);
745 				}
746 			}
747 		}
748 		return allMethods.toArray(new IMethodBinding[allMethods.size()]);
749 	}
750 
getOverridableMethods(AST ast, ITypeBinding typeBinding, boolean isSubType)751 	public static IMethodBinding[] getOverridableMethods(AST ast, ITypeBinding typeBinding, boolean isSubType) {
752 		List<IMethodBinding> allMethods= new ArrayList<>();
753 		IMethodBinding[] typeMethods= typeBinding.getDeclaredMethods();
754 		for (IMethodBinding typeMethod : typeMethods) {
755 			final int modifiers= typeMethod.getModifiers();
756 			if (!typeMethod.isConstructor() && !Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers)) {
757 				allMethods.add(typeMethod);
758 			}
759 		}
760 		ITypeBinding clazz= typeBinding.getSuperclass();
761 		while (clazz != null) {
762 			for (IMethodBinding method : clazz.getDeclaredMethods()) {
763 				final int modifiers= method.getModifiers();
764 				if (!method.isConstructor() && !Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers)) {
765 					if (findOverridingMethod(method, allMethods) == null) {
766 						allMethods.add(method);
767 					}
768 				}
769 			}
770 			clazz= clazz.getSuperclass();
771 		}
772 		clazz= typeBinding;
773 		while (clazz != null) {
774 			for (ITypeBinding superInterface : clazz.getInterfaces()) {
775 				getOverridableMethods(ast, superInterface, allMethods);
776 			}
777 			clazz= clazz.getSuperclass();
778 		}
779 		if (typeBinding.isInterface())
780 			getOverridableMethods(ast, ast.resolveWellKnownType("java.lang.Object"), allMethods); //$NON-NLS-1$
781 		if (!isSubType)
782 			allMethods.removeAll(Arrays.asList(typeMethods));
783 		for (int index= allMethods.size() - 1; index >= 0; index--) {
784 			IMethodBinding method= allMethods.get(index);
785 			if (Modifier.isFinal(method.getModifiers()))
786 				allMethods.remove(index);
787 		}
788 		return allMethods.toArray(new IMethodBinding[allMethods.size()]);
789 	}
790 
getOverridableMethods(AST ast, ITypeBinding superBinding, List<IMethodBinding> allMethods)791 	private static void getOverridableMethods(AST ast, ITypeBinding superBinding, List<IMethodBinding> allMethods) {
792 		for (IMethodBinding method : superBinding.getDeclaredMethods()) {
793 			final int modifiers= method.getModifiers();
794 			if (!method.isConstructor() && !Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers)) {
795 				if (findOverridingMethod(method, allMethods) == null) {
796 					allMethods.add(method);
797 				}
798 			}
799 		}
800 		for (ITypeBinding superInterface : superBinding.getInterfaces()) {
801 			getOverridableMethods(ast, superInterface, allMethods);
802 		}
803 	}
804 
suggestParameterName(ICompilationUnit unit, IVariableBinding binding, String[] excluded)805 	private static String suggestParameterName(ICompilationUnit unit, IVariableBinding binding, String[] excluded) {
806 		String name= StubUtility.getBaseName(binding, unit.getJavaProject());
807 		return StubUtility.suggestArgumentName(unit.getJavaProject(), name, excluded);
808 	}
809 
getUnimplementedMethods(ITypeBinding typeBinding)810 	public static IMethodBinding[] getUnimplementedMethods(ITypeBinding typeBinding) {
811 		return getUnimplementedMethods(typeBinding, false);
812 	}
813 
getUnimplementedMethods(ITypeBinding typeBinding, boolean implementAbstractsOfInput)814 	public static IMethodBinding[] getUnimplementedMethods(ITypeBinding typeBinding, boolean implementAbstractsOfInput) {
815 		ArrayList<IMethodBinding> allMethods= new ArrayList<>();
816 		ArrayList<IMethodBinding> toImplement= new ArrayList<>();
817 
818 		for (IMethodBinding curr : typeBinding.getDeclaredMethods()) {
819 			int modifiers= curr.getModifiers();
820 			if (!curr.isConstructor() && !Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers)) {
821 				allMethods.add(curr);
822 			}
823 		}
824 
825 		ITypeBinding superClass= typeBinding.getSuperclass();
826 		while (superClass != null) {
827 			for (IMethodBinding curr : superClass.getDeclaredMethods()) {
828 				int modifiers= curr.getModifiers();
829 				if (!curr.isConstructor() && !Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers)) {
830 					if (findMethodBinding(curr, allMethods) == null) {
831 						allMethods.add(curr);
832 					}
833 				}
834 			}
835 			superClass= superClass.getSuperclass();
836 		}
837 
838 		for (IMethodBinding curr : allMethods) {
839 			int modifiers= curr.getModifiers();
840 			if ((Modifier.isAbstract(modifiers) || curr.getDeclaringClass().isInterface()) && (implementAbstractsOfInput || typeBinding != curr.getDeclaringClass())) {
841 				// implement all abstract methods
842 				toImplement.add(curr);
843 			}
844 		}
845 
846 		HashSet<ITypeBinding> visited= new HashSet<>();
847 		ITypeBinding curr= typeBinding;
848 		while (curr != null) {
849 			for (ITypeBinding superInterface : curr.getInterfaces()) {
850 				findUnimplementedInterfaceMethods(superInterface, visited, allMethods, typeBinding.getPackage(), toImplement);
851 			}
852 			curr= curr.getSuperclass();
853 		}
854 
855 		return toImplement.toArray(new IMethodBinding[toImplement.size()]);
856 	}
857 
getVisibleConstructors(ITypeBinding binding, boolean accountExisting, boolean proposeDefault)858 	public static IMethodBinding[] getVisibleConstructors(ITypeBinding binding, boolean accountExisting, boolean proposeDefault) {
859 		List<IMethodBinding> constructorMethods= new ArrayList<>();
860 		List<IMethodBinding> existingConstructors= null;
861 		ITypeBinding superType= binding.getSuperclass();
862 		if (superType == null)
863 			return new IMethodBinding[0];
864 		if (accountExisting) {
865 			IMethodBinding[] methods= binding.getDeclaredMethods();
866 			existingConstructors= new ArrayList<>(methods.length);
867 			for (IMethodBinding method : methods) {
868 				if (method.isConstructor() && !method.isDefaultConstructor())
869 					existingConstructors.add(method);
870 			}
871 		}
872 		if (existingConstructors != null)
873 			constructorMethods.addAll(existingConstructors);
874 		IMethodBinding[] methods= binding.getDeclaredMethods();
875 		for (IMethodBinding method : superType.getDeclaredMethods()) {
876 			if (method.isConstructor()) {
877 				if (Bindings.isVisibleInHierarchy(method, binding.getPackage()) && (!accountExisting || !Bindings.containsSignatureEquivalentConstructor(methods, method)))
878 					constructorMethods.add(method);
879 			}
880 		}
881 		if (existingConstructors != null)
882 			constructorMethods.removeAll(existingConstructors);
883 		if (constructorMethods.isEmpty()) {
884 			superType= binding;
885 			while (superType.getSuperclass() != null)
886 				superType= superType.getSuperclass();
887 			IMethodBinding method= Bindings.findMethodInType(superType, "Object", new ITypeBinding[0]); //$NON-NLS-1$
888 			if (method != null) {
889 				if ((proposeDefault || !accountExisting || existingConstructors == null || existingConstructors.isEmpty()) && (!accountExisting || !Bindings.containsSignatureEquivalentConstructor(methods, method)))
890 					constructorMethods.add(method);
891 			}
892 		}
893 		return constructorMethods.toArray(new IMethodBinding[constructorMethods.size()]);
894 	}
895 
896 
897 	/**
898 	 * Evaluates the insertion position of a new node.
899 	 *
900 	 * @param listRewrite The list rewriter to which the new node will be added
901 	 * @param sibling The Java element before which the new element should be added.
902 	 * @return the AST node of the list to insert before or null to insert as last.
903 	 * @throws JavaModelException thrown if accessing the Java element failed
904 	 */
905 
getNodeToInsertBefore(ListRewrite listRewrite, IJavaElement sibling)906 	public static ASTNode getNodeToInsertBefore(ListRewrite listRewrite, IJavaElement sibling) throws JavaModelException {
907 		if (sibling instanceof IMember) {
908 			ISourceRange sourceRange= ((IMember) sibling).getSourceRange();
909 			if (sourceRange == null) {
910 				return null;
911 			}
912 			int insertPos= sourceRange.getOffset();
913 
914 			for (ASTNode curr : (List<? extends ASTNode>)listRewrite.getOriginalList()) {
915 				if (curr.getStartPosition() >= insertPos) {
916 					return curr;
917 				}
918 			}
919 		}
920 		return null;
921 	}
922 
923 	/**
924 	 * Adds <code>@Override</code> annotation to <code>methodDecl</code> if not already present and
925 	 * if requested by code style settings or compiler errors/warnings settings.
926 	 *
927 	 * @param settings the code generation style settings, may be <code>null</code>
928 	 * @param project the Java project used to access the compiler settings
929 	 * @param rewrite the ASTRewrite
930 	 * @param imports the ImportRewrite
931 	 * @param methodDecl the method declaration to add the annotation to
932 	 * @param isDeclaringTypeInterface <code>true</code> if the type declaring the method overridden
933 	 *            by <code>methodDecl</code> is an interface
934 	 * @param group the text edit group, may be <code>null</code>
935 	 */
addOverrideAnnotation(CodeGenerationSettings settings, IJavaProject project, ASTRewrite rewrite, ImportRewrite imports, MethodDeclaration methodDecl, boolean isDeclaringTypeInterface, TextEditGroup group)936 	public static void addOverrideAnnotation(CodeGenerationSettings settings, IJavaProject project, ASTRewrite rewrite, ImportRewrite imports, MethodDeclaration methodDecl,
937 			boolean isDeclaringTypeInterface, TextEditGroup group) {
938 		if (!JavaModelUtil.is50OrHigher(project)) {
939 			return;
940 		}
941 		if (isDeclaringTypeInterface) {
942 			String version= project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
943 			if (JavaModelUtil.isVersionLessThan(version, JavaCore.VERSION_1_6))
944 				return; // not allowed in 1.5
945 			if (JavaCore.DISABLED.equals(project.getOption(JavaCore.COMPILER_PB_MISSING_OVERRIDE_ANNOTATION_FOR_INTERFACE_METHOD_IMPLEMENTATION, true)))
946 				return; // user doesn't want to use 1.6 style
947 		}
948 		if ((settings != null && settings.overrideAnnotation) || !JavaCore.IGNORE.equals(project.getOption(JavaCore.COMPILER_PB_MISSING_OVERRIDE_ANNOTATION, true))) {
949 			createOverrideAnnotation(rewrite, imports, methodDecl, group);
950 		}
951 	}
952 
createOverrideAnnotation(ASTRewrite rewrite, ImportRewrite imports, MethodDeclaration decl, TextEditGroup group)953 	public static void createOverrideAnnotation(ASTRewrite rewrite, ImportRewrite imports, MethodDeclaration decl, TextEditGroup group) {
954 		if (findAnnotation("java.lang.Override", decl.modifiers()) != null) { //$NON-NLS-1$
955 			return; // No need to add duplicate annotation
956 		}
957 		AST ast= rewrite.getAST();
958 		ASTNode root= decl.getRoot();
959 		ImportRewriteContext context= null;
960 		if (root instanceof CompilationUnit) {
961 			context= new ContextSensitiveImportRewriteContext((CompilationUnit) root, decl.getStartPosition(), imports);
962 		}
963 		Annotation marker= ast.newMarkerAnnotation();
964 		marker.setTypeName(ast.newName(imports.addImport("java.lang.Override", context))); //$NON-NLS-1$
965 		rewrite.getListRewrite(decl, MethodDeclaration.MODIFIERS2_PROPERTY).insertFirst(marker, group);
966 	}
967 
isCopyOnInheritAnnotation(ITypeBinding annotationType, IJavaProject project, EnumSet<TypeLocation> nullnessDefault, TypeLocation typeLocation)968 	public static boolean isCopyOnInheritAnnotation(ITypeBinding annotationType, IJavaProject project, EnumSet<TypeLocation> nullnessDefault, TypeLocation typeLocation) {
969 		if (JavaCore.ENABLED.equals(project.getOption(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, true)))
970 			return false;
971 		if (nullnessDefault != null && Bindings.isNonNullAnnotation(annotationType, project)) {
972 			if (!nullnessDefault.contains(typeLocation)) {
973 				return true;
974 			}
975 			return false; // nonnull within the scope of @NonNullByDefault: don't copy
976 		}
977 		return Bindings.isAnyNullAnnotation(annotationType, project);
978 	}
979 
findAnnotation(String qualifiedTypeName, List<IExtendedModifier> modifiers)980 	public static Annotation findAnnotation(String qualifiedTypeName, List<IExtendedModifier> modifiers) {
981 		for (IExtendedModifier curr : modifiers) {
982 			if (curr instanceof Annotation) {
983 				Annotation annot= (Annotation) curr;
984 				ITypeBinding binding= annot.getTypeName().resolveTypeBinding();
985 				if (binding != null && qualifiedTypeName.equals(binding.getQualifiedName())) {
986 					return annot;
987 				}
988 			}
989 		}
990 		return null;
991 	}
992 
replaceWildcardsAndCaptures(ITypeBinding type)993 	public static ITypeBinding replaceWildcardsAndCaptures(ITypeBinding type) {
994 		while (type.isWildcardType() || type.isCapture() || (type.isArray() && type.getElementType().isCapture())) {
995 			ITypeBinding bound = type.getBound();
996 			type = (bound != null) ? bound : type.getErasure();
997 		}
998 		return type;
999 	}
1000 
1001 	/**
1002 	 * Creates a new stub utility.
1003 	 */
StubUtility2Core()1004 	private StubUtility2Core() {
1005 		// Not for instantiation
1006 	}
1007 
1008 }
1009