Skip to content

Commit 872b84e

Browse files
committed
Расчет типа возвращаемого значения локального метода и описания переменной
1 parent d789d6f commit 872b84e

File tree

3 files changed

+122
-14
lines changed

3 files changed

+122
-14
lines changed

src/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolver.java

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@
2424
import com.github._1c_syntax.bsl.languageserver.context.ServerContext;
2525
import com.github._1c_syntax.bsl.languageserver.context.symbol.Describable;
2626
import com.github._1c_syntax.bsl.languageserver.context.symbol.SourceDefinedSymbol;
27+
import com.github._1c_syntax.bsl.languageserver.context.symbol.description.MethodDescription;
28+
import com.github._1c_syntax.bsl.languageserver.context.symbol.description.TypeDescription;
2729
import com.github._1c_syntax.bsl.languageserver.context.symbol.variable.VariableDescription;
2830
import com.github._1c_syntax.bsl.languageserver.references.ReferenceIndex;
2931
import com.github._1c_syntax.bsl.languageserver.references.ReferenceResolver;
3032
import com.github._1c_syntax.bsl.languageserver.references.model.OccurrenceType;
3133
import com.github._1c_syntax.bsl.languageserver.references.model.Reference;
34+
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
3235
import com.github._1c_syntax.bsl.languageserver.utils.Trees;
3336
import com.github._1c_syntax.bsl.languageserver.utils.bsl.Constructors;
3437
import com.github._1c_syntax.bsl.parser.BSLParser;
@@ -41,6 +44,8 @@
4144
import java.util.Collection;
4245
import java.util.Collections;
4346
import java.util.List;
47+
import java.util.regex.MatchResult;
48+
import java.util.regex.Pattern;
4449
import java.util.stream.Stream;
4550

4651
@Component
@@ -74,20 +79,34 @@ private List<Type> calculateTypes(SourceDefinedSymbol symbol) {
7479
if (maybeDescription.isPresent()) {
7580
var description = maybeDescription.get();
7681
if (description instanceof VariableDescription variableDescription) {
77-
// TODO: extract types from type description and return.
82+
// TODO: use new type information from new bsp-parser
83+
var purposeDescription = variableDescription.getPurposeDescription();
84+
var typeName = Pattern.compile("^(\\S+)").matcher(purposeDescription).results()
85+
.findFirst()
86+
.map(MatchResult::group)
87+
.orElse("");
88+
89+
if (!typeName.isEmpty()) {
90+
return List.of(new Type(typeName));
91+
}
7892
}
7993
}
8094
}
8195

8296
// reference-based type resolver
97+
var uri = symbol.getOwner().getUri();
8398
var ast = symbol.getOwner().getAst();
99+
if (ast == null) {
100+
return Collections.emptyList();
101+
}
102+
84103
var position = symbol.getSelectionRange().getStart();
85104

86-
var typesOfCurrentReference = calculateTypes(ast, position);
105+
var typesOfCurrentReference = calculateTypes(uri, ast, position);
87106

88107
var typesOfOtherReferences = referenceIndex.getReferencesTo(symbol).stream()
89108
.filter(referenceTo -> referenceTo.getOccurrenceType() == OccurrenceType.DEFINITION)
90-
.map(referenceTo -> calculateTypes(ast, referenceTo.getSelectionRange().getStart()))
109+
.map(referenceTo -> calculateTypes(uri, ast, referenceTo.getSelectionRange().getStart()))
91110
.flatMap(Collection::stream)
92111
.toList();
93112

@@ -107,38 +126,47 @@ private List<Type> calculateTypes(URI uri, Reference reference) {
107126
if (reference.getOccurrenceType() == OccurrenceType.DEFINITION) {
108127
var document = serverContext.getDocument(uri);
109128
var ast = document.getAst();
129+
if (ast == null) {
130+
return Collections.emptyList();
131+
}
110132
var position = reference.getSelectionRange().getStart();
111-
return calculateTypes(ast, position);
133+
return calculateTypes(uri, ast, position);
112134
}
113135

114136
// no-op
115137
return Collections.emptyList();
116138
}
117139

118-
private List<Type> calculateTypes(BSLParser.FileContext ast, Position position) {
140+
private List<Type> calculateTypes(URI uri, BSLParser.FileContext ast, Position position) {
119141
return Trees.findTerminalNodeContainsPosition(ast, position)
120142
.map(TerminalNode::getParent)
121143
.map(ruleNode -> Trees.getRootParent(ruleNode, BSLParser.RULE_assignment))
122144
.map(BSLParser.AssignmentContext.class::cast)
123145
.map(BSLParser.AssignmentContext::expression)
124-
.map(this::calculateTypes)
146+
.map(expression -> calculateTypes(uri, expression))
125147
.orElseGet(Collections::emptyList);
126148
}
127149

128-
private List<Type> calculateTypes(BSLParser.ExpressionContext expression) {
150+
private List<Type> calculateTypes(URI uri, BSLParser.ExpressionContext expression) {
129151

130152
// only simple cases for now. Use ExpressionTree in the future.
131153
if (!expression.operation().isEmpty()) {
132154
return Collections.emptyList();
133155
}
134156

135157
// new-resolver
136-
var typeName = typeName(expression);
158+
var typeName = newTypeName(expression);
137159
if (!typeName.isEmpty()) {
138160
Type type = new Type(typeName);
139161
return List.of(type);
140162
}
141163

164+
// globalMethodCall resolver
165+
var typeNames = returnedValue(uri, expression);
166+
if (!typeNames.isEmpty()) {
167+
return typeNames;
168+
}
169+
142170
// const-value resolver
143171
var constValueContext = expression.member(0).constValue();
144172
if (constValueContext == null) {
@@ -168,14 +196,48 @@ private List<Type> calculateTypes(BSLParser.ExpressionContext expression) {
168196

169197
}
170198

171-
private String typeName(BSLParser.ExpressionContext ctx) {
199+
private String newTypeName(BSLParser.ExpressionContext expression) {
172200
var typeName = "";
173-
var newCtx = Trees.getNextNode(ctx, ctx, BSLParser.RULE_newExpression);
201+
var newCtx = Trees.getNextNode(expression, expression, BSLParser.RULE_newExpression);
174202
if (newCtx instanceof BSLParser.NewExpressionContext newExpression) {
175203
typeName = Constructors.typeName(newExpression).orElse("");
176204
}
177205
return typeName;
178206
}
179207

208+
private List<Type> returnedValue(URI uri, BSLParser.ExpressionContext expression) {
209+
var complexIdentifier = expression.member(0).complexIdentifier();
210+
211+
if (complexIdentifier == null) {
212+
return Collections.emptyList();
213+
}
214+
215+
if (!complexIdentifier.modifier().isEmpty()) {
216+
return Collections.emptyList();
217+
}
218+
219+
var globalMethodCall = complexIdentifier.globalMethodCall();
220+
221+
if (globalMethodCall == null) {
222+
return Collections.emptyList();
223+
}
224+
225+
var calledMethod = referenceResolver.findReference(uri, Ranges.create(globalMethodCall.methodName()).getStart());
226+
227+
return calledMethod.filter(Reference::isSourceDefinedSymbolReference)
228+
.flatMap(Reference::getSourceDefinedSymbol)
229+
.filter(Describable.class::isInstance)
230+
.map(Describable.class::cast)
231+
.flatMap(Describable::getDescription)
232+
.filter(MethodDescription.class::isInstance)
233+
.map(MethodDescription.class::cast)
234+
.map(MethodDescription::getReturnedValue)
235+
.stream()
236+
.flatMap(List::stream)
237+
.map(TypeDescription::getName)
238+
.map(Type::new)
239+
.toList();
240+
241+
}
180242

181243
}

src/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeResolverTest.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void simpleType() {
4141
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
4242

4343
// when
44-
var types = typeResolver.findTypes(documentContext.getUri(), new Position(2, 10));
44+
var types = typeResolver.findTypes(documentContext.getUri(), new Position(5, 10));
4545

4646
// then
4747
assertThat(types).hasSize(1);
@@ -53,7 +53,7 @@ void twoTypesOnReassignment() {
5353
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
5454

5555
// when
56-
var types = typeResolver.findTypes(documentContext.getUri(), new Position(5, 4));
56+
var types = typeResolver.findTypes(documentContext.getUri(), new Position(8, 4));
5757

5858
// then
5959
assertThat(types).hasSize(2);
@@ -65,7 +65,7 @@ void twoTypesOnPlaceOfUsage() {
6565
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
6666

6767
// when
68-
var types = typeResolver.findTypes(documentContext.getUri(), new Position(7, 10));
68+
var types = typeResolver.findTypes(documentContext.getUri(), new Position(10, 10));
6969

7070
// then
7171
assertThat(types).hasSize(2);
@@ -98,7 +98,7 @@ void twoAssignments() {
9898
}
9999

100100
@Test
101-
void array() {
101+
void newArray() {
102102
// given
103103
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
104104
var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("ДругоеИмяМассива", documentContext.getSymbolTree().getModule()).orElseThrow();
@@ -111,4 +111,32 @@ void array() {
111111
assertThat(types.get(0).getName()).isEqualTo("Массив");
112112
}
113113

114+
@Test
115+
void globalMethodCall() {
116+
// given
117+
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
118+
var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("РезультатФункции", documentContext.getSymbolTree().getModule()).orElseThrow();
119+
120+
// when
121+
var types = typeResolver.findTypes(variableSymbol);
122+
123+
// then
124+
assertThat(types).hasSize(1);
125+
assertThat(types.get(0).getName()).isEqualTo("Строка");
126+
}
127+
128+
@Test
129+
void varWithDescription() {
130+
// given
131+
var documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/types/TypeResolver.os");
132+
var variableSymbol = documentContext.getSymbolTree().getVariableSymbol("ПеременнаяСОписанием", documentContext.getSymbolTree().getModule()).orElseThrow();
133+
134+
// when
135+
var types = typeResolver.findTypes(variableSymbol);
136+
137+
// then
138+
assertThat(types).hasSize(1);
139+
assertThat(types.get(0).getName()).isEqualTo("Строка");
140+
}
141+
114142
}

src/test/resources/types/TypeResolver.os

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Строка - какая-то переменная
2+
Перем ПеременнаяСОписанием;
3+
14
ИмяКорневойАннотации = "Завязь";
25

36
Сообщить(ИмяКорневойАннотации);
@@ -14,3 +17,18 @@
1417

1518
ДругоеИмяМассива = Новый Массив;
1619
ДругоеИмяМассива.Добавить(1);
20+
21+
РезультатФункции = КакаяТоФункция();
22+
23+
Сообщить(РезультатФункции);
24+
25+
Сообщить(ПеременнаяСОписанием);
26+
27+
// Важная функция
28+
//
29+
// Возвращаемое значение:
30+
// Строка - что-то там.
31+
//
32+
Функция КакаяТоФункция()
33+
Возврат "Какая-то функция";
34+
КонецФункции

0 commit comments

Comments
 (0)