Skip to content

Commit e87003b

Browse files
authored
Merge pull request #3643 from 1c-syntax/copilot/update-bsl-parser-to-0280
Обновить bsl-parser до версии 0.28.0
2 parents 71297e3 + 3364179 commit e87003b

File tree

9 files changed

+154
-55
lines changed

9 files changed

+154
-55
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ dependencies {
8282
api("org.eclipse.lsp4j", "org.eclipse.lsp4j.websocket.jakarta", "0.24.0")
8383

8484
// 1c-syntax
85-
api("io.github.1c-syntax", "bsl-parser", "0.27.0") {
85+
api("io.github.1c-syntax", "bsl-parser", "0.28.0") {
8686
exclude("com.ibm.icu", "*")
8787
exclude("org.antlr", "ST4")
8888
exclude("org.antlr", "antlr-runtime")

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/MethodSymbolComputer.java

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

2424
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
25+
import com.github._1c_syntax.bsl.languageserver.context.symbol.AnnotationSymbol;
2526
import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
2627
import com.github._1c_syntax.bsl.languageserver.context.symbol.ParameterDefinition;
2728
import com.github._1c_syntax.bsl.languageserver.context.symbol.ParameterDefinition.ParameterType;
@@ -35,6 +36,7 @@
3536
import com.github._1c_syntax.bsl.languageserver.utils.Trees;
3637
import com.github._1c_syntax.bsl.parser.BSLParser;
3738
import com.github._1c_syntax.bsl.parser.BSLParserBaseVisitor;
39+
import org.eclipse.lsp4j.jsonrpc.messages.Either;
3840
import org.jspecify.annotations.Nullable;
3941
import org.antlr.v4.runtime.ParserRuleContext;
4042
import org.antlr.v4.runtime.Token;
@@ -356,15 +358,23 @@ private static List<AnnotationParameterDefinition> getAnnotationParameter(
356358
.toList();
357359
}
358360

359-
private static AnnotationParameterDefinition getAnnotationParam(BSLParser.AnnotationParamContext o) {
360-
var name = Optional.ofNullable(o.annotationParamName())
361+
private static AnnotationParameterDefinition getAnnotationParam(BSLParser.AnnotationParamContext annotationParam) {
362+
var name = Optional.ofNullable(annotationParam.annotationParamName())
361363
.map(ParserRuleContext::getText)
362364
.orElse("");
363-
var value = Optional.ofNullable(o.constValue())
365+
var value = Optional.ofNullable(annotationParam.annotationParamValue())
366+
.map(BSLParser.AnnotationParamValueContext::constValue)
364367
.map(ParserRuleContext::getText)
365368
.map(MethodSymbolComputer::excludeTrailingQuotes)
366-
.orElse("");
367-
var optional = o.constValue() != null;
369+
.map(Either::<String, Annotation>forLeft)
370+
.or(
371+
() -> Optional.ofNullable(annotationParam.annotationParamValue())
372+
.map(BSLParser.AnnotationParamValueContext::annotation)
373+
.map(MethodSymbolComputer::createAnnotation)
374+
.map(Either::<String, Annotation>forRight)
375+
)
376+
.orElse(Either.forLeft(""));
377+
var optional = annotationParam.annotationParamValue() != null;
368378

369379
return new AnnotationParameterDefinition(name, value, optional);
370380
}

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/AnnotationParamSymbol.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
/**
4040
* Символ параметра аннотации.
4141
* <p>
42-
* Представляет параметр компиляторной аннотации или директивы препроцессора,
42+
* Представляет параметр аннотации или директивы компиляции,
4343
* содержащий имя и значение параметра.
4444
*/
4545
@Value

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/symbol/annotations/AnnotationParameterDefinition.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@
2121
*/
2222
package com.github._1c_syntax.bsl.languageserver.context.symbol.annotations;
2323

24+
import org.eclipse.lsp4j.jsonrpc.messages.Either;
25+
2426
/**
2527
* Класс хранит информацию о параметре аннотации.
2628
* См. {@link Annotation}
2729
*/
28-
public record AnnotationParameterDefinition(String name, String value, boolean optional) {
30+
public record AnnotationParameterDefinition(String name, Either<String, Annotation> value, boolean optional) {
2931
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,11 @@ private void addAnnotationsFromAst(List<TokenEntry> entries, ParseTree parseTree
332332

333333
var annotationParams = annotation.annotationParams();
334334
if (annotationParams != null) {
335-
for (var annotationParamName : Trees.<AnnotationParamNameContext>findAllRuleNodes(annotationParams, BSLParser.RULE_annotationParamName)) {
335+
for (var annotationParam : annotationParams.annotationParam()) {
336+
var annotationParamName = annotationParam.annotationParamName();
337+
if (annotationParamName == null) {
338+
continue;
339+
}
336340
addRange(entries, Ranges.create(annotationParamName.IDENTIFIER()), SemanticTokenTypes.Parameter);
337341
}
338342
}

src/main/java/com/github/_1c_syntax/bsl/languageserver/references/AnnotationReferenceFinder.java

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.github._1c_syntax.bsl.languageserver.context.symbol.AnnotationSymbol;
3232
import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
3333
import com.github._1c_syntax.bsl.languageserver.context.symbol.annotations.Annotation;
34+
import com.github._1c_syntax.bsl.languageserver.context.symbol.annotations.AnnotationParameterDefinition;
3435
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
3536
import com.github._1c_syntax.bsl.languageserver.utils.Methods;
3637
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
@@ -41,6 +42,7 @@
4142
import org.apache.commons.lang3.tuple.Pair;
4243
import org.eclipse.lsp4j.Location;
4344
import org.eclipse.lsp4j.Position;
45+
import org.eclipse.lsp4j.jsonrpc.messages.Either;
4446
import org.springframework.context.event.EventListener;
4547
import org.springframework.stereotype.Component;
4648

@@ -98,9 +100,14 @@ private void findAndRegisterAnnotation(DocumentContext documentContext) {
98100

99101
var symbolTree = documentContext.getSymbolTree();
100102

101-
Methods.getOscriptClassConstructor(symbolTree)
102-
.flatMap(AnnotationReferenceFinder::findAnnotation)
103-
.map(methodSymbolAnnotationPair -> AnnotationSymbol.from(getAnnotationName(methodSymbolAnnotationPair.getRight()), methodSymbolAnnotationPair.getLeft()))
103+
var methodSymbolAnnotationPair = Methods.getOscriptClassConstructor(symbolTree)
104+
.flatMap(AnnotationReferenceFinder::findAnnotation);
105+
106+
methodSymbolAnnotationPair
107+
.map(Pair::getRight)
108+
.flatMap(AnnotationReferenceFinder::getAnnotationName)
109+
.flatMap(annotationName -> methodSymbolAnnotationPair.map(Pair::getLeft)
110+
.map(methodSymbol -> AnnotationSymbol.from(annotationName, methodSymbol)))
104111
.ifPresent(annotationSymbol -> registeredAnnotations.put(annotationSymbol.getName(), annotationSymbol));
105112
}
106113

@@ -127,38 +134,23 @@ public Optional<Reference> findReference(URI uri, Position position) {
127134
return Optional.empty();
128135
}
129136

130-
return Optional.of(parentContext)
131-
.filter(BSLParser.AnnotationNameContext.class::isInstance)
132-
.map(BSLParser.AnnotationNameContext.class::cast)
133-
.flatMap(annotationName -> getReferenceToAnnotationSymbol(uri, annotationName, documentContext))
134-
135-
.or(() -> Optional.of(parentContext)
136-
.filter(BSLParser.AnnotationParamNameContext.class::isInstance)
137-
.map(BSLParser.AnnotationParamNameContext.class::cast)
138-
.flatMap(annotationParamName -> getReferenceToAnnotationParamSymbol(annotationParamName, documentContext))
139-
)
140-
141-
.or(() -> Optional.of(parentContext)
142-
.filter(BSLParser.ConstValueContext.class::isInstance)
143-
.map(BSLParser.ConstValueContext.class::cast)
144-
.flatMap(constValue -> getReferenceToAnnotationParamSymbol(constValue, documentContext))
145-
)
146-
147-
.or(() -> Optional.of(parentContext)
148-
.map(ParserRuleContext::getParent)
149-
.filter(BSLParser.ConstValueContext.class::isInstance)
150-
.map(BSLParser.ConstValueContext.class::cast)
151-
.flatMap(constValue -> getReferenceToAnnotationParamSymbol(constValue, documentContext))
152-
)
153-
154-
.or(() -> Optional.of(parentContext)
155-
.map(ParserRuleContext::getParent)
156-
.map(ParserRuleContext::getParent)
157-
.filter(BSLParser.ConstValueContext.class::isInstance)
158-
.map(BSLParser.ConstValueContext.class::cast)
159-
.flatMap(constValue -> getReferenceToAnnotationParamSymbol(constValue, documentContext))
160-
);
137+
// Проверяем parentContext напрямую
138+
if (parentContext instanceof BSLParser.AnnotationNameContext annotationNameContext) {
139+
return getReferenceToAnnotationSymbol(uri, annotationNameContext, documentContext);
140+
}
141+
142+
if (parentContext instanceof BSLParser.AnnotationParamNameContext annotationParamNameContext) {
143+
return getReferenceToAnnotationParamSymbol(annotationParamNameContext, documentContext);
144+
}
145+
146+
// Ищем AnnotationParamValueContext среди parentContext и его предков
147+
var annotationParamValueContext = parentContext instanceof BSLParser.AnnotationParamValueContext apv
148+
? apv
149+
: Trees.<BSLParser.AnnotationParamValueContext>getAncestorByRuleIndex(
150+
parentContext, BSLParser.RULE_annotationParamValue);
161151

152+
return Optional.ofNullable(annotationParamValueContext)
153+
.flatMap(apv -> getReferenceToAnnotationParamSymbol(apv, documentContext));
162154
}
163155

164156
private Optional<Reference> getReferenceToAnnotationSymbol(URI uri, BSLParser.AnnotationNameContext annotationName, DocumentContext documentContext) {
@@ -179,8 +171,8 @@ private Optional<Reference> getReferenceToAnnotationParamSymbol(BSLParser.Annota
179171
.flatMap(annotationParamContext -> getReferenceToAnnotationParam(documentContext, Optional.of(annotationParamContext)));
180172
}
181173

182-
private Optional<Reference> getReferenceToAnnotationParamSymbol(BSLParser.ConstValueContext constValue, DocumentContext documentContext) {
183-
return Optional.of(constValue)
174+
private Optional<Reference> getReferenceToAnnotationParamSymbol(BSLParser.AnnotationParamValueContext annotationParamValue, DocumentContext documentContext) {
175+
return Optional.of(annotationParamValue)
184176
.map(ParserRuleContext::getParent) // BSLParser.AnnotationParamContext
185177
.filter(BSLParser.AnnotationParamContext.class::isInstance)
186178
.map(BSLParser.AnnotationParamContext.class::cast)
@@ -205,7 +197,7 @@ private Optional<Reference> getReferenceToAnnotationParam(
205197
ParserRuleContext annotationParamLocation = annotationParamContext
206198
.map(BSLParser.AnnotationParamContext::annotationParamName)
207199
.map(ParserRuleContext.class::cast)
208-
.or(() -> annotationParamContext.map(BSLParser.AnnotationParamContext::constValue))
200+
.or(() -> annotationParamContext.map(BSLParser.AnnotationParamContext::annotationParamValue))
209201
.orElseThrow();
210202

211203
return annotationParamContext
@@ -234,7 +226,11 @@ private static Optional<Pair<MethodSymbol, Annotation>> findAnnotation(MethodSym
234226
.map(annotation -> Pair.of(methodSymbol, annotation));
235227
}
236228

237-
private static String getAnnotationName(Annotation annotation) {
238-
return annotation.getParameters().get(0).value();
229+
private static Optional<String> getAnnotationName(Annotation annotation) {
230+
var annotationParameterDefinition = annotation.getParameters().get(0);
231+
return Optional.of(annotationParameterDefinition)
232+
.map(AnnotationParameterDefinition::value)
233+
.map(Either::getLeft);
234+
239235
}
240236
}

src/test/java/com/github/_1c_syntax/bsl/languageserver/context/computer/MethodSymbolComputerTest.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,36 +161,36 @@ void testAnnotation() {
161161

162162
assertThat(parameters.get(0).name()).isEqualTo("ДажеСПараметром");
163163
assertThat(parameters.get(0).optional()).isTrue();
164-
assertThat(parameters.get(0).value()).isEqualTo("Да");
164+
assertThat(parameters.get(0).value().getLeft()).isEqualTo("Да");
165165

166166
assertThat(parameters.get(1).name()).isEqualTo("СПараметромБезЗначения");
167167
assertThat(parameters.get(1).optional()).isFalse();
168-
assertThat(parameters.get(1).value()).isEmpty();
168+
assertThat(parameters.get(1).value().getLeft()).isEmpty();
169169

170170
assertThat(parameters.get(2).name()).isEmpty();
171171
assertThat(parameters.get(2).optional()).isTrue();
172-
assertThat(parameters.get(2).value()).isEqualTo("Значение без параметра");
172+
assertThat(parameters.get(2).value().getLeft()).isEqualTo("Значение без параметра");
173173

174174
// BEFORE
175175
methodSymbol = methods.get(20);
176176
assertThat(methodSymbol.getName()).isEqualTo("Р_Перед");
177177
assertThat(methodSymbol.getAnnotations().get(0).getName()).isEqualTo("Перед");
178178
assertThat(methodSymbol.getAnnotations().get(0).getKind()).isEqualTo(AnnotationKind.BEFORE);
179-
assertThat(methodSymbol.getAnnotations().get(0).getParameters().get(0).value()).isEqualTo("Перед");
179+
assertThat(methodSymbol.getAnnotations().get(0).getParameters().get(0).value().getLeft()).isEqualTo("Перед");
180180

181181
// AFTER
182182
methodSymbol = methods.get(21);
183183
assertThat(methodSymbol.getName()).isEqualTo("Р_После");
184184
assertThat(methodSymbol.getAnnotations().get(0).getName()).isEqualTo("После");
185185
assertThat(methodSymbol.getAnnotations().get(0).getKind()).isEqualTo(AnnotationKind.AFTER);
186-
assertThat(methodSymbol.getAnnotations().get(0).getParameters().get(0).value()).isEqualTo("После");
186+
assertThat(methodSymbol.getAnnotations().get(0).getParameters().get(0).value().getLeft()).isEqualTo("После");
187187

188188
// AROUND
189189
methodSymbol = methods.get(22);
190190
assertThat(methodSymbol.getName()).isEqualTo("Р_Вместо");
191191
assertThat(methodSymbol.getAnnotations().get(0).getName()).isEqualTo("Вместо");
192192
assertThat(methodSymbol.getAnnotations().get(0).getKind()).isEqualTo(AnnotationKind.AROUND);
193-
assertThat(methodSymbol.getAnnotations().get(0).getParameters().get(0).value()).isEqualTo("Вместо");
193+
assertThat(methodSymbol.getAnnotations().get(0).getParameters().get(0).value().getLeft()).isEqualTo("Вместо");
194194
}
195195

196196
@Test
@@ -243,7 +243,7 @@ void testParameters() {
243243
assertThat(parameters.get(1).getAnnotations().get(0).getKind()).isEqualTo(AnnotationKind.CUSTOM);
244244
assertThat(parameters.get(1).getAnnotations().get(0).getParameters()).hasSize(1);
245245
assertThat(parameters.get(1).getAnnotations().get(0).getParameters().get(0).name()).isEmpty();
246-
assertThat(parameters.get(1).getAnnotations().get(0).getParameters().get(0).value()).isEqualTo("СПараметром");
246+
assertThat(parameters.get(1).getAnnotations().get(0).getParameters().get(0).value().getLeft()).isEqualTo("СПараметром");
247247
assertThat(parameters.get(2).getName()).isEqualTo("Парам3");
248248
assertThat(parameters.get(2).getAnnotations()).isEmpty();
249249

src/test/java/com/github/_1c_syntax/bsl/languageserver/references/AnnotationReferenceFinderTest.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,4 +261,81 @@ void testNonOSFileIgnored() {
261261
// then - ссылка не должна быть найдена, т.к. работаем только с .os файлами
262262
assertThat(reference).isEmpty();
263263
}
264+
265+
@Test
266+
void findReferenceOfNestedAnnotationName() {
267+
// given
268+
// Строка 32 (1-based), 31 (0-based): &ТестоваяАннотация(&ВложеннаяАннотация("Значение"))
269+
// При клике на имя вложенной аннотации должна находиться ссылка на определение этой аннотации
270+
initServerContext("./src/test/resources/references/annotations");
271+
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/references/AnnotationReferenceFinder.os");
272+
273+
var module = documentContext.getSymbolTree().getModule();
274+
275+
// when - кликаем на имя вложенной аннотации "ВложеннаяАннотация"
276+
// &ТестоваяАннотация(&ВложеннаяАннотация("Значение"))
277+
// Позиция 20 - это внутри имени "ВложеннаяАннотация"
278+
var optionalReference = referenceFinder.findReference(documentContext.getUri(), new Position(31, 22));
279+
280+
// then - должна найтись ссылка на определение аннотации ВложеннаяАннотация (если она зарегистрирована)
281+
// Поскольку аннотация ВложеннаяАннотация не зарегистрирована в тестовом контексте, ссылка не найдётся
282+
assertThat(optionalReference).isEmpty();
283+
}
284+
285+
@Test
286+
void findReferenceOfNestedAnnotationParameterValue() {
287+
// given
288+
// Строка 32 (1-based), 31 (0-based): &ТестоваяАннотация(&ВложеннаяАннотация("Значение"))
289+
// При клике на значение параметра вложенной аннотации должна находиться ссылка на параметр вложенной аннотации
290+
initServerContext("./src/test/resources/references/annotations");
291+
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/references/AnnotationReferenceFinder.os");
292+
293+
var module = documentContext.getSymbolTree().getModule();
294+
295+
// when - кликаем на значение "Значение" внутри вложенной аннотации
296+
// &ТестоваяАннотация(&ВложеннаяАннотация("Значение"))
297+
// Позиция 40 - это внутри "Значение"
298+
var optionalReference = referenceFinder.findReference(documentContext.getUri(), new Position(31, 40));
299+
300+
// then - должна найтись ссылка на параметр "Значение" вложенной аннотации
301+
// Поскольку аннотация ВложеннаяАннотация не зарегистрирована, ссылка не найдётся
302+
assertThat(optionalReference).isEmpty();
303+
}
304+
305+
@Test
306+
void findReferenceOfNestedAnnotationWithNamedParameter() {
307+
// given
308+
// Строка 35 (1-based), 34 (0-based): &ТестоваяАннотация(Параметр = &ВложеннаяАннотация("Значение"))
309+
initServerContext("./src/test/resources/references/annotations");
310+
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/references/AnnotationReferenceFinder.os");
311+
312+
var module = documentContext.getSymbolTree().getModule();
313+
314+
// when - кликаем на имя параметра "Параметр" внешней аннотации
315+
// &ТестоваяАннотация(Параметр = &ВложеннаяАннотация("Значение"))
316+
// Позиция 20 - это внутри "Параметр"
317+
var optionalReference = referenceFinder.findReference(documentContext.getUri(), new Position(34, 20));
318+
319+
// then - должна найтись ссылка на параметр "Параметр" внешней аннотации ТестоваяАннотация
320+
assertThat(optionalReference)
321+
.isPresent()
322+
.hasValueSatisfying(reference -> assertThat(reference.getFrom()).isEqualTo(module))
323+
.hasValueSatisfying(reference -> assertThat(reference.getSymbol().getName()).isEqualTo("Параметр"))
324+
.hasValueSatisfying(reference -> assertThat(reference.getSymbol().getSymbolKind()).isEqualTo(SymbolKind.TypeParameter));
325+
}
326+
327+
@Test
328+
void findReferenceOfDeeplyNestedAnnotationName() {
329+
// given
330+
// Строка 38 (1-based), 37 (0-based): &ТестоваяАннотация(&ВложеннаяАннотация(&ГлубокоВложеннаяАннотация("Глубокое значение")))
331+
initServerContext("./src/test/resources/references/annotations");
332+
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/references/AnnotationReferenceFinder.os");
333+
334+
// when - кликаем на имя глубоко вложенной аннотации "ГлубокоВложеннаяАннотация"
335+
// Позиция 45 - это внутри имени "ГлубокоВложеннаяАннотация"
336+
var optionalReference = referenceFinder.findReference(documentContext.getUri(), new Position(37, 45));
337+
338+
// then - поскольку аннотация не зарегистрирована, ссылка не найдётся
339+
assertThat(optionalReference).isEmpty();
340+
}
264341
}

0 commit comments

Comments
 (0)