Skip to content

Commit 3d44dca

Browse files
committed
Improve semantic analysis around label and goto statements
1 parent e3ef411 commit 3d44dca

File tree

19 files changed

+274
-19
lines changed

19 files changed

+274
-19
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- **API:** `UsesClauseNode::getImports` method.
1616
- **API:** `InterfaceSectionNode::getUsesClause` method.
1717
- **API:** `ImplementationSectionNode::getUsesClause` method.
18+
- **API:** `LabelNameDeclaration` symbol declaration type.
19+
- **API:** `DelphiScope::getLabelDeclarations` method.
20+
- **API:** `LabelDeclarationNode` node type.
21+
- **API:** `LabelStatementNode::getNameReference` method.
22+
- **API:** `LabelStatementNode::getStatement` method.
23+
- **API:** `GotoStatementNode::getNameReference` method.
24+
25+
### Changed
26+
27+
- Improve semantic analysis around `label` and `goto` statements.
1828

1929
### Fixed
2030

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

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ interfaceDecl : constSection
336336
| routineInterface
337337
| attributeList
338338
;
339-
labelDeclSection : LABEL (label (','!)?)+ ';'
339+
labelDeclSection : LABEL<LabelDeclarationNodeImpl>^ labelNameDeclaration (',' labelNameDeclaration)* ';'
340340
;
341341
constSection : (CONST<ConstSectionNodeImpl>^ | RESOURCESTRING<ConstSectionNodeImpl>^) constDeclaration*
342342
// constSection was changed at some point from "constDeclaration+" to "constDeclaration*" to cater to invalid includes
@@ -871,13 +871,14 @@ statementList : delimitedStatements? -> ^(TkStatementList<Stateme
871871
;
872872
delimitedStatements : (statement | ';')+
873873
;
874-
labelStatement : label ':' statement? -> ^(TkLabelStatement<LabelStatementNodeImpl> label statement?)
874+
labelStatement : {input.LA(2) == COLON}? => labelNameReference ':' statement?
875+
-> ^(TkLabelStatement<LabelStatementNodeImpl> labelNameReference ':' statement?)
875876
;
876877
assignmentStatement : expression ':='<AssignmentStatementNodeImpl>^ expression
877878
;
878879
expressionStatement : expression -> ^(TkExpressionStatement<ExpressionStatementNodeImpl> expression)
879880
;
880-
gotoStatement : GOTO<GotoStatementNodeImpl>^ label
881+
gotoStatement : GOTO<GotoStatementNodeImpl>^ labelNameReference
881882
;
882883
tryStatement : TRY<TryStatementNodeImpl>^ statementList (exceptBlock | finallyBlock) END
883884
;
@@ -998,9 +999,6 @@ keywords : (ABSOLUTE | ABSTRACT | AND | ALIGN | ARRAY | AS |
998999
;
9991000
nameDeclarationList : nameDeclaration (',' nameDeclaration)* -> ^(TkNameDeclarationList<NameDeclarationListNodeImpl> nameDeclaration (',' nameDeclaration)*)
10001001
;
1001-
label : ident
1002-
| intNum
1003-
;
10041002
nameDeclaration : ident -> ^(TkNameDeclaration<SimpleNameDeclarationNodeImpl> ident)
10051003
;
10061004
genericNameDeclaration : ident ('.' extendedIdent)* genericDefinition?
@@ -1026,6 +1024,15 @@ extendedNameReference : extendedIdent genericArguments? ('.' extendedName
10261024
extendedIdent : ident
10271025
| keywords -> ^({changeTokenType(TkIdentifier)})
10281026
;
1027+
labelIdent : ident
1028+
| TkIntNumber -> ^({changeTokenType(TkIdentifier)})
1029+
| TkHexNumber -> ^({changeTokenType(TkIdentifier)})
1030+
| TkBinaryNumber -> ^({changeTokenType(TkIdentifier)})
1031+
;
1032+
labelNameDeclaration : labelIdent -> ^(TkNameDeclaration<SimpleNameDeclarationNodeImpl> labelIdent)
1033+
;
1034+
labelNameReference : labelIdent -> ^(TkNameReference<NameReferenceNodeImpl> labelIdent)
1035+
;
10291036
//----------------------------------------------------------------------------
10301037
// Literals
10311038
//----------------------------------------------------------------------------

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import au.com.integradev.delphi.antlr.ast.visitors.DelphiParserVisitor;
2222
import org.antlr.runtime.Token;
2323
import org.sonar.plugins.communitydelphi.api.ast.GotoStatementNode;
24+
import org.sonar.plugins.communitydelphi.api.ast.NameReferenceNode;
2425

2526
public final class GotoStatementNodeImpl extends DelphiNodeImpl implements GotoStatementNode {
2627
public GotoStatementNodeImpl(Token token) {
@@ -31,4 +32,9 @@ public GotoStatementNodeImpl(Token token) {
3132
public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
3233
return visitor.visit(this, data);
3334
}
35+
36+
@Override
37+
public NameReferenceNode getNameReference() {
38+
return (NameReferenceNode) getChild(0);
39+
}
3440
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2024 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 java.util.List;
23+
import org.antlr.runtime.Token;
24+
import org.sonar.plugins.communitydelphi.api.ast.LabelDeclarationNode;
25+
import org.sonar.plugins.communitydelphi.api.ast.NameDeclarationNode;
26+
27+
public final class LabelDeclarationNodeImpl extends DelphiNodeImpl implements LabelDeclarationNode {
28+
public LabelDeclarationNodeImpl(Token token) {
29+
super(token);
30+
}
31+
32+
public LabelDeclarationNodeImpl(int tokenType) {
33+
super(tokenType);
34+
}
35+
36+
@Override
37+
public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
38+
return visitor.visit(this, data);
39+
}
40+
41+
@Override
42+
public List<NameDeclarationNode> getDeclarations() {
43+
return findChildrenOfType(NameDeclarationNode.class);
44+
}
45+
}

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

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

2121
import au.com.integradev.delphi.antlr.ast.visitors.DelphiParserVisitor;
22+
import javax.annotation.Nullable;
2223
import org.antlr.runtime.Token;
2324
import org.sonar.plugins.communitydelphi.api.ast.LabelStatementNode;
25+
import org.sonar.plugins.communitydelphi.api.ast.NameReferenceNode;
26+
import org.sonar.plugins.communitydelphi.api.ast.StatementNode;
2427

2528
public final class LabelStatementNodeImpl extends DelphiNodeImpl implements LabelStatementNode {
2629
public LabelStatementNodeImpl(Token token) {
@@ -35,4 +38,15 @@ public LabelStatementNodeImpl(int tokenType) {
3538
public <T> T accept(DelphiParserVisitor<T> visitor, T data) {
3639
return visitor.visit(this, data);
3740
}
41+
42+
@Override
43+
public NameReferenceNode getNameReference() {
44+
return (NameReferenceNode) getChild(0);
45+
}
46+
47+
@Override
48+
@Nullable
49+
public StatementNode getStatement() {
50+
return (StatementNode) getChild(2);
51+
}
3852
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public enum DeclarationKind {
8787
IMPORT,
8888
INLINE_CONST,
8989
INLINE_VAR,
90+
LABEL,
9091
LOOP_VAR,
9192
ROUTINE,
9293
PARAMETER,

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

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
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.ImmutableMap;
2223
import java.util.Map;
2324
import java.util.Objects;
2425
import org.antlr.runtime.Token;
@@ -29,17 +30,19 @@
2930
public final class SimpleNameDeclarationNodeImpl extends NameDeclarationNodeImpl
3031
implements SimpleNameDeclarationNode {
3132
private static final Map<Class<?>, DeclarationKind> PARENT_NODE_KIND_MAP =
32-
Map.of(
33-
ConstDeclarationNodeImpl.class, DeclarationKind.CONST,
34-
ConstStatementNodeImpl.class, DeclarationKind.INLINE_CONST,
35-
EnumElementNodeImpl.class, DeclarationKind.ENUM_ELEMENT,
36-
ExceptItemNodeImpl.class, DeclarationKind.EXCEPT_ITEM,
37-
ForLoopVarDeclarationNodeImpl.class, DeclarationKind.LOOP_VAR,
38-
RoutineNameNodeImpl.class, DeclarationKind.ROUTINE,
39-
PropertyNodeImpl.class, DeclarationKind.PROPERTY,
40-
RecordVariantTagNodeImpl.class, DeclarationKind.RECORD_VARIANT_TAG,
41-
TypeDeclarationNodeImpl.class, DeclarationKind.TYPE,
42-
TypeParameterNodeImpl.class, DeclarationKind.TYPE_PARAMETER);
33+
ImmutableMap.<Class<?>, DeclarationKind>builder()
34+
.put(ConstDeclarationNodeImpl.class, DeclarationKind.CONST)
35+
.put(ConstStatementNodeImpl.class, DeclarationKind.INLINE_CONST)
36+
.put(EnumElementNodeImpl.class, DeclarationKind.ENUM_ELEMENT)
37+
.put(ExceptItemNodeImpl.class, DeclarationKind.EXCEPT_ITEM)
38+
.put(LabelDeclarationNodeImpl.class, DeclarationKind.LABEL)
39+
.put(ForLoopVarDeclarationNodeImpl.class, DeclarationKind.LOOP_VAR)
40+
.put(RoutineNameNodeImpl.class, DeclarationKind.ROUTINE)
41+
.put(PropertyNodeImpl.class, DeclarationKind.PROPERTY)
42+
.put(RecordVariantTagNodeImpl.class, DeclarationKind.RECORD_VARIANT_TAG)
43+
.put(TypeDeclarationNodeImpl.class, DeclarationKind.TYPE)
44+
.put(TypeParameterNodeImpl.class, DeclarationKind.TYPE_PARAMETER)
45+
.build();
4346

4447
private static final Map<Class<?>, DeclarationKind> GRANDPARENT_NODE_KIND_MAP =
4548
Map.of(

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
import org.sonar.plugins.communitydelphi.api.ast.InterfaceGuidNode;
8686
import org.sonar.plugins.communitydelphi.api.ast.InterfaceSectionNode;
8787
import org.sonar.plugins.communitydelphi.api.ast.InterfaceTypeNode;
88+
import org.sonar.plugins.communitydelphi.api.ast.LabelDeclarationNode;
8889
import org.sonar.plugins.communitydelphi.api.ast.LabelStatementNode;
8990
import org.sonar.plugins.communitydelphi.api.ast.LibraryDeclarationNode;
9091
import org.sonar.plugins.communitydelphi.api.ast.LocalDeclarationSectionNode;
@@ -312,6 +313,10 @@ default T visit(InterfaceSectionNode node, T data) {
312313
return visit((DelphiNode) node, data);
313314
}
314315

316+
default T visit(LabelDeclarationNode node, T data) {
317+
return visit((DelphiNode) node, data);
318+
}
319+
315320
default T visit(RoutineBodyNode node, T data) {
316321
return visit((DelphiNode) node, data);
317322
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import au.com.integradev.delphi.symbol.ImportResolutionHandler;
3131
import au.com.integradev.delphi.symbol.SymbolicNode;
3232
import au.com.integradev.delphi.symbol.declaration.EnumElementNameDeclarationImpl;
33+
import au.com.integradev.delphi.symbol.declaration.LabelNameDeclarationImpl;
3334
import au.com.integradev.delphi.symbol.declaration.NameDeclarationImpl;
3435
import au.com.integradev.delphi.symbol.declaration.PropertyNameDeclarationImpl;
3536
import au.com.integradev.delphi.symbol.declaration.RoutineNameDeclarationImpl;
@@ -87,10 +88,12 @@
8788
import org.sonar.plugins.communitydelphi.api.ast.FormalParameterNode.FormalParameterData;
8889
import org.sonar.plugins.communitydelphi.api.ast.GenericDefinitionNode;
8990
import org.sonar.plugins.communitydelphi.api.ast.GenericDefinitionNode.TypeParameter;
91+
import org.sonar.plugins.communitydelphi.api.ast.GotoStatementNode;
9092
import org.sonar.plugins.communitydelphi.api.ast.IfStatementNode;
9193
import org.sonar.plugins.communitydelphi.api.ast.ImplementationSectionNode;
9294
import org.sonar.plugins.communitydelphi.api.ast.InitializationSectionNode;
9395
import org.sonar.plugins.communitydelphi.api.ast.InterfaceSectionNode;
96+
import org.sonar.plugins.communitydelphi.api.ast.LabelDeclarationNode;
9497
import org.sonar.plugins.communitydelphi.api.ast.LabelStatementNode;
9598
import org.sonar.plugins.communitydelphi.api.ast.MethodResolutionClauseNode;
9699
import org.sonar.plugins.communitydelphi.api.ast.NameDeclarationNode;
@@ -354,6 +357,14 @@ public Data visit(ExceptItemNode node, Data data) {
354357
return visitScope(node, data);
355358
}
356359

360+
@Override
361+
public Data visit(LabelDeclarationNode node, Data data) {
362+
for (NameDeclarationNode declarationNode : node.getDeclarations()) {
363+
data.addDeclaration(new LabelNameDeclarationImpl(declarationNode), declarationNode);
364+
}
365+
return DelphiParserVisitor.super.visit(node, data);
366+
}
367+
357368
@Override
358369
public Data visit(RoutineDeclarationNode node, Data data) {
359370
DeclarationScope scope = new DeclarationScopeImpl();
@@ -671,6 +682,7 @@ public Data visit(CaseItemStatementNode node, Data data) {
671682

672683
@Override
673684
public Data visit(LabelStatementNode node, Data data) {
685+
data.nameResolutionHelper.resolve(node.getNameReference());
674686
// Bizarre behavior:
675687
// If a label is the first statement in a given scope (routine, local, etc.), then it
676688
// doesn't get its own local scope!
@@ -778,6 +790,12 @@ public Data visit(AttributeNode node, Data data) {
778790
return data;
779791
}
780792

793+
@Override
794+
public Data visit(GotoStatementNode node, Data data) {
795+
data.nameResolutionHelper.resolve(node.getNameReference());
796+
return data;
797+
}
798+
781799
@Override
782800
public Data visit(TypeSectionNode node, Data data) {
783801
DelphiParserVisitor.super.visit(node, data);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2024 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.symbol.declaration;
20+
21+
import org.sonar.plugins.communitydelphi.api.ast.NameDeclarationNode;
22+
import org.sonar.plugins.communitydelphi.api.symbol.declaration.LabelNameDeclaration;
23+
24+
public class LabelNameDeclarationImpl extends NameDeclarationImpl implements LabelNameDeclaration {
25+
public LabelNameDeclarationImpl(NameDeclarationNode node) {
26+
super(node);
27+
}
28+
}

0 commit comments

Comments
 (0)