blob: 0bbae06153bad53f2f8597c83ad8264a5d14a26d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Renaud Waldura <renaud+eclipse@waldura.com> - New class/interface with wizard
* Rabea Gransberger <rgransberger@gmx.de> - [quick fix] Fix several visibility issues - https://bugs.eclipse.org/394692
*******************************************************************************/
package org.eclipse.jdt.internal.ui.text.correction;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import org.osgi.framework.Bundle;
import org.eclipse.swt.graphics.Image;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.resource.DeleteResourceChange;
import org.eclipse.ltk.core.refactoring.resource.ResourceChange;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTMatcher;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ConstructorInvocation;
import org.eclipse.jdt.core.dom.EnhancedForStatement;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ExpressionMethodReference;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.IPackageBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NameQualifiedType;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
import org.eclipse.jdt.core.dom.ProvidesDirective;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.jdt.core.dom.SuperFieldAccess;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
import org.eclipse.jdt.core.dom.SwitchCase;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.ThisExpression;
import org.eclipse.jdt.core.dom.ThrowStatement;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation;
import org.eclipse.jdt.core.manipulation.TypeKinds;
import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.dom.Bindings;
import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
import org.eclipse.jdt.internal.corext.refactoring.changes.ClasspathChange;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.internal.corext.util.QualifiedTypeNameHistory;
import org.eclipse.jdt.internal.corext.util.TypeFilter;
import org.eclipse.jdt.ui.JavaElementImageDescriptor;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jdt.ui.text.java.IInvocationContext;
import org.eclipse.jdt.ui.text.java.IProblemLocation;
import org.eclipse.jdt.ui.text.java.correction.ASTRewriteCorrectionProposal;
import org.eclipse.jdt.ui.text.java.correction.CUCorrectionProposal;
import org.eclipse.jdt.ui.text.java.correction.ChangeCorrectionProposal;
import org.eclipse.jdt.ui.text.java.correction.ICommandAccess;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.text.correction.proposals.AddArgumentCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.AddImportCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.AddModuleRequiresCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.AddTypeParameterProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.CastCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal.ChangeDescription;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal.EditDescription;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal.InsertDescription;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal.RemoveDescription;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeMethodSignatureProposal.SwapDescription;
import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.NewAnnotationMemberProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.NewCUUsingWizardProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.NewMethodCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.NewVariableCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.RenameNodeCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ReplaceCorrectionProposal;
import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
public class UnresolvedElementsSubProcessor {
private static final String ADD_IMPORT_ID= "org.eclipse.jdt.ui.correction.addImport"; //$NON-NLS-1$
public static void getVariableProposals(IInvocationContext context, IProblemLocation problem, IVariableBinding resolvedField, Collection<ICommandAccess> proposals) throws CoreException {
ICompilationUnit cu= context.getCompilationUnit();
CompilationUnit astRoot= context.getASTRoot();
ASTNode selectedNode= problem.getCoveredNode(astRoot);
if (selectedNode == null) {
return;
}
// type that defines the variable
ITypeBinding binding= null;
ITypeBinding declaringTypeBinding= Bindings.getBindingOfParentTypeContext(selectedNode);
if (declaringTypeBinding == null) {
return;
}
// possible type kind of the node
boolean suggestVariableProposals= true;
int typeKind= 0;
while (selectedNode instanceof ParenthesizedExpression) {
selectedNode= ((ParenthesizedExpression) selectedNode).getExpression();
}
Name node= null;
switch (selectedNode.getNodeType()) {
case ASTNode.SIMPLE_NAME:
node= (SimpleName) selectedNode;
ASTNode parent= node.getParent();
StructuralPropertyDescriptor locationInParent= node.getLocationInParent();
if (locationInParent == ExpressionMethodReference.EXPRESSION_PROPERTY) {
typeKind= TypeKinds.REF_TYPES;
} else if (locationInParent == MethodInvocation.EXPRESSION_PROPERTY) {
if (JavaModelUtil.is18OrHigher(cu.getJavaProject())) {
typeKind= TypeKinds.CLASSES | TypeKinds.INTERFACES | TypeKinds.ENUMS;
} else {
typeKind= TypeKinds.CLASSES;
}
} else if (locationInParent == FieldAccess.NAME_PROPERTY) {
Expression expression= ((FieldAccess) parent).getExpression();
if (expression != null) {
binding= expression.resolveTypeBinding();
if (binding == null) {
node= null;
}
}
} else if (parent instanceof SimpleType || parent instanceof NameQualifiedType) {
suggestVariableProposals= false;
typeKind= TypeKinds.REF_TYPES_AND_VAR;
} else if (parent instanceof QualifiedName) {
Name qualifier= ((QualifiedName) parent).getQualifier();
if (qualifier != node) {
binding= qualifier.resolveTypeBinding();
} else {
typeKind= TypeKinds.REF_TYPES;
}
ASTNode outerParent= parent.getParent();
while (outerParent instanceof QualifiedName) {
outerParent= outerParent.getParent();
}
if (outerParent instanceof SimpleType || outerParent instanceof NameQualifiedType) {
typeKind= TypeKinds.REF_TYPES;
suggestVariableProposals= false;
}
} else if (locationInParent == SwitchCase.EXPRESSION_PROPERTY) {
ITypeBinding switchExp= ((SwitchStatement) node.getParent().getParent()).getExpression().resolveTypeBinding();
if (switchExp != null && switchExp.isEnum()) {
binding= switchExp;
}
} else if (locationInParent == SuperFieldAccess.NAME_PROPERTY) {
binding= declaringTypeBinding.getSuperclass();
}
break;
case ASTNode.QUALIFIED_NAME:
QualifiedName qualifierName= (QualifiedName) selectedNode;
ITypeBinding qualifierBinding= qualifierName.getQualifier().resolveTypeBinding();
if (qualifierBinding != null) {
node= qualifierName.getName();
binding= qualifierBinding;
} else {
node= qualifierName.getQualifier();
typeKind= TypeKinds.REF_TYPES;
suggestVariableProposals= node.isSimpleName();
}
if (selectedNode.getParent() instanceof SimpleType || selectedNode.getParent() instanceof NameQualifiedType) {
typeKind= TypeKinds.REF_TYPES;
suggestVariableProposals= false;
}
break;
case ASTNode.FIELD_ACCESS:
FieldAccess access= (FieldAccess) selectedNode;
Expression expression= access.getExpression();
if (expression != null) {
binding= expression.resolveTypeBinding();
if (binding != null) {
node= access.getName();
}
}
break;
case ASTNode.SUPER_FIELD_ACCESS:
binding= declaringTypeBinding.getSuperclass();
node= ((SuperFieldAccess) selectedNode).getName();
break;
default:
}
if (node == null) {
return;
}
// add type proposals
if (typeKind != 0) {
if (!JavaModelUtil.is50OrHigher(cu.getJavaProject())) {
typeKind &= ~(TypeKinds.ANNOTATIONS | TypeKinds.ENUMS | TypeKinds.VARIABLES);
}
int relevance= Character.isUpperCase(ASTNodes.getSimpleNameIdentifier(node).charAt(0)) ? IProposalRelevance.VARIABLE_TYPE_PROPOSAL_1 : IProposalRelevance.VARIABLE_TYPE_PROPOSAL_2;
addSimilarTypeProposals(typeKind, cu, node, relevance + 1, proposals);
typeKind &= ~TypeKinds.ANNOTATIONS;
addNewTypeProposals(cu, node, typeKind, relevance, proposals);
ReorgCorrectionsSubProcessor.addProjectSetupFixProposal(context, problem, node.getFullyQualifiedName(), proposals);
}
if (!suggestVariableProposals) {
return;
}
SimpleName simpleName= node.isSimpleName() ? (SimpleName) node : ((QualifiedName) node).getName();
boolean isWriteAccess= ASTResolving.isWriteAccess(node);
// similar variables
addSimilarVariableProposals(cu, astRoot, binding, resolvedField, simpleName, isWriteAccess, proposals);
if (binding == null) {
addStaticImportFavoriteProposals(context, simpleName, false, proposals);
}
if (resolvedField == null || binding == null || resolvedField.getDeclaringClass() != binding.getTypeDeclaration() && Modifier.isPrivate(resolvedField.getModifiers())) {
// new fields
addNewFieldProposals(cu, astRoot, binding, declaringTypeBinding, simpleName, isWriteAccess, proposals);
// new parameters and local variables
if (binding == null) {
addNewVariableProposals(cu, node, simpleName, proposals);
}
}
}
private static void addNewVariableProposals(ICompilationUnit cu, Name node, SimpleName simpleName, Collection<ICommandAccess> proposals) {
String name= simpleName.getIdentifier();
BodyDeclaration bodyDeclaration= ASTResolving.findParentBodyDeclaration(node, true);
int type= bodyDeclaration.getNodeType();
if (type == ASTNode.METHOD_DECLARATION) {
int relevance= StubUtility.hasParameterName(cu.getJavaProject(), name) ? IProposalRelevance.CREATE_PARAMETER_PREFIX_OR_SUFFIX_MATCH : IProposalRelevance.CREATE_PARAMETER;
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createparameter_description, BasicElementLabels.getJavaElementName(name));
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL);
proposals.add(new NewVariableCorrectionProposal(label, cu, NewVariableCorrectionProposal.PARAM, simpleName, null, relevance, image));
}
if (type == ASTNode.INITIALIZER || type == ASTNode.METHOD_DECLARATION && !ASTResolving.isInsideConstructorInvocation((MethodDeclaration) bodyDeclaration, node)) {
int relevance= StubUtility.hasLocalVariableName(cu.getJavaProject(), name) ? IProposalRelevance.CREATE_LOCAL_PREFIX_OR_SUFFIX_MATCH : IProposalRelevance.CREATE_LOCAL;
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createlocal_description, BasicElementLabels.getJavaElementName(name));
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL);
proposals.add(new NewVariableCorrectionProposal(label, cu, NewVariableCorrectionProposal.LOCAL, simpleName, null, relevance, image));
}
if (node.getParent().getNodeType() == ASTNode.ASSIGNMENT) {
Assignment assignment= (Assignment) node.getParent();
if (assignment.getLeftHandSide() == node && assignment.getParent().getNodeType() == ASTNode.EXPRESSION_STATEMENT) {
ASTNode statement= assignment.getParent();
ASTRewrite rewrite= ASTRewrite.create(statement.getAST());
if (ASTNodes.isControlStatementBody(assignment.getParent().getLocationInParent())) {
rewrite.replace(statement, rewrite.getAST().newBlock(), null);
} else {
rewrite.remove(statement, null);
}
String label= CorrectionMessages.UnresolvedElementsSubProcessor_removestatement_description;
Image image= JavaPlugin.getDefault().getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, cu, rewrite, IProposalRelevance.REMOVE_ASSIGNMENT, image);
proposals.add(proposal);
}
}
}
private static void addNewFieldProposals(ICompilationUnit cu, CompilationUnit astRoot, ITypeBinding binding, ITypeBinding declaringTypeBinding, SimpleName simpleName, boolean isWriteAccess, Collection<ICommandAccess> proposals) throws JavaModelException {
// new variables
ICompilationUnit targetCU;
ITypeBinding senderDeclBinding;
if (binding != null) {
senderDeclBinding= binding.getTypeDeclaration();
targetCU= ASTResolving.findCompilationUnitForBinding(cu, astRoot, senderDeclBinding);
} else { // binding is null for accesses without qualifier
senderDeclBinding= declaringTypeBinding;
targetCU= cu;
}
if (!senderDeclBinding.isFromSource() || targetCU == null) {
return;
}
boolean mustBeConst= ASTResolving.isInsideModifiers(simpleName);
addNewFieldForType(targetCU, binding, senderDeclBinding, simpleName, isWriteAccess, mustBeConst, proposals);
if (binding == null && senderDeclBinding.isNested()) {
ASTNode anonymDecl= astRoot.findDeclaringNode(senderDeclBinding);
if (anonymDecl != null) {
ITypeBinding bind= Bindings.getBindingOfParentType(anonymDecl.getParent());
if (!bind.isAnonymous()) {
addNewFieldForType(targetCU, bind, bind, simpleName, isWriteAccess, mustBeConst, proposals);
}
}
}
}
private static void addNewFieldForType(ICompilationUnit targetCU, ITypeBinding binding, ITypeBinding senderDeclBinding, SimpleName simpleName, boolean isWriteAccess, boolean mustBeConst, Collection<ICommandAccess> proposals) {
String name= simpleName.getIdentifier();
String nameLabel= BasicElementLabels.getJavaElementName(name);
String label;
Image image;
if (senderDeclBinding.isEnum() && !isWriteAccess) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createenum_description, new Object[] { nameLabel, org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getTypeSignature(senderDeclBinding) });
image= JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PUBLIC);
proposals.add(new NewVariableCorrectionProposal(label, targetCU, NewVariableCorrectionProposal.ENUM_CONST, simpleName, senderDeclBinding, 10, image));
} else {
if (!mustBeConst) {
if (binding == null) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createfield_description, nameLabel);
image= JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PRIVATE);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createfield_other_description, new Object[] { nameLabel, org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getTypeSignature(senderDeclBinding) } );
image= JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PUBLIC);
}
int fieldRelevance= StubUtility.hasFieldName(targetCU.getJavaProject(), name) ? IProposalRelevance.CREATE_FIELD_PREFIX_OR_SUFFIX_MATCH : IProposalRelevance.CREATE_FIELD;
proposals.add(new NewVariableCorrectionProposal(label, targetCU, NewVariableCorrectionProposal.FIELD, simpleName, senderDeclBinding, fieldRelevance, image));
}
if (!isWriteAccess && !senderDeclBinding.isAnonymous()) {
if (binding == null) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createconst_description, nameLabel);
image= JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PRIVATE);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createconst_other_description, new Object[] { nameLabel, org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getTypeSignature(senderDeclBinding) } );
image= JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PUBLIC);
}
int constRelevance= StubUtility.hasConstantName(targetCU.getJavaProject(), name) ? IProposalRelevance.CREATE_CONSTANT_PREFIX_OR_SUFFIX_MATCH : IProposalRelevance.CREATE_CONSTANT;
proposals.add(new NewVariableCorrectionProposal(label, targetCU, NewVariableCorrectionProposal.CONST_FIELD, simpleName, senderDeclBinding, constRelevance, image));
}
}
}
private static void addSimilarVariableProposals(ICompilationUnit cu, CompilationUnit astRoot, ITypeBinding binding, IVariableBinding resolvedField, SimpleName node, boolean isWriteAccess, Collection<ICommandAccess> proposals) {
int kind= ScopeAnalyzer.VARIABLES | ScopeAnalyzer.CHECK_VISIBILITY;
if (!isWriteAccess) {
kind |= ScopeAnalyzer.METHODS; // also try to find similar methods
}
IBinding[] varsAndMethodsInScope= (new ScopeAnalyzer(astRoot)).getDeclarationsInScope(node, kind);
if (varsAndMethodsInScope.length > 0) {
// avoid corrections like int i= i;
String otherNameInAssign= null;
// help with x.getString() -> y.getString()
String methodSenderName= null;
String fieldSenderName= null;
ASTNode parent= node.getParent();
switch (parent.getNodeType()) {
case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
// node must be initializer
otherNameInAssign= ((VariableDeclarationFragment) parent).getName().getIdentifier();
break;
case ASTNode.ASSIGNMENT:
Assignment assignment= (Assignment) parent;
if (isWriteAccess && assignment.getRightHandSide() instanceof SimpleName) {
otherNameInAssign= ((SimpleName) assignment.getRightHandSide()).getIdentifier();
} else if (!isWriteAccess && assignment.getLeftHandSide() instanceof SimpleName) {
otherNameInAssign= ((SimpleName) assignment.getLeftHandSide()).getIdentifier();
}
break;
case ASTNode.METHOD_INVOCATION:
MethodInvocation inv= (MethodInvocation) parent;
if (inv.getExpression() == node) {
methodSenderName= inv.getName().getIdentifier();
}
break;
case ASTNode.QUALIFIED_NAME:
QualifiedName qualName= (QualifiedName) parent;
if (qualName.getQualifier() == node) {
fieldSenderName= qualName.getName().getIdentifier();
}
break;
}
ITypeBinding guessedType= ASTResolving.guessBindingForReference(node);
ITypeBinding objectBinding= astRoot.getAST().resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
String identifier= node.getIdentifier();
boolean isInStaticContext= ASTResolving.isInStaticContext(node);
ArrayList<CUCorrectionProposal> newProposals= new ArrayList<>(51);
loop: for (int i= 0; i < varsAndMethodsInScope.length && newProposals.size() <= 50; i++) {
IBinding varOrMeth= varsAndMethodsInScope[i];
if (varOrMeth instanceof IVariableBinding) {
IVariableBinding curr= (IVariableBinding) varOrMeth;
String currName= curr.getName();
if (currName.equals(otherNameInAssign)) {
continue loop;
}
if (resolvedField != null && Bindings.equals(resolvedField, curr)) {
continue loop;
}
boolean isFinal= Modifier.isFinal(curr.getModifiers());
if (isFinal && curr.isField() && isWriteAccess) {
continue loop;
}
if (isInStaticContext && !Modifier.isStatic(curr.getModifiers()) && curr.isField()) {
continue loop;
}
int relevance= IProposalRelevance.SIMILAR_VARIABLE_PROPOSAL;
if (NameMatcher.isSimilarName(currName, identifier)) {
relevance += 3; // variable with a similar name than the unresolved variable
}
if (currName.equalsIgnoreCase(identifier)) {
relevance+= 5;
}
ITypeBinding varType= curr.getType();
if (varType != null) {
if (guessedType != null && guessedType != objectBinding) { // too many result with object
// variable type is compatible with the guessed type
if (!isWriteAccess && canAssign(varType, guessedType)
|| isWriteAccess && canAssign(guessedType, varType)) {
relevance += 2; // unresolved variable can be assign to this variable
}
}
if (methodSenderName != null && hasMethodWithName(varType, methodSenderName)) {
relevance += 2;
}
if (fieldSenderName != null && hasFieldWithName(varType, fieldSenderName)) {
relevance += 2;
}
}
if (relevance > 0) {
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changevariable_description, BasicElementLabels.getJavaElementName(currName));
newProposals.add(new RenameNodeCorrectionProposal(label, cu, node.getStartPosition(), node.getLength(), currName, relevance));
}
} else if (varOrMeth instanceof IMethodBinding) {
IMethodBinding curr= (IMethodBinding) varOrMeth;
if (!curr.isConstructor() && guessedType != null && canAssign(curr.getReturnType(), guessedType)) {
if (NameMatcher.isSimilarName(curr.getName(), identifier)) {
AST ast= astRoot.getAST();
ASTRewrite rewrite= ASTRewrite.create(ast);
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changetomethod_description, org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(curr));
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, cu, rewrite, IProposalRelevance.CHANGE_TO_METHOD, image);
newProposals.add(proposal);
MethodInvocation newInv= ast.newMethodInvocation();
newInv.setName(ast.newSimpleName(curr.getName()));
ITypeBinding[] parameterTypes= curr.getParameterTypes();
for (int k= 0; k < parameterTypes.length; k++) {
ASTNode arg= ASTNodeFactory.newDefaultExpression(ast, parameterTypes[k]);
newInv.arguments().add(arg);
proposal.addLinkedPosition(rewrite.track(arg), false, null);
}
rewrite.replace(node, newInv, null);
}
}
}
}
if (newProposals.size() <= 50)
proposals.addAll(newProposals);
}
if (binding != null && binding.isArray()) {
String idLength= "length"; //$NON-NLS-1$
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changevariable_description, idLength);
proposals.add(new RenameNodeCorrectionProposal(label, cu, node.getStartPosition(), node.getLength(), idLength, IProposalRelevance.CHANGE_VARIABLE));
}
}
private static boolean canAssign(ITypeBinding returnType, ITypeBinding guessedType) {
return returnType.isAssignmentCompatible(guessedType);
}
private static boolean hasMethodWithName(ITypeBinding typeBinding, String name) {
IVariableBinding[] fields= typeBinding.getDeclaredFields();
for (int i= 0; i < fields.length; i++) {
if (fields[i].getName().equals(name)) {
return true;
}
}
ITypeBinding superclass= typeBinding.getSuperclass();
if (superclass != null) {
return hasMethodWithName(superclass, name);
}
return false;
}
private static boolean hasFieldWithName(ITypeBinding typeBinding, String name) {
IMethodBinding[] methods= typeBinding.getDeclaredMethods();
for (int i= 0; i < methods.length; i++) {
if (methods[i].getName().equals(name)) {
return true;
}
}
ITypeBinding superclass= typeBinding.getSuperclass();
if (superclass != null) {
return hasMethodWithName(superclass, name);
}
return false;
}
private static int evauateTypeKind(ASTNode node, IJavaProject project) {
int kind= ASTResolving.getPossibleTypeKinds(node, JavaModelUtil.is50OrHigher(project));
return kind;
}
public static void getTypeProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException {
ICompilationUnit cu= context.getCompilationUnit();
ASTNode selectedNode= problem.getCoveringNode(context.getASTRoot());
if (selectedNode == null) {
return;
}
IJavaProject javaProject= cu.getJavaProject();
int kind= evauateTypeKind(selectedNode, javaProject);
if (kind == TypeKinds.REF_TYPES) {
addEnhancedForWithoutTypeProposals(cu, selectedNode, proposals);
}
while (selectedNode.getLocationInParent() == QualifiedName.NAME_PROPERTY) {
selectedNode= selectedNode.getParent();
}
Name node= null;
if (selectedNode instanceof SimpleType) {
node= ((SimpleType) selectedNode).getName();
} else if (selectedNode instanceof NameQualifiedType) {
node= ((NameQualifiedType) selectedNode).getName();
} else if (selectedNode instanceof ArrayType) {
Type elementType= ((ArrayType) selectedNode).getElementType();
if (elementType.isSimpleType()) {
node= ((SimpleType) elementType).getName();
} else if (elementType.isNameQualifiedType()) {
node= ((NameQualifiedType) elementType).getName();
} else {
return;
}
} else if (selectedNode instanceof Name) {
node= (Name) selectedNode;
} else {
return;
}
// change to similar type proposals
addSimilarTypeProposals(kind, cu, node, IProposalRelevance.SIMILAR_TYPE, proposals);
while (node.getParent() instanceof QualifiedName) {
node= (Name) node.getParent();
}
IModuleDescription moduleDescription= cu.getModule();
if (moduleDescription != null && moduleDescription.exists()
&& javaProject != null && JavaModelUtil.is9OrHigher(javaProject)) {
ICompilationUnit moduleCompilationUnit= moduleDescription.getCompilationUnit();
if (cu.equals(moduleCompilationUnit)) {
addRequiresModuleProposals(cu, node, kind, proposals, false);
ASTNode parentNode= node.getParent();
if (parentNode instanceof ProvidesDirective) {
Name serviceName= ((ProvidesDirective) parentNode).getName();
IBinding binding= serviceName.resolveBinding();
if (binding instanceof ITypeBinding) {
ITypeBinding typeBinding= (ITypeBinding) binding;
if (typeBinding.isClass()) {
kind= TypeKinds.CLASSES;
} else if (typeBinding.isInterface()) {
kind= TypeKinds.CLASSES | TypeKinds.INTERFACES;
}
}
}
}
}
if (selectedNode != node) {
kind= evauateTypeKind(node, javaProject);
}
if ((kind & (TypeKinds.CLASSES | TypeKinds.INTERFACES)) != 0) {
kind &= ~TypeKinds.ANNOTATIONS; // only propose annotations when there are no other suggestions
}
addNewTypeProposals(cu, node, kind, IProposalRelevance.NEW_TYPE, proposals);
ReorgCorrectionsSubProcessor.addProjectSetupFixProposal(context, problem, node.getFullyQualifiedName(), proposals);
}
private static void addEnhancedForWithoutTypeProposals(ICompilationUnit cu, ASTNode selectedNode, Collection<ICommandAccess> proposals) {
if (selectedNode instanceof SimpleName && (selectedNode.getLocationInParent() == SimpleType.NAME_PROPERTY || selectedNode.getLocationInParent() == NameQualifiedType.NAME_PROPERTY)) {
ASTNode type= selectedNode.getParent();
if (type.getLocationInParent() == SingleVariableDeclaration.TYPE_PROPERTY) {
SingleVariableDeclaration svd= (SingleVariableDeclaration) type.getParent();
if (svd.getLocationInParent() == EnhancedForStatement.PARAMETER_PROPERTY) {
if (svd.getName().getLength() == 0) {
SimpleName simpleName= (SimpleName) selectedNode;
String name= simpleName.getIdentifier();
int relevance= StubUtility.hasLocalVariableName(cu.getJavaProject(), name) ? 10 : 7;
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_create_loop_variable_description, BasicElementLabels.getJavaElementName(name));
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL);
proposals.add(new NewVariableCorrectionProposal(label, cu, NewVariableCorrectionProposal.LOCAL, simpleName, null, relevance, image));
}
}
}
}
}
private static void addNullityAnnotationTypesProposals(ICompilationUnit cu, Name node, Collection<ICommandAccess> proposals) throws CoreException {
ASTNode parent= node.getParent();
boolean isAnnotationName= parent instanceof Annotation && ((Annotation) parent).getTypeNameProperty() == node.getLocationInParent();
if (!isAnnotationName) {
boolean isImportName= parent instanceof ImportDeclaration && ImportDeclaration.NAME_PROPERTY == node.getLocationInParent();
if (!isImportName)
return;
}
final IJavaProject javaProject= cu.getJavaProject();
String name= node.getFullyQualifiedName();
String nullityAnnotation= null;
String[] annotationNameOptions= { JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME, JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, JavaCore.COMPILER_NONNULL_BY_DEFAULT_ANNOTATION_NAME };
Hashtable<String, String> defaultOptions= JavaCore.getDefaultOptions();
for (String annotationNameOption : annotationNameOptions) {
String annotationName= javaProject.getOption(annotationNameOption, true);
if (! annotationName.equals(defaultOptions.get(annotationNameOption)))
return;
if (JavaModelUtil.isMatchingName(name, annotationName)) {
nullityAnnotation= annotationName;
}
}
if (nullityAnnotation == null)
return;
if (javaProject.findType(defaultOptions.get(annotationNameOptions[0])) != null)
return;
String version= JavaModelUtil.is18OrHigher(javaProject) ? "2" : "[1.1.0,2.0.0)"; //$NON-NLS-1$ //$NON-NLS-2$
Bundle[] annotationsBundles= JavaPlugin.getDefault().getBundles("org.eclipse.jdt.annotation", version); //$NON-NLS-1$
if (annotationsBundles == null)
return;
if (! cu.getJavaProject().getProject().hasNature("org.eclipse.pde.PluginNature")) //$NON-NLS-1$
addCopyAnnotationsJarProposal(cu, node, nullityAnnotation, annotationsBundles[0], proposals);
}
private static void addCopyAnnotationsJarProposal(final ICompilationUnit cu, final Name name, final String fullyQualifiedName, Bundle annotationsBundle, Collection<ICommandAccess> proposals) {
final IJavaProject javaProject= cu.getJavaProject();
final File bundleFile;
try {
bundleFile= FileLocator.getBundleFile(annotationsBundle);
} catch (IOException e) {
JavaPlugin.log(e);
return;
}
if (!bundleFile.isFile() || !bundleFile.canRead())
return; // we only support a JAR'd bundle, so this won't work in the runtime if you have org.eclipse.jdt.annotation in source.
final String changeName= CorrectionMessages.UnresolvedElementsSubProcessor_copy_annotation_jar_description;
ChangeCorrectionProposal proposal= new ChangeCorrectionProposal(changeName, null, IProposalRelevance.COPY_ANNOTATION_JAR) {
@Override
protected Change createChange() throws CoreException {
final IFile file= javaProject.getProject().getFile(bundleFile.getName());
ResourceChange copyFileChange= new ResourceChange() {
@Override
public Change perform(IProgressMonitor pm) throws CoreException {
try {
if (file.exists())
file.delete(false, pm);
file.create(new BufferedInputStream(new FileInputStream(bundleFile)), false, pm);
return new DeleteResourceChange(file.getFullPath(), false);
} catch (FileNotFoundException e) {
throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), e.getMessage()));
}
}
@Override
public String getName() {
return changeName;
}
@Override
protected IResource getModifiedResource() {
return javaProject.getProject();
}
};
ClasspathChange addEntryChange= ClasspathChange.addEntryChange(javaProject, JavaCore.newLibraryEntry(file.getFullPath(), null, null));
CompilationUnitChange addImportChange= createAddImportChange(cu, name, fullyQualifiedName);
return new CompositeChange(changeName, new Change[] { copyFileChange, addEntryChange, addImportChange});
}
@Override
public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
return CorrectionMessages.UnresolvedElementsSubProcessor_copy_annotation_jar_info;
}
};
proposals.add(proposal);
}
static CompilationUnitChange createAddImportChange(ICompilationUnit cu, Name name, String fullyQualifiedName) throws CoreException {
String[] args= { BasicElementLabels.getJavaElementName(Signature.getSimpleName(fullyQualifiedName)),
BasicElementLabels.getJavaElementName(Signature.getQualifier(fullyQualifiedName)) };
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_importtype_description, args);
CompilationUnitChange cuChange= new CompilationUnitChange(label, cu);
ImportRewrite importRewrite= StubUtility.createImportRewrite((CompilationUnit) name.getRoot(), true);
importRewrite.addImport(fullyQualifiedName);
cuChange.setEdit(importRewrite.rewriteImports(null));
return cuChange;
}
private static void addSimilarTypeProposals(int kind, ICompilationUnit cu, Name node, int relevance, Collection<ICommandAccess> proposals) throws CoreException {
SimilarElement[] elements= SimilarElementsRequestor.findSimilarElement(cu, node, kind);
// try to resolve type in context -> highest severity
String resolvedTypeName= null;
ITypeBinding binding= ASTResolving.guessBindingForTypeReference(node);
if (binding != null) {
ITypeBinding simpleBinding= binding;
if (simpleBinding.isArray()) {
simpleBinding= simpleBinding.getElementType();
}
simpleBinding= simpleBinding.getTypeDeclaration();
if (!simpleBinding.isRecovered()) {
resolvedTypeName= simpleBinding.getQualifiedName();
CUCorrectionProposal proposal= createTypeRefChangeProposal(cu, resolvedTypeName, node, relevance + 2, elements.length);
ChangeCorrectionProposal compositeProposal= getCompositeChangeProposal(proposal);
if (compositeProposal != null) {
proposals.add(compositeProposal);
} else {
proposals.add(proposal);
}
if (proposal instanceof AddImportCorrectionProposal) {
int rel= relevance + elements.length + 2;
proposal.setRelevance(rel);
if (compositeProposal != null) {
compositeProposal.setRelevance(rel);
}
}
if (binding.isParameterizedType()
&& (node.getParent() instanceof SimpleType || node.getParent() instanceof NameQualifiedType)
&& !(node.getParent().getParent() instanceof Type)) {
proposals.add(createTypeRefChangeFullProposal(cu, binding, node, relevance + 5, TypeLocation.UNKNOWN));
}
}
} else {
ASTNode normalizedNode= ASTNodes.getNormalizedNode(node);
if (!(normalizedNode.getParent() instanceof Type) && node.getParent() != normalizedNode) {
ITypeBinding normBinding= ASTResolving.guessBindingForTypeReference(normalizedNode);
if (normBinding != null && !normBinding.isRecovered()) {
proposals.add(createTypeRefChangeFullProposal(cu, normBinding, normalizedNode, relevance + 5, TypeLocation.UNKNOWN));
}
}
}
// add all similar elements
for (int i= 0; i < elements.length; i++) {
SimilarElement elem= elements[i];
if ((elem.getKind() & TypeKinds.ALL_TYPES) != 0) {
String fullName= elem.getName();
if (!fullName.equals(resolvedTypeName)) {
CUCorrectionProposal cuProposal= createTypeRefChangeProposal(cu, fullName, node, relevance, elements.length);
ChangeCorrectionProposal compositeProposal= getCompositeChangeProposal(cuProposal);
if (compositeProposal != null) {
proposals.add(compositeProposal);
} else {
proposals.add(cuProposal);
}
}
}
}
if (elements.length == 0) {
addRequiresModuleProposals(cu, node, IProposalRelevance.IMPORT_NOT_FOUND_ADD_REQUIRES_MODULE, proposals, true);
}
}
private static ChangeCorrectionProposal getCompositeChangeProposal(ChangeCorrectionProposal proposal) throws CoreException {
ChangeCorrectionProposal compositeProposal= null;
if (proposal instanceof AddImportCorrectionProposal) {
AddModuleRequiresCorrectionProposal cp= ((AddImportCorrectionProposal) proposal).getAdditionalProposal();
if (cp != null) {
Change importChange= proposal.getChange();
Change change= cp.getChange();
if (change != null) {
ImportRewrite importRewrite= ((AddImportCorrectionProposal) proposal).getImportRewrite();
boolean importNeedsToBeAdded= false;
if (importRewrite != null) {
String[] imports= importRewrite.getAddedImports();
if (imports != null && imports.length > 0) {
importNeedsToBeAdded= true;
}
}
if (importNeedsToBeAdded) {
change.initializeValidationData(new NullProgressMonitor());
String importChangeName= importChange.getName();
String moduleRequiresChangeName= change.getName();
moduleRequiresChangeName= moduleRequiresChangeName.substring(0, 1).toLowerCase() + moduleRequiresChangeName.substring(1);
String changeName= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_combine_two_proposals_info, new String[] { importChangeName, moduleRequiresChangeName });
compositeProposal= new ChangeCorrectionProposal(changeName, null, IProposalRelevance.IMPORT_NOT_FOUND_ADD_REQUIRES_MODULE) {
@Override
protected Change createChange() throws CoreException {
return new CompositeChange(changeName, new Change[] { change, importChange });
}
@Override
public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
return changeName;
}
};
} else {
compositeProposal= new ChangeCorrectionProposal(change.getName(), null, IProposalRelevance.IMPORT_NOT_FOUND_ADD_REQUIRES_MODULE) {
@Override
protected Change createChange() throws CoreException {
return change;
}
@Override
public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
return change.getName();
}
};
}
}
}
}
return compositeProposal;
}
private static CUCorrectionProposal createTypeRefChangeProposal(ICompilationUnit cu, String fullName, Name node, int relevance, int maxProposals) {
ImportRewrite importRewrite= null;
String simpleName= fullName;
String packName= Signature.getQualifier(fullName);
if (packName.length() > 0) { // no imports for primitive types, type variables
importRewrite= StubUtility.createImportRewrite((CompilationUnit) node.getRoot(), true);
BodyDeclaration scope= ASTResolving.findParentBodyDeclaration(node); // can be null in package-info.java
ImportRewriteContext context= new ContextSensitiveImportRewriteContext(scope != null ? scope : node, importRewrite);
simpleName= importRewrite.addImport(fullName, context);
}
if (!isLikelyTypeName(simpleName)) {
relevance -= 2;
}
ASTRewriteCorrectionProposal proposal;
if (importRewrite != null && node.isSimpleName() && simpleName.equals(((SimpleName) node).getIdentifier())) { // import only
// import only
String[] arg= { BasicElementLabels.getJavaElementName(simpleName), BasicElementLabels.getJavaElementName(packName) };
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_importtype_description, arg);
Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_IMPDECL);
int boost= QualifiedTypeNameHistory.getBoost(fullName, 0, maxProposals);
proposal= new AddImportCorrectionProposal(label, cu, relevance + 100 + boost, image, packName, simpleName, (SimpleName)node);
proposal.setCommandId(ADD_IMPORT_ID);
} else {
String label;
if (packName.length() == 0) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changetype_nopack_description, BasicElementLabels.getJavaElementName(simpleName));
} else {
String[] arg= { BasicElementLabels.getJavaElementName(simpleName), BasicElementLabels.getJavaElementName(packName) };
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changetype_description, arg);
}
ASTRewrite rewrite= ASTRewrite.create(node.getAST());
rewrite.replace(node, rewrite.createStringPlaceholder(simpleName, ASTNode.SIMPLE_TYPE), null);
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
proposal= new ASTRewriteCorrectionProposal(label, cu, rewrite, relevance, image);
}
if (importRewrite != null) {
proposal.setImportRewrite(importRewrite);
}
return proposal;
}
static CUCorrectionProposal createTypeRefChangeFullProposal(ICompilationUnit cu, ITypeBinding binding, ASTNode node, int relevance, TypeLocation typeLocation) {
ASTRewrite rewrite= ASTRewrite.create(node.getAST());
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_change_full_type_description, BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_DEFAULT));
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, cu, rewrite, relevance, image);
ImportRewrite imports= proposal.createImportRewrite((CompilationUnit) node.getRoot());
ImportRewriteContext context= new ContextSensitiveImportRewriteContext(node, imports);
Type type= imports.addImport(binding, node.getAST(), context, typeLocation);
rewrite.replace(node, type, null);
return proposal;
}
private static boolean isLikelyTypeName(String name) {
return name.length() > 0 && Character.isUpperCase(name.charAt(0));
}
private static boolean isLikelyPackageName(String name) {
if (name.length() != 0) {
int i= 0;
do {
if (Character.isUpperCase(name.charAt(i))) {
return false;
}
i= name.indexOf('.', i) + 1;
} while (i != 0 && i < name.length());
}
return true;
}
private static boolean isLikelyTypeParameterName(String name) {
return name.length() == 1 && Character.isUpperCase(name.charAt(0));
}
private static boolean isLikelyMethodTypeParameterName(String name) {
if (name.length() == 1) {
switch (name.charAt(0)) {
case 'S':
case 'T':
case 'U':
return true;
}
}
return false;
}
public static void addNewTypeProposals(ICompilationUnit cu, Name refNode, int kind, int relevance, Collection<ICommandAccess> proposals) throws CoreException {
Name node= refNode;
do {
String typeName= ASTNodes.getSimpleNameIdentifier(node);
Name qualifier= null;
// only propose to create types for qualifiers when the name starts with upper case
boolean isPossibleName= isLikelyTypeName(typeName) || node == refNode;
if (isPossibleName) {
IPackageFragment enclosingPackage= null;
IType enclosingType= null;
if (node.isSimpleName()) {
enclosingPackage= (IPackageFragment) cu.getParent();
// don't suggest member type, user can select it in wizard
} else {
Name qualifierName= ((QualifiedName) node).getQualifier();
IBinding binding= qualifierName.resolveBinding();
if (binding != null && binding.isRecovered()) {
binding= null;
}
if (binding instanceof ITypeBinding) {
enclosingType=(IType) binding.getJavaElement();
} else if (binding instanceof IPackageBinding) {
qualifier= qualifierName;
enclosingPackage= (IPackageFragment) binding.getJavaElement();
} else {
IJavaElement[] res= cu.codeSelect(qualifierName.getStartPosition(), qualifierName.getLength());
if (res!= null && res.length > 0 && res[0] instanceof IType) {
enclosingType= (IType) res[0];
} else {
qualifier= qualifierName;
enclosingPackage= JavaModelUtil.getPackageFragmentRoot(cu).getPackageFragment(ASTResolving.getFullName(qualifierName));
}
}
}
int rel= relevance;
if (enclosingPackage != null && isLikelyPackageName(enclosingPackage.getElementName())) {
rel += 3;
}
if (enclosingPackage != null && !enclosingPackage.getCompilationUnit(typeName + JavaModelUtil.DEFAULT_CU_SUFFIX).exists()
|| enclosingType != null && !enclosingType.isReadOnly() && !enclosingType.getType(typeName).exists()) { // new member type
IJavaElement enclosing= enclosingPackage != null ? (IJavaElement) enclosingPackage : enclosingType;
if ((kind & TypeKinds.CLASSES) != 0) {
proposals.add(new NewCUUsingWizardProposal(cu, node, NewCUUsingWizardProposal.K_CLASS, enclosing, rel+3));
}
if ((kind & TypeKinds.INTERFACES) != 0) {
proposals.add(new NewCUUsingWizardProposal(cu, node, NewCUUsingWizardProposal.K_INTERFACE, enclosing, rel+2));
}
if ((kind & TypeKinds.ENUMS) != 0) {
proposals.add(new NewCUUsingWizardProposal(cu, node, NewCUUsingWizardProposal.K_ENUM, enclosing, rel));
}
if ((kind & TypeKinds.ANNOTATIONS) != 0) {
proposals.add(new NewCUUsingWizardProposal(cu, node, NewCUUsingWizardProposal.K_ANNOTATION, enclosing, rel + 1));
addNullityAnnotationTypesProposals(cu, node, proposals);
}
}
}
node= qualifier;
} while (node != null);
// type parameter proposals
if (refNode.isSimpleName() && (kind & TypeKinds.VARIABLES) != 0) {
CompilationUnit root= (CompilationUnit) refNode.getRoot();
String name= ((SimpleName) refNode).getIdentifier();
BodyDeclaration declaration= ASTResolving.findParentBodyDeclaration(refNode);
int baseRel= relevance;
if (isLikelyTypeParameterName(name)) {
baseRel += 8;
}
while (declaration != null) {
IBinding binding= null;
int rel= baseRel;
if (declaration instanceof MethodDeclaration) {
binding= ((MethodDeclaration) declaration).resolveBinding();
if (isLikelyMethodTypeParameterName(name))
rel+= 2;
} else if (declaration instanceof TypeDeclaration) {
binding= ((TypeDeclaration) declaration).resolveBinding();
rel++;
}
if (binding != null) {
AddTypeParameterProposal proposal= new AddTypeParameterProposal(cu, binding, root, name, null, rel);
proposals.add(proposal);
}
if (!Modifier.isStatic(declaration.getModifiers())) {
declaration= ASTResolving.findParentBodyDeclaration(declaration.getParent());
} else {
declaration= null;
}
}
}
}
public static void addRequiresModuleProposals(ICompilationUnit cu, Name node, int relevance, Collection<ICommandAccess> proposals, boolean isOnDemand) throws CoreException {
if (cu == null) {
return;
}
IJavaProject currentJavaProject= cu.getJavaProject();
if (currentJavaProject == null || !JavaModelUtil.is9OrHigher(currentJavaProject)) {
return;
}
IModuleDescription currentModuleDescription= currentJavaProject.getModuleDescription();
if (currentModuleDescription == null) {
return;
}
ICompilationUnit currentModuleCompilationUnit= currentModuleDescription.getCompilationUnit();
if (currentModuleCompilationUnit == null || !currentModuleCompilationUnit.exists()) {
return;
}
int typeRule= IJavaSearchConstants.TYPE;
if (isOnDemand) {
typeRule= IJavaSearchConstants.PACKAGE;
}
List<IPackageFragment> matchingPackageFragments= new ArrayList<>();
if (node.isSimpleName() && !isOnDemand) {
matchingPackageFragments.add((IPackageFragment) cu.getParent());
} else {
String qualifiedName= node.getFullyQualifiedName();
List<IPackageFragment> packageFragments= AddModuleRequiresCorrectionProposal.getPackageFragmentsOfMatchingTypes(qualifiedName, typeRule, currentJavaProject);
if (packageFragments.size() > 0) {
matchingPackageFragments.addAll(packageFragments);
} else if (isOnDemand) {
packageFragments= AddModuleRequiresCorrectionProposal.getPackageFragmentsOfMatchingTypes(qualifiedName, IJavaSearchConstants.TYPE, currentJavaProject);
if (packageFragments.size() > 0) {
matchingPackageFragments.addAll(packageFragments);
}
}
}
IModuleDescription projectModule= null;
if (matchingPackageFragments.size() > 0) {
HashSet<String> modules= new HashSet<>();
for (IPackageFragment enclosingPackage : matchingPackageFragments) {
if (enclosingPackage.isReadOnly()) { // This is to handle the case where the enclosingPackage belongs to a jar file
IPackageFragmentRoot root= (IPackageFragmentRoot) enclosingPackage.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
if (root != null) {
projectModule= root.getModuleDescription();
}
} else {
IJavaProject project= enclosingPackage.getJavaProject();
if (project != null && JavaModelUtil.is9OrHigher(project)) {
projectModule= project.getModuleDescription();
}
}
if (projectModule != null && projectModule.exists() && !projectModule.equals(currentModuleDescription)) {
String moduleName= projectModule.getElementName();
if (!modules.contains(moduleName)) {
String[] args= { moduleName };
final String changeName= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_add_requires_module_info, args);
final String changeDescription= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_add_requires_module_description, args);
ChangeCorrectionProposal proposal= new AddModuleRequiresCorrectionProposal(moduleName, changeName, changeDescription, currentModuleCompilationUnit, relevance);
Change change= proposal.getChange();
if (change != null) {
proposals.add(proposal);
modules.add(moduleName);
}
}
}
}
}
}
public static void getMethodProposals(IInvocationContext context, IProblemLocation problem, boolean isOnlyParameterMismatch, Collection<ICommandAccess> proposals) throws CoreException {
ICompilationUnit cu= context.getCompilationUnit();
CompilationUnit astRoot= context.getASTRoot();
ASTNode selectedNode= problem.getCoveringNode(astRoot);
if (!(selectedNode instanceof SimpleName)) {
return;
}
SimpleName nameNode= (SimpleName) selectedNode;
List<Expression> arguments;
Expression sender;
boolean isSuperInvocation;
ASTNode invocationNode= nameNode.getParent();
if (invocationNode instanceof MethodInvocation) {
MethodInvocation methodImpl= (MethodInvocation) invocationNode;
arguments= methodImpl.arguments();
sender= methodImpl.getExpression();
isSuperInvocation= false;
} else if (invocationNode instanceof SuperMethodInvocation) {
SuperMethodInvocation methodImpl= (SuperMethodInvocation) invocationNode;
arguments= methodImpl.arguments();
sender= methodImpl.getQualifier();
isSuperInvocation= true;
} else {
return;
}
String methodName= nameNode.getIdentifier();
int nArguments= arguments.size();
// corrections
IBinding[] bindings= (new ScopeAnalyzer(astRoot)).getDeclarationsInScope(nameNode, ScopeAnalyzer.METHODS);
HashSet<String> suggestedRenames= new HashSet<>();
for (int i= 0; i < bindings.length; i++) {
IMethodBinding binding= (IMethodBinding) bindings[i];
String curr= binding.getName();
if (!curr.equals(methodName) && binding.getParameterTypes().length == nArguments && NameMatcher.isSimilarName(methodName, curr) && suggestedRenames.add(curr)) {
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changemethod_description, BasicElementLabels.getJavaElementName(curr));
proposals.add(new RenameNodeCorrectionProposal(label, context.getCompilationUnit(), problem.getOffset(), problem.getLength(), curr, IProposalRelevance.CHANGE_METHOD));
}
}
suggestedRenames= null;
if (isOnlyParameterMismatch) {
ArrayList<IMethodBinding> parameterMismatchs= new ArrayList<>();
for (int i= 0; i < bindings.length; i++) {
IMethodBinding binding= (IMethodBinding) bindings[i];
if (binding.getName().equals(methodName)) {
parameterMismatchs.add(binding);
}
}
addParameterMissmatchProposals(context, problem, parameterMismatchs, invocationNode, arguments, proposals);
}
if (sender == null) {
addStaticImportFavoriteProposals(context, nameNode, true, proposals);
}
// new method
addNewMethodProposals(cu, astRoot, sender, arguments, isSuperInvocation, invocationNode, methodName, proposals);
if (!isOnlyParameterMismatch && !isSuperInvocation && sender != null) {
addMissingCastParentsProposal(cu, (MethodInvocation) invocationNode, proposals);
}
if (!isSuperInvocation && sender == null && invocationNode.getParent() instanceof ThrowStatement) {
String str= "new "; //$NON-NLS-1$ // do it the manual way, copting all the arguments is nasty
String label= CorrectionMessages.UnresolvedElementsSubProcessor_addnewkeyword_description;
int relevance= Character.isUpperCase(methodName.charAt(0)) ? IProposalRelevance.ADD_NEW_KEYWORD_UPPERCASE : IProposalRelevance.ADD_NEW_KEYWORD;
ReplaceCorrectionProposal proposal= new ReplaceCorrectionProposal(label, cu, invocationNode.getStartPosition(), 0, str, relevance);
proposals.add(proposal);
}
}
private static void addStaticImportFavoriteProposals(IInvocationContext context, SimpleName node, boolean isMethod, Collection<ICommandAccess> proposals) throws JavaModelException {
IJavaProject project= context.getCompilationUnit().getJavaProject();
if (JavaModelUtil.is50OrHigher(project)) {
String pref= PreferenceConstants.getPreference(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS, project);
String[] favourites= pref.split(";"); //$NON-NLS-1$
if (favourites.length == 0) {
return;
}
CompilationUnit root= context.getASTRoot();
AST ast= root.getAST();
String name= node.getIdentifier();
String[] staticImports= SimilarElementsRequestor.getStaticImportFavorites(context.getCompilationUnit(), name, isMethod, favourites);
for (int i= 0; i < staticImports.length; i++) {
String curr= staticImports[i];
ImportRewrite importRewrite= StubUtility.createImportRewrite(root, true);
ASTRewrite astRewrite= ASTRewrite.create(ast);
String label;
String qualifiedTypeName= Signature.getQualifier(curr);
String elementLabel= BasicElementLabels.getJavaElementName(JavaModelUtil.concatenateName(Signature.getSimpleName(qualifiedTypeName), name));
String res= importRewrite.addStaticImport(qualifiedTypeName, name, isMethod, new ContextSensitiveImportRewriteContext(root, node.getStartPosition(), importRewrite));
int dot= res.lastIndexOf('.');
if (dot != -1) {
String usedTypeName= importRewrite.addImport(qualifiedTypeName);
Name newName= ast.newQualifiedName(ast.newName(usedTypeName), ast.newSimpleName(name));
astRewrite.replace(node, newName, null);
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_change_to_static_import_description, elementLabel);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_add_static_import_description, elementLabel);
}
Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_IMPDECL);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), astRewrite, IProposalRelevance.ADD_STATIC_IMPORT, image);
proposal.setImportRewrite(importRewrite);
proposals.add(proposal);
}
}
}
private static void addNewMethodProposals(ICompilationUnit cu, CompilationUnit astRoot, Expression sender, List<Expression> arguments, boolean isSuperInvocation, ASTNode invocationNode, String methodName, Collection<ICommandAccess> proposals) throws JavaModelException {
ITypeBinding nodeParentType= Bindings.getBindingOfParentType(invocationNode);
ITypeBinding binding= null;
if (sender != null) {
binding= sender.resolveTypeBinding();
} else {
binding= nodeParentType;
if (isSuperInvocation && binding != null) {
binding= binding.getSuperclass();
}
}
if (binding != null && binding.isFromSource()) {
ITypeBinding senderDeclBinding= binding.getErasure().getTypeDeclaration();
ICompilationUnit targetCU= ASTResolving.findCompilationUnitForBinding(cu, astRoot, senderDeclBinding);
if (targetCU != null) {
String label;
Image image;
ITypeBinding[] parameterTypes= getParameterTypes(arguments);
if (parameterTypes != null) {
String sig= org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(methodName, parameterTypes, false);
boolean is18OrHigher= JavaModelUtil.is18OrHigher(targetCU.getJavaProject());
boolean isSenderBindingInterface= senderDeclBinding.isInterface();
if (nodeParentType == senderDeclBinding) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createmethod_description, sig);
if (isSenderBindingInterface) {
image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC);
} else {
image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PRIVATE);
}
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createmethod_other_description, new Object[] { sig, BasicElementLabels.getJavaElementName(senderDeclBinding.getName()) } );
image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC);
}
if (is18OrHigher || !isSenderBindingInterface
|| (nodeParentType != senderDeclBinding && (!(sender instanceof SimpleName) || !((SimpleName) sender).getIdentifier().equals(senderDeclBinding.getName())))) {
proposals.add(new NewMethodCorrectionProposal(label, targetCU, invocationNode, arguments, senderDeclBinding, IProposalRelevance.CREATE_METHOD, image));
}
if (senderDeclBinding.isNested() && cu.equals(targetCU) && sender == null && Bindings.findMethodInHierarchy(senderDeclBinding, methodName, (ITypeBinding[]) null) == null) { // no covering method
ASTNode anonymDecl= astRoot.findDeclaringNode(senderDeclBinding);
if (anonymDecl != null) {
senderDeclBinding= Bindings.getBindingOfParentType(anonymDecl.getParent());
isSenderBindingInterface= senderDeclBinding.isInterface();
if (!senderDeclBinding.isAnonymous()) {
if (is18OrHigher || !isSenderBindingInterface) {
String[] args= new String[] { sig, org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getTypeSignature(senderDeclBinding) };
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createmethod_other_description, args);
if (isSenderBindingInterface) {
image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC);
} else {
image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PROTECTED);
}
proposals.add(new NewMethodCorrectionProposal(label, targetCU, invocationNode, arguments, senderDeclBinding, IProposalRelevance.CREATE_METHOD, image));
}
}
}
}
}
}
}
}
private static void addMissingCastParentsProposal(ICompilationUnit cu, MethodInvocation invocationNode, Collection<ICommandAccess> proposals) {
Expression sender= invocationNode.getExpression();
if (sender instanceof ThisExpression) {
return;
}
ITypeBinding senderBinding= sender.resolveTypeBinding();
if (senderBinding == null || Modifier.isFinal(senderBinding.getModifiers())) {
return;
}
if (sender instanceof Name && ((Name) sender).resolveBinding() instanceof ITypeBinding) {
return; // static access
}
ASTNode parent= invocationNode.getParent();
while (parent instanceof Expression && parent.getNodeType() != ASTNode.CAST_EXPRESSION) {
parent= parent.getParent();
}
boolean hasCastProposal= false;
if (parent instanceof CastExpression) {
// (TestCase) x.getName() -> ((TestCase) x).getName
hasCastProposal= useExistingParentCastProposal(cu, (CastExpression) parent, sender, invocationNode.getName(), getArgumentTypes(invocationNode.arguments()), proposals);
}
if (!hasCastProposal) {
// x.getName() -> ((TestCase) x).getName
Expression target= sender;
while (target instanceof ParenthesizedExpression) {
target= ((ParenthesizedExpression) target).getExpression();
}
String label;
if (target.getNodeType() != ASTNode.CAST_EXPRESSION) {
String targetName= null;
if (target.getLength() <= 18) {
targetName= ASTNodes.asString(target);
}
if (targetName == null) {
label= CorrectionMessages.UnresolvedElementsSubProcessor_methodtargetcast_description;
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_methodtargetcast2_description, BasicElementLabels.getJavaCodeString(targetName));
}
} else {
String targetName= null;
if (target.getLength() <= 18) {
targetName= ASTNodes.asString(((CastExpression)target).getExpression());
}
if (targetName == null) {
label= CorrectionMessages.UnresolvedElementsSubProcessor_changemethodtargetcast_description;
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changemethodtargetcast2_description, BasicElementLabels.getJavaCodeString(targetName));
}
}
proposals.add(new CastCorrectionProposal(label, cu, target, (ITypeBinding) null, IProposalRelevance.CHANGE_CAST));
}
}
private static boolean useExistingParentCastProposal(ICompilationUnit cu, CastExpression expression, Expression accessExpression, SimpleName accessSelector, ITypeBinding[] paramTypes, Collection<ICommandAccess> proposals) {
ITypeBinding castType= expression.getType().resolveBinding();
if (castType == null) {
return false;
}
if (paramTypes != null) {
if (Bindings.findMethodInHierarchy(castType, accessSelector.getIdentifier(), paramTypes) == null) {
return false;
}
} else if (Bindings.findFieldInHierarchy(castType, accessSelector.getIdentifier()) == null) {
return false;
}
ITypeBinding bindingToCast= accessExpression.resolveTypeBinding();
if (bindingToCast != null && !bindingToCast.isCastCompatible(castType)) {
return false;
}
IMethodBinding res= Bindings.findMethodInHierarchy(castType, accessSelector.getIdentifier(), paramTypes);
if (res != null) {
AST ast= expression.getAST();
ASTRewrite rewrite= ASTRewrite.create(ast);
CastExpression newCast= ast.newCastExpression();
newCast.setType((Type) ASTNode.copySubtree(ast, expression.getType()));
newCast.setExpression((Expression) rewrite.createCopyTarget(accessExpression));
ParenthesizedExpression parents= ast.newParenthesizedExpression();
parents.setExpression(newCast);
ASTNode node= rewrite.createCopyTarget(expression.getExpression());
rewrite.replace(expression, node, null);
rewrite.replace(accessExpression, parents, null);
String label= CorrectionMessages.UnresolvedElementsSubProcessor_missingcastbrackets_description;
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CAST);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, cu, rewrite, IProposalRelevance.ADD_PARENTHESES_AROUND_CAST, image);
proposals.add(proposal);
return true;
}
return false;
}
private static void addParameterMissmatchProposals(IInvocationContext context, IProblemLocation problem, List<IMethodBinding> similarElements, ASTNode invocationNode, List<Expression> arguments, Collection<ICommandAccess> proposals) throws CoreException {
int nSimilarElements= similarElements.size();
ITypeBinding[] argTypes= getArgumentTypes(arguments);
if (argTypes == null || nSimilarElements == 0) {
return;
}
for (int i= 0; i < nSimilarElements; i++) {
IMethodBinding elem = similarElements.get(i);
int diff= elem.getParameterTypes().length - argTypes.length;
if (diff == 0) {
int nProposals= proposals.size();
doEqualNumberOfParameters(context, invocationNode, problem, arguments, argTypes, elem, proposals);
if (nProposals != proposals.size()) {
return; // only suggest for one method (avoid duplicated proposals)
}
} else if (diff > 0) {
doMoreParameters(context, invocationNode, argTypes, elem, proposals);
} else {
doMoreArguments(context, invocationNode, arguments, argTypes, elem, proposals);
}
}
}
private static void doMoreParameters(IInvocationContext context, ASTNode invocationNode, ITypeBinding[] argTypes, IMethodBinding methodBinding, Collection<ICommandAccess> proposals) throws CoreException {
ITypeBinding[] paramTypes= methodBinding.getParameterTypes();
int k= 0, nSkipped= 0;
int diff= paramTypes.length - argTypes.length;
int[] indexSkipped= new int[diff];
for (int i= 0; i < paramTypes.length; i++) {
if (k < argTypes.length && canAssign(argTypes[k], paramTypes[i])) {
k++; // match
} else {
if (nSkipped >= diff) {
return; // too different
}
indexSkipped[nSkipped++]= i;
}
}
ITypeBinding declaringType= methodBinding.getDeclaringClass();
ICompilationUnit cu= context.getCompilationUnit();
CompilationUnit astRoot= context.getASTRoot();
// add arguments
{
String[] arg= new String[] { org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(methodBinding) };
String label;
if (diff == 1) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_addargument_description, arg);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_addarguments_description, arg);
}
AddArgumentCorrectionProposal proposal= new AddArgumentCorrectionProposal(label, context.getCompilationUnit(), invocationNode, indexSkipped, paramTypes, IProposalRelevance.ADD_ARGUMENTS);
proposal.setImage(JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_ADD));
proposals.add(proposal);
}
// remove parameters
if (!declaringType.isFromSource()) {
return;
}
ICompilationUnit targetCU= ASTResolving.findCompilationUnitForBinding(cu, astRoot, declaringType);
if (targetCU != null) {
IMethodBinding methodDecl= methodBinding.getMethodDeclaration();
ITypeBinding[] declParameterTypes= methodDecl.getParameterTypes();
ChangeDescription[] changeDesc= new ChangeDescription[declParameterTypes.length];
ITypeBinding[] changedTypes= new ITypeBinding[diff];
for (int i= diff - 1; i >= 0; i--) {
int idx= indexSkipped[i];
changeDesc[idx]= new RemoveDescription();
changedTypes[i]= declParameterTypes[idx];
}
String[] arg= new String[] { org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(methodDecl), getTypeNames(changedTypes) };
String label;
if (methodDecl.isConstructor()) {
if (diff == 1) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_removeparam_constr_description, arg);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_removeparams_constr_description, arg);
}
} else {
if (diff == 1) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_removeparam_description, arg);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_removeparams_description, arg);
}
}
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_REMOVE);
ChangeMethodSignatureProposal proposal= new ChangeMethodSignatureProposal(label, targetCU, invocationNode, methodDecl, changeDesc, null, IProposalRelevance.CHANGE_METHOD_REMOVE_PARAMETER, image);
proposals.add(proposal);
}
}
private static String getTypeNames(ITypeBinding[] types) {
StringBuffer buf= new StringBuffer();
for (int i= 0; i < types.length; i++) {
if (i > 0) {
buf.append(", "); //$NON-NLS-1$
}
buf.append(org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getTypeSignature(types[i]));
}
return BasicElementLabels.getJavaElementName(buf.toString());
}
private static String getArgumentName(List<Expression> arguments, int index) {
String def= String.valueOf(index + 1);
ASTNode expr= arguments.get(index);
if (expr.getLength() > 18) {
return def;
}
ASTMatcher matcher= new ASTMatcher();
for (int i= 0; i < arguments.size(); i++) {
if (i != index && matcher.safeSubtreeMatch(expr, arguments.get(i))) {
return def;
}
}
return '\'' + BasicElementLabels.getJavaElementName(ASTNodes.asString(expr)) + '\'';
}
private static void doMoreArguments(IInvocationContext context, ASTNode invocationNode, List<Expression> arguments, ITypeBinding[] argTypes, IMethodBinding methodRef, Collection<ICommandAccess> proposals) throws CoreException {
ITypeBinding[] paramTypes= methodRef.getParameterTypes();
int k= 0, nSkipped= 0;
int diff= argTypes.length - paramTypes.length;
int[] indexSkipped= new int[diff];
for (int i= 0; i < argTypes.length; i++) {
if (k < paramTypes.length && canAssign(argTypes[i], paramTypes[k])) {
k++; // match
} else {
if (nSkipped >= diff) {
return; // too different
}
indexSkipped[nSkipped++]= i;
}
}
ICompilationUnit cu= context.getCompilationUnit();
CompilationUnit astRoot= context.getASTRoot();
// remove arguments
{
ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST());
for (int i= diff - 1; i >= 0; i--) {
rewrite.remove(arguments.get(indexSkipped[i]), null);
}
String[] arg= new String[] { org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(methodRef) };
String label;
if (diff == 1) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_removeargument_description, arg);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_removearguments_description, arg);
}
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_REMOVE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, cu, rewrite, IProposalRelevance.REMOVE_ARGUMENTS, image);
proposals.add(proposal);
}
IMethodBinding methodDecl= methodRef.getMethodDeclaration();
ITypeBinding declaringType= methodDecl.getDeclaringClass();
// add parameters
if (!declaringType.isFromSource()) {
return;
}
ICompilationUnit targetCU= ASTResolving.findCompilationUnitForBinding(cu, astRoot, declaringType);
if (targetCU != null) {
if (isImplicitConstructor(methodDecl)) {
return;
}
ChangeDescription[] changeDesc= new ChangeDescription[argTypes.length];
ITypeBinding[] changeTypes= new ITypeBinding[diff];
for (int i= diff - 1; i >= 0; i--) {
int idx= indexSkipped[i];
Expression arg= arguments.get(idx);
String name= getExpressionBaseName(arg);
ITypeBinding newType= Bindings.normalizeTypeBinding(argTypes[idx]);
if (newType == null) {
newType= astRoot.getAST().resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
}
if (newType.isWildcardType()) {
newType= ASTResolving.normalizeWildcardType(newType, true, astRoot.getAST());
}
if (!ASTResolving.isUseableTypeInContext(newType, methodDecl, false)) {
return;
}
changeDesc[idx]= new InsertDescription(newType, name);
changeTypes[i]= newType;
}
String[] arg= new String[] { org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(methodDecl), getTypeNames(changeTypes) };
String label;
if (methodDecl.isConstructor()) {
if (diff == 1) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_addparam_constr_description, arg);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_addparams_constr_description, arg);
}
} else {
if (diff == 1) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_addparam_description, arg);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_addparams_description, arg);
}
}
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_ADD);
ChangeMethodSignatureProposal proposal= new ChangeMethodSignatureProposal(label, targetCU, invocationNode, methodDecl, changeDesc, null, IProposalRelevance.CHANGE_METHOD_ADD_PARAMETER, image);
proposals.add(proposal);
}
}
private static boolean isImplicitConstructor(IMethodBinding meth) {
return meth.isDefaultConstructor();
}
private static ITypeBinding[] getParameterTypes(List<Expression> args) {
ITypeBinding[] params= new ITypeBinding[args.size()];
for (int i= 0; i < args.size(); i++) {
Expression expr= args.get(i);
ITypeBinding curr= Bindings.normalizeTypeBinding(expr.resolveTypeBinding());
if (curr != null && curr.isWildcardType()) {
curr= ASTResolving.normalizeWildcardType(curr, true, expr.getAST());
}
if (curr == null) {
curr= expr.getAST().resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
}
params[i]= curr;
}
return params;
}
private static void doEqualNumberOfParameters(IInvocationContext context, ASTNode invocationNode, IProblemLocation problem, List<Expression> arguments, ITypeBinding[] argTypes, IMethodBinding methodBinding, Collection<ICommandAccess> proposals) throws CoreException {
ITypeBinding[] paramTypes= methodBinding.getParameterTypes();
int[] indexOfDiff= new int[paramTypes.length];
int nDiffs= 0;
for (int n= 0; n < argTypes.length; n++) {
if (!canAssign(argTypes[n], paramTypes[n])) {
indexOfDiff[nDiffs++]= n;
}
}
ITypeBinding declaringTypeDecl= methodBinding.getDeclaringClass().getTypeDeclaration();
ICompilationUnit cu= context.getCompilationUnit();
CompilationUnit astRoot= context.getASTRoot();
ASTNode nameNode= problem.getCoveringNode(astRoot);
if (nameNode == null) {
return;
}
if (nDiffs == 0) {
if (nameNode.getParent() instanceof MethodInvocation) {
MethodInvocation inv= (MethodInvocation) nameNode.getParent();
if (inv.getExpression() == null) {
addQualifierToOuterProposal(context, inv, methodBinding, proposals);
}
}
return;
}
if (nDiffs == 1) { // one argument mismatching: try to fix
int idx= indexOfDiff[0];
Expression nodeToCast= arguments.get(idx);
ITypeBinding castType= paramTypes[idx];
castType= Bindings.normalizeTypeBinding(castType);
if (castType.isWildcardType()) {
castType= ASTResolving.normalizeWildcardType(castType, false, nodeToCast.getAST());
}
if (castType != null) {
ITypeBinding binding= nodeToCast.resolveTypeBinding();
ITypeBinding castFixType= null;
if (binding == null || castType.isCastCompatible(binding)) {
castFixType= castType;
} else if (JavaModelUtil.is50OrHigher(cu.getJavaProject())) {
ITypeBinding boxUnboxedTypeBinding= TypeMismatchSubProcessor.boxUnboxPrimitives(castType, binding, nodeToCast.getAST());
if (boxUnboxedTypeBinding != castType && boxUnboxedTypeBinding.isCastCompatible(binding)) {
castFixType= boxUnboxedTypeBinding;
}
}
if (castFixType != null) {
ASTRewriteCorrectionProposal proposal= TypeMismatchSubProcessor.createCastProposal(context, castFixType, nodeToCast, IProposalRelevance.CAST_ARGUMENT_1);
String castTypeName= BindingLabelProvider.getBindingLabel(castFixType, JavaElementLabels.ALL_DEFAULT);
String[] arg= new String[] { getArgumentName(arguments, idx), castTypeName};
proposal.setDisplayName(Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_addargumentcast_description, arg));
proposals.add(proposal);
}
TypeMismatchSubProcessor.addChangeSenderTypeProposals(context, nodeToCast, castType, false, IProposalRelevance.CAST_ARGUMENT_2, proposals);
}
}
if (nDiffs == 2) { // try to swap
int idx1= indexOfDiff[0];
int idx2= indexOfDiff[1];
boolean canSwap= canAssign(argTypes[idx1], paramTypes[idx2]) && canAssign(argTypes[idx2], paramTypes[idx1]);
if (canSwap) {
Expression arg1= arguments.get(idx1);
Expression arg2= arguments.get(idx2);
ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST());
rewrite.replace(arg1, rewrite.createCopyTarget(arg2), null);
rewrite.replace(arg2, rewrite.createCopyTarget(arg1), null);
{
String[] arg= new String[] { getArgumentName(arguments, idx1), getArgumentName(arguments, idx2) };
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_swaparguments_description, arg);
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.SWAP_ARGUMENTS, image);
proposals.add(proposal);
}
if (declaringTypeDecl.isFromSource()) {
ICompilationUnit targetCU= ASTResolving.findCompilationUnitForBinding(cu, astRoot, declaringTypeDecl);
if (targetCU != null) {
ChangeDescription[] changeDesc= new ChangeDescription[paramTypes.length];
for (int i= 0; i < nDiffs; i++) {
changeDesc[idx1]= new SwapDescription(idx2);
}
IMethodBinding methodDecl= methodBinding.getMethodDeclaration();
ITypeBinding[] declParamTypes= methodDecl.getParameterTypes();
ITypeBinding[] swappedTypes= new ITypeBinding[] { declParamTypes[idx1], declParamTypes[idx2] };
String[] args= new String[] { org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(methodDecl), getTypeNames(swappedTypes) };
String label;
if (methodDecl.isConstructor()) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_swapparams_constr_description, args);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_swapparams_description, args);
}
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ChangeMethodSignatureProposal proposal= new ChangeMethodSignatureProposal(label, targetCU, invocationNode, methodDecl, changeDesc, null, IProposalRelevance.CHANGE_METHOD_SWAP_PARAMETERS, image);
proposals.add(proposal);
}
}
return;
}
}
if (declaringTypeDecl.isFromSource()) {
ICompilationUnit targetCU= ASTResolving.findCompilationUnitForBinding(cu, astRoot, declaringTypeDecl);
if (targetCU != null) {
ChangeDescription[] changeDesc= createSignatureChangeDescription(indexOfDiff, nDiffs, paramTypes, arguments, argTypes);
if (changeDesc != null) {
IMethodBinding methodDecl= methodBinding.getMethodDeclaration();
ITypeBinding[] declParamTypes= methodDecl.getParameterTypes();
ITypeBinding[] newParamTypes= new ITypeBinding[changeDesc.length];
for (int i= 0; i < newParamTypes.length; i++) {
newParamTypes[i]= changeDesc[i] == null ? declParamTypes[i] : ((EditDescription) changeDesc[i]).type;
}
boolean isVarArgs= methodDecl.isVarargs() && newParamTypes.length > 0 && newParamTypes[newParamTypes.length - 1].isArray();
String[] args= new String[] { org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(methodDecl), org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature(methodDecl.getName(), newParamTypes, isVarArgs) };
String label;
if (methodDecl.isConstructor()) {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changeparamsignature_constr_description, args);
} else {
label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changeparamsignature_description, args);
}
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ChangeMethodSignatureProposal proposal= new ChangeMethodSignatureProposal(label, targetCU, invocationNode, methodDecl, changeDesc, null, IProposalRelevance.CHANGE_METHOD_SIGNATURE, image);
proposals.add(proposal);
}
}
}
}
private static ChangeDescription[] createSignatureChangeDescription(int[] indexOfDiff, int nDiffs, ITypeBinding[] paramTypes, List<Expression> arguments, ITypeBinding[] argTypes) {
ChangeDescription[] changeDesc= new ChangeDescription[paramTypes.length];
for (int i= 0; i < nDiffs; i++) {
int diffIndex= indexOfDiff[i];
Expression arg= arguments.get(diffIndex);
String name= getExpressionBaseName(arg);
ITypeBinding argType= argTypes[diffIndex];
if (argType.isWildcardType()) {
argType= ASTResolving.normalizeWildcardType(argType, true, arg.getAST());
if (argType== null) {
return null;
}
}
changeDesc[diffIndex]= new EditDescription(argType, name);
}
return changeDesc;
}
private static String getExpressionBaseName(Expression expr) {
IBinding argBinding= Bindings.resolveExpressionBinding(expr, true);
if (argBinding instanceof IVariableBinding) {
IJavaProject project= null;
ASTNode root= expr.getRoot();
if (root instanceof CompilationUnit) {
ITypeRoot typeRoot= ((CompilationUnit) root).getTypeRoot();
if (typeRoot != null)
project= typeRoot.getJavaProject();
}
return StubUtility.getBaseName((IVariableBinding)argBinding, project);
}
if (expr instanceof SimpleName)
return ((SimpleName) expr).getIdentifier();
return null;
}
private static ITypeBinding[] getArgumentTypes(List<Expression> arguments) {
ITypeBinding[] res= new ITypeBinding[arguments.size()];
for (int i= 0; i < res.length; i++) {
Expression expression= arguments.get(i);
ITypeBinding curr= expression.resolveTypeBinding();
if (curr == null) {
return null;
}
if (!curr.isNullType()) { // don't normalize null type
curr= Bindings.normalizeTypeBinding(curr);
if (curr == null) {
curr= expression.getAST().resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
}
}
res[i]= curr;
}
return res;
}
private static void addQualifierToOuterProposal(IInvocationContext context, MethodInvocation invocationNode, IMethodBinding binding, Collection<ICommandAccess> proposals) {
ITypeBinding declaringType= binding.getDeclaringClass();
ITypeBinding parentType= Bindings.getBindingOfParentType(invocationNode);
ITypeBinding currType= parentType;
boolean isInstanceMethod= !Modifier.isStatic(binding.getModifiers());
while (currType != null && !Bindings.isSuperType(declaringType, currType)) {
if (isInstanceMethod && Modifier.isStatic(currType.getModifiers())) {
return;
}
currType= currType.getDeclaringClass();
}
if (currType == null || currType == parentType) {
return;
}
ASTRewrite rewrite= ASTRewrite.create(invocationNode.getAST());
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_changetoouter_description, org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getTypeSignature(currType));
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.QUALIFY_WITH_ENCLOSING_TYPE, image);
ImportRewrite imports= proposal.createImportRewrite(context.getASTRoot());
ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(invocationNode, imports);
AST ast= invocationNode.getAST();
String qualifier= imports.addImport(currType, importRewriteContext);
Name name= ASTNodeFactory.newName(ast, qualifier);
Expression newExpression;
if (isInstanceMethod) {
ThisExpression expr= ast.newThisExpression();
expr.setQualifier(name);
newExpression= expr;
} else {
newExpression= name;
}
rewrite.set(invocationNode, MethodInvocation.EXPRESSION_PROPERTY, newExpression, null);
proposals.add(proposal);
}
public static void getConstructorProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException {
ICompilationUnit cu= context.getCompilationUnit();
CompilationUnit astRoot= context.getASTRoot();
ASTNode selectedNode= problem.getCoveringNode(astRoot);
if (selectedNode == null) {
return;
}
ITypeBinding targetBinding= null;
List<Expression> arguments= null;
IMethodBinding recursiveConstructor= null;
int type= selectedNode.getNodeType();
if (type == ASTNode.CLASS_INSTANCE_CREATION) {
ClassInstanceCreation creation= (ClassInstanceCreation) selectedNode;
IBinding binding= creation.getType().resolveBinding();
if (binding instanceof ITypeBinding) {
targetBinding= (ITypeBinding) binding;
arguments= creation.arguments();
}
} else if (type == ASTNode.SUPER_CONSTRUCTOR_INVOCATION) {
ITypeBinding typeBinding= Bindings.getBindingOfParentType(selectedNode);
if (typeBinding != null && !typeBinding.isAnonymous()) {
targetBinding= typeBinding.getSuperclass();
arguments= ((SuperConstructorInvocation) selectedNode).arguments();
}
} else if (type == ASTNode.CONSTRUCTOR_INVOCATION) {
ITypeBinding typeBinding= Bindings.getBindingOfParentType(selectedNode);
if (typeBinding != null && !typeBinding.isAnonymous()) {
targetBinding= typeBinding;
arguments= ((ConstructorInvocation) selectedNode).arguments();
recursiveConstructor= ASTResolving.findParentMethodDeclaration(selectedNode).resolveBinding();
}
}
if (targetBinding == null) {
return;
}
IMethodBinding[] methods= targetBinding.getDeclaredMethods();
ArrayList<IMethodBinding> similarElements= new ArrayList<>();
for (int i= 0; i < methods.length; i++) {
IMethodBinding curr= methods[i];
if (curr.isConstructor() && recursiveConstructor != curr) {
similarElements.add(curr); // similar elements can contain a implicit default constructor
}
}
addParameterMissmatchProposals(context, problem, similarElements, selectedNode, arguments, proposals);
if (targetBinding.isFromSource()) {
ITypeBinding targetDecl= targetBinding.getTypeDeclaration();
ICompilationUnit targetCU= ASTResolving.findCompilationUnitForBinding(cu, astRoot, targetDecl);
if (targetCU != null) {
String[] args= new String[] { org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getMethodSignature( org.eclipse.jdt.internal.ui.text.correction.ASTResolving.getTypeSignature(targetDecl), getParameterTypes(arguments), false) };
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_createconstructor_description, args);
Image image= JavaElementImageProvider.getDecoratedImage(JavaPluginImages.DESC_MISC_PUBLIC, JavaElementImageDescriptor.CONSTRUCTOR, JavaElementImageProvider.SMALL_SIZE);
proposals.add(new NewMethodCorrectionProposal(label, targetCU, selectedNode, arguments, targetDecl, IProposalRelevance.CREATE_CONSTRUCTOR, image));
}
}
}
public static void getAmbiguosTypeReferenceProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException {
final ICompilationUnit cu= context.getCompilationUnit();
int offset= problem.getOffset();
int len= problem.getLength();
IJavaElement[] elements= cu.codeSelect(offset, len);
for (int i= 0; i < elements.length; i++) {
IJavaElement curr= elements[i];
if (curr instanceof IType && !TypeFilter.isFiltered((IType) curr)) {
String qualifiedTypeName= ((IType) curr).getFullyQualifiedName('.');
CompilationUnit root= context.getASTRoot();
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_importexplicit_description, BasicElementLabels.getJavaElementName(qualifiedTypeName));
Image image= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_IMPDECL);
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, cu, ASTRewrite.create(root.getAST()), IProposalRelevance.IMPORT_EXPLICIT, image);
ImportRewrite imports= proposal.createImportRewrite(root);
imports.addImport(qualifiedTypeName);
proposals.add(proposal);
}
}
}
public static void getArrayAccessProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) {
CompilationUnit root= context.getASTRoot();
ASTNode selectedNode= problem.getCoveringNode(root);
if (!(selectedNode instanceof MethodInvocation)) {
return;
}
MethodInvocation decl= (MethodInvocation) selectedNode;
SimpleName nameNode= decl.getName();
String methodName= nameNode.getIdentifier();
IBinding[] bindings= (new ScopeAnalyzer(root)).getDeclarationsInScope(nameNode, ScopeAnalyzer.METHODS);
for (int i= 0; i < bindings.length; i++) {
String currName= bindings[i].getName();
if (NameMatcher.isSimilarName(methodName, currName)) {
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_arraychangetomethod_description, BasicElementLabels.getJavaElementName(currName));
proposals.add(new RenameNodeCorrectionProposal(label, context.getCompilationUnit(), nameNode.getStartPosition(), nameNode.getLength(), currName, IProposalRelevance.ARRAY_CHANGE_TO_METHOD));
}
}
// always suggest 'length'
String lengthId= "length"; //$NON-NLS-1$
String label= CorrectionMessages.UnresolvedElementsSubProcessor_arraychangetolength_description;
int offset= nameNode.getStartPosition();
int length= decl.getStartPosition() + decl.getLength() - offset;
proposals.add(new RenameNodeCorrectionProposal(label, context.getCompilationUnit(), offset, length, lengthId, IProposalRelevance.ARRAY_CHANGE_TO_LENGTH));
}
public static void getAnnotationMemberProposals(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) throws CoreException {
CompilationUnit astRoot= context.getASTRoot();
ICompilationUnit cu= context.getCompilationUnit();
ASTNode selectedNode= problem.getCoveringNode(astRoot);
Annotation annotation;
String memberName;
if (selectedNode.getLocationInParent() == MemberValuePair.NAME_PROPERTY) {
if (selectedNode.getParent().getLocationInParent() != NormalAnnotation.VALUES_PROPERTY) {
return;
}
annotation= (Annotation) selectedNode.getParent().getParent();
memberName= ((SimpleName) selectedNode).getIdentifier();
} else if (selectedNode.getLocationInParent() == SingleMemberAnnotation.VALUE_PROPERTY) {
annotation= (Annotation) selectedNode.getParent();
memberName= "value"; //$NON-NLS-1$
} else {
return;
}
ITypeBinding annotBinding= annotation.resolveTypeBinding();
if (annotBinding == null) {
return;
}
if (annotation instanceof NormalAnnotation) {
// similar names
IMethodBinding[] otherMembers= annotBinding.getDeclaredMethods();
for (int i= 0; i < otherMembers.length; i++) {
IMethodBinding binding= otherMembers[i];
String curr= binding.getName();
int relevance= NameMatcher.isSimilarName(memberName, curr) ? IProposalRelevance.CHANGE_TO_ATTRIBUTE_SIMILAR_NAME : IProposalRelevance.CHANGE_TO_ATTRIBUTE;
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_UnresolvedElementsSubProcessor_changetoattribute_description, BasicElementLabels.getJavaElementName(curr));
proposals.add(new RenameNodeCorrectionProposal(label, cu, problem.getOffset(), problem.getLength(), curr, relevance));
}
}
if (annotBinding.isFromSource()) {
ICompilationUnit targetCU= ASTResolving.findCompilationUnitForBinding(cu, astRoot, annotBinding);
if (targetCU != null) {
String label= Messages.format(CorrectionMessages.UnresolvedElementsSubProcessor_UnresolvedElementsSubProcessor_createattribute_description, BasicElementLabels.getJavaElementName(memberName));
Image image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC);
proposals.add(new NewAnnotationMemberProposal(label, targetCU, selectedNode, annotBinding, IProposalRelevance.CREATE_ATTRIBUTE, image));
}
}
}
}