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