Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Name resolution failures when accessing ancestors of enclosing types from nested type methods.
- Name resolution failures on invocations of methods with generic open array parameters.
- Name resolution failures around `Create` calls on types with `constructor` constraints.
- Name resolution failures on `read` and `write` specifiers of indexed properties.
- Incorrect file position calculation for multiline string tokens.
- Analysis errors around `type of` type declarations.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import org.sonar.plugins.communitydelphi.api.symbol.scope.DelphiScope;
import org.sonar.plugins.communitydelphi.api.symbol.scope.FileScope;
import org.sonar.plugins.communitydelphi.api.symbol.scope.RoutineScope;
import org.sonar.plugins.communitydelphi.api.type.IntrinsicType;
import org.sonar.plugins.communitydelphi.api.type.Type;
import org.sonar.plugins.communitydelphi.api.type.Type.AliasType;
import org.sonar.plugins.communitydelphi.api.type.Type.ProceduralType;
Expand Down Expand Up @@ -252,17 +253,15 @@ public void resolve(PropertyNode property) {
if (read != null) {
NameResolver readResolver = createNameResolver();
readResolver.readPrimaryExpression(read.getExpression());
readResolver.disambiguateParameters(property.getParameterTypes());
readResolver.disambiguateParameters(getGetterParameterTypes(property));
readResolver.addToSymbolTable();
}

PropertyWriteSpecifierNode write = property.getWriteSpecifier();
if (write != null) {
List<Type> parameterTypes = new ArrayList<>(property.getParameterTypes());
parameterTypes.add(property.getType());
NameResolver writeResolver = createNameResolver();
writeResolver.readPrimaryExpression(write.getExpression());
writeResolver.disambiguateParameters(parameterTypes);
writeResolver.disambiguateParameters(getSetterParameterTypes(property));
writeResolver.addToSymbolTable();
}

Expand All @@ -272,6 +271,25 @@ public void resolve(PropertyNode property) {
}
}

private List<Type> getGetterParameterTypes(PropertyNode property) {
if (property.getIndexSpecifier() == null) {
return property.getParameterTypes();
}

var parameterTypes = new ArrayList<>(property.getParameterTypes());
parameterTypes.add(typeFactory.getIntrinsic(IntrinsicType.INTEGER));
return parameterTypes;
}

private List<Type> getSetterParameterTypes(PropertyNode property) {
var parameterTypes = new ArrayList<>(property.getParameterTypes());
if (property.getIndexSpecifier() != null) {
parameterTypes.add(typeFactory.getIntrinsic(IntrinsicType.INTEGER));
}
parameterTypes.add(property.getType());
return parameterTypes;
}

public void resolve(RoutineDeclarationNode routine) {
resolveRoutine(routine);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,27 @@ void testSimilarParameterDeclarations() {
verifyUsages(9, 19);
}

@Test
void testProperties() {
execute("Properties.pas");
// Field
verifyUsages(10, 4, reference(19, 33), reference(19, 46));
// Normal getter
verifyUsages(16, 13, reference(20, 33), reference(21, 33));
// Normal setter
verifyUsages(14, 14, reference(20, 50));
// Const setter
verifyUsages(12, 14, reference(21, 50));
// Alias setter
verifyUsages(13, 14, reference(22, 55));
// Alias getter
verifyUsages(17, 13, reference(22, 33));
// Index getter
verifyUsages(29, 13, reference(32, 41));
// Index setter
verifyUsages(30, 14, reference(32, 58));
}

@Test
void testRecords() {
execute("Records.pas");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
unit Properties;

interface

type
TIntAlias = Integer;

TMyObj = class(TObject)
private
FField: Integer;

procedure SetMyFieldConst(const Val: Integer);
procedure SetMyFieldAlias(Val: TIntAlias);
procedure SetMyField(Val: Integer);

function GetMyField: Integer;
function GetMyFieldAlias: TIntAlias;
public
property Prop1: Integer read FField write FField;
property Prop2: Integer read GetMyField write SetMyField;
property Prop3: Integer read GetMyField write SetMyFieldConst;
property Prop4: Integer read GetMyFieldAlias write SetMyFieldAlias;
end;

TIndexObj = class(TObject)
private
FField: TObject;

function GetMyField(Index: Integer): TObject;
procedure SetMyField(Index: Integer; Value: TObject);
public
property Prop1: TObject index 0 read GetMyField write SetMyField;
end;

implementation

end.