Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8b754e3
Initial plan
Copilot Nov 1, 2025
645c470
Add CommonModuleReference utility and initial tests
Copilot Nov 1, 2025
f3dcf26
Add addModuleReference method and update ReferenceIndexFiller
Copilot Nov 1, 2025
feb1eb3
Add support for common module references via variable - WIP
Copilot Nov 1, 2025
08dc796
Complete implementation of common module reference tracking
Copilot Nov 1, 2025
fc496e7
Clean up code per review comments
Copilot Nov 1, 2025
b039c9f
Clear stale CommonModule mappings on reassignment and between methods
Copilot Nov 1, 2025
53a253e
Preserve module-level variable mappings across methods
Copilot Nov 1, 2025
ef90941
Add support for multiple common module accessor names and manager mod…
Copilot Nov 1, 2025
fc7d40b
Use MDOType.fromValue() instead of hardcoded manager types
Copilot Dec 2, 2025
60a3011
Add configurable references options for common module accessors
Copilot Dec 2, 2025
a13dd1f
Add references configuration to JSON schema and documentation
Copilot Dec 2, 2025
fb4eff5
Merge branch 'develop' into copilot/support-method-module-references
nixel2007 Dec 2, 2025
d177d29
Rename CommonModuleReference to ModuleReference and refactor code
Copilot Dec 3, 2025
5b881d0
Merge branch 'develop' into copilot/support-method-module-references
nixel2007 Dec 3, 2025
457974a
Fix missing @Test annotation and closing brace in ReferenceIndexFille…
Copilot Dec 5, 2025
5340761
Merge branch 'develop' into copilot/support-method-module-references
nixel2007 Dec 6, 2025
277132d
Add unit tests for manager module functionality in ModuleReference
Copilot Dec 7, 2025
b7bd706
Fix jspecify issues: use Optional instead of null returns
Copilot Dec 7, 2025
e2cf62d
Remove manager module functionality per review request
Copilot Dec 8, 2025
042a37a
Restore ManagerModule in DEFAULT_MODULE_TYPES and refactor extractPar…
Copilot Dec 8, 2025
daaa80f
Add module reference for common module identifiers in call statements
Copilot Dec 8, 2025
acae691
Fix ReferenceIndexTest tests for new module reference indexing
Copilot Dec 8, 2025
ffe716e
Address code review feedback
Copilot Dec 8, 2025
a336ad6
Address review feedback: caching, case-insensitive compare, hover for…
Copilot Dec 8, 2025
b22bab1
Remove null check for CommonModule.getComment()
Copilot Dec 8, 2025
e9dd21a
Address review feedback: optimize patterns, improve hover, add tests
Copilot Dec 8, 2025
d52da3b
Address review feedback: use locale-aware mdoRef, fix imports
Copilot Dec 8, 2025
fd94d14
Merge branch 'develop' into copilot/support-method-module-references
theshadowco Dec 9, 2025
7ccc3fd
Рефакторинг
nixel2007 Dec 9, 2025
57fb106
Улучшение ховера по модулю
nixel2007 Dec 9, 2025
b5ee7fb
Fix QF
nixel2007 Dec 9, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,35 @@ public void addMethodCall(URI uri, String mdoRef, ModuleType moduleType, String
locationRepository.updateLocation(symbolOccurrence);
}

/**
* Добавить ссылку на модуль в индекс.
*
* @param uri URI документа, откуда произошло обращение к модулю.
* @param mdoRef Ссылка на объект-метаданных модуля (например, CommonModule.ОбщийМодуль1).
* @param moduleType Тип модуля (например, {@link ModuleType#CommonModule}).
* @param range Диапазон, в котором происходит обращение к модулю.
*/
public void addModuleReference(URI uri, String mdoRef, ModuleType moduleType, Range range) {
var symbol = Symbol.builder()
.mdoRef(mdoRef)
.moduleType(moduleType)
.scopeName("")
.symbolKind(SymbolKind.Module)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Проверь, не нужно ли нам добавить новый hover MarkdownBuilder для этого типа модуля. Предложи детально описание решения, но не реализовывай.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Анализ hover для ModuleSymbol

Текущая ситуация

На данный момент:

  • ModuleSymbol использует SymbolKind.Module (строка 73 в ModuleSymbol.java)
  • HoverProvider делегирует построение hover контента в Map<SymbolKind, MarkupContentBuilder<Symbol>>
  • Существуют MarkupContentBuilder для: Method, Variable, TypeParameter (Annotation), Interface (AnnotationSymbol)
  • Нет MarkupContentBuilder для SymbolKind.Module

Необходимость добавления

Когда пользователь наведет курсор на ссылку, которая разрешается в ModuleSymbol (например, переменная с общим модулем), HoverProvider.getHover() вернет Optional.empty(), так как нет соответствующего builder'а.

Предлагаемое решение

1. Создать ModuleSymbolMarkupContentBuilder:

@Component
@RequiredArgsConstructor
public class ModuleSymbolMarkupContentBuilder implements MarkupContentBuilder<ModuleSymbol> {

  private final DescriptionFormatter descriptionFormatter;

  @Override
  public MarkupContent getContent(ModuleSymbol symbol) {
    var markupBuilder = new StringJoiner("\n");

    // Сигнатура модуля: "CommonModule: ОбщегоНазначения"
    String signature = buildModuleSignature(symbol);
    descriptionFormatter.addSectionIfNotEmpty(markupBuilder, signature);

    // Местоположение модуля (путь к файлу)
    String location = descriptionFormatter.getLocation(symbol);
    descriptionFormatter.addSectionIfNotEmpty(markupBuilder, location);

    // Опционально: описание модуля из метаданных конфигурации
    // (если доступно через mdclasses)

    return new MarkupContent(MarkupKind.MARKDOWN, markupBuilder.toString());
  }

  private String buildModuleSignature(ModuleSymbol symbol) {
    // Получить тип модуля и имя из symbol.getName()
    // Формат: "ОбщийМодуль: ИмяМодуля" или "CommonModule: ModuleName"
  }

  @Override
  public SymbolKind getSymbolKind() {
    return SymbolKind.Module;
  }
}

2. Информация для отображения:

  • Тип модуля (CommonModule, ManagerModule, ObjectModule, etc.)
  • Имя модуля
  • Путь к файлу
  • Опционально: синоним и комментарий из метаданных (если доступны через mdclasses)

3. Изменения в DescriptionFormatter:

  • Возможно потребуется добавить метод getSignature(ModuleSymbol) или использовать существующую логику

Рекомендация

Добавление ModuleSymbolMarkupContentBuilder не является критичным для базовой функциональности reference tracking. Ссылки будут находиться и без hover. Однако для полноценного user experience это полезное улучшение.

Реализовывать в рамках текущего PR или создать отдельный issue?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отличная идея про описание модуля из метаданных. Добавь вывод комментария, флаги доступности модуля на клиенте, сервере, клиент-сервере, обычном приложении, вызове сервера, привилегированного режима и режима повторного использования

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot смотри мой комментарий и реализуй.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Реализация ModuleSymbolMarkupContentBuilder будет включать:

  1. Сигнатура модуля: ОбщийМодуль: ИмяМодуля
  2. Комментарий модуля из метаданных (если есть)
  3. Флаги доступности:
    • Клиент / Сервер / КлиентСервер
    • Обычное приложение
    • Вызов сервера
    • Привилегированный режим
    • Режим повторного использования

Для получения метаданных можно использовать:

var commonModule = configuration.findCommonModule(moduleName);
commonModule.ifPresent(cm -> {
  cm.getComment(); // комментарий
  cm.isClientManagedApplication(); // на клиенте
  cm.isServer(); // на сервере
  // и т.д.
});

Хотите, чтобы я реализовал это в рамках текущего PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot да, реализуй.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Реализовано в a336ad6. Создан ModuleSymbolMarkupContentBuilder который отображает:

  • Сигнатура модуля (тип и имя)
  • Местоположение модуля
  • Комментарий из метаданных
  • Флаги доступности: Сервер, Управляемое приложение, Обычное приложение, Внешнее соединение, Вызов сервера, Привилегированный режим, Глобальный
  • Режим повторного использования возвращаемых значений (На время вызова / На время сеанса)

Локализация: ru/en.

.symbolName("")
.build()
.intern();

var location = new Location(uri, range);
var symbolOccurrence = SymbolOccurrence.builder()
.occurrenceType(OccurrenceType.REFERENCE)
.symbol(symbol)
.location(location)
.build();

symbolOccurrenceRepository.save(symbolOccurrence);
locationRepository.updateLocation(symbolOccurrence);
}

/**
* Добавить обращение к переменной в индекс.
*
Expand Down Expand Up @@ -269,6 +298,12 @@ private Optional<SourceDefinedSymbol> getSourceDefinedSymbol(Symbol symbolEntity
.or(() -> symbolTree.getVariableSymbol(symbolName, symbolTree.getModule())));
}

if (symbolEntity.symbolKind() == SymbolKind.Module) {
return serverContext.getDocument(mdoRef, moduleType)
.map(DocumentContext::getSymbolTree)
.map(SymbolTree::getModule);
}

return serverContext.getDocument(mdoRef, moduleType)
.map(DocumentContext::getSymbolTree)
.flatMap(symbolTree -> symbolTree.getMethodSymbol(symbolName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.github._1c_syntax.bsl.languageserver.context.events.DocumentContextContentChangedEvent;
import com.github._1c_syntax.bsl.languageserver.context.symbol.SourceDefinedSymbol;
import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol;
import com.github._1c_syntax.bsl.languageserver.utils.CommonModuleReference;
import com.github._1c_syntax.bsl.languageserver.utils.MdoRefBuilder;
import com.github._1c_syntax.bsl.languageserver.utils.Methods;
import com.github._1c_syntax.bsl.languageserver.utils.Modules;
Expand All @@ -47,7 +48,10 @@

import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -263,6 +267,7 @@ private class VariableSymbolReferenceIndexFinder extends BSLParserBaseVisitor<BS

private final DocumentContext documentContext;
private SourceDefinedSymbol currentScope;
private final Map<String, String> variableToCommonModuleMap = new HashMap<>();

@Override
public BSLParserRuleContext visitModuleVarDeclaration(BSLParser.ModuleVarDeclarationContext ctx) {
Expand Down Expand Up @@ -296,6 +301,37 @@ public BSLParserRuleContext visitSub(BSLParser.SubContext ctx) {
return result;
}

@Override
public BSLParserRuleContext visitAssignment(BSLParser.AssignmentContext ctx) {
// Detect pattern: Variable = ОбщегоНазначения.ОбщийМодуль("ModuleName") or Variable = ОбщийМодуль("ModuleName")
var lValue = ctx.lValue();
var expression = ctx.expression();

if (lValue != null && lValue.IDENTIFIER() != null && expression != null) {
if (CommonModuleReference.isCommonModuleExpression(expression)) {
var variableName = lValue.IDENTIFIER().getText();
CommonModuleReference.extractCommonModuleName(expression)
.flatMap(moduleName -> documentContext.getServerContext()
.getConfiguration()
.findCommonModule(moduleName))
.ifPresent(commonModule -> {
var mdoRef = commonModule.getMdoReference().getMdoRef();
variableToCommonModuleMap.put(variableName.toLowerCase(Locale.ENGLISH), mdoRef);

// Добавляем ссылку на модуль в индекс
index.addModuleReference(
documentContext.getUri(),
mdoRef,
ModuleType.CommonModule,
Ranges.create(expression)
);
});
}
}

return super.visitAssignment(ctx);
}

@Override
public BSLParserRuleContext visitLValue(BSLParser.LValueContext ctx) {
if (ctx.IDENTIFIER() == null) {
Expand Down Expand Up @@ -323,6 +359,21 @@ public BSLParserRuleContext visitCallStatement(BSLParser.CallStatementContext ct
}

var variableName = ctx.IDENTIFIER().getText();

// Check if variable references a common module
var commonModuleMdoRef = variableToCommonModuleMap.get(variableName.toLowerCase(Locale.ENGLISH));

if (commonModuleMdoRef != null) {
// Process method calls on the common module variable
// Check both modifiers and accessCall
if (!ctx.modifier().isEmpty()) {
processCommonModuleMethodCalls(ctx.modifier(), commonModuleMdoRef);
}
if (ctx.accessCall() != null) {
processCommonModuleAccessCall(ctx.accessCall(), commonModuleMdoRef);
}
}

findVariableSymbol(variableName)
.ifPresent(s -> addVariableUsage(
s.getRootParent(SymbolKind.Method), variableName, Ranges.create(ctx.IDENTIFIER()), true
Expand All @@ -338,6 +389,22 @@ public BSLParserRuleContext visitComplexIdentifier(BSLParser.ComplexIdentifierCo
}

var variableName = ctx.IDENTIFIER().getText();

// Check if we are inside a callStatement - if so, skip processing here to avoid duplication
var parentCallStatement = Trees.getRootParent(ctx, BSLParser.RULE_callStatement);
var isInsideCallStatement = false;
if (parentCallStatement instanceof BSLParser.CallStatementContext callStmt) {
isInsideCallStatement = callStmt.IDENTIFIER() != null
&& callStmt.IDENTIFIER().getText().equals(variableName);
}

// Check if variable references a common module
var commonModuleMdoRef = variableToCommonModuleMap.get(variableName.toLowerCase(Locale.ENGLISH));
if (commonModuleMdoRef != null && !ctx.modifier().isEmpty() && !isInsideCallStatement) {
// Process method calls on the common module variable
processCommonModuleMethodCalls(ctx.modifier(), commonModuleMdoRef);
}

findVariableSymbol(variableName)
.ifPresent(s -> addVariableUsage(
s.getRootParent(SymbolKind.Method), variableName, Ranges.create(ctx.IDENTIFIER()), true
Expand Down Expand Up @@ -435,5 +502,30 @@ private void addVariableUsage(Optional<SourceDefinedSymbol> methodSymbol,
!usage
);
}

private void processCommonModuleMethodCalls(List<? extends BSLParser.ModifierContext> modifiers, String mdoRef) {
for (var modifier : modifiers) {
var accessCall = modifier.accessCall();
if (accessCall != null) {
processCommonModuleAccessCall(accessCall, mdoRef);
}
}
}

private void processCommonModuleAccessCall(BSLParser.AccessCallContext accessCall, String mdoRef) {
var methodCall = accessCall.methodCall();
if (methodCall != null && methodCall.methodName() != null) {
var methodNameToken = methodCall.methodName().IDENTIFIER();
if (methodNameToken != null) {
index.addMethodCall(
documentContext.getUri(),
mdoRef,
ModuleType.CommonModule,
methodNameToken.getText(),
Ranges.create(methodNameToken)
);
}
}
}
}
}
Loading
Loading