From 7b21327d309a7e60a178e9b4d3368d6e9610dc6e Mon Sep 17 00:00:00 2001 From: Nikita Fedkin Date: Thu, 25 Apr 2024 08:13:36 +0200 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20=D1=81?= =?UTF-8?q?=20=D1=85=D0=BE=D0=B2=D0=B5=D1=80=D0=BE=D0=BC=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=B0=20=D0=BD=D0=B0?= =?UTF-8?q?=20reference-api.=20=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD?= =?UTF-8?q?=D0=BE=D0=B5=20NPE=20=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B8=20=D1=82=D0=B8=D0=BF=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=81=D0=B8=D0=BC=D0=B2=D0=BE=D0=BB=D1=83.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hover/MarkupContentBuilder.java | 6 ++-- .../MethodSymbolMarkupContentBuilder.java | 3 +- .../VariableSymbolMarkupContentBuilder.java | 5 +-- .../providers/HoverProvider.java | 2 +- .../languageserver/types/TypeResolver.java | 28 +++++++++++----- .../MethodSymbolMarkupContentBuilderTest.java | 22 +++++++++++-- ...ariableSymbolMarkupContentBuilderTest.java | 28 +++++++++++++--- .../types/TypeResolverTest.java | 32 +++++++++++++++---- 8 files changed, 98 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MarkupContentBuilder.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MarkupContentBuilder.java index 8ef2864767f..d63624dfa84 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MarkupContentBuilder.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MarkupContentBuilder.java @@ -22,6 +22,7 @@ package com.github._1c_syntax.bsl.languageserver.hover; import com.github._1c_syntax.bsl.languageserver.context.symbol.Symbol; +import com.github._1c_syntax.bsl.languageserver.references.model.Reference; import org.eclipse.lsp4j.MarkupContent; import org.eclipse.lsp4j.SymbolKind; @@ -34,10 +35,11 @@ public interface MarkupContentBuilder { /** * Возвращает контент для всплывающего окна на основе символа. * - * @param symbol Символ, для которого нужно построить контент. + * @param reference Ссылка на символ, для которого нужно построить контент. + * @param symbol Символ с приведенным типом, для которого нужно построить контент. * @return Сконструированный контент. */ - MarkupContent getContent(T symbol); + MarkupContent getContent(Reference reference, T symbol); /** * Тип символа, на основе которого работает данный построитель. diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilder.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilder.java index de16d79d37f..f41e4c6eaec 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilder.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilder.java @@ -27,6 +27,7 @@ import com.github._1c_syntax.bsl.languageserver.context.symbol.description.MethodDescription; import com.github._1c_syntax.bsl.languageserver.context.symbol.description.ParameterDescription; import com.github._1c_syntax.bsl.languageserver.context.symbol.description.TypeDescription; +import com.github._1c_syntax.bsl.languageserver.references.model.Reference; import com.github._1c_syntax.bsl.languageserver.utils.MdoRefBuilder; import com.github._1c_syntax.bsl.languageserver.utils.Resources; import lombok.RequiredArgsConstructor; @@ -63,7 +64,7 @@ public class MethodSymbolMarkupContentBuilder implements MarkupContentBuilder addSectionIfNotEmpty(markupBuilder, trailingDescription)); - var types = typeResolver.findTypes(symbol); + var types = typeResolver.findTypes(reference); var typeDescription = getTypeDescription(types); addSectionIfNotEmpty(markupBuilder, typeDescription); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/HoverProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/HoverProvider.java index 2d180202559..cc11646e0d9 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/HoverProvider.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/HoverProvider.java @@ -52,7 +52,7 @@ public Optional getHover(DocumentContext documentContext, HoverParams par var range = reference.getSelectionRange(); return Optional.ofNullable(markupContentBuilders.get(symbol.getSymbolKind())) - .map(markupContentBuilder -> markupContentBuilder.getContent(symbol)) + .map(markupContentBuilder -> markupContentBuilder.getContent(reference, symbol)) .map(content -> new Hover(content, range)); }); } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolver.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolver.java index 18d99905174..a0bfe99bc95 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolver.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolver.java @@ -24,6 +24,7 @@ import com.github._1c_syntax.bsl.languageserver.context.ServerContext; import com.github._1c_syntax.bsl.languageserver.context.symbol.Describable; import com.github._1c_syntax.bsl.languageserver.context.symbol.SourceDefinedSymbol; +import com.github._1c_syntax.bsl.languageserver.context.symbol.Symbol; import com.github._1c_syntax.bsl.languageserver.context.symbol.description.MethodDescription; import com.github._1c_syntax.bsl.languageserver.context.symbol.description.TypeDescription; import com.github._1c_syntax.bsl.languageserver.context.symbol.variable.VariableDescription; @@ -58,20 +59,26 @@ public class TypeResolver { // TODO: Create LRU cache for calculated types. - // TODO: Use reference instead of symbol. Refactor hover provider to pass references to markup content builders. - public List findTypes(SourceDefinedSymbol symbol) { - return calculateTypes(symbol); + public List findTypes(Reference reference) { + return calculateTypes(reference.getUri(), reference.getSymbol()); } public List findTypes(URI uri, Position position) { return referenceResolver.findReference(uri, position) .stream() - .flatMap(reference -> calculateTypes(uri, reference).stream()) + .flatMap(reference -> calculateTypes(reference).stream()) .distinct() .toList(); } - private List calculateTypes(SourceDefinedSymbol symbol) { + private List calculateTypes(URI uri, Symbol symbol) { + if (symbol instanceof SourceDefinedSymbol sourceDefinedSymbol) { + return calculateTypes(uri, sourceDefinedSymbol); + } + return Collections.emptyList(); + } + + private List calculateTypes(URI uri, SourceDefinedSymbol symbol) { // variable description resolver if (symbol instanceof Describable describableSymbol) { @@ -94,7 +101,9 @@ private List calculateTypes(SourceDefinedSymbol symbol) { } // reference-based type resolver - var uri = symbol.getOwner().getUri(); + if (symbol.getOwner().getContent() == null) { + return Collections.emptyList(); + } var ast = symbol.getOwner().getAst(); if (ast == null) { return Collections.emptyList(); @@ -115,13 +124,16 @@ private List calculateTypes(SourceDefinedSymbol symbol) { .toList(); } - private List calculateTypes(URI uri, Reference reference) { + private List calculateTypes(Reference reference) { + + var uri = reference.getUri(); // source defined symbol resolver if (reference.isSourceDefinedSymbolReference()) { - return calculateTypes(reference.getSourceDefinedSymbol().orElseThrow()); + return calculateTypes(uri, reference.getSourceDefinedSymbol().orElseThrow()); } + // expression tree resolver if (reference.getOccurrenceType() == OccurrenceType.DEFINITION) { var document = serverContext.getDocument(uri); diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilderTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilderTest.java index da295eb3092..c1902954090 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilderTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilderTest.java @@ -21,11 +21,16 @@ */ package com.github._1c_syntax.bsl.languageserver.hover; +import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; import com.github._1c_syntax.bsl.languageserver.context.ServerContext; +import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol; +import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType; +import com.github._1c_syntax.bsl.languageserver.references.model.Reference; import com.github._1c_syntax.bsl.languageserver.util.CleanupContextBeforeClassAndAfterClass; import com.github._1c_syntax.bsl.languageserver.util.TestUtils; import com.github._1c_syntax.bsl.types.ModuleType; import jakarta.annotation.PostConstruct; +import org.eclipse.lsp4j.Location; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -59,9 +64,10 @@ void testContentFromDirectFile() { // given var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE); var methodSymbol = documentContext.getSymbolTree().getMethodSymbol("ИмяФункции").orElseThrow(); + var reference = getReference(documentContext, methodSymbol); // when - var content = markupContentBuilder.getContent(methodSymbol).getValue(); + var content = markupContentBuilder.getContent(reference, methodSymbol).getValue(); assertThat(content).isNotEmpty(); @@ -122,9 +128,10 @@ void testContentFromManagerModule() { // given var documentContext = serverContext.getDocument("Catalog.Справочник1", ModuleType.ManagerModule).orElseThrow(); var methodSymbol = documentContext.getSymbolTree().getMethodSymbol("ТестЭкспортная").orElseThrow(); + var reference = getReference(documentContext, methodSymbol); // when - var content = markupContentBuilder.getContent(methodSymbol).getValue(); + var content = markupContentBuilder.getContent(reference, methodSymbol).getValue(); // then assertThat(content).isNotEmpty(); @@ -146,9 +153,10 @@ void testMethodsFromCommonModule() { // given var documentContext = serverContext.getDocument("CommonModule.ПервыйОбщийМодуль", ModuleType.CommonModule).orElseThrow(); var methodSymbol = documentContext.getSymbolTree().getMethodSymbol("УстаревшаяПроцедура").orElseThrow(); + var reference = getReference(documentContext, methodSymbol); // when - var content = markupContentBuilder.getContent(methodSymbol).getValue(); + var content = markupContentBuilder.getContent(reference, methodSymbol).getValue(); // then assertThat(content).isNotEmpty(); @@ -166,4 +174,12 @@ void testMethodsFromCommonModule() { assertThat(blocks.get(2)).isEqualTo("Процедура - Устаревшая процедура\n\n"); } + private static Reference getReference(DocumentContext documentContext, MethodSymbol methodSymbol) { + return Reference.of( + documentContext.getSymbolTree().getModule(), + methodSymbol, + new Location(documentContext.getUri().toString(), methodSymbol.getSelectionRange()), + OccurrenceType.DEFINITION + ); + } } \ No newline at end of file diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/VariableSymbolMarkupContentBuilderTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/VariableSymbolMarkupContentBuilderTest.java index b8ade4cb595..4f501ddb472 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/VariableSymbolMarkupContentBuilderTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/VariableSymbolMarkupContentBuilderTest.java @@ -21,11 +21,16 @@ */ package com.github._1c_syntax.bsl.languageserver.hover; +import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; import com.github._1c_syntax.bsl.languageserver.context.ServerContext; +import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol; +import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType; +import com.github._1c_syntax.bsl.languageserver.references.model.Reference; import com.github._1c_syntax.bsl.languageserver.util.CleanupContextBeforeClassAndAfterClass; import com.github._1c_syntax.bsl.languageserver.util.TestUtils; import com.github._1c_syntax.bsl.types.ModuleType; import jakarta.annotation.PostConstruct; +import org.eclipse.lsp4j.Location; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -60,9 +65,10 @@ void testFileVarContentFromDirectFile_NoComments() { var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE); final var symbolTree = documentContext.getSymbolTree(); var varSymbol = symbolTree.getVariableSymbol("ИмяБезОписания", symbolTree.getModule()).orElseThrow(); + var reference = getReference(documentContext, varSymbol); // when - var content = markupContentBuilder.getContent(varSymbol).getValue(); + var content = markupContentBuilder.getContent(reference, varSymbol).getValue(); assertThat(content).isNotEmpty(); @@ -87,9 +93,10 @@ void testFileVarContentFromDirectFile_OneCommentsStringFromRight() { var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE); final var symbolTree = documentContext.getSymbolTree(); var varSymbol = symbolTree.getVariableSymbol("Имя_ОписаниеСправаОднойСтрокой", symbolTree.getModule()).orElseThrow(); + var reference = getReference(documentContext, varSymbol); // when - var content = markupContentBuilder.getContent(varSymbol).getValue(); + var content = markupContentBuilder.getContent(reference, varSymbol).getValue(); assertThat(content).isNotEmpty(); @@ -119,9 +126,10 @@ void testMethodVarContentFromDirectFile_2_comments_strings() { final var symbolTree = documentContext.getSymbolTree(); var methodSymbol = symbolTree.getMethodSymbol("ИмяФункции").orElseThrow(); var varSymbol = symbolTree.getVariableSymbol("Имя_ОписаниеСверхуДвеСтроки_Функция", methodSymbol).orElseThrow(); + var reference = getReference(documentContext, varSymbol); // when - var content = markupContentBuilder.getContent(varSymbol).getValue(); + var content = markupContentBuilder.getContent(reference, varSymbol).getValue(); assertThat(content).isNotEmpty(); @@ -153,9 +161,10 @@ void testMethodVarContentFromDirectFile_3_comments_strings() { final var symbolTree = documentContext.getSymbolTree(); var methodSymbol = symbolTree.getMethodSymbol("ИмяФункции").orElseThrow(); var varSymbol = symbolTree.getVariableSymbol("Имя_ОписаниеСверхуТриСтрокиПоследняяПустая_Функция", methodSymbol).orElseThrow(); + var reference = getReference(documentContext, varSymbol); // when - var content = markupContentBuilder.getContent(varSymbol).getValue(); + var content = markupContentBuilder.getContent(reference, varSymbol).getValue(); assertThat(content).isNotEmpty(); @@ -186,9 +195,10 @@ void testContentFromObjectModule() { var documentContext = serverContext.getDocument("Catalog.Справочник1", ModuleType.ObjectModule).orElseThrow(); final var symbolTree = documentContext.getSymbolTree(); var varSymbol = symbolTree.getVariableSymbol("ВалютаУчета", symbolTree.getModule()).orElseThrow(); + var reference = getReference(documentContext, varSymbol); // when - var content = markupContentBuilder.getContent(varSymbol).getValue(); + var content = markupContentBuilder.getContent(reference, varSymbol).getValue(); // then assertThat(content).isNotEmpty(); @@ -205,4 +215,12 @@ void testContentFromObjectModule() { assertThat(blocks.get(1)).matches("\\[Catalog.Справочник1]\\(.*Catalogs/.*/Ext/ObjectModule.bsl#\\d+\\)\n\n"); } + private static Reference getReference(DocumentContext documentContext, VariableSymbol variableSymbol) { + return Reference.of( + documentContext.getSymbolTree().getModule(), + variableSymbol, + new Location(documentContext.getUri().toString(), variableSymbol.getSelectionRange()), + OccurrenceType.DEFINITION + ); + } } diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolverTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolverTest.java index 8d0c0f0519f..bb4c8617e8c 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolverTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolverTest.java @@ -21,7 +21,12 @@ */ package com.github._1c_syntax.bsl.languageserver.types; +import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; +import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol; +import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType; +import com.github._1c_syntax.bsl.languageserver.references.model.Reference; import com.github._1c_syntax.bsl.languageserver.util.TestUtils; +import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Position; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -35,6 +40,8 @@ class TypeResolverTest { @Autowired private TypeResolver typeResolver; + public static final String PATH_TO_FILE = "./src/test/resources/types/TypeResolver.os"; + @Test void simpleType() { // given @@ -76,9 +83,10 @@ void twoTypesFromSymbol() { // given var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os"); var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("ДваТипа", documentContext.getSymbolTree().getModule()).orElseThrow(); + var reference = getReference(documentContext, variableSymbol); // when - var types = typeResolver.findTypes(variableSymbol); + var types = typeResolver.findTypes(reference); // then assertThat(types).hasSize(2); @@ -89,9 +97,10 @@ void twoAssignments() { // given var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os"); var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("Переприсваивание", documentContext.getSymbolTree().getModule()).orElseThrow(); + var reference = getReference(documentContext, variableSymbol); // when - var types = typeResolver.findTypes(variableSymbol); + var types = typeResolver.findTypes(reference); // then assertThat(types).hasSize(1); @@ -102,9 +111,10 @@ void newArray() { // given var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os"); var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("ДругоеИмяМассива", documentContext.getSymbolTree().getModule()).orElseThrow(); + var reference = getReference(documentContext, variableSymbol); // when - var types = typeResolver.findTypes(variableSymbol); + var types = typeResolver.findTypes(reference); // then assertThat(types).hasSize(1); @@ -116,9 +126,10 @@ void globalMethodCall() { // given var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os"); var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("РезультатФункции", documentContext.getSymbolTree().getModule()).orElseThrow(); + var reference = getReference(documentContext, variableSymbol); // when - var types = typeResolver.findTypes(variableSymbol); + var types = typeResolver.findTypes(reference); // then assertThat(types).hasSize(1); @@ -128,15 +139,24 @@ void globalMethodCall() { @Test void varWithDescription() { // given - var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os"); + var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE); var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("ПеременнаяСОписанием", documentContext.getSymbolTree().getModule()).orElseThrow(); + var reference = getReference(documentContext, variableSymbol); // when - var types = typeResolver.findTypes(variableSymbol); + var types = typeResolver.findTypes(reference); // then assertThat(types).hasSize(1); assertThat(types.get(0).getName()).isEqualTo("Строка"); } + private static Reference getReference(DocumentContext documentContext, VariableSymbol variableSymbol) { + return Reference.of( + documentContext.getSymbolTree().getModule(), + variableSymbol, + new Location(documentContext.getUri().toString(), variableSymbol.getSelectionRange()), + OccurrenceType.DEFINITION + ); + } } \ No newline at end of file