1 11 package org.eclipse.jdt.internal.ui.text.javadoc; 12 13 14 import java.util.ArrayList ; 15 import java.util.List ; 16 17 import org.eclipse.core.resources.IFile; 18 19 import org.eclipse.swt.graphics.Image; 20 21 import org.eclipse.jface.resource.ImageDescriptor; 22 23 import org.eclipse.jface.text.BadLocationException; 24 import org.eclipse.jface.text.IDocument; 25 import org.eclipse.jface.text.IRegion; 26 import org.eclipse.jface.text.contentassist.IContextInformation; 27 28 import org.eclipse.ui.IEditorInput; 29 import org.eclipse.ui.part.FileEditorInput; 30 31 import org.eclipse.jdt.core.CompletionProposal; 32 import org.eclipse.jdt.core.CompletionRequestor; 33 import org.eclipse.jdt.core.ICompilationUnit; 34 import org.eclipse.jdt.core.IField; 35 import org.eclipse.jdt.core.IJavaElement; 36 import org.eclipse.jdt.core.IMember; 37 import org.eclipse.jdt.core.IMethod; 38 import org.eclipse.jdt.core.IType; 39 import org.eclipse.jdt.core.ITypeParameter; 40 import org.eclipse.jdt.core.JavaModelException; 41 import org.eclipse.jdt.core.Signature; 42 43 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 44 import org.eclipse.jdt.internal.corext.util.TypeFilter; 45 46 import org.eclipse.jdt.ui.JavaElementLabelProvider; 47 import org.eclipse.jdt.ui.JavaElementLabels; 48 import org.eclipse.jdt.ui.JavaUI; 49 import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; 50 import org.eclipse.jdt.ui.text.java.IJavadocCompletionProcessor; 51 52 import org.eclipse.jdt.internal.ui.JavaPlugin; 53 import org.eclipse.jdt.internal.ui.JavaPluginImages; 54 import org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal; 55 import org.eclipse.jdt.internal.ui.text.java.ProposalInfo; 56 import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider; 57 58 public class JavaDocCompletionEvaluator implements IJavadocCompletionProcessor, IJavaDocTagConstants, IHtmlTagConstants { 59 60 private static final String [] fgHTMLProposals= new String [HTML_GENERAL_TAGS.length * 2]; 61 { 62 String tag= null; 63 64 int index= 0; 65 int offset= 0; 66 67 while (index < fgHTMLProposals.length) { 68 69 tag= HTML_GENERAL_TAGS[offset]; 70 fgHTMLProposals[index++]= HTML_TAG_PREFIX + tag + HTML_TAG_POSTFIX; 71 fgHTMLProposals[index++]= HTML_CLOSE_PREFIX + tag + HTML_TAG_POSTFIX; 72 offset++; 73 } 74 } 75 76 private ICompilationUnit fCompilationUnit; 77 private IDocument fDocument; 78 private int fCurrentPos; 79 private int fCurrentLength; 80 81 private String fErrorMessage; 82 83 private JavaElementLabelProvider fLabelProvider; 84 private List fResult; 85 86 private boolean fRestrictToMatchingCase; 87 88 public JavaDocCompletionEvaluator() { 89 fResult= new ArrayList (); 90 } 91 92 private static boolean isWordPart(char ch) { 93 return Character.isJavaIdentifierPart(ch) || (ch == '#') || (ch == '.') || (ch == '/'); 94 } 95 96 private static int findCharBeforeWord(IDocument doc, int lineBeginPos, int pos) { 97 int currPos= pos - 1; 98 if (currPos > lineBeginPos) { 99 try { 100 while (currPos > lineBeginPos && isWordPart(doc.getChar(currPos))) { 101 currPos--; 102 } 103 return currPos; 104 } catch (BadLocationException e) { 105 } 107 } 108 return pos; 109 } 110 111 private static int findLastWhitespace(IDocument doc, int lineBeginPos, int pos) { 112 try { 113 int currPos= pos - 1; 114 while (currPos >= lineBeginPos && Character.isWhitespace(doc.getChar(currPos))) { 115 currPos--; 116 } 117 return currPos + 1; 118 } catch (BadLocationException e) { 119 } 121 return pos; 122 } 123 124 private static int findClosingCharacter(IDocument doc, int pos, int end, char endChar) throws BadLocationException { 125 int curr= pos; 126 while (curr < end && (doc.getChar(curr) != endChar)) { 127 curr++; 128 } 129 if (curr < end) { 130 return curr + 1; 131 } 132 return pos; 133 } 134 135 private static int findReplaceEndPos(IDocument doc, String newText, String oldText, int pos) { 136 if (oldText.length() == 0 || oldText.equals(newText)) { 137 return pos; 138 } 139 140 try { 141 IRegion lineInfo= doc.getLineInformationOfOffset(pos); 142 int end= lineInfo.getOffset() + lineInfo.getLength(); 143 144 if (newText.endsWith(">")) { return findClosingCharacter(doc, pos, end, '>'); 147 } 148 char ch= 0; 149 int pos1= pos; 150 while (pos1 < end && Character.isJavaIdentifierPart(ch= doc.getChar(pos1))) { 151 pos1++; 152 } 153 if (pos1 < end) { 154 if ((ch == '(') && newText.endsWith(")")) { return findClosingCharacter(doc, pos1, end, ')'); 157 } 158 159 } 160 return pos1; 161 } catch (BadLocationException e) { 162 } 164 return pos; 165 } 166 167 170 public IJavaCompletionProposal[] computeCompletionProposals(ICompilationUnit cu, int offset, int length, int flags) { 171 fCompilationUnit= cu; 172 fCurrentPos= offset; 173 fCurrentLength= length; 174 fRestrictToMatchingCase= (flags & RESTRICT_TO_MATCHING_CASE) != 0; 175 176 IEditorInput editorInput= new FileEditorInput((IFile) cu.getResource()); 177 fDocument= JavaUI.getDocumentProvider().getDocument(editorInput); 178 if (fDocument == null) { 179 return null; 180 } 181 182 fLabelProvider= new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_POST_QUALIFIED | JavaElementLabelProvider.SHOW_PARAMETERS); 183 try { 184 evalProposals(); 185 return (JavaCompletionProposal[]) fResult.toArray(new JavaCompletionProposal[fResult.size()]); 186 } catch (JavaModelException e) { 187 fErrorMessage= e.getLocalizedMessage(); 188 } finally { 189 fLabelProvider.dispose(); 190 fLabelProvider= null; 191 fResult.clear(); 192 } 193 return null; 194 } 195 196 private void evalProposals() throws JavaModelException { 197 try { 198 199 IRegion info= fDocument.getLineInformationOfOffset(fCurrentPos); 200 int lineBeginPos= info.getOffset(); 201 202 int word1Begin= findCharBeforeWord(fDocument, lineBeginPos, fCurrentPos); 203 if (word1Begin == fCurrentPos) { 204 return; 205 } 206 char firstChar= fDocument.getChar(word1Begin); 207 if (firstChar == '@') { 208 String prefix= fDocument.get(word1Begin, fCurrentPos - word1Begin); 209 addProposals(prefix, JAVADOC_GENERAL_TAGS, JavaPluginImages.IMG_OBJS_JAVADOCTAG); 210 return; 211 } else if (firstChar == '<') { 212 String prefix= fDocument.get(word1Begin, fCurrentPos - word1Begin); 213 addProposals(prefix, fgHTMLProposals, JavaPluginImages.IMG_OBJS_HTMLTAG); 214 return; 215 } else if (!Character.isWhitespace(firstChar)) { 216 return; 217 } 218 String prefix= fDocument.get(word1Begin + 1, fCurrentPos - word1Begin - 1); 219 220 int word2End= findLastWhitespace(fDocument, lineBeginPos, word1Begin); 222 if (word2End != lineBeginPos) { 223 int word2Begin= findCharBeforeWord(fDocument, lineBeginPos, word2End); 225 if (fDocument.getChar(word2Begin) == '@') { 226 String tag= fDocument.get(word2Begin, word2End - word2Begin); 227 if (addArgumentProposals(tag, prefix)) { 228 return; 229 } 230 } 231 } 232 addAllTags(prefix); 233 } catch (BadLocationException e) { 234 } 236 } 237 238 private boolean prefixMatches(String prefix, String proposal) { 239 if (fRestrictToMatchingCase) { 240 return proposal.startsWith(prefix); 241 } else if (proposal.length() >= prefix.length()) { 242 return prefix.equalsIgnoreCase(proposal.substring(0, prefix.length())); 243 } 244 return false; 245 } 246 247 248 249 250 private void addAllTags(String prefix) { 251 String jdocPrefix= "@" + prefix; for (int i= 0; i < JAVADOC_GENERAL_TAGS.length; i++) { 253 String curr= JAVADOC_GENERAL_TAGS[i]; 254 if (prefixMatches(jdocPrefix, curr)) { 255 fResult.add(createCompletion(curr, prefix, curr, JavaPluginImages.get(JavaPluginImages.IMG_OBJS_JAVADOCTAG), null, 0)); 256 } 257 } 258 String htmlPrefix= "<" + prefix; for (int i= 0; i < fgHTMLProposals.length; i++) { 260 String curr= fgHTMLProposals[i]; 261 if (prefixMatches(htmlPrefix, curr)) { 262 fResult.add(createCompletion(curr, prefix, curr, JavaPluginImages.get(JavaPluginImages.IMG_OBJS_HTMLTAG), null, 0)); 263 } 264 } 265 } 266 267 private void addProposals(String prefix, String [] choices, String imageName) { 268 for (int i= 0; i < choices.length; i++) { 269 String curr= choices[i]; 270 if (prefixMatches(prefix, curr)) { 271 fResult.add(createCompletion(curr, prefix, curr, JavaPluginImages.get(imageName), null, 0)); 272 } 273 } 274 } 275 276 private void addProposals(String prefix, IJavaElement[] choices) { 277 for (int i= 0; i < choices.length; i++) { 278 IJavaElement elem= choices[i]; 279 String curr= getReplaceString(elem); 280 if (prefixMatches(prefix, curr)) { 281 ProposalInfo info= (elem instanceof IMember) ? new ProposalInfo((IMember) elem) : null; 282 fResult.add(createCompletion(curr, prefix, fLabelProvider.getText(elem), fLabelProvider.getImage(elem), info, 0)); 283 } 284 } 285 } 286 287 private String getReplaceString(IJavaElement elem) { 288 if (elem instanceof IMethod) { 289 IMethod meth= (IMethod)elem; 290 StringBuffer buf= new StringBuffer (); 291 buf.append(meth.getElementName()); 292 buf.append('('); 293 String [] types= meth.getParameterTypes(); 294 int last= types.length - 1; 295 for (int i= 0; i <= last; i++) { 296 buf.append(Signature.toString(Signature.getTypeErasure(types[i]))); 297 if (i != last) { 298 buf.append(", "); } 300 } 301 buf.append(')'); 302 return buf.toString(); 303 } 304 return elem.getElementName(); 305 } 306 307 310 private boolean addArgumentProposals(String tag, String argument) throws JavaModelException { 311 IJavaElement elem= fCompilationUnit.getElementAt(fCurrentPos); 312 if ("@see".equals(tag) || "@link".equals(tag) || "@linkplain".equals(tag) || "@value".equals(tag)) { if (elem instanceof IMember) { 314 evalSeeTag((IMember) elem, argument); 315 return true; 316 } 317 } else if ("@param".equals(tag)) { if (elem instanceof IMethod) { 319 String [] names= ((IMethod)elem).getParameterNames(); 320 addProposals(argument, names, JavaPluginImages.IMG_MISC_DEFAULT); 321 ITypeParameter[] typeParameters= ((IMethod)elem).getTypeParameters(); 322 String [] typeParameterNames= new String [typeParameters.length]; 323 for (int i= 0; i < typeParameters.length; i++) { 324 typeParameterNames[i]= "<"+typeParameters[i].getElementName()+">"; } 326 addProposals(argument, typeParameterNames, JavaPluginImages.IMG_MISC_DEFAULT); 327 } else if (elem instanceof IType) { 328 ITypeParameter[] typeParameters= ((IType) elem).getTypeParameters(); 329 String [] typeParameterNames= new String [typeParameters.length]; 330 for (int i= 0; i < typeParameters.length; i++) { 331 typeParameterNames[i]= "<"+typeParameters[i].getElementName()+">"; } 333 addProposals(argument, typeParameterNames, JavaPluginImages.IMG_MISC_DEFAULT); 334 } 335 return true; 336 } else if ("@throws".equals(tag) || "@exception".equals(tag)) { if (elem instanceof IMethod) { 338 String [] exceptions= ((IMethod)elem).getExceptionTypes(); 339 for (int i= 0; i < exceptions.length; i++) { 340 String curr= Signature.toString(exceptions[i]); 341 if (prefixMatches(argument, curr)) { 342 fResult.add(createCompletion(curr, argument, curr, JavaPluginImages.get(JavaPluginImages.IMG_OBJS_CLASS), null, 100)); 343 } 344 } 345 evalTypeNameCompletions((IMethod)elem, fCurrentPos - argument.length(), argument); 346 } 347 return true; 348 } else if ("@serialData".equals(tag)) { if (elem instanceof IField) { 350 String name= ((IField)elem).getElementName(); 351 fResult.add(createCompletion(name, argument, name, fLabelProvider.getImage(elem), null, 0)); 352 } 353 return true; 354 } 355 return false; 356 } 357 358 private void evalSeeTag(IMember elem, String arg) throws JavaModelException { 359 int wordStart= fCurrentPos - arg.length(); 360 int pidx= arg.indexOf('#'); 361 if (pidx == -1) { 362 evalTypeNameCompletions(elem, wordStart, arg); 363 } else { 364 IType parent= null; 365 if (pidx > 0) { 366 parent= getTypeNameResolve(elem, wordStart, wordStart + pidx); 368 } else { 369 parent= (IType) elem.getAncestor(IJavaElement.TYPE); 371 } 372 373 if (parent != null) { 374 int nidx= arg.indexOf('(', pidx); 375 if (nidx == -1) { 376 nidx= arg.length(); 377 } 378 String prefix= arg.substring(pidx + 1, nidx); 379 380 addProposals(prefix, parent.getMethods()); 381 addProposals(prefix, parent.getFields()); 382 } 383 } 384 } 385 386 private void evalTypeNameCompletions(IMember currElem, int wordStart, String arg) throws JavaModelException { 387 ICompilationUnit preparedCU= createPreparedCU(currElem, wordStart, fCurrentPos); 388 if (preparedCU != null) { 389 CompletionRequestor requestor= new CompletionRequestor() { 390 public void accept(CompletionProposal proposal) { 391 if (proposal.getKind() == CompletionProposal.TYPE_REF) { 392 String fullTypeName= new String (Signature.toCharArray(proposal.getSignature())); 393 if (TypeFilter.isFiltered(fullTypeName)) { 394 return; 395 } 396 397 int start= proposal.getReplaceStart(); 398 int end= proposal.getReplaceEnd(); 399 char[] completion= proposal.getCompletion(); 400 fResult.add(createSeeTypeCompletion(proposal.getFlags(), start, end, completion, fullTypeName, proposal.getRelevance())); 401 } 402 } 403 }; 404 try { 405 preparedCU.codeComplete(fCurrentPos, requestor); 406 if (currElem.getDeclaringType() == null && fCurrentPos > wordStart && currElem.getElementName().startsWith(arg)) { 407 IType type= (IType) currElem; 409 char[] name= type.getElementName().toCharArray(); 410 fResult.add(createSeeTypeCompletion(0, wordStart, fCurrentPos, name, JavaModelUtil.getFullyQualifiedName(type), 50)); 411 } 412 } finally { 413 preparedCU.discardWorkingCopy(); 414 } 415 } 416 } 417 418 private IType getTypeNameResolve(IMember elem, int wordStart, int wordEnd) throws JavaModelException { 419 ICompilationUnit preparedCU= createPreparedCU(elem, wordStart, wordEnd); 420 if (preparedCU != null) { 421 try { 422 IJavaElement[] elements= preparedCU.codeSelect(wordEnd, 0); 423 if (elements != null && elements.length == 1 && elements[0] instanceof IType) { 424 IType type= (IType) elements[0]; 425 if (preparedCU.equals(type.getCompilationUnit())) { 426 IJavaElement[] res= elem.getCompilationUnit().findElements(type); 427 if (res.length > 0) { 428 return (IType) res[0]; 429 } 430 } else { 431 return type; 432 } 433 } 434 } finally { 435 preparedCU.getBuffer().setContents(fCompilationUnit.getBuffer().getCharacters()); 436 preparedCU.discardWorkingCopy(); 437 } 438 } 439 return null; 440 } 441 442 private ICompilationUnit createPreparedCU(IMember elem, int wordStart, int wordEnd) throws JavaModelException { 443 int startpos= elem.getSourceRange().getOffset(); 444 char[] content= (char[]) fCompilationUnit.getBuffer().getCharacters().clone(); 445 if ((elem.getDeclaringType() == null) && (wordStart + 6 < content.length)) { 446 content[startpos++]= 'i'; content[startpos++]= 'm'; content[startpos++]= 'p'; 447 content[startpos++]= 'o'; content[startpos++]= 'r'; content[startpos++]= 't'; 448 } 449 if (wordStart < content.length) { 450 for (int i= startpos; i < wordStart; i++) { 451 content[i]= ' '; 452 } 453 } 454 455 458 ICompilationUnit newCU= fCompilationUnit.getWorkingCopy(null); 459 newCU.getBuffer().setContents(content); 460 return newCU; 461 } 462 463 464 private JavaCompletionProposal createCompletion(String newText, String oldText, String labelText, Image image, ProposalInfo proposalInfo, int severity) { 465 int offset= fCurrentPos - oldText.length(); 466 int length= fCurrentLength + oldText.length(); 467 if (fCurrentLength == 0) 468 length= findReplaceEndPos(fDocument, newText, oldText, fCurrentPos) - offset; 469 470 JavaCompletionProposal proposal= new JavaCompletionProposal(newText, offset, length, image, labelText, severity); 471 proposal.setProposalInfo(proposalInfo); 472 proposal.setTriggerCharacters( new char[] { '#' }); 473 return proposal; 474 } 475 476 private JavaCompletionProposal createSeeTypeCompletion(int flags, int start, int end, char[] completion, String fullTypeName, int severity) { 477 ProposalInfo proposalInfo= new ProposalInfo(fCompilationUnit.getJavaProject(), fullTypeName); 478 StringBuffer nameBuffer= new StringBuffer (); 479 String simpleName= Signature.getSimpleName(fullTypeName); 480 nameBuffer.append(simpleName); 481 if (simpleName.length() != fullTypeName.length()) { 482 nameBuffer.append(JavaElementLabels.CONCAT_STRING); 483 nameBuffer.append(Signature.getQualifier(fullTypeName)); 484 } 485 ImageDescriptor desc= JavaElementImageProvider.getTypeImageDescriptor(false, false, flags, false); 486 Image image= JavaPlugin.getImageDescriptorRegistry().get(desc); 487 488 int compLen= completion.length; 489 if (compLen > 0 && completion[compLen - 1] == ';') { 490 compLen--; } 492 493 JavaCompletionProposal proposal= new JavaCompletionProposal(new String (completion, 0, compLen), start, end - start, image, nameBuffer.toString(), severity); 494 proposal.setProposalInfo(proposalInfo); 495 proposal.setTriggerCharacters( new char[] { '#' }); 496 return proposal; 497 } 498 499 500 503 public IContextInformation[] computeContextInformation(ICompilationUnit cu, int offset) { 504 fErrorMessage= null; 505 return null; 506 } 507 508 511 public String getErrorMessage() { 512 return fErrorMessage; 513 } 514 } 515 | Popular Tags |