WEB-34928 JSON Schema reference breaks other references to JSON properties

remove the special "reference" that delegates navigation to schema properties and replace it with a goto-provider
1) it never worked correctly (i.e., rename is not handled properly, etc.)
2) it prevents other references from functioning
This commit is contained in:
Anton Lobov
2018-09-21 13:03:12 +02:00
parent 434ac7472a
commit d891c576f7
9 changed files with 91 additions and 130 deletions
@@ -15,4 +15,6 @@ public interface JsonStringLiteral extends JsonLiteral {
@NotNull
String getValue();
boolean isPropertyName();
}
@@ -37,4 +37,8 @@ public class JsonStringLiteralImpl extends JsonStringLiteralMixin implements Jso
return JsonPsiImplUtils.getValue(this);
}
public boolean isPropertyName() {
return JsonPsiImplUtils.isPropertyName(this);
}
}
+1
View File
@@ -108,6 +108,7 @@ string_literal ::= SINGLE_QUOTED_STRING | DOUBLE_QUOTED_STRING {
methods=[
getTextFragments
getValue
isPropertyName
SINGLE_QUOTED_STRING=""
DOUBLE_QUOTED_STRING=""
]
@@ -218,6 +218,11 @@ public class JsonPsiImplUtils {
return StringUtil.unescapeStringCharacters(JsonPsiUtil.stripQuotes(literal.getText()));
}
public static boolean isPropertyName(@NotNull JsonStringLiteral literal) {
final PsiElement parent = literal.getParent();
return parent instanceof JsonProperty && ((JsonProperty)parent).getNameElement() == literal;
}
public static boolean getValue(@NotNull JsonBooleanLiteral literal) {
return literal.textMatches("true");
}
@@ -1,52 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.jsonSchema.impl;
import com.intellij.json.psi.JsonProperty;
import com.intellij.json.psi.JsonStringLiteral;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.ElementManipulators;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceProvider;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author Irina.Chernushina on 4/15/2016.
*/
public class JsonPropertyName2SchemaDefinitionReferenceProvider extends PsiReferenceProvider {
@NotNull
@Override
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
return new PsiReference[] {new JsonPropertyName2SchemaRefReference((JsonStringLiteral)element)};
}
private static class JsonPropertyName2SchemaRefReference extends JsonSchemaBaseReference<JsonStringLiteral> {
JsonPropertyName2SchemaRefReference(JsonStringLiteral element) {
super(element, ElementManipulators.getValueTextRange(element));
}
@Nullable
@Override
public PsiElement resolveInner() {
final JsonSchemaService service = JsonSchemaService.Impl.get(myElement.getProject());
final VirtualFile file = myElement.getContainingFile().getVirtualFile();
if (file == null || !service.isApplicableToFile(file)) return null;
final List<JsonSchemaVariantsTreeBuilder.Step> steps = JsonOriginalPsiWalker.INSTANCE.findPosition(getElement(), true);
if (steps == null) return null;
final JsonSchemaObject schemaObject = service.getSchemaObject(file);
if (schemaObject != null) {
final JsonProperty parentProperty = PsiTreeUtil.getParentOfType(myElement, JsonProperty.class);
return new JsonSchemaResolver(schemaObject, true, steps)
.findNavigationTarget(false, parentProperty == null ? null : parentProperty.getValue(),
JsonSchemaService.isSchemaFile(myElement.getContainingFile()));
}
return null;
}
}
}
@@ -0,0 +1,48 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.jsonSchema.impl;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.psi.JsonProperty;
import com.intellij.json.psi.JsonStringLiteral;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class JsonSchemaGotoDeclarationHandler implements GotoDeclarationHandler {
@Nullable
@Override
public PsiElement[] getGotoDeclarationTargets(@Nullable PsiElement sourceElement, int offset, Editor editor) {
final IElementType elementType = PsiUtilCore.getElementType(sourceElement);
if (elementType != JsonElementTypes.DOUBLE_QUOTED_STRING && elementType != JsonElementTypes.SINGLE_QUOTED_STRING) return null;
final JsonStringLiteral literal = PsiTreeUtil.getParentOfType(sourceElement, JsonStringLiteral.class);
if (literal == null) return null;
final PsiElement parent = literal.getParent();
if (parent instanceof JsonProperty && ((JsonProperty)parent).getNameElement() == literal) {
final JsonSchemaService service = JsonSchemaService.Impl.get(literal.getProject());
final PsiFile containingFile = literal.getContainingFile();
final VirtualFile file = containingFile.getVirtualFile();
if (file == null || !service.isApplicableToFile(file)) return null;
final List<JsonSchemaVariantsTreeBuilder.Step> steps = JsonOriginalPsiWalker.INSTANCE.findPosition(literal, true);
if (steps == null) return null;
final JsonSchemaObject schemaObject = service.getSchemaObject(file);
if (schemaObject != null) {
final PsiElement target = new JsonSchemaResolver(schemaObject, false, steps)
.findNavigationTarget(false, ((JsonProperty)parent).getValue(),
JsonSchemaService.isSchemaFile(containingFile));
if (target != null) {
return new PsiElement[] {target};
}
}
}
return null;
}
}
@@ -36,13 +36,11 @@ import org.jetbrains.annotations.Nullable;
*/
public class JsonSchemaReferenceContributor extends PsiReferenceContributor {
public static final PsiElementPattern.Capture<JsonValue> REF_PATTERN = createPropertyValuePattern("$ref");
public static final PsiElementPattern.Capture<JsonStringLiteral> PROPERTY_NAME_PATTERN = createPropertyNamePattern();
public static final PsiElementPattern.Capture<JsonStringLiteral> REQUIRED_PROP_PATTERN = createRequiredPropPattern();
@Override
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(REF_PATTERN, new JsonSchemaRefReferenceProvider());
registrar.registerReferenceProvider(PROPERTY_NAME_PATTERN, new JsonPropertyName2SchemaDefinitionReferenceProvider());
registrar.registerReferenceProvider(REQUIRED_PROP_PATTERN, new JsonRequiredPropsReferenceProvider());
}
@@ -70,24 +68,6 @@ public class JsonSchemaReferenceContributor extends PsiReferenceContributor {
}));
}
private static PsiElementPattern.Capture<JsonStringLiteral> createPropertyNamePattern() {
return PlatformPatterns.psiElement(JsonStringLiteral.class).and(new FilterPattern(new ElementFilter() {
@Override
public boolean isAcceptable(Object element, @Nullable PsiElement context) {
if (element instanceof JsonStringLiteral) {
final PsiElement parent = ((JsonStringLiteral)element).getParent();
return parent instanceof JsonProperty && ((JsonProperty)parent).getNameElement() == element;
}
return false;
}
@Override
public boolean isClassAcceptable(Class hintClass) {
return true;
}
}));
}
private static PsiElementPattern.Capture<JsonStringLiteral> createRequiredPropPattern() {
return PlatformPatterns.psiElement(JsonStringLiteral.class).and(new FilterPattern(new ElementFilter() {
@Override
@@ -3,6 +3,7 @@ package com.jetbrains.jsonSchema;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
import com.intellij.json.JsonFileType;
import com.intellij.json.psi.*;
import com.intellij.openapi.application.ApplicationManager;
@@ -26,7 +27,6 @@ import com.jetbrains.jsonSchema.extension.JsonSchemaProjectSelfProviderFactory;
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
import com.jetbrains.jsonSchema.impl.JsonSchemaComplianceInspection;
import com.jetbrains.jsonSchema.impl.JsonSchemaObject;
import com.jetbrains.jsonSchema.impl.JsonSchemaReferenceContributor;
import com.jetbrains.jsonSchema.impl.JsonSchemaVersion;
import com.jetbrains.jsonSchema.schemaFile.TestJsonSchemaMappingsProjectConfiguration;
import org.jetbrains.annotations.NotNull;
@@ -196,7 +196,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
skeleton(new Callback() {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
int offset = getCaretOffset();
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
@@ -256,7 +256,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
int offset = getCaretOffset();
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
@@ -291,20 +291,8 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
PsiElement element = myFile.findElementAt(offset);
boolean found = false;
while (element.getTextRange().contains(offset)) {
if (JsonSchemaReferenceContributor.PROPERTY_NAME_PATTERN.accepts(element)) {
found = true;
break;
}
element = element.getParent();
}
Assert.assertTrue(found);
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
int offset = getCaretOffset();
final PsiElement resolve = GotoDeclarationAction.findTargetElement(getProject(), myEditor, offset);
Assert.assertNotNull(resolve);
Assert.assertEquals("basePropertiesSchema.json", resolve.getContainingFile().getName());
Assert.assertEquals("\"baseEnum\"", resolve.getText());
@@ -330,7 +318,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
int offset = getCaretOffset();
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
@@ -361,7 +349,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
int offset = getCaretOffset();
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
@@ -391,9 +379,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
final String text = myFile.getText();
final int indexOf = text.indexOf("dependencies");
assertTrue(indexOf > 0);
final PsiReference referenceAt = myFile.findReferenceAt(indexOf);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
final PsiElement resolve = GotoDeclarationAction.findTargetElement(getProject(), myEditor, indexOf);
Assert.assertNotNull(resolve);
Assert.assertEquals("packageJsonSchema.json", resolve.getContainingFile().getName());
Assert.assertEquals("\"dependencies\"", resolve.getText());
@@ -418,10 +404,8 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
int offset = getCaretOffset();
final PsiElement resolve = GotoDeclarationAction.findTargetElement(getProject(), myEditor, offset);
Assert.assertNotNull(resolve);
Assert.assertEquals("nestedDefinitionsSchema.json", resolve.getContainingFile().getName());
Assert.assertEquals("\"definitions\"", resolve.getText());
@@ -448,10 +432,8 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
int offset = getCaretOffset();
final PsiElement resolve = GotoDeclarationAction.findTargetElement(getProject(), myEditor, offset);
Assert.assertNotNull(resolve);
Assert.assertEquals("nestedAllOfOneOfDefinitionsSchema.json", resolve.getContainingFile().getName());
Assert.assertEquals("\"begriff\"", resolve.getText());
@@ -478,10 +460,8 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
int offset = getCaretOffset();
final PsiElement resolve = GotoDeclarationAction.findTargetElement(getProject(), myEditor, offset);
Assert.assertNotNull(resolve);
Assert.assertEquals("baseSchema.json", resolve.getContainingFile().getName());
Assert.assertEquals("\"findMe\"", resolve.getText());
@@ -556,7 +536,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
int offset = getCaretOffset();
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
@@ -618,10 +598,8 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
int offset = getCaretOffset();
final PsiElement resolve = GotoDeclarationAction.findTargetElement(getProject(), myEditor, offset);
Assert.assertNotNull(resolve);
Assert.assertEquals("\"properties\"", resolve.getText());
final PsiElement parent = resolve.getParent();
@@ -699,23 +677,19 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
" }\n" +
" }\n" +
" }";
checkNavigationTo(midia, "midia", JsonSchemaObject.DEFINITIONS);
checkNavigationTo(midia, "midia", getCaretOffset(), JsonSchemaObject.DEFINITIONS, true);
}
});
}
private void checkNavigationTo(@NotNull String resolvedText, @NotNull String name, @NotNull String base) {
int offset = myEditor.getCaretModel().getPrimaryCaret().getOffset();
final PsiElement element = myFile.findElementAt(offset);
Assert.assertNotNull(element);
checkNavigationTo(resolvedText, name, offset, base);
private int getCaretOffset() {
return myEditor.getCaretModel().getPrimaryCaret().getOffset();
}
private void checkNavigationTo(@NotNull String resolvedText, @NotNull String name, int offset, @NotNull String base) {
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
private void checkNavigationTo(@NotNull String resolvedText, @NotNull String name, int offset, @NotNull String base, boolean isReference) {
final PsiElement resolve = isReference
? myFile.findReferenceAt(offset).resolve()
: GotoDeclarationAction.findTargetElement(getProject(), myEditor, offset);
Assert.assertNotNull(resolve);
Assert.assertEquals(resolvedText, resolve.getText());
final PsiElement parent = resolve.getParent();
@@ -744,7 +718,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
public void doCheck() {
checkNavigationTo("{\n" +
" \"$ref\": \"#/definitions/one\"\n" +
" }", "all", JsonSchemaObject.DEFINITIONS);
" }", "all", getCaretOffset(), JsonSchemaObject.DEFINITIONS, true);
}
});
}
@@ -766,7 +740,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
checkNavigationTo("\"bbb\"", "bbb", JsonSchemaObject.PROPERTIES);
checkNavigationTo("\"bbb\"", "bbb", getCaretOffset(), JsonSchemaObject.PROPERTIES, false);
}
});
}
@@ -803,7 +777,8 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
" \"type\": \"string\"\n" +
" }\n" +
" }\n" +
" }", "cycle.schema", literal.getTextRange().getEndOffset() - 1, JsonSchemaObject.DEFINITIONS));
" }", "cycle.schema", literal.getTextRange().getEndOffset() - 1,
JsonSchemaObject.DEFINITIONS, true));
}
});
}
@@ -827,7 +802,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
@Override
public void doCheck() {
checkNavigationTo("\"id\"", "id", JsonSchemaObject.PROPERTIES);
checkNavigationTo("\"id\"", "id", getCaretOffset(), JsonSchemaObject.PROPERTIES, false);
}
});
}
@@ -902,10 +877,7 @@ public class JsonSchemaCrossReferencesTest extends JsonSchemaHeavyAbstractTest {
}
private void checkNavigationToSchemaVariant(@NotNull String name, int offset, @NotNull String parentPropertyName) {
final PsiReference referenceAt = myFile.findReferenceAt(offset);
Assert.assertNotNull(referenceAt);
final PsiElement resolve = referenceAt.resolve();
Assert.assertNotNull(resolve);
final PsiElement resolve = GotoDeclarationAction.findTargetElement(getProject(), myEditor, offset);
Assert.assertEquals("\"" + name + "\"", resolve.getText());
final PsiElement parent = resolve.getParent();
Assert.assertTrue(parent instanceof JsonProperty);
@@ -102,6 +102,7 @@
<psi.referenceContributor language="JSON" implementation="com.jetbrains.jsonSchema.impl.JsonSchemaReferenceContributor"/>
<multiHostInjector implementation="com.jetbrains.jsonSchema.impl.JsonSchemaRegexInjector"/>
<lang.lineWrapStrategy language="JSON" implementationClass="com.intellij.json.formatter.JsonLineWrapPositionStrategy"/>
<gotoDeclarationHandler implementation="com.jetbrains.jsonSchema.impl.JsonSchemaGotoDeclarationHandler"/>
</extensions>
<extensions defaultExtensionNs="JavaScript">
<JsonSchema.ProviderFactory implementation="com.jetbrains.jsonSchema.extension.JsonSchemaUserDefinedProviderFactory"/>