Skip to content

Commit 7b21327

Browse files
committed
Работа с ховером переведена на reference-api. Исправлено возможное NPE на получении типа по символу.
1 parent 872b84e commit 7b21327

File tree

8 files changed

+98
-28
lines changed

8 files changed

+98
-28
lines changed

src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MarkupContentBuilder.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package com.github._1c_syntax.bsl.languageserver.hover;
2323

2424
import com.github._1c_syntax.bsl.languageserver.context.symbol.Symbol;
25+
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
2526
import org.eclipse.lsp4j.MarkupContent;
2627
import org.eclipse.lsp4j.SymbolKind;
2728

@@ -34,10 +35,11 @@ public interface MarkupContentBuilder<T extends Symbol> {
3435
/**
3536
* Возвращает контент для всплывающего окна на основе символа.
3637
*
37-
* @param symbol Символ, для которого нужно построить контент.
38+
* @param reference Ссылка на символ, для которого нужно построить контент.
39+
* @param symbol Символ с приведенным типом, для которого нужно построить контент.
3840
* @return Сконструированный контент.
3941
*/
40-
MarkupContent getContent(T symbol);
42+
MarkupContent getContent(Reference reference, T symbol);
4143

4244
/**
4345
* Тип символа, на основе которого работает данный построитель.

src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.github._1c_syntax.bsl.languageserver.context.symbol.description.MethodDescription;
2828
import com.github._1c_syntax.bsl.languageserver.context.symbol.description.ParameterDescription;
2929
import com.github._1c_syntax.bsl.languageserver.context.symbol.description.TypeDescription;
30+
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
3031
import com.github._1c_syntax.bsl.languageserver.utils.MdoRefBuilder;
3132
import com.github._1c_syntax.bsl.languageserver.utils.Resources;
3233
import lombok.RequiredArgsConstructor;
@@ -63,7 +64,7 @@ public class MethodSymbolMarkupContentBuilder implements MarkupContentBuilder<Me
6364
private final LanguageServerConfiguration configuration;
6465

6566
@Override
66-
public MarkupContent getContent(MethodSymbol symbol) {
67+
public MarkupContent getContent(Reference reference, MethodSymbol symbol) {
6768
var markupBuilder = new StringJoiner("\n");
6869

6970
// сигнатура

src/main/java/com/github/_1c_syntax/bsl/languageserver/hover/VariableSymbolMarkupContentBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
2525
import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol;
2626
import com.github._1c_syntax.bsl.languageserver.context.symbol.variable.VariableDescription;
27+
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
2728
import com.github._1c_syntax.bsl.languageserver.types.Type;
2829
import com.github._1c_syntax.bsl.languageserver.types.TypeResolver;
2930
import com.github._1c_syntax.bsl.languageserver.utils.MdoRefBuilder;
@@ -49,7 +50,7 @@ public class VariableSymbolMarkupContentBuilder implements MarkupContentBuilder<
4950
private final LanguageServerConfiguration configuration;
5051

5152
@Override
52-
public MarkupContent getContent(VariableSymbol symbol) {
53+
public MarkupContent getContent(Reference reference, VariableSymbol symbol) {
5354
var markupBuilder = new StringJoiner("\n");
5455

5556
// сигнатура
@@ -74,7 +75,7 @@ public MarkupContent getContent(VariableSymbol symbol) {
7475
.map(VariableDescription::getPurposeDescription)
7576
.ifPresent(trailingDescription -> addSectionIfNotEmpty(markupBuilder, trailingDescription));
7677

77-
var types = typeResolver.findTypes(symbol);
78+
var types = typeResolver.findTypes(reference);
7879
var typeDescription = getTypeDescription(types);
7980
addSectionIfNotEmpty(markupBuilder, typeDescription);
8081

src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/HoverProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public Optional<Hover> getHover(DocumentContext documentContext, HoverParams par
5252
var range = reference.getSelectionRange();
5353

5454
return Optional.ofNullable(markupContentBuilders.get(symbol.getSymbolKind()))
55-
.map(markupContentBuilder -> markupContentBuilder.getContent(symbol))
55+
.map(markupContentBuilder -> markupContentBuilder.getContent(reference, symbol))
5656
.map(content -> new Hover(content, range));
5757
});
5858
}

src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolver.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.github._1c_syntax.bsl.languageserver.context.ServerContext;
2525
import com.github._1c_syntax.bsl.languageserver.context.symbol.Describable;
2626
import com.github._1c_syntax.bsl.languageserver.context.symbol.SourceDefinedSymbol;
27+
import com.github._1c_syntax.bsl.languageserver.context.symbol.Symbol;
2728
import com.github._1c_syntax.bsl.languageserver.context.symbol.description.MethodDescription;
2829
import com.github._1c_syntax.bsl.languageserver.context.symbol.description.TypeDescription;
2930
import com.github._1c_syntax.bsl.languageserver.context.symbol.variable.VariableDescription;
@@ -58,20 +59,26 @@ public class TypeResolver {
5859

5960
// TODO: Create LRU cache for calculated types.
6061

61-
// TODO: Use reference instead of symbol. Refactor hover provider to pass references to markup content builders.
62-
public List<Type> findTypes(SourceDefinedSymbol symbol) {
63-
return calculateTypes(symbol);
62+
public List<Type> findTypes(Reference reference) {
63+
return calculateTypes(reference.getUri(), reference.getSymbol());
6464
}
6565

6666
public List<Type> findTypes(URI uri, Position position) {
6767
return referenceResolver.findReference(uri, position)
6868
.stream()
69-
.flatMap(reference -> calculateTypes(uri, reference).stream())
69+
.flatMap(reference -> calculateTypes(reference).stream())
7070
.distinct()
7171
.toList();
7272
}
7373

74-
private List<Type> calculateTypes(SourceDefinedSymbol symbol) {
74+
private List<Type> calculateTypes(URI uri, Symbol symbol) {
75+
if (symbol instanceof SourceDefinedSymbol sourceDefinedSymbol) {
76+
return calculateTypes(uri, sourceDefinedSymbol);
77+
}
78+
return Collections.emptyList();
79+
}
80+
81+
private List<Type> calculateTypes(URI uri, SourceDefinedSymbol symbol) {
7582

7683
// variable description resolver
7784
if (symbol instanceof Describable describableSymbol) {
@@ -94,7 +101,9 @@ private List<Type> calculateTypes(SourceDefinedSymbol symbol) {
94101
}
95102

96103
// reference-based type resolver
97-
var uri = symbol.getOwner().getUri();
104+
if (symbol.getOwner().getContent() == null) {
105+
return Collections.emptyList();
106+
}
98107
var ast = symbol.getOwner().getAst();
99108
if (ast == null) {
100109
return Collections.emptyList();
@@ -115,13 +124,16 @@ private List<Type> calculateTypes(SourceDefinedSymbol symbol) {
115124
.toList();
116125
}
117126

118-
private List<Type> calculateTypes(URI uri, Reference reference) {
127+
private List<Type> calculateTypes(Reference reference) {
128+
129+
var uri = reference.getUri();
119130

120131
// source defined symbol resolver
121132
if (reference.isSourceDefinedSymbolReference()) {
122-
return calculateTypes(reference.getSourceDefinedSymbol().orElseThrow());
133+
return calculateTypes(uri, reference.getSourceDefinedSymbol().orElseThrow());
123134
}
124135

136+
125137
// expression tree resolver
126138
if (reference.getOccurrenceType() == OccurrenceType.DEFINITION) {
127139
var document = serverContext.getDocument(uri);

src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/MethodSymbolMarkupContentBuilderTest.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@
2121
*/
2222
package com.github._1c_syntax.bsl.languageserver.hover;
2323

24+
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
2425
import com.github._1c_syntax.bsl.languageserver.context.ServerContext;
26+
import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
27+
import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType;
28+
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
2529
import com.github._1c_syntax.bsl.languageserver.util.CleanupContextBeforeClassAndAfterClass;
2630
import com.github._1c_syntax.bsl.languageserver.util.TestUtils;
2731
import com.github._1c_syntax.bsl.types.ModuleType;
2832
import jakarta.annotation.PostConstruct;
33+
import org.eclipse.lsp4j.Location;
2934
import org.junit.jupiter.api.Test;
3035
import org.springframework.beans.factory.annotation.Autowired;
3136
import org.springframework.boot.test.context.SpringBootTest;
@@ -59,9 +64,10 @@ void testContentFromDirectFile() {
5964
// given
6065
var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE);
6166
var methodSymbol = documentContext.getSymbolTree().getMethodSymbol("ИмяФункции").orElseThrow();
67+
var reference = getReference(documentContext, methodSymbol);
6268

6369
// when
64-
var content = markupContentBuilder.getContent(methodSymbol).getValue();
70+
var content = markupContentBuilder.getContent(reference, methodSymbol).getValue();
6571

6672
assertThat(content).isNotEmpty();
6773

@@ -122,9 +128,10 @@ void testContentFromManagerModule() {
122128
// given
123129
var documentContext = serverContext.getDocument("Catalog.Справочник1", ModuleType.ManagerModule).orElseThrow();
124130
var methodSymbol = documentContext.getSymbolTree().getMethodSymbol("ТестЭкспортная").orElseThrow();
131+
var reference = getReference(documentContext, methodSymbol);
125132

126133
// when
127-
var content = markupContentBuilder.getContent(methodSymbol).getValue();
134+
var content = markupContentBuilder.getContent(reference, methodSymbol).getValue();
128135

129136
// then
130137
assertThat(content).isNotEmpty();
@@ -146,9 +153,10 @@ void testMethodsFromCommonModule() {
146153
// given
147154
var documentContext = serverContext.getDocument("CommonModule.ПервыйОбщийМодуль", ModuleType.CommonModule).orElseThrow();
148155
var methodSymbol = documentContext.getSymbolTree().getMethodSymbol("УстаревшаяПроцедура").orElseThrow();
156+
var reference = getReference(documentContext, methodSymbol);
149157

150158
// when
151-
var content = markupContentBuilder.getContent(methodSymbol).getValue();
159+
var content = markupContentBuilder.getContent(reference, methodSymbol).getValue();
152160

153161
// then
154162
assertThat(content).isNotEmpty();
@@ -166,4 +174,12 @@ void testMethodsFromCommonModule() {
166174
assertThat(blocks.get(2)).isEqualTo("Процедура - Устаревшая процедура\n\n");
167175
}
168176

177+
private static Reference getReference(DocumentContext documentContext, MethodSymbol methodSymbol) {
178+
return Reference.of(
179+
documentContext.getSymbolTree().getModule(),
180+
methodSymbol,
181+
new Location(documentContext.getUri().toString(), methodSymbol.getSelectionRange()),
182+
OccurrenceType.DEFINITION
183+
);
184+
}
169185
}

src/test/java/com/github/_1c_syntax/bsl/languageserver/hover/VariableSymbolMarkupContentBuilderTest.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@
2121
*/
2222
package com.github._1c_syntax.bsl.languageserver.hover;
2323

24+
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
2425
import com.github._1c_syntax.bsl.languageserver.context.ServerContext;
26+
import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol;
27+
import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType;
28+
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
2529
import com.github._1c_syntax.bsl.languageserver.util.CleanupContextBeforeClassAndAfterClass;
2630
import com.github._1c_syntax.bsl.languageserver.util.TestUtils;
2731
import com.github._1c_syntax.bsl.types.ModuleType;
2832
import jakarta.annotation.PostConstruct;
33+
import org.eclipse.lsp4j.Location;
2934
import org.junit.jupiter.api.Test;
3035
import org.springframework.beans.factory.annotation.Autowired;
3136
import org.springframework.boot.test.context.SpringBootTest;
@@ -60,9 +65,10 @@ void testFileVarContentFromDirectFile_NoComments() {
6065
var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE);
6166
final var symbolTree = documentContext.getSymbolTree();
6267
var varSymbol = symbolTree.getVariableSymbol("ИмяБезОписания", symbolTree.getModule()).orElseThrow();
68+
var reference = getReference(documentContext, varSymbol);
6369

6470
// when
65-
var content = markupContentBuilder.getContent(varSymbol).getValue();
71+
var content = markupContentBuilder.getContent(reference, varSymbol).getValue();
6672

6773
assertThat(content).isNotEmpty();
6874

@@ -87,9 +93,10 @@ void testFileVarContentFromDirectFile_OneCommentsStringFromRight() {
8793
var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE);
8894
final var symbolTree = documentContext.getSymbolTree();
8995
var varSymbol = symbolTree.getVariableSymbol("Имя_ОписаниеСправаОднойСтрокой", symbolTree.getModule()).orElseThrow();
96+
var reference = getReference(documentContext, varSymbol);
9097

9198
// when
92-
var content = markupContentBuilder.getContent(varSymbol).getValue();
99+
var content = markupContentBuilder.getContent(reference, varSymbol).getValue();
93100

94101
assertThat(content).isNotEmpty();
95102

@@ -119,9 +126,10 @@ void testMethodVarContentFromDirectFile_2_comments_strings() {
119126
final var symbolTree = documentContext.getSymbolTree();
120127
var methodSymbol = symbolTree.getMethodSymbol("ИмяФункции").orElseThrow();
121128
var varSymbol = symbolTree.getVariableSymbol("Имя_ОписаниеСверхуДвеСтроки_Функция", methodSymbol).orElseThrow();
129+
var reference = getReference(documentContext, varSymbol);
122130

123131
// when
124-
var content = markupContentBuilder.getContent(varSymbol).getValue();
132+
var content = markupContentBuilder.getContent(reference, varSymbol).getValue();
125133

126134
assertThat(content).isNotEmpty();
127135

@@ -153,9 +161,10 @@ void testMethodVarContentFromDirectFile_3_comments_strings() {
153161
final var symbolTree = documentContext.getSymbolTree();
154162
var methodSymbol = symbolTree.getMethodSymbol("ИмяФункции").orElseThrow();
155163
var varSymbol = symbolTree.getVariableSymbol("Имя_ОписаниеСверхуТриСтрокиПоследняяПустая_Функция", methodSymbol).orElseThrow();
164+
var reference = getReference(documentContext, varSymbol);
156165

157166
// when
158-
var content = markupContentBuilder.getContent(varSymbol).getValue();
167+
var content = markupContentBuilder.getContent(reference, varSymbol).getValue();
159168

160169
assertThat(content).isNotEmpty();
161170

@@ -186,9 +195,10 @@ void testContentFromObjectModule() {
186195
var documentContext = serverContext.getDocument("Catalog.Справочник1", ModuleType.ObjectModule).orElseThrow();
187196
final var symbolTree = documentContext.getSymbolTree();
188197
var varSymbol = symbolTree.getVariableSymbol("ВалютаУчета", symbolTree.getModule()).orElseThrow();
198+
var reference = getReference(documentContext, varSymbol);
189199

190200
// when
191-
var content = markupContentBuilder.getContent(varSymbol).getValue();
201+
var content = markupContentBuilder.getContent(reference, varSymbol).getValue();
192202

193203
// then
194204
assertThat(content).isNotEmpty();
@@ -205,4 +215,12 @@ void testContentFromObjectModule() {
205215
assertThat(blocks.get(1)).matches("\\[Catalog.Справочник1]\\(.*Catalogs/.*/Ext/ObjectModule.bsl#\\d+\\)\n\n");
206216
}
207217

218+
private static Reference getReference(DocumentContext documentContext, VariableSymbol variableSymbol) {
219+
return Reference.of(
220+
documentContext.getSymbolTree().getModule(),
221+
variableSymbol,
222+
new Location(documentContext.getUri().toString(), variableSymbol.getSelectionRange()),
223+
OccurrenceType.DEFINITION
224+
);
225+
}
208226
}

src/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolverTest.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@
2121
*/
2222
package com.github._1c_syntax.bsl.languageserver.types;
2323

24+
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
25+
import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol;
26+
import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType;
27+
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
2428
import com.github._1c_syntax.bsl.languageserver.util.TestUtils;
29+
import org.eclipse.lsp4j.Location;
2530
import org.eclipse.lsp4j.Position;
2631
import org.junit.jupiter.api.Test;
2732
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,6 +40,8 @@ class TypeResolverTest {
3540
@Autowired
3641
private TypeResolver typeResolver;
3742

43+
public static final String PATH_TO_FILE = "./src/test/resources/types/TypeResolver.os";
44+
3845
@Test
3946
void simpleType() {
4047
// given
@@ -76,9 +83,10 @@ void twoTypesFromSymbol() {
7683
// given
7784
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
7885
var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("ДваТипа", documentContext.getSymbolTree().getModule()).orElseThrow();
86+
var reference = getReference(documentContext, variableSymbol);
7987

8088
// when
81-
var types = typeResolver.findTypes(variableSymbol);
89+
var types = typeResolver.findTypes(reference);
8290

8391
// then
8492
assertThat(types).hasSize(2);
@@ -89,9 +97,10 @@ void twoAssignments() {
8997
// given
9098
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
9199
var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("Переприсваивание", documentContext.getSymbolTree().getModule()).orElseThrow();
100+
var reference = getReference(documentContext, variableSymbol);
92101

93102
// when
94-
var types = typeResolver.findTypes(variableSymbol);
103+
var types = typeResolver.findTypes(reference);
95104

96105
// then
97106
assertThat(types).hasSize(1);
@@ -102,9 +111,10 @@ void newArray() {
102111
// given
103112
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
104113
var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("ДругоеИмяМассива", documentContext.getSymbolTree().getModule()).orElseThrow();
114+
var reference = getReference(documentContext, variableSymbol);
105115

106116
// when
107-
var types = typeResolver.findTypes(variableSymbol);
117+
var types = typeResolver.findTypes(reference);
108118

109119
// then
110120
assertThat(types).hasSize(1);
@@ -116,9 +126,10 @@ void globalMethodCall() {
116126
// given
117127
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
118128
var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("РезультатФункции", documentContext.getSymbolTree().getModule()).orElseThrow();
129+
var reference = getReference(documentContext, variableSymbol);
119130

120131
// when
121-
var types = typeResolver.findTypes(variableSymbol);
132+
var types = typeResolver.findTypes(reference);
122133

123134
// then
124135
assertThat(types).hasSize(1);
@@ -128,15 +139,24 @@ void globalMethodCall() {
128139
@Test
129140
void varWithDescription() {
130141
// given
131-
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
142+
var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE);
132143
var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("ПеременнаяСОписанием", documentContext.getSymbolTree().getModule()).orElseThrow();
144+
var reference = getReference(documentContext, variableSymbol);
133145

134146
// when
135-
var types = typeResolver.findTypes(variableSymbol);
147+
var types = typeResolver.findTypes(reference);
136148

137149
// then
138150
assertThat(types).hasSize(1);
139151
assertThat(types.get(0).getName()).isEqualTo("Строка");
140152
}
141153

154+
private static Reference getReference(DocumentContext documentContext, VariableSymbol variableSymbol) {
155+
return Reference.of(
156+
documentContext.getSymbolTree().getModule(),
157+
variableSymbol,
158+
new Location(documentContext.getUri().toString(), variableSymbol.getSelectionRange()),
159+
OccurrenceType.DEFINITION
160+
);
161+
}
142162
}

0 commit comments

Comments
 (0)