Skip to content

Commit 46846b7

Browse files
fourlscirras
authored andcommitted
Disambiguate index property read/write methods correctly
When a property has an `index` specifier, its `read` specifier must be a function with an `Integer` final argument, and its `write` specifier must be a procedure with an `Integer` second-last argument. We were not previously modelling this behaviour, causing `read` and `write` specifier methods to fail to resolve when an `index` property is present.
1 parent 878e99d commit 46846b7

File tree

4 files changed

+81
-4
lines changed

4 files changed

+81
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5959
- Name resolution failures when accessing ancestors of enclosing types from nested type methods.
6060
- Name resolution failures on invocations of methods with generic open array parameters.
6161
- Name resolution failures around `Create` calls on types with `constructor` constraints.
62+
- Name resolution failures on `read` and `write` specifiers of indexed properties.
6263
- Incorrect file position calculation for multiline string tokens.
6364
- Analysis errors around `type of` type declarations.
6465

delphi-frontend/src/main/java/au/com/integradev/delphi/symbol/resolve/NameResolutionHelper.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
import org.sonar.plugins.communitydelphi.api.symbol.scope.DelphiScope;
8282
import org.sonar.plugins.communitydelphi.api.symbol.scope.FileScope;
8383
import org.sonar.plugins.communitydelphi.api.symbol.scope.RoutineScope;
84+
import org.sonar.plugins.communitydelphi.api.type.IntrinsicType;
8485
import org.sonar.plugins.communitydelphi.api.type.Type;
8586
import org.sonar.plugins.communitydelphi.api.type.Type.AliasType;
8687
import org.sonar.plugins.communitydelphi.api.type.Type.ProceduralType;
@@ -252,17 +253,15 @@ public void resolve(PropertyNode property) {
252253
if (read != null) {
253254
NameResolver readResolver = createNameResolver();
254255
readResolver.readPrimaryExpression(read.getExpression());
255-
readResolver.disambiguateParameters(property.getParameterTypes());
256+
readResolver.disambiguateParameters(getGetterParameterTypes(property));
256257
readResolver.addToSymbolTable();
257258
}
258259

259260
PropertyWriteSpecifierNode write = property.getWriteSpecifier();
260261
if (write != null) {
261-
List<Type> parameterTypes = new ArrayList<>(property.getParameterTypes());
262-
parameterTypes.add(property.getType());
263262
NameResolver writeResolver = createNameResolver();
264263
writeResolver.readPrimaryExpression(write.getExpression());
265-
writeResolver.disambiguateParameters(parameterTypes);
264+
writeResolver.disambiguateParameters(getSetterParameterTypes(property));
266265
writeResolver.addToSymbolTable();
267266
}
268267

@@ -272,6 +271,25 @@ public void resolve(PropertyNode property) {
272271
}
273272
}
274273

274+
private List<Type> getGetterParameterTypes(PropertyNode property) {
275+
if (property.getIndexSpecifier() == null) {
276+
return property.getParameterTypes();
277+
}
278+
279+
var parameterTypes = new ArrayList<>(property.getParameterTypes());
280+
parameterTypes.add(typeFactory.getIntrinsic(IntrinsicType.INTEGER));
281+
return parameterTypes;
282+
}
283+
284+
private List<Type> getSetterParameterTypes(PropertyNode property) {
285+
var parameterTypes = new ArrayList<>(property.getParameterTypes());
286+
if (property.getIndexSpecifier() != null) {
287+
parameterTypes.add(typeFactory.getIntrinsic(IntrinsicType.INTEGER));
288+
}
289+
parameterTypes.add(property.getType());
290+
return parameterTypes;
291+
}
292+
275293
public void resolve(RoutineDeclarationNode routine) {
276294
resolveRoutine(routine);
277295
}

delphi-frontend/src/test/java/au/com/integradev/delphi/executor/DelphiSymbolTableExecutorTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,27 @@ void testSimilarParameterDeclarations() {
103103
verifyUsages(9, 19);
104104
}
105105

106+
@Test
107+
void testProperties() {
108+
execute("Properties.pas");
109+
// Field
110+
verifyUsages(10, 4, reference(19, 33), reference(19, 46));
111+
// Normal getter
112+
verifyUsages(16, 13, reference(20, 33), reference(21, 33));
113+
// Normal setter
114+
verifyUsages(14, 14, reference(20, 50));
115+
// Const setter
116+
verifyUsages(12, 14, reference(21, 50));
117+
// Alias setter
118+
verifyUsages(13, 14, reference(22, 55));
119+
// Alias getter
120+
verifyUsages(17, 13, reference(22, 33));
121+
// Index getter
122+
verifyUsages(29, 13, reference(32, 41));
123+
// Index setter
124+
verifyUsages(30, 14, reference(32, 58));
125+
}
126+
106127
@Test
107128
void testRecords() {
108129
execute("Records.pas");
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
unit Properties;
2+
3+
interface
4+
5+
type
6+
TIntAlias = Integer;
7+
8+
TMyObj = class(TObject)
9+
private
10+
FField: Integer;
11+
12+
procedure SetMyFieldConst(const Val: Integer);
13+
procedure SetMyFieldAlias(Val: TIntAlias);
14+
procedure SetMyField(Val: Integer);
15+
16+
function GetMyField: Integer;
17+
function GetMyFieldAlias: TIntAlias;
18+
public
19+
property Prop1: Integer read FField write FField;
20+
property Prop2: Integer read GetMyField write SetMyField;
21+
property Prop3: Integer read GetMyField write SetMyFieldConst;
22+
property Prop4: Integer read GetMyFieldAlias write SetMyFieldAlias;
23+
end;
24+
25+
TIndexObj = class(TObject)
26+
private
27+
FField: TObject;
28+
29+
function GetMyField(Index: Integer): TObject;
30+
procedure SetMyField(Index: Integer; Value: TObject);
31+
public
32+
property Prop1: TObject index 0 read GetMyField write SetMyField;
33+
end;
34+
35+
implementation
36+
37+
end.

0 commit comments

Comments
 (0)