mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 04:51:24 +07:00
IDEA-62743 Render issue links in Java comments
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Fixes ABC-1123 and ABC-2. See details at BBB-22
|
||||
*/
|
||||
class IssueLinksInJavaDoc {
|
||||
// Fixes ABC-22 and ABC-11. See details at BBB-33
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection;
|
||||
import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection;
|
||||
import com.intellij.openapi.paths.WebReference;
|
||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.vcs.IssueNavigationConfiguration;
|
||||
import com.intellij.openapi.vcs.IssueNavigationLink;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
|
||||
@@ -96,9 +98,36 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testMissingReturnDescription() { doTest(); }
|
||||
public void testDoubleParenthesesInCode() { doTest(); }
|
||||
|
||||
public void testIssueLinksInJavaDoc() {
|
||||
IssueNavigationConfiguration navigationConfiguration = IssueNavigationConfiguration.getInstance(getProject());
|
||||
List<IssueNavigationLink> oldLinks = navigationConfiguration.getLinks();
|
||||
try {
|
||||
IssueNavigationLink link = new IssueNavigationLink("ABC-\\d+", "http://example.com/$0");
|
||||
navigationConfiguration.setLinks(ContainerUtil.<IssueNavigationLink>newArrayList(link));
|
||||
configureByFile(BASE_PATH + "/" + getTestName(false) + ".java");
|
||||
List<String> expected = ContainerUtil.newArrayList("http://example.com/ABC-1123", "http://example.com/ABC-2",
|
||||
"http://example.com/ABC-22", "http://example.com/ABC-11");
|
||||
List<String> actual = collectWebReferences().stream().map(WebReference::getUrl).collect(Collectors.toList());
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
finally {
|
||||
navigationConfiguration.setLinks(oldLinks);
|
||||
}
|
||||
}
|
||||
|
||||
public void testLinksInJavaDoc() {
|
||||
configureByFile(BASE_PATH + "/" + getTestName(false) + ".java");
|
||||
@SuppressWarnings("SpellCheckingInspection") Set<String> expected = ContainerUtil.newHashSet(
|
||||
"http://www.unicode.org/unicode/standard/standard.html",
|
||||
"http://docs.oracle.com/javase/7/docs/technotes/guides/lang/cl-mt.html",
|
||||
"https://youtrack.jetbrains.com/issue/IDEA-131621",
|
||||
"mailto:webmaster@jetbrains.com");
|
||||
Set<String> actual = collectWebReferences().stream().map(PsiReferenceBase::getCanonicalText).collect(Collectors.toSet());
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<WebReference> collectWebReferences() {
|
||||
final List<WebReference> refs = new ArrayList<>();
|
||||
myFile.accept(new PsiRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
@@ -109,18 +138,8 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
super.visitElement(element);
|
||||
}
|
||||
});
|
||||
|
||||
assertTrue(refs.stream().allMatch(PsiReferenceBase::isSoft));
|
||||
|
||||
assertTrue(refs.stream().allMatch(ref -> ref.resolve() != null));
|
||||
|
||||
@SuppressWarnings("SpellCheckingInspection") Set<String> expected = ContainerUtil.newHashSet(
|
||||
"http://www.unicode.org/unicode/standard/standard.html",
|
||||
"http://docs.oracle.com/javase/7/docs/technotes/guides/lang/cl-mt.html",
|
||||
"https://youtrack.jetbrains.com/issue/IDEA-131621",
|
||||
"mailto:webmaster@jetbrains.com");
|
||||
Set<String> actual = refs.stream().map(PsiReferenceBase::getCanonicalText).collect(Collectors.toSet());
|
||||
assertEquals(expected, actual);
|
||||
return refs;
|
||||
}
|
||||
|
||||
private void doTestWithLangLevel(LanguageLevel level) {
|
||||
|
||||
@@ -52,7 +52,7 @@ public class WebReference extends PsiReferenceBase<PsiElement> {
|
||||
return new MyFakePsiElement();
|
||||
}
|
||||
|
||||
protected String getUrl() {
|
||||
public String getUrl() {
|
||||
return myUrl != null ? myUrl : getValue();
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ package com.intellij.psi.impl.source.resolve.reference;
|
||||
|
||||
import com.intellij.openapi.paths.GlobalPathReferenceProvider;
|
||||
import com.intellij.openapi.paths.PathReferenceManager;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.UserDataCache;
|
||||
import com.intellij.openapi.vcs.IssueNavigationConfiguration;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.PsiReferenceProvider;
|
||||
@@ -27,46 +27,40 @@ import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class ArbitraryPlaceUrlReferenceProvider extends PsiReferenceProvider {
|
||||
private static final UserDataCache<CachedValue<PsiReference[]>, PsiElement, Object> ourRefsCache = new UserDataCache<CachedValue<PsiReference[]>, PsiElement, Object>("psielement.url.refs") {
|
||||
private final AtomicReference<GlobalPathReferenceProvider> myReferenceProvider = new AtomicReference<GlobalPathReferenceProvider>();
|
||||
private final AtomicReference<GlobalPathReferenceProvider> myReferenceProvider = new AtomicReference<GlobalPathReferenceProvider>();
|
||||
|
||||
@Override
|
||||
protected CachedValue<PsiReference[]> compute(final PsiElement element, Object p) {
|
||||
return CachedValuesManager
|
||||
.getManager(element.getProject()).createCachedValue(new CachedValueProvider<PsiReference[]>() {
|
||||
@Override
|
||||
protected CachedValue<PsiReference[]> compute(final PsiElement element, Object p) {
|
||||
return CachedValuesManager.getManager(element.getProject()).createCachedValue(new CachedValueProvider<PsiReference[]>() {
|
||||
public Result<PsiReference[]> compute() {
|
||||
Matcher matcher = URLUtil.URL_PATTERN.matcher(element.getText());
|
||||
|
||||
IssueNavigationConfiguration navigationConfiguration = IssueNavigationConfiguration.getInstance(element.getProject());
|
||||
if (navigationConfiguration == null) {
|
||||
return Result.create(PsiReference.EMPTY_ARRAY, element);
|
||||
}
|
||||
|
||||
List<PsiReference> refs = null;
|
||||
GlobalPathReferenceProvider provider = myReferenceProvider.get();
|
||||
|
||||
while (matcher.find()) {
|
||||
final int start = matcher.start();
|
||||
final int end = matcher.end();
|
||||
for (IssueNavigationConfiguration.LinkMatch link : navigationConfiguration.findIssueLinks(element.getText())) {
|
||||
if (refs == null) refs = new SmartList<PsiReference>();
|
||||
if (provider == null) {
|
||||
provider = (GlobalPathReferenceProvider)PathReferenceManager.getInstance().getGlobalWebPathReferenceProvider();
|
||||
myReferenceProvider.lazySet(provider);
|
||||
}
|
||||
|
||||
provider.createUrlReference(element, matcher.group(0), new TextRange(start, end), refs);
|
||||
provider.createUrlReference(element, link.getTargetUrl(), link.getRange(), refs);
|
||||
}
|
||||
|
||||
return new Result<PsiReference[]>(refs != null ? refs.toArray(new PsiReference[refs.size()]) : PsiReference.EMPTY_ARRAY,
|
||||
element);
|
||||
PsiReference[] references = refs != null ? refs.toArray(new PsiReference[refs.size()]) : PsiReference.EMPTY_ARRAY;
|
||||
return new Result<PsiReference[]>(references, element, navigationConfiguration);
|
||||
}
|
||||
}, false);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.intellij.openapi.vcs;
|
||||
import com.intellij.lifecycle.PeriodicalTasksCloser;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.SimpleModificationTracker;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.util.io.URLUtil;
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil;
|
||||
@@ -40,7 +41,7 @@ import java.util.regex.Pattern;
|
||||
@Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/vcs.xml", scheme = StorageScheme.DIRECTORY_BASED)
|
||||
}
|
||||
)
|
||||
public class IssueNavigationConfiguration implements PersistentStateComponent<IssueNavigationConfiguration> {
|
||||
public class IssueNavigationConfiguration extends SimpleModificationTracker implements PersistentStateComponent<IssueNavigationConfiguration> {
|
||||
public static IssueNavigationConfiguration getInstance(Project project) {
|
||||
return PeriodicalTasksCloser.getInstance().safeGetService(project, IssueNavigationConfiguration.class);
|
||||
}
|
||||
@@ -53,6 +54,7 @@ public class IssueNavigationConfiguration implements PersistentStateComponent<Is
|
||||
|
||||
public void setLinks(final List<IssueNavigationLink> links) {
|
||||
myLinks = new ArrayList<IssueNavigationLink>(links);
|
||||
incModificationCount();
|
||||
}
|
||||
|
||||
public IssueNavigationConfiguration getState() {
|
||||
|
||||
Reference in New Issue
Block a user