Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/antlr/BSLDescriptionParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ typesBlock: splitter type
;

type: listTypes | collectionType | hyperlinkType | simpleType;
simpleType: typeName=(WORD | DOTSWORD) colon=COLON?;
simpleType: typeName=(WORD | DOTSWORD) (colon=COLON (SPACE? hyperlink)?)?;
collectionType: collection=(WORD | DOTSWORD) SPACE OF_KEYWORD SPACE value=type;
hyperlinkType: hyperlink;
listTypes: listType (COMMA SPACE? listType?)+;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,18 @@
package com.github._1c_syntax.bsl.parser.description;

import com.github._1c_syntax.bsl.parser.description.support.DescriptionElement;
import com.github._1c_syntax.bsl.parser.description.support.Hyperlink;
import com.github._1c_syntax.bsl.parser.description.support.SimpleRange;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Value;
import lombok.experimental.Accessors;
import org.jspecify.annotations.Nullable;

import java.util.Collections;
import java.util.List;


/**
* Описание простого типа
*/
Expand All @@ -41,7 +44,8 @@ public class SimpleTypeDescription implements TypeDescription {
"",
"",
Collections.emptyList(),
new DescriptionElement(SimpleRange.EMPTY, DescriptionElement.Type.UNKNOWN)
new DescriptionElement(SimpleRange.EMPTY, DescriptionElement.Type.UNKNOWN),
null
);

@Accessors(fluent = true)
Expand All @@ -56,18 +60,34 @@ public class SimpleTypeDescription implements TypeDescription {
@Accessors(fluent = true)
DescriptionElement element;

/**
* Ссылка, уточняющая тип; {@code null}, если тип ссылкой не уточнён
*/
@Nullable
@Accessors(fluent = true)
Hyperlink hyperlink;

public static TypeDescription create(String name,
DescriptionElement element,
String description,
List<ParameterDescription> fieldList) {
return create(name, element, description, fieldList, null);
}

public static TypeDescription create(String name,
DescriptionElement element,
String description,
List<ParameterDescription> fieldList,
@Nullable Hyperlink hyperlink) {
if (name.isBlank() && description.isBlank()) {
return EMPTY;
}
return new SimpleTypeDescription(
name.strip().intern(),
description.strip(),
fieldList,
element
element,
hyperlink
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@

import com.github._1c_syntax.bsl.parser.description.support.DescriptionElement;

import com.github._1c_syntax.bsl.parser.description.support.Hyperlink;
import org.jspecify.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -66,6 +69,18 @@ public interface TypeDescription {
*/
DescriptionElement element();

/**
* Ссылка типа: у гиперссылочного типа это он сам, у простого — уточнение записью вида
* {@code СтрокаТабличнойЧасти: См. Справочник.Товары.ЕдиницыИзмерения}, где имя типа
* говорит, чем значение является, а ссылка — откуда взять его состав.
*
* @return Ссылка; {@code null}, если у типа ссылки нет
*/
@Nullable
default Hyperlink hyperlink() {
return null;
}

/**
* Список элементов описания включая все дочерние описания (поля, типы...)
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@
BSLDescriptionParser.@Nullable TypeDescriptionContext description) {
if (typeContext.typeName != null) {
var lastType = new TempParameterTypeData(typeContext.typeName, TypeDescription.Variant.SIMPLE, level);
lastType.setHyperlink(typeContext.hyperlink());
if (description != null) {
lastType.addTypeDescription(description);
}
Expand Down Expand Up @@ -525,6 +526,8 @@
private final TypeDescription.Variant variant;
private final List<TempParameterTypeData> valueTypes;
private @Nullable Token linkParamsToken;
private @Nullable Token hyperlinkToken;
private @Nullable Token hyperlinkParamsToken;

private final SimpleRange range;

Expand Down Expand Up @@ -552,6 +555,35 @@
this.name = typeName.getText();
}

/**
* Запомнить ссылку, уточняющую тип: {@code СтрокаТабличнойЧасти: См. Справочник.Товары.ЕдиницыИзмерения}.
*
* @param hyperlink Узел ссылки
*/
/**
* Собрать ссылку, уточняющую тип.
*
* @param lineShift Сдвиг номера строки
* @param charShifts Сдвиг символов по строкам
*
* @return Ссылка; {@code null}, если тип ссылкой не уточнён
*/
private @Nullable Hyperlink buildHyperlink(int lineShift, int[] charShifts) {

Check warning on line 571 in src/main/java/com/github/_1c_syntax/bsl/parser/description/reader/MethodDescriptionReader.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove or merge the dangling Javadoc comment(s).

See more on https://sonarcloud.io/project/issues?id=1c-syntax_bsl-parser&issues=AZ_CBZtD7LyVx862kJVM&open=AZ_CBZtD7LyVx862kJVM&pullRequest=406
if (hyperlinkToken == null) {
return null;
}
var params = hyperlinkParamsToken == null ? "" : hyperlinkParamsToken.getText();
return Hyperlink.create(hyperlinkToken.getText(), params,
SimpleRange.create(hyperlinkToken, lineShift, charShifts));
}

private void setHyperlink(BSLDescriptionParser.@Nullable HyperlinkContext hyperlink) {
if (hyperlink != null && hyperlink.link != null) {
this.hyperlinkToken = hyperlink.link;
this.hyperlinkParamsToken = hyperlink.linkParams;
}
}

private void addTypeDescription(BSLDescriptionParser.TypeDescriptionContext typeDescription) {
var lastField = lastField();
if (lastField.isPresent()) {
Expand Down Expand Up @@ -620,7 +652,8 @@
var element = new DescriptionElement(newRange, DescriptionElement.Type.TYPE_NAME);

return switch (variant) {
case SIMPLE -> SimpleTypeDescription.create(name, element, description.toString(), fieldList);
case SIMPLE -> SimpleTypeDescription.create(name, element, description.toString(), fieldList,
buildHyperlink(lineShift, charShifts));
case COLLECTION -> CollectionTypeDescription.create(
name, element, description.toString(),
valueTypes.stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* This file is a part of BSL Parser.
*
* Copyright (c) 2018-2026
* Alexey Sosnoviy <labotamy@gmail.com>, Nikita Fedkin <nixel2007@gmail.com>, Sergey Batanov <sergey.batanov@dmpas.ru>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* BSL Parser is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* BSL Parser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BSL Parser.
*/
package com.github._1c_syntax.bsl.parser.description.reader;

import com.github._1c_syntax.bsl.parser.BSLParser;
import com.github._1c_syntax.bsl.parser.BSLTokenizer;
import com.github._1c_syntax.bsl.parser.description.MethodDescription;
import com.github._1c_syntax.bsl.parser.description.TypeDescription;
import org.antlr.v4.runtime.Token;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Тип, уточнённый ссылкой: {@code СтрокаТабличнойЧасти: См. Справочник.Товары.ЕдиницыИзмерения}.
* Голова говорит, чем значение является, ссылка — откуда взять его состав.
*/
class TypeWithHyperlinkTest {

private List<Token> getTokens(String example) {
var tokenizer = new BSLTokenizer(example);
return tokenizer.getTokens().stream()
.filter(token -> token.getType() == BSLParser.LINE_COMMENT)
.toList();
}

@Test
void typeRefinedByHyperlinkKeepsBothParts() {
// given
var src = "// Параметры:\n// Объект - СтрокаТабличнойЧасти: См. Справочник.Товары.ЕдиницыИзмерения\n";

// when
var description = MethodDescription.create(getTokens(src));

// then
assertThat(description.getParameters())
.singleElement()
.satisfies(parameter -> {
assertThat(parameter.name()).isEqualTo("Объект");
assertThat(parameter.types()).singleElement().satisfies(type -> {
assertThat(type.variant()).isEqualTo(TypeDescription.Variant.SIMPLE);
assertThat(type.name()).isEqualTo("СтрокаТабличнойЧасти");
assertThat(type.hyperlink()).isNotNull();
assertThat(type.hyperlink().link()).isEqualTo("Справочник.Товары.ЕдиницыИзмерения");
});
});
}

@Test
void hyperlinkWithoutColonDoesNotRefineType() {
// given: разделителем в этой записи служит двоеточие, без него это не уточнение типа.
var src = "// Параметры:\n// Объект - СтрокаТабличнойЧасти См. Справочник.Товары.ЕдиницыИзмерения\n";

// when
var description = MethodDescription.create(getTokens(src));

// then: ссылка осталась сама по себе — уточнённого ею простого типа не появилось.
var types = description.getParameters().stream()
.flatMap(parameter -> parameter.types().stream())
.toList();
assertThat(types)
.filteredOn(type -> type.variant() == TypeDescription.Variant.HYPERLINK)
.singleElement()
.satisfies(type ->
assertThat(type.hyperlink().link()).isEqualTo("Справочник.Товары.ЕдиницыИзмерения"));
assertThat(types)
.filteredOn(type -> type.variant() == TypeDescription.Variant.SIMPLE)
.allSatisfy(type -> assertThat(type.hyperlink()).isNull());
}

@Test
void plainTypeHasNoHyperlink() {
// given
var src = "// Параметры:\n// Объект - СтрокаТабличнойЧасти\n";

// when
var description = MethodDescription.create(getTokens(src));

// then
assertThat(description.getParameters())
.singleElement()
.satisfies(parameter -> assertThat(parameter.types())
.singleElement()
.satisfies(type -> assertThat(type.hyperlink()).isNull()));
}
}
Loading