[jsonpath] IJPL-156278 Support external references in IDs and string literals

GitOrigin-RevId: 4418fd2511dc5ed2348d16a24c82f1ca9b501b8b
This commit is contained in:
Yuriy Artamonov
2024-06-07 14:49:35 +02:00
committed by intellij-monorepo-bot
parent 80be07a4f4
commit 5523dffc58
8 changed files with 127 additions and 3 deletions

View File

@@ -8,10 +8,10 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import static com.intellij.jsonpath.psi.JsonPathTypes.*;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.jsonpath.psi.JsonPathIdMixin;
import com.intellij.jsonpath.psi.*;
public class JsonPathIdImpl extends ASTWrapperPsiElement implements JsonPathId {
public class JsonPathIdImpl extends JsonPathIdMixin implements JsonPathId {
public JsonPathIdImpl(@NotNull ASTNode node) {
super(node);

View File

@@ -51,6 +51,7 @@ wildcardSegment ::= WILDCARD {
}
id ::= IDENTIFIER {
name="identifier"
mixin="com.intellij.jsonpath.psi.JsonPathIdMixin"
}
idSegment ::= id

View File

@@ -24,6 +24,11 @@
<completion.contributor language="JSONPath" order="last" implementationClass="com.intellij.jsonpath.JsonPathCompletionContributor"/>
<spellchecker.support language="JSONPath" implementationClass="com.intellij.jsonpath.JsonPathSpellcheckerStrategy"/>
<lang.elementManipulator forClass="com.intellij.jsonpath.psi.JsonPathId"
implementationClass="com.intellij.jsonpath.psi.JsonPathIdManipulator"/>
<lang.elementManipulator forClass="com.intellij.jsonpath.psi.JsonPathStringLiteral"
implementationClass="com.intellij.jsonpath.psi.JsonPathStringManipulator"/>
<localInspection language="JSONPath" shortName="JsonPathUnknownFunction"
implementationClass="com.intellij.jsonpath.inspections.JsonPathUnknownFunctionInspection"
bundle="messages.JsonPathBundle" key="inspection.jsonpath.unknown.function"

View File

@@ -0,0 +1,33 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.jsonpath.psi;
import com.intellij.jsonpath.JsonPathFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import org.jetbrains.annotations.NotNull;
import static java.util.Objects.requireNonNull;
final class JsonPathElementGenerator {
private final Project myProject;
JsonPathElementGenerator(@NotNull Project project) {
myProject = project;
}
public @NotNull PsiFile createDummyFile(@NotNull String content) {
var psiFileFactory = PsiFileFactory.getInstance(myProject);
return psiFileFactory.createFileFromText("dummy." + JsonPathFileType.INSTANCE.getDefaultExtension(),
JsonPathFileType.INSTANCE,
content);
}
public @NotNull PsiElement createStringLiteral(String unescapedContent) {
PsiFile file = createDummyFile("['" + StringUtil.escapeStringCharacters(unescapedContent) + "']");
JsonPathQuotedPathsList quotedPathsList = ((JsonPathExpressionSegment)file.getFirstChild()).getQuotedPathsList();
return requireNonNull(quotedPathsList).getStringLiteralList().get(0);
}
}

View File

@@ -0,0 +1,23 @@
// 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.jsonpath.psi;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.AbstractElementManipulator;
import com.intellij.psi.impl.source.tree.LeafElement;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
final class JsonPathIdManipulator extends AbstractElementManipulator<JsonPathId> {
@Override
public @NotNull JsonPathId handleContentChange(@NotNull JsonPathId element, @NotNull TextRange range,
String newContent) throws IncorrectOperationException {
var replacement = range.replace(element.getText(), newContent);
ASTNode node = element.getNode();
((LeafElement)node.getFirstChildNode()).replaceWithText(replacement);
return element;
}
}

View File

@@ -0,0 +1,21 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.jsonpath.psi;
import com.intellij.extapi.psi.ASTWrapperPsiElement;
import com.intellij.lang.ASTNode;
import com.intellij.model.psi.PsiExternalReferenceHost;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import org.jetbrains.annotations.NotNull;
public abstract class JsonPathIdMixin extends ASTWrapperPsiElement implements PsiExternalReferenceHost {
public JsonPathIdMixin(@NotNull ASTNode node) {
super(node);
}
@Override
public PsiReference @NotNull [] getReferences() {
return ReferenceProvidersRegistry.getReferencesFromProviders(this);
}
}

View File

@@ -3,9 +3,12 @@ package com.intellij.jsonpath.psi;
import com.intellij.jsonpath.psi.impl.JsonPathLiteralValueImpl;
import com.intellij.lang.ASTNode;
import com.intellij.model.psi.PsiExternalReferenceHost;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
import org.jetbrains.annotations.NotNull;
public abstract class JsonPathStringLiteralMixin extends JsonPathLiteralValueImpl {
public abstract class JsonPathStringLiteralMixin extends JsonPathLiteralValueImpl implements PsiExternalReferenceHost {
public JsonPathStringLiteralMixin(@NotNull ASTNode node) {
super(node);
@@ -15,4 +18,9 @@ public abstract class JsonPathStringLiteralMixin extends JsonPathLiteralValueImp
public void subtreeChanged() {
putUserData(JsonPathPsiUtils.STRING_FRAGMENTS, null);
}
@Override
public PsiReference @NotNull [] getReferences() {
return ReferenceProvidersRegistry.getReferencesFromProviders(this);
}
}

View File

@@ -0,0 +1,33 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.jsonpath.psi;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.AbstractElementManipulator;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
final class JsonPathStringManipulator extends AbstractElementManipulator<JsonPathStringLiteral> {
@Override
public @Nullable JsonPathStringLiteral handleContentChange(@NotNull JsonPathStringLiteral element,
@NotNull TextRange range,
String newContent) throws IncorrectOperationException {
String originalContent = element.getText();
TextRange withoutQuotes = getRangeInElement(element);
JsonPathElementGenerator generator = new JsonPathElementGenerator(element.getProject());
String replacement =
StringUtil.unescapeStringCharacters(originalContent.substring(withoutQuotes.getStartOffset(), range.getStartOffset())) +
newContent +
StringUtil.unescapeStringCharacters(originalContent.substring(range.getEndOffset(), withoutQuotes.getEndOffset()));
return (JsonPathStringLiteral)element.replace(generator.createStringLiteral(replacement));
}
@Override
public @NotNull TextRange getRangeInElement(@NotNull JsonPathStringLiteral element) {
String content = element.getText();
int startOffset = content.startsWith("'") || content.startsWith("\"") ? 1 : 0;
int endOffset = content.length() > 1 && (content.endsWith("'") || content.endsWith("\"")) ? -1 : 0;
return new TextRange(startOffset, content.length() + endOffset);
}
}