1 /******************************************************************************* 2 * Copyright (c) 2000, 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 * Renaud Waldura <renaud+eclipse@waldura.com> - Access to static proposal 14 * Benjamin Muskalla <bmuskalla@innoopract.com> - [quick fix] Shouldn't offer "Add throws declaration" quickfix for overriding signature if result would conflict with overridden signature 15 * Lukas Hanke <hanke@yatta.de> - Bug 241696 [quick fix] quickfix to iterate over a collection - https://bugs.eclipse.org/bugs/show_bug.cgi?id=241696 16 * Sandra Lions <sandra.lions-piron@oracle.com> - [quick fix] for qualified enum constants in switch-case labels - https://bugs.eclipse.org/bugs/90140 17 * Stephan Herrmann - Contribution for Bug 463360 - [override method][null] generating method override should not create redundant null annotations 18 *******************************************************************************/ 19 package org.eclipse.jdt.internal.ui.text.correction; 20 21 import java.util.ArrayList; 22 import java.util.Arrays; 23 import java.util.Collection; 24 import java.util.HashMap; 25 import java.util.Hashtable; 26 import java.util.List; 27 import java.util.Map; 28 import java.util.stream.Collectors; 29 30 import org.eclipse.swt.graphics.Image; 31 32 import org.eclipse.core.runtime.CoreException; 33 import org.eclipse.core.runtime.IProgressMonitor; 34 35 import org.eclipse.core.resources.IFile; 36 37 import org.eclipse.text.edits.InsertEdit; 38 import org.eclipse.text.edits.TextEdit; 39 40 import org.eclipse.jface.viewers.StructuredSelection; 41 42 import org.eclipse.jface.text.IDocument; 43 44 import org.eclipse.ui.IEditorInput; 45 import org.eclipse.ui.IEditorPart; 46 import org.eclipse.ui.IEditorSite; 47 import org.eclipse.ui.ISharedImages; 48 import org.eclipse.ui.IWorkbenchPage; 49 import org.eclipse.ui.PlatformUI; 50 import org.eclipse.ui.part.FileEditorInput; 51 52 import org.eclipse.jdt.core.ICompilationUnit; 53 import org.eclipse.jdt.core.IJavaProject; 54 import org.eclipse.jdt.core.IMethod; 55 import org.eclipse.jdt.core.IType; 56 import org.eclipse.jdt.core.compiler.IProblem; 57 import org.eclipse.jdt.core.dom.AST; 58 import org.eclipse.jdt.core.dom.ASTNode; 59 import org.eclipse.jdt.core.dom.ASTParser; 60 import org.eclipse.jdt.core.dom.ASTVisitor; 61 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 62 import org.eclipse.jdt.core.dom.Annotation; 63 import org.eclipse.jdt.core.dom.ArrayType; 64 import org.eclipse.jdt.core.dom.Assignment; 65 import org.eclipse.jdt.core.dom.Block; 66 import org.eclipse.jdt.core.dom.BodyDeclaration; 67 import org.eclipse.jdt.core.dom.CastExpression; 68 import org.eclipse.jdt.core.dom.CatchClause; 69 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; 70 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 71 import org.eclipse.jdt.core.dom.CompilationUnit; 72 import org.eclipse.jdt.core.dom.ConditionalExpression; 73 import org.eclipse.jdt.core.dom.EmptyStatement; 74 import org.eclipse.jdt.core.dom.EnumDeclaration; 75 import org.eclipse.jdt.core.dom.Expression; 76 import org.eclipse.jdt.core.dom.ExpressionStatement; 77 import org.eclipse.jdt.core.dom.FieldAccess; 78 import org.eclipse.jdt.core.dom.ForStatement; 79 import org.eclipse.jdt.core.dom.IBinding; 80 import org.eclipse.jdt.core.dom.IMethodBinding; 81 import org.eclipse.jdt.core.dom.ITypeBinding; 82 import org.eclipse.jdt.core.dom.IVariableBinding; 83 import org.eclipse.jdt.core.dom.IfStatement; 84 import org.eclipse.jdt.core.dom.InfixExpression; 85 import org.eclipse.jdt.core.dom.Initializer; 86 import org.eclipse.jdt.core.dom.InstanceofExpression; 87 import org.eclipse.jdt.core.dom.LambdaExpression; 88 import org.eclipse.jdt.core.dom.MethodDeclaration; 89 import org.eclipse.jdt.core.dom.MethodInvocation; 90 import org.eclipse.jdt.core.dom.MethodReference; 91 import org.eclipse.jdt.core.dom.Modifier; 92 import org.eclipse.jdt.core.dom.Name; 93 import org.eclipse.jdt.core.dom.NameQualifiedType; 94 import org.eclipse.jdt.core.dom.NodeFinder; 95 import org.eclipse.jdt.core.dom.ParenthesizedExpression; 96 import org.eclipse.jdt.core.dom.PrefixExpression; 97 import org.eclipse.jdt.core.dom.PrimitiveType; 98 import org.eclipse.jdt.core.dom.ProvidesDirective; 99 import org.eclipse.jdt.core.dom.QualifiedName; 100 import org.eclipse.jdt.core.dom.ReturnStatement; 101 import org.eclipse.jdt.core.dom.SimpleName; 102 import org.eclipse.jdt.core.dom.SimpleType; 103 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 104 import org.eclipse.jdt.core.dom.Statement; 105 import org.eclipse.jdt.core.dom.StringLiteral; 106 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; 107 import org.eclipse.jdt.core.dom.SwitchCase; 108 import org.eclipse.jdt.core.dom.SwitchExpression; 109 import org.eclipse.jdt.core.dom.SwitchStatement; 110 import org.eclipse.jdt.core.dom.ThrowStatement; 111 import org.eclipse.jdt.core.dom.TryStatement; 112 import org.eclipse.jdt.core.dom.Type; 113 import org.eclipse.jdt.core.dom.TypeDeclaration; 114 import org.eclipse.jdt.core.dom.UnionType; 115 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 116 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 117 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 118 import org.eclipse.jdt.core.dom.WhileStatement; 119 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 120 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 121 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext; 122 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation; 123 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 124 125 import org.eclipse.jdt.internal.core.manipulation.StubUtility; 126 import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving; 127 import org.eclipse.jdt.internal.core.manipulation.dom.NecessaryParenthesesChecker; 128 import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels; 129 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings; 130 import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; 131 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2; 132 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; 133 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 134 import org.eclipse.jdt.internal.corext.dom.Bindings; 135 import org.eclipse.jdt.internal.corext.dom.BodyDeclarationRewrite; 136 import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder; 137 import org.eclipse.jdt.internal.corext.dom.IASTSharedValues; 138 import org.eclipse.jdt.internal.corext.dom.Selection; 139 import org.eclipse.jdt.internal.corext.dom.TypeRules; 140 import org.eclipse.jdt.internal.corext.fix.CleanUpConstants; 141 import org.eclipse.jdt.internal.corext.fix.CodeStyleFix; 142 import org.eclipse.jdt.internal.corext.fix.IProposableFix; 143 import org.eclipse.jdt.internal.corext.fix.Java50Fix; 144 import org.eclipse.jdt.internal.corext.fix.StringFix; 145 import org.eclipse.jdt.internal.corext.fix.TypeParametersFix; 146 import org.eclipse.jdt.internal.corext.fix.UnimplementedCodeFix; 147 import org.eclipse.jdt.internal.corext.fix.UnusedCodeFix; 148 import org.eclipse.jdt.internal.corext.refactoring.code.Invocations; 149 import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; 150 import org.eclipse.jdt.internal.corext.refactoring.surround.ExceptionAnalyzer; 151 import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryCatchAnalyzer; 152 import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryCatchRefactoring; 153 import org.eclipse.jdt.internal.corext.refactoring.util.NoCommentSourceRangeComputer; 154 import org.eclipse.jdt.internal.corext.refactoring.util.SurroundWithAnalyzer; 155 import org.eclipse.jdt.internal.corext.refactoring.util.TightSourceRangeComputer; 156 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 157 import org.eclipse.jdt.internal.corext.util.Messages; 158 159 import org.eclipse.jdt.ui.JavaElementImageDescriptor; 160 import org.eclipse.jdt.ui.actions.GenerateHashCodeEqualsAction; 161 import org.eclipse.jdt.ui.actions.IJavaEditorActionDefinitionIds; 162 import org.eclipse.jdt.ui.actions.InferTypeArgumentsAction; 163 import org.eclipse.jdt.ui.cleanup.CleanUpOptions; 164 import org.eclipse.jdt.ui.cleanup.ICleanUp; 165 import org.eclipse.jdt.ui.text.java.IInvocationContext; 166 import org.eclipse.jdt.ui.text.java.IProblemLocation; 167 import org.eclipse.jdt.ui.text.java.correction.ASTRewriteCorrectionProposal; 168 import org.eclipse.jdt.ui.text.java.correction.CUCorrectionProposal; 169 import org.eclipse.jdt.ui.text.java.correction.ChangeCorrectionProposal; 170 import org.eclipse.jdt.ui.text.java.correction.ICommandAccess; 171 172 import org.eclipse.jdt.internal.ui.JavaPlugin; 173 import org.eclipse.jdt.internal.ui.JavaPluginImages; 174 import org.eclipse.jdt.internal.ui.fix.CodeStyleCleanUp; 175 import org.eclipse.jdt.internal.ui.fix.Java50CleanUp; 176 import org.eclipse.jdt.internal.ui.fix.StringCleanUp; 177 import org.eclipse.jdt.internal.ui.fix.TypeParametersCleanUp; 178 import org.eclipse.jdt.internal.ui.fix.UnimplementedCodeCleanUp; 179 import org.eclipse.jdt.internal.ui.fix.UnnecessaryCodeCleanUp; 180 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; 181 import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings; 182 import org.eclipse.jdt.internal.ui.refactoring.nls.ExternalizeWizard; 183 import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal; 184 import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal.ChangeDescription; 185 import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal.InsertDescription; 186 import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal.RemoveDescription; 187 import org.eclipse.jdt.internal.ui.text.correction.proposals.ConstructorFromSuperclassProposal; 188 import org.eclipse.jdt.internal.ui.text.correction.proposals.FixCorrectionProposal; 189 import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedCorrectionProposal; 190 import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedNamesAssistProposal; 191 import org.eclipse.jdt.internal.ui.text.correction.proposals.MissingAnnotationAttributesProposal; 192 import org.eclipse.jdt.internal.ui.text.correction.proposals.ModifierChangeCorrectionProposal; 193 import org.eclipse.jdt.internal.ui.text.correction.proposals.NewMethodCorrectionProposal; 194 import org.eclipse.jdt.internal.ui.text.correction.proposals.NewProviderMethodDeclaration; 195 import org.eclipse.jdt.internal.ui.text.correction.proposals.NewVariableCorrectionProposal; 196 import org.eclipse.jdt.internal.ui.text.correction.proposals.RefactoringCorrectionProposal; 197 import org.eclipse.jdt.internal.ui.text.correction.proposals.ReplaceCorrectionProposal; 198 import org.eclipse.jdt.internal.ui.util.ASTHelper; 199 import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider; 200 201 /** 202 */ 203 public class LocalCorrectionsSubProcessor { 204 205 private static final String RAW_TYPE_REFERENCE_ID= "org.eclipse.jdt.ui.correction.rawTypeReference"; //$NON-NLS-1$ 206 private static final String ADD_EXCEPTION_TO_THROWS_ID= "org.eclipse.jdt.ui.correction.addThrowsDecl"; //$NON-NLS-1$ 207 private static final String ADD_NON_NLS_ID= "org.eclipse.jdt.ui.correction.addNonNLS"; //$NON-NLS-1$ 208 private static final String ADD_FIELD_QUALIFICATION_ID= "org.eclipse.jdt.ui.correction.qualifyField"; //$NON-NLS-1$ 209 private static final String ADD_STATIC_ACCESS_ID= "org.eclipse.jdt.ui.correction.changeToStatic"; //$NON-NLS-1$ 210 private static final String REMOVE_UNNECESSARY_NLS_TAG_ID= "org.eclipse.jdt.ui.correction.removeNlsTag"; //$NON-NLS-1$ 211 212 @SuppressWarnings("deprecation") addUncaughtExceptionProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)213 public static void addUncaughtExceptionProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException { 214 ICompilationUnit cu= context.getCompilationUnit(); 215 216 CompilationUnit astRoot= context.getASTRoot(); 217 ASTNode selectedNode= problem.getCoveringNode(astRoot); 218 if (selectedNode == null) { 219 return; 220 } 221 while (selectedNode != null && !(selectedNode instanceof Statement) && !(selectedNode instanceof VariableDeclarationExpression) 222 && (selectedNode.getLocationInParent() != LambdaExpression.BODY_PROPERTY) && !(selectedNode instanceof MethodReference)) { 223 selectedNode= selectedNode.getParent(); 224 } 225 if (selectedNode == null) { 226 return; 227 } 228 boolean isSelectedNodeThrowStatement= false; 229 if (selectedNode instanceof ThrowStatement) { 230 isSelectedNodeThrowStatement = true; 231 } 232 233 int offset= selectedNode.getStartPosition(); 234 int length= selectedNode.getLength(); 235 int selectionEnd= context.getSelectionOffset() + context.getSelectionLength(); 236 if (selectionEnd > offset + length) { 237 // extend the selection if more than one statement is selected (bug 72149) 238 length= selectionEnd - offset; 239 } 240 241 //Surround with proposals 242 SurroundWithTryCatchRefactoring refactoring= SurroundWithTryCatchRefactoring.create(cu, offset, length); 243 if (refactoring == null) 244 return; 245 246 List<String> affectedLocals= new ArrayList<>(); 247 SimpleName vName= null; 248 ITypeBinding vType= null; 249 if (selectedNode.getAST().apiLevel() >= AST.JLS10 && (selectedNode instanceof VariableDeclarationStatement)) { 250 for (Object o : ((VariableDeclarationStatement)selectedNode).fragments()) { 251 VariableDeclarationFragment v= ((VariableDeclarationFragment)o); 252 vName= v.getName(); 253 vType= ((VariableDeclarationStatement)selectedNode).getType().resolveBinding(); 254 } 255 256 // If no references to 'var' type exist, entire statement will be placed in try block 257 SurroundWithTryCatchAnalyzer analyzer= new SurroundWithTryCatchAnalyzer(cu, Selection.createFromStartLength(offset, length)); 258 astRoot.accept(analyzer); 259 affectedLocals= Arrays.asList(analyzer.getAffectedLocals()).stream().map(f -> f.getName().getIdentifier()).collect(Collectors.toList()); 260 } 261 262 refactoring.setLeaveDirty(true); 263 if (refactoring.checkActivationBasics(astRoot).isOK() && !isSelectedNodeThrowStatement) { 264 String label; 265 if ((vType != null) && (vName != null) && ASTNodes.isVarType(selectedNode, astRoot) && affectedLocals.contains(vName.getIdentifier())) { 266 label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_surroundwith_trycatch_var_description, new Object[] { vName.getIdentifier(), vType.getName() }); 267 } else { 268 label= CorrectionMessages.LocalCorrectionsSubProcessor_surroundwith_trycatch_description; 269 } 270 Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_EXCEPTION); 271 RefactoringCorrectionProposal proposal= new RefactoringCorrectionProposal(label, cu, refactoring, IProposalRelevance.SURROUND_WITH_TRY_CATCH, image); 272 proposal.setLinkedProposalModel(refactoring.getLinkedProposalModel()); 273 proposals.add(proposal); 274 } 275 276 if (JavaModelUtil.is17OrHigher(cu.getJavaProject())) { 277 refactoring= SurroundWithTryCatchRefactoring.create(cu, offset, length, true); 278 if (refactoring == null) 279 return; 280 281 refactoring.setLeaveDirty(true); 282 if (refactoring.checkActivationBasics(astRoot).isOK()) { 283 String label; 284 if ((vType != null) && (vName != null) && ASTNodes.isVarType(selectedNode, astRoot) && affectedLocals.contains(vName.getIdentifier())) { 285 label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_surroundwith_trymulticatch_var_description, new Object[] { vName.getIdentifier(), vType.getName() }); 286 } else { 287 label= CorrectionMessages.LocalCorrectionsSubProcessor_surroundwith_trymulticatch_description; 288 } 289 Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_EXCEPTION); 290 RefactoringCorrectionProposal proposal= new RefactoringCorrectionProposal(label, cu, refactoring, IProposalRelevance.SURROUND_WITH_TRY_MULTICATCH, image); 291 proposal.setLinkedProposalModel(refactoring.getLinkedProposalModel()); 292 proposals.add(proposal); 293 } 294 } 295 296 //Catch exception 297 BodyDeclaration decl= ASTResolving.findParentBodyDeclaration(selectedNode); 298 if (decl == null) { 299 return; 300 } 301 302 ASTNode enclosingNode= SurroundWithAnalyzer.getEnclosingNode(selectedNode); 303 if (enclosingNode == null) { 304 return; 305 } 306 307 ITypeBinding[] uncaughtExceptions= ExceptionAnalyzer.perform(enclosingNode, Selection.createFromStartLength(offset, length)); 308 if (uncaughtExceptions.length == 0) { 309 return; 310 } 311 312 TryStatement surroundingTry= ASTResolving.findParentTryStatement(selectedNode); 313 AST ast= astRoot.getAST(); 314 if (surroundingTry != null && (ASTNodes.isParent(selectedNode, surroundingTry.getBody()) || selectedNode.getLocationInParent() == TryStatement.RESOURCES2_PROPERTY)) { 315 { 316 ASTRewrite rewrite= ASTRewrite.create(surroundingTry.getAST()); 317 318 String label= CorrectionMessages.LocalCorrectionsSubProcessor_addadditionalcatch_description; 319 Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_EXCEPTION); 320 LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, cu, rewrite, IProposalRelevance.ADD_ADDITIONAL_CATCH, image); 321 322 ImportRewrite imports= proposal.createImportRewrite(context.getASTRoot()); 323 ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(decl, imports); 324 325 CodeScopeBuilder.Scope scope= CodeScopeBuilder.perform(decl, Selection.createFromStartLength(offset, length)). 326 findScope(offset, length); 327 scope.setCursor(offset); 328 329 ListRewrite clausesRewrite= rewrite.getListRewrite(surroundingTry, TryStatement.CATCH_CLAUSES_PROPERTY); 330 for (int i= 0; i < uncaughtExceptions.length; i++) { 331 ITypeBinding excBinding= uncaughtExceptions[i]; 332 String varName= StubUtility.getExceptionVariableName(cu.getJavaProject()); 333 String name= scope.createName(varName, false); 334 SingleVariableDeclaration var= ast.newSingleVariableDeclaration(); 335 var.setName(ast.newSimpleName(name)); 336 var.setType(imports.addImport(excBinding, ast, importRewriteContext, TypeLocation.EXCEPTION)); 337 CatchClause newClause= ast.newCatchClause(); 338 newClause.setException(var); 339 String catchBody= StubUtility.getCatchBodyContent(cu, excBinding.getName(), name, selectedNode, String.valueOf('\n')); 340 if (catchBody != null) { 341 ASTNode node= rewrite.createStringPlaceholder(catchBody, ASTNode.RETURN_STATEMENT); 342 newClause.getBody().statements().add(node); 343 } 344 clausesRewrite.insertLast(newClause, null); 345 346 String typeKey= "type" + i; //$NON-NLS-1$ 347 String nameKey= "name" + i; //$NON-NLS-1$ 348 proposal.addLinkedPosition(rewrite.track(var.getType()), false, typeKey); 349 proposal.addLinkedPosition(rewrite.track(var.getName()), false, nameKey); 350 addExceptionTypeLinkProposals(proposal, excBinding, typeKey); 351 } 352 proposals.add(proposal); 353 } 354 355 if (JavaModelUtil.is17OrHigher(cu.getJavaProject())) { 356 List<CatchClause> catchClauses= surroundingTry.catchClauses(); 357 358 if (catchClauses != null && catchClauses.size() == 1) { 359 List<ITypeBinding> filteredExceptions= SurroundWithTryCatchRefactoring.filterSubtypeExceptions(uncaughtExceptions); 360 String label= filteredExceptions.size() > 1 361 ? CorrectionMessages.LocalCorrectionsSubProcessor_addexceptionstoexistingcatch_description 362 : CorrectionMessages.LocalCorrectionsSubProcessor_addexceptiontoexistingcatch_description; 363 Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_EXCEPTION); 364 ASTRewrite rewrite= ASTRewrite.create(ast); 365 LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, cu, rewrite, IProposalRelevance.ADD_EXCEPTIONS_TO_EXISTING_CATCH, image); 366 ImportRewrite imports= proposal.createImportRewrite(context.getASTRoot()); 367 ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(decl, imports); 368 369 CatchClause catchClause= catchClauses.get(0); 370 Type type= catchClause.getException().getType(); 371 if (type instanceof UnionType) { 372 UnionType unionType= (UnionType) type; 373 ListRewrite listRewrite= rewrite.getListRewrite(unionType, UnionType.TYPES_PROPERTY); 374 for (int i= 0; i < filteredExceptions.size(); i++) { 375 ITypeBinding excBinding= filteredExceptions.get(i); 376 Type type2= imports.addImport(excBinding, ast, importRewriteContext, TypeLocation.EXCEPTION); 377 listRewrite.insertLast(type2, null); 378 379 String typeKey= "type" + i; //$NON-NLS-1$ 380 proposal.addLinkedPosition(rewrite.track(type2), false, typeKey); 381 addExceptionTypeLinkProposals(proposal, excBinding, typeKey); 382 } 383 } else { 384 UnionType newUnionType= ast.newUnionType(); 385 List<Type> types= newUnionType.types(); 386 387 types.add((Type) rewrite.createCopyTarget(type)); 388 for (int i= 0; i < filteredExceptions.size(); i++) { 389 ITypeBinding excBinding= filteredExceptions.get(i); 390 Type type2= imports.addImport(excBinding, ast, importRewriteContext, TypeLocation.EXCEPTION); 391 types.add(type2); 392 393 String typeKey= "type" + i; //$NON-NLS-1$ 394 proposal.addLinkedPosition(rewrite.track(type2), false, typeKey); 395 addExceptionTypeLinkProposals(proposal, excBinding, typeKey); 396 } 397 rewrite.replace(type, newUnionType, null); 398 } 399 proposals.add(proposal); 400 } else if (catchClauses != null && catchClauses.isEmpty()) { 401 List<ITypeBinding> filteredExceptions= SurroundWithTryCatchRefactoring.filterSubtypeExceptions(uncaughtExceptions); 402 if (filteredExceptions.size() > 1) { 403 String label= CorrectionMessages.LocalCorrectionsSubProcessor_addadditionalmulticatch_description; 404 Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_EXCEPTION); 405 ASTRewrite rewrite= ASTRewrite.create(ast); 406 LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, cu, rewrite, IProposalRelevance.ADD_ADDITIONAL_MULTI_CATCH, image); 407 ImportRewrite imports= proposal.createImportRewrite(context.getASTRoot()); 408 ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(decl, imports); 409 410 CodeScopeBuilder.Scope scope= CodeScopeBuilder.perform(decl, Selection.createFromStartLength(offset, length)).findScope(offset, length); 411 scope.setCursor(offset); 412 413 CatchClause newCatchClause= ast.newCatchClause(); 414 String varName= StubUtility.getExceptionVariableName(cu.getJavaProject()); 415 String name= scope.createName(varName, false); 416 SingleVariableDeclaration var= ast.newSingleVariableDeclaration(); 417 var.setName(ast.newSimpleName(name)); 418 419 UnionType newUnionType= ast.newUnionType(); 420 List<Type> types= newUnionType.types(); 421 422 for (int i= 0; i < filteredExceptions.size(); i++) { 423 ITypeBinding excBinding= filteredExceptions.get(i); 424 Type type2= imports.addImport(excBinding, ast, importRewriteContext, TypeLocation.EXCEPTION); 425 types.add(type2); 426 427 String typeKey= "type" + i; //$NON-NLS-1$ 428 proposal.addLinkedPosition(rewrite.track(type2), false, typeKey); 429 addExceptionTypeLinkProposals(proposal, excBinding, typeKey); 430 } 431 String nameKey= "name"; //$NON-NLS-1$ 432 proposal.addLinkedPosition(rewrite.track(var.getName()), false, nameKey); 433 var.setType(newUnionType); 434 newCatchClause.setException(var); 435 String catchBody= StubUtility.getCatchBodyContent(cu, "Exception", name, selectedNode, String.valueOf('\n')); //$NON-NLS-1$ 436 if (catchBody != null) { 437 ASTNode node= rewrite.createStringPlaceholder(catchBody, ASTNode.RETURN_STATEMENT); 438 newCatchClause.getBody().statements().add(node); 439 } 440 ListRewrite listRewrite= rewrite.getListRewrite(surroundingTry, TryStatement.CATCH_CLAUSES_PROPERTY); 441 listRewrite.insertFirst(newCatchClause, null); 442 proposals.add(proposal); 443 } 444 } 445 } 446 } 447 448 //Add throws declaration 449 if (enclosingNode instanceof MethodDeclaration) { 450 MethodDeclaration methodDecl= (MethodDeclaration) enclosingNode; 451 IMethodBinding binding= methodDecl.resolveBinding(); 452 boolean isApplicable= (binding != null); 453 if (isApplicable) { 454 IMethodBinding overriddenMethod= Bindings.findOverriddenMethod(binding, true); 455 if (overriddenMethod != null ) { 456 isApplicable= overriddenMethod.getDeclaringClass().isFromSource(); 457 if (!isApplicable) { // bug 349051 458 ITypeBinding[] exceptionTypes= overriddenMethod.getExceptionTypes(); 459 ArrayList<ITypeBinding> unhandledExceptions= new ArrayList<>(uncaughtExceptions.length); 460 for (ITypeBinding curr : uncaughtExceptions) { 461 if (isSubtype(curr, exceptionTypes)) { 462 unhandledExceptions.add(curr); 463 } 464 } 465 uncaughtExceptions= unhandledExceptions.toArray(new ITypeBinding[unhandledExceptions.size()]); 466 isApplicable|= uncaughtExceptions.length > 0; 467 } 468 } 469 } 470 if (isApplicable) { 471 ITypeBinding[] methodExceptions= binding.getExceptionTypes(); 472 ArrayList<ITypeBinding> unhandledExceptions= new ArrayList<>(uncaughtExceptions.length); 473 for (ITypeBinding curr : uncaughtExceptions) { 474 if (!isSubtype(curr, methodExceptions)) { 475 unhandledExceptions.add(curr); 476 } 477 } 478 uncaughtExceptions= unhandledExceptions.toArray(new ITypeBinding[unhandledExceptions.size()]); 479 480 List<Type> exceptions= methodDecl.thrownExceptionTypes(); 481 int nExistingExceptions= exceptions.size(); 482 ChangeDescription[] desc= new ChangeDescription[nExistingExceptions + uncaughtExceptions.length]; 483 for (int i= 0; i < exceptions.size(); i++) { 484 Type elem= exceptions.get(i); 485 if (isSubtype(elem.resolveBinding(), uncaughtExceptions)) { 486 desc[i]= new RemoveDescription(); 487 } 488 } 489 for (int i = 0; i < uncaughtExceptions.length; i++) { 490 desc[i + nExistingExceptions]= new InsertDescription(uncaughtExceptions[i], ""); //$NON-NLS-1$ 491 } 492 493 String label= CorrectionMessages.LocalCorrectionsSubProcessor_addthrows_description; 494 Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_EXCEPTION); 495 496 ChangeMethodSignatureProposal proposal= new ChangeMethodSignatureProposal(label, cu, astRoot, binding, null, desc, IProposalRelevance.ADD_THROWS_DECLARATION, image); 497 for (int i= 0; i < uncaughtExceptions.length; i++) { 498 addExceptionTypeLinkProposals(proposal, uncaughtExceptions[i], proposal.getExceptionTypeGroupId(i + nExistingExceptions)); 499 } 500 proposal.setCommandId(ADD_EXCEPTION_TO_THROWS_ID); 501 proposals.add(proposal); 502 } 503 } 504 } 505 addExceptionTypeLinkProposals(LinkedCorrectionProposal proposal, ITypeBinding exc, String key)506 private static void addExceptionTypeLinkProposals(LinkedCorrectionProposal proposal, ITypeBinding exc, String key) { 507 // all super classes except Object 508 while (exc != null && !"java.lang.Object".equals(exc.getQualifiedName())) { //$NON-NLS-1$ 509 proposal.addLinkedPositionProposal(key, exc); 510 exc= exc.getSuperclass(); 511 } 512 } 513 514 isSubtype(ITypeBinding curr, ITypeBinding[] addedExceptions)515 private static boolean isSubtype(ITypeBinding curr, ITypeBinding[] addedExceptions) { 516 while (curr != null) { 517 for (ITypeBinding addedException : addedExceptions) { 518 if (curr == addedException) { 519 return true; 520 } 521 } 522 curr= curr.getSuperclass(); 523 } 524 return false; 525 } 526 addUnreachableCatchProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)527 public static void addUnreachableCatchProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 528 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 529 if (selectedNode == null) { 530 return; 531 } 532 533 QuickAssistProcessor.getCatchClauseToThrowsProposals(context, selectedNode, proposals); 534 } 535 addNLSProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)536 public static void addNLSProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException { 537 final ICompilationUnit cu= context.getCompilationUnit(); 538 if (cu == null || !cu.exists()){ 539 return; 540 } 541 String name= CorrectionMessages.LocalCorrectionsSubProcessor_externalizestrings_description; 542 543 ChangeCorrectionProposal proposal= new ChangeCorrectionProposal(name, null, IProposalRelevance.EXTERNALIZE_STRINGS, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE)) { 544 @Override 545 public void apply(IDocument document) { 546 ExternalizeWizard.open(cu, JavaPlugin.getActiveWorkbenchShell()); 547 } 548 @Override 549 public Object getAdditionalProposalInfo(IProgressMonitor monitor) { 550 return CorrectionMessages.LocalCorrectionsSubProcessor_externalizestrings_additional_info; 551 } 552 553 }; 554 proposals.add(proposal); 555 556 IProposableFix fix= StringFix.createFix(context.getASTRoot(), problem, false, true); 557 if (fix != null) { 558 Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_NLS_NEVER_TRANSLATE); 559 Map<String, String> options= new Hashtable<>(); 560 options.put(CleanUpConstants.ADD_MISSING_NLS_TAGS, CleanUpOptions.TRUE); 561 FixCorrectionProposal addNLS= new FixCorrectionProposal(fix, new StringCleanUp(options), IProposalRelevance.ADD_MISSING_NLS_TAGS, image, context); 562 addNLS.setCommandId(ADD_NON_NLS_ID); 563 proposals.add(addNLS); 564 } 565 } 566 getUnnecessaryNLSTagProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)567 public static void getUnnecessaryNLSTagProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException { 568 IProposableFix fix= StringFix.createFix(context.getASTRoot(), problem, true, false); 569 if (fix != null) { 570 Image image= PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE); 571 Map<String, String> options= new Hashtable<>(); 572 options.put(CleanUpConstants.REMOVE_UNNECESSARY_NLS_TAGS, CleanUpOptions.TRUE); 573 FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new StringCleanUp(options), IProposalRelevance.UNNECESSARY_NLS_TAG, image, context); 574 proposal.setCommandId(REMOVE_UNNECESSARY_NLS_TAG_ID); 575 proposals.add(proposal); 576 } 577 } 578 579 580 /* 581 * Fix instance accesses and indirect (static) accesses to static fields/methods 582 */ addCorrectAccessToStaticProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)583 public static void addCorrectAccessToStaticProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException { 584 IProposableFix fix= CodeStyleFix.createIndirectAccessToStaticFix(context.getASTRoot(), problem); 585 if (fix != null) { 586 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 587 Map<String, String> options= new HashMap<>(); 588 options.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS, CleanUpOptions.TRUE); 589 options.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS_SUBTYPE_ACCESS, CleanUpOptions.TRUE); 590 FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new CodeStyleCleanUp(options), IProposalRelevance.CREATE_INDIRECT_ACCESS_TO_STATIC, image, context); 591 proposal.setCommandId(ADD_STATIC_ACCESS_ID); 592 proposals.add(proposal); 593 return; 594 } 595 596 IProposableFix[] fixes= CodeStyleFix.createNonStaticAccessFixes(context.getASTRoot(), problem); 597 if (fixes != null) { 598 IProposableFix fix1= fixes[0]; 599 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 600 Map<String, String> options= new HashMap<>(); 601 options.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS, CleanUpOptions.TRUE); 602 options.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS_INSTANCE_ACCESS, CleanUpOptions.TRUE); 603 FixCorrectionProposal proposal= new FixCorrectionProposal(fix1, new CodeStyleCleanUp(options), IProposalRelevance.CREATE_NON_STATIC_ACCESS_USING_DECLARING_TYPE, image, context); 604 proposal.setCommandId(ADD_STATIC_ACCESS_ID); 605 proposals.add(proposal); 606 607 if (fixes.length > 1) { 608 Map<String, String> options1= new HashMap<>(); 609 options1.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS, CleanUpOptions.TRUE); 610 options1.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS_SUBTYPE_ACCESS, CleanUpOptions.TRUE); 611 options1.put(CleanUpConstants.MEMBER_ACCESSES_STATIC_QUALIFY_WITH_DECLARING_CLASS_INSTANCE_ACCESS, CleanUpOptions.TRUE); 612 IProposableFix fix2= fixes[1]; 613 proposal= new FixCorrectionProposal(fix2, new CodeStyleCleanUp(options), IProposalRelevance.CREATE_NON_STATIC_ACCESS_USING_INSTANCE_TYPE, image, context); 614 proposals.add(proposal); 615 } 616 } 617 ModifierCorrectionSubProcessor.addNonAccessibleReferenceProposal(context, problem, proposals, ModifierCorrectionSubProcessor.TO_NON_STATIC, IProposalRelevance.REMOVE_STATIC_MODIFIER); 618 } 619 addUnimplementedMethodsProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)620 public static void addUnimplementedMethodsProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 621 IProposableFix addMethodFix= UnimplementedCodeFix.createAddUnimplementedMethodsFix(context.getASTRoot(), problem); 622 if (addMethodFix != null) { 623 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 624 625 Map<String, String> settings= new Hashtable<>(); 626 settings.put(CleanUpConstants.ADD_MISSING_METHODES, CleanUpOptions.TRUE); 627 ICleanUp cleanUp= new UnimplementedCodeCleanUp(settings); 628 629 proposals.add(new FixCorrectionProposal(addMethodFix, cleanUp, IProposalRelevance.ADD_UNIMPLEMENTED_METHODS, image, context)); 630 } 631 632 IProposableFix makeAbstractFix= UnimplementedCodeFix.createMakeTypeAbstractFix(context.getASTRoot(), problem); 633 if (makeAbstractFix != null) { 634 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 635 636 Map<String, String> settings= new Hashtable<>(); 637 settings.put(UnimplementedCodeCleanUp.MAKE_TYPE_ABSTRACT, CleanUpOptions.TRUE); 638 ICleanUp cleanUp= new UnimplementedCodeCleanUp(settings); 639 640 proposals.add(new FixCorrectionProposal(makeAbstractFix, cleanUp, IProposalRelevance.MAKE_TYPE_ABSTRACT, image, context)); 641 } 642 } 643 addUninitializedLocalVariableProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)644 public static void addUninitializedLocalVariableProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 645 ICompilationUnit cu= context.getCompilationUnit(); 646 647 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 648 if (!(selectedNode instanceof Name)) { 649 return; 650 } 651 Name name= (Name) selectedNode; 652 IBinding binding= name.resolveBinding(); 653 if (!(binding instanceof IVariableBinding)) { 654 return; 655 } 656 IVariableBinding varBinding= (IVariableBinding) binding; 657 658 CompilationUnit astRoot= context.getASTRoot(); 659 ASTNode node= astRoot.findDeclaringNode(binding); 660 if (node instanceof VariableDeclarationFragment) { 661 ASTRewrite rewrite= ASTRewrite.create(node.getAST()); 662 663 VariableDeclarationFragment fragment= (VariableDeclarationFragment) node; 664 if (fragment.getInitializer() != null) { 665 return; 666 } 667 Expression expression= ASTNodeFactory.newDefaultExpression(astRoot.getAST(), varBinding.getType()); 668 if (expression == null) { 669 return; 670 } 671 rewrite.set(fragment, VariableDeclarationFragment.INITIALIZER_PROPERTY, expression, null); 672 673 String label= CorrectionMessages.LocalCorrectionsSubProcessor_uninitializedvariable_description; 674 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 675 676 LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, cu, rewrite, IProposalRelevance.INITIALIZE_VARIABLE, image); 677 proposal.addLinkedPosition(rewrite.track(expression), false, "initializer"); //$NON-NLS-1$ 678 proposals.add(proposal); 679 } 680 } 681 addConstructorFromSuperclassProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)682 public static void addConstructorFromSuperclassProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException { 683 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 684 if (selectedNode == null) { 685 return; 686 } 687 688 TypeDeclaration typeDeclaration= null; 689 if (selectedNode.getLocationInParent() == TypeDeclaration.NAME_PROPERTY) { 690 typeDeclaration= (TypeDeclaration) selectedNode.getParent(); 691 } else { 692 BodyDeclaration declaration= ASTResolving.findParentBodyDeclaration(selectedNode); 693 if (declaration instanceof Initializer && problem.getProblemId() == IProblem.UnhandledExceptionInDefaultConstructor) { 694 addUncaughtExceptionProposals(context, problem, proposals); 695 } 696 return; 697 } 698 699 ITypeBinding binding= typeDeclaration.resolveBinding(); 700 if (binding == null || binding.getSuperclass() == null) { 701 return; 702 } 703 ICompilationUnit cu= context.getCompilationUnit(); 704 for (IMethodBinding curr : binding.getSuperclass().getDeclaredMethods()) { 705 if (curr.isConstructor() && !Modifier.isPrivate(curr.getModifiers())) { 706 proposals.add(new ConstructorFromSuperclassProposal(cu, typeDeclaration, curr, IProposalRelevance.ADD_CONSTRUCTOR_FROM_SUPER_CLASS)); 707 } 708 } 709 } 710 addUnusedMemberProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)711 public static void addUnusedMemberProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 712 int problemId = problem.getProblemId(); 713 UnusedCodeFix fix= UnusedCodeFix.createUnusedMemberFix(context.getASTRoot(), problem, false); 714 if (fix != null) { 715 addProposal(context, proposals, fix); 716 } 717 718 if (problemId==IProblem.LocalVariableIsNeverUsed){ 719 fix= UnusedCodeFix.createUnusedMemberFix(context.getASTRoot(), problem, true); 720 addProposal(context, proposals, fix); 721 } 722 723 if (problemId == IProblem.ArgumentIsNeverUsed) { 724 JavadocTagsSubProcessor.getUnusedAndUndocumentedParameterOrExceptionProposals(context, problem, proposals); 725 } 726 727 if (problemId == IProblem.UnusedPrivateField) { 728 GetterSetterCorrectionSubProcessor.addGetterSetterProposal(context, problem, proposals, IProposalRelevance.GETTER_SETTER_UNUSED_PRIVATE_FIELD); 729 } 730 731 } 732 addUnusedTypeParameterProposal(IInvocationContext context, IProblemLocation problemLoc, Collection<ICommandAccess> proposals)733 public static void addUnusedTypeParameterProposal(IInvocationContext context, IProblemLocation problemLoc, Collection<ICommandAccess> proposals) { 734 UnusedCodeFix fix= UnusedCodeFix.createUnusedTypeParameterFix(context.getASTRoot(), problemLoc); 735 if (fix != null) { 736 addProposal(context, proposals, fix); 737 } 738 739 JavadocTagsSubProcessor.getUnusedAndUndocumentedParameterOrExceptionProposals(context, problemLoc, proposals); 740 } 741 addRedundantSuperInterfaceProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)742 public static void addRedundantSuperInterfaceProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 743 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 744 if (!(selectedNode instanceof Name)) { 745 return; 746 } 747 ASTNode node= ASTNodes.getNormalizedNode(selectedNode); 748 749 ASTRewrite rewrite= ASTRewrite.create(node.getAST()); 750 rewrite.remove(node, null); 751 752 String label= CorrectionMessages.LocalCorrectionsSubProcessor_remove_redundant_superinterface; 753 Image image= PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE); 754 755 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.REMOVE_REDUNDANT_SUPER_INTERFACE, image); 756 proposals.add(proposal); 757 758 } 759 addProposal(IInvocationContext context, Collection<ICommandAccess> proposals, final UnusedCodeFix fix)760 private static void addProposal(IInvocationContext context, Collection<ICommandAccess> proposals, final UnusedCodeFix fix) { 761 if (fix != null) { 762 Image image= PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE); 763 FixCorrectionProposal proposal= new FixCorrectionProposal(fix, fix.getCleanUp(), IProposalRelevance.UNUSED_MEMBER, image, context); 764 proposals.add(proposal); 765 } 766 } 767 addSuperfluousSemicolonProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)768 public static void addSuperfluousSemicolonProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 769 String label= CorrectionMessages.LocalCorrectionsSubProcessor_removesemicolon_description; 770 ReplaceCorrectionProposal proposal= new ReplaceCorrectionProposal(label, context.getCompilationUnit(), problem.getOffset(), problem.getLength(), "", IProposalRelevance.REMOVE_SEMICOLON); //$NON-NLS-1$ 771 proposals.add(proposal); 772 } 773 addUnnecessaryCastProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)774 public static void addUnnecessaryCastProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 775 IProposableFix fix= UnusedCodeFix.createRemoveUnusedCastFix(context.getASTRoot(), problem); 776 if (fix != null) { 777 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 778 Map<String, String> options= new Hashtable<>(); 779 options.put(CleanUpConstants.REMOVE_UNNECESSARY_CASTS, CleanUpOptions.TRUE); 780 FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new UnnecessaryCodeCleanUp(options), IProposalRelevance.REMOVE_UNUSED_CAST, image, context); 781 proposals.add(proposal); 782 } 783 } 784 addUnnecessaryInstanceofProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)785 public static void addUnnecessaryInstanceofProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 786 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 787 788 ASTNode curr= ASTNodes.getUnparenthesedExpression(selectedNode); 789 790 if (curr instanceof InstanceofExpression) { 791 AST ast= curr.getAST(); 792 793 ASTRewrite rewrite= ASTRewrite.create(ast); 794 795 InstanceofExpression inst= (InstanceofExpression) curr; 796 797 InfixExpression expression= ast.newInfixExpression(); 798 expression.setLeftOperand((Expression) rewrite.createCopyTarget(inst.getLeftOperand())); 799 expression.setOperator(InfixExpression.Operator.NOT_EQUALS); 800 expression.setRightOperand(ast.newNullLiteral()); 801 802 rewrite.replace(inst, expression, null); 803 804 String label= CorrectionMessages.LocalCorrectionsSubProcessor_unnecessaryinstanceof_description; 805 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 806 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.UNNECESSARY_INSTANCEOF, image); 807 proposals.add(proposal); 808 } 809 810 } 811 addIllegalQualifiedEnumConstantLabelProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)812 public static void addIllegalQualifiedEnumConstantLabelProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 813 ASTNode coveringNode= problem.getCoveringNode(context.getASTRoot()); 814 815 ASTNode curr= ASTNodes.getUnparenthesedExpression(coveringNode); 816 817 if (!(curr instanceof QualifiedName)) { 818 return; 819 } 820 821 SimpleName simpleName= ((QualifiedName) curr).getName(); 822 final ASTRewrite rewrite= ASTRewrite.create(curr.getAST()); 823 rewrite.replace(coveringNode, simpleName, null); 824 825 String label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_replace_with_unqualified_enum_constant, BasicElementLabels.getJavaElementName(simpleName.getIdentifier())); 826 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 827 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.REPLACE_WITH_UNQUALIFIED_ENUM_CONSTANT, image); 828 proposals.add(proposal); 829 } 830 addUnnecessaryThrownExceptionProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)831 public static void addUnnecessaryThrownExceptionProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 832 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 833 selectedNode= ASTNodes.getNormalizedNode(selectedNode); 834 if (selectedNode == null || selectedNode.getLocationInParent() != MethodDeclaration.THROWN_EXCEPTION_TYPES_PROPERTY) { 835 return; 836 } 837 MethodDeclaration decl= (MethodDeclaration) selectedNode.getParent(); 838 IMethodBinding binding= decl.resolveBinding(); 839 if (binding != null) { 840 List<Type> thrownExceptions= decl.thrownExceptionTypes(); 841 int index= thrownExceptions.indexOf(selectedNode); 842 if (index == -1) { 843 return; 844 } 845 ChangeDescription[] desc= new ChangeDescription[thrownExceptions.size()]; 846 desc[index]= new RemoveDescription(); 847 848 ICompilationUnit cu= context.getCompilationUnit(); 849 String label= CorrectionMessages.LocalCorrectionsSubProcessor_unnecessarythrow_description; 850 Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_EXCEPTION); 851 852 proposals.add(new ChangeMethodSignatureProposal(label, cu, selectedNode, binding, null, desc, IProposalRelevance.UNNECESSARY_THROW, image)); 853 } 854 855 JavadocTagsSubProcessor.getUnusedAndUndocumentedParameterOrExceptionProposals(context, problem, proposals); 856 } 857 addUnqualifiedFieldAccessProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)858 public static void addUnqualifiedFieldAccessProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 859 IProposableFix fix= CodeStyleFix.createAddFieldQualifierFix(context.getASTRoot(), problem); 860 if (fix != null) { 861 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 862 Map<String, String> options= new HashMap<>(); 863 options.put(CleanUpConstants.MEMBER_ACCESSES_NON_STATIC_FIELD_USE_THIS, CleanUpOptions.TRUE); 864 options.put(CleanUpConstants.MEMBER_ACCESSES_NON_STATIC_FIELD_USE_THIS_ALWAYS, CleanUpOptions.TRUE); 865 FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new CodeStyleCleanUp(options), IProposalRelevance.ADD_FIELD_QUALIFIER, image, context); 866 proposal.setCommandId(ADD_FIELD_QUALIFICATION_ID); 867 proposals.add(proposal); 868 } 869 } 870 addInvalidVariableNameProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)871 public static void addInvalidVariableNameProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 872 // hiding, redefined or future keyword 873 874 CompilationUnit root= context.getASTRoot(); 875 ASTNode selectedNode= problem.getCoveringNode(root); 876 if (selectedNode instanceof MethodDeclaration) { 877 selectedNode= ((MethodDeclaration) selectedNode).getName(); 878 } 879 if (!(selectedNode instanceof SimpleName)) { 880 return; 881 } 882 SimpleName nameNode= (SimpleName) selectedNode; 883 String valueSuggestion= null; 884 885 String name; 886 switch (problem.getProblemId()) { 887 case IProblem.LocalVariableHidingLocalVariable: 888 case IProblem.LocalVariableHidingField: 889 name= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_hiding_local_label, BasicElementLabels.getJavaElementName(nameNode.getIdentifier())); 890 break; 891 case IProblem.FieldHidingLocalVariable: 892 case IProblem.FieldHidingField: 893 case IProblem.DuplicateField: 894 name= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_hiding_field_label, BasicElementLabels.getJavaElementName(nameNode.getIdentifier())); 895 break; 896 case IProblem.ArgumentHidingLocalVariable: 897 case IProblem.ArgumentHidingField: 898 name= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_hiding_argument_label, BasicElementLabels.getJavaElementName(nameNode.getIdentifier())); 899 break; 900 case IProblem.DuplicateMethod: 901 name= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_renaming_duplicate_method, BasicElementLabels.getJavaElementName(nameNode.getIdentifier())); 902 break; 903 904 default: 905 name= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_rename_var_label, BasicElementLabels.getJavaElementName(nameNode.getIdentifier())); 906 } 907 908 if (problem.getProblemId() == IProblem.UseEnumAsAnIdentifier) { 909 valueSuggestion= "enumeration"; //$NON-NLS-1$ 910 } else { 911 valueSuggestion= nameNode.getIdentifier() + '1'; 912 } 913 914 LinkedNamesAssistProposal proposal= new LinkedNamesAssistProposal(name, context, nameNode, valueSuggestion); 915 proposals.add(proposal); 916 } 917 getInvalidOperatorProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)918 public static void getInvalidOperatorProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 919 CompilationUnit root= context.getASTRoot(); 920 AST ast= root.getAST(); 921 922 ASTNode selectedNode= ASTNodes.getUnparenthesedExpression(problem.getCoveringNode(root)); 923 924 if (selectedNode instanceof PrefixExpression) { 925 // !x instanceof X -> !(x instanceof X) 926 927 PrefixExpression expression= (PrefixExpression) selectedNode; 928 if (expression.getOperator() == PrefixExpression.Operator.NOT) { 929 ASTNode parent= expression.getParent(); 930 931 String label= null; 932 switch (parent.getNodeType()) { 933 case ASTNode.INSTANCEOF_EXPRESSION: 934 label= CorrectionMessages.LocalCorrectionsSubProcessor_setparenteses_instanceof_description; 935 break; 936 case ASTNode.INFIX_EXPRESSION: 937 InfixExpression infixExpression= (InfixExpression)parent; 938 label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_setparenteses_description, infixExpression.getOperator().toString()); 939 break; 940 } 941 942 if (label != null) { 943 ASTRewrite rewrite= ASTRewrite.create(ast); 944 rewrite.replace(selectedNode, rewrite.createMoveTarget(expression.getOperand()), null); 945 946 ParenthesizedExpression newParentExpr= ast.newParenthesizedExpression(); 947 newParentExpr.setExpression((Expression) rewrite.createMoveTarget(parent)); 948 PrefixExpression newPrefixExpr= ast.newPrefixExpression(); 949 newPrefixExpr.setOperand(newParentExpr); 950 newPrefixExpr.setOperator(PrefixExpression.Operator.NOT); 951 952 rewrite.replace(parent, newPrefixExpr, null); 953 954 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CAST); 955 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.INVALID_OPERATOR, image); 956 proposals.add(proposal); 957 } 958 } 959 } else if (selectedNode instanceof InfixExpression && isBitOperation((((InfixExpression) selectedNode).getOperator()))) { 960 // a & b == c -> (a & b) == c 961 final CompareInBitWiseOpFinder opFinder= new CompareInBitWiseOpFinder(selectedNode); 962 if (opFinder.getCompareExpression() != null) { // compare operation inside bit operations: set parents 963 String label= CorrectionMessages.LocalCorrectionsSubProcessor_setparenteses_bitop_description; 964 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CAST); 965 CUCorrectionProposal proposal= new CUCorrectionProposal(label, context.getCompilationUnit(), IProposalRelevance.INVALID_OPERATOR, image) { 966 @Override 967 protected void addEdits(IDocument document, TextEdit edit) throws CoreException { 968 InfixExpression compareExpression= opFinder.getCompareExpression(); 969 InfixExpression expression= opFinder.getParentInfixExpression(); 970 ASTNode left= compareExpression.getLeftOperand(); 971 if (expression.getStartPosition() < left.getStartPosition()) { 972 edit.addChild(new InsertEdit(expression.getStartPosition(), String.valueOf('('))); 973 edit.addChild(new InsertEdit(ASTNodes.getExclusiveEnd(left), String.valueOf(')'))); 974 } 975 ASTNode rigth= compareExpression.getRightOperand(); 976 int selEnd= ASTNodes.getExclusiveEnd(expression); 977 if (selEnd > ASTNodes.getExclusiveEnd(rigth)) { 978 edit.addChild(new InsertEdit(rigth.getStartPosition(), String.valueOf('('))); 979 edit.addChild(new InsertEdit(selEnd, String.valueOf(')'))); 980 } 981 } 982 }; 983 proposals.add(proposal); 984 } 985 } 986 } 987 isBitOperation(InfixExpression.Operator op)988 private static boolean isBitOperation(InfixExpression.Operator op) { 989 return op == InfixExpression.Operator.AND || op == InfixExpression.Operator.OR || op == InfixExpression.Operator.XOR; 990 } 991 992 private static class CompareInBitWiseOpFinder extends ASTVisitor { 993 994 private InfixExpression fCompareExpression= null; 995 private final ASTNode fSelectedNode; 996 CompareInBitWiseOpFinder(ASTNode selectedNode)997 public CompareInBitWiseOpFinder(ASTNode selectedNode) { 998 fSelectedNode= selectedNode; 999 selectedNode.accept(this); 1000 } 1001 1002 @Override visit(InfixExpression e)1003 public boolean visit(InfixExpression e) { 1004 InfixExpression.Operator op= e.getOperator(); 1005 if (isBitOperation(op)) { 1006 return true; 1007 } else if (op == InfixExpression.Operator.EQUALS || op == InfixExpression.Operator.NOT_EQUALS) { 1008 fCompareExpression= e; 1009 return false; 1010 } 1011 return false; 1012 } 1013 getCompareExpression()1014 public InfixExpression getCompareExpression() { 1015 return fCompareExpression; 1016 } 1017 getParentInfixExpression()1018 public InfixExpression getParentInfixExpression() { 1019 ASTNode expr= fSelectedNode; 1020 ASTNode parent= expr.getParent(); // include all parents 1021 while (parent instanceof InfixExpression && isBitOperation(((InfixExpression) parent).getOperator())) { 1022 expr= parent; 1023 parent= expr.getParent(); 1024 } 1025 return (InfixExpression) expr; 1026 } 1027 } 1028 getUnnecessaryElseProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1029 public static void getUnnecessaryElseProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1030 CompilationUnit root= context.getASTRoot(); 1031 ASTNode selectedNode= problem.getCoveringNode(root); 1032 if (selectedNode == null) { 1033 return; 1034 } 1035 ASTNode parent= selectedNode.getParent(); 1036 if (parent instanceof ExpressionStatement) { 1037 parent= parent.getParent(); 1038 } 1039 if (!(parent instanceof IfStatement)) { 1040 return; 1041 } 1042 IfStatement ifStatement= (IfStatement) parent; 1043 ASTNode ifParent= ifStatement.getParent(); 1044 if (!(ifParent instanceof Block) && !(ifParent instanceof SwitchStatement) && !ASTNodes.isControlStatementBody(ifStatement.getLocationInParent())) { 1045 return; 1046 } 1047 1048 ASTRewrite rewrite= ASTRewrite.create(root.getAST()); 1049 ASTNode placeholder=QuickAssistProcessor.getCopyOfInner(rewrite, ifStatement.getElseStatement(), false); 1050 if (placeholder == null) { 1051 return; 1052 } 1053 rewrite.remove(ifStatement.getElseStatement(), null); 1054 1055 if (ifParent instanceof Block) { 1056 ListRewrite listRewrite= rewrite.getListRewrite(ifParent, Block.STATEMENTS_PROPERTY); 1057 listRewrite.insertAfter(placeholder, ifStatement, null); 1058 } else if (ifParent instanceof SwitchStatement) { 1059 ListRewrite listRewrite= rewrite.getListRewrite(ifParent, SwitchStatement.STATEMENTS_PROPERTY); 1060 listRewrite.insertAfter(placeholder, ifStatement, null); 1061 } else { 1062 Block block= root.getAST().newBlock(); 1063 rewrite.replace(ifStatement, block, null); 1064 block.statements().add(rewrite.createCopyTarget(ifStatement)); 1065 block.statements().add(placeholder); 1066 } 1067 1068 String label= CorrectionMessages.LocalCorrectionsSubProcessor_removeelse_description; 1069 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1070 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.REMOVE_ELSE, image); 1071 proposals.add(proposal); 1072 } 1073 1074 getInterfaceExtendsClassProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1075 public static void getInterfaceExtendsClassProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1076 CompilationUnit root= context.getASTRoot(); 1077 ASTNode selectedNode= problem.getCoveringNode(root); 1078 if (selectedNode == null) { 1079 return; 1080 } 1081 while (selectedNode.getParent() instanceof Type) { 1082 selectedNode= selectedNode.getParent(); 1083 } 1084 1085 StructuralPropertyDescriptor locationInParent= selectedNode.getLocationInParent(); 1086 if (locationInParent != TypeDeclaration.SUPERCLASS_TYPE_PROPERTY) { 1087 return; 1088 } 1089 1090 TypeDeclaration typeDecl= (TypeDeclaration) selectedNode.getParent(); 1091 { 1092 ASTRewrite rewrite= ASTRewrite.create(root.getAST()); 1093 ASTNode placeHolder= rewrite.createMoveTarget(selectedNode); 1094 ListRewrite interfaces= rewrite.getListRewrite(typeDecl, TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY); 1095 interfaces.insertFirst(placeHolder, null); 1096 1097 String label= CorrectionMessages.LocalCorrectionsSubProcessor_extendstoimplements_description; 1098 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1099 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.CHANGE_EXTENDS_TO_IMPLEMENTS, image); 1100 proposals.add(proposal); 1101 } 1102 { 1103 ASTRewrite rewrite= ASTRewrite.create(root.getAST()); 1104 1105 rewrite.set(typeDecl, TypeDeclaration.INTERFACE_PROPERTY, Boolean.TRUE, null); 1106 1107 String typeName= typeDecl.getName().getIdentifier(); 1108 String label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_classtointerface_description, BasicElementLabels.getJavaElementName(typeName)); 1109 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1110 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.CHANGE_CLASS_TO_INTERFACE, image); 1111 proposals.add(proposal); 1112 } 1113 } 1114 getUnreachableCodeProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1115 public static void getUnreachableCodeProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1116 CompilationUnit root= context.getASTRoot(); 1117 ASTNode selectedNode= problem.getCoveringNode(root); 1118 if (selectedNode == null) { 1119 return; 1120 } 1121 1122 ASTNode parent= selectedNode.getParent(); 1123 while (parent instanceof ExpressionStatement) { 1124 selectedNode= parent; 1125 parent= selectedNode.getParent(); 1126 } 1127 1128 if (parent instanceof WhileStatement) { 1129 addRemoveIncludingConditionProposal(context, parent, null, proposals); 1130 1131 } else if (selectedNode.getLocationInParent() == IfStatement.THEN_STATEMENT_PROPERTY) { 1132 Statement elseStatement= ((IfStatement)parent).getElseStatement(); 1133 addRemoveIncludingConditionProposal(context, parent, elseStatement, proposals); 1134 1135 } else if (selectedNode.getLocationInParent() == IfStatement.ELSE_STATEMENT_PROPERTY) { 1136 Statement thenStatement= ((IfStatement)parent).getThenStatement(); 1137 addRemoveIncludingConditionProposal(context, parent, thenStatement, proposals); 1138 1139 } else if (selectedNode.getLocationInParent() == ForStatement.BODY_PROPERTY) { 1140 Statement body= ((ForStatement)parent).getBody(); 1141 addRemoveIncludingConditionProposal(context, parent, body, proposals); 1142 1143 } else if (selectedNode.getLocationInParent() == ConditionalExpression.THEN_EXPRESSION_PROPERTY) { 1144 Expression elseExpression= ((ConditionalExpression)parent).getElseExpression(); 1145 addRemoveIncludingConditionProposal(context, parent, elseExpression, proposals); 1146 1147 } else if (selectedNode.getLocationInParent() == ConditionalExpression.ELSE_EXPRESSION_PROPERTY) { 1148 Expression thenExpression= ((ConditionalExpression)parent).getThenExpression(); 1149 addRemoveIncludingConditionProposal(context, parent, thenExpression, proposals); 1150 1151 } else if (selectedNode.getLocationInParent() == InfixExpression.RIGHT_OPERAND_PROPERTY) { 1152 // also offer split && / || condition proposals: 1153 InfixExpression infixExpression= (InfixExpression)parent; 1154 Expression leftOperand= infixExpression.getLeftOperand(); 1155 1156 ASTRewrite rewrite= ASTRewrite.create(parent.getAST()); 1157 1158 Expression replacement= ASTNodes.getUnparenthesedExpression(leftOperand); 1159 1160 Expression toReplace= infixExpression; 1161 while (toReplace.getLocationInParent() == ParenthesizedExpression.EXPRESSION_PROPERTY) { 1162 toReplace= (Expression) toReplace.getParent(); 1163 } 1164 1165 if (NecessaryParenthesesChecker.needsParentheses(replacement, toReplace.getParent(), toReplace.getLocationInParent())) { 1166 if (leftOperand instanceof ParenthesizedExpression) { 1167 replacement= (Expression) replacement.getParent(); 1168 } else if (infixExpression.getLocationInParent() == ParenthesizedExpression.EXPRESSION_PROPERTY) { 1169 toReplace= ((ParenthesizedExpression) toReplace).getExpression(); 1170 } 1171 } 1172 1173 rewrite.replace(toReplace, rewrite.createMoveTarget(replacement), null); 1174 1175 String label= CorrectionMessages.LocalCorrectionsSubProcessor_removeunreachablecode_description; 1176 addRemoveProposal(context, rewrite, label, proposals); 1177 1178 AssistContext assistContext= new AssistContext(context.getCompilationUnit(), infixExpression.getRightOperand().getStartPosition() - 1, 0); 1179 assistContext.setASTRoot(root); 1180 AdvancedQuickAssistProcessor.getSplitAndConditionProposals(assistContext, infixExpression, proposals); 1181 AdvancedQuickAssistProcessor.getSplitOrConditionProposals(assistContext, infixExpression, proposals); 1182 1183 } else if (selectedNode instanceof Statement && selectedNode.getLocationInParent().isChildListProperty()) { 1184 // remove all statements following the unreachable: 1185 List<Statement> statements= ASTNodes.<Statement>getChildListProperty(selectedNode.getParent(), (ChildListPropertyDescriptor) selectedNode.getLocationInParent()); 1186 int idx= statements.indexOf(selectedNode); 1187 1188 ASTRewrite rewrite= ASTRewrite.create(selectedNode.getAST()); 1189 String label= CorrectionMessages.LocalCorrectionsSubProcessor_removeunreachablecode_description; 1190 1191 if (idx > 0) { 1192 Object prevStatement= statements.get(idx - 1); 1193 if (prevStatement instanceof IfStatement) { 1194 IfStatement ifStatement= (IfStatement) prevStatement; 1195 if (ifStatement.getElseStatement() == null) { 1196 // remove if (true), see https://bugs.eclipse.org/bugs/show_bug.cgi?id=261519 1197 Statement thenStatement= ifStatement.getThenStatement(); 1198 label= CorrectionMessages.LocalCorrectionsSubProcessor_removeunreachablecode_including_condition_description; 1199 if (thenStatement instanceof Block) { 1200 // add all child nodes from Block node 1201 List<Statement> thenStatements= ((Block) thenStatement).statements(); 1202 if (thenStatements.isEmpty()) { 1203 return; 1204 } 1205 ASTNode[] thenStatementsArray= new ASTNode[thenStatements.size()]; 1206 for (int i= 0; i < thenStatementsArray.length; i++) { 1207 thenStatementsArray[i]= thenStatements.get(i); 1208 } 1209 ASTNode newThenStatement= rewrite.createGroupNode(thenStatementsArray); 1210 1211 rewrite.replace(ifStatement, newThenStatement, null); 1212 } else { 1213 rewrite.replace(ifStatement, thenStatement, null); 1214 } 1215 } 1216 } 1217 } 1218 1219 for (int i= idx; i < statements.size(); i++) { 1220 ASTNode statement= statements.get(i); 1221 if (statement instanceof SwitchCase) 1222 break; // stop at case *: and default: 1223 rewrite.remove(statement, null); 1224 } 1225 1226 addRemoveProposal(context, rewrite, label, proposals); 1227 1228 1229 } else { 1230 // no special case, just remove the node: 1231 addRemoveProposal(context, selectedNode, proposals); 1232 } 1233 } 1234 addRemoveProposal(IInvocationContext context, ASTNode selectedNode, Collection<ICommandAccess> proposals)1235 private static void addRemoveProposal(IInvocationContext context, ASTNode selectedNode, Collection<ICommandAccess> proposals) { 1236 ASTRewrite rewrite= ASTRewrite.create(selectedNode.getAST()); 1237 rewrite.remove(selectedNode, null); 1238 1239 String label= CorrectionMessages.LocalCorrectionsSubProcessor_removeunreachablecode_description; 1240 addRemoveProposal(context, rewrite, label, proposals); 1241 } 1242 addRemoveIncludingConditionProposal(IInvocationContext context, ASTNode toRemove, ASTNode replacement, Collection<ICommandAccess> proposals)1243 private static void addRemoveIncludingConditionProposal(IInvocationContext context, ASTNode toRemove, ASTNode replacement, Collection<ICommandAccess> proposals) { 1244 Image image= PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE); 1245 String label= CorrectionMessages.LocalCorrectionsSubProcessor_removeunreachablecode_including_condition_description; 1246 AST ast= toRemove.getAST(); 1247 ASTRewrite rewrite= ASTRewrite.create(ast); 1248 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.REMOVE_UNREACHABLE_CODE_INCLUDING_CONDITION, image); 1249 1250 if (replacement == null 1251 || replacement instanceof EmptyStatement 1252 || replacement instanceof Block && ((Block)replacement).statements().size() == 0) { 1253 if (ASTNodes.isControlStatementBody(toRemove.getLocationInParent())) { 1254 rewrite.replace(toRemove, toRemove.getAST().newBlock(), null); 1255 } else { 1256 rewrite.remove(toRemove, null); 1257 } 1258 1259 } else if (toRemove instanceof Expression && replacement instanceof Expression) { 1260 Expression moved= (Expression) rewrite.createMoveTarget(replacement); 1261 Expression toRemoveExpression= (Expression) toRemove; 1262 Expression replacementExpression= (Expression) replacement; 1263 ITypeBinding explicitCast= ASTNodes.getExplicitCast(replacementExpression, toRemoveExpression); 1264 if (explicitCast != null) { 1265 CastExpression cast= ast.newCastExpression(); 1266 if (NecessaryParenthesesChecker.needsParentheses(replacementExpression, cast, CastExpression.EXPRESSION_PROPERTY)) { 1267 ParenthesizedExpression parenthesized= ast.newParenthesizedExpression(); 1268 parenthesized.setExpression(moved); 1269 moved= parenthesized; 1270 } 1271 cast.setExpression(moved); 1272 ImportRewrite imports= proposal.createImportRewrite(context.getASTRoot()); 1273 ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(toRemove, imports); 1274 cast.setType(imports.addImport(explicitCast, ast, importRewriteContext, TypeLocation.CAST)); 1275 moved= cast; 1276 } 1277 rewrite.replace(toRemove, moved, null); 1278 1279 } else { 1280 ASTNode parent= toRemove.getParent(); 1281 ASTNode moveTarget; 1282 if ((parent instanceof Block || parent instanceof SwitchStatement) && replacement instanceof Block) { 1283 ListRewrite listRewrite= rewrite.getListRewrite(replacement, Block.STATEMENTS_PROPERTY); 1284 List<Statement> list= ((Block)replacement).statements(); 1285 int lastIndex= list.size() - 1; 1286 moveTarget= listRewrite.createMoveTarget(list.get(0), list.get(lastIndex)); 1287 } else { 1288 moveTarget= rewrite.createMoveTarget(replacement); 1289 } 1290 1291 rewrite.replace(toRemove, moveTarget, null); 1292 } 1293 1294 proposals.add(proposal); 1295 } 1296 addRemoveProposal(IInvocationContext context, ASTRewrite rewrite, String label, Collection<ICommandAccess> proposals)1297 private static void addRemoveProposal(IInvocationContext context, ASTRewrite rewrite, String label, Collection<ICommandAccess> proposals) { 1298 Image image= PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE); 1299 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 10, image); 1300 proposals.add(proposal); 1301 } 1302 getUnusedObjectAllocationProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1303 public static void getUnusedObjectAllocationProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1304 CompilationUnit root= context.getASTRoot(); 1305 AST ast= root.getAST(); 1306 ASTNode selectedNode= problem.getCoveringNode(root); 1307 if (selectedNode == null) { 1308 return; 1309 } 1310 1311 ASTNode parent= selectedNode.getParent(); 1312 1313 if (parent instanceof ExpressionStatement) { 1314 ExpressionStatement expressionStatement= (ExpressionStatement) parent; 1315 Expression expr= expressionStatement.getExpression(); 1316 ITypeBinding exprType= expr.resolveTypeBinding(); 1317 1318 if (exprType != null && Bindings.isSuperType(ast.resolveWellKnownType("java.lang.Throwable"), exprType)) { //$NON-NLS-1$ 1319 ASTRewrite rewrite= ASTRewrite.create(ast); 1320 TightSourceRangeComputer sourceRangeComputer= new TightSourceRangeComputer(); 1321 rewrite.setTargetSourceRangeComputer(sourceRangeComputer); 1322 1323 ThrowStatement throwStatement= ast.newThrowStatement(); 1324 throwStatement.setExpression((Expression) rewrite.createMoveTarget(expr)); 1325 sourceRangeComputer.addTightSourceNode(expressionStatement); 1326 rewrite.replace(expressionStatement, throwStatement, null); 1327 1328 String label= CorrectionMessages.LocalCorrectionsSubProcessor_throw_allocated_description; 1329 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1330 LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.THROW_ALLOCATED_OBJECT, image); 1331 proposal.setEndPosition(rewrite.track(throwStatement)); 1332 proposals.add(proposal); 1333 } 1334 1335 MethodDeclaration method= ASTResolving.findParentMethodDeclaration(selectedNode); 1336 if (method != null && !method.isConstructor()) { 1337 ASTRewrite rewrite= ASTRewrite.create(ast); 1338 TightSourceRangeComputer sourceRangeComputer= new TightSourceRangeComputer(); 1339 rewrite.setTargetSourceRangeComputer(sourceRangeComputer); 1340 1341 ReturnStatement returnStatement= ast.newReturnStatement(); 1342 returnStatement.setExpression((Expression) rewrite.createMoveTarget(expr)); 1343 sourceRangeComputer.addTightSourceNode(expressionStatement); 1344 rewrite.replace(expressionStatement, returnStatement, null); 1345 1346 String label= CorrectionMessages.LocalCorrectionsSubProcessor_return_allocated_description; 1347 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1348 int relevance; 1349 ITypeBinding returnTypeBinding= method.getReturnType2().resolveBinding(); 1350 if (returnTypeBinding != null && exprType != null && exprType.isAssignmentCompatible(returnTypeBinding)) { 1351 relevance= IProposalRelevance.RETURN_ALLOCATED_OBJECT_MATCH; 1352 } else if (method.getReturnType2() instanceof PrimitiveType 1353 && ((PrimitiveType)method.getReturnType2()).getPrimitiveTypeCode() == PrimitiveType.VOID) { 1354 relevance= IProposalRelevance.RETURN_ALLOCATED_OBJECT_VOID; 1355 } else { 1356 relevance= IProposalRelevance.RETURN_ALLOCATED_OBJECT; 1357 } 1358 LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, context.getCompilationUnit(), rewrite, relevance, image); 1359 proposal.setEndPosition(rewrite.track(returnStatement)); 1360 proposals.add(proposal); 1361 } 1362 1363 { 1364 ASTRewrite rewrite= ASTRewrite.create(ast); 1365 rewrite.remove(parent, null); 1366 1367 String label= CorrectionMessages.LocalCorrectionsSubProcessor_remove_allocated_description; 1368 Image image= PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE); 1369 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.REMOVE_UNUSED_ALLOCATED_OBJECT, image); 1370 proposals.add(proposal); 1371 } 1372 1373 } 1374 1375 QuickAssistProcessor.getAssignToVariableProposals(context, selectedNode, null, proposals); 1376 } 1377 getAssignmentHasNoEffectProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1378 public static void getAssignmentHasNoEffectProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1379 CompilationUnit root= context.getASTRoot(); 1380 ASTNode selectedNode= problem.getCoveringNode(root); 1381 if (!(selectedNode instanceof Assignment)) { 1382 return; 1383 } 1384 ASTNode assignedNode= ((Assignment) selectedNode).getLeftHandSide(); 1385 ASTNode assignExpression= ((Assignment) selectedNode).getRightHandSide(); 1386 if (!(assignedNode instanceof SimpleName) && !(assignExpression instanceof SimpleName)) { 1387 return; 1388 } 1389 1390 IBinding binding= (assignedNode instanceof SimpleName) ? ((SimpleName) assignedNode).resolveBinding() : ((SimpleName) assignExpression).resolveBinding(); 1391 if (!(binding instanceof IVariableBinding)) { 1392 return; 1393 } 1394 ITypeBinding typeBinding= Bindings.getBindingOfParentType(selectedNode); 1395 if (typeBinding == null) { 1396 return; 1397 } 1398 IVariableBinding fieldBinding= Bindings.findFieldInHierarchy(typeBinding, binding.getName()); 1399 if (fieldBinding == null || fieldBinding.getDeclaringClass() != typeBinding && Modifier.isPrivate(fieldBinding.getModifiers())) { 1400 return; 1401 } 1402 1403 if (binding != fieldBinding) { 1404 if (assignedNode instanceof SimpleName) { 1405 String label= CorrectionMessages.LocalCorrectionsSubProcessor_qualify_left_hand_side_description; 1406 proposals.add(createNoSideEffectProposal(context, (SimpleName) assignedNode, fieldBinding, label, IProposalRelevance.QUALIFY_LHS)); 1407 } 1408 if (assignExpression instanceof SimpleName) { 1409 String label= CorrectionMessages.LocalCorrectionsSubProcessor_qualify_right_hand_side_description; 1410 proposals.add(createNoSideEffectProposal(context, (SimpleName) assignExpression, fieldBinding, label, IProposalRelevance.QUALIFY_RHS)); 1411 } 1412 } 1413 1414 if (binding == fieldBinding && ASTResolving.findParentBodyDeclaration(selectedNode) instanceof MethodDeclaration) { 1415 SimpleName simpleName= (SimpleName) ((assignedNode instanceof SimpleName) ? assignedNode : assignExpression); 1416 String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createparameter_description, BasicElementLabels.getJavaElementName(simpleName.getIdentifier())); 1417 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL); 1418 proposals.add(new NewVariableCorrectionProposal(label, context.getCompilationUnit(), NewVariableCorrectionProposal.PARAM, simpleName, null, IProposalRelevance.CREATE_PARAMETER, image)); 1419 } 1420 1421 1422 } 1423 createNoSideEffectProposal(IInvocationContext context, SimpleName nodeToQualify, IVariableBinding fieldBinding, String label, int relevance)1424 private static ASTRewriteCorrectionProposal createNoSideEffectProposal(IInvocationContext context, SimpleName nodeToQualify, IVariableBinding fieldBinding, String label, int relevance) { 1425 AST ast= nodeToQualify.getAST(); 1426 1427 Expression qualifier; 1428 if (Modifier.isStatic(fieldBinding.getModifiers())) { 1429 ITypeBinding declaringClass= fieldBinding.getDeclaringClass(); 1430 qualifier= ast.newSimpleName(declaringClass.getTypeDeclaration().getName()); 1431 } else { 1432 qualifier= ast.newThisExpression(); 1433 } 1434 1435 ASTRewrite rewrite= ASTRewrite.create(ast); 1436 FieldAccess access= ast.newFieldAccess(); 1437 access.setName((SimpleName) rewrite.createCopyTarget(nodeToQualify)); 1438 access.setExpression(qualifier); 1439 rewrite.replace(nodeToQualify, access, null); 1440 1441 1442 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1443 return new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, relevance, image); 1444 } 1445 addValueForAnnotationProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1446 public static void addValueForAnnotationProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1447 ICompilationUnit cu= context.getCompilationUnit(); 1448 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 1449 if (selectedNode instanceof Annotation) { 1450 Annotation annotation= (Annotation) selectedNode; 1451 if (annotation.resolveTypeBinding() == null) { 1452 return; 1453 } 1454 MissingAnnotationAttributesProposal proposal= new MissingAnnotationAttributesProposal(cu, annotation, 10); 1455 proposals.add(proposal); 1456 } 1457 } 1458 addTypePrametersToRawTypeReference(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1459 public static void addTypePrametersToRawTypeReference(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1460 IProposableFix fix= Java50Fix.createRawTypeReferenceFix(context.getASTRoot(), problem); 1461 if (fix != null) { 1462 for (ICommandAccess element : proposals) { 1463 if (element instanceof FixCorrectionProposal) { 1464 FixCorrectionProposal fixProp= (FixCorrectionProposal)element; 1465 if (RAW_TYPE_REFERENCE_ID.equals(fixProp.getCommandId())) { 1466 return; 1467 } 1468 } 1469 } 1470 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1471 Map<String, String> options= new Hashtable<>(); 1472 options.put(CleanUpConstants.VARIABLE_DECLARATION_USE_TYPE_ARGUMENTS_FOR_RAW_TYPE_REFERENCES, CleanUpOptions.TRUE); 1473 FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new Java50CleanUp(options), IProposalRelevance.RAW_TYPE_REFERENCE, image, context); 1474 proposal.setCommandId(RAW_TYPE_REFERENCE_ID); 1475 proposals.add(proposal); 1476 } 1477 1478 //Infer Generic Type Arguments... proposal 1479 boolean hasInferTypeArgumentsProposal= false; 1480 for (ICommandAccess completionProposal : proposals) { 1481 if (completionProposal instanceof ChangeCorrectionProposal) { 1482 if (IJavaEditorActionDefinitionIds.INFER_TYPE_ARGUMENTS_ACTION.equals(((ChangeCorrectionProposal)completionProposal).getCommandId())) { 1483 hasInferTypeArgumentsProposal= true; 1484 break; 1485 } 1486 } 1487 } 1488 if (! hasInferTypeArgumentsProposal) { 1489 final ICompilationUnit cu= context.getCompilationUnit(); 1490 ChangeCorrectionProposal proposal= new ChangeCorrectionProposal(CorrectionMessages.LocalCorrectionsSubProcessor_InferGenericTypeArguments, null, IProposalRelevance.INFER_GENERIC_TYPE_ARGUMENTS, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE)) { 1491 @Override 1492 public void apply(IDocument document) { 1493 IEditorInput input= new FileEditorInput((IFile) cu.getResource()); 1494 IWorkbenchPage p= JavaPlugin.getActivePage(); 1495 if (p == null) 1496 return; 1497 1498 IEditorPart part= p.findEditor(input); 1499 if (!(part instanceof JavaEditor)) 1500 return; 1501 1502 IEditorSite site= ((JavaEditor)part).getEditorSite(); 1503 InferTypeArgumentsAction action= new InferTypeArgumentsAction(site); 1504 action.run(new StructuredSelection(cu)); 1505 } 1506 1507 @Override 1508 public Object getAdditionalProposalInfo(IProgressMonitor monitor) { 1509 return CorrectionMessages.LocalCorrectionsSubProcessor_InferGenericTypeArguments_description; 1510 } 1511 }; 1512 proposal.setCommandId(IJavaEditorActionDefinitionIds.INFER_TYPE_ARGUMENTS_ACTION); 1513 proposals.add(proposal); 1514 } 1515 1516 addTypeArgumentsFromContext(context, problem, proposals); 1517 } 1518 addTypeArgumentsFromContext(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1519 private static void addTypeArgumentsFromContext(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1520 // similar to UnresolvedElementsSubProcessor.getTypeProposals(context, problem, proposals); 1521 1522 ICompilationUnit cu= context.getCompilationUnit(); 1523 1524 CompilationUnit root= context.getASTRoot(); 1525 ASTNode selectedNode= problem.getCoveringNode(root); 1526 if (selectedNode == null) { 1527 return; 1528 } 1529 1530 while (selectedNode.getLocationInParent() == QualifiedName.NAME_PROPERTY) { 1531 selectedNode= selectedNode.getParent(); 1532 } 1533 1534 Name node= null; 1535 if (selectedNode instanceof SimpleType) { 1536 node= ((SimpleType) selectedNode).getName(); 1537 } else if (selectedNode instanceof NameQualifiedType) { 1538 node= ((NameQualifiedType) selectedNode).getName(); 1539 } else if (selectedNode instanceof ArrayType) { 1540 Type elementType= ((ArrayType) selectedNode).getElementType(); 1541 if (elementType.isSimpleType()) { 1542 node= ((SimpleType) elementType).getName(); 1543 } else if (elementType.isNameQualifiedType()) { 1544 node= ((NameQualifiedType) elementType).getName(); 1545 } else { 1546 return; 1547 } 1548 } else if (selectedNode instanceof Name) { 1549 node= (Name) selectedNode; 1550 } else { 1551 return; 1552 } 1553 1554 // try to resolve type in context 1555 ITypeBinding binding= ASTResolving.guessBindingForTypeReference(node); 1556 if (binding != null) { 1557 ASTNode parent= node.getParent(); 1558 if (parent instanceof Type && parent.getLocationInParent() == ClassInstanceCreation.TYPE_PROPERTY && binding.isInterface()) { //bug 351853 1559 return; 1560 } 1561 ITypeBinding simpleBinding= binding; 1562 if (simpleBinding.isArray()) { 1563 simpleBinding= simpleBinding.getElementType(); 1564 } 1565 simpleBinding= simpleBinding.getTypeDeclaration(); 1566 1567 if (!simpleBinding.isRecovered()) { 1568 if (binding.isParameterizedType() && (node.getParent() instanceof SimpleType || node.getParent() instanceof NameQualifiedType) && !(node.getParent().getParent() instanceof Type)) { 1569 proposals.add(UnresolvedElementsSubProcessor.createTypeRefChangeFullProposal(cu, binding, node, IProposalRelevance.TYPE_ARGUMENTS_FROM_CONTEXT, TypeLocation.TYPE_ARGUMENT)); 1570 } 1571 } 1572 } else { 1573 ASTNode normalizedNode= ASTNodes.getNormalizedNode(node); 1574 if (!(normalizedNode.getParent() instanceof Type) && node.getParent() != normalizedNode) { 1575 ITypeBinding normBinding= ASTResolving.guessBindingForTypeReference(normalizedNode); 1576 if (normBinding != null && !normBinding.isRecovered()) { 1577 proposals.add(UnresolvedElementsSubProcessor.createTypeRefChangeFullProposal(cu, normBinding, normalizedNode, IProposalRelevance.TYPE_ARGUMENTS_FROM_CONTEXT, TypeLocation.TYPE_ARGUMENT)); 1578 } 1579 } 1580 } 1581 } 1582 addRemoveRedundantTypeArgumentsProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1583 public static void addRemoveRedundantTypeArgumentsProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1584 IProposableFix fix= TypeParametersFix.createRemoveRedundantTypeArgumentsFix(context.getASTRoot(), problem); 1585 if (fix != null) { 1586 Image image= PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE); 1587 Map<String, String> options= new HashMap<>(); 1588 options.put(CleanUpConstants.REMOVE_REDUNDANT_TYPE_ARGUMENTS, CleanUpOptions.TRUE); 1589 FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new TypeParametersCleanUp(options), IProposalRelevance.REMOVE_REDUNDANT_TYPE_ARGUMENTS, image, context); 1590 proposals.add(proposal); 1591 } 1592 } 1593 addFallThroughProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1594 public static void addFallThroughProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1595 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 1596 if (selectedNode instanceof SwitchCase && selectedNode.getLocationInParent() == SwitchStatement.STATEMENTS_PROPERTY) { 1597 AST ast= selectedNode.getAST(); 1598 ASTNode parent= selectedNode.getParent(); 1599 1600 // insert break: 1601 ASTRewrite rewrite= ASTRewrite.create(ast); 1602 ListRewrite listRewrite= rewrite.getListRewrite(parent, SwitchStatement.STATEMENTS_PROPERTY); 1603 listRewrite.insertBefore(ast.newBreakStatement(), selectedNode, null); 1604 1605 String label= CorrectionMessages.LocalCorrectionsSubProcessor_insert_break_statement; 1606 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1607 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.INSERT_BREAK_STATEMENT, image); 1608 proposals.add(proposal); 1609 1610 // insert //$FALL-THROUGH$: 1611 rewrite= ASTRewrite.create(ast); 1612 rewrite.setTargetSourceRangeComputer(new NoCommentSourceRangeComputer()); 1613 listRewrite= rewrite.getListRewrite(parent, SwitchStatement.STATEMENTS_PROPERTY); 1614 ASTNode fallThroughComment= rewrite.createStringPlaceholder("//$FALL-THROUGH$", ASTNode.EMPTY_STATEMENT); //$NON-NLS-1$ 1615 listRewrite.insertBefore(fallThroughComment, selectedNode, null); 1616 1617 label= CorrectionMessages.LocalCorrectionsSubProcessor_insert_fall_through; 1618 image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1619 proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.INSERT_FALL_THROUGH, image); 1620 proposals.add(proposal); 1621 } 1622 } 1623 addCasesOmittedProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1624 public static void addCasesOmittedProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1625 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 1626 if (selectedNode instanceof Expression && selectedNode.getLocationInParent() == SwitchStatement.EXPRESSION_PROPERTY) { 1627 AST ast= selectedNode.getAST(); 1628 SwitchStatement parent= (SwitchStatement) selectedNode.getParent(); 1629 1630 for (Statement statement : (List<Statement>) parent.statements()) { 1631 if (statement instanceof SwitchCase && ((SwitchCase) statement).isDefault()) { 1632 1633 // insert //$CASES-OMITTED$: 1634 ASTRewrite rewrite= ASTRewrite.create(ast); 1635 rewrite.setTargetSourceRangeComputer(new NoCommentSourceRangeComputer()); 1636 ListRewrite listRewrite= rewrite.getListRewrite(parent, SwitchStatement.STATEMENTS_PROPERTY); 1637 ASTNode casesOmittedComment= rewrite.createStringPlaceholder("//$CASES-OMITTED$", ASTNode.EMPTY_STATEMENT); //$NON-NLS-1$ 1638 listRewrite.insertBefore(casesOmittedComment, statement, null); 1639 1640 String label= CorrectionMessages.LocalCorrectionsSubProcessor_insert_cases_omitted; 1641 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1642 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.INSERT_CASES_OMITTED, image); 1643 proposals.add(proposal); 1644 break; 1645 } 1646 } 1647 } 1648 } 1649 addDeprecatedFieldsToMethodsProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1650 public static void addDeprecatedFieldsToMethodsProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1651 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 1652 if (selectedNode instanceof Name) { 1653 IBinding binding= ((Name) selectedNode).resolveBinding(); 1654 if (binding instanceof IVariableBinding) { 1655 IVariableBinding variableBinding= (IVariableBinding) binding; 1656 if (variableBinding.isField()) { 1657 String qualifiedName= variableBinding.getDeclaringClass().getTypeDeclaration().getQualifiedName(); 1658 String fieldName= variableBinding.getName(); 1659 String[] methodName= getMethod(JavaModelUtil.concatenateName(qualifiedName, fieldName)); 1660 if (methodName != null) { 1661 AST ast= selectedNode.getAST(); 1662 ASTRewrite astRewrite= ASTRewrite.create(ast); 1663 ImportRewrite importRewrite= StubUtility.createImportRewrite(context.getASTRoot(), true); 1664 1665 MethodInvocation method= ast.newMethodInvocation(); 1666 String qfn= importRewrite.addImport(methodName[0]); 1667 method.setExpression(ast.newName(qfn)); 1668 method.setName(ast.newSimpleName(methodName[1])); 1669 ASTNode parent= selectedNode.getParent(); 1670 ICompilationUnit cu= context.getCompilationUnit(); 1671 // add explicit type arguments if necessary (for 1.8 and later, we're optimistic that inference just works): 1672 if (Invocations.isInvocationWithArguments(parent) && !JavaModelUtil.is18OrHigher(cu.getJavaProject())) { 1673 IMethodBinding methodBinding= Invocations.resolveBinding(parent); 1674 if (methodBinding != null) { 1675 ITypeBinding[] parameterTypes= methodBinding.getParameterTypes(); 1676 int i= Invocations.getArguments(parent).indexOf(selectedNode); 1677 if (parameterTypes.length >= i && parameterTypes[i].isParameterizedType()) { 1678 ITypeBinding[] typeArguments= parameterTypes[i].getTypeArguments(); 1679 for (ITypeBinding typeArgument : typeArguments) { 1680 typeArgument= Bindings.normalizeForDeclarationUse(typeArgument, ast); 1681 if (! TypeRules.isJavaLangObject(typeArgument)) { 1682 // add all type arguments if at least one is found to be necessary: 1683 List<Type> typeArgumentsList= method.typeArguments(); 1684 for (ITypeBinding t : typeArguments) { 1685 typeArgument= Bindings.normalizeForDeclarationUse(t, ast); 1686 typeArgumentsList.add(importRewrite.addImport(typeArgument, ast)); 1687 } 1688 break; 1689 } 1690 } 1691 } 1692 } 1693 } 1694 1695 astRewrite.replace(selectedNode, method, null); 1696 1697 String label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_replacefieldaccesswithmethod_description, BasicElementLabels.getJavaElementName(ASTNodes.asString(method))); 1698 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1699 ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, cu, astRewrite, IProposalRelevance.REPLACE_FIELD_ACCESS_WITH_METHOD, image); 1700 proposal.setImportRewrite(importRewrite); 1701 proposals.add(proposal); 1702 } 1703 } 1704 } 1705 } 1706 } 1707 1708 private static Map<String, String[]> resolveMap; getMethod(String fieldName)1709 private static String[] getMethod(String fieldName) { 1710 if (resolveMap==null){ 1711 resolveMap=new HashMap<>(); 1712 resolveMap.put("java.util.Collections.EMPTY_MAP", new String[]{"java.util.Collections","emptyMap"}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ 1713 resolveMap.put("java.util.Collections.EMPTY_SET", new String[]{"java.util.Collections","emptySet"}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ 1714 resolveMap.put("java.util.Collections.EMPTY_LIST", new String[]{"java.util.Collections","emptyList"});//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ 1715 } 1716 return resolveMap.get(fieldName); 1717 } 1718 getMissingEnumConstantCaseProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals)1719 public static void getMissingEnumConstantCaseProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1720 for (ICommandAccess proposal : proposals) { 1721 if (proposal instanceof ChangeCorrectionProposal) { 1722 if (CorrectionMessages.LocalCorrectionsSubProcessor_add_missing_cases_description.equals(((ChangeCorrectionProposal) proposal).getName())) { 1723 return; 1724 } 1725 } 1726 } 1727 1728 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 1729 if (selectedNode instanceof Expression) { 1730 StructuralPropertyDescriptor locationInParent= selectedNode.getLocationInParent(); 1731 ASTNode parent= selectedNode.getParent(); 1732 ITypeBinding binding; 1733 List<Statement> statements; 1734 1735 if (locationInParent == SwitchStatement.EXPRESSION_PROPERTY) { 1736 SwitchStatement statement= (SwitchStatement) parent; 1737 binding= statement.getExpression().resolveTypeBinding(); 1738 statements= statement.statements(); 1739 } else if (locationInParent == SwitchExpression.EXPRESSION_PROPERTY) { 1740 SwitchExpression switchExpression= (SwitchExpression) parent; 1741 binding= switchExpression.getExpression().resolveTypeBinding(); 1742 statements= switchExpression.statements(); 1743 } else { 1744 return; 1745 } 1746 1747 if (binding == null || !binding.isEnum()) { 1748 return; 1749 } 1750 1751 ArrayList<String> missingEnumCases= new ArrayList<>(); 1752 boolean hasDefault= evaluateMissingSwitchCases(binding, statements, missingEnumCases); 1753 if (missingEnumCases.size() == 0 && hasDefault) 1754 return; 1755 1756 createMissingCaseProposals(context, parent, missingEnumCases, proposals); 1757 } 1758 } 1759 1760 @SuppressWarnings("deprecation") evaluateMissingSwitchCases(ITypeBinding enumBindings, List<Statement> switchStatements, ArrayList<String> enumConstNames)1761 public static boolean evaluateMissingSwitchCases(ITypeBinding enumBindings, List<Statement> switchStatements, ArrayList<String> enumConstNames) { 1762 for (IVariableBinding field : enumBindings.getDeclaredFields()) { 1763 if (field.isEnumConstant()) { 1764 enumConstNames.add(field.getName()); 1765 } 1766 } 1767 1768 boolean hasDefault=false; 1769 for (Statement curr : switchStatements) { 1770 if (curr instanceof SwitchCase) { 1771 SwitchCase switchCase= (SwitchCase) curr; 1772 if (ASTHelper.isSwitchCaseExpressionsSupportedInAST(switchCase.getAST())) { 1773 List<Expression> expressions= switchCase.expressions(); 1774 if (expressions.size() == 0) { 1775 hasDefault= true; 1776 } else { 1777 for (Expression expression : expressions) { 1778 if (expression instanceof SimpleName) { 1779 enumConstNames.remove(((SimpleName) expression).getFullyQualifiedName()); 1780 } 1781 } 1782 } 1783 } else { 1784 Expression expression= ((SwitchCase) curr).getExpression(); 1785 if (expression instanceof SimpleName) { 1786 enumConstNames.remove(((SimpleName) expression).getFullyQualifiedName()); 1787 } else if (expression == null) { 1788 hasDefault= true; 1789 } 1790 } 1791 } 1792 } 1793 return hasDefault; 1794 } 1795 1796 @SuppressWarnings("deprecation") createMissingCaseProposals(IInvocationContext context, ASTNode parent, ArrayList<String> enumConstNames, Collection<ICommandAccess> proposals)1797 public static void createMissingCaseProposals(IInvocationContext context, ASTNode parent, ArrayList<String> enumConstNames, Collection<ICommandAccess> proposals) { 1798 List<Statement> statements; 1799 Expression expression; 1800 if (parent instanceof SwitchStatement) { 1801 SwitchStatement switchStatement= (SwitchStatement) parent; 1802 statements= switchStatement.statements(); 1803 expression= switchStatement.getExpression(); 1804 } else if (parent instanceof SwitchExpression) { 1805 SwitchExpression switchExpression= (SwitchExpression) parent; 1806 statements= switchExpression.statements(); 1807 expression= switchExpression.getExpression(); 1808 } else { 1809 return; 1810 } 1811 int defaultIndex= statements.size(); 1812 for (int i= 0; i < statements.size(); i++) { 1813 Statement curr= statements.get(i); 1814 if (curr instanceof SwitchCase) { 1815 SwitchCase switchCase= (SwitchCase) curr; 1816 if (ASTHelper.isSwitchCaseExpressionsSupportedInAST(switchCase.getAST())) { 1817 if (switchCase.expressions().size() == 0) { 1818 defaultIndex= i; 1819 break; 1820 } 1821 } else if (switchCase.getExpression() == null) { 1822 defaultIndex= i; 1823 break; 1824 } 1825 } 1826 } 1827 boolean hasDefault= defaultIndex < statements.size(); 1828 1829 AST ast= parent.getAST(); 1830 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1831 1832 if (enumConstNames.size() > 0) { 1833 ASTRewrite astRewrite= ASTRewrite.create(ast); 1834 ListRewrite listRewrite; 1835 if (parent instanceof SwitchStatement) { 1836 listRewrite= astRewrite.getListRewrite(parent, SwitchStatement.STATEMENTS_PROPERTY); 1837 } else { 1838 listRewrite= astRewrite.getListRewrite(parent, SwitchExpression.STATEMENTS_PROPERTY); 1839 } 1840 1841 String label= CorrectionMessages.LocalCorrectionsSubProcessor_add_missing_cases_description; 1842 LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, context.getCompilationUnit(), astRewrite, IProposalRelevance.ADD_MISSING_CASE_STATEMENTS, image); 1843 1844 for (String enumConstName : enumConstNames) { 1845 SwitchCase newSwitchCase= ast.newSwitchCase(); 1846 Name newName= ast.newName(enumConstName); 1847 if (ASTHelper.isSwitchCaseExpressionsSupportedInAST(ast)) { 1848 newSwitchCase.expressions().add(newName); 1849 } else { 1850 newSwitchCase.setExpression(newName); 1851 } 1852 listRewrite.insertAt(newSwitchCase, defaultIndex, null); 1853 defaultIndex++; 1854 if (!hasDefault) { 1855 if (ASTHelper.isSwitchExpressionNodeSupportedInAST(ast)) { 1856 if (statements.size() > 0) { 1857 Statement firstStatement= statements.get(0); 1858 SwitchCase switchCase= (SwitchCase) firstStatement; 1859 boolean isArrow= switchCase.isSwitchLabeledRule(); 1860 newSwitchCase.setSwitchLabeledRule(isArrow); 1861 if (isArrow || parent instanceof SwitchExpression) { 1862 ThrowStatement newThrowStatement= getThrowForUnsupportedCase(expression, ast, astRewrite); 1863 listRewrite.insertLast(newThrowStatement, null); 1864 proposal.addLinkedPosition(astRewrite.track(newThrowStatement), true, enumConstName); 1865 } else { 1866 listRewrite.insertAt(ast.newBreakStatement(), defaultIndex, null); 1867 } 1868 } else { 1869 listRewrite.insertAt(ast.newBreakStatement(), defaultIndex, null); 1870 } 1871 } else { 1872 listRewrite.insertAt(ast.newBreakStatement(), defaultIndex, null); 1873 } 1874 1875 defaultIndex++; 1876 } 1877 } 1878 if (!hasDefault) { 1879 SwitchCase newSwitchCase= ast.newSwitchCase(); 1880 listRewrite.insertAt(newSwitchCase, defaultIndex, null); 1881 defaultIndex++; 1882 1883 if (ASTHelper.isSwitchExpressionNodeSupportedInAST(ast)) { 1884 if (statements.size() > 0) { 1885 Statement firstStatement= statements.get(0); 1886 SwitchCase switchCase= (SwitchCase) firstStatement; 1887 boolean isArrow= switchCase.isSwitchLabeledRule(); 1888 newSwitchCase.setSwitchLabeledRule(isArrow); 1889 if (isArrow || parent instanceof SwitchExpression) { 1890 ThrowStatement newThrowStatement= getThrowForUnexpectedDefault(expression, ast, astRewrite); 1891 listRewrite.insertLast(newThrowStatement, null); 1892 proposal.addLinkedPosition(astRewrite.track(newThrowStatement), true, "defaultCase"); //$NON-NLS-1$ 1893 } else { 1894 listRewrite.insertAt(ast.newBreakStatement(), defaultIndex, null); 1895 } 1896 } else { 1897 listRewrite.insertAt(ast.newBreakStatement(), defaultIndex, null); 1898 } 1899 } else { 1900 newSwitchCase.setExpression(null); 1901 listRewrite.insertAt(ast.newBreakStatement(), defaultIndex, null); 1902 } 1903 } 1904 proposals.add(proposal); 1905 } 1906 if (!hasDefault) { 1907 createMissingDefaultProposal(context, parent, image, proposals); 1908 } 1909 } 1910 1911 private static ThrowStatement getThrowForUnsupportedCase(Expression switchExpr, AST ast, ASTRewrite astRewrite) { 1912 ThrowStatement newThrowStatement= ast.newThrowStatement(); 1913 ClassInstanceCreation newCic= ast.newClassInstanceCreation(); 1914 newCic.setType(ast.newSimpleType(ast.newSimpleName("UnsupportedOperationException"))); //$NON-NLS-1$ 1915 InfixExpression newInfixExpr= ast.newInfixExpression(); 1916 StringLiteral newStringLiteral= ast.newStringLiteral(); 1917 newStringLiteral.setLiteralValue("Unimplemented case: "); //$NON-NLS-1$ 1918 newInfixExpr.setLeftOperand(newStringLiteral); 1919 newInfixExpr.setOperator(InfixExpression.Operator.PLUS); 1920 newInfixExpr.setRightOperand((Expression) astRewrite.createCopyTarget(switchExpr)); 1921 newCic.arguments().add(newInfixExpr); 1922 newThrowStatement.setExpression(newCic); 1923 return newThrowStatement; 1924 } 1925 1926 public static void addMissingDefaultCaseProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 1927 ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot()); 1928 if (selectedNode instanceof Expression) { 1929 StructuralPropertyDescriptor locationInParent= selectedNode.getLocationInParent(); 1930 ASTNode parent= selectedNode.getParent(); 1931 List<Statement> statements; 1932 1933 if (locationInParent == SwitchStatement.EXPRESSION_PROPERTY) { 1934 statements= ((SwitchStatement) parent).statements(); 1935 } else if (locationInParent == SwitchExpression.EXPRESSION_PROPERTY) { 1936 statements= ((SwitchExpression) parent).statements(); 1937 } else { 1938 return; 1939 } 1940 1941 for (Statement statement : statements) { 1942 if (statement instanceof SwitchCase && ((SwitchCase) statement).isDefault()) { 1943 return; 1944 } 1945 } 1946 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 1947 createMissingDefaultProposal(context, parent, image, proposals); 1948 } 1949 } 1950 1951 @SuppressWarnings("deprecation") 1952 private static void createMissingDefaultProposal(IInvocationContext context, ASTNode parent, Image image, Collection<ICommandAccess> proposals) { 1953 List<Statement> statements; 1954 Expression expression; 1955 if (parent instanceof SwitchStatement) { 1956 SwitchStatement switchStatement= (SwitchStatement) parent; 1957 statements= switchStatement.statements(); 1958 expression= switchStatement.getExpression(); 1959 } else if (parent instanceof SwitchExpression) { 1960 SwitchExpression switchExpression= (SwitchExpression) parent; 1961 statements= switchExpression.statements(); 1962 expression= switchExpression.getExpression(); 1963 } else { 1964 return; 1965 } 1966 AST ast= parent.getAST(); 1967 ASTRewrite astRewrite= ASTRewrite.create(ast); 1968 ListRewrite listRewrite; 1969 if (parent instanceof SwitchStatement) { 1970 listRewrite= astRewrite.getListRewrite(parent, SwitchStatement.STATEMENTS_PROPERTY); 1971 } else { 1972 listRewrite= astRewrite.getListRewrite(parent, SwitchExpression.STATEMENTS_PROPERTY); 1973 } 1974 String label= CorrectionMessages.LocalCorrectionsSubProcessor_add_default_case_description; 1975 LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, context.getCompilationUnit(), astRewrite, IProposalRelevance.ADD_MISSING_DEFAULT_CASE, image); 1976 1977 SwitchCase newSwitchCase= ast.newSwitchCase(); 1978 listRewrite.insertLast(newSwitchCase, null); 1979 1980 if (ASTHelper.isSwitchCaseExpressionsSupportedInAST(ast)) { 1981 if (statements.size() > 0) { 1982 Statement firstStatement= statements.get(0); 1983 SwitchCase switchCase= (SwitchCase) firstStatement; 1984 boolean isArrow= switchCase.isSwitchLabeledRule(); 1985 newSwitchCase.setSwitchLabeledRule(isArrow); 1986 if (isArrow || parent instanceof SwitchExpression) { 1987 ThrowStatement newThrowStatement= getThrowForUnexpectedDefault(expression, ast, astRewrite); 1988 listRewrite.insertLast(newThrowStatement, null); 1989 proposal.addLinkedPosition(astRewrite.track(newThrowStatement), true, null); 1990 } else { 1991 listRewrite.insertLast(ast.newBreakStatement(), null); 1992 } 1993 } else { 1994 listRewrite.insertLast(ast.newBreakStatement(), null); 1995 } 1996 } else { 1997 newSwitchCase.setExpression(null); 1998 listRewrite.insertLast(ast.newBreakStatement(), null); 1999 } 2000 2001 proposals.add(proposal); 2002 } 2003 2004 private static ThrowStatement getThrowForUnexpectedDefault(Expression switchExpression, AST ast, ASTRewrite astRewrite) { 2005 ThrowStatement newThrowStatement= ast.newThrowStatement(); 2006 ClassInstanceCreation newCic= ast.newClassInstanceCreation(); 2007 newCic.setType(ast.newSimpleType(ast.newSimpleName("IllegalArgumentException"))); //$NON-NLS-1$ 2008 InfixExpression newInfixExpr= ast.newInfixExpression(); 2009 StringLiteral newStringLiteral= ast.newStringLiteral(); 2010 newStringLiteral.setLiteralValue("Unexpected value: "); //$NON-NLS-1$ 2011 newInfixExpr.setLeftOperand(newStringLiteral); 2012 newInfixExpr.setOperator(InfixExpression.Operator.PLUS); 2013 newInfixExpr.setRightOperand((Expression) astRewrite.createCopyTarget(switchExpression)); 2014 newCic.arguments().add(newInfixExpr); 2015 newThrowStatement.setExpression(newCic); 2016 return newThrowStatement; 2017 } 2018 2019 public static void addMissingHashCodeProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 2020 final ICompilationUnit cu= context.getCompilationUnit(); 2021 2022 CompilationUnit astRoot= context.getASTRoot(); 2023 ASTNode selectedNode= problem.getCoveringNode(astRoot); 2024 if (!(selectedNode instanceof Name)) { 2025 return; 2026 } 2027 2028 AbstractTypeDeclaration typeDeclaration= null; 2029 StructuralPropertyDescriptor locationInParent= selectedNode.getLocationInParent(); 2030 if (locationInParent != TypeDeclaration.NAME_PROPERTY && locationInParent != EnumDeclaration.NAME_PROPERTY) { 2031 return; 2032 } 2033 2034 typeDeclaration= (AbstractTypeDeclaration) selectedNode.getParent(); 2035 2036 ITypeBinding binding= typeDeclaration.resolveBinding(); 2037 if (binding == null || binding.getSuperclass() == null) { 2038 return; 2039 } 2040 final IType type= (IType) binding.getJavaElement(); 2041 2042 boolean hasInstanceFields= false; 2043 for (IVariableBinding declaredField : binding.getDeclaredFields()) { 2044 if (!Modifier.isStatic(declaredField.getModifiers())) { 2045 hasInstanceFields= true; 2046 break; 2047 } 2048 } 2049 if (hasInstanceFields) { 2050 //Generate hashCode() and equals()... proposal 2051 String label= CorrectionMessages.LocalCorrectionsSubProcessor_generate_hashCode_equals_description; 2052 Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); 2053 ChangeCorrectionProposal proposal= new ChangeCorrectionProposal(label, null, IProposalRelevance.GENERATE_HASHCODE_AND_EQUALS, image) { 2054 @Override 2055 public void apply(IDocument document) { 2056 IEditorInput input= new FileEditorInput((IFile) cu.getResource()); 2057 IWorkbenchPage p= JavaPlugin.getActivePage(); 2058 if (p == null) 2059 return; 2060 2061 IEditorPart part= p.findEditor(input); 2062 if (!(part instanceof JavaEditor)) 2063 return; 2064 2065 IEditorSite site= ((JavaEditor)part).getEditorSite(); 2066 GenerateHashCodeEqualsAction action= new GenerateHashCodeEqualsAction(site); 2067 action.run(new StructuredSelection(type)); 2068 } 2069 2070 @Override 2071 public Object getAdditionalProposalInfo(IProgressMonitor monitor) { 2072 return CorrectionMessages.LocalCorrectionsSubProcessor_generate_hashCode_equals_additional_info; 2073 } 2074 }; 2075 proposals.add(proposal); 2076 } 2077 2078 2079 //Override hashCode() proposal 2080 IMethodBinding superHashCode= Bindings.findMethodInHierarchy(binding, "hashCode", new ITypeBinding[0]); //$NON-NLS-1$ 2081 if (superHashCode == null) { 2082 return; 2083 } 2084 2085 String label= CorrectionMessages.LocalCorrectionsSubProcessor_override_hashCode_description; 2086 Image image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC); 2087 2088 ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST()); 2089 LinkedCorrectionProposal proposal2= new LinkedCorrectionProposal(label, cu, rewrite, IProposalRelevance.OVERRIDE_HASHCODE, image); 2090 ImportRewrite importRewrite= proposal2.createImportRewrite(astRoot); 2091 2092 final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject()); 2093 2094 try { 2095 ImportRewriteContext importContext= new ContextSensitiveImportRewriteContext(astRoot, problem.getOffset(), importRewrite); 2096 MethodDeclaration hashCode= StubUtility2.createImplementationStub(cu, rewrite, importRewrite, importContext, superHashCode, binding, settings, false, null); 2097 BodyDeclarationRewrite.create(rewrite, typeDeclaration).insert(hashCode, null); 2098 2099 proposal2.setEndPosition(rewrite.track(hashCode)); 2100 2101 } catch (CoreException e) { 2102 JavaPlugin.log(e); 2103 } 2104 2105 2106 proposals.add(proposal2); 2107 } 2108 2109 public static void getGenerateForLoopProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 2110 ASTNode coveringNode= problem.getCoveringNode(context.getASTRoot()); 2111 if (coveringNode != null) { 2112 QuickAssistProcessor.getGenerateForLoopProposals(context, coveringNode, null, proposals); 2113 } 2114 } 2115 2116 public static void getConvertLambdaToAnonymousClassCreationsProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 2117 ASTNode coveringNode= problem.getCoveringNode(context.getASTRoot()); 2118 if (coveringNode != null) { 2119 QuickAssistProcessor.getConvertLambdaToAnonymousClassCreationsProposals(context, coveringNode, proposals); 2120 } 2121 } 2122 2123 public static void addOverrideDefaultMethodProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { 2124 CompilationUnit astRoot= context.getASTRoot(); 2125 2126 ASTNode selectedNode= problem.getCoveringNode(astRoot); 2127 if (selectedNode == null) { 2128 return; 2129 } 2130 2131 StructuralPropertyDescriptor locationInParent= selectedNode.getLocationInParent(); 2132 if (locationInParent != TypeDeclaration.NAME_PROPERTY && locationInParent != EnumDeclaration.NAME_PROPERTY) { 2133 return; 2134 } 2135 2136 ASTNode typeNode= selectedNode.getParent(); 2137 if (typeNode == null) { 2138 return; 2139 } 2140 2141 ITypeBinding typeBinding= ((AbstractTypeDeclaration) typeNode).resolveBinding(); 2142 if (typeBinding == null) { 2143 return; 2144 } 2145 2146 if (problem.getProblemId() == IProblem.DuplicateInheritedDefaultMethods) { 2147 String[] args= problem.getProblemArguments(); 2148 if (args.length < 5) { 2149 return; 2150 } 2151 2152 String methodName= args[0]; 2153 if (methodName == null) { 2154 return; 2155 } 2156 2157 String[] parameters1= {}; 2158 if (args[1] != null && args[1].length() != 0) { 2159 parameters1= args[1].split(", "); //$NON-NLS-1$ 2160 } 2161 String[] parameters2= {}; 2162 if (args[2] != null && args[2].length() != 0) { 2163 parameters2= args[2].split(", "); //$NON-NLS-1$ 2164 } 2165 2166 addOverrideProposal(typeNode, typeBinding, methodName, parameters1, args[3], context, proposals); 2167 addOverrideProposal(typeNode, typeBinding, methodName, parameters2, args[4], context, proposals); 2168 2169 } else if (problem.getProblemId() == IProblem.InheritedDefaultMethodConflictsWithOtherInherited) { 2170 String[] args= problem.getProblemArguments(); 2171 if (args.length < 3) { 2172 return; 2173 } 2174 2175 String arg0= args[0]; 2176 if (arg0 == null) { 2177 return; 2178 } 2179 int indexOfLParen= arg0.indexOf('('); 2180 if (indexOfLParen == -1) { 2181 return; 2182 } 2183 int indexOfRParen= arg0.indexOf(')'); 2184 if (indexOfRParen == -1) { 2185 return; 2186 } 2187 2188 String methodName= arg0.substring(0, indexOfLParen); 2189 2190 String paramString= arg0.substring(indexOfLParen + 1, indexOfRParen); 2191 String[] parameters= {}; 2192 if (paramString != null && paramString.length() != 0) { 2193 parameters= paramString.split(", "); //$NON-NLS-1$ 2194 } 2195 2196 addOverrideProposal(typeNode, typeBinding, methodName, parameters, args[1], context, proposals); 2197 addOverrideProposal(typeNode, typeBinding, methodName, parameters, args[2], context, proposals); 2198 2199 } 2200 } 2201 2202 private static void addOverrideProposal(ASTNode typeNode, ITypeBinding typeBinding, String methodName, String[] parameters, String superType, 2203 IInvocationContext context, Collection<ICommandAccess> proposals) { 2204 ITypeBinding superTypeBinding= null; 2205 if (superType != null) { 2206 int i= superType.indexOf('<'); 2207 if (i > 0) { 2208 superType= superType.substring(0, i); 2209 } 2210 superTypeBinding= Bindings.findTypeInHierarchy(typeBinding, superType); 2211 } 2212 if (superTypeBinding == null) { 2213 return; 2214 } 2215 2216 IMethodBinding methodToOverride= Bindings.findMethodWithDeclaredParameterTypesInType(superTypeBinding, methodName, parameters); 2217 if (methodToOverride == null) { 2218 return; 2219 } 2220 2221 String label; 2222 int modifiers= methodToOverride.getModifiers(); 2223 if (Modifier.isDefault(modifiers)) { 2224 label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_override_default_method_description, superTypeBinding.getName()); 2225 } else if (Modifier.isAbstract(modifiers)) { 2226 label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_implement_method_description, superTypeBinding.getName()); 2227 } else { 2228 label= Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_override_method_description, superTypeBinding.getName()); 2229 } 2230 Image image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC); 2231 2232 CompilationUnit astRoot= context.getASTRoot(); 2233 ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST()); 2234 ICompilationUnit cu= context.getCompilationUnit(); 2235 LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, cu, rewrite, IProposalRelevance.OVERRIDE_DEFAULT_METHOD, image); 2236 2237 ImportRewrite importRewrite= proposal.createImportRewrite(astRoot); 2238 ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(astRoot, typeNode.getStartPosition(), importRewrite); 2239 CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject()); 2240 try { 2241 MethodDeclaration stub= StubUtility2.createImplementationStub(cu, rewrite, importRewrite, importRewriteContext, methodToOverride, typeBinding, settings, 2242 typeBinding.isInterface(), new NodeFinder(astRoot, typeNode.getStartPosition(), 0).getCoveringNode()); 2243 BodyDeclarationRewrite.create(rewrite, typeNode).insert(stub, null); 2244 2245 proposal.setEndPosition(rewrite.track(stub)); 2246 } catch (CoreException e) { 2247 JavaPlugin.log(e); 2248 } 2249 2250 proposals.add(proposal); 2251 } 2252 2253 public static void addServiceProviderProposal (IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException { 2254 ASTNode node= problem.getCoveredNode(context.getASTRoot()); 2255 if (! (node instanceof Name) && ! (node.getParent() instanceof ProvidesDirective)) { 2256 return; 2257 } 2258 2259 Name name= (Name) node; 2260 ProvidesDirective prov= (ProvidesDirective) name.getParent(); 2261 ITypeBinding targetBinding= name.resolveTypeBinding(); 2262 ITypeBinding serviceBinding= prov.getName().resolveTypeBinding(); 2263 if (targetBinding != null && serviceBinding != null) { 2264 ICompilationUnit targetCU= ASTResolving.findCompilationUnitForBinding(context.getCompilationUnit(), context.getASTRoot(), targetBinding); 2265 2266 IJavaProject proj= context.getCompilationUnit().getJavaProject(); 2267 IType type= proj.findType(serviceBinding.getQualifiedName()); 2268 Image image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC); 2269 proposals.add(new NewProviderMethodDeclaration( 2270 Messages.format(CorrectionMessages.LocalCorrectionsSubProcessor_add_provider_method_description, type.getElementName()), 2271 targetCU, context.getASTRoot(), targetBinding, 2272 IProposalRelevance.CREATE_METHOD, image, type)); 2273 } 2274 } 2275 2276 public static void addServiceProviderConstructorProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException { 2277 ASTNode node= problem.getCoveredNode(context.getASTRoot()); 2278 if (! (node instanceof Name) && ! (node.getParent() instanceof ProvidesDirective)) { 2279 return; 2280 } 2281 2282 Name name= (Name) node; 2283 ITypeBinding targetBinding= name.resolveTypeBinding(); 2284 2285 if (targetBinding != null && 2286 !targetBinding.isInterface() 2287 && !Modifier.isAbstract(targetBinding.getModifiers())) { 2288 ICompilationUnit targetCU= ASTResolving.findCompilationUnitForBinding(context.getCompilationUnit(), context.getASTRoot(), targetBinding); 2289 IJavaProject proj= targetCU.getJavaProject(); 2290 2291 // Get the AST Root (CompilationUnit) for target class 2292 ASTParser parser= ASTParser.newParser(IASTSharedValues.SHARED_AST_LEVEL); 2293 parser.setKind(ASTParser.K_COMPILATION_UNIT); 2294 parser.setSource(targetCU); 2295 parser.setProject(proj); 2296 parser.setUnitName(targetCU.getPath().toString()); 2297 parser.setResolveBindings(true); 2298 ASTNode targetRoot= parser.createAST(null); 2299 2300 if (!(targetRoot instanceof CompilationUnit)) { 2301 return; 2302 } 2303 2304 IType targetType= proj.findType(targetBinding.getQualifiedName()); 2305 2306 // Locate the no-arg constructor binding for the type 2307 List<IMethodBinding> result= Arrays.asList(targetBinding.getDeclaredMethods()).stream() 2308 .filter(m -> m.isConstructor() && m.getParameterTypes().length == 0) 2309 .collect(Collectors.toList()); 2310 2311 // no-arg constructor exists, need to change visibility 2312 if (!result.isEmpty()) { 2313 IMethodBinding targetMethodBinding= result.get(0); 2314 IMethod targetMethod= null; 2315 for (IMethod m : targetType.getMethods()) { 2316 if (m.isConstructor() && m.getParameters().length == 0) { 2317 targetMethod= m; 2318 break; 2319 } 2320 } 2321 2322 String label= CorrectionMessages.LocalCorrectionsSubProcessor_changeconstructor_public_description; 2323 int include=Modifier.PUBLIC; 2324 int exclude=Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC; 2325 2326 // Locate the constructor declaration node in the target AST Node 2327 MethodDeclaration targetMethodDecl= ASTNodeSearchUtil.getMethodDeclarationNode(targetMethod, (CompilationUnit) targetRoot); 2328 proposals.add(new ModifierChangeCorrectionProposal(label, targetCU, targetMethodBinding, targetMethodDecl.getName(), 2329 include, exclude, IProposalRelevance.CHANGE_VISIBILITY_TO_NON_PRIVATE, 2330 JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE))); 2331 } else { 2332 // no-arg constructor does not exist, need to create it 2333 String[] args= new String[] { org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getTypeSignature(targetBinding), new ITypeBinding[0], false) }; 2334 String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createconstructor_description, args); 2335 Image image= JavaElementImageProvider.getDecoratedImage(JavaPluginImages.DESC_MISC_PUBLIC, JavaElementImageDescriptor.CONSTRUCTOR, JavaElementImageProvider.SMALL_SIZE); 2336 proposals.add(new NewMethodCorrectionProposal(label, targetCU, targetRoot, new ArrayList<> (), targetBinding, IProposalRelevance.CREATE_CONSTRUCTOR, image)); 2337 } 2338 } 2339 } 2340 2341 private LocalCorrectionsSubProcessor() { 2342 } 2343 } 2344