Skip to content

Commit 83b0a66

Browse files
committed
Persist routine directives into ProceduralType
This was prompted by the realization that `varargs` weren't consistently persisted into procedural type data, causing non-routine procedural types to never be recognized as variadic. Now we simply persist all of the directives, which will also make it easier to factor calling conventions when comparing procedural types for overload resolution.
1 parent a38d11d commit 83b0a66

File tree

18 files changed

+182
-61
lines changed

18 files changed

+182
-61
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- **API:** `ProceduralType::directives` method.
13+
- **API:** `ProceduralTypeNode::getDirectives` method.
14+
- **API:** `ProceduralTypeNode::hasDirective` method.
15+
- **API:** `ProceduralTypeHeadingNode::getDirectives` method.
1216
- **API:** `AnonymousMethodNode::getAnonymousMethodHeading` method.
1317
- **API:** `AnonymousMethodNode::getDirectives` method.
1418
- **API:** `AnonymousMethodNode::hasDirective` method.
@@ -20,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2024

2125
- Parsing errors on `implementation` keywords nested in conditional branches.
2226
- Parsing errors on anonymous methods with routine directives (like calling conventions).
27+
- `IndexOutOfBoundsException` errors around procedural types declared with `varargs` in
28+
`VariableInitialization`.
2329

2430
## [1.10.0] - 2024-10-01
2531

delphi-checks/src/test/java/au/com/integradev/delphi/checks/VariableInitializationCheckTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,6 +1237,25 @@ void testOutParameterInitializedInNestedRoutineShouldNotAddIssue() {
12371237
.verifyNoIssues();
12381238
}
12391239

1240+
// See: https://github.com/integrated-application-development/sonar-delphi/issues/297
1241+
@Test
1242+
void testIssue297ShouldAddIssue() {
1243+
CheckVerifier.newVerifier()
1244+
.withCheck(new VariableInitializationCheck())
1245+
.onFile(
1246+
new DelphiTestUnitBuilder()
1247+
.appendImpl("var")
1248+
.appendImpl(" SetValues: procedure(Values: Integer); cdecl varargs;")
1249+
.appendImpl("")
1250+
.appendImpl("procedure MyProcedure;")
1251+
.appendImpl("var")
1252+
.appendImpl(" Value: Integer;")
1253+
.appendImpl("begin")
1254+
.appendImpl(" SetValues(Value, Value); // Noncompliant")
1255+
.appendImpl("end;"))
1256+
.verifyIssues();
1257+
}
1258+
12401259
private static DelphiTestUnitBuilder createSysUtils() {
12411260
return new DelphiTestUnitBuilder()
12421261
.unitName("System.SysUtils")

delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/AnonymousMethodNodeImpl.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,16 @@ protected Type createType() {
123123
RoutineReturnTypeNode returnTypeNode = getReturnTypeNode();
124124

125125
return ((TypeFactoryImpl) getTypeFactory())
126-
.anonymous(
126+
.createProcedural(
127+
ProceduralKind.ANONYMOUS,
127128
parameters == null
128129
? Collections.emptyList()
129130
: parameters.getParameters().stream()
130131
.map(FormalParameter::create)
131132
.collect(Collectors.toUnmodifiableList()),
132133
returnTypeNode == null
133134
? TypeFactory.voidType()
134-
: returnTypeNode.getTypeNode().getType());
135+
: returnTypeNode.getTypeNode().getType(),
136+
getDirectives());
135137
}
136138
}

delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/ProceduralTypeNodeImpl.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020

2121
import java.util.Collections;
2222
import java.util.List;
23+
import java.util.Set;
2324
import org.antlr.runtime.Token;
2425
import org.sonar.plugins.communitydelphi.api.ast.FormalParameterNode.FormalParameterData;
2526
import org.sonar.plugins.communitydelphi.api.ast.ProceduralTypeNode;
2627
import org.sonar.plugins.communitydelphi.api.ast.ProcedureTypeHeadingNode;
2728
import org.sonar.plugins.communitydelphi.api.ast.RoutineParametersNode;
2829
import org.sonar.plugins.communitydelphi.api.ast.RoutineReturnTypeNode;
30+
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineDirective;
2931
import org.sonar.plugins.communitydelphi.api.type.Type;
3032
import org.sonar.plugins.communitydelphi.api.type.TypeFactory;
3133

@@ -53,4 +55,14 @@ public List<FormalParameterData> getParameters() {
5355
RoutineParametersNode parametersNode = getHeading().getRoutineParametersNode();
5456
return parametersNode == null ? Collections.emptyList() : parametersNode.getParameters();
5557
}
58+
59+
@Override
60+
public Set<RoutineDirective> getDirectives() {
61+
return getHeading().getDirectives();
62+
}
63+
64+
@Override
65+
public boolean hasDirective(RoutineDirective directive) {
66+
return getDirectives().contains(directive);
67+
}
5668
}

delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/ProcedureOfObjectTypeNodeImpl.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.antlr.runtime.Token;
2727
import org.sonar.plugins.communitydelphi.api.ast.ProcedureOfObjectTypeNode;
2828
import org.sonar.plugins.communitydelphi.api.type.Type;
29+
import org.sonar.plugins.communitydelphi.api.type.Type.ProceduralType.ProceduralKind;
2930

3031
public final class ProcedureOfObjectTypeNodeImpl extends ProceduralTypeNodeImpl
3132
implements ProcedureOfObjectTypeNode {
@@ -42,10 +43,12 @@ public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
4243
@Nonnull
4344
protected Type createType() {
4445
return ((TypeFactoryImpl) getTypeFactory())
45-
.ofObject(
46+
.createProcedural(
47+
ProceduralKind.PROCEDURE_OF_OBJECT,
4648
getParameters().stream()
4749
.map(FormalParameter::create)
4850
.collect(Collectors.toUnmodifiableList()),
49-
getReturnType());
51+
getReturnType(),
52+
getDirectives());
5053
}
5154
}

delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/ProcedureReferenceTypeNodeImpl.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.antlr.runtime.Token;
2727
import org.sonar.plugins.communitydelphi.api.ast.ProcedureReferenceTypeNode;
2828
import org.sonar.plugins.communitydelphi.api.type.Type;
29+
import org.sonar.plugins.communitydelphi.api.type.Type.ProceduralType.ProceduralKind;
2930

3031
public final class ProcedureReferenceTypeNodeImpl extends ProceduralTypeNodeImpl
3132
implements ProcedureReferenceTypeNode {
@@ -42,10 +43,12 @@ public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
4243
@Nonnull
4344
protected Type createType() {
4445
return ((TypeFactoryImpl) getTypeFactory())
45-
.reference(
46+
.createProcedural(
47+
ProceduralKind.REFERENCE,
4648
getParameters().stream()
4749
.map(FormalParameter::create)
4850
.collect(Collectors.toUnmodifiableList()),
49-
getReturnType());
51+
getReturnType(),
52+
getDirectives());
5053
}
5154
}

delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/ProcedureTypeHeadingNodeImpl.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,21 @@
1919
package au.com.integradev.delphi.antlr.ast.node;
2020

2121
import au.com.integradev.delphi.antlr.ast.visitors.DelphiParserVisitor;
22+
import com.google.common.collect.ImmutableSet;
23+
import java.util.Set;
2224
import javax.annotation.Nullable;
2325
import org.antlr.runtime.Token;
2426
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
2527
import org.sonar.plugins.communitydelphi.api.ast.ProcedureTypeHeadingNode;
2628
import org.sonar.plugins.communitydelphi.api.ast.RoutineParametersNode;
2729
import org.sonar.plugins.communitydelphi.api.ast.RoutineReturnTypeNode;
30+
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineDirective;
31+
import org.sonar.plugins.communitydelphi.api.token.DelphiToken;
2832

2933
public final class ProcedureTypeHeadingNodeImpl extends DelphiNodeImpl
3034
implements ProcedureTypeHeadingNode {
35+
private Set<RoutineDirective> directives;
36+
3137
public ProcedureTypeHeadingNodeImpl(Token token) {
3238
super(token);
3339
}
@@ -61,6 +67,22 @@ public RoutineReturnTypeNode getRoutineReturnTypeNode() {
6167
return (node instanceof RoutineReturnTypeNode) ? (RoutineReturnTypeNode) node : null;
6268
}
6369

70+
@Override
71+
public Set<RoutineDirective> getDirectives() {
72+
if (directives == null) {
73+
var builder = new ImmutableSet.Builder<RoutineDirective>();
74+
for (DelphiNode child : getChildren()) {
75+
DelphiToken token = child.getToken();
76+
RoutineDirective directive = RoutineDirective.fromToken(token);
77+
if (directive != null) {
78+
builder.add(directive);
79+
}
80+
}
81+
directives = builder.build();
82+
}
83+
return directives;
84+
}
85+
6486
private boolean hasRoutineParametersNode() {
6587
return getRoutineParametersNode() != null;
6688
}

delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/ProcedureTypeNodeImpl.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.antlr.runtime.Token;
2727
import org.sonar.plugins.communitydelphi.api.ast.ProcedureTypeNode;
2828
import org.sonar.plugins.communitydelphi.api.type.Type;
29+
import org.sonar.plugins.communitydelphi.api.type.Type.ProceduralType.ProceduralKind;
2930

3031
public final class ProcedureTypeNodeImpl extends ProceduralTypeNodeImpl
3132
implements ProcedureTypeNode {
@@ -46,10 +47,12 @@ public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
4647
@Nonnull
4748
protected Type createType() {
4849
return ((TypeFactoryImpl) getTypeFactory())
49-
.procedure(
50+
.createProcedural(
51+
ProceduralKind.PROCEDURE,
5052
getParameters().stream()
5153
.map(FormalParameter::create)
5254
.collect(Collectors.toUnmodifiableList()),
53-
getReturnType());
55+
getReturnType(),
56+
getDirectives());
5457
}
5558
}

delphi-frontend/src/main/java/au/com/integradev/delphi/symbol/declaration/RoutineNameDeclarationImpl.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.sonar.plugins.communitydelphi.api.type.Parameter;
5353
import org.sonar.plugins.communitydelphi.api.type.Type;
5454
import org.sonar.plugins.communitydelphi.api.type.Type.ProceduralType;
55+
import org.sonar.plugins.communitydelphi.api.type.Type.ProceduralType.ProceduralKind;
5556
import org.sonar.plugins.communitydelphi.api.type.TypeFactory;
5657
import org.sonar.plugins.communitydelphi.api.type.TypeSpecializationContext;
5758

@@ -112,7 +113,11 @@ public static RoutineNameDeclaration create(
112113
true,
113114
data.getRoutineKind(),
114115
((TypeFactoryImpl) typeFactory)
115-
.routine(createParameters(data), data.getReturnType(), data.isVariadic()),
116+
.createProcedural(
117+
ProceduralKind.ROUTINE,
118+
createParameters(data),
119+
data.getReturnType(),
120+
data.isVariadic() ? Set.of(RoutineDirective.VARARGS) : Collections.emptySet()),
116121
null,
117122
VisibilityType.PUBLIC,
118123
Collections.emptyList(),
@@ -147,7 +152,12 @@ public static RoutineNameDeclarationImpl create(RoutineNode routine, TypeFactory
147152
routine.isClassMethod(),
148153
isCallable,
149154
routine.getRoutineKind(),
150-
((TypeFactoryImpl) typeFactory).routine(createParameters(routine), routine.getReturnType()),
155+
((TypeFactoryImpl) typeFactory)
156+
.createProcedural(
157+
ProceduralKind.ROUTINE,
158+
createParameters(routine),
159+
routine.getReturnType(),
160+
routine.getDirectives()),
151161
routine.getTypeDeclaration(),
152162
routine.getVisibility(),
153163
extractGenericTypeParameters(routine),

delphi-frontend/src/main/java/au/com/integradev/delphi/type/factory/ProceduralTypeImpl.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
import au.com.integradev.delphi.type.generic.GenerifiableTypeImpl;
2222
import com.google.common.collect.Iterables;
2323
import java.util.List;
24+
import java.util.Set;
2425
import java.util.stream.Collectors;
26+
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineDirective;
2527
import org.sonar.plugins.communitydelphi.api.type.Parameter;
2628
import org.sonar.plugins.communitydelphi.api.type.Type;
2729
import org.sonar.plugins.communitydelphi.api.type.Type.ProceduralType;
@@ -32,19 +34,19 @@ public final class ProceduralTypeImpl extends GenerifiableTypeImpl implements Pr
3234
private final ProceduralKind kind;
3335
private final List<Parameter> parameters;
3436
private final Type returnType;
35-
private final boolean variadic;
37+
private final Set<RoutineDirective> directives;
3638

3739
ProceduralTypeImpl(
3840
int size,
3941
ProceduralKind kind,
4042
List<Parameter> parameters,
4143
Type returnType,
42-
boolean variadic) {
44+
Set<RoutineDirective> directives) {
4345
this.size = size;
4446
this.kind = kind;
4547
this.parameters = List.copyOf(parameters);
4648
this.returnType = returnType;
47-
this.variadic = variadic;
49+
this.directives = directives;
4850
}
4951

5052
@Override
@@ -93,14 +95,14 @@ public List<Parameter> parameters() {
9395

9496
@Override
9597
public int parametersCount() {
96-
return variadic ? 255 : parameters().size();
98+
return directives.contains(RoutineDirective.VARARGS) ? 255 : parameters().size();
9799
}
98100

99101
@Override
100102
public Parameter getParameter(int index) {
101103
if (index < parameters().size()) {
102104
return parameters().get(index);
103-
} else if (variadic) {
105+
} else if (directives.contains(RoutineDirective.VARARGS)) {
104106
return Iterables.getLast(parameters());
105107
}
106108

@@ -122,6 +124,11 @@ public ProceduralKind kind() {
122124
return kind;
123125
}
124126

127+
@Override
128+
public Set<RoutineDirective> directives() {
129+
return directives;
130+
}
131+
125132
@Override
126133
public boolean isProcedural() {
127134
return true;
@@ -151,6 +158,6 @@ public GenerifiableTypeImpl doSpecialization(TypeSpecializationContext context)
151158
.map(parameter -> parameter.specialize(context))
152159
.collect(Collectors.toUnmodifiableList()),
153160
returnType.specialize(context),
154-
variadic);
161+
directives);
155162
}
156163
}

0 commit comments

Comments
 (0)