1 11 package org.eclipse.jdt.internal.corext.codemanipulation; 12 13 import java.util.ArrayList ; 14 15 import org.eclipse.text.edits.MultiTextEdit; 16 import org.eclipse.text.edits.ReplaceEdit; 17 import org.eclipse.text.edits.TextEdit; 18 19 import org.eclipse.core.runtime.Assert; 20 import org.eclipse.core.runtime.CoreException; 21 import org.eclipse.core.runtime.IProgressMonitor; 22 import org.eclipse.core.runtime.IStatus; 23 import org.eclipse.core.runtime.NullProgressMonitor; 24 import org.eclipse.core.runtime.OperationCanceledException; 25 import org.eclipse.core.runtime.Status; 26 import org.eclipse.core.runtime.SubProgressMonitor; 27 import org.eclipse.core.runtime.jobs.ISchedulingRule; 28 29 import org.eclipse.core.resources.IWorkspaceRunnable; 30 31 import org.eclipse.jface.text.BadLocationException; 32 33 import org.eclipse.jdt.core.Flags; 34 import org.eclipse.jdt.core.IBuffer; 35 import org.eclipse.jdt.core.ICompilationUnit; 36 import org.eclipse.jdt.core.IJavaElement; 37 import org.eclipse.jdt.core.JavaModelException; 38 import org.eclipse.jdt.core.Signature; 39 import org.eclipse.jdt.core.dom.ASTNode; 40 import org.eclipse.jdt.core.dom.Annotation; 41 import org.eclipse.jdt.core.dom.CompilationUnit; 42 import org.eclipse.jdt.core.dom.IBinding; 43 import org.eclipse.jdt.core.dom.IMethodBinding; 44 import org.eclipse.jdt.core.dom.ITypeBinding; 45 import org.eclipse.jdt.core.dom.IVariableBinding; 46 import org.eclipse.jdt.core.dom.MarkerAnnotation; 47 import org.eclipse.jdt.core.dom.MethodInvocation; 48 import org.eclipse.jdt.core.dom.Modifier; 49 import org.eclipse.jdt.core.dom.Name; 50 import org.eclipse.jdt.core.dom.QualifiedName; 51 import org.eclipse.jdt.core.dom.QualifiedType; 52 import org.eclipse.jdt.core.dom.SimpleName; 53 import org.eclipse.jdt.core.dom.Type; 54 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 55 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext; 56 import org.eclipse.jdt.core.search.IJavaSearchConstants; 57 import org.eclipse.jdt.core.search.IJavaSearchScope; 58 import org.eclipse.jdt.core.search.SearchEngine; 59 import org.eclipse.jdt.core.search.SearchPattern; 60 import org.eclipse.jdt.core.search.TypeNameMatch; 61 62 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 63 import org.eclipse.jdt.internal.corext.dom.NodeFinder; 64 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 65 import org.eclipse.jdt.internal.corext.util.Messages; 66 import org.eclipse.jdt.internal.corext.util.TypeNameMatchCollector; 67 68 import org.eclipse.jdt.internal.ui.JavaPlugin; 69 import org.eclipse.jdt.internal.ui.JavaUIStatus; 70 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider; 71 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving; 72 import org.eclipse.jdt.internal.ui.text.correction.SimilarElementsRequestor; 73 74 80 public class AddImportsOperation implements IWorkspaceRunnable { 81 82 public static interface IChooseImportQuery { 83 90 TypeNameMatch chooseImport(TypeNameMatch[] openChoices, String containerName); 91 } 92 93 private ICompilationUnit fCompilationUnit; 94 private final int fSelectionOffset; 95 private final int fSelectionLength; 96 private final IChooseImportQuery fQuery; 97 private IStatus fStatus; 98 private boolean fDoSave; 99 100 101 112 public AddImportsOperation(ICompilationUnit cu, int selectionOffset, int selectionLength, IChooseImportQuery query, boolean save) { 113 super(); 114 Assert.isNotNull(cu); 115 116 fCompilationUnit= cu; 117 fSelectionOffset= selectionOffset; 118 fSelectionLength= selectionLength; 119 fQuery= query; 120 fStatus= Status.OK_STATUS; 121 fDoSave= save; 122 } 123 124 127 public IStatus getStatus() { 128 return fStatus; 129 } 130 131 137 public void run(IProgressMonitor monitor) throws CoreException, OperationCanceledException { 138 if (monitor == null) { 139 monitor= new NullProgressMonitor(); 140 } 141 try { 142 monitor.beginTask(CodeGenerationMessages.AddImportsOperation_description, 4); 143 144 CompilationUnit astRoot= JavaPlugin.getDefault().getASTProvider().getAST(fCompilationUnit, ASTProvider.WAIT_YES, new SubProgressMonitor(monitor, 1)); 145 146 ImportRewrite importRewrite= StubUtility.createImportRewrite(astRoot, true); 147 148 MultiTextEdit res= new MultiTextEdit(); 149 150 TextEdit edit= evaluateEdits(astRoot, importRewrite, fSelectionOffset, fSelectionLength, new SubProgressMonitor(monitor, 1)); 151 if (edit == null) { 152 return; 153 } 154 res.addChild(edit); 155 156 TextEdit importsEdit= importRewrite.rewriteImports(new SubProgressMonitor(monitor, 1)); 157 res.addChild(importsEdit); 158 159 JavaModelUtil.applyEdit(fCompilationUnit, res, fDoSave, new SubProgressMonitor(monitor, 1)); 160 } catch (BadLocationException e) { 161 throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, e)); 162 } finally { 163 monitor.done(); 164 } 165 } 166 167 private TextEdit evaluateEdits(CompilationUnit root, ImportRewrite importRewrite, int offset, int length, IProgressMonitor monitor) throws BadLocationException, JavaModelException { 168 SimpleName nameNode= null; 169 if (root != null) { ASTNode node= NodeFinder.perform(root, offset, length); 171 if (node instanceof MarkerAnnotation) { 172 node= ((Annotation) node).getTypeName(); 173 } 174 if (node instanceof QualifiedName) { 175 nameNode= ((QualifiedName) node).getName(); 176 } else if (node instanceof SimpleName) { 177 nameNode= (SimpleName) node; 178 } 179 } 180 181 String name, simpleName, containerName; 182 int qualifierStart; 183 int simpleNameStart; 184 if (nameNode != null) { 185 simpleName= nameNode.getIdentifier(); 186 simpleNameStart= nameNode.getStartPosition(); 187 if (nameNode.getLocationInParent() == QualifiedName.NAME_PROPERTY) { 188 Name qualifier= ((QualifiedName) nameNode.getParent()).getQualifier(); 189 containerName= qualifier.getFullyQualifiedName(); 190 name= JavaModelUtil.concatenateName(containerName, simpleName); 191 qualifierStart= qualifier.getStartPosition(); 192 } else if (nameNode.getParent().getLocationInParent() == QualifiedType.NAME_PROPERTY) { 193 Type qualifier= ((QualifiedType) nameNode.getParent().getParent()).getQualifier(); 194 containerName= ASTNodes.asString(qualifier); 195 name= JavaModelUtil.concatenateName(containerName, simpleName); 196 qualifierStart= qualifier.getStartPosition(); 197 } else if (nameNode.getLocationInParent() == MethodInvocation.NAME_PROPERTY) { 198 ASTNode qualifier= ((MethodInvocation) nameNode.getParent()).getExpression(); 199 if (qualifier instanceof Name) { 200 containerName= ASTNodes.asString(qualifier); 201 name= JavaModelUtil.concatenateName(containerName, simpleName); 202 qualifierStart= qualifier.getStartPosition(); 203 } else { 204 return null; 205 } 206 } else { 207 containerName= ""; name= simpleName; 209 qualifierStart= simpleNameStart; 210 } 211 212 IBinding binding= nameNode.resolveBinding(); 213 if (binding != null && !binding.isRecovered()) { 214 if (binding instanceof ITypeBinding) { 215 ITypeBinding typeBinding= (ITypeBinding) binding; 216 String qualifiedBindingName= typeBinding.getQualifiedName(); 217 if (containerName.length() > 0 && !qualifiedBindingName.equals(name)) { 218 return null; 219 } 220 221 String res= importRewrite.addImport(typeBinding); 222 if (containerName.length() > 0 && !res.equals(simpleName)) { 223 return null; 225 } 226 return new ReplaceEdit(qualifierStart, simpleNameStart - qualifierStart, new String ()); 227 } else if (binding instanceof IVariableBinding || binding instanceof IMethodBinding) { 228 boolean isField= binding instanceof IVariableBinding; 229 ITypeBinding declaringClass= isField ? ((IVariableBinding) binding).getDeclaringClass() : ((IMethodBinding) binding).getDeclaringClass(); 230 if (declaringClass == null) { 231 return null; } 233 if (Modifier.isStatic(binding.getModifiers())) { 234 if (Modifier.isPrivate(declaringClass.getModifiers())) { 235 fStatus= JavaUIStatus.createError(IStatus.ERROR, Messages.format(CodeGenerationMessages.AddImportsOperation_error_not_visible_class, declaringClass.getName()), null); 236 return null; 237 } 238 239 if (containerName.length() > 0) { 240 if (containerName.equals(declaringClass.getName()) || containerName.equals(declaringClass.getQualifiedName()) ) { 241 String res= importRewrite.addStaticImport(declaringClass.getQualifiedName(), binding.getName(), isField); 242 if (!res.equals(simpleName)) { 243 return null; 245 } 246 return new ReplaceEdit(qualifierStart, simpleNameStart - qualifierStart, ""); } 248 } 249 } 250 return null; } else { 252 return null; 253 } 254 } 255 if (binding != null && binding.getKind() != IBinding.TYPE) { 256 return null; 258 } 259 260 } else { 261 IBuffer buffer= fCompilationUnit.getBuffer(); 262 263 qualifierStart= getNameStart(buffer, offset); 264 int nameEnd= getNameEnd(buffer, offset + length); 265 int len= nameEnd - qualifierStart; 266 name= buffer.getText(qualifierStart, len).trim(); 267 if (name.length() == 0) { 268 return null; 269 } 270 271 simpleName= Signature.getSimpleName(name); 272 containerName= Signature.getQualifier(name); 273 274 simpleNameStart= getSimpleNameStart(buffer, qualifierStart, containerName); 275 276 int res= importRewrite.getDefaultImportRewriteContext().findInContext(containerName, simpleName, ImportRewriteContext.KIND_TYPE); 277 if (res == ImportRewriteContext.RES_NAME_CONFLICT) { 278 fStatus= JavaUIStatus.createError(IStatus.ERROR, CodeGenerationMessages.AddImportsOperation_error_importclash, null); 279 return null; 280 } else if (res == ImportRewriteContext.RES_NAME_FOUND) { 281 return new ReplaceEdit(qualifierStart, simpleNameStart - qualifierStart, ""); } 283 } 284 IJavaSearchScope searchScope= SearchEngine.createJavaSearchScope(new IJavaElement[] { fCompilationUnit.getJavaProject() }); 285 286 TypeNameMatch[] types= findAllTypes(simpleName, searchScope, nameNode, new SubProgressMonitor(monitor, 1)); 287 if (types.length == 0) { 288 fStatus= JavaUIStatus.createError(IStatus.ERROR, Messages.format(CodeGenerationMessages.AddImportsOperation_error_notresolved_message, simpleName), null); 289 return null; 290 } 291 292 if (monitor.isCanceled()) { 293 throw new OperationCanceledException(); 294 } 295 TypeNameMatch chosen; 296 if (types.length > 1 && fQuery != null) { 297 chosen= fQuery.chooseImport(types, containerName); 298 if (chosen == null) { 299 throw new OperationCanceledException(); 300 } 301 } else { 302 chosen= types[0]; 303 } 304 importRewrite.addImport(chosen.getFullyQualifiedName()); 305 return new ReplaceEdit(qualifierStart, simpleNameStart - qualifierStart, ""); } 307 308 309 private int getNameStart(IBuffer buffer, int pos) throws BadLocationException { 310 while (pos > 0) { 311 char ch= buffer.getChar(pos - 1); 312 if (!Character.isJavaIdentifierPart(ch) && ch != '.') { 313 return pos; 314 } 315 pos--; 316 } 317 return pos; 318 } 319 320 private int getNameEnd(IBuffer doc, int pos) throws BadLocationException { 321 if (pos > 0) { 322 if (Character.isWhitespace(doc.getChar(pos - 1))) { 323 return pos; 324 } 325 } 326 int len= doc.getLength(); 327 while (pos < len) { 328 char ch= doc.getChar(pos); 329 if (!Character.isJavaIdentifierPart(ch)) { 330 return pos; 331 } 332 pos++; 333 } 334 return pos; 335 } 336 337 private int getSimpleNameStart(IBuffer buffer, int nameStart, String containerName) throws BadLocationException { 338 int containerLen= containerName.length(); 339 int docLen= buffer.getLength(); 340 if ((containerLen > 0) && (nameStart + containerLen + 1 < docLen)) { 341 for (int k= 0; k < containerLen; k++) { 342 if (buffer.getChar(nameStart + k) != containerName.charAt(k)) { 343 return nameStart; 344 } 345 } 346 if (buffer.getChar(nameStart + containerLen) == '.') { 347 return nameStart + containerLen + 1; 348 } 349 } 350 return nameStart; 351 } 352 353 private int getSearchForConstant(int typeKinds) { 354 final int CLASSES= SimilarElementsRequestor.CLASSES; 355 final int INTERFACES= SimilarElementsRequestor.INTERFACES; 356 final int ENUMS= SimilarElementsRequestor.ENUMS; 357 final int ANNOTATIONS= SimilarElementsRequestor.ANNOTATIONS; 358 359 switch (typeKinds & (CLASSES | INTERFACES | ENUMS | ANNOTATIONS)) { 360 case CLASSES: return IJavaSearchConstants.CLASS; 361 case INTERFACES: return IJavaSearchConstants.INTERFACE; 362 case ENUMS: return IJavaSearchConstants.ENUM; 363 case ANNOTATIONS: return IJavaSearchConstants.ANNOTATION_TYPE; 364 case CLASSES | INTERFACES: return IJavaSearchConstants.CLASS_AND_INTERFACE; 365 case CLASSES | ENUMS: return IJavaSearchConstants.CLASS_AND_ENUM; 366 default: return IJavaSearchConstants.TYPE; 367 } 368 } 369 370 371 374 private TypeNameMatch[] findAllTypes(String simpleTypeName, IJavaSearchScope searchScope, SimpleName nameNode, IProgressMonitor monitor) throws JavaModelException { 375 boolean is50OrHigher= JavaModelUtil.is50OrHigher(fCompilationUnit.getJavaProject()); 376 377 int typeKinds= SimilarElementsRequestor.ALL_TYPES; 378 if (nameNode != null) { 379 typeKinds= ASTResolving.getPossibleTypeKinds(nameNode, is50OrHigher); 380 } 381 382 ArrayList typeInfos= new ArrayList (); 383 TypeNameMatchCollector requestor= new TypeNameMatchCollector(typeInfos); 384 int matchMode= SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE; 385 new SearchEngine().searchAllTypeNames(null, matchMode, simpleTypeName.toCharArray(), matchMode, getSearchForConstant(typeKinds), searchScope, requestor, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor); 386 387 ArrayList typeRefsFound= new ArrayList (typeInfos.size()); 388 for (int i= 0, len= typeInfos.size(); i < len; i++) { 389 TypeNameMatch curr= (TypeNameMatch) typeInfos.get(i); 390 if (curr.getPackageName().length() > 0) { if (isOfKind(curr, typeKinds, is50OrHigher) && isVisible(curr)) { 392 typeRefsFound.add(curr); 393 } 394 } 395 } 396 return (TypeNameMatch[]) typeRefsFound.toArray(new TypeNameMatch[typeRefsFound.size()]); 397 } 398 399 private boolean isOfKind(TypeNameMatch curr, int typeKinds, boolean is50OrHigher) { 400 int flags= curr.getModifiers(); 401 if (Flags.isAnnotation(flags)) { 402 return is50OrHigher && ((typeKinds & SimilarElementsRequestor.ANNOTATIONS) != 0); 403 } 404 if (Flags.isEnum(flags)) { 405 return is50OrHigher && ((typeKinds & SimilarElementsRequestor.ENUMS) != 0); 406 } 407 if (Flags.isInterface(flags)) { 408 return (typeKinds & SimilarElementsRequestor.INTERFACES) != 0; 409 } 410 return (typeKinds & SimilarElementsRequestor.CLASSES) != 0; 411 } 412 413 414 private boolean isVisible(TypeNameMatch curr) { 415 int flags= curr.getModifiers(); 416 if (Flags.isPrivate(flags)) { 417 return false; 418 } 419 if (Flags.isPublic(flags) || Flags.isProtected(flags)) { 420 return true; 421 } 422 return curr.getPackageName().equals(fCompilationUnit.getParent().getElementName()); 423 } 424 425 426 429 public ISchedulingRule getScheduleRule() { 430 return fCompilationUnit.getJavaProject().getResource(); 431 } 432 433 } 434 | Popular Tags |