diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguagServerBootApp.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguagServerBootApp.java index 0d07f446e..a7b42f4ee 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguagServerBootApp.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguagServerBootApp.java @@ -41,6 +41,7 @@ import org.springframework.ide.vscode.boot.metadata.ClassReferenceProvider; import org.springframework.ide.vscode.boot.metadata.LoggerNameProvider; import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.PropertyInfo; +import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndex; import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry; import org.springframework.ide.vscode.boot.yaml.completions.ApplicationYamlAssistContext; import org.springframework.ide.vscode.commons.languageserver.LanguageServerRunner; @@ -172,7 +173,7 @@ public class BootLanguagServerBootApp { @Override public YamlAssistContext getGlobalAssistContext(YamlDocument ydoc) { IDocument doc = ydoc.getDocument(); - FuzzyMap index = params.indexProvider.getIndex(doc); + SpringPropertyIndex index = params.indexProvider.getIndex(doc); return ApplicationYamlAssistContext.global(ydoc, index, new PropertyCompletionFactory(), params.typeUtilProvider.getTypeUtil(sourceLinks, doc), RelaxedNameConfig.COMPLETION_DEFAULTS, javaElementLocationProvider); } }; 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 d360095a2..338c1b0d6 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 @@ -64,7 +64,7 @@ public class PropertiesJavaDefinitionHandler implements DefinitionHandler, Langu try { TextDocument doc = documents.get(position); TypeUtil typeUtil = params.typeUtilProvider.getTypeUtil(sourceLinks, doc); - FuzzyMap index = params.indexProvider.getIndex(doc); + FuzzyMap index = params.indexProvider.getIndex(doc).getProperties(); int offset; offset = doc.toOffset(position.getPosition()); return getDefinitions(index, typeUtil, doc, offset); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueCompletionProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueCompletionProcessor.java index ce3e7153f..e882cc476 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueCompletionProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueCompletionProcessor.java @@ -201,7 +201,7 @@ public class ValueCompletionProcessor implements CompletionProvider { } private List> findMatches(String prefix, IDocument doc) { - FuzzyMap index = indexProvider.getIndex(doc); + FuzzyMap index = indexProvider.getIndex(doc).getProperties(); List> matches =index.find(camelCaseToHyphens(prefix)); //First the 'real' properties. diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java index df65b996d..1f7ad557b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java @@ -96,7 +96,7 @@ public class AdHocSpringPropertyIndexProvider implements ProjectBasedPropertyInd log.error("", e); } } - return SpringPropertyIndex.EMPTY_INDEX; + return SpringPropertyIndex.EMPTY_INDEX.getProperties(); } private void processFile(Function parserFunction, File file, SimplePropertyIndex index) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java index 2ca8fa92f..f9c62a541 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/DefaultSpringPropertyIndexProvider.java @@ -42,7 +42,7 @@ public class DefaultSpringPropertyIndexProvider implements SpringPropertyIndexPr } @Override - public FuzzyMap getIndex(IDocument doc) { + public SpringPropertyIndex getIndex(IDocument doc) { Optional jp = javaProjectFinder.find(new TextDocumentIdentifier(doc.getUri())); if (jp.isPresent()) { return indexManager.get(jp.get(), progressService); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/PropertyInfo.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/PropertyInfo.java index ef72d0db3..7b15c3655 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/PropertyInfo.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/PropertyInfo.java @@ -63,6 +63,36 @@ public class PropertyInfo { public String getSourceMethod() { return sourceMethod; } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((sourceMethod == null) ? 0 : sourceMethod.hashCode()); + result = prime * result + ((sourceType == null) ? 0 : sourceType.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PropertySource other = (PropertySource) obj; + if (sourceMethod == null) { + if (other.sourceMethod != null) + return false; + } else if (!sourceMethod.equals(other.sourceMethod)) + return false; + if (sourceType == null) { + if (other.sourceType != null) + return false; + } else if (!sourceType.equals(other.sourceType)) + return false; + return true; + } + } final private String id; @@ -173,11 +203,13 @@ public class PropertyInfo { public String toString() { return "PropertyInfo("+getId()+")"; } - public void addSource(ConfigurationMetadataSource source) { + public PropertySource addSource(ConfigurationMetadataSource source) { if (sources==null) { sources = new ArrayList(); } - sources.add(new PropertySource(source)); + PropertySource s = new PropertySource(source); + sources.add(s); + return s; } public PropertyInfo withId(String alias) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java index e598d2bc4..f33e10987 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndex.java @@ -11,21 +11,34 @@ package org.springframework.ide.vscode.boot.metadata; import java.util.Collection; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import org.springframework.ide.vscode.boot.configurationmetadata.ConfigurationMetadataGroup; import org.springframework.ide.vscode.boot.configurationmetadata.ConfigurationMetadataProperty; import org.springframework.ide.vscode.boot.configurationmetadata.ConfigurationMetadataRepository; import org.springframework.ide.vscode.boot.configurationmetadata.ConfigurationMetadataSource; +import org.springframework.ide.vscode.boot.metadata.PropertyInfo.PropertySource; import org.springframework.ide.vscode.commons.java.IClasspath; import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.StringUtil; -public class SpringPropertyIndex extends FuzzyMap { +import com.google.common.collect.ImmutableSet; - public static final FuzzyMap EMPTY_INDEX = new SpringPropertyIndex(null, null); +public class SpringPropertyIndex { + + public static final SpringPropertyIndex EMPTY_INDEX = new SpringPropertyIndex(null, null); - private ValueProviderRegistry valueProviders; + private final ValueProviderRegistry valueProviders; + + private final Map> groups = new HashMap>(); + + private final FuzzyMap properties = new FuzzyMap() { + @Override + protected String getKey(PropertyInfo entry) { + return entry.getId(); + } + }; public SpringPropertyIndex(ValueProviderRegistry valueProviders, IClasspath projectPath) { this.valueProviders = valueProviders; @@ -37,15 +50,17 @@ public class SpringPropertyIndex extends FuzzyMap { Collection allEntries = metadata.getAllProperties().values(); for (ConfigurationMetadataProperty item : allEntries) { - add(new PropertyInfo(valueProviders, item)); + properties.add(new PropertyInfo(valueProviders, item)); } for (ConfigurationMetadataGroup group : metadata.getAllGroups().values()) { for (ConfigurationMetadataSource source : group.getSources().values()) { + ImmutableSet.Builder sources = ImmutableSet.builder(); for (ConfigurationMetadataProperty prop : source.getProperties().values()) { - PropertyInfo info = get(prop.getId()); - info.addSource(source); + PropertyInfo info = properties.get(prop.getId()); + sources.add(info.addSource(source)); } + groups.put(group.getId(), sources.build()); } } @@ -59,34 +74,34 @@ public class SpringPropertyIndex extends FuzzyMap { } public void add(ConfigurationMetadataProperty propertyInfo) { - add(new PropertyInfo(valueProviders, propertyInfo)); + properties.add(new PropertyInfo(valueProviders, propertyInfo)); } - /** - * Dumps out 'test data' based on the current contents of the index. This is not meant to be - * used in 'production' code. The idea is to call this method during development to dump a - * 'snapshot' of the index onto System.out. The data is printed in a forma so that it can be easily - * pasted/used into JUNit testing code. - */ - public void dumpAsTestData() { - List> allData = this.find(""); - for (Match match : allData) { - PropertyInfo d = match.data; - System.out.println("data(" - +dumpString(d.getId())+", " - +dumpString(d.getType())+", " - +dumpString(d.getDefaultValue())+", " - +dumpString(d.getDescription()) +");" - ); -// for (PropertySource source : d.getSources()) { -// String st = source.getSourceType(); -// String sm = source.getSourceMethod(); -// if (sm!=null) { -// System.out.println(d.getId() +" from: "+st+"::"+sm); -// } -// } - } - } +// /** +// * Dumps out 'test data' based on the current contents of the index. This is not meant to be +// * used in 'production' code. The idea is to call this method during development to dump a +// * 'snapshot' of the index onto System.out. The data is printed in a forma so that it can be easily +// * pasted/used into JUNit testing code. +// */ +// public void dumpAsTestData() { +// List> allData = this.find(""); +// for (Match match : allData) { +// PropertyInfo d = match.data; +// System.out.println("data(" +// +dumpString(d.getId())+", " +// +dumpString(d.getType())+", " +// +dumpString(d.getDefaultValue())+", " +// +dumpString(d.getDescription()) +");" +// ); +//// for (PropertySource source : d.getSources()) { +//// String st = source.getSourceType(); +//// String sm = source.getSourceMethod(); +//// if (sm!=null) { +//// System.out.println(d.getId() +" from: "+st+"::"+sm); +//// } +//// } +// } +// } private String dumpString(Object v) { if (v==null) { @@ -124,11 +139,6 @@ public class SpringPropertyIndex extends FuzzyMap { } } - @Override - protected String getKey(PropertyInfo entry) { - return entry.getId(); - } - /** * Find the longest known property that is a prefix of the given name. Here prefix does not mean * 'string prefix' but a prefix in the sense of treating '.' as a kind of separators. So @@ -155,4 +165,16 @@ public class SpringPropertyIndex extends FuzzyMap { return null; } + public FuzzyMap getProperties() { + return properties; + } + + public int size() { + return properties.size(); + } + + public Collection getGroupSources(String prefix) { + return groups.get(prefix); + } + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java index fd93c10b6..d2dc2ff46 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/SpringPropertyIndexProvider.java @@ -10,10 +10,9 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.metadata; -import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.text.IDocument; public interface SpringPropertyIndexProvider { - FuzzyMap getIndex(IDocument doc); + SpringPropertyIndex getIndex(IDocument doc); void onChange(Runnable runnable); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java index 2d7261f22..096698a6a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/completions/SpringPropertiesCompletionEngine.java @@ -51,7 +51,7 @@ public class SpringPropertiesCompletionEngine implements ICompletionEngine { */ @Override public Collection getCompletions(TextDocument doc, int offset) throws BadLocationException { - return new PropertiesCompletionProposalsCalculator(indexProvider.getIndex(doc), + return new PropertiesCompletionProposalsCalculator(indexProvider.getIndex(doc).getProperties(), typeUtilProvider.getTypeUtil(sourceLinks, doc), completionFactory, doc, offset, preferLowerCaseEnums).calculate(); } 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 296881cb4..abb544b44 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 @@ -58,14 +58,14 @@ public class PropertiesDefinitionCalculator { public static Collection getPropertyJavaElements(TypeUtil typeUtil, PropertyFinder propertyFinder, IJavaProject project, String propertyKey) { PropertyInfo best = propertyFinder.findBestHoverMatch(propertyKey); if (best != null) { - return getPropertyJavaElement(typeUtil, project, best); + return getPropertyJavaElements(typeUtil, project, best); } return ImmutableList.of(); } - public static Collection getPropertyJavaElement(TypeUtil typeUtil, IJavaProject project, PropertyInfo property) { - ImmutableList.Builder elements = ImmutableList.builder(); + public static Collection getPropertyJavaElements(TypeUtil typeUtil, IJavaProject project, PropertyInfo property) { List sources = property.getSources(); + ImmutableList.Builder elements = ImmutableList.builder(); if (sources != null) { for (PropertySource source : sources) { IMember e = getPropertyJavaElement(typeUtil, project, property, source); @@ -77,6 +77,44 @@ public class PropertiesDefinitionCalculator { return elements.build(); } + public static Collection getPropertySourceJavaElements(TypeUtil typeUtil, IJavaProject project, Collection sources) { + ImmutableList.Builder elements = ImmutableList.builder(); + if (sources != null) { + for (PropertySource source : sources) { + IMember e = getPropertySourceJavaElement(typeUtil, project, source); + if (e!=null) { + elements.add(e); + } + } + } + return elements.build(); + } + + private static IMember getPropertySourceJavaElement(TypeUtil typeUtil, IJavaProject project, PropertySource source) { + List elements = new ArrayList<>(); + // collect elements in increasing order of accuracy, so that we can return the last + // (most accurate) element at the end of this method. + String typeName = source.getSourceType(); + if (typeName!=null) { + IType type = project.getIndex().findType(typeName); + if (type!=null) { + elements.add(type); + String methodSig = source.getSourceMethod(); + if (methodSig!=null) { + // the property source is a method, so actually we look for accessor in the return type. + IMethod method = getMethod(type, methodSig); + if (method!=null) { + elements.add(method); + } + } + } + } + if (!elements.isEmpty()) { + return elements.get(elements.size()-1); + } + return null; + } + private static IMember getPropertyJavaElement(TypeUtil typeUtil, IJavaProject project, PropertyInfo property, PropertySource source) { List elements = new ArrayList<>(); // collect elements in increasing order of accuracy, so that we can return the last diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverInfoProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverInfoProvider.java index 1dcd3cef5..76e57f336 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverInfoProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/hover/PropertiesHoverInfoProvider.java @@ -38,7 +38,7 @@ public class PropertiesHoverInfoProvider implements HoverInfoProvider { @Override public Tuple2 getHoverInfo(IDocument document, int offset) throws Exception { - return new PropertiesHoverCalculator(indexProvider.getIndex(document), + return new PropertiesHoverCalculator(indexProvider.getIndex(document).getProperties(), typeUtilProvider.getTypeUtil(sourceLinks, document), document, offset).calculate(); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java index 8ae612052..ac871fd97 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertiesReconcileEngine.java @@ -90,7 +90,7 @@ public class SpringPropertiesReconcileEngine implements IReconcileEngine { @Override public void reconcile(IDocument doc, IProblemCollector problemCollector) { - FuzzyMap index = fIndexProvider.getIndex(doc); + FuzzyMap index = fIndexProvider.getIndex(doc).getProperties(); problemCollector.beginCollecting(); try { ParseResults results = parser.parse(doc.get()); 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 fb629251a..457b53ec9 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 @@ -26,11 +26,14 @@ import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.common.InformationTemplates; import org.springframework.ide.vscode.boot.common.PropertyCompletionFactory; import org.springframework.ide.vscode.boot.common.RelaxedNameConfig; +import org.springframework.ide.vscode.boot.configurationmetadata.ConfigurationMetadataGroup; import org.springframework.ide.vscode.boot.configurationmetadata.Deprecation; import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider; import org.springframework.ide.vscode.boot.java.links.SourceLinks; import org.springframework.ide.vscode.boot.metadata.IndexNavigator; import org.springframework.ide.vscode.boot.metadata.PropertyInfo; +import org.springframework.ide.vscode.boot.metadata.PropertyInfo.PropertySource; +import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndex; import org.springframework.ide.vscode.boot.metadata.hints.HintProvider; import org.springframework.ide.vscode.boot.metadata.hints.StsValueHint; import org.springframework.ide.vscode.boot.metadata.hints.ValueHintHoverInfo; @@ -53,7 +56,6 @@ import org.springframework.ide.vscode.commons.languageserver.completion.IComplet import org.springframework.ide.vscode.commons.languageserver.completion.LazyProposalApplier; import org.springframework.ide.vscode.commons.languageserver.completion.ScoreableProposal; import org.springframework.ide.vscode.commons.util.CollectionUtil; -import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.FuzzyMap.Match; import org.springframework.ide.vscode.commons.util.FuzzyMatcher; import org.springframework.ide.vscode.commons.util.Renderable; @@ -136,8 +138,8 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon */ protected abstract Type getType(); - public static ApplicationYamlAssistContext subdocument(YamlDocument doc, int documentSelector, FuzzyMap index, PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf, JavaElementLocationProvider javaElementLocationProvider) { - return new IndexContext(doc, documentSelector, YamlPath.EMPTY, IndexNavigator.with(index), completionFactory, typeUtil, conf, javaElementLocationProvider); + public static ApplicationYamlAssistContext subdocument(YamlDocument doc, int documentSelector, SpringPropertyIndex index, PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf, JavaElementLocationProvider javaElementLocationProvider) { + return new IndexContext(doc, documentSelector, YamlPath.EMPTY, index, IndexNavigator.with(index.getProperties()), completionFactory, typeUtil, conf, javaElementLocationProvider); } private static class TypeContext extends ApplicationYamlAssistContext { @@ -428,12 +430,14 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon private static class IndexContext extends ApplicationYamlAssistContext { - private IndexNavigator indexNav; - PropertyCompletionFactory completionFactory; + final private SpringPropertyIndex index; + final private IndexNavigator indexNav; + final PropertyCompletionFactory completionFactory; - public IndexContext(YamlDocument doc, int documentSelector, YamlPath contextPath, IndexNavigator indexNav, + public IndexContext(YamlDocument doc, int documentSelector, YamlPath contextPath, SpringPropertyIndex index, IndexNavigator indexNav, PropertyCompletionFactory completionFactory, TypeUtil typeUtil, RelaxedNameConfig conf, JavaElementLocationProvider javaElementLocationProvider) { super(doc, documentSelector, contextPath, typeUtil, conf, javaElementLocationProvider); + this.index = index; this.indexNav = indexNav; this.completionFactory = completionFactory; } @@ -519,9 +523,9 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon } } if (subIndex.getExtensionCandidate()!=null) { - return new IndexContext(getDocument(), documentSelector, contextPath.append(s), subIndex, completionFactory, typeUtil, conf, javaElementLocationProvider); + return new IndexContext(getDocument(), documentSelector, contextPath.append(s), index, subIndex, completionFactory, typeUtil, conf, javaElementLocationProvider); } else if (subIndex.getExactMatch()!=null) { - IndexContext asIndexContext = new IndexContext(getDocument(), documentSelector, contextPath.append(s), subIndex, completionFactory, typeUtil, conf, javaElementLocationProvider); + IndexContext asIndexContext = new IndexContext(getDocument(), documentSelector, contextPath.append(s), index, subIndex, completionFactory, typeUtil, conf, javaElementLocationProvider); PropertyInfo prop = subIndex.getExactMatch(); return new TypeContext(asIndexContext, contextPath.append(s), TypeParser.parse(prop.getType()), completionFactory, typeUtil, conf, prop.getHints(typeUtil), javaElementLocationProvider); } @@ -559,8 +563,16 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon PropertyInfo prop = indexNav.getExactMatch(); if (prop != null) { IJavaProject project = typeUtil.getJavaProject(); - Collection elements = PropertiesDefinitionCalculator.getPropertyJavaElement(typeUtil, project, prop); + Collection elements = PropertiesDefinitionCalculator.getPropertyJavaElements(typeUtil, project, prop); return PropertiesDefinitionCalculator.getLocations(javaElementLocationProvider, project, elements); + } else { + //handle finding property source directly by property key + Collection sources = index.getGroupSources(indexNav.getPrefix()); + if (sources!=null && !sources.isEmpty()) { + IJavaProject project = typeUtil.getJavaProject(); + Collection elements = PropertiesDefinitionCalculator.getPropertySourceJavaElements(typeUtil, project, sources); + return PropertiesDefinitionCalculator.getLocations(javaElementLocationProvider, project, elements); + } } return ImmutableList.of(); } @@ -590,7 +602,7 @@ public abstract class ApplicationYamlAssistContext extends AbstractYamlAssistCon return null; } - public static YamlAssistContext global(YamlDocument doc, final FuzzyMap index, final PropertyCompletionFactory completionFactory, final TypeUtil typeUtil, final RelaxedNameConfig conf, JavaElementLocationProvider javaElementLocationProvider) { + public static YamlAssistContext global(YamlDocument doc, final SpringPropertyIndex index, final PropertyCompletionFactory completionFactory, final TypeUtil typeUtil, final RelaxedNameConfig conf, JavaElementLocationProvider javaElementLocationProvider) { return new TopLevelAssistContext() { @Override protected YamlAssistContext getDocumentContext(int documentSelector) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java index b0e4ce721..0eff3dc9d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/yaml/reconcile/ApplicationYamlReconcileEngine.java @@ -43,7 +43,7 @@ public class ApplicationYamlReconcileEngine extends YamlReconcileEngine { @Override protected YamlASTReconciler getASTReconciler(IDocument doc, IProblemCollector problemCollector) { - FuzzyMap index = indexProvider.getIndex(doc); + FuzzyMap index = indexProvider.getIndex(doc).getProperties(); if (index!=null && !index.isEmpty()) { IndexNavigator nav = IndexNavigator.with(index); return new ApplicationYamlASTReconciler(problemCollector, nav, typeUtilProvider.getTypeUtil(sourceLinks, doc), quickFixes); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java index f799b8741..b830f9849 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/editor/harness/PropertyIndexHarness.java @@ -46,7 +46,7 @@ public class PropertyIndexHarness { protected final SpringPropertyIndexProvider indexProvider = new SpringPropertyIndexProvider() { @Override - public FuzzyMap getIndex(IDocument doc) { + public SpringPropertyIndex getIndex(IDocument doc) { synchronized (PropertyIndexHarness.this) { if (index==null) { IClasspath classpath = testProject == null ? null : testProject.getClasspath(); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/IndexNavigatorTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/IndexNavigatorTest.java index b3936db47..be7f350a5 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/IndexNavigatorTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/IndexNavigatorTest.java @@ -125,7 +125,7 @@ public class IndexNavigatorTest { * Reset navigation state to point at the root of the index. */ public void start(PropertyIndexHarness harness) { - navigator = IndexNavigator.with(harness.getIndexProvider().getIndex(null)); + navigator = IndexNavigator.with(harness.getIndexProvider().getIndex(null).getProperties()); } /** diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/PropertiesIndexTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/PropertiesIndexTest.java index 15df3faa3..b6bade0e3 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/PropertiesIndexTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/metadata/PropertiesIndexTest.java @@ -38,7 +38,7 @@ public class PropertiesIndexTest { SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( new ValueProviderRegistry(), null, null); IJavaProject mavenProject = projects.mavenProject(CUSTOM_PROPERTIES_PROJECT); - FuzzyMap index = indexManager.get(mavenProject, progressService); + FuzzyMap index = indexManager.get(mavenProject, progressService).getProperties(); PropertyInfo propertyInfo = index.get("server.port"); assertNotNull(propertyInfo); assertEquals(Integer.class.getName(), propertyInfo.getType()); @@ -50,7 +50,7 @@ public class PropertiesIndexTest { SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( new ValueProviderRegistry(), null, null); IJavaProject mavenProject = projects.mavenProject(CUSTOM_PROPERTIES_PROJECT); - FuzzyMap index = indexManager.get(mavenProject, progressService); + FuzzyMap index = indexManager.get(mavenProject, progressService).getProperties(); PropertyInfo propertyInfo = index.get("demo.settings.user"); assertNotNull(propertyInfo); assertEquals(String.class.getName(), propertyInfo.getType()); @@ -62,7 +62,7 @@ public class PropertiesIndexTest { SpringPropertiesIndexManager indexManager = new SpringPropertiesIndexManager( new ValueProviderRegistry(), null, null); IJavaProject mavenProject = projects.mavenProject(CUSTOM_PROPERTIES_PROJECT); - FuzzyMap index = indexManager.get(mavenProject, progressService); + FuzzyMap index = indexManager.get(mavenProject, progressService).getProperties(); PropertyInfo propertyInfo = index.get("my.server.port"); assertNull(propertyInfo); } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java index abc0eead2..70c60ceb3 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java @@ -1859,8 +1859,10 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { editor = newEditor( "my.screen.background=green" ); - definitionLinkAsserts.assertLinkTargets(editor, "background", project, editor.rangeOf("my.screen.background", "my.screen.background"), method("com.example.demo.MyProperties$Screen", "getScreen")); - definitionLinkAsserts.assertLinkTargets(editor, "green", project, editor.rangeOf("green", "green"), field("com.example.demo.Color", "GREEN")); + definitionLinkAsserts.assertLinkTargets(editor, "background", project, editor.rangeOf("my.screen.background"), + method("com.example.demo.MyProperties$Screen", "setBackground", "com.example.demo.Color") + ); + definitionLinkAsserts.assertLinkTargets(editor, "green", project, editor.rangeOf("green"), field("com.example.demo.Color", "GREEN")); } @Test public void testNoHoverForUnrecognizedProperty() throws Exception { 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 bb20ec2b4..cae93b4a3 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 @@ -3849,7 +3849,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { ); } - @Test public void definitionLinks_bug_169240253() throws Exception { + @Test public void definitionLinks_bug_169240253_nested() throws Exception { MavenJavaProject p = createPredefinedMavenProject("boot-web-actuator-2.2.0"); //See: https://www.pivotaltracker.com/story/show/169240253 useProject(p ); @@ -3874,6 +3874,26 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { ); } + @Test public void definitionLinks_bug_169240253_parent() throws Exception { + MavenJavaProject p = createPredefinedMavenProject("boot-web-actuator-2.2.0"); + //See: https://www.pivotaltracker.com/story/show/169240253 + useProject(p ); + Editor editor = newEditor( + "management:\n" + + " endpoints:\n" + + " web:\n" + + " exposure:\n" + + " exclude: '*'\n" + + "spring:\n" + + " messages:\n" + + " basename: messages/messages\n" + ); + //org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties.getExposure() + definitionLinkAsserts.assertLinkTargets(editor, "exposure", p, editor.rangeOf("exposure"), + method("org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties", "getExposure") + ); + } + @Test public void testClassReferenceInValueLink() throws Exception { Editor editor; MavenJavaProject project = createPredefinedMavenProject("empty-boot-1.3.0-with-mongo"); @@ -3992,7 +4012,7 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { useProject(createPredefinedMavenProject("boot-1.3.3-app-with-resource-prop")); //Check the metadata reflects the 'handle-as': - PropertyInfo metadata = getIndexProvider().getIndex(null).get("my.welcome.path"); + PropertyInfo metadata = getIndexProvider().getIndex(null).getProperties().get("my.welcome.path"); assertEquals("org.springframework.core.io.Resource", metadata.getType()); //Check the content assist based on it works too: