From bd061a4ec3e4d0ab684944c05d782cd9287e4f38 Mon Sep 17 00:00:00 2001 From: Kris De Volder Date: Thu, 25 Jul 2019 13:09:17 -0700 Subject: [PATCH] Take superclass into account for properties CTRL-click See: https://github.com/spring-projects/sts4/issues/326 --- .../app/PropertiesJavaDefinitionHandler.java | 2 +- .../vscode/boot/metadata/types/TypeUtil.java | 7 +++ .../hover/PropertiesDefinitionCalculator.java | 21 ++++--- .../ApplicationYamlAssistContext.java | 4 +- .../boot/test/ApplicationYamlEditorTest.java | 27 +++++++- .../super-property-nav-sample/.gitignore | 31 ++++++++++ .../super-property-nav-sample/pom.xml | 61 +++++++++++++++++++ .../SuperPropertyNavSampleApplication.java | 13 ++++ .../src/main/resources/application.yml | 5 ++ ...uperPropertyNavSampleApplicationTests.java | 16 +++++ 10 files changed, 174 insertions(+), 13 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/.gitignore create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/pom.xml create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/main/java/com/example/demo/SuperPropertyNavSampleApplication.java create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/main/resources/application.yml create mode 100644 headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/test/java/com/example/demo/SuperPropertyNavSampleApplicationTests.java diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/PropertiesJavaDefinitionHandler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/PropertiesJavaDefinitionHandler.java index a0640490a..19e27674f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/PropertiesJavaDefinitionHandler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/PropertiesJavaDefinitionHandler.java @@ -72,7 +72,7 @@ public class PropertiesJavaDefinitionHandler implements DefinitionHandler, Langu PropertyFinder propertyFinder = new PropertyFinder(index, typeUtil, doc, offset); Node node = propertyFinder.findNode(); if (node instanceof Key) { - Collection propertyJavaElements = PropertiesDefinitionCalculator.getPropertyJavaElements(propertyFinder, project, ((Key) node).decode()); + Collection propertyJavaElements = PropertiesDefinitionCalculator.getPropertyJavaElements(typeUtil, propertyFinder, project, ((Key) node).decode()); return PropertiesDefinitionCalculator.getLocations(javaElementLocationProvider, project, propertyJavaElements); } else if (node instanceof Value) { Value value = (Value) node; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java index 0032abaa6..9bf3614e1 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java @@ -578,6 +578,13 @@ public class TypeUtil { } return false; } + + public IType getSuperType(IType type) { + if (type!=null) { + return findType(type.getSuperclassName()); + } + return null; + } private IType findType(String typeName) { try { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesDefinitionCalculator.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesDefinitionCalculator.java index 4368eb172..1b8c5be79 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesDefinitionCalculator.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesDefinitionCalculator.java @@ -52,15 +52,15 @@ public class PropertiesDefinitionCalculator { return null; } - public static Collection getPropertyJavaElements(PropertyFinder propertyFinder, IJavaProject project, String propertyKey) { + public static Collection getPropertyJavaElements(TypeUtil typeUtil, PropertyFinder propertyFinder, IJavaProject project, String propertyKey) { PropertyInfo best = propertyFinder.findBestHoverMatch(propertyKey); if (best != null) { - return getPropertyJavaElement(project, best); + return getPropertyJavaElement(typeUtil, project, best); } return ImmutableList.of(); } - public static Collection getPropertyJavaElement(IJavaProject project, PropertyInfo property) { + public static Collection getPropertyJavaElement(TypeUtil typeUtil, IJavaProject project, PropertyInfo property) { List sources = property.getSources(); ImmutableList.Builder elements = ImmutableList.builder(); if (sources != null) { @@ -74,7 +74,7 @@ public class PropertiesDefinitionCalculator { if (methodSig!=null) { method = getMethod(type, methodSig); } else { - method = getPropertyMethod(type, property.getName()); + method = getPropertyMethod(typeUtil, type, property.getName()); } } if (method!=null) { @@ -146,13 +146,16 @@ public class PropertiesDefinitionCalculator { } } - public static IMethod getPropertyMethod(IType type, String propName) { + public static IMethod getPropertyMethod(TypeUtil typeUtil, IType type, String propName) { String[] accessors = { "set", "get", "is" }; - for (String a : accessors) { - IMethod propertyMethod = getAccessor(type, a, propName); - if (propertyMethod != null) { - return propertyMethod; + while (type!=null && !"java.lang.Object".equals(type.getFullyQualifiedName())) { + for (String a : accessors) { + IMethod propertyMethod = getAccessor(type, a, propName); + if (propertyMethod != null) { + return propertyMethod; + } } + type = typeUtil.getSuperType(type); } return null; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java index 23e50d0c0..05d020d69 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/completions/ApplicationYamlAssistContext.java @@ -406,7 +406,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon } else { IType javaType = javaProject.getIndex().findType(parentType.getErasure()); if (javaType != null) { - IMethod method = PropertiesDefinitionCalculator.getPropertyMethod(javaType, propName); + IMethod method = PropertiesDefinitionCalculator.getPropertyMethod(typeUtil, javaType, propName); if (method != null) { Location location = javaElementLocationProvider.findLocation(javaProject, method); if (location != null) { @@ -555,7 +555,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon PropertyInfo prop = indexNav.getExactMatch(); if (prop != null) { IJavaProject project = typeUtil.getJavaProject(); - Collection elements = PropertiesDefinitionCalculator.getPropertyJavaElement(project, prop); + Collection elements = PropertiesDefinitionCalculator.getPropertyJavaElement(typeUtil, project, prop); return PropertiesDefinitionCalculator.getLocations(javaElementLocationProvider, project, elements); } return ImmutableList.of(); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java index dbed58789..2dc104a63 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java @@ -140,7 +140,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { ); editor.assertProblems(/*NONE*/); } - + @Test public void bug_158348104() throws Exception { //See: https://www.pivotaltracker.com/story/show/158348104 data("spring.activemq.close-timeout", "java.time.Duration", null, null); @@ -542,6 +542,31 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { definitionLinkAsserts.assertLinkTargets(editor, "data", project, method("demo.FooProperties", "setData", "demo.ColorData")); definitionLinkAsserts.assertLinkTargets(editor, "wavelen", project, method("demo.ColorData", "setWavelen", "double")); } + + @Test + public void testInheritedPropertyLinkTarget() throws Exception { + //See: https://github.com/spring-projects/sts4/issues/326 + MavenJavaProject project = createPredefinedMavenProject("super-property-nav-sample"); + useProject(project); + + Editor editor = harness.newEditor( + "initializr:\n" + + " languages:\n" + + " - name: foo\n" + + " id: yada\n" + + " default: false\n" + + " bogus: whatever\n" + ); + + //io.spring.initializr.metadata.DefaultMetadataElement.setDefault(boolean) + //io.spring.initializr.metadata.MetadataElement.setId(String) + //io.spring.initializr.metadata.MetadataElement.setName(String) + definitionLinkAsserts.assertLinkTargets(editor, "name", project, method("io.spring.initializr.metadata.MetadataElement", "setName", "java.lang.String")); + definitionLinkAsserts.assertLinkTargets(editor, "id", project, method("io.spring.initializr.metadata.MetadataElement", "setId", "java.lang.String")); + definitionLinkAsserts.assertLinkTargets(editor, "default", project, method("io.spring.initializr.metadata.DefaultMetadataElement", "setDefault", "boolean")); + + definitionLinkAsserts.assertLinkTargets(editor, "bogus", project /*NONE*/); + } @Test public void testHyperlinkTargets() throws Exception { IJavaProject p = createPredefinedMavenProject("tricky-getters-boot-1.3.1-app"); diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/.gitignore b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/.gitignore new file mode 100644 index 000000000..a2a3040aa --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/.gitignore @@ -0,0 +1,31 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/pom.xml b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/pom.xml new file mode 100644 index 000000000..274a171e8 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.6.RELEASE + + + com.example + super-property-nav-sample + 0.0.1-SNAPSHOT + super-property-nav-sample + Demo project for Spring Boot + + + 1.8 + + + + + + true + + spring-snapshots + Spring Snapshots + https://repo.spring.io/libs-snapshot + + + + + + org.springframework.boot + spring-boot-starter + + + + io.spring.initializr + initializr-generator-spring + 0.8.0.BUILD-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/main/java/com/example/demo/SuperPropertyNavSampleApplication.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/main/java/com/example/demo/SuperPropertyNavSampleApplication.java new file mode 100644 index 000000000..fc9244925 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/main/java/com/example/demo/SuperPropertyNavSampleApplication.java @@ -0,0 +1,13 @@ +package com.example.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SuperPropertyNavSampleApplication { + + public static void main(String[] args) { + SpringApplication.run(SuperPropertyNavSampleApplication.class, args); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/main/resources/application.yml b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/main/resources/application.yml new file mode 100644 index 000000000..c06f411df --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/main/resources/application.yml @@ -0,0 +1,5 @@ +initializr: + languages: + - name: ffo + id: yada + default: false diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/test/java/com/example/demo/SuperPropertyNavSampleApplicationTests.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/test/java/com/example/demo/SuperPropertyNavSampleApplicationTests.java new file mode 100644 index 000000000..3f6a7a04e --- /dev/null +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/super-property-nav-sample/src/test/java/com/example/demo/SuperPropertyNavSampleApplicationTests.java @@ -0,0 +1,16 @@ +package com.example.demo; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SuperPropertyNavSampleApplicationTests { + + @Test + public void contextLoads() { + } + +}