Skip to content

Commit 4c664d9

Browse files
cirrasfourls
authored andcommitted
Fix various name resolution errors around routine references
1 parent 4017843 commit 4c664d9

File tree

4 files changed

+93
-12
lines changed

4 files changed

+93
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6363
- Name resolution failures on invocations of methods with generic open array parameters.
6464
- Name resolution failures around `Create` calls on types with `constructor` constraints.
6565
- Name resolution failures on `read`, `write`, and `stored` specifiers of indexed properties.
66+
- Name resolution failures on routine references assigned to a `var`/`const` declaration.
67+
- Name resolution failures on routine references in constant arrays.
6668
- Type resolution failures on array expressions nested within multidimensional constant arrays.
6769
- Incorrect file position calculation for multiline string tokens.
6870
- Analysis errors around `type of` type declarations.

delphi-frontend/src/main/java/au/com/integradev/delphi/symbol/resolve/NameResolutionHelper.java

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,14 @@
3838
import java.util.stream.Collectors;
3939
import javax.annotation.Nullable;
4040
import org.sonar.plugins.communitydelphi.api.ast.AnonymousMethodNode;
41+
import org.sonar.plugins.communitydelphi.api.ast.ArrayExpressionNode;
4142
import org.sonar.plugins.communitydelphi.api.ast.ArrayIndicesNode;
4243
import org.sonar.plugins.communitydelphi.api.ast.ArrayTypeNode;
4344
import org.sonar.plugins.communitydelphi.api.ast.AssignmentStatementNode;
4445
import org.sonar.plugins.communitydelphi.api.ast.AttributeListNode;
4546
import org.sonar.plugins.communitydelphi.api.ast.AttributeNode;
47+
import org.sonar.plugins.communitydelphi.api.ast.ConstDeclarationNode;
48+
import org.sonar.plugins.communitydelphi.api.ast.ConstStatementNode;
4649
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
4750
import org.sonar.plugins.communitydelphi.api.ast.ExpressionNode;
4851
import org.sonar.plugins.communitydelphi.api.ast.ForInStatementNode;
@@ -71,6 +74,8 @@
7174
import org.sonar.plugins.communitydelphi.api.ast.TypeNode;
7275
import org.sonar.plugins.communitydelphi.api.ast.TypeReferenceNode;
7376
import org.sonar.plugins.communitydelphi.api.ast.UnaryExpressionNode;
77+
import org.sonar.plugins.communitydelphi.api.ast.VarDeclarationNode;
78+
import org.sonar.plugins.communitydelphi.api.ast.VarStatementNode;
7479
import org.sonar.plugins.communitydelphi.api.operator.UnaryOperator;
7580
import org.sonar.plugins.communitydelphi.api.symbol.Invocable;
7681
import org.sonar.plugins.communitydelphi.api.symbol.NameOccurrence;
@@ -86,6 +91,7 @@
8691
import org.sonar.plugins.communitydelphi.api.type.IntrinsicType;
8792
import org.sonar.plugins.communitydelphi.api.type.Type;
8893
import org.sonar.plugins.communitydelphi.api.type.Type.AliasType;
94+
import org.sonar.plugins.communitydelphi.api.type.Type.CollectionType;
8995
import org.sonar.plugins.communitydelphi.api.type.Type.ProceduralType;
9096
import org.sonar.plugins.communitydelphi.api.type.Type.ScopedType;
9197
import org.sonar.plugins.communitydelphi.api.type.Type.TypeParameterType;
@@ -517,18 +523,18 @@ private static boolean handleRoutineReference(
517523

518524
if (parent instanceof AssignmentStatementNode) {
519525
ExpressionNode assignee = ((AssignmentStatementNode) parent).getAssignee();
520-
if (expression == assignee) {
521-
return false;
522-
}
523-
524-
if (assignee.getType().isProcedural()) {
525-
NameResolver clone = new NameResolver(resolver);
526-
clone.disambiguateRoutineReference((ProceduralType) assignee.getType());
527-
if (!clone.getDeclarations().isEmpty()) {
528-
clone.addToSymbolTable();
529-
return true;
530-
}
531-
}
526+
return expression != assignee && handleRoutineReference(assignee.getType(), resolver);
527+
} else if (parent instanceof VarDeclarationNode) {
528+
return handleRoutineReference(((VarDeclarationNode) parent).getType(), resolver);
529+
} else if (parent instanceof ConstDeclarationNode) {
530+
return handleRoutineReference(((ConstDeclarationNode) parent).getTypeNode(), resolver);
531+
} else if (parent instanceof VarStatementNode) {
532+
return handleRoutineReference(((VarStatementNode) parent).getTypeNode(), resolver);
533+
} else if (parent instanceof ConstStatementNode) {
534+
return handleRoutineReference(((ConstStatementNode) parent).getTypeNode(), resolver);
535+
} else if (parent instanceof ArrayExpressionNode) {
536+
Type arrayType = ((ArrayExpressionNode) parent).getType();
537+
return handleRoutineReference(((CollectionType) arrayType).elementType(), resolver);
532538
} else if (parent instanceof RecordExpressionItemNode) {
533539
resolver.addToSymbolTable();
534540
return true;
@@ -537,6 +543,23 @@ private static boolean handleRoutineReference(
537543
return false;
538544
}
539545

546+
private static boolean handleRoutineReference(TypeNode typeNode, NameResolver resolver) {
547+
// You can't assign routine references unless a procedural type is explicitly declared.
548+
return typeNode != null && handleRoutineReference(typeNode.getType(), resolver);
549+
}
550+
551+
private static boolean handleRoutineReference(Type type, NameResolver resolver) {
552+
if (type.isProcedural()) {
553+
NameResolver clone = new NameResolver(resolver);
554+
clone.disambiguateRoutineReference((ProceduralType) type);
555+
if (!clone.getDeclarations().isEmpty()) {
556+
clone.addToSymbolTable();
557+
return true;
558+
}
559+
}
560+
return false;
561+
}
562+
540563
private static boolean handlePascalReturn(
541564
PrimaryExpressionNode expression, NameResolver resolver) {
542565
if (expression.getChildren().size() != 1) {

delphi-frontend/src/test/java/au/com/integradev/delphi/executor/DelphiSymbolTableExecutorTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,27 @@ void testBestEffortArguments() {
422422
verifyUsages(9, 2, reference(11, 6), reference(11, 11));
423423
}
424424

425+
@Test
426+
void testRoutineReferenceAssignedToProcedural() {
427+
execute("RoutineReferenceAssignedToProcedural.pas");
428+
verifyUsages(
429+
10,
430+
9,
431+
reference(21, 17),
432+
reference(25, 35),
433+
reference(27, 5),
434+
reference(28, 10),
435+
reference(32, 28));
436+
verifyUsages(
437+
15,
438+
9,
439+
reference(22, 19),
440+
reference(25, 40),
441+
reference(27, 10),
442+
reference(28, 5),
443+
reference(33, 31));
444+
}
445+
425446
@Test
426447
void testClassReferenceMethodResolution() {
427448
execute("classReferences/MethodResolution.pas");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
unit RoutineReferenceAssignedToProcedural;
2+
3+
interface
4+
5+
implementation
6+
7+
type
8+
TFoo = function(const A: Integer; B: string; var C: Variant): Boolean;
9+
10+
function Bar(const A: Integer; B: string; var C: Variant): Boolean;
11+
begin
12+
Result := True;
13+
end;
14+
15+
function Baz(const A: Integer; B: string; var C: Variant): Boolean;
16+
begin
17+
Result := False;
18+
end;
19+
20+
var
21+
VarFoo: TFoo = Bar;
22+
ConstFoo: TFoo = Baz;
23+
24+
const
25+
FooArray: array[0..1] of TFoo = (Bar, Baz);
26+
MultiFooArray: array[0..1, 0..1] of TFoo = (
27+
(Bar, Baz),
28+
(Baz, Bar)
29+
);
30+
31+
initialization
32+
var InlineVarFoo: TFoo := Bar;
33+
const InlineConstFoo: TFoo = Baz;
34+
35+
end.

0 commit comments

Comments
 (0)