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