mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
revert original fix for IDEA-152628
performing IO in background thread while holding read lock sometimes leads to EDT freeze (when there's a pending write action)
This commit is contained in:
@@ -331,7 +331,7 @@ public class JavaDocInfoGenerator {
|
||||
if (fragment != null && targetElement instanceof PsiClass) {
|
||||
if (fragment.contains("-") || fragment.contains("(")) {
|
||||
for (PsiMethod method : ((PsiClass)targetElement).getMethods()) {
|
||||
Set<String> signatures = JavaDocumentationProvider.getHtmlMethodSignatures(method);
|
||||
Set<String> signatures = JavaDocumentationProvider.getHtmlMethodSignatures(method, true);
|
||||
if (signatures.contains(fragment)) {
|
||||
targetElement = method;
|
||||
fragment = null;
|
||||
|
||||
@@ -27,9 +27,9 @@ import com.intellij.lang.CodeDocumentationAwareCommenter;
|
||||
import com.intellij.lang.LangBundle;
|
||||
import com.intellij.lang.LanguageCommenters;
|
||||
import com.intellij.lang.documentation.CodeDocumentationProvider;
|
||||
import com.intellij.lang.documentation.CompositeDocumentationProvider;
|
||||
import com.intellij.lang.documentation.DocumentationProviderEx;
|
||||
import com.intellij.lang.documentation.ExternalDocumentationProvider;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.module.Module;
|
||||
@@ -41,8 +41,9 @@ import com.intellij.openapi.util.Conditions;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.*;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.openapi.vfs.JarFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileSystem;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.beanProperties.BeanPropertyElement;
|
||||
import com.intellij.psi.impl.source.javadoc.PsiDocParamRef;
|
||||
@@ -57,19 +58,14 @@ import com.intellij.util.SmartList;
|
||||
import com.intellij.util.Url;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.builtInWebServer.BuiltInWebBrowserUrlProvider;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Maxim.Mossienko
|
||||
@@ -614,25 +610,22 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
sb.append("<br>");
|
||||
}
|
||||
|
||||
// this method is closely related to hasUrlFor, both should be updated in sync
|
||||
@Nullable
|
||||
public static List<String> getExternalJavaDocUrl(final PsiElement element) {
|
||||
// this method can be slow, as it can perform IO (potentially via network), so it shouldn't be invoked on EDT
|
||||
LOG.assertTrue(ApplicationManager.getApplication().isUnitTestMode() || !ApplicationManager.getApplication().isDispatchThread());
|
||||
|
||||
List<String> urls = null;
|
||||
|
||||
if (element instanceof PsiClass) {
|
||||
ClassInfo info = findUrlForClass((PsiClass)element);
|
||||
urls = info == null ? null : info.externalDocUrls;
|
||||
urls = findUrlForClass((PsiClass)element);
|
||||
}
|
||||
else if (element instanceof PsiField) {
|
||||
PsiField field = (PsiField)element;
|
||||
PsiClass aClass = field.getContainingClass();
|
||||
if (aClass != null) {
|
||||
ClassInfo info = findUrlForClass(aClass);
|
||||
if (info != null) {
|
||||
urls = ContainerUtil.map(info.externalDocUrls, (url) -> url + "#" + field.getName());
|
||||
urls = findUrlForClass(aClass);
|
||||
if (urls != null) {
|
||||
for (int i = 0; i < urls.size(); i++) {
|
||||
urls.set(i, urls.get(i) + "#" + field.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -640,17 +633,17 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
PsiMethod method = (PsiMethod)element;
|
||||
PsiClass aClass = method.getContainingClass();
|
||||
if (aClass != null) {
|
||||
ClassInfo info = findUrlForClass(aClass);
|
||||
if (info != null) {
|
||||
List<String> classUrls = findUrlForClass(aClass);
|
||||
if (classUrls != null) {
|
||||
urls = ContainerUtil.newSmartList();
|
||||
for (int i = 0; i < info.externalDocUrls.size(); i++) {
|
||||
// For JDK docs we assume it's always generated with matching javadoc version
|
||||
LanguageLevel languageLevel = info.isInJdk ? PsiUtil.getLanguageLevel(method) : detectLanguageLevel(info.internalDocUrls.get(i));
|
||||
|
||||
String signature = formatMethodSignature(method,
|
||||
languageLevel.isAtLeast(LanguageLevel.JDK_1_5),
|
||||
languageLevel.isAtLeast(LanguageLevel.JDK_1_8));
|
||||
urls.add(info.externalDocUrls.get(i) + "#" + signature);
|
||||
final boolean useJava8Format = PsiUtil.isLanguageLevel8OrHigher(method);
|
||||
|
||||
final Set<String> signatures = getHtmlMethodSignatures(method, useJava8Format);
|
||||
for (String signature : signatures) {
|
||||
for (String classUrl : classUrls) {
|
||||
urls.add(classUrl + "#" + signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -669,104 +662,20 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return ContainerUtil.map(urls, FileUtil::toSystemIndependentName);
|
||||
}
|
||||
}
|
||||
|
||||
// this method is closely related to getExternalJavaDocUrl, both should be updated in sync
|
||||
public static boolean hasUrlFor(PsiElement element) {
|
||||
if (element instanceof PsiClass) {
|
||||
ClassInfo info = findUrlForClass((PsiClass)element);
|
||||
return info != null;
|
||||
}
|
||||
else if (element instanceof PsiField || element instanceof PsiMethod) {
|
||||
PsiMember member = (PsiMember)element;
|
||||
PsiClass aClass = member.getContainingClass();
|
||||
return aClass != null && findUrlForClass(aClass) != null;
|
||||
}
|
||||
else if (element instanceof PsiPackage) {
|
||||
return findUrlForPackage((PsiPackage)element) != null;
|
||||
}
|
||||
else if (element instanceof PsiDirectory) {
|
||||
PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
|
||||
return aPackage != null && findUrlForPackage(aPackage) != null;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Pattern GENERATED_SIGNATURE = Pattern.compile("<!-- Generated by javadoc(.*) on .* -->");
|
||||
|
||||
private static LanguageLevel detectLanguageLevel(String javadocPageUrl) {
|
||||
try {
|
||||
URL url = VfsUtilCore.convertToURL(javadocPageUrl);
|
||||
if (url == null) {
|
||||
LOG.warn("Couldn't open URL " + javadocPageUrl);
|
||||
}
|
||||
else {
|
||||
try (InputStream stream = URLUtil.openStream(url);
|
||||
Reader isr = new InputStreamReader(stream);
|
||||
BufferedReader reader = new BufferedReader(isr)) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
Matcher matcher = GENERATED_SIGNATURE.matcher(line);
|
||||
if (matcher.matches()) {
|
||||
String version = matcher.group(1);
|
||||
LanguageLevel level = parseVersion(version);
|
||||
if (level == null) {
|
||||
LOG.warn("Couldn't parse javadoc version " + version);
|
||||
}
|
||||
else {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Language level " + level + " detected for " + javadocPageUrl);
|
||||
}
|
||||
return level;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.warn("Couldn't find javadoc version in " + javadocPageUrl);
|
||||
for (int i = 0; i < urls.size(); i++) {
|
||||
urls.set(i, FileUtil.toSystemIndependentName(urls.get(i)));
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.warn("Error reading " + javadocPageUrl, e);
|
||||
}
|
||||
return LanguageLevel.HIGHEST; // default, if detection fails
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LanguageLevel parseVersion(@NotNull String javadocVersionString) {
|
||||
if (javadocVersionString.isEmpty()) return LanguageLevel.JDK_1_3;
|
||||
javadocVersionString = StringUtil.trim(javadocVersionString);
|
||||
javadocVersionString = StringUtil.trimStart(javadocVersionString, "(");
|
||||
javadocVersionString = StringUtil.trimEnd(javadocVersionString, ")");
|
||||
javadocVersionString = StringUtil.trimStart(javadocVersionString, "version");
|
||||
javadocVersionString = StringUtil.trimStart(javadocVersionString, "build");
|
||||
javadocVersionString = StringUtil.trim(javadocVersionString);
|
||||
String[] parts = javadocVersionString.split("[_.-]");
|
||||
if (parts.length > 0) {
|
||||
if (parts[0].equals("9")) return LanguageLevel.JDK_1_9;
|
||||
if (parts[0].equals("1") && parts.length > 1) {
|
||||
switch (parts[1]) {
|
||||
case "8": return LanguageLevel.JDK_1_8;
|
||||
case "7": return LanguageLevel.JDK_1_7;
|
||||
case "6": return LanguageLevel.JDK_1_6;
|
||||
case "5": return LanguageLevel.JDK_1_5;
|
||||
case "4": return LanguageLevel.JDK_1_4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Set<String> getHtmlMethodSignatures(PsiMethod method) {
|
||||
public static Set<String> getHtmlMethodSignatures(PsiMethod method, boolean java8FormatFirst) {
|
||||
final Set<String> signatures = new LinkedHashSet<String>();
|
||||
signatures.add(formatMethodSignature(method, true, true));
|
||||
signatures.add(formatMethodSignature(method, false, true));
|
||||
signatures.add(formatMethodSignature(method, true, false));
|
||||
signatures.add(formatMethodSignature(method, false, false));
|
||||
signatures.add(formatMethodSignature(method, true, java8FormatFirst));
|
||||
signatures.add(formatMethodSignature(method, false, java8FormatFirst));
|
||||
|
||||
signatures.add(formatMethodSignature(method, true, !java8FormatFirst));
|
||||
signatures.add(formatMethodSignature(method, false, !java8FormatFirst));
|
||||
return signatures;
|
||||
}
|
||||
|
||||
@@ -788,7 +697,7 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ClassInfo findUrlForClass(@NotNull PsiClass aClass) {
|
||||
public static List<String> findUrlForClass(@NotNull PsiClass aClass) {
|
||||
String qName = aClass.getQualifiedName();
|
||||
if (qName == null) return null;
|
||||
|
||||
@@ -811,7 +720,7 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ClassInfo findUrlForVirtualFile(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull String relPath) {
|
||||
public static List<String> findUrlForVirtualFile(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull String relPath) {
|
||||
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
|
||||
Module module = fileIndex.getModuleForFile(virtualFile);
|
||||
if (module == null) {
|
||||
@@ -828,31 +737,28 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
final List<String> httpRoots = PlatformDocumentationUtil.getHttpRoots(javadocPaths, relPath);
|
||||
// if found nothing and the file is from library classes, fall back to order entries
|
||||
if (httpRoots != null || !fileIndex.isInLibraryClasses(virtualFile)) {
|
||||
return ContainerUtil.isEmpty(httpRoots) ? null : new ClassInfo(false, httpRoots);
|
||||
return httpRoots;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (OrderEntry orderEntry : fileIndex.getOrderEntriesForFile(virtualFile)) {
|
||||
boolean isJdk = orderEntry instanceof JdkOrderEntry;
|
||||
List<String> internalUrls = new ArrayList<>();
|
||||
for (VirtualFile root : orderEntry.getFiles(JavadocOrderRootType.getInstance())) {
|
||||
String internalUrl = PlatformDocumentationUtil.getDocUrl(root, relPath);
|
||||
if (internalUrl == null) continue;
|
||||
if (root.getFileSystem() == JarFileSystem.getInstance()) {
|
||||
VirtualFile file = root.findFileByRelativePath(relPath);
|
||||
List<Url> urls = file == null ? null : BuiltInWebBrowserUrlProvider.getUrls(file, project, null);
|
||||
if (!ContainerUtil.isEmpty(urls)) {
|
||||
List<String> externalUrls = new SmartList<String>();
|
||||
List<String> result = new SmartList<String>();
|
||||
for (Url url : urls) {
|
||||
externalUrls.add(url.toExternalForm());
|
||||
result.add(url.toExternalForm());
|
||||
}
|
||||
return new ClassInfo(isJdk, Collections.nCopies(externalUrls.size(), internalUrl), externalUrls);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
internalUrls.add(internalUrl);
|
||||
}
|
||||
if (!ContainerUtil.isEmpty(internalUrls)) {
|
||||
return new ClassInfo(isJdk, internalUrls);
|
||||
|
||||
List<String> httpRoot = PlatformDocumentationUtil.getHttpRoots(JavadocOrderRootType.getUrls(orderEntry), relPath);
|
||||
if (httpRoot != null) {
|
||||
return httpRoot;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -863,9 +769,9 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
String qName = aPackage.getQualifiedName();
|
||||
qName = qName.replace('.', '/') + '/' + PACKAGE_SUMMARY_FILE;
|
||||
for (PsiDirectory directory : aPackage.getDirectories()) {
|
||||
ClassInfo urls = findUrlForVirtualFile(aPackage.getProject(), directory.getVirtualFile(), qName);
|
||||
if (urls != null) {
|
||||
return urls.externalDocUrls;
|
||||
List<String> url = findUrlForVirtualFile(aPackage.getProject(), directory.getVirtualFile(), qName);
|
||||
if (url != null) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -883,7 +789,7 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
|
||||
@Override
|
||||
public boolean hasDocumentationFor(PsiElement element, PsiElement originalElement) {
|
||||
return hasUrlFor(element);
|
||||
return CompositeDocumentationProvider.hasUrlsFor(this, element, originalElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -929,22 +835,4 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ClassInfo {
|
||||
private final boolean isInJdk;
|
||||
/** These should be used to fetch documentation in IDEA code */
|
||||
private final @NotNull List<String> internalDocUrls;
|
||||
/** These are for viewing documentation in browser (jar:// urls here are replaced with http:// urls provided by built-in web server) */
|
||||
private final @NotNull List<String> externalDocUrls;
|
||||
|
||||
private ClassInfo(boolean jdk, @NotNull List<String> docUrls) {
|
||||
this(jdk, docUrls, docUrls);
|
||||
}
|
||||
|
||||
private ClassInfo(boolean jdk, @NotNull List<String> internalUrls, @NotNull List<String> externalUrls) {
|
||||
isInJdk = jdk;
|
||||
internalDocUrls = internalUrls;
|
||||
externalDocUrls = externalUrls;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user