Skip to content

Commit 0b11382

Browse files
cirrasfourls
authored andcommitted
Implement full support for generic constraints
1 parent 635b533 commit 0b11382

37 files changed

+1441
-36
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- **API:** `EnumeratorOccurrence::getCurrent` method.
1616
- **API:** `ForInStatementNode.getEnumeratorOccurrence` method.
1717
- **API:** `TypeOfTypeNode::getTypeReferenceNode` method.
18+
- **API:** `NameReferenceNode::getFirstName` method.
19+
- **API:** `DelphiTokenType.TYPE_CONSTRAINT` token type.
20+
- **API:** `ConstraintNode` node type.
21+
- **API:** `ClassConstraintNode` node type.
22+
- **API:** `ConstructorConstraintNode` node type.
23+
- **API:** `RecordConstraintNode` node type.
24+
- **API:** `TypeConstraintNode` node type.
25+
- **API:** `TypeParameterNode::getConstraintNodes` method.
26+
- **API:** `TypeParameterType::constraintItems` method.
27+
- **API:** `Constraint` type.
28+
- **API:** `Constraint.ClassConstraint` type.
29+
- **API:** `Constraint.ConstructorConstraint` type.
30+
- **API:** `Constraint.RecordConstraint` type.
31+
- **API:** `Constraint.TypeConstraint` type.
1832

1933
### Changed
2034

2135
- Detect tab-indented multiline strings in `TabulationCharacter`.
2236
- Improve support for evaluating name references in compiler directive expressions.
37+
- Improve overload resolution in cases involving generic type parameter constraints.
2338

2439
### Deprecated
2540

@@ -29,6 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2944
`getEnumeratorOccurrence` instead.
3045
- **API:** `ForInStatementNode::getCurrentDeclaration` method, get the declaration through
3146
`getEnumeratorOccurrence` instead.
47+
- **API:** `TypeParameterNode::getTypeConstraintNodes` method, use `getConstraintNodes` instead.
48+
- **API:** `TypeParameterType::constraints` method, use `constraintItems` instead.
3249

3350
### Fixed
3451

@@ -39,6 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3956
- Name resolution failures in legacy initialization sections referencing the implementation section.
4057
- Name resolution failures whena accessing ancestors of enclosing types from nested type methods.
4158
- Name resolution failures on invocations of methods with generic open array parameters.
59+
- Name resolution failures around `Create` calls on types with `constructor` constraints.
4260
- Incorrect file position calculation for multiline string tokens.
4361
- Analysis errors around `type of` type declarations.
4462

delphi-frontend/src/main/antlr3/au/com/integradev/delphi/antlr/Delphi.g

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ tokens {
6464
TkCompilerDirective;
6565
TkRealNumber;
6666
TkTypeParameter;
67+
TkTypeConstraint;
6768
TkForLoopVar;
6869
TkArrayAccessorNode;
6970
TkArrayConstructor;
@@ -780,10 +781,10 @@ typeParameter : nameDeclaration (',' nameDeclaration)* (':' gene
780781
nameDeclaration (nameDeclaration)* (genericConstraint genericConstraint*)?
781782
)
782783
;
783-
genericConstraint : typeReference
784-
| RECORD
785-
| CLASS
786-
| CONSTRUCTOR
784+
genericConstraint : typeReference -> ^(TkTypeConstraint<TypeConstraintNodeImpl> typeReference)
785+
| RECORD<RecordConstraintNodeImpl>^
786+
| CLASS<ClassConstraintNodeImpl>^
787+
| CONSTRUCTOR<ConstructorConstraintNodeImpl>^
787788
;
788789
genericArguments : '<' typeReferenceOrStringOrFile (',' typeReferenceOrStringOrFile)* '>'
789790
-> ^(TkGenericArguments<GenericArgumentsNodeImpl> '<' typeReferenceOrStringOrFile (',' typeReferenceOrStringOrFile)* '>')
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2025 Integrated Application Development
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
18+
*/
19+
package au.com.integradev.delphi.antlr.ast.node;
20+
21+
import au.com.integradev.delphi.antlr.ast.visitors.DelphiParserVisitor;
22+
import au.com.integradev.delphi.type.generic.constraint.ClassConstraintImpl;
23+
import org.antlr.runtime.Token;
24+
import org.sonar.plugins.communitydelphi.api.ast.ClassConstraintNode;
25+
import org.sonar.plugins.communitydelphi.api.type.Constraint;
26+
27+
public final class ClassConstraintNodeImpl extends DelphiNodeImpl implements ClassConstraintNode {
28+
public ClassConstraintNodeImpl(Token token) {
29+
super(token);
30+
}
31+
32+
@Override
33+
public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
34+
return visitor.visit(this, data);
35+
}
36+
37+
@Override
38+
public Constraint getConstraint() {
39+
return ClassConstraintImpl.instance();
40+
}
41+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2025 Integrated Application Development
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
18+
*/
19+
package au.com.integradev.delphi.antlr.ast.node;
20+
21+
import au.com.integradev.delphi.antlr.ast.visitors.DelphiParserVisitor;
22+
import au.com.integradev.delphi.type.generic.constraint.ConstructorConstraintImpl;
23+
import org.antlr.runtime.Token;
24+
import org.sonar.plugins.communitydelphi.api.ast.ConstructorConstraintNode;
25+
import org.sonar.plugins.communitydelphi.api.type.Constraint;
26+
27+
public final class ConstructorConstraintNodeImpl extends DelphiNodeImpl
28+
implements ConstructorConstraintNode {
29+
public ConstructorConstraintNodeImpl(Token token) {
30+
super(token);
31+
}
32+
33+
@Override
34+
public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
35+
return visitor.visit(this, data);
36+
}
37+
38+
@Override
39+
public Constraint getConstraint() {
40+
return ConstructorConstraintImpl.instance();
41+
}
42+
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
import java.util.List;
2525
import java.util.stream.Collectors;
2626
import org.antlr.runtime.Token;
27+
import org.sonar.plugins.communitydelphi.api.ast.ConstraintNode;
2728
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
2829
import org.sonar.plugins.communitydelphi.api.ast.GenericDefinitionNode;
2930
import org.sonar.plugins.communitydelphi.api.ast.NameDeclarationNode;
3031
import org.sonar.plugins.communitydelphi.api.ast.TypeParameterNode;
31-
import org.sonar.plugins.communitydelphi.api.type.Type;
32+
import org.sonar.plugins.communitydelphi.api.type.Constraint;
3233
import org.sonar.plugins.communitydelphi.api.type.Type.TypeParameterType;
33-
import org.sonar.plugins.communitydelphi.api.type.Typed;
3434

3535
public final class GenericDefinitionNodeImpl extends DelphiNodeImpl
3636
implements GenericDefinitionNode {
@@ -56,9 +56,9 @@ public List<TypeParameter> getTypeParameters() {
5656
ImmutableList.Builder<TypeParameter> builder = ImmutableList.builder();
5757

5858
for (TypeParameterNode parameterNode : getTypeParameterNodes()) {
59-
List<Type> constraints =
60-
parameterNode.getTypeConstraintNodes().stream()
61-
.map(Typed::getType)
59+
List<Constraint> constraints =
60+
parameterNode.getConstraintNodes().stream()
61+
.map(ConstraintNode::getConstraint)
6262
.collect(Collectors.toUnmodifiableList());
6363

6464
for (NameDeclarationNode name : parameterNode.getTypeParameterNameNodes()) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,15 @@ public Type getType() {
155155
}
156156
}
157157

158+
@Override
159+
public NameReferenceNode getFirstName() {
160+
NameReferenceNode result = this;
161+
while (result.getParent() instanceof NameReferenceNode) {
162+
result = (NameReferenceNode) result.getParent();
163+
}
164+
return result;
165+
}
166+
158167
@Override
159168
public NameReferenceNode getLastName() {
160169
List<NameReferenceNode> flatNames = flatten();
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2025 Integrated Application Development
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
18+
*/
19+
package au.com.integradev.delphi.antlr.ast.node;
20+
21+
import au.com.integradev.delphi.antlr.ast.visitors.DelphiParserVisitor;
22+
import au.com.integradev.delphi.type.generic.constraint.RecordConstraintImpl;
23+
import org.antlr.runtime.Token;
24+
import org.sonar.plugins.communitydelphi.api.ast.RecordConstraintNode;
25+
import org.sonar.plugins.communitydelphi.api.type.Constraint;
26+
27+
public final class RecordConstraintNodeImpl extends DelphiNodeImpl implements RecordConstraintNode {
28+
public RecordConstraintNodeImpl(Token token) {
29+
super(token);
30+
}
31+
32+
@Override
33+
public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
34+
return visitor.visit(this, data);
35+
}
36+
37+
@Override
38+
public Constraint getConstraint() {
39+
return RecordConstraintImpl.instance();
40+
}
41+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2025 Integrated Application Development
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
18+
*/
19+
package au.com.integradev.delphi.antlr.ast.node;
20+
21+
import au.com.integradev.delphi.antlr.ast.visitors.DelphiParserVisitor;
22+
import au.com.integradev.delphi.type.generic.constraint.TypeConstraintImpl;
23+
import org.antlr.runtime.Token;
24+
import org.sonar.plugins.communitydelphi.api.ast.TypeConstraintNode;
25+
import org.sonar.plugins.communitydelphi.api.ast.TypeReferenceNode;
26+
import org.sonar.plugins.communitydelphi.api.type.Constraint;
27+
28+
public final class TypeConstraintNodeImpl extends DelphiNodeImpl implements TypeConstraintNode {
29+
private Constraint constraint;
30+
31+
public TypeConstraintNodeImpl(Token token) {
32+
super(token);
33+
}
34+
35+
public TypeConstraintNodeImpl(int tokenType) {
36+
super(tokenType);
37+
}
38+
39+
@Override
40+
public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
41+
return visitor.visit(this, data);
42+
}
43+
44+
@Override
45+
public TypeReferenceNode getTypeNode() {
46+
return (TypeReferenceNode) getChild(0);
47+
}
48+
49+
@Override
50+
public Constraint getConstraint() {
51+
if (constraint == null) {
52+
constraint = new TypeConstraintImpl(getTypeNode().getType());
53+
}
54+
return constraint;
55+
}
56+
}

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020

2121
import au.com.integradev.delphi.antlr.ast.visitors.DelphiParserVisitor;
2222
import java.util.List;
23+
import java.util.stream.Collectors;
2324
import org.antlr.runtime.Token;
25+
import org.sonar.plugins.communitydelphi.api.ast.ConstraintNode;
2426
import org.sonar.plugins.communitydelphi.api.ast.NameDeclarationNode;
27+
import org.sonar.plugins.communitydelphi.api.ast.TypeConstraintNode;
2528
import org.sonar.plugins.communitydelphi.api.ast.TypeParameterNode;
2629
import org.sonar.plugins.communitydelphi.api.ast.TypeReferenceNode;
2730

@@ -44,8 +47,18 @@ public List<NameDeclarationNode> getTypeParameterNameNodes() {
4447
return findChildrenOfType(NameDeclarationNode.class);
4548
}
4649

50+
@SuppressWarnings("removal")
4751
@Override
4852
public List<TypeReferenceNode> getTypeConstraintNodes() {
49-
return findChildrenOfType(TypeReferenceNode.class);
53+
return getConstraintNodes().stream()
54+
.filter(TypeConstraintNode.class::isInstance)
55+
.map(TypeConstraintNode.class::cast)
56+
.map(TypeConstraintNode::getTypeNode)
57+
.collect(Collectors.toList());
58+
}
59+
60+
@Override
61+
public List<ConstraintNode> getConstraintNodes() {
62+
return findChildrenOfType(ConstraintNode.class);
5063
}
5164
}

delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/visitors/DelphiParserVisitor.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.sonar.plugins.communitydelphi.api.ast.BinaryExpressionNode;
4141
import org.sonar.plugins.communitydelphi.api.ast.CaseItemStatementNode;
4242
import org.sonar.plugins.communitydelphi.api.ast.CaseStatementNode;
43+
import org.sonar.plugins.communitydelphi.api.ast.ClassConstraintNode;
4344
import org.sonar.plugins.communitydelphi.api.ast.ClassHelperTypeNode;
4445
import org.sonar.plugins.communitydelphi.api.ast.ClassReferenceTypeNode;
4546
import org.sonar.plugins.communitydelphi.api.ast.ClassTypeNode;
@@ -49,6 +50,8 @@
4950
import org.sonar.plugins.communitydelphi.api.ast.ConstDeclarationNode;
5051
import org.sonar.plugins.communitydelphi.api.ast.ConstSectionNode;
5152
import org.sonar.plugins.communitydelphi.api.ast.ConstStatementNode;
53+
import org.sonar.plugins.communitydelphi.api.ast.ConstraintNode;
54+
import org.sonar.plugins.communitydelphi.api.ast.ConstructorConstraintNode;
5255
import org.sonar.plugins.communitydelphi.api.ast.ContainsClauseNode;
5356
import org.sonar.plugins.communitydelphi.api.ast.DelphiAst;
5457
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
@@ -117,6 +120,7 @@
117120
import org.sonar.plugins.communitydelphi.api.ast.RaiseStatementNode;
118121
import org.sonar.plugins.communitydelphi.api.ast.RangeExpressionNode;
119122
import org.sonar.plugins.communitydelphi.api.ast.RealLiteralNode;
123+
import org.sonar.plugins.communitydelphi.api.ast.RecordConstraintNode;
120124
import org.sonar.plugins.communitydelphi.api.ast.RecordExpressionItemNode;
121125
import org.sonar.plugins.communitydelphi.api.ast.RecordExpressionNode;
122126
import org.sonar.plugins.communitydelphi.api.ast.RecordHelperTypeNode;
@@ -144,6 +148,7 @@
144148
import org.sonar.plugins.communitydelphi.api.ast.SubRangeTypeNode;
145149
import org.sonar.plugins.communitydelphi.api.ast.TextLiteralNode;
146150
import org.sonar.plugins.communitydelphi.api.ast.TryStatementNode;
151+
import org.sonar.plugins.communitydelphi.api.ast.TypeConstraintNode;
147152
import org.sonar.plugins.communitydelphi.api.ast.TypeDeclarationNode;
148153
import org.sonar.plugins.communitydelphi.api.ast.TypeNode;
149154
import org.sonar.plugins.communitydelphi.api.ast.TypeOfTypeNode;
@@ -745,4 +750,25 @@ default T visit(WhileStatementNode node, T data) {
745750
default T visit(WithStatementNode node, T data) {
746751
return visit((StatementNode) node, data);
747752
}
753+
754+
/* Constraints */
755+
default T visit(ConstraintNode node, T data) {
756+
return visit((DelphiNode) node, data);
757+
}
758+
759+
default T visit(ClassConstraintNode node, T data) {
760+
return visit((ConstraintNode) node, data);
761+
}
762+
763+
default T visit(ConstructorConstraintNode node, T data) {
764+
return visit((ConstraintNode) node, data);
765+
}
766+
767+
default T visit(RecordConstraintNode node, T data) {
768+
return visit((ConstraintNode) node, data);
769+
}
770+
771+
default T visit(TypeConstraintNode node, T data) {
772+
return visit((ConstraintNode) node, data);
773+
}
748774
}

0 commit comments

Comments
 (0)