Skip to content

Commit 1d57fde

Browse files
authored
Merge pull request #2833 from artbear/ref-index-fix-2832
Доработка ReferenceIndex - Исправлен расчет ссылок на символы-методы + падение анализа
2 parents a0c1877 + 8fae65a commit 1d57fde

File tree

6 files changed

+208
-7
lines changed

6 files changed

+208
-7
lines changed

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

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,23 @@
3838
import com.github._1c_syntax.bsl.types.ModuleType;
3939
import lombok.RequiredArgsConstructor;
4040
import org.antlr.v4.runtime.Token;
41+
import org.antlr.v4.runtime.tree.ParseTree;
4142
import org.eclipse.lsp4j.Range;
4243
import org.eclipse.lsp4j.SymbolKind;
4344
import org.springframework.context.event.EventListener;
4445
import org.springframework.stereotype.Component;
4546

47+
import javax.annotation.Nullable;
4648
import java.net.URI;
49+
import java.util.Collection;
50+
import java.util.Collections;
4751
import java.util.EnumSet;
52+
import java.util.List;
4853
import java.util.Map;
54+
import java.util.Objects;
4955
import java.util.Optional;
5056
import java.util.Set;
57+
import java.util.stream.Collectors;
5158
import java.util.function.Predicate;
5259

5360
@Component
@@ -82,6 +89,19 @@ public void fill(DocumentContext documentContext) {
8289
private class MethodSymbolReferenceIndexFinder extends BSLParserBaseVisitor<BSLParserRuleContext> {
8390

8491
private final DocumentContext documentContext;
92+
private Set<String> commonModuleMdoRefFromSubParams = Collections.emptySet();
93+
94+
@Override
95+
public BSLParserRuleContext visitProcDeclaration(BSLParser.ProcDeclarationContext ctx) {
96+
commonModuleMdoRefFromSubParams = calcParams(ctx.paramList());
97+
return super.visitProcDeclaration(ctx);
98+
}
99+
100+
@Override
101+
public BSLParserRuleContext visitFuncDeclaration(BSLParser.FuncDeclarationContext ctx) {
102+
commonModuleMdoRefFromSubParams = calcParams(ctx.paramList());
103+
return super.visitFuncDeclaration(ctx);
104+
}
85105

86106
@Override
87107
public BSLParserRuleContext visitCallStatement(BSLParser.CallStatementContext ctx) {
@@ -156,11 +176,28 @@ public BSLParserRuleContext visitNewExpression(BSLParser.NewExpressionContext ct
156176
return super.visitNewExpression(ctx);
157177
}
158178

179+
@Override
180+
public BSLParserRuleContext visitLValue(BSLParser.LValueContext ctx) {
181+
final var identifier = ctx.IDENTIFIER();
182+
if (identifier != null){
183+
final List<? extends BSLParser.ModifierContext> modifiers = Optional.ofNullable(ctx.acceptor())
184+
.map(BSLParser.AcceptorContext::modifier)
185+
.orElseGet(Collections::emptyList);
186+
String mdoRef = MdoRefBuilder.getMdoRef(documentContext, identifier, modifiers);
187+
if (!mdoRef.isEmpty()) {
188+
Methods.getMethodName(ctx).ifPresent(methodName -> checkCall(mdoRef, methodName));
189+
}
190+
}
191+
return super.visitLValue(ctx);
192+
}
193+
159194
private void checkCall(String mdoRef, Token methodName) {
160195
var methodNameText = Strings.trimQuotes(methodName.getText());
161-
Map<ModuleType, URI> modules = documentContext.getServerContext().getConfiguration().getModulesByMDORef(mdoRef);
196+
final var configuration = documentContext.getServerContext().getConfiguration();
197+
Map<ModuleType, URI> modules = configuration.getModulesByMDORef(mdoRef);
162198
for (ModuleType moduleType : modules.keySet()) {
163-
if (!DEFAULT_MODULE_TYPES.contains(moduleType)) {
199+
if (!DEFAULT_MODULE_TYPES.contains(moduleType)
200+
|| (moduleType == ModuleType.CommonModule && commonModuleMdoRefFromSubParams.contains(mdoRef))) {
164201
continue;
165202
}
166203
addMethodCall(mdoRef, moduleType, methodNameText, Ranges.create(methodName));
@@ -172,6 +209,10 @@ private void addMethodCall(String mdoRef, ModuleType moduleType, String methodNa
172209
}
173210

174211
private void addCallbackMethodCall(BSLParser.CallParamContext methodName, String mdoRef) {
212+
// todo: move this out of method
213+
if (mdoRef.isEmpty()){
214+
return;
215+
}
175216
Methods.getMethodName(methodName).ifPresent((Token methodNameToken) -> {
176217
if (!mdoRef.equals(MdoRefBuilder.getMdoRef(documentContext))) {
177218
checkCall(mdoRef, methodNameToken);
@@ -187,13 +228,34 @@ private void addCallbackMethodCall(BSLParser.CallParamContext methodName, String
187228
}
188229

189230
private String getModule(BSLParser.CallParamContext callParamContext) {
190-
return NotifyDescription.getFirstMember(callParamContext)
231+
final var complexIdentifierContext1 = NotifyDescription.getFirstMember(callParamContext)
191232
.map(BSLParser.MemberContext::complexIdentifier)
233+
.filter(complexIdentifierContext -> complexIdentifierContext.IDENTIFIER() != null)
234+
.filter(complexIdentifierContext -> complexIdentifierContext.modifier().isEmpty());
235+
if (complexIdentifierContext1.isEmpty()){
236+
return "";
237+
}
238+
return complexIdentifierContext1
192239
.filter(Predicate.not(Modules::isThisObject))
193240
.map(complexIdentifier -> MdoRefBuilder.getMdoRef(documentContext, complexIdentifier))
194241
.orElse(MdoRefBuilder.getMdoRef(documentContext));
195242
}
196243

244+
private Set<String> calcParams(@Nullable BSLParser.ParamListContext paramList) {
245+
if (paramList == null) {
246+
return Collections.emptySet();
247+
}
248+
final var configuration = documentContext.getServerContext().getConfiguration();
249+
return paramList.param().stream()
250+
.map(BSLParser.ParamContext::IDENTIFIER)
251+
.filter(Objects::nonNull)
252+
.map(ParseTree::getText)
253+
.map(configuration::getCommonModule)
254+
.filter(Optional::isPresent)
255+
.flatMap(Optional::stream)
256+
.map(mdCommonModule -> mdCommonModule.getMdoReference().getMdoRef())
257+
.collect(Collectors.toSet());
258+
}
197259
}
198260

199261
@RequiredArgsConstructor

src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/Methods.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,10 @@ public static Optional<Token> getMethodName(BSLParser.CallParamContext callParam
7676
.map(BSLParser.StringContext::getStart);
7777
}
7878

79+
public static Optional<Token> getMethodName(BSLParser.LValueContext lValueContext) {
80+
return Optional.ofNullable(lValueContext.acceptor())
81+
.map(BSLParser.AcceptorContext::modifier)
82+
.flatMap(Methods::getMethodName);
83+
}
84+
7985
}

src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/Modules.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,15 @@
3131
public class Modules {
3232

3333
private static final Pattern THIS_OBJECT_PATTERN = CaseInsensitivePattern.compile(
34-
"^(ЭтотОбъект|ThisObject)$"
34+
"ЭтотОбъект|ThisObject"
3535
);
3636

3737
public static boolean isThisObject(BSLParser.ComplexIdentifierContext complexIdentifier) {
38-
return THIS_OBJECT_PATTERN.matcher(complexIdentifier.IDENTIFIER().getText()).find();
38+
final var identifier = complexIdentifier.IDENTIFIER();
39+
if (identifier == null){
40+
return false;
41+
}
42+
return THIS_OBJECT_PATTERN.matcher(identifier.getText()).matches();
3943
}
4044

4145
}

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

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@
2929
import com.github._1c_syntax.bsl.types.ModuleType;
3030
import org.eclipse.lsp4j.Location;
3131
import org.eclipse.lsp4j.Position;
32+
import org.eclipse.lsp4j.SymbolKind;
3233
import org.junit.jupiter.api.Test;
3334
import org.springframework.beans.factory.annotation.Autowired;
3435
import org.springframework.boot.test.context.SpringBootTest;
3536
import org.springframework.test.annotation.DirtiesContext;
3637

3738
import javax.annotation.PostConstruct;
3839
import java.nio.file.Paths;
40+
import java.util.stream.Collectors;
3941

4042
import static com.github._1c_syntax.bsl.languageserver.util.TestUtils.PATH_TO_METADATA;
4143
import static org.assertj.core.api.Assertions.assertThat;
@@ -158,6 +160,95 @@ void testGetReferenceToCommonModuleMethod() {
158160
assertThat(reference.getUri()).isEqualTo(uri);
159161
}
160162

163+
@Test
164+
void getReferencesToCommonModuleMethodFromAssignment() {
165+
// given
166+
var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE);
167+
var methodSymbol = documentContext.getSymbolTree().getMethodSymbol("Тест_Присваивание").orElseThrow();
168+
var commonModuleContext = serverContext.getDocument("CommonModule.ПервыйОбщийМодуль", ModuleType.CommonModule).orElseThrow();
169+
var calledMethodSymbol = commonModuleContext.getSymbolTree().getMethodSymbol("НеУстаревшаяФункция").orElseThrow();
170+
171+
var uri = documentContext.getUri();
172+
173+
// when
174+
final var referencesTo = referenceIndex.getReferencesTo(calledMethodSymbol).stream()
175+
.filter(reference -> reference.getUri().equals(uri))
176+
.filter(reference -> Ranges.containsRange(methodSymbol.getRange(), reference.toLocation().getRange()))
177+
.collect(Collectors.toList());
178+
179+
// then
180+
var reference = referencesTo.get(0);
181+
assertThat(reference.getFrom()).isEqualTo(methodSymbol);
182+
assertThat(reference.getSymbol()).isEqualTo(calledMethodSymbol);
183+
assertThat(reference.getSelectionRange()).isEqualTo(Ranges.create(8, 26, 45));
184+
assertThat(reference.getUri()).isEqualTo(uri);
185+
186+
reference = referencesTo.get(1);
187+
assertThat(reference.getFrom()).isEqualTo(methodSymbol);
188+
assertThat(reference.getSymbol()).isEqualTo(calledMethodSymbol);
189+
assertThat(reference.getSelectionRange()).isEqualTo(Ranges.create(9, 26, 45));
190+
assertThat(reference.getUri()).isEqualTo(uri);
191+
192+
reference = referencesTo.get(2);
193+
assertThat(reference.getFrom()).isEqualTo(methodSymbol);
194+
assertThat(reference.getSymbol()).isEqualTo(calledMethodSymbol);
195+
assertThat(reference.getSelectionRange()).isEqualTo(Ranges.create(10, 22, 41));
196+
assertThat(reference.getUri()).isEqualTo(uri);
197+
198+
assertThat(referencesTo).hasSize(3);
199+
}
200+
201+
@Test
202+
void getReferencesToFullPathModuleMethodFromAssignment() {
203+
// given
204+
var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE);
205+
var methodSymbol = documentContext.getSymbolTree().getMethodSymbol("Тест_ВызовЧерезПолноеИмяОбъекта").orElseThrow();
206+
var commonModuleContext = serverContext.getDocument("InformationRegister.РегистрСведений1", ModuleType.ManagerModule).orElseThrow();
207+
var calledMethodSymbol = commonModuleContext.getSymbolTree().getMethodSymbol("НеУстаревшаяФункция").orElseThrow();
208+
209+
var uri = documentContext.getUri();
210+
211+
// when
212+
final var referencesTo = referenceIndex.getReferencesTo(calledMethodSymbol).stream()
213+
.filter(reference -> reference.getUri().equals(uri))
214+
.filter(reference -> Ranges.containsRange(methodSymbol.getRange(), reference.toLocation().getRange()))
215+
.collect(Collectors.toList());
216+
217+
// then
218+
var reference = referencesTo.get(0);
219+
assertThat(reference.getFrom()).isEqualTo(methodSymbol);
220+
assertThat(reference.getSymbol()).isEqualTo(calledMethodSymbol);
221+
assertThat(reference.getSelectionRange()).isEqualTo(Ranges.create(22, 42, 61));
222+
assertThat(reference.getUri()).isEqualTo(uri);
223+
224+
reference = referencesTo.get(1);
225+
assertThat(reference.getFrom()).isEqualTo(methodSymbol);
226+
assertThat(reference.getSymbol()).isEqualTo(calledMethodSymbol);
227+
assertThat(reference.getSelectionRange()).isEqualTo(Ranges.create(23, 42, 61));
228+
assertThat(reference.getUri()).isEqualTo(uri);
229+
230+
reference = referencesTo.get(2);
231+
assertThat(reference.getFrom()).isEqualTo(methodSymbol);
232+
assertThat(reference.getSymbol()).isEqualTo(calledMethodSymbol);
233+
assertThat(reference.getSelectionRange()).isEqualTo(Ranges.create(24, 38, 57));
234+
assertThat(reference.getUri()).isEqualTo(uri);
235+
236+
assertThat(referencesTo).hasSize(3);
237+
}
238+
239+
@Test
240+
void getReferencesToCommonModuleMethodWithEqualNameWitMethodParam() {
241+
242+
var documentContext = TestUtils.getDocumentContextFromFile(PATH_TO_FILE);
243+
var methodSymbol = documentContext.getSymbolTree().getMethodSymbol("Тест_ИмяПараметр").orElseThrow();
244+
245+
final var referencesFromLocationRepo = referenceIndex.getReferencesFrom(documentContext.getUri(), SymbolKind.Method).stream()
246+
.filter(reference -> Ranges.containsRange(methodSymbol.getRange(), reference.getSelectionRange()))
247+
.collect(Collectors.toList());
248+
249+
assertThat(referencesFromLocationRepo).isEmpty();
250+
}
251+
161252
@Test
162253
void testCantGetReferenceToNonExportCommonModuleMethod() {
163254
// given

src/test/resources/references/ReferenceIndex.bsl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,23 @@
44
РегистрыСведений.РегистрСведений1.УстаревшаяПроцедура();
55
ПервыйОбщийМодуль.Тест();
66
КонецПроцедуры
7+
8+
Процедура Тест_Присваивание()
9+
А = ПервыйОбщийМодуль.НеУстаревшаяФункция();
10+
Б = ПервыйОбщийМодуль.НеУстаревшаяФункция().Добавить();
11+
ПервыйОбщийМодуль.НеУстаревшаяФункция().Реквизит = 10;
12+
КонецПроцедуры
13+
14+
Процедура Тест_ИмяПараметр(ПервыйОбщийМодуль)
15+
ПервыйОбщийМодуль.НеУстаревшаяПроцедура(1, 2); // ошибка
16+
А = ПервыйОбщийМодуль.НеУстаревшаяФункция(); // ошибка
17+
ПервыйОбщийМодуль.НеУстаревшаяФункция().Добавить(); // ошибка
18+
ПервыйОбщийМодуль.НеУстаревшаяФункция().Реквизит = 10; // ошибка
19+
Б = ПервыйОбщийМодуль.НеУстаревшаяФункция().Добавить(); // ошибка
20+
КонецПроцедуры
21+
22+
Процедура Тест_ВызовЧерезПолноеИмяОбъекта()
23+
А = РегистрыСведений.РегистрСведений1.НеУстаревшаяФункция();
24+
Б = РегистрыСведений.РегистрСведений1.НеУстаревшаяФункция().Добавить();
25+
РегистрыСведений.РегистрСведений1.НеУстаревшаяФункция().Реквизит = 10;
26+
КонецПроцедуры

src/test/resources/references/ReferenceIndexNotifyDescription.bsl

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,28 @@
99
ЭтотОбъект
1010
);
1111

12+
// Такое объявление не ловим
13+
ОписаниеОповещения2 = Новый ОписаниеОповещения(
14+
"ОбработчикОписаниеОповещения",
15+
ОбщийМодуль("Имя"),
16+
,
17+
"ОшибкаОписаниеОповещения",
18+
ОбщегоНазначения.ОбщийМодуль("Имя")
19+
);
20+
21+
// Такое объявление не ловим
22+
ОписаниеОповещения3 = Новый ОписаниеОповещения(
23+
"ОбработчикОписаниеОповещения",
24+
"ИмяМодуля",
25+
,
26+
"ОшибкаОписаниеОповещения",
27+
"ДругоеИмяМодуля"
28+
);
29+
1230
// Такое объявление не ловим
1331
ОбработчикОписаниеОповещения = "ОбработчикОписаниеОповещенияВПеременной";
1432
ОшибкаОписаниеОповещения = "ОшибкаОписаниеОповещенияВПеременной";
15-
ОписаниеОповещения2 = Новый ОписаниеОповещения(
33+
ОписаниеОповещения4 = Новый ОписаниеОповещения(
1634
ОбработчикОписаниеОповещения,
1735
ЭтотОбъект,
1836
,
@@ -26,7 +44,7 @@
2644
ПараметрыОбработчика[1] = ЭтотОбъект;
2745
ПараметрыОбработчика[3] = "ОшибкаОписаниеОповещения";
2846
ПараметрыОбработчика[4] = ЭтотОбъект;
29-
ОписаниеОповещения3 = Новый("ОписаниеОповещения", ПараметрыОбработчика);
47+
ОписаниеОповещения5 = Новый("ОписаниеОповещения", ПараметрыОбработчика);
3048

3149
КонецПроцедуры
3250

0 commit comments

Comments
 (0)