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
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
package com.github._1c_syntax.bsl.languageserver.context.computer;

import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
import com.github._1c_syntax.bsl.languageserver.context.symbol.ModuleSymbol;
import com.github._1c_syntax.bsl.languageserver.context.symbol.RegionSymbol;
import com.github._1c_syntax.bsl.languageserver.context.symbol.VariableSymbol;
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
import com.github._1c_syntax.bsl.parser.BSLParser;
import com.github._1c_syntax.bsl.parser.BSLParserBaseVisitor;
import org.antlr.v4.runtime.tree.ParseTree;
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.lsp4j.Range;
Expand All @@ -38,46 +40,60 @@
import java.util.Set;

/**
* Вычислитель символов областей (регионов).
* Вычислитель символов переменных и регионов за <b>один</b> обход AST.
* <p>
* Анализирует директивы #Область/#Region и #КонецОбласти/#EndRegion
* для построения иерархии областей кода.
* И сбор переменных ({@link VariableSymbolComputer}), и сбор регионов обходили всё дерево вглубь
* (методы — вместе с телами), и при перестроении дерева символов на каждый keystroke это были два
* отдельных полных обхода 48k-строчного модуля (по профилю набора текста на больших модулях обход
* визиторами — заметная доля стоимости перестроения). Наборы перекрытых узлов у них не пересекаются
* (директивы {@code #Область}/{@code #КонецОбласти} против объявлений переменных/параметров/lvalue/
* циклов), поэтому сбор регионов добавляется поверх обхода переменных, и два полных обхода
* схлопываются в один.
* <p>
* {@link VariableSymbolComputer} остаётся самостоятельным (используется отдельно), а этот класс лишь
* расширяет его сбором регионов в том же {@code visitFile}.
*/
public final class RegionSymbolComputer
extends BSLParserBaseVisitor<ParseTree>
implements Computer<List<RegionSymbol>> {
public final class RegionVariableSymbolComputer extends VariableSymbolComputer {

private final DocumentContext documentContext;
private final Deque<Pair<RegionSymbol.RegionSymbolBuilder, BSLParser.RegionStartContext>> regionStack =
new ArrayDeque<>();
private final Set<RegionSymbol> regions = new HashSet<>();

public RegionSymbolComputer(DocumentContext documentContext) {
public RegionVariableSymbolComputer(DocumentContext documentContext,
ModuleSymbol module,
List<? extends MethodSymbol> methods) {
super(documentContext, module, methods);
this.documentContext = documentContext;
}

@Override
public List<RegionSymbol> compute() {
public List<VariableSymbol> compute() {
regionStack.clear();
regions.clear();

visitFile(documentContext.getAst());
// Единственный обход дерева: попутно с переменными собираем регионы (см. visitRegion*).
var variables = super.compute();

regionStack.clear();
return variables;
}

List<RegionSymbol> result = new ArrayList<>(regions);
regions.clear();

return result;
/**
* Собранные за тот же обход регионы. Вызывать после {@link #compute()}.
*
* @return список символов регионов модуля.
*/
public List<RegionSymbol> getRegions() {
return new ArrayList<>(regions);
}

@Override
public ParseTree visitRegionStart(BSLParser.RegionStartContext ctx) {

RegionSymbol.RegionSymbolBuilder builder = RegionSymbol.builder()
.owner(documentContext)
.name(ctx.regionName().getText().intern())
.regionNameRange(Ranges.create(ctx.regionName()))

Check warning on line 96 in src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/RegionVariableSymbolComputer.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Annotate the parameter with @javax.annotation.Nullable in method 'create' declaration, or make sure that null can not be passed as argument.

See more on https://sonarcloud.io/project/issues?id=1c-syntax_bsl-language-server&issues=AZ7lBt5i2xsScYI5GtVK&open=AZ7lBt5i2xsScYI5GtVK&pullRequest=4176
.startRange(Ranges.create(ctx));

regionStack.push(Pair.of(builder, ctx));
Expand All @@ -86,7 +102,6 @@

@Override
public ParseTree visitRegionEnd(BSLParser.RegionEndContext ctx) {

if (regionStack.isEmpty()) {
return super.visitRegionEnd(ctx);
}
Expand All @@ -94,19 +109,15 @@
var pair = regionStack.pop();

RegionSymbol.RegionSymbolBuilder builder = pair.getLeft();
BSLParser.RegionStartContext regionStartContext = pair.getRight();

Check warning on line 112 in src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/RegionVariableSymbolComputer.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Declare this local variable with "var" instead.

See more on https://sonarcloud.io/project/issues?id=1c-syntax_bsl-language-server&issues=AZ7lBt5i2xsScYI5GtVL&open=AZ7lBt5i2xsScYI5GtVL&pullRequest=4176

Range range = Ranges.create(regionStartContext, ctx);

Check warning on line 114 in src/main/java/com/github/_1c_syntax/bsl/languageserver/context/computer/RegionVariableSymbolComputer.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Declare this local variable with "var" instead.

See more on https://sonarcloud.io/project/issues?id=1c-syntax_bsl-language-server&issues=AZ7lBt5i2xsScYI5GtVM&open=AZ7lBt5i2xsScYI5GtVM&pullRequest=4176
builder
.range(range)
.endRange(Ranges.create(ctx))
;
.endRange(Ranges.create(ctx));

RegionSymbol region = builder.build();

regions.add(region);
regions.add(builder.build());

return super.visitRegionEnd(ctx);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ public SymbolTree compute() {

ModuleSymbol moduleSymbol = new ModuleSymbolComputer(documentContext).compute();
List<MethodSymbol> methods = new MethodSymbolComputer(documentContext).compute();
List<RegionSymbol> regions = new RegionSymbolComputer(documentContext).compute();
List<VariableSymbol> variables = new VariableSymbolComputer(documentContext, moduleSymbol, methods).compute();
// Переменные и регионы — за один общий обход дерева (оба обходят его вглубь).
var regionVariableComputer = new RegionVariableSymbolComputer(documentContext, moduleSymbol, methods);
List<VariableSymbol> variables = regionVariableComputer.compute();
List<RegionSymbol> regions = regionVariableComputer.getRegions();

List<SourceDefinedSymbol> allOfThem = new ArrayList<>(methods);
allOfThem.addAll(regions);
Expand Down
Loading