2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com
.intellij
.lang
.java
;
19 import com
.intellij
.codeInsight
.CodeInsightBundle
;
20 import com
.intellij
.codeInsight
.documentation
.DocumentationManager
;
21 import com
.intellij
.codeInsight
.editorActions
.CodeDocumentationUtil
;
22 import com
.intellij
.codeInsight
.javadoc
.JavaDocExternalFilter
;
23 import com
.intellij
.codeInsight
.javadoc
.JavaDocInfoGenerator
;
24 import com
.intellij
.codeInsight
.javadoc
.JavaDocUtil
;
25 import com
.intellij
.featureStatistics
.FeatureUsageTracker
;
26 import com
.intellij
.ide
.BrowserUtil
;
27 import com
.intellij
.ide
.DataManager
;
28 import com
.intellij
.lang
.CodeDocumentationAwareCommenter
;
29 import com
.intellij
.lang
.LangBundle
;
30 import com
.intellij
.lang
.LanguageCommenters
;
31 import com
.intellij
.lang
.documentation
.CodeDocumentationProvider
;
32 import com
.intellij
.openapi
.module
.Module
;
33 import com
.intellij
.openapi
.module
.ModuleUtil
;
34 import com
.intellij
.openapi
.project
.Project
;
35 import com
.intellij
.openapi
.roots
.*;
36 import com
.intellij
.openapi
.ui
.Messages
;
37 import com
.intellij
.openapi
.ui
.popup
.JBPopup
;
38 import com
.intellij
.openapi
.ui
.popup
.JBPopupFactory
;
39 import com
.intellij
.openapi
.ui
.popup
.PopupStep
;
40 import com
.intellij
.openapi
.ui
.popup
.util
.BaseListPopupStep
;
41 import com
.intellij
.openapi
.util
.io
.FileUtil
;
42 import com
.intellij
.openapi
.vfs
.JarFileSystem
;
43 import com
.intellij
.openapi
.vfs
.VirtualFile
;
44 import com
.intellij
.openapi
.vfs
.VirtualFileManager
;
45 import com
.intellij
.openapi
.vfs
.VirtualFileSystem
;
46 import com
.intellij
.openapi
.vfs
.ex
.http
.HttpFileSystem
;
47 import com
.intellij
.psi
.*;
48 import com
.intellij
.psi
.impl
.beanProperties
.BeanPropertyElement
;
49 import com
.intellij
.psi
.impl
.source
.javadoc
.PsiDocParamRef
;
50 import com
.intellij
.psi
.infos
.CandidateInfo
;
51 import com
.intellij
.psi
.javadoc
.PsiDocComment
;
52 import com
.intellij
.psi
.javadoc
.PsiDocTag
;
53 import com
.intellij
.psi
.util
.PsiFormatUtil
;
54 import com
.intellij
.util
.ArrayUtil
;
55 import com
.intellij
.util
.StringBuilderSpinAllocator
;
56 import com
.intellij
.util
.containers
.HashMap
;
57 import org
.jetbrains
.annotations
.NonNls
;
58 import org
.jetbrains
.annotations
.NotNull
;
59 import org
.jetbrains
.annotations
.Nullable
;
64 * Created by IntelliJ IDEA.
65 * User: Maxim.Mossienko
68 * To change this template use File | Settings | File Templates.
70 public class JavaDocumentationProvider
implements CodeDocumentationProvider
{
71 private static final String LINE_SEPARATOR
= "\n";
73 @NonNls private static final String PARAM_TAG
= "@param";
74 @NonNls private static final String RETURN_TAG
= "@return";
75 @NonNls private static final String THROWS_TAG
= "@throws";
76 @NonNls public static final String HTML_EXTENSION
= ".html";
77 @NonNls public static final String PACKAGE_SUMMARY_FILE
= "package-summary.html";
79 public String
getQuickNavigateInfo(PsiElement element
) {
80 if (element
instanceof PsiClass
) {
81 return generateClassInfo((PsiClass
)element
);
83 else if (element
instanceof PsiMethod
) {
84 return generateMethodInfo((PsiMethod
)element
);
86 else if (element
instanceof PsiField
) {
87 return generateFieldInfo((PsiField
)element
);
89 else if (element
instanceof PsiVariable
) {
90 return generateVariableInfo((PsiVariable
)element
);
92 else if (element
instanceof PsiPackage
) {
93 return generatePackageInfo((PsiPackage
)element
);
95 else if (element
instanceof BeanPropertyElement
) {
96 return generateMethodInfo(((BeanPropertyElement
) element
).getMethod());
101 public List
<String
> getUrlFor(final PsiElement element
, final PsiElement originalElement
) {
102 return getExternalJavaDocUrl(element
);
105 private static void newLine(StringBuffer buffer
) {
106 // Don't know why space has to be added after newline for good text alignment...
107 buffer
.append("\n ");
110 private static void generateType(@NonNls StringBuffer buffer
, PsiType type
, PsiElement context
) {
111 if (type
instanceof PsiPrimitiveType
) {
112 buffer
.append(type
.getCanonicalText());
117 if (type
instanceof PsiWildcardType
) {
118 PsiWildcardType wc
= ((PsiWildcardType
)type
);
119 PsiType bound
= wc
.getBound();
124 buffer
.append(wc
.isExtends() ?
" extends " : " super ");
125 generateType(buffer
, bound
, context
);
129 if (type
instanceof PsiArrayType
) {
130 generateType(buffer
, ((PsiArrayType
)type
).getComponentType(), context
);
131 if (type
instanceof PsiEllipsisType
) {
132 buffer
.append("...");
141 if (type
instanceof PsiClassType
) {
142 PsiClassType
.ClassResolveResult result
= ((PsiClassType
)type
).resolveGenerics();
143 PsiClass psiClass
= result
.getElement();
144 PsiSubstitutor psiSubst
= result
.getSubstitutor();
146 if (psiClass
== null || psiClass
instanceof PsiTypeParameter
) {
147 buffer
.append(type
.getPresentableText());
151 buffer
.append(JavaDocUtil
.getShortestClassName(psiClass
, context
));
153 if (psiClass
.hasTypeParameters()) {
154 StringBuffer subst
= new StringBuffer();
155 boolean goodSubst
= true;
157 PsiTypeParameter
[] params
= psiClass
.getTypeParameters();
160 for (int i
= 0; i
< params
.length
; i
++) {
161 PsiType t
= psiSubst
.substitute(params
[i
]);
168 generateType(subst
, t
, context
);
170 if (i
< params
.length
- 1) {
177 String text
= subst
.toString();
185 private static void generateInitializer(StringBuffer buffer
, PsiVariable variable
) {
186 PsiExpression initializer
= variable
.getInitializer();
187 if (initializer
!= null) {
188 String text
= initializer
.getText().trim();
189 int index1
= text
.indexOf('\n');
190 if (index1
< 0) index1
= text
.length();
191 int index2
= text
.indexOf('\r');
192 if (index2
< 0) index2
= text
.length();
193 int index
= Math
.min(index1
, index2
);
194 boolean trunc
= index
< text
.length();
195 text
= text
.substring(0, index
);
196 buffer
.append(" = ");
199 buffer
.append("...");
204 private static void generateModifiers(StringBuffer buffer
, PsiElement element
) {
205 String modifiers
= PsiFormatUtil
.formatModifiers(element
, PsiFormatUtil
.JAVADOC_MODIFIERS_ONLY
);
207 if (modifiers
.length() > 0) {
208 buffer
.append(modifiers
);
213 private static String
generatePackageInfo(PsiPackage aPackage
) {
214 return aPackage
.getQualifiedName();
217 @SuppressWarnings({"HardCodedStringLiteral"})
218 private static String
generateClassInfo(PsiClass aClass
) {
219 StringBuffer buffer
= new StringBuffer();
221 if (aClass
instanceof PsiAnonymousClass
) return LangBundle
.message("java.terms.anonymous.class");
223 PsiFile file
= aClass
.getContainingFile();
224 final Module module
= ModuleUtil
.findModuleForPsiElement(file
);
225 if (module
!= null) {
226 buffer
.append('[').append(module
.getName()).append("] ");
229 if (file
instanceof PsiJavaFile
) {
230 String packageName
= ((PsiJavaFile
)file
).getPackageName();
231 if (packageName
.length() > 0) {
232 buffer
.append(packageName
);
237 generateModifiers(buffer
, aClass
);
239 final String classString
= aClass
.isAnnotationType() ?
"java.terms.annotation.interface"
240 : aClass
.isInterface()
241 ?
"java.terms.interface"
242 : aClass
instanceof PsiTypeParameter
243 ?
"java.terms.type.parameter"
244 : aClass
.isEnum() ?
"java.terms.enum" : "java.terms.class";
245 buffer
.append(LangBundle
.message(classString
)).append(" ");
247 buffer
.append(JavaDocUtil
.getShortestClassName(aClass
, aClass
));
249 if (aClass
.hasTypeParameters()) {
250 PsiTypeParameter
[] parms
= aClass
.getTypeParameters();
254 for (int i
= 0; i
< parms
.length
; i
++) {
255 PsiTypeParameter p
= parms
[i
];
257 buffer
.append(p
.getName());
259 PsiClassType
[] refs
= p
.getExtendsList().getReferencedTypes();
261 if (refs
.length
> 0) {
262 buffer
.append(" extends ");
264 for (int j
= 0; j
< refs
.length
; j
++) {
265 generateType(buffer
, refs
[j
], aClass
);
267 if (j
< refs
.length
- 1) {
268 buffer
.append(" & ");
273 if (i
< parms
.length
- 1) {
282 if (!aClass
.isEnum() && !aClass
.isAnnotationType()) {
283 PsiReferenceList extendsList
= aClass
.getExtendsList();
284 refs
= extendsList
== null ? PsiClassType
.EMPTY_ARRAY
: extendsList
.getReferencedTypes();
285 if (refs
.length
> 0 || !aClass
.isInterface() && !"java.lang.Object".equals(aClass
.getQualifiedName())) {
286 buffer
.append(" extends ");
287 if (refs
.length
== 0) {
288 buffer
.append("Object");
291 for (int i
= 0; i
< refs
.length
; i
++) {
292 generateType(buffer
, refs
[i
], aClass
);
294 if (i
< refs
.length
- 1) {
302 refs
= aClass
.getImplementsListTypes();
303 if (refs
.length
> 0) {
305 buffer
.append("implements ");
306 for (int i
= 0; i
< refs
.length
; i
++) {
307 generateType(buffer
, refs
[i
], aClass
);
309 if (i
< refs
.length
- 1) {
315 return buffer
.toString();
318 @SuppressWarnings({"HardCodedStringLiteral"})
319 public static String
generateMethodInfo(PsiMethod method
) {
320 StringBuffer buffer
= new StringBuffer();
322 PsiClass parentClass
= method
.getContainingClass();
324 if (parentClass
!= null) {
325 buffer
.append(JavaDocUtil
.getShortestClassName(parentClass
, method
));
329 generateModifiers(buffer
, method
);
331 PsiTypeParameter
[] params
= method
.getTypeParameters();
333 if (params
.length
> 0) {
335 for (int i
= 0; i
< params
.length
; i
++) {
336 PsiTypeParameter param
= params
[i
];
338 buffer
.append(param
.getName());
340 PsiClassType
[] extendees
= param
.getExtendsList().getReferencedTypes();
342 if (extendees
.length
> 0) {
343 buffer
.append(" extends ");
345 for (int j
= 0; j
< extendees
.length
; j
++) {
346 generateType(buffer
, extendees
[j
], method
);
348 if (j
< extendees
.length
- 1) {
349 buffer
.append(" & ");
354 if (i
< params
.length
- 1) {
361 if (method
.getReturnType() != null) {
362 generateType(buffer
, method
.getReturnType(), method
);
366 buffer
.append(method
.getName());
369 PsiParameter
[] parms
= method
.getParameterList().getParameters();
370 for (int i
= 0; i
< parms
.length
; i
++) {
371 PsiParameter parm
= parms
[i
];
372 generateType(buffer
, parm
.getType(), method
);
374 if (parm
.getName() != null) {
375 buffer
.append(parm
.getName());
377 if (i
< parms
.length
- 1) {
384 PsiClassType
[] refs
= method
.getThrowsList().getReferencedTypes();
385 if (refs
.length
> 0) {
387 buffer
.append(" throws ");
388 for (int i
= 0; i
< refs
.length
; i
++) {
389 PsiClass throwsClass
= refs
[i
].resolve();
391 if (throwsClass
!= null) {
392 buffer
.append(JavaDocUtil
.getShortestClassName(throwsClass
, method
));
395 buffer
.append(refs
[i
].getPresentableText());
398 if (i
< refs
.length
- 1) {
404 return buffer
.toString();
407 private static String
generateFieldInfo(PsiField field
) {
408 StringBuffer buffer
= new StringBuffer();
409 PsiClass parentClass
= field
.getContainingClass();
411 if (parentClass
!= null) {
412 buffer
.append(JavaDocUtil
.getShortestClassName(parentClass
, field
));
416 generateModifiers(buffer
, field
);
418 generateType(buffer
, field
.getType(), field
);
420 buffer
.append(field
.getName());
422 generateInitializer(buffer
, field
);
424 return buffer
.toString();
427 private static String
generateVariableInfo(PsiVariable variable
) {
428 StringBuffer buffer
= new StringBuffer();
430 generateModifiers(buffer
, variable
);
432 generateType(buffer
, variable
.getType(), variable
);
436 buffer
.append(variable
.getName());
437 generateInitializer(buffer
, variable
);
439 return buffer
.toString();
442 public PsiComment
findExistingDocComment(final PsiComment _element
) {
443 PsiElement parentElement
= _element
.getParent();
445 return parentElement
instanceof PsiDocCommentOwner ?
((PsiDocCommentOwner
)parentElement
).getDocComment() : null;
448 public String
generateDocumentationContentStub(PsiComment _element
) {
449 PsiElement parentElement
= _element
.getParent();
450 final Project project
= _element
.getProject();
451 final StringBuilder builder
= StringBuilderSpinAllocator
.alloc();
453 if (parentElement
instanceof PsiMethod
) {
454 PsiMethod psiMethod
= (PsiMethod
)parentElement
;
455 final PsiParameter
[] parameters
= psiMethod
.getParameterList().getParameters();
456 final CodeDocumentationAwareCommenter commenter
= (CodeDocumentationAwareCommenter
)LanguageCommenters
.INSTANCE
457 .forLanguage(parentElement
.getLanguage());
458 final Map
<String
, String
> param2Description
= new HashMap
<String
, String
>();
459 final PsiMethod
[] superMethods
= psiMethod
.findSuperMethods();
460 for (PsiMethod superMethod
: superMethods
) {
461 final PsiDocComment comment
= superMethod
.getDocComment();
462 if (comment
!= null) {
463 final PsiDocTag
[] params
= comment
.findTagsByName("param");
464 for (PsiDocTag param
: params
) {
465 final PsiElement
[] dataElements
= param
.getDataElements();
466 if (dataElements
!= null) {
467 String paramName
= null;
468 for (PsiElement dataElement
: dataElements
) {
469 if (dataElement
instanceof PsiDocParamRef
) {
470 paramName
= dataElement
.getReference().getCanonicalText();
474 if (paramName
!= null) {
475 param2Description
.put(paramName
, param
.getText());
481 for (PsiParameter parameter
: parameters
) {
482 String description
= param2Description
.get(parameter
.getName());
483 if (description
!= null) {
484 builder
.append(CodeDocumentationUtil
.createDocCommentLine("", project
, commenter
));
485 if (description
.indexOf('\n') > -1) description
= description
.substring(0, description
.lastIndexOf('\n'));
486 builder
.append(description
);
489 builder
.append(CodeDocumentationUtil
.createDocCommentLine(PARAM_TAG
, project
, commenter
));
490 builder
.append(parameter
.getName());
492 builder
.append(LINE_SEPARATOR
);
495 final PsiTypeParameterList typeParameterList
= psiMethod
.getTypeParameterList();
496 if (typeParameterList
!= null) {
497 createTypeParamsListComment(builder
, project
, commenter
, typeParameterList
);
499 if (psiMethod
.getReturnType() != null && psiMethod
.getReturnType() != PsiType
.VOID
) {
500 builder
.append(CodeDocumentationUtil
.createDocCommentLine(RETURN_TAG
, project
, commenter
));
501 builder
.append(LINE_SEPARATOR
);
504 final PsiJavaCodeReferenceElement
[] references
= psiMethod
.getThrowsList().getReferenceElements();
505 for (PsiJavaCodeReferenceElement reference
: references
) {
506 builder
.append(CodeDocumentationUtil
.createDocCommentLine(THROWS_TAG
, project
, commenter
));
507 builder
.append(reference
.getText());
508 builder
.append(LINE_SEPARATOR
);
511 else if (parentElement
instanceof PsiClass
) {
512 final PsiTypeParameterList typeParameterList
= ((PsiClass
)parentElement
).getTypeParameterList();
513 if (typeParameterList
!= null) {
514 final CodeDocumentationAwareCommenter commenter
= (CodeDocumentationAwareCommenter
)LanguageCommenters
.INSTANCE
515 .forLanguage(parentElement
.getLanguage());
516 createTypeParamsListComment(builder
, project
, commenter
, typeParameterList
);
519 return builder
.length() > 0 ? builder
.toString() : null;
522 StringBuilderSpinAllocator
.dispose(builder
);
526 private static void createTypeParamsListComment(final StringBuilder buffer
,
527 final Project project
,
528 final CodeDocumentationAwareCommenter commenter
,
529 final PsiTypeParameterList typeParameterList
) {
530 final PsiTypeParameter
[] typeParameters
= typeParameterList
.getTypeParameters();
531 for (PsiTypeParameter typeParameter
: typeParameters
) {
532 buffer
.append(CodeDocumentationUtil
.createDocCommentLine(PARAM_TAG
, project
, commenter
));
533 buffer
.append("<").append(typeParameter
.getName()).append(">");
534 buffer
.append(LINE_SEPARATOR
);
538 public String
generateDoc(final PsiElement element
, final PsiElement originalElement
) {
539 if (element
instanceof PsiMethodCallExpression
) {
540 return getMethodCandidateInfo((PsiMethodCallExpression
)element
);
544 //external documentation finder
545 return generateExternalJavadoc(element
);
548 public PsiElement
getDocumentationElementForLookupItem(final PsiManager psiManager
, final Object object
, final PsiElement element
) {
553 public static String
generateExternalJavadoc(final PsiElement element
) {
554 final JavaDocInfoGenerator javaDocInfoGenerator
= new JavaDocInfoGenerator(element
.getProject(), element
);
555 JavaDocExternalFilter docFilter
= new JavaDocExternalFilter(element
.getProject());
556 List
<String
> docURLs
= getExternalJavaDocUrl(element
);
558 if (docURLs
!= null) {
559 for (String docURL
: docURLs
) {
560 final String javadoc
= generateExternalJavadoc(element
, docURL
, true, docFilter
);
561 if (javadoc
!= null) return javadoc
;
565 return JavaDocExternalFilter
.filterInternalDocInfo(javaDocInfoGenerator
.generateDocInfo());
570 private static String
generateExternalJavadoc(final PsiElement element
, String fromUrl
, boolean checkCompiled
, JavaDocExternalFilter filter
) {
571 if (!checkCompiled
|| element
instanceof PsiCompiledElement
) {
573 String externalDoc
= filter
.getExternalDocInfoForElement(fromUrl
, element
);
574 if (externalDoc
!= null && externalDoc
.length() > 0) {
578 catch (Exception e
) {
579 //try to generate some javadoc
585 private String
getMethodCandidateInfo(PsiMethodCallExpression expr
) {
586 final PsiResolveHelper rh
= JavaPsiFacade
.getInstance(expr
.getProject()).getResolveHelper();
587 final CandidateInfo
[] candidates
= rh
.getReferencedMethodCandidates(expr
, true);
588 final String text
= expr
.getText();
589 if (candidates
.length
> 0) {
590 @NonNls final StringBuffer sb
= new StringBuffer();
592 for (final CandidateInfo candidate
: candidates
) {
593 final PsiElement element
= candidate
.getElement();
595 if (!(element
instanceof PsiMethod
)) {
599 final String str
= PsiFormatUtil
.formatMethod((PsiMethod
)element
, candidate
.getSubstitutor(),
600 PsiFormatUtil
.SHOW_NAME
| PsiFormatUtil
.SHOW_TYPE
| PsiFormatUtil
.SHOW_PARAMETERS
,
601 PsiFormatUtil
.SHOW_TYPE
);
602 createElementLink(sb
, element
, str
);
605 return CodeInsightBundle
.message("javadoc.candiates", text
, sb
);
608 return CodeInsightBundle
.message("javadoc.candidates.not.found", text
);
611 private void createElementLink(@NonNls final StringBuffer sb
, final PsiElement element
, final String str
) {
612 sb
.append(" <a href=\"psi_element://");
613 sb
.append(JavaDocUtil
.getReferenceText(element
.getProject(), element
));
620 public boolean isExternalDocumentationEnabled(final PsiElement element
, final PsiElement originalElement
) {
621 boolean actionEnabled
= element
!= null && getExternalJavaDocUrl(element
) != null;
622 if (element
instanceof PsiVariable
&& !(element
instanceof PsiField
)) {
623 actionEnabled
= false;
625 return actionEnabled
;
628 public String
getExternalDocumentation(@NotNull final String url
, final Project project
) throws Exception
{
629 if (JavaDocExternalFilter
.isJavaDocURL(url
)) {
630 String text
= new JavaDocExternalFilter(project
).getExternalDocInfo(url
);
638 public void openExternalDocumentation(final PsiElement element
, final PsiElement originalElement
) {
639 FeatureUsageTracker
.getInstance().triggerFeatureUsed("codeassists.javadoc.external");
640 List
<String
> urls
= getExternalJavaDocUrl(element
);
641 if (urls
!= null && !urls
.isEmpty()) {
642 final JavaDocExternalFilter filter
= new JavaDocExternalFilter(element
.getProject());
643 for (Iterator
<String
> it
= urls
.iterator(); it
.hasNext();) {
644 String url
= it
.next();
645 if (generateExternalJavadoc(element
, url
, false, filter
) == null) it
.remove();
647 final HashSet
<String
> set
= new HashSet
<String
>(urls
);
648 if (set
.size() > 1) {
649 JBPopupFactory
.getInstance().createListPopup(new BaseListPopupStep
<String
>("Choose javadoc root", ArrayUtil
.toStringArray(set
)) {
650 public PopupStep
onChosen(final String selectedValue
, final boolean finalChoice
) {
651 BrowserUtil
.launchBrowser(selectedValue
);
652 return PopupStep
.FINAL_CHOICE
;
654 }).showInBestPositionFor(DataManager
.getInstance().getDataContext());
656 else if (set
.size() == 1){
657 BrowserUtil
.launchBrowser(urls
.get(0));
661 final JBPopup docInfoHint
= DocumentationManager
.getInstance(element
.getProject()).getDocInfoHint();
662 if (docInfoHint
!= null && docInfoHint
.isVisible()) {
663 docInfoHint
.cancel();
665 Messages
.showMessageDialog(element
.getProject(), CodeInsightBundle
.message("javadoc.documentation.not.found.message"),
666 CodeInsightBundle
.message("javadoc.documentation.not.found.title"), Messages
.getErrorIcon());
671 public static List
<String
> getExternalJavaDocUrl(final PsiElement element
) {
672 List
<String
> urls
= null;
674 if (element
instanceof PsiClass
) {
675 urls
= findUrlForClass((PsiClass
)element
);
677 else if (element
instanceof PsiField
) {
678 PsiField field
= (PsiField
)element
;
679 PsiClass aClass
= field
.getContainingClass();
680 if (aClass
!= null) {
681 urls
= findUrlForClass(aClass
);
683 for (int i
= 0; i
< urls
.size(); i
++) {
684 urls
.set(i
, urls
.get(i
) + "#" + field
.getName());
689 else if (element
instanceof PsiMethod
) {
690 PsiMethod method
= (PsiMethod
)element
;
691 PsiClass aClass
= method
.getContainingClass();
692 if (aClass
!= null) {
693 final List
<String
> classUrls
= findUrlForClass(aClass
);
695 if (classUrls
!= null) {
696 urls
= new ArrayList
<String
>();
697 String signature
= PsiFormatUtil
.formatMethod(method
, PsiSubstitutor
.EMPTY
,
698 PsiFormatUtil
.SHOW_NAME
| PsiFormatUtil
.SHOW_PARAMETERS
| PsiFormatUtil
.SHOW_RAW_TYPE
,
699 PsiFormatUtil
.SHOW_TYPE
| PsiFormatUtil
.SHOW_FQ_CLASS_NAMES
| PsiFormatUtil
.SHOW_RAW_TYPE
, 999);
700 for (String classUrl
: classUrls
) {
701 urls
.add(classUrl
+ "#" + signature
);
703 signature
= PsiFormatUtil
.formatMethod(method
, PsiSubstitutor
.EMPTY
,
704 PsiFormatUtil
.SHOW_NAME
| PsiFormatUtil
.SHOW_PARAMETERS
,
705 PsiFormatUtil
.SHOW_TYPE
| PsiFormatUtil
.SHOW_FQ_CLASS_NAMES
, 999);
706 for (String classUrl
: classUrls
) {
707 urls
.add(classUrl
+ "#" + signature
);
712 else if (element
instanceof PsiPackage
) {
713 urls
= findUrlForPackage((PsiPackage
)element
);
715 else if (element
instanceof PsiDirectory
) {
716 PsiPackage aPackage
= JavaDirectoryService
.getInstance().getPackage(((PsiDirectory
)element
));
717 if (aPackage
!= null) {
718 urls
= findUrlForPackage(aPackage
);
726 for (int i
= 0; i
< urls
.size(); i
++) {
727 urls
.set(i
, FileUtil
.toSystemIndependentName(urls
.get(i
)));
734 public static List
<String
> findUrlForClass(PsiClass aClass
) {
735 String qName
= aClass
.getQualifiedName();
736 if (qName
== null) return null;
737 PsiFile file
= aClass
.getContainingFile();
738 if (!(file
instanceof PsiJavaFile
)) return null;
739 String packageName
= ((PsiJavaFile
)file
).getPackageName();
742 if (packageName
.length() > 0) {
743 relPath
= packageName
.replace('.', '/') + '/' + qName
.substring(packageName
.length() + 1) + HTML_EXTENSION
;
746 relPath
= qName
+ HTML_EXTENSION
;
749 final PsiFile containingFile
= aClass
.getContainingFile();
750 if (containingFile
== null) return null;
751 final VirtualFile virtualFile
= containingFile
.getVirtualFile();
752 if (virtualFile
== null) return null;
754 return findUrlForVirtualFile(containingFile
.getProject(), virtualFile
, relPath
);
758 public static List
<String
> findUrlForVirtualFile(final Project project
, final VirtualFile virtualFile
, final String relPath
) {
759 final ProjectFileIndex fileIndex
= ProjectRootManager
.getInstance(project
).getFileIndex();
760 Module module
= fileIndex
.getModuleForFile(virtualFile
);
761 if (module
== null) {
762 final VirtualFileSystem fs
= virtualFile
.getFileSystem();
763 if (fs
instanceof JarFileSystem
) {
764 final VirtualFile jar
= ((JarFileSystem
)fs
).getVirtualFileForJar(virtualFile
);
766 module
= fileIndex
.getModuleForFile(jar
);
770 if (module
!= null) {
771 String
[] javadocPaths
= ModuleRootManager
.getInstance(module
).getRootUrls(JavadocOrderRootType
.getInstance());
772 List
<String
> httpRoot
= getHttpRoots(javadocPaths
, relPath
);
773 if (httpRoot
!= null) return httpRoot
;
776 final List
<OrderEntry
> orderEntries
= fileIndex
.getOrderEntriesForFile(virtualFile
);
777 for (OrderEntry orderEntry
: orderEntries
) {
778 final String
[] files
= orderEntry
.getUrls(JavadocOrderRootType
.getInstance());
779 final List
<String
> httpRoot
= getHttpRoots(files
, relPath
);
780 if (httpRoot
!= null) return httpRoot
;
786 public static List
<String
> getHttpRoots(final String
[] roots
, String relPath
) {
787 final ArrayList
<String
> result
= new ArrayList
<String
>();
788 for (String root
: roots
) {
789 final VirtualFile virtualFile
= VirtualFileManager
.getInstance().findFileByUrl(root
);
790 if (virtualFile
!= null) {
791 if (virtualFile
.getFileSystem() instanceof HttpFileSystem
) {
792 String url
= virtualFile
.getUrl();
793 if (!url
.endsWith("/")) url
+= "/";
794 result
.add(url
+ relPath
);
797 VirtualFile file
= virtualFile
.findFileByRelativePath(relPath
);
798 if (file
!= null) result
.add(file
.getUrl());
803 return result
.isEmpty() ?
null : result
;
807 public static List
<String
> findUrlForPackage(PsiPackage aPackage
) {
808 String qName
= aPackage
.getQualifiedName();
809 qName
= qName
.replace('.', '/') + '/' + PACKAGE_SUMMARY_FILE
;
810 for (PsiDirectory directory
: aPackage
.getDirectories()) {
811 List
<String
> url
= findUrlForVirtualFile(aPackage
.getProject(), directory
.getVirtualFile(), qName
);
819 public PsiElement
getDocumentationElementForLink(final PsiManager psiManager
, final String link
, final PsiElement context
) {
820 return JavaDocUtil
.findReferenceTarget(psiManager
, link
, context
);