diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/commons/ConfigSourceInfo.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/commons/ConfigSourceInfo.java new file mode 100644 index 000000000..cfce8aed5 --- /dev/null +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/commons/ConfigSourceInfo.java @@ -0,0 +1,59 @@ +/******************************************************************************* +* Copyright (c) 2022 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4mp.commons; + +public class ConfigSourceInfo { + + private String uri; + + private String profile; + + private int ordinal; + + public ConfigSourceInfo() { + } + + public ConfigSourceInfo(String uri, int ordinal, String profile) { + super(); + this.uri = uri; + this.ordinal = ordinal; + this.profile = profile; + } + + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } + + public int getOrdinal() { + return ordinal; + } + + public void setOrdinal(int ordinal) { + this.ordinal = ordinal; + } + +} diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/commons/MicroProfileProjectInfo.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/commons/MicroProfileProjectInfo.java index c85c22bc2..a88410a78 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/commons/MicroProfileProjectInfo.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/commons/MicroProfileProjectInfo.java @@ -14,6 +14,7 @@ package org.eclipse.lsp4mp.commons; import java.util.Collections; +import java.util.Set; import org.eclipse.lsp4mp.commons.metadata.ConfigurationMetadata; @@ -38,6 +39,8 @@ public class MicroProfileProjectInfo extends ConfigurationMetadata { private ClasspathKind classpathKind; + private Set configSources; + /** * Returns the project URI. * @@ -74,4 +77,11 @@ public void setClasspathKind(ClasspathKind classpathKind) { this.classpathKind = classpathKind; } + public Set getConfigSources() { + return configSources; + } + + public void setConfigSources(Set configSources) { + this.configSources = configSources; + } } diff --git a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/PropertiesManager.java b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/PropertiesManager.java index cdf634d1f..786a42470 100644 --- a/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/PropertiesManager.java +++ b/microprofile.jdt/org.eclipse.lsp4mp.jdt.core/src/main/java/org/eclipse/lsp4mp/jdt/core/PropertiesManager.java @@ -17,6 +17,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -51,11 +52,14 @@ import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4mp.commons.ClasspathKind; +import org.eclipse.lsp4mp.commons.ConfigSourceInfo; import org.eclipse.lsp4mp.commons.DocumentFormat; import org.eclipse.lsp4mp.commons.MicroProfileProjectInfo; import org.eclipse.lsp4mp.commons.MicroProfileProjectInfoParams; import org.eclipse.lsp4mp.commons.MicroProfilePropertiesScope; import org.eclipse.lsp4mp.commons.MicroProfilePropertyDefinitionParams; +import org.eclipse.lsp4mp.jdt.core.project.JDTMicroProfileProject; +import org.eclipse.lsp4mp.jdt.core.project.JDTMicroProfileProjectManager; import org.eclipse.lsp4mp.jdt.core.utils.IJDTUtils; import org.eclipse.lsp4mp.jdt.core.utils.JDTMicroProfileUtils; import org.eclipse.lsp4mp.jdt.internal.core.FakeJavaProject; @@ -116,6 +120,9 @@ public MicroProfileProjectInfo getMicroProfileProjectInfo(IJavaProject javaProje List scopes, ClasspathKind classpathKind, IJDTUtils utils, DocumentFormat documentFormat, IProgressMonitor monitor) throws JavaModelException, CoreException { MicroProfileProjectInfo info = createInfo(javaProject.getProject(), classpathKind); + Set configSources = getConfigSourceInfos(javaProject); + info.setConfigSources(configSources); + if (classpathKind == ClasspathKind.NONE) { info.setProperties(Collections.emptyList()); return info; @@ -156,6 +163,16 @@ public MicroProfileProjectInfo getMicroProfileProjectInfo(IJavaProject javaProje return info; } + private static Set getConfigSourceInfos(IJavaProject javaProject) throws JavaModelException { + JDTMicroProfileProject mpProject = JDTMicroProfileProjectManager.getInstance() + .getJDTMicroProfileProject(javaProject); + return mpProject.getConfigSources() // + .stream() // + .map(configSource -> new ConfigSourceInfo(configSource.getSourceConfigFileURI(), + configSource.getOrdinal(), configSource.getProfile())) // + .collect(Collectors.toSet()); + } + /** * Configure the classpath used for the search of MicroProfile properties. At * this step we can add new JARs to use for the search (ex : for Quarkus we add diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/ConfigSourceInfo.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/ConfigSourceInfo.java new file mode 100644 index 000000000..cfce8aed5 --- /dev/null +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/ConfigSourceInfo.java @@ -0,0 +1,59 @@ +/******************************************************************************* +* Copyright (c) 2022 Red Hat Inc. and others. +* +* This program and the accompanying materials are made available under the +* terms of the Eclipse Public License v. 2.0 which is available at +* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +* which is available at https://www.apache.org/licenses/LICENSE-2.0. +* +* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lsp4mp.commons; + +public class ConfigSourceInfo { + + private String uri; + + private String profile; + + private int ordinal; + + public ConfigSourceInfo() { + } + + public ConfigSourceInfo(String uri, int ordinal, String profile) { + super(); + this.uri = uri; + this.ordinal = ordinal; + this.profile = profile; + } + + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getProfile() { + return profile; + } + + public void setProfile(String profile) { + this.profile = profile; + } + + public int getOrdinal() { + return ordinal; + } + + public void setOrdinal(int ordinal) { + this.ordinal = ordinal; + } + +} diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/MicroProfileProjectInfo.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/MicroProfileProjectInfo.java index c85c22bc2..a88410a78 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/MicroProfileProjectInfo.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/commons/MicroProfileProjectInfo.java @@ -14,6 +14,7 @@ package org.eclipse.lsp4mp.commons; import java.util.Collections; +import java.util.Set; import org.eclipse.lsp4mp.commons.metadata.ConfigurationMetadata; @@ -38,6 +39,8 @@ public class MicroProfileProjectInfo extends ConfigurationMetadata { private ClasspathKind classpathKind; + private Set configSources; + /** * Returns the project URI. * @@ -74,4 +77,11 @@ public void setClasspathKind(ClasspathKind classpathKind) { this.classpathKind = classpathKind; } + public Set getConfigSources() { + return configSources; + } + + public void setConfigSources(Set configSources) { + this.configSources = configSources; + } } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/extensions/ExtendedMicroProfileProjectInfo.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/extensions/ExtendedMicroProfileProjectInfo.java index a416b5a6f..254f64419 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/extensions/ExtendedMicroProfileProjectInfo.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/extensions/ExtendedMicroProfileProjectInfo.java @@ -76,6 +76,7 @@ public ComputedItemMetadata(ItemMetadata metadata, ItemHint itemHint, ValueHint public ExtendedMicroProfileProjectInfo(MicroProfileProjectInfo delegate) { super.setProjectURI(delegate.getProjectURI()); + super.setConfigSources(delegate.getConfigSources()); // Update hints super.setHints( new CopyOnWriteArrayList<>(delegate.getHints() != null ? delegate.getHints() : new ArrayList<>())); diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java index 985a9b96d..8c3bda501 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/java/JavaFileTextDocumentService.java @@ -64,10 +64,10 @@ import org.eclipse.lsp4mp.ls.commons.client.CommandKind; import org.eclipse.lsp4mp.ls.commons.client.ExtendedCompletionCapabilities; import org.eclipse.lsp4mp.ls.java.JavaTextDocuments.JavaTextDocument; -import org.eclipse.lsp4mp.ls.properties.IPropertiesModelProvider; import org.eclipse.lsp4mp.model.Node; import org.eclipse.lsp4mp.model.PropertiesModel; import org.eclipse.lsp4mp.model.Property; +import org.eclipse.lsp4mp.services.properties.IPropertiesModelProvider; import org.eclipse.lsp4mp.settings.MicroProfileCodeLensSettings; import org.eclipse.lsp4mp.settings.MicroProfileValidationSettings; import org.eclipse.lsp4mp.settings.SharedSettings; @@ -272,10 +272,7 @@ public CompletableFuture, List> cache; + private final Map> cache; private final MicroProfileProjectInfoProvider provider; @@ -52,11 +52,12 @@ public MicroProfileProjectInfoCache(MicroProfileProjectInfoProvider provider) { /** * Returns as promise the MicroProfile project information for the given - * application.properties URI. + * microprofile-config.properties, application.properties, etc URI. + * + * @param params the URI of themicroprofile-config.properties, application.properties, etc. * - * @param params the URI of the application.properties. * @return as promise the MicroProfile project information for the given - * application.properties URI. + * microprofile-config.properties, application.properties, etc URI. */ public CompletableFuture getProjectInfo(MicroProfileProjectInfoParams params) { return getProjectInfoFromCache(params). // @@ -94,8 +95,8 @@ CompletableFuture getProjectInfoFromCache(MicroProfileP LOGGER.log(Level.WARNING, String.format( "Error while getting MicroProfileProjectInfo (sources) for '%s'", params.getUri()), ex); return MicroProfileProjectInfo.EMPTY_PROJECT_INFO; - }). // - thenApply(info -> + }) // + .thenApply(info -> // then update the cache with the new properties { wrapper.updateSourcesProperties(info.getProperties(), info.getHints()); @@ -131,13 +132,13 @@ public Collection propertiesChanged(MicroProfilePropertiesChangeEvent ev } private Collection classpathChanged(Set projectURIs) { - List applicationPropertiesURIs = getApplicationPropertiesURIs(projectURIs); + List applicationPropertiesURIs = getPropertiesFileURIs(projectURIs); applicationPropertiesURIs.forEach(cache::remove); return applicationPropertiesURIs; } private Collection javaSourceChanged(Set projectURIs) { - List applicationPropertiesURIs = getApplicationPropertiesURIs(projectURIs); + List applicationPropertiesURIs = getPropertiesFileURIs(projectURIs); for (String uri : applicationPropertiesURIs) { ExtendedMicroProfileProjectInfo info = getProjectInfoWrapper(cache.get(uri)); if (info != null) { @@ -148,15 +149,15 @@ private Collection javaSourceChanged(Set projectURIs) { } /** - * Returns the application.propeties URIs which belongs to the given project - * URIs. + * Returns the propeties file URIs (microprofile-config.properties, + * application.properties, etc) which belongs to the given project URI. * * @param projectURIs project URIs * - * @return the application.propeties URIs which belongs to the given project - * URIs. + * @return the propeties file URIs (microprofile-config.properties, + * application.properties, etc) which belongs to the given project URI. */ - private List getApplicationPropertiesURIs(Set projectURIs) { + private List getPropertiesFileURIs(Set projectURIs) { return cache.entrySet().stream().filter(entry -> { MicroProfileProjectInfo projectInfo = getProjectInfoWrapper(entry.getValue()); if (projectInfo != null) { diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/PropertiesFileTextDocumentService.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/PropertiesFileTextDocumentService.java index b296d7906..91776eca7 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/PropertiesFileTextDocumentService.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/PropertiesFileTextDocumentService.java @@ -59,9 +59,9 @@ import org.eclipse.lsp4mp.ls.MicroProfileLanguageServer; import org.eclipse.lsp4mp.ls.api.MicroProfileLanguageServerAPI.JsonSchemaForProjectInfo; import org.eclipse.lsp4mp.ls.commons.ModelTextDocument; -import org.eclipse.lsp4mp.ls.commons.ModelTextDocuments; import org.eclipse.lsp4mp.ls.commons.ValidatorDelayer; import org.eclipse.lsp4mp.model.PropertiesModel; +import org.eclipse.lsp4mp.services.properties.IPropertiesModelProvider; import org.eclipse.lsp4mp.services.properties.PropertiesFileLanguageService; import org.eclipse.lsp4mp.settings.MicroProfileFormattingSettings; import org.eclipse.lsp4mp.settings.MicroProfileInlayHintSettings; @@ -69,7 +69,6 @@ import org.eclipse.lsp4mp.settings.MicroProfileValidationSettings; import org.eclipse.lsp4mp.settings.SharedSettings; import org.eclipse.lsp4mp.utils.JSONSchemaUtils; -import org.eclipse.lsp4mp.utils.URIUtils; /** * LSP text document service for 'microprofile-config.properties', @@ -80,7 +79,7 @@ public class PropertiesFileTextDocumentService extends AbstractTextDocumentServi private static final MicroProfileProjectInfo PROJECT_INFO_LOADING = new MicroProfileProjectInfo(); - private final ModelTextDocuments documents; + private final PropertiesTextDocuments documents; private MicroProfileProjectInfoCache projectInfoCache; @@ -89,7 +88,7 @@ public class PropertiesFileTextDocumentService extends AbstractTextDocumentServi public PropertiesFileTextDocumentService(MicroProfileLanguageServer microprofileLanguageServer, SharedSettings sharedSettings) { super(microprofileLanguageServer, sharedSettings); - this.documents = new ModelTextDocuments((document, cancelChecker) -> { + this.documents = new PropertiesTextDocuments((document, cancelChecker) -> { return PropertiesModel.parse(document, cancelChecker); }); this.validatorDelayer = new ValidatorDelayer>((document) -> { @@ -138,8 +137,8 @@ public CompletableFuture, CompletionList>> completio // then return completion by using the MicroProfile project information and the // Properties model document CompletionList list = getPropertiesFileLanguageService().doComplete(document, params.getPosition(), - projectInfo, sharedSettings.getCompletionCapabilities(), sharedSettings.getFormattingSettings(), - cancelChecker); + projectInfo, this, sharedSettings.getCompletionCapabilities(), + sharedSettings.getFormattingSettings(), cancelChecker); return Either.forRight(list); }); } @@ -152,14 +151,11 @@ public CompletableFuture hover(HoverParams params) { // Don't block if it hasn't been computed yet MicroProfileProjectInfoParams projectInfoParams = createProjectInfoParams(params.getTextDocument()); MicroProfileProjectInfo projectInfo = getProjectInfoCache().getProjectInfo(projectInfoParams).getNow(null); - if (projectInfo == null || projectInfo.getProperties().isEmpty()) { - return null; - } cancelChecker.checkCanceled(); // then return hover by using the MicroProfile project information and the // Properties model document - return getPropertiesFileLanguageService().doHover(document, params.getPosition(), projectInfo, + return getPropertiesFileLanguageService().doHover(document, params.getPosition(), projectInfo, this, sharedSettings.getHoverSettings(), cancelChecker); }); } @@ -193,7 +189,7 @@ public CompletableFuture, List { MicroProfileProjectInfoParams projectInfoParams = createProjectInfoParams(params.getTextDocument()); MicroProfileProjectInfo projectInfo = getProjectInfoCache().getProjectInfo(projectInfoParams).getNow(null); - return getPropertiesFileLanguageService().findDefinition(document, params.getPosition(), projectInfo, + return getPropertiesFileLanguageService().findDefinition(document, params.getPosition(), projectInfo, this, microprofileLanguageServer.getLanguageClient(), isDefinitionLinkSupport(), cancelChecker); }); } @@ -268,7 +264,8 @@ public CompletableFuture> inlayHint(InlayHintParams params) { private List inlayHint(InlayHintParams params, PropertiesModel document, MicroProfileProjectInfo projectInfo, CancelChecker cancelChecker) { - return getPropertiesFileLanguageService().getInlayHint(document, projectInfo, params.getRange(), cancelChecker); + return getPropertiesFileLanguageService().getInlayHint(document, projectInfo, this, params.getRange(), + cancelChecker); } private MicroProfileProjectInfoParams createProjectInfoParams(TextDocumentIdentifier id) { @@ -320,12 +317,9 @@ private void triggerValidationFor(ModelTextDocument model) { private CompletionStage triggerValidationFor(PropertiesModel propertiesModel, MicroProfileProjectInfo projectInfo, CancelChecker cancelChecker) { cancelChecker.checkCanceled(); - if (projectInfo.getProperties().isEmpty()) { - return CompletableFuture.completedFuture(null); - } List diagnostics = getPropertiesFileLanguageService().doDiagnostics(propertiesModel, projectInfo, - getSharedSettings().getValidationSettings(), cancelChecker); + this, getSharedSettings().getValidationSettings(), cancelChecker); cancelChecker.checkCanceled(); microprofileLanguageServer.getLanguageClient() .publishDiagnostics(new PublishDiagnosticsParams(propertiesModel.getDocumentURI(), diagnostics)); @@ -431,22 +425,9 @@ public CompletableFuture getJsonSchemaForProjectInfo( @Override public PropertiesModel getPropertiesModel(String documentURI) { // Try to get the document from the Map. - ModelTextDocument document = documents.get(documentURI); - if (document != null) { - return document.getModel(); - } - // vscode opens the file by encoding the file URI and the 'C' of hard drive - // lower case - // 'c'. - // for --> file:///C:/Users/a folder/application.properties - // vscode didOpen --> file:///c%3A/Users/a%20folder/application.properties - String encodedFileURI = URIUtils.encodeFileURI(documentURI).toUpperCase(); - // We loop for all properties files which are opened and we compare the encoded - // file URI with upper case - for (ModelTextDocument textDocument : documents.all()) { - if (textDocument.getUri().toUpperCase().equals(encodedFileURI)) { - return textDocument.getModel(); - } + PropertiesModel model = documents.getModel(documentURI); + if (model != null) { + return model; } return null; } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/PropertiesTextDocuments.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/PropertiesTextDocuments.java new file mode 100644 index 000000000..b1678ce07 --- /dev/null +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/PropertiesTextDocuments.java @@ -0,0 +1,73 @@ +package org.eclipse.lsp4mp.ls.properties; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; + +import org.eclipse.lsp4j.DidOpenTextDocumentParams; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.eclipse.lsp4mp.ls.commons.ModelTextDocument; +import org.eclipse.lsp4mp.ls.commons.ModelTextDocuments; +import org.eclipse.lsp4mp.ls.commons.TextDocument; +import org.eclipse.lsp4mp.model.PropertiesModel; +import org.eclipse.lsp4mp.utils.PropertiesFileUtils; +import org.eclipse.lsp4mp.utils.URIUtils; + +public class PropertiesTextDocuments extends ModelTextDocuments { + + private final Map closedModels; + + public PropertiesTextDocuments(BiFunction parse) { + super(parse); + this.closedModels = new HashMap<>(); + } + + @Override + public ModelTextDocument onDidOpenTextDocument(DidOpenTextDocumentParams params) { + String uri = params.getTextDocument().getUri(); + if (closedModels.containsKey(uri)) { + synchronized (closedModels) { + this.closedModels.remove(uri); + } + } + return super.onDidOpenTextDocument(params); + } + + @Override + public PropertiesModel getModel(String uri) { + PropertiesModel openedModel = super.getModel(uri); + if (openedModel != null) { + return openedModel; + } + // vscode opens the file by encoding the file URI and the 'C' of hard drive + // lower case + // 'c'. + // for --> file:///C:/Users/a folder/application.properties + // vscode didOpen --> file:///c%3A/Users/a%20folder/application.properties + String encodedFileURI = URIUtils.encodeFileURI(uri).toUpperCase(); + // We loop for all properties files which are opened and we compare the encoded + // file URI with upper case + for (ModelTextDocument textDocument : all()) { + if (textDocument.getUri().toUpperCase().equals(encodedFileURI)) { + return textDocument.getModel(); + } + } + PropertiesModel closedModel = closedModels.get(uri); + if (closedModel != null) { + return closedModel; + } + synchronized (closedModels) { + closedModel = closedModels.get(uri); + if (closedModel != null) { + return closedModel; + } + closedModel = PropertiesFileUtils.loadProperties(uri); + if (closedModel != null) { + closedModels.put(uri, closedModel); + } + } + return closedModel; + + } + +} diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/IPropertiesModelProvider.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/IPropertiesModelProvider.java similarity index 92% rename from microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/IPropertiesModelProvider.java rename to microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/IPropertiesModelProvider.java index f410009ac..db473b14b 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/ls/properties/IPropertiesModelProvider.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/IPropertiesModelProvider.java @@ -11,7 +11,7 @@ * Contributors: * Red Hat Inc. - initial API and implementation *******************************************************************************/ -package org.eclipse.lsp4mp.ls.properties; +package org.eclipse.lsp4mp.services.properties; import org.eclipse.lsp4mp.model.PropertiesModel; diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileCompletions.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileCompletions.java index 28ed0a022..c6f510d6f 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileCompletions.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileCompletions.java @@ -13,12 +13,12 @@ *******************************************************************************/ package org.eclipse.lsp4mp.services.properties; +import static org.eclipse.lsp4mp.services.properties.PropertiesInfoPropertiesProvider.createConfigSourcePropertiesProvider; + import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Predicate; @@ -40,7 +40,7 @@ import org.eclipse.lsp4mp.commons.metadata.ConverterKind; import org.eclipse.lsp4mp.commons.metadata.ItemMetadata; import org.eclipse.lsp4mp.commons.metadata.ValueHint; -import org.eclipse.lsp4mp.commons.utils.ConfigSourcePropertiesProviderUtils; +import org.eclipse.lsp4mp.commons.utils.IConfigSourcePropertiesProvider; import org.eclipse.lsp4mp.commons.utils.PropertyValueExpander; import org.eclipse.lsp4mp.commons.utils.StringUtils; import org.eclipse.lsp4mp.ls.commons.BadLocationException; @@ -77,15 +77,16 @@ class PropertiesFileCompletions { /** * Returns completion list for the given position * - * @param document the properties model document - * @param position the position where completion was triggered - * @param projectInfo the MicroProfile project information - * @param completionCapabilities the completion capabilities - * @param cancelChecker the cancel checker + * @param document the properties model document + * @param position the position where completion was triggered + * @param projectInfo the MicroProfile project information + * @param propertiesModelProvider + * @param completionCapabilities the completion capabilities + * @param cancelChecker the cancel checker * @return completion list for the given position */ public CompletionList doComplete(PropertiesModel document, Position position, MicroProfileProjectInfo projectInfo, - MicroProfileCompletionCapabilities completionCapabilities, + IPropertiesModelProvider propertiesModelProvider, MicroProfileCompletionCapabilities completionCapabilities, MicroProfileFormattingSettings formattingSettings, CancelChecker cancelChecker) { CompletionList list = new CompletionList(); int offset = -1; @@ -117,8 +118,8 @@ public CompletionList doComplete(PropertiesModel document, Position position, Mi list); } else { // other.test.property = ${|} - collectPropertyValueExpressionSuggestions(propExpr, document, projectInfo, completionCapabilities, - list, cancelChecker); + collectPropertyValueExpressionSuggestions(propExpr, document, projectInfo, propertiesModelProvider, + completionCapabilities, list, cancelChecker); } break; @@ -454,10 +455,13 @@ private static void collectPropertyValueSuggestions(Node node, PropertiesModel m } private static void collectPropertyValueExpressionSuggestions(PropertyValueExpression node, PropertiesModel model, - MicroProfileProjectInfo projectInfo, MicroProfileCompletionCapabilities completionCapabilities, - CompletionList list, CancelChecker cancelChecker) { + MicroProfileProjectInfo projectInfo, IPropertiesModelProvider propertiesModelProvider, + MicroProfileCompletionCapabilities completionCapabilities, CompletionList list, + CancelChecker cancelChecker) { - PropertyValueExpander expander = new PropertyValueExpander(model); + IConfigSourcePropertiesProvider properties = createConfigSourcePropertiesProvider(model, projectInfo, + propertiesModelProvider, cancelChecker); + PropertyValueExpander expander = new PropertyValueExpander(properties); cancelChecker.checkCanceled(); // Find properties that won't make a circular dependency and suggest them for diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileDefinition.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileDefinition.java index 593254b50..732b4dfe1 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileDefinition.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileDefinition.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.logging.Level; import java.util.logging.Logger; @@ -24,6 +25,7 @@ import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.eclipse.lsp4mp.commons.ConfigSourceInfo; import org.eclipse.lsp4mp.commons.MicroProfileProjectInfo; import org.eclipse.lsp4mp.commons.MicroProfilePropertyDefinitionParams; import org.eclipse.lsp4mp.commons.metadata.ItemHint; @@ -57,18 +59,19 @@ public class PropertiesFileDefinition { * given position of the given microprofile-config.properties * document. * - * @param document the properties model. - * @param position the position where definition was triggered - * @param projectInfo the MicroProfile project info - * @param provider the MicroProfile property definition provider. - * @param cancelChecker the cancel checker + * @param document the properties model. + * @param position the position where definition was triggered + * @param projectInfo the MicroProfile project info + * @param propertiesModelProvider + * @param provider the MicroProfile property definition provider. + * @param cancelChecker the cancel checker * @return as promise the Java field definition location of the property at the * given position of the given * microprofile-config.properties document. */ public CompletableFuture> findDefinition(PropertiesModel document, Position position, - MicroProfileProjectInfo projectInfo, MicroProfilePropertyDefinitionProvider provider, - CancelChecker cancelChecker) { + MicroProfileProjectInfo projectInfo, IPropertiesModelProvider propertiesModelProvider, + MicroProfilePropertyDefinitionProvider provider, CancelChecker cancelChecker) { try { int offset = document.offsetAt(position); @@ -82,8 +85,8 @@ public CompletableFuture> findDefinition(PropertiesModel docu PropertyValueExpression propertyValueExpression = (PropertyValueExpression) node; inDefautlValue = propertyValueExpression.isInDefaultValue(offset); if (!inDefautlValue) { - return CompletableFuture - .completedFuture(findPropertyValueExpressionDefinition(document, propertyValueExpression)); + return CompletableFuture.completedFuture(findPropertyValueExpressionDefinition(document, + propertyValueExpression, projectInfo.getConfigSources(), propertiesModelProvider)); } } @@ -135,16 +138,34 @@ public CompletableFuture> findDefinition(PropertiesModel docu * PropertyValueExpression * @param propertyValueExpression the PropertyValueExpression whose definition * is to be found + * @param configSources + * @param propertiesModelProvider * @return a list of LocationLinks to the lines where the property referenced by * the property expression is assigned a value */ private static List findPropertyValueExpressionDefinition(PropertiesModel document, - PropertyValueExpression propertyValueExpression) { + PropertyValueExpression propertyValueExpression, Set configSources, + IPropertiesModelProvider propertiesModelProvider) { String propToResolveName = propertyValueExpression.getReferencedPropertyName(); + List locationLinks = new ArrayList<>(); - List props = new ArrayList<>(); + fillPropertyDefinition(document, propertyValueExpression, propToResolveName, locationLinks); + if (configSources != null) { + for (ConfigSourceInfo configSource : configSources) { + PropertiesModel document2 = propertiesModelProvider.getPropertiesModel(configSource.getUri()); + if (document2 != null && document2 != document) { + fillPropertyDefinition(document2, propertyValueExpression, propToResolveName, locationLinks); + } + } + } + return locationLinks; + } + + public static void fillPropertyDefinition(PropertiesModel document, PropertyValueExpression propertyValueExpression, + String propToResolveName, List locationLinks) { + List props = new ArrayList<>(); for (Node modelChild : document.getChildren()) { if (modelChild.getNodeType() == NodeType.PROPERTY) { Property property = (Property) modelChild; @@ -156,10 +177,8 @@ private static List findPropertyValueExpressionDefinition(Properti } if (!props.isEmpty()) { - return getPropertyDefinition(document, propertyValueExpression, props); + fillPropertyDefinition(document, propertyValueExpression, props, locationLinks); } - - return Collections.emptyList(); } private static CompletableFuture> getEmptyDefinition() { @@ -181,34 +200,34 @@ private static MicroProfilePropertyDefinitionParams getPropertyDefinitionParams( String sourceField = null; switch (node.getNodeType()) { - case PROPERTY_KEY: { - sourceType = item.getSourceType(); - sourceField = item.getSourceField(); - break; - } - case PROPERTY_VALUE_EXPRESSION: - case PROPERTY_VALUE_LITERAL: - case PROPERTY_VALUE: { - sourceType = item.getHintType(); - sourceField = getSourceField(node, inDefautlValue); - // for the case of property which uses kebab_case, we must get the real value of - // the Java enumeration - // Ex: for quarkus.datasource.transaction-isolation-level = read-uncommitted - // the real value of Java enumeration 'read-uncommitted' is 'READ_UNCOMMITTED' - ItemHint itemHint = projectInfo.getHint(sourceType); - if (itemHint != null) { - ValueHint realValue = itemHint.getValue(sourceField, item.getConverterKinds()); - if (realValue != null) { - sourceField = realValue.getValue(); - if (realValue.getSourceType() != null) { - sourceType = realValue.getSourceType(); - } + case PROPERTY_KEY: { + sourceType = item.getSourceType(); + sourceField = item.getSourceField(); + break; + } + case PROPERTY_VALUE_EXPRESSION: + case PROPERTY_VALUE_LITERAL: + case PROPERTY_VALUE: { + sourceType = item.getHintType(); + sourceField = getSourceField(node, inDefautlValue); + // for the case of property which uses kebab_case, we must get the real value of + // the Java enumeration + // Ex: for quarkus.datasource.transaction-isolation-level = read-uncommitted + // the real value of Java enumeration 'read-uncommitted' is 'READ_UNCOMMITTED' + ItemHint itemHint = projectInfo.getHint(sourceType); + if (itemHint != null) { + ValueHint realValue = itemHint.getValue(sourceField, item.getConverterKinds()); + if (realValue != null) { + sourceField = realValue.getValue(); + if (realValue.getSourceType() != null) { + sourceType = realValue.getSourceType(); } } - break; } - default: - return null; + break; + } + default: + return null; } // Find definition (class, field of class, method of class, enum) only when @@ -235,10 +254,9 @@ private static String getSourceField(Node node, boolean inDefautlValue) { return propertyValue.getValue(); } - private static List getPropertyDefinition(PropertiesModel document, - PropertyValueExpression propertyValueExpression, List referencedProperties) { - - List locationLinks = new ArrayList<>(); + private static void fillPropertyDefinition(PropertiesModel document, + PropertyValueExpression propertyValueExpression, List referencedProperties, + List locationLinks) { for (Property referencedProperty : referencedProperties) { Node key = referencedProperty.getKey(); Range referencedPropertyRange = PositionUtils.createRange(key); @@ -246,7 +264,6 @@ private static List getPropertyDefinition(PropertiesModel document locationLinks.add(new LocationLink(document.getDocumentURI(), referencedPropertyRange, referencedPropertyRange, propertyReferenceRange)); } - return locationLinks; } private static PropertyKey getPropertyKey(Node node) { @@ -254,14 +271,14 @@ private static PropertyKey getPropertyKey(Node node) { return null; } switch (node.getNodeType()) { - case PROPERTY_KEY: - return (PropertyKey) node; - case PROPERTY_VALUE: - case PROPERTY_VALUE_EXPRESSION: - case PROPERTY_VALUE_LITERAL: - return ((BasePropertyValue) node).getProperty().getKey(); - default: - return null; + case PROPERTY_KEY: + return (PropertyKey) node; + case PROPERTY_VALUE: + case PROPERTY_VALUE_EXPRESSION: + case PROPERTY_VALUE_LITERAL: + return ((BasePropertyValue) node).getProperty().getKey(); + default: + return null; } } } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileDiagnostics.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileDiagnostics.java index d79b8801c..f2340546b 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileDiagnostics.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileDiagnostics.java @@ -34,18 +34,19 @@ class PropertiesFileDiagnostics { * * @param document the properties model. * @param projectInfo the MicroProfile properties + * @param propertiesModelProvider * @param validationSettings the validation settings. * @param cancelChecker the cancel checker. * @return the result of the validation. */ public List doDiagnostics(PropertiesModel document, MicroProfileProjectInfo projectInfo, - MicroProfileValidationSettings validationSettings, CancelChecker cancelChecker) { + IPropertiesModelProvider propertiesModelProvider, MicroProfileValidationSettings validationSettings, CancelChecker cancelChecker) { if (validationSettings == null) { validationSettings = MicroProfileValidationSettings.DEFAULT; } List diagnostics = new ArrayList(); if (validationSettings.isEnabled()) { - PropertiesFileValidator validator = new PropertiesFileValidator(projectInfo, diagnostics, validationSettings); + PropertiesFileValidator validator = new PropertiesFileValidator(projectInfo, propertiesModelProvider, diagnostics, validationSettings); validator.validate(document, cancelChecker); } return diagnostics; diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileHover.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileHover.java index d6ff7e0b6..b443596c2 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileHover.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileHover.java @@ -13,6 +13,8 @@ *******************************************************************************/ package org.eclipse.lsp4mp.services.properties; +import static org.eclipse.lsp4mp.services.properties.PropertiesInfoPropertiesProvider.resolveExpression; + import java.util.logging.Level; import java.util.logging.Logger; @@ -27,9 +29,6 @@ import org.eclipse.lsp4mp.commons.metadata.ItemHint; import org.eclipse.lsp4mp.commons.metadata.ItemMetadata; import org.eclipse.lsp4mp.commons.metadata.ValueHint; -import org.eclipse.lsp4mp.commons.utils.ConfigSourcePropertiesProviderUtils; -import org.eclipse.lsp4mp.commons.utils.IConfigSourcePropertiesProvider; -import org.eclipse.lsp4mp.commons.utils.PropertyValueExpander; import org.eclipse.lsp4mp.commons.utils.StringUtils; import org.eclipse.lsp4mp.ls.commons.BadLocationException; import org.eclipse.lsp4mp.model.BasePropertyValue; @@ -60,8 +59,11 @@ class PropertiesFileHover { * @return Hover object for the currently hovered token */ public Hover doHover(PropertiesModel document, Position position, MicroProfileProjectInfo projectInfo, - MicroProfileHoverSettings hoverSettings, CancelChecker cancelChecker) { - + IPropertiesModelProvider propertiesModelProvider, MicroProfileHoverSettings hoverSettings, + CancelChecker cancelChecker) { + if (projectInfo == null) { + projectInfo = MicroProfileProjectInfo.EMPTY_PROJECT_INFO; + } Node node = null; int offset = -1; try { @@ -87,7 +89,8 @@ public Hover doHover(PropertiesModel document, Position position, MicroProfilePr return getPropertyValueHover(propExpr, inDefaultValue, projectInfo, hoverSettings); } // quarkus.log.file.level=${E|NV:OFF} - return getPropertyValueExpressionHover(propExpr, projectInfo, hoverSettings, cancelChecker); + return getPropertyValueExpressionHover(propExpr, projectInfo, propertiesModelProvider, hoverSettings, + cancelChecker); case PROPERTY_VALUE_LITERAL: case PROPERTY_VALUE: return getPropertyValueHover((BasePropertyValue) node, false, projectInfo, hoverSettings); @@ -98,7 +101,7 @@ public Hover doHover(PropertiesModel document, Position position, MicroProfilePr return getProfileHover(key, hoverSettings); } else { // hover documentation on property key - return getPropertyKeyHover(key, projectInfo, hoverSettings, cancelChecker); + return getPropertyKeyHover(key, projectInfo, propertiesModelProvider, hoverSettings, cancelChecker); } default: @@ -135,26 +138,24 @@ private static Hover getProfileHover(PropertyKey key, MicroProfileHoverSettings * Returns the documentation hover for property key represented by the property * key key * - * @param key the property key - * @param offset the hover offset - * @param projectInfo the MicroProfile project information - * @param hoverSettings the hover settings - * @param cancelChecker the cancel checker + * @param key the property key + * @param offset the hover offset + * @param projectInfo the MicroProfile project information + * @param propertiesModelProvider + * @param hoverSettings the hover settings + * @param cancelChecker the cancel checker * @return the documentation hover for property key represented by token */ private static Hover getPropertyKeyHover(PropertyKey key, MicroProfileProjectInfo projectInfo, - MicroProfileHoverSettings hoverSettings, CancelChecker cancelChecker) { + IPropertiesModelProvider propertiesModelProvider, MicroProfileHoverSettings hoverSettings, + CancelChecker cancelChecker) { boolean markdownSupported = hoverSettings.isContentFormatSupported(MarkupKind.MARKDOWN); // retrieve MicroProfile property from the project information String propertyName = key.getPropertyName(); PropertiesModel model = key.getOwnerModel(); - IConfigSourcePropertiesProvider propertiesProvider = ConfigSourcePropertiesProviderUtils.layer(model, - new PropertiesInfoPropertiesProvider(projectInfo.getProperties())); - PropertyValueExpander expander = new PropertyValueExpander(propertiesProvider); - cancelChecker.checkCanceled(); - - String propertyValue = expander.getValue(key.getPropertyNameWithProfile()); + String propertyValue = resolveExpression(key.getPropertyNameWithProfile(), model, projectInfo, + propertiesModelProvider, cancelChecker); if (!StringUtils.hasText(propertyValue)) { propertyValue = null; } @@ -217,18 +218,14 @@ private static Hover getPropertyValueHover(BasePropertyValue value, boolean inDe } private static Hover getPropertyValueExpressionHover(PropertyValueExpression node, - MicroProfileProjectInfo projectInfo, MicroProfileHoverSettings hoverSettings, CancelChecker cancelChecker) { + MicroProfileProjectInfo projectInfo, IPropertiesModelProvider propertiesModelProvider, + MicroProfileHoverSettings hoverSettings, CancelChecker cancelChecker) { String referencedProp = node.getReferencedPropertyName(); if (referencedProp == null) { return null; } - - PropertiesModel model = node.getOwnerModel(); - IConfigSourcePropertiesProvider propertiesProvider = ConfigSourcePropertiesProviderUtils.layer(model, new PropertiesInfoPropertiesProvider(projectInfo.getProperties())); - PropertyValueExpander expander = new PropertyValueExpander(propertiesProvider); - cancelChecker.checkCanceled(); - - String resolvedValue = expander.getValue(referencedProp); + String resolvedValue = resolveExpression(referencedProp, node.getOwnerModel(), projectInfo, + propertiesModelProvider, cancelChecker); if (StringUtils.hasText(resolvedValue)) { return createHover(resolvedValue, node); diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileInlayHint.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileInlayHint.java index 4f06cdcad..f4a9e2c2f 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileInlayHint.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileInlayHint.java @@ -13,8 +13,9 @@ *******************************************************************************/ package org.eclipse.lsp4mp.services.properties; +import static org.eclipse.lsp4mp.services.properties.PropertiesInfoPropertiesProvider.resolveExpression; + import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -24,10 +25,6 @@ import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.jsonrpc.CancelChecker; import org.eclipse.lsp4mp.commons.MicroProfileProjectInfo; -import org.eclipse.lsp4mp.commons.metadata.ItemMetadata; -import org.eclipse.lsp4mp.commons.utils.ConfigSourcePropertiesProviderUtils; -import org.eclipse.lsp4mp.commons.utils.IConfigSourcePropertiesProvider; -import org.eclipse.lsp4mp.commons.utils.PropertyValueExpander; import org.eclipse.lsp4mp.ls.commons.BadLocationException; import org.eclipse.lsp4mp.model.Node; import org.eclipse.lsp4mp.model.Node.NodeType; @@ -63,11 +60,8 @@ class PropertiesFileInlayHint { private static final Logger LOGGER = Logger.getLogger(PropertiesFileInlayHint.class.getName()); - public List getInlayHint(PropertiesModel document, MicroProfileProjectInfo projectInfo, Range range, - CancelChecker cancelChecker) { - List metadatas = projectInfo != null && projectInfo.getProperties() != null - ? projectInfo.getProperties() - : Collections.emptyList(); + public List getInlayHint(PropertiesModel document, MicroProfileProjectInfo projectInfo, + IPropertiesModelProvider propertiesModelProvider, Range range, CancelChecker cancelChecker) { List hints = new ArrayList<>(); List children = document.getChildren(); for (Node child : children) { @@ -78,10 +72,8 @@ public List getInlayHint(PropertiesModel document, MicroProfileProjec if (valueNode != null && valueNode.hasExpression()) { // The current property has a value with expression: // ex : server.url=https://${host}:${port:8080}/${endpoint} - IConfigSourcePropertiesProvider propertiesProvider = ConfigSourcePropertiesProviderUtils - .layer(document, new PropertiesInfoPropertiesProvider(metadatas)); - PropertyValueExpander expander = new PropertyValueExpander(propertiesProvider); - String resolved = expander.getValue(property.getKey().getPropertyNameWithProfile()); + String resolved = resolveExpression(property.getPropertyNameWithProfile(), document, projectInfo, + propertiesModelProvider, cancelChecker); if (resolved != null) { try { // The expression 'https://${host}:${port:8080}/${endpoint}' can be resolved @@ -103,4 +95,5 @@ public List getInlayHint(PropertiesModel document, MicroProfileProjec } return hints; } + } \ No newline at end of file diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileLanguageService.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileLanguageService.java index b07d09b9a..e5feb805a 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileLanguageService.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileLanguageService.java @@ -84,11 +84,11 @@ public PropertiesFileLanguageService() { * @return completion list for the given position */ public CompletionList doComplete(PropertiesModel document, Position position, MicroProfileProjectInfo projectInfo, - MicroProfileCompletionCapabilities completionCapabilities, + IPropertiesModelProvider propertiesModelProvider, MicroProfileCompletionCapabilities completionCapabilities, MicroProfileFormattingSettings formattingSettings, CancelChecker cancelChecker) { updateProperties(projectInfo, document); - return completions.doComplete(document, position, projectInfo, completionCapabilities, formattingSettings, - cancelChecker); + return completions.doComplete(document, position, projectInfo, propertiesModelProvider, completionCapabilities, + formattingSettings, cancelChecker); } /** @@ -101,9 +101,10 @@ public CompletionList doComplete(PropertiesModel document, Position position, Mi * @return Hover object for the currently hovered token */ public Hover doHover(PropertiesModel document, Position position, MicroProfileProjectInfo projectInfo, - MicroProfileHoverSettings hoverSettings, CancelChecker cancelChecker) { + IPropertiesModelProvider propertiesModelProvider, MicroProfileHoverSettings hoverSettings, + CancelChecker cancelChecker) { updateProperties(projectInfo, document); - return hover.doHover(document, position, projectInfo, hoverSettings, cancelChecker); + return hover.doHover(document, position, projectInfo, propertiesModelProvider, hoverSettings, cancelChecker); } /** @@ -146,11 +147,11 @@ public List findDocumentSymbols(PropertiesModel document, Cancel */ public CompletableFuture, List>> findDefinition( PropertiesModel document, Position position, MicroProfileProjectInfo projectInfo, - MicroProfilePropertyDefinitionProvider provider, boolean definitionLinkSupport, - CancelChecker cancelChecker) { + IPropertiesModelProvider propertiesModelProvider, MicroProfilePropertyDefinitionProvider provider, + boolean definitionLinkSupport, CancelChecker cancelChecker) { updateProperties(projectInfo, document); CompletableFuture> definitionLocationLinks = definition.findDefinition(document, position, - projectInfo, provider, cancelChecker); + projectInfo, propertiesModelProvider, provider, cancelChecker); if (definitionLinkSupport) { return definitionLocationLinks.thenApply((List resolvedLinks) -> { return Either.forRight(resolvedLinks); @@ -203,9 +204,11 @@ public List doRangeFormat(PropertiesModel document, Range ra * @return the result of the validation. */ public List doDiagnostics(PropertiesModel document, MicroProfileProjectInfo projectInfo, - MicroProfileValidationSettings validationSettings, CancelChecker cancelChecker) { + IPropertiesModelProvider propertiesModelProvider, MicroProfileValidationSettings validationSettings, + CancelChecker cancelChecker) { updateProperties(projectInfo, document); - return diagnostics.doDiagnostics(document, projectInfo, validationSettings, cancelChecker); + return diagnostics.doDiagnostics(document, projectInfo, propertiesModelProvider, validationSettings, + cancelChecker); } /** @@ -252,9 +255,9 @@ private void updateProperties(MicroProfileProjectInfo projectInfo, PropertiesMod } } - public List getInlayHint(PropertiesModel document, MicroProfileProjectInfo projectInfo, Range range, - CancelChecker cancelChecker) { - return inlayHint.getInlayHint(document, projectInfo, range, cancelChecker); + public List getInlayHint(PropertiesModel document, MicroProfileProjectInfo projectInfo, + IPropertiesModelProvider propertiesModelProvider, Range range, CancelChecker cancelChecker) { + return inlayHint.getInlayHint(document, projectInfo, propertiesModelProvider, range, cancelChecker); } } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileValidator.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileValidator.java index 9f00dc6cc..7b7000453 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileValidator.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesFileValidator.java @@ -28,6 +28,7 @@ import org.eclipse.lsp4j.DiagnosticSeverity; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.eclipse.lsp4mp.commons.ConfigSourceInfo; import org.eclipse.lsp4mp.commons.MicroProfileProjectInfo; import org.eclipse.lsp4mp.commons.metadata.ConfigurationMetadata; import org.eclipse.lsp4mp.commons.metadata.ItemMetadata; @@ -54,21 +55,23 @@ class PropertiesFileValidator { private final MicroProfileProjectInfo projectInfo; + private final IPropertiesModelProvider propertiesModelProvider; + private final List diagnostics; private final MicroProfileValidationSettings validationSettings; - private final Map> existingProperties; - private Set allPropertiesFromFile; + private Map> allPropertiesFromFiles; private Set allPropertiesFromJava; - public PropertiesFileValidator(MicroProfileProjectInfo projectInfo, List diagnostics, - MicroProfileValidationSettings validationSettings) { + public PropertiesFileValidator(MicroProfileProjectInfo projectInfo, + IPropertiesModelProvider propertiesModelProvider, List diagnostics, + MicroProfileValidationSettings validationSettings) { this.projectInfo = projectInfo; + this.propertiesModelProvider = propertiesModelProvider; this.diagnostics = diagnostics; this.validationSettings = validationSettings; - this.existingProperties = new HashMap>(); // to be lazily init - this.allPropertiesFromFile = null; + this.allPropertiesFromFiles = null; this.allPropertiesFromJava = null; } @@ -76,25 +79,21 @@ public void validate(PropertiesModel document, CancelChecker cancelChecker) { List nodes = document.getChildren(); for (Node node : nodes) { - if (cancelChecker != null) { - cancelChecker.checkCanceled(); - } + checkCanceled(cancelChecker); if (node.getNodeType() == NodeType.PROPERTY) { - validateProperty((Property) node); + validateProperty((Property) node, cancelChecker); } } - addDiagnosticsForDuplicates(); - addDiagnosticsForMissingRequired(document); + addDiagnosticsForDuplicates(document, cancelChecker); + addDiagnosticsForMissingRequired(document, cancelChecker); } - private void validateProperty(Property property) { + private void validateProperty(Property property, CancelChecker cancelChecker) { String propertyNameWithProfile = property.getPropertyNameWithProfile(); if (!StringUtils.isEmpty(propertyNameWithProfile)) { // Validate Syntax property validateSyntaxProperty(propertyNameWithProfile, property); - // Validate Duplicate property - validateDuplicateProperty(propertyNameWithProfile, property); } String propertyName = property.getPropertyName(); @@ -108,7 +107,7 @@ private void validateProperty(Property property) { // Validate simple property Value validateSimplePropertyValue(propertyNameWithProfile, metadata, property); } else { - validatePropertyValueExpressions(propertyNameWithProfile, metadata, property); + validatePropertyValueExpressions(propertyNameWithProfile, metadata, property, cancelChecker); } } } @@ -121,24 +120,10 @@ private void validateSyntaxProperty(String propertyName, Property property) { } if (property.getDelimiterAssign() == null) { addDiagnostic("Missing equals sign after '" + propertyName + "'", property.getKey(), severity, - ValidationType.syntax.name()); + ValidationType.syntax.name()); } } - private void validateDuplicateProperty(String propertyName, Property property) { - DiagnosticSeverity severity = validationSettings.getDuplicate().getDiagnosticSeverity(propertyName); - if (severity == null) { - // The duplicate validation must be ignored for this property name - return; - } - - if (!existingProperties.containsKey(propertyName)) { - existingProperties.put(propertyName, new ArrayList()); - } - - existingProperties.get(propertyName).add(property); - } - private void validateUnknownProperty(String propertyName, Property property) { DiagnosticSeverity severity = validationSettings.getUnknown().getDiagnosticSeverity(propertyName); if (severity == null) { @@ -146,7 +131,7 @@ private void validateUnknownProperty(String propertyName, Property property) { return; } addDiagnostic("Unknown property '" + propertyName + "'", property.getKey(), severity, - ValidationType.unknown.name()); + ValidationType.unknown.name()); } private void validateSimplePropertyValue(String propertyName, ItemMetadata metadata, Property property) { @@ -157,11 +142,11 @@ private void validateSimplePropertyValue(String propertyName, ItemMetadata metad int start = propertyValue.getStart(); int end = propertyValue.getEnd(); validatePropertyValue(propertyName, metadata, property.getPropertyValue(), start, end, - property.getOwnerModel()); + property.getOwnerModel()); } private void validatePropertyValue(String propertyName, ItemMetadata metadata, String value, int start, int end, - PropertiesModel propertiesModel) { + PropertiesModel propertiesModel) { if (metadata == null || StringUtils.isEmpty(value)) { return; } @@ -190,16 +175,18 @@ private void validatePropertyValue(String propertyName, ItemMetadata metadata, S * Checks if the property expression is closed, and if the referenced property * exists. * - * @param property The property to validate + * @param property The property to validate + * @param cancelChecker */ - private void validatePropertyValueExpressions(String propertyName, ItemMetadata metadata, Property property) { + private void validatePropertyValueExpressions(String propertyName, ItemMetadata metadata, Property property, + CancelChecker cancelChecker) { if (property.getValue() == null) { return; } DiagnosticSeverity expressionSeverity = validationSettings.getExpression() - .getDiagnosticSeverity(property.getPropertyName()); + .getDiagnosticSeverity(property.getPropertyName()); DiagnosticSeverity syntaxSeverity = validationSettings.getSyntax() - .getDiagnosticSeverity(property.getPropertyName()); + .getDiagnosticSeverity(property.getPropertyName()); if (expressionSeverity == null || syntaxSeverity == null) { return; } @@ -207,36 +194,29 @@ private void validatePropertyValueExpressions(String propertyName, ItemMetadata if (child != null && child.getNodeType() == NodeType.PROPERTY_VALUE_EXPRESSION) { PropertyValueExpression propValExpr = (PropertyValueExpression) child; if (expressionSeverity != null) { - if (allPropertiesFromFile == null) { - // Collect names of all properties defined in the configuration file and the - // project information - allPropertiesFromFile = property.getOwnerModel().getChildren().stream().filter(n -> { - return n.getNodeType() == NodeType.PROPERTY; - }).map(prop -> { - return ((Property) prop).getPropertyNameWithProfile(); - }).collect(Collectors.toSet()); - allPropertiesFromJava = projectInfo.getProperties().stream().map((ItemMetadata info) -> { - return info.getName(); - }).collect(Collectors.toSet()); - } String refdProp = propValExpr.getReferencedPropertyName(); - if (!allPropertiesFromFile.contains(refdProp)) { + if (!getAllPropertiesFromFiles(property.getOwnerModel(), cancelChecker).containsKey(refdProp)) { + if (allPropertiesFromJava == null) { + allPropertiesFromJava = projectInfo.getProperties().stream().map((ItemMetadata info) -> { + return info.getName(); + }).collect(Collectors.toSet()); + } // The referenced property name doesn't reference a property inside the file if (allPropertiesFromJava.contains(refdProp)) { Range range = PositionUtils.createRange(propValExpr.getReferenceStartOffset(), - propValExpr.getReferenceEndOffset(), propValExpr.getDocument()); + propValExpr.getReferenceEndOffset(), propValExpr.getDocument()); if (range != null) { ItemMetadata referencedProperty = PropertiesFileUtils.getProperty(refdProp, - projectInfo); + projectInfo); if (referencedProperty.getDefaultValue() != null) { // The referenced property has a default value. addDiagnostic("Cannot reference the property '" + refdProp - + "'. A default value defined via annotation like ConfigProperty is not eligible to be expanded since multiple candidates may be available.", - range, expressionSeverity, ValidationType.expression.name()); + + "'. A default value defined via annotation like ConfigProperty is not eligible to be expanded since multiple candidates may be available.", + range, expressionSeverity, ValidationType.expression.name()); } else if (!propValExpr.hasDefaultValue()) { // The referenced property and the property expression have not a default value. addDiagnostic("The referenced property '" + refdProp + "' has no default value.", - range, expressionSeverity, ValidationType.expression.name()); + range, expressionSeverity, ValidationType.expression.name()); } } } else { @@ -245,16 +225,16 @@ private void validatePropertyValueExpressions(String propertyName, ItemMetadata int start = propValExpr.getDefaultValueStartOffset(); int end = propValExpr.getDefaultValueEndOffset(); validatePropertyValue(propertyName, metadata, propValExpr.getDefaultValue(), start, end, - propValExpr.getOwnerModel()); + propValExpr.getOwnerModel()); } else { if (!(EnvUtils.isEnvVariable(refdProp))) { // or the expression is an ENV variable // otherwise the error is reported Range range = PositionUtils.createRange(propValExpr.getReferenceStartOffset(), - propValExpr.getReferenceEndOffset(), propValExpr.getDocument()); + propValExpr.getReferenceEndOffset(), propValExpr.getDocument()); if (range != null) { addDiagnostic("Unknown referenced property value expression '" + refdProp + "'", - range, expressionSeverity, ValidationType.expression.name()); + range, expressionSeverity, ValidationType.expression.name()); } } } @@ -268,6 +248,51 @@ private void validatePropertyValueExpressions(String propertyName, ItemMetadata } } + private Map> getAllPropertiesFromFiles(PropertiesModel current, + CancelChecker cancelChecker) { + if (allPropertiesFromFiles != null) { + return allPropertiesFromFiles; + } + Map> allPropertiesFromFiles = new HashMap<>(); + boolean fillWithCurrent = false; + Set configSources = projectInfo != null ? projectInfo.getConfigSources() : null; + if (configSources != null) { + for (ConfigSourceInfo configSource : configSources) { + checkCanceled(cancelChecker); + PropertiesModel document = propertiesModelProvider.getPropertiesModel(configSource.getUri()); + if (document != null) { + if (document == current) { + fillWithCurrent = true; + } + fill(document, allPropertiesFromFiles, cancelChecker); + } + } + } + if (!fillWithCurrent) { + fill(current, allPropertiesFromFiles, cancelChecker); + } + this.allPropertiesFromFiles = allPropertiesFromFiles; + return this.allPropertiesFromFiles; + } + + private void fill(PropertiesModel document, Map> allPropertiesFromFiles, + CancelChecker cancelChecker) { + List nodes = document.getChildren(); + for (Node node : nodes) { + checkCanceled(cancelChecker); + if (node.getNodeType() == NodeType.PROPERTY) { + Property property = (Property) node; + String propertyNameWithProfile = property.getPropertyNameWithProfile(); + if (!StringUtils.isEmpty(propertyNameWithProfile)) { + if (!allPropertiesFromFiles.containsKey(propertyNameWithProfile)) { + allPropertiesFromFiles.put(propertyNameWithProfile, new ArrayList()); + } + allPropertiesFromFiles.get(propertyNameWithProfile).add(property); + } + } + } + } + /** * Returns an error message only if value is an invalid enum for * the property defined by metadata @@ -278,7 +303,7 @@ private void validatePropertyValueExpressions(String propertyName, ItemMetadata * property defined by metadata */ private String getErrorIfInvalidEnum(ItemMetadata metadata, ConfigurationMetadata configuration, - PropertiesModel model, String value) { + PropertiesModel model, String value) { if (!PropertiesFileUtils.isValidEnum(metadata, configuration, value)) { return "Invalid enum value: '" + value + "' is invalid for type " + metadata.getType(); } @@ -311,14 +336,14 @@ private static String getErrorIfValueTypeMismatch(ItemMetadata metadata, String if (metadata.isBooleanType() && !isBooleanString(value)) { return "Type mismatch: " + metadata.getType() - + " expected. By default, this value will be interpreted as 'false'"; + + " expected. By default, this value will be interpreted as 'false'"; } if ((metadata.isIntegerType() && !isIntegerString(value) || (metadata.isFloatType() && !isFloatString(value)) - || (metadata.isDoubleType() && !isDoubleString(value)) || (metadata.isLongType() && !isLongString(value)) - || (metadata.isShortType() && !isShortString(value)) - || (metadata.isBigDecimalType() && !isBigDecimalString(value)) - || (metadata.isBigIntegerType() && !isBigIntegerString(value)))) { + || (metadata.isDoubleType() && !isDoubleString(value)) + || (metadata.isLongType() && !isLongString(value)) || (metadata.isShortType() && !isShortString(value)) + || (metadata.isBigDecimalType() && !isBigDecimalString(value)) + || (metadata.isBigIntegerType() && !isBigIntegerString(value)))) { return "Type mismatch: " + metadata.getType() + " expected"; } return null; @@ -330,7 +355,7 @@ private static boolean isBooleanString(String str) { } String strUpper = str.toUpperCase(); return "TRUE".equals(strUpper) || "FALSE".equals(strUpper) || "Y".equals(strUpper) || "YES".equals(strUpper) - || "1".equals(strUpper) || "ON".equals(strUpper); + || "1".equals(strUpper) || "ON".equals(strUpper); } private static boolean isIntegerString(String str) { @@ -421,8 +446,8 @@ private static boolean isBuildtimePlaceholder(String str) { return str.startsWith("${") && str.endsWith("}"); } - private void addDiagnosticsForDuplicates() { - existingProperties.forEach((propertyName, propertyList) -> { + private void addDiagnosticsForDuplicates(PropertiesModel document, CancelChecker cancelChecker) { + getAllPropertiesFromFiles(document, cancelChecker).forEach((propertyName, propertyList) -> { if (propertyList.size() <= 1) { return; } @@ -431,12 +456,12 @@ private void addDiagnosticsForDuplicates() { for (Property property : propertyList) { addDiagnostic("Duplicate property '" + propertyName + "'", property.getKey(), severity, - ValidationType.duplicate.name()); + ValidationType.duplicate.name()); } }); } - private void addDiagnosticsForMissingRequired(PropertiesModel document) { + private void addDiagnosticsForMissingRequired(PropertiesModel document, CancelChecker cancelChecker) { for (ItemMetadata property : projectInfo.getProperties()) { String propertyName = property.getName(); @@ -444,18 +469,19 @@ private void addDiagnosticsForMissingRequired(PropertiesModel document) { DiagnosticSeverity severity = validationSettings.getRequired().getDiagnosticSeverity(propertyName); if (severity != null && property.isRequired()) { - if (!existingProperties.containsKey(propertyName)) { + if (!getAllPropertiesFromFiles(document, cancelChecker).containsKey(propertyName)) { addDiagnostic("Missing required property '" + propertyName + "'", document, severity, - ValidationType.required.name()); + ValidationType.required.name()); } else { - addDiagnosticsForRequiredIfNoValue(propertyName, severity); + addDiagnosticsForRequiredIfNoValue(document, propertyName, severity, cancelChecker); } } } } - private void addDiagnosticsForRequiredIfNoValue(String propertyName, DiagnosticSeverity severity) { - List propertyList = existingProperties.get(propertyName); + private void addDiagnosticsForRequiredIfNoValue(PropertiesModel document, String propertyName, + DiagnosticSeverity severity, CancelChecker cancelChecker) { + List propertyList = getAllPropertiesFromFiles(document, cancelChecker).get(propertyName); for (Property property : propertyList) { if (property.getValue() != null && !property.getValue().getValue().isEmpty()) { @@ -465,7 +491,7 @@ private void addDiagnosticsForRequiredIfNoValue(String propertyName, DiagnosticS for (Property property : propertyList) { addDiagnostic("Missing required property value for '" + propertyName + "'", property, severity, - ValidationType.requiredValue.name()); + ValidationType.requiredValue.name()); } } @@ -482,4 +508,9 @@ public MicroProfileValidationSettings getValidationSettings() { return validationSettings; } + private void checkCanceled(CancelChecker cancelChecker) { + if (cancelChecker != null) { + cancelChecker.checkCanceled(); + } + } } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesInfoPropertiesProvider.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesInfoPropertiesProvider.java index a73aee773..0bc02533f 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesInfoPropertiesProvider.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/main/java/org/eclipse/lsp4mp/services/properties/PropertiesInfoPropertiesProvider.java @@ -13,17 +13,25 @@ *******************************************************************************/ package org.eclipse.lsp4mp.services.properties; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.eclipse.lsp4mp.commons.ConfigSourceInfo; +import org.eclipse.lsp4mp.commons.MicroProfileProjectInfo; import org.eclipse.lsp4mp.commons.metadata.ItemMetadata; +import org.eclipse.lsp4mp.commons.utils.ConfigSourcePropertiesProviderUtils; import org.eclipse.lsp4mp.commons.utils.IConfigSourcePropertiesProvider; +import org.eclipse.lsp4mp.commons.utils.PropertyValueExpander; import org.eclipse.lsp4mp.commons.utils.StringUtils; +import org.eclipse.lsp4mp.model.PropertiesModel; /** - * Adapts a list of ItemMetadata to IConfigSourcePropertiesProvider + * Adapts a list of ItemMetadata to + * IConfigSourcePropertiesProvider * * @author datho7561 */ @@ -38,8 +46,7 @@ public PropertiesInfoPropertiesProvider(List properties) { @Override public Set keys() { return properties.stream() // - .filter(item -> StringUtils.hasText(item.getDefaultValue())) - .map(item -> item.getName()) // + .filter(item -> StringUtils.hasText(item.getDefaultValue())).map(item -> item.getName()) // .filter(Objects::nonNull) // .collect(Collectors.toSet()); } @@ -70,4 +77,37 @@ public String getValue(String key) { return null; } + public static String resolveExpression(String propertyName, PropertiesModel document, + MicroProfileProjectInfo projectInfo, IPropertiesModelProvider propertiesModelProvider, + CancelChecker cancelChecker) { + IConfigSourcePropertiesProvider propertiesProvider = createConfigSourcePropertiesProvider(document, projectInfo, + propertiesModelProvider, cancelChecker); + List metadatas = projectInfo != null && projectInfo.getProperties() != null + ? projectInfo.getProperties() + : Collections.emptyList(); + propertiesProvider = ConfigSourcePropertiesProviderUtils.layer(propertiesProvider, + new PropertiesInfoPropertiesProvider(metadatas)); + PropertyValueExpander expander = new PropertyValueExpander(propertiesProvider); + return expander.getValue(propertyName); + } + + public static IConfigSourcePropertiesProvider createConfigSourcePropertiesProvider(PropertiesModel document, + MicroProfileProjectInfo projectInfo, IPropertiesModelProvider propertiesModelProvider, + CancelChecker cancelChecker) { + IConfigSourcePropertiesProvider propertiesProvider = document; + Set configSources = projectInfo != null && projectInfo.getConfigSources() != null + ? projectInfo.getConfigSources() + : Collections.emptySet(); + if (configSources != null) { + for (ConfigSourceInfo configSource : configSources) { + PropertiesModel model = propertiesModelProvider.getPropertiesModel(configSource.getUri()); + if (model != null && !model.equals(document)) { + cancelChecker.checkCanceled(); + propertiesProvider = ConfigSourcePropertiesProviderUtils.layer(propertiesProvider, model); + } + } + } + return propertiesProvider; + } + } \ No newline at end of file diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/properties/PropertiesFileAssert.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/properties/PropertiesFileAssert.java index 727c6ced8..ead563095 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/properties/PropertiesFileAssert.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/properties/PropertiesFileAssert.java @@ -188,7 +188,8 @@ public static void testCompletionFor(String value, boolean snippetSupport, boole formattingSettings.setSurroundEqualsWithSpaces(insertSpacing); PropertiesFileLanguageService languageService = new PropertiesFileLanguageService(); - CompletionList list = languageService.doComplete(model, position, projectInfo, + IPropertiesModelProvider propertiesModelProvider = documentURI -> model; + CompletionList list = languageService.doComplete(model, position, projectInfo, propertiesModelProvider, microProfileCompletionCapabilities, formattingSettings, () -> { }); @@ -371,9 +372,11 @@ public static void assertHover(String value, String fileURI, MicroProfileProject Position position = model.positionAt(offset); PropertiesFileLanguageService languageService = new PropertiesFileLanguageService(); + IPropertiesModelProvider propertiesModelProvider = documentURI -> model; - Hover hover = languageService.doHover(model, position, projectInfo, hoverSettings, () -> { - }); + Hover hover = languageService.doHover(model, position, projectInfo, propertiesModelProvider, hoverSettings, + () -> { + }); if (expectedHoverLabel == null) { Assert.assertNull(hover); } else { @@ -473,9 +476,10 @@ public static void testDefinitionFor(String value, String documentName, MicroPro PropertiesFileLanguageService languageService = new PropertiesFileLanguageService(); PropertiesModel document = parse(value, documentName); Position position = document.positionAt(offset); + IPropertiesModelProvider propertiesModelProvider = documentURI -> document; - Either, List> actual = languageService - .findDefinition(document, position, projectInfo, definitionProvider, true, NOOP_CHECKER).get(); + Either, List> actual = languageService.findDefinition(document, + position, projectInfo, propertiesModelProvider, definitionProvider, true, NOOP_CHECKER).get(); assertLocationLink(actual.getRight(), expected); } @@ -518,9 +522,11 @@ public static void testDiagnosticsFor(String value, String fileURI, Integer expe MicroProfileProjectInfo projectInfo, MicroProfileValidationSettings validationSettings, Diagnostic... expected) { PropertiesModel model = parse(value, fileURI); + IPropertiesModelProvider propertiesModelProvider = documentURI -> model; PropertiesFileLanguageService languageService = new PropertiesFileLanguageService(); - List actual = languageService.doDiagnostics(model, projectInfo, validationSettings, () -> { - }); + List actual = languageService.doDiagnostics(model, projectInfo, propertiesModelProvider, + validationSettings, () -> { + }); if (expectedCount != null) { assertEquals(expectedCount.intValue(), actual.size()); } @@ -738,8 +744,10 @@ public static void testInlayHintFor(String value, MicroProfileInlayHintSettings PropertiesModel model = parse(value, null); Range range = null; PropertiesFileLanguageService languageService = new PropertiesFileLanguageService(); - List actual = languageService.getInlayHint(model, projectInfo, range, () -> { - }); + IPropertiesModelProvider propertiesModelProvider = documentURI -> model; + List actual = languageService.getInlayHint(model, projectInfo, propertiesModelProvider, range, + () -> { + }); assertInlayHint(actual, expected); } diff --git a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/properties/PropertiesFileHoverTest.java b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/properties/PropertiesFileHoverTest.java index bb399f524..59b9ea476 100644 --- a/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/properties/PropertiesFileHoverTest.java +++ b/microprofile.ls/org.eclipse.lsp4mp.ls/src/test/java/org/eclipse/lsp4mp/services/properties/PropertiesFileHoverTest.java @@ -12,7 +12,6 @@ import static org.eclipse.lsp4mp.services.properties.PropertiesFileAssert.assertHoverMarkdown; import static org.eclipse.lsp4mp.services.properties.PropertiesFileAssert.assertHoverPlaintext; -import static org.eclipse.lsp4mp.services.properties.PropertiesFileAssert.assertNoHover; import org.eclipse.lsp4mp.ls.commons.BadLocationException; import org.junit.Test;