Skip to content

Improve handling for various intrinsics #383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Support for the `AtomicCmpExchange128` intrinsic routine.
- Support for the `GetTypeKind` intrinsic routine.
- Support for the `OpenString` intrinsic type.
- **API:** `TypeParameterNode::getTypeParameters` method.
- **API:** `InterfaceTypeNode::getGuidExpression` method.
- **API:** `AttributeNode::getExpression` method.

### Changed

- Issue locations no longer span the entire routine declaration in `RoutineName`.
- Improve type modeling around the `VarArg*` intrinsic routines.

### Deprecated

Expand All @@ -31,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Type resolution failures on `as` casts where the type is returned from a routine invocation.
- Inaccurate type resolution when calling a constructor on a class reference type.
- Grammar ambiguity causing attributes to be misinterpreted as interface GUIDs.
- Failure to resolve invocations of `System.IsManagedType` where a value is passed.

## [1.16.0] - 2025-05-09

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,15 @@ private Path createStandardLibrary() {
+ " TCustomAttribute = class(TObject)\n"
+ " end;\n"
+ "\n"
+ " TVarArgList = record\n"
+ " end;\n"
+ "\n"
+ " TTypeKind = (\n"
+ " tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat, tkString, tkSet,\n"
+ " tkClass, tkMethod, tkWChar, tkLString, tkWString, tkVariant, tkArray,\n"
+ " tkClassRef, tkPointer, tkProcedure, tkMRecord\n"
+ " );\n"
+ "\n"
+ "implementation\n"
+ "\n"
+ "end.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import au.com.integradev.delphi.type.TypeUtils;
import au.com.integradev.delphi.type.factory.ClassReferenceTypeImpl;
import au.com.integradev.delphi.type.factory.PointerTypeImpl;
import au.com.integradev.delphi.type.intrinsic.IntrinsicsInjector;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterables;
import java.nio.file.Path;
Expand Down Expand Up @@ -269,6 +270,22 @@ public Data visit(DelphiAst node, Data data) {
return super.visit(node, data);
}

@Override
public Data visit(InterfaceSectionNode node, Data data) {
DelphiScope scope = Objects.requireNonNull(data.getUnitDeclaration()).getScope();

if (scope instanceof SystemScope) {
IntrinsicsInjector injector = new IntrinsicsInjector(data.typeFactory);
injector.injectTypes(scope);
injector.injectConstants(scope);
super.visit(node, data);
injector.injectRoutines(scope);
return data;
}

return super.visit(node, data);
}

@Override
public Data visit(ImplementationSectionNode node, Data data) {
return data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/
package au.com.integradev.delphi.symbol.scope;

import au.com.integradev.delphi.type.intrinsic.IntrinsicsInjector;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.NameDeclaration;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.TypeNameDeclaration;
import org.sonar.plugins.communitydelphi.api.symbol.scope.SystemScope;
Expand All @@ -32,12 +31,6 @@ public class SystemScopeImpl extends FileScopeImpl implements SystemScope {

public SystemScopeImpl(TypeFactory typeFactory) {
super("System");
injectIntrinsics(typeFactory);
}

private void injectIntrinsics(TypeFactory typeFactory) {
IntrinsicsInjector injector = new IntrinsicsInjector(typeFactory);
injector.inject(this);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ private void createIntrinsicTypes() {
addString(IntrinsicType.UNICODESTRING, pointerSize(), IntrinsicType.WIDECHAR);
addString(IntrinsicType.SHORTSTRING, 256, IntrinsicType.ANSICHAR);

addWeakAlias(IntrinsicType.OPENSTRING, IntrinsicType.SHORTSTRING);

if (isStringUnicode()) {
addWeakAlias(IntrinsicType.STRING, IntrinsicType.UNICODESTRING);
addWeakAlias(IntrinsicType.CHAR, IntrinsicType.WIDECHAR);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Sonar Delphi Plugin
* Copyright (C) 2025 Integrated Application Development
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package au.com.integradev.delphi.type.intrinsic;

import org.sonar.plugins.communitydelphi.api.type.IntrinsicType;

final class IntrinsicConstant {
private final String name;
private final IntrinsicType type;

public IntrinsicConstant(String name, IntrinsicType type) {
this.name = name;
this.type = type;
}

public String getName() {
return name;
}

public IntrinsicType getType() {
return type;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import org.sonar.plugins.communitydelphi.api.symbol.Qualifiable;
import org.sonar.plugins.communitydelphi.api.symbol.QualifiedName;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineKind;
import org.sonar.plugins.communitydelphi.api.symbol.declaration.TypedDeclaration;
import org.sonar.plugins.communitydelphi.api.symbol.scope.DelphiScope;
import org.sonar.plugins.communitydelphi.api.type.Type;
import org.sonar.plugins.communitydelphi.api.type.TypeFactory;

Expand Down Expand Up @@ -123,8 +125,9 @@ Builder hasDefaultValue(boolean hasDefaultValue) {
return this;
}

IntrinsicParameterData build() {
return new IntrinsicParameterData(type, isOut, isVar, isConst, hasDefaultValue);
IntrinsicParameterData build(DelphiScope scope) {
Type resolvedType = resolveType(type, scope);
return new IntrinsicParameterData(resolvedType, isOut, isVar, isConst, hasDefaultValue);
}
}
}
Expand Down Expand Up @@ -185,26 +188,43 @@ Builder returns(Type returnType) {
return this;
}

IntrinsicRoutine build() {
IntrinsicRoutine build(DelphiScope scope) {
return new IntrinsicRoutine(
routineName, buildParameters(), returnType, variadicParameter != null);
routineName, buildParameters(scope), buildReturnType(scope), variadicParameter != null);
}

private List<IntrinsicParameterData> buildParameters() {
private List<IntrinsicParameterData> buildParameters(DelphiScope scope) {
List<IntrinsicParameterData> result = new ArrayList<>();

for (int i = 0; i < parameters.size(); ++i) {
IntrinsicParameterData.Builder paramBuilder = parameters.get(i);
paramBuilder.hasDefaultValue(requiredParameters != -1 && i >= requiredParameters);
result.add(paramBuilder.build());
result.add(paramBuilder.build(scope));
}

if (variadicParameter != null) {
variadicParameter.hasDefaultValue(true);
result.add(variadicParameter.build());
result.add(variadicParameter.build(scope));
}

return result;
}

private Type buildReturnType(DelphiScope scope) {
return resolveType(returnType, scope);
}
}

private static Type resolveType(Type type, DelphiScope scope) {
if (type.isUnresolved()) {
String simpleName = type.getImage();
type =
scope.getTypeDeclarations().stream()
.filter(declaration -> declaration.getName().equalsIgnoreCase(simpleName))
.map(TypedDeclaration::getType)
.findFirst()
.orElse(type);
}
return type;
}
}
Loading