diff --git a/CHANGELOG.md b/CHANGELOG.md index 11c34290f..830961127 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **API:** `EnumeratorOccurrence::getMoveNext` method. - **API:** `EnumeratorOccurrence::getCurrent` method. - **API:** `ForInStatementNode.getEnumeratorOccurrence` method. +- **API:** `TypeOfTypeNode::getTypeReferenceNode` method. ### Changed @@ -37,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - False positives on enums that are never referenced by name (but have used values) in `UnusedType`. - Name resolution failures in legacy initialization sections referencing the implementation section. - Incorrect file position calculation for multiline string tokens. +- Analysis errors around `type of` type declarations. ## [1.15.0] - 2025-04-03 diff --git a/delphi-frontend/src/main/antlr3/au/com/integradev/delphi/antlr/Delphi.g b/delphi-frontend/src/main/antlr3/au/com/integradev/delphi/antlr/Delphi.g index 5d30ad4cc..11947bd7c 100644 --- a/delphi-frontend/src/main/antlr3/au/com/integradev/delphi/antlr/Delphi.g +++ b/delphi-frontend/src/main/antlr3/au/com/integradev/delphi/antlr/Delphi.g @@ -646,7 +646,7 @@ simpleProcedureType : procedureTypeHeading -> ^(TkProcedureType^ routineParameters? routineReturnType? ((';')? interfaceDirective)* | PROCEDURE^ routineParameters? ((';')? interfaceDirective)* ; -typeOfType : TYPE^ OF typeDecl +typeOfType : TYPE^ OF typeReference ; strongAliasType : TYPE^ typeReferenceOrStringOrFile codePageExpression? ; diff --git a/delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/TypeOfTypeNodeImpl.java b/delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/TypeOfTypeNodeImpl.java index f6615a0ec..a01a7c716 100644 --- a/delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/TypeOfTypeNodeImpl.java +++ b/delphi-frontend/src/main/java/au/com/integradev/delphi/antlr/ast/node/TypeOfTypeNodeImpl.java @@ -21,8 +21,9 @@ import au.com.integradev.delphi.antlr.ast.visitors.DelphiParserVisitor; import javax.annotation.Nonnull; import org.antlr.runtime.Token; -import org.sonar.plugins.communitydelphi.api.ast.TypeNode; +import org.sonar.plugins.communitydelphi.api.ast.TypeDeclarationNode; import org.sonar.plugins.communitydelphi.api.ast.TypeOfTypeNode; +import org.sonar.plugins.communitydelphi.api.ast.TypeReferenceNode; import org.sonar.plugins.communitydelphi.api.type.Type; public final class TypeOfTypeNodeImpl extends TypeNodeImpl implements TypeOfTypeNode { @@ -35,9 +36,19 @@ public T accept(DelphiParserVisitor visitor, T data) { return visitor.visit(this, data); } + @Override + public TypeReferenceNode getTypeReferenceNode() { + return (TypeReferenceNode) getChild(1); + } + @Override @Nonnull protected Type createType() { - return ((TypeNode) getChild(0)).getType(); + String image = null; + if (parent instanceof TypeDeclarationNode) { + image = ((TypeDeclarationNode) parent).fullyQualifiedName(); + } + Type type = getTypeReferenceNode().getType(); + return getTypeFactory().classOf(image, type); } } diff --git a/delphi-frontend/src/main/java/org/sonar/plugins/communitydelphi/api/ast/TypeOfTypeNode.java b/delphi-frontend/src/main/java/org/sonar/plugins/communitydelphi/api/ast/TypeOfTypeNode.java index bc63b87bf..d93d4956c 100644 --- a/delphi-frontend/src/main/java/org/sonar/plugins/communitydelphi/api/ast/TypeOfTypeNode.java +++ b/delphi-frontend/src/main/java/org/sonar/plugins/communitydelphi/api/ast/TypeOfTypeNode.java @@ -18,4 +18,6 @@ */ package org.sonar.plugins.communitydelphi.api.ast; -public interface TypeOfTypeNode extends TypeNode {} +public interface TypeOfTypeNode extends TypeNode { + TypeReferenceNode getTypeReferenceNode(); +} diff --git a/delphi-frontend/src/test/java/au/com/integradev/delphi/executor/DelphiSymbolTableExecutorTest.java b/delphi-frontend/src/test/java/au/com/integradev/delphi/executor/DelphiSymbolTableExecutorTest.java index 19970f82a..e52a8d60f 100644 --- a/delphi-frontend/src/test/java/au/com/integradev/delphi/executor/DelphiSymbolTableExecutorTest.java +++ b/delphi-frontend/src/test/java/au/com/integradev/delphi/executor/DelphiSymbolTableExecutorTest.java @@ -421,6 +421,12 @@ void testClassReferenceConstructorTypeResolution() { verifyUsages(8, 16, reference(22, 11)); } + @Test + void testClassReferenceTypeOf() { + execute("classReferences/TypeOf.pas"); + verifyUsages(10, 10, reference(17, 2)); + } + @Test void testSimpleForwardDeclarations() { execute("forwardDeclarations/Simple.pas"); diff --git a/delphi-frontend/src/test/resources/au/com/integradev/delphi/symbol/classReferences/TypeOf.pas b/delphi-frontend/src/test/resources/au/com/integradev/delphi/symbol/classReferences/TypeOf.pas new file mode 100644 index 000000000..3bd2e8695 --- /dev/null +++ b/delphi-frontend/src/test/resources/au/com/integradev/delphi/symbol/classReferences/TypeOf.pas @@ -0,0 +1,20 @@ +unit TypeOf; + +interface + +type + TIntegerType = type of Integer; + +implementation + +procedure Foo(T: TIntegerType); +begin + // do nothing +end; + +procedure Test; +begin + Foo(Integer); +end; + +end. \ No newline at end of file