[javadoc] Snippet: create file from usage

IDEA-314508 Support external snippets in @snippet
Helps partially for IDEA-314510 Impossible to create snippet-files directory

GitOrigin-RevId: 0a891fe7cfafa93d814edf865b0bfbb9bc6e9e2a
This commit is contained in:
Tagir Valeev
2023-03-21 16:02:59 +01:00
committed by intellij-monorepo-bot
parent 4084f2a0c5
commit 6838e9720c
5 changed files with 66 additions and 10 deletions

View File

@@ -4,6 +4,9 @@ package com.intellij.codeInspection.javaDoc;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix;
import com.intellij.codeInsight.daemon.quickFix.CreateFilePathFix;
import com.intellij.codeInsight.daemon.quickFix.NewFileLocation;
import com.intellij.codeInsight.daemon.quickFix.TargetDirectory;
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
@@ -24,6 +27,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.PsiFileReference;
import com.intellij.psi.impl.source.tree.JavaDocElementType;
import com.intellij.psi.javadoc.*;
import com.intellij.psi.util.PsiTreeUtil;
@@ -116,10 +120,23 @@ public class JavaDocReferenceInspection extends LocalInspectionTool {
@Override
public void visitSnippetAttributeValue(@NotNull PsiSnippetAttributeValue attributeValue) {
PsiReference ref = attributeValue.getReference();
if (ref != null) {
PsiElement resolved = ref.resolve();
if (ref instanceof PsiFileReference fileRef) {
PsiElement resolved = fileRef.resolve();
if (resolved == null) {
holder.registerProblem(attributeValue, JavaBundle.message("inspection.message.snippet.file.not.found"));
CreateFilePathFix fix = null;
String path = fileRef.getCanonicalText();
PsiDirectory parent = comment.getContainingFile().getParent();
if (parent != null) {
String[] components = path.split("/");
if (components.length > 0) {
TargetDirectory directory = new TargetDirectory(parent, Arrays.copyOf(components, components.length - 1));
NewFileLocation location = new NewFileLocation(Collections.singletonList(directory), components[components.length - 1]);
fix = new CreateFilePathFix(attributeValue, location);
}
}
holder.registerProblem(attributeValue,
JavaBundle.message("inspection.message.snippet.file.not.found", path),
LocalQuickFix.notNullElements(fix));
}
}
PsiSymbolReference symRef = ContainerUtil.getOnlyItem(attributeValue.getOwnReferences());

View File

@@ -140,7 +140,7 @@ public class PsiSnippetAttributeValueImpl extends LeafPsiElement implements PsiS
@Nullable
private VirtualFile getDirectory() {
if (mySnippetRoot == null) return null;
List<String> path = StringUtil.split(getCanonicalText(), mySeparator);
List<String> path = StringUtil.split(getValue(), mySeparator);
if (path.isEmpty()) return null;
VirtualFile dir = mySnippetRoot;
for (int i = 0; i < path.size() - 1; i++) {
@@ -175,7 +175,7 @@ public class PsiSnippetAttributeValueImpl extends LeafPsiElement implements PsiS
}
@Override
public Object @NotNull [] getVariants() {
public @NotNull Object @NotNull [] getVariants() {
VirtualFile directory = getDirectory();
if (directory == null) return ArrayUtilRt.EMPTY_OBJECT_ARRAY;
PsiManager manager = getManager();
@@ -199,7 +199,9 @@ public class PsiSnippetAttributeValueImpl extends LeafPsiElement implements PsiS
@Override
public @NotNull @NlsSafe String getCanonicalText() {
return getValue();
String text = getValue();
return PsiSnippetAttribute.SNIPPETS_FOLDER + '/' +
text.replace(mySeparator, "/") + (myExtension == null ? "" : "." + myExtension);
}
@Override
@@ -252,7 +254,7 @@ public class PsiSnippetAttributeValueImpl extends LeafPsiElement implements PsiS
@Override
public String toString() {
return getClass().getName() + "(" + getCanonicalText() + ")";
return getClass().getName() + "(" + getValue() + ")";
}
}
}

View File

@@ -3,11 +3,11 @@ package pkg;
/**
* {@snippet file="Test.java"}
* {@snippet class=Test}
* {@snippet class=<error descr="Snippet file is not found">Test1</error>}
* {@snippet class=<error descr="Snippet file 'snippet-files/Test1.java' is not found">Test1</error>}
* {@snippet class="Test"}
* {@snippet class='Test''}
* {@snippet class='sub.Test' region="reg"}
* {@snippet class=<error descr="Snippet file is not found">'sub.Test2'</error>}
* {@snippet class=<error descr="Snippet file 'snippet-files/sub/Test2.java' is not found">'sub.Test2'</error>}
* {@snippet file="sub/test.txt"}
* {@snippet file="sub/test.txt" region=<error descr="Region is not found">"notfound"</error>}
*/

View File

@@ -0,0 +1,37 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInsight.javadoc;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
import java.io.File;
public class JavadocCreateSnippetFileFromUsageFixTest extends LightJavaCodeInsightFixtureTestCase {
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return JAVA_20;
}
public void testCreateSnippetClass() {
myFixture.enableInspections(new JavaDocReferenceInspection());
myFixture.configureByText("Test.java", """
/**
* {@snippet class=<error descr="Snippet file 'snippet-files/a/b/Hello.java' is not found">"a.<caret>b.Hello"</error>}
*/
class Test{}
""");
myFixture.checkHighlighting();
IntentionAction action = myFixture.findSingleIntention("Create file Hello.java");
myFixture.checkIntentionPreviewHtml(action, """
Create file <icon src="file"/>&nbsp;snippet-files#a#b#Hello.java<br/>\
including intermediate directories<br/>\
inside directory <icon src="dir"/>&nbsp;#src""".replace('#', File.separatorChar));
myFixture.launchAction(action);
VirtualFile path = myFixture.getFile().getVirtualFile().findFileByRelativePath("../snippet-files/a/b/Hello.java");
assertTrue(path.exists());
}
}

View File

@@ -1817,7 +1817,7 @@ intention.family.name.dismiss=Dismiss
intention.family.name.ignore.project=Do not show again in this project
fix.move.to.source.root=Move to source root
warning.java.file.outside.source.root=Java file is located outside of the module source root, so it won't be compiled
inspection.message.snippet.file.not.found=Snippet file is not found
inspection.message.snippet.file.not.found=Snippet file ''{0}'' is not found
inspection.message.snippet.region.not.found=Region is not found
javadoc.snippet.not.found=Snippet not found: {0}
javadoc.snippet.region.not.found=Region not found: {0}