Skip to content

Commit

Permalink
Dart: fix problems with default values that use collection types (#1622)
Browse files Browse the repository at this point in the history
This series fixes problems that occur when either @immutable
or @PositionalDefaults annotation is used in combination with
collection types.

-------- @PositionalDefaults --------
The usage of 'PositionalDefaults' annotation
combined with nullable collection field that has 'null'
default value yields the code that does not compile.

The generator blindly applies 'const' keyword before
the default value for collections. A special 'null' value is
not taken into account.

-------- @immutable --------
Usage of 'Immutable' annotation combined
with collection fields that have default values yields the
code that does not compile.

The generator does not apply 'const' keyword before the calls
to constructors of collections. It is required, because the
constructor of 'Immutable' structure is marked as 'const'.

The same happens when an explicit field constructor is used.
Because of 'Immutable' usage it is marked as a const, but
the default values are not initialized with values prepended
by 'const'.

-------- Content of change --------

- New smoke and functional tests that were used to confirm
   the invalid behavior.
- Adjustments of 'DartStructConstructors.mustache' file to
   correctly prepend 'const' keyword when needed and to treat
   'null' as it should be treated.

Signed-off-by: Patryk Wrobel <[email protected]>
  • Loading branch information
pwrobeldev authored Nov 21, 2024
1 parent 33567ae commit b516e6b
Show file tree
Hide file tree
Showing 11 changed files with 1,112 additions and 21 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## Unreleased:
### Features:
* Implemented validation of comments used for functions. When the description of parameters or return value is missing, then warning is generated. The user may also treat the warning as error via 'werror' flag.
### Bug fixes:
* Dart: fixed a bug related to missing/superflous 'const' keyword usage in definition of default values in constructors that used collections when `@Immutable` or `PositionalDefaults` were specified.

## 13.9.7
Release date 2024-11-13
Expand Down
36 changes: 35 additions & 1 deletion functional-tests/functional/input/lime/Defaults.lime
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2016-2019 HERE Europe B.V.
# Copyright (C) 2016-2024 HERE Europe B.V.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -43,6 +43,40 @@ class Defaults {
stringField: String = "some string"
enumField: SomeEnum = SomeEnum.BarValue
}
@Immutable
struct ImmutableStructWithCollections {
nullableListField: List<Int>? = null
emptyListField: List<Int> = []
valuesListField: List<Int> = [1, 2, 3]

nullableMapField: Map<Int, String>? = null
emptyMapField: Map<Int, String> = []
valuesMapField: Map<Int, String> = [9: "baz", 27: "bar"]

nullableSetField: Set<String>? = null
emptySetField: Set<String> = []
valuesSetField: Set<String> = ["bar", "baz"]
}
@Immutable
struct ImmutableStructWithFieldConstructorAndCollections {
nullableListField: List<Int>? = null
emptyListField: List<Int> = []
valuesListField: List<Int> = [1, 2, 3]

nullableMapField: Map<Int, String>? = null
emptyMapField: Map<Int, String> = []
valuesMapField: Map<Int, String> = [9: "baz", 27: "bar"]

nullableSetField: Set<String>? = null
emptySetField: Set<String> = []
valuesSetField: Set<String> = ["bar", "baz"]

someField: Int = 5
anotherField: Int = 7

@Dart("withIntegers")
field constructor(someField, anotherField)
}
struct StructWithSpecialDefaults {
floatNanField: Float = NaN
floatInfinityField: Float = Infinity
Expand Down
10 changes: 9 additions & 1 deletion functional-tests/functional/input/lime/PositionalDefaults.lime
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2016-2021 HERE Europe B.V.
# Copyright (C) 2016-2024 HERE Europe B.V.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -52,6 +52,14 @@ struct StructWithCollectionDefaults {
setField: Set<String> = ["foo", "bar"]
}

@Dart(PositionalDefaults)
@Java(Skip) @Swift(Skip)
struct StructWithNullableCollectionDefaults {
nullableListField: List<String>? = null
nullableMapField: Map<String, String>? = null
nullableSetField: Set<String>? = null
}

@Dart(PositionalDefaults)
@Java(Skip) @Swift(Skip)
struct PosDefaultsWithDuration {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{!!
!
! Copyright (C) 2016-2021 HERE Europe B.V.
! Copyright (C) 2016-2024 HERE Europe B.V.
!
! Licensed under the Apache License, Version 2.0 (the "License");
! you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -43,13 +43,14 @@ All fields constructor
Initialized fields constructor
}}{{#unless constructors}}{{#unless fieldConstructors}}{{#if initializedFields}}
}}{{#unless constructors}}{{#unless fieldConstructors}}{{#if initializedFields}}{{#set struct=this}}{{#struct}}
{{#if attributes.immutable}}const {{/if}}{{resolveName}}{{#if external.dart.converter}}Internal{{/if}}{{!!
}}{{#ifPredicate "allFieldsCtorIsPublic"}}.withDefaults{{/ifPredicate}}({{!!
}}{{#uninitializedFields}}{{resolveName typeRef}} {{resolveName}}{{#if iter.hasNext}}, {{/if}}{{/uninitializedFields}})
: {{#fields}}{{resolveName "visibility"}}{{resolveName}} = {{#if defaultValue}}{{resolveName defaultValue}}{{/if}}{{!!
: {{#fields}}{{resolveName "visibility"}}{{resolveName}} = {{!!
}}{{#if defaultValue}}{{#if struct.attributes.immutable}}{{>constPrefix}}{{/if}}{{resolveName defaultValue}}{{/if}}{{!!
}}{{#unless defaultValue}}{{resolveName}}{{/unless}}{{#if iter.hasNext}}, {{/if}}{{/fields}};
{{/if}}{{/unless}}{{/unless}}{{!!
{{/struct}}{{/set}}{{/if}}{{/unless}}{{/unless}}{{!!
}}{{/unless}}{{/if}}{{!!
Expand All @@ -76,14 +77,17 @@ Explicit `field constructor` definitions
{{/if}}{{prefixPartial "dart/DartAttributes" " "}}{{!!
}} {{#if struct.attributes.immutable}}const {{/if}}{{resolveName struct}}{{#if external.dart.converter}}Internal{{/if}}{{!!
}}{{>dart/DartConstructorName}}({{>thisDotFields}}){{#if omittedFields}}
: {{#omittedFields}}{{resolveName "visibility"}}{{resolveName}} = {{resolveName defaultValue}}{{#if iter.hasNext}}, {{/if}}{{/omittedFields}}{{/if}};
: {{#omittedFields}}{{resolveName "visibility"}}{{resolveName}} = {{!!
}}{{#if struct.attributes.immutable}}{{>constPrefix}}{{/if}}{{resolveName defaultValue}}{{#if iter.hasNext}}, {{/if}}{{/omittedFields}}{{/if}};
{{/fieldConstructors}}{{/set}}{{!!
}}{{+constPrefix}}{{#set type=typeRef.type.actualType}}{{!!
}}{{+constPrefix}}{{#notInstanceOf defaultValue "Null"}}{{!!
}}{{#set type=typeRef.type.actualType}}{{!!
}}{{#instanceOf type "LimeList"}}const {{/instanceOf}}{{!!
}}{{#instanceOf type "LimeMap"}}const {{/instanceOf}}{{!!
}}{{#instanceOf type "LimeSet"}}const {{/instanceOf}}{{!!
}}{{/set}}{{/constPrefix}}{{!!
}}{{/set}}{{!!
}}{{/notInstanceOf}}{{/constPrefix}}{{!!
}}{{+constructorComment}}{{#resolveName constructorComment}}{{#unless this.isEmpty}}{{!!
}}{{prefix this " /// "}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2016-2021 HERE Europe B.V.
# Copyright (C) 2016-2024 HERE Europe B.V.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -42,6 +42,14 @@ struct StructWithCollectionDefaults {
setField: Set<String> = ["foo", "bar"]
}

@Dart(PositionalDefaults)
@Java(Skip) @Swift(Skip)
struct StructWithNullableCollectionDefaults {
nullableListField: List<String>? = null
nullableMapField: Map<String, String>? = null
nullableSetField: Set<String>? = null
}

// Foo Bar this is a comment
// @constructor buzz fizz
@Dart(PositionalDefaults = "Sorry, this is deprecated.")
Expand Down
38 changes: 37 additions & 1 deletion gluecodium/src/test/resources/smoke/defaults/input/Defaults.lime
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (C) 2016-2019 HERE Europe B.V.
# Copyright (C) 2016-2024 HERE Europe B.V.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -82,6 +82,42 @@ struct TypesWithDefaults {
boolField: Boolean
stringField: String = "\\Jonny \"Magic\" Smith\n"
}

@Immutable
struct ImmutableStructWithCollections {
nullableListField: List<Int>? = null
emptyListField: List<Int> = []
valuesListField: List<Int> = [1, 2, 3]

nullableMapField: Map<Int, String>? = null
emptyMapField: Map<Int, String> = []
valuesMapField: Map<Int, String> = [9: "baz", 27: "bar"]

nullableSetField: Set<String>? = null
emptySetField: Set<String> = []
valuesSetField: Set<String> = ["bar", "baz"]
}

@Immutable
struct ImmutableStructWithFieldConstructorAndCollections {
nullableListField: List<Int>? = null
emptyListField: List<Int> = []
valuesListField: List<Int> = [1, 2, 3]

nullableMapField: Map<Int, String>? = null
emptyMapField: Map<Int, String> = []
valuesMapField: Map<Int, String> = [9: "baz", 27: "bar"]

nullableSetField: Set<String>? = null
emptySetField: Set<String> = []
valuesSetField: Set<String> = ["bar", "baz"]

someField: Int = 5
anotherField: Int = 7

@Dart("withIntegers")
field constructor(someField, anotherField)
}
}

struct StructWithInitializerDefaults {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
/*
*
*/

package com.example.smoke;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.example.HashMapBuilder;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public final class TypesWithDefaults {
public static final class StructWithDefaults {
public int intField;
Expand All @@ -12,6 +26,7 @@ public static final class StructWithDefaults {
public boolean boolField;
@NonNull
public String stringField;

public StructWithDefaults() {
this.intField = 42;
this.uintField = 4294967295L;
Expand All @@ -20,7 +35,10 @@ public StructWithDefaults() {
this.boolField = true;
this.stringField = "\\Jonny \"Magic\" Smith\n";
}


}

public static final class ImmutableStructWithDefaults {
public final int intField;
public final long uintField;
Expand All @@ -29,6 +47,7 @@ public static final class ImmutableStructWithDefaults {
public final boolean boolField;
@NonNull
public final String stringField;

public ImmutableStructWithDefaults(final long uintField, final boolean boolField) {
this.intField = 42;
this.uintField = uintField;
Expand All @@ -37,6 +56,7 @@ public ImmutableStructWithDefaults(final long uintField, final boolean boolField
this.boolField = boolField;
this.stringField = "\\Jonny \"Magic\" Smith\n";
}

public ImmutableStructWithDefaults(final int intField, final long uintField, final float floatField, final double doubleField, final boolean boolField, @NonNull final String stringField) {
this.intField = intField;
this.uintField = uintField;
Expand All @@ -45,5 +65,111 @@ public ImmutableStructWithDefaults(final int intField, final long uintField, fin
this.boolField = boolField;
this.stringField = stringField;
}


}

public static final class ImmutableStructWithCollections {
@Nullable
public final List<Integer> nullableListField;
@NonNull
public final List<Integer> emptyListField;
@NonNull
public final List<Integer> valuesListField;
@Nullable
public final Map<Integer, String> nullableMapField;
@NonNull
public final Map<Integer, String> emptyMapField;
@NonNull
public final Map<Integer, String> valuesMapField;
@Nullable
public final Set<String> nullableSetField;
@NonNull
public final Set<String> emptySetField;
@NonNull
public final Set<String> valuesSetField;

public ImmutableStructWithCollections() {
this.nullableListField = null;
this.emptyListField = new ArrayList<>();
this.valuesListField = new ArrayList<>(Arrays.asList(1, 2, 3));
this.nullableMapField = null;
this.emptyMapField = new HashMap<>();
this.valuesMapField = new HashMapBuilder<Integer, String>().put(9, "baz").put(27, "bar").build();
this.nullableSetField = null;
this.emptySetField = new HashSet<>();
this.valuesSetField = new HashSet<>(Arrays.asList("bar", "baz"));
}

public ImmutableStructWithCollections(@Nullable final List<Integer> nullableListField, @NonNull final List<Integer> emptyListField, @NonNull final List<Integer> valuesListField, @Nullable final Map<Integer, String> nullableMapField, @NonNull final Map<Integer, String> emptyMapField, @NonNull final Map<Integer, String> valuesMapField, @Nullable final Set<String> nullableSetField, @NonNull final Set<String> emptySetField, @NonNull final Set<String> valuesSetField) {
this.nullableListField = nullableListField;
this.emptyListField = emptyListField;
this.valuesListField = valuesListField;
this.nullableMapField = nullableMapField;
this.emptyMapField = emptyMapField;
this.valuesMapField = valuesMapField;
this.nullableSetField = nullableSetField;
this.emptySetField = emptySetField;
this.valuesSetField = valuesSetField;
}


}

public static final class ImmutableStructWithFieldConstructorAndCollections {
@Nullable
public final List<Integer> nullableListField;
@NonNull
public final List<Integer> emptyListField;
@NonNull
public final List<Integer> valuesListField;
@Nullable
public final Map<Integer, String> nullableMapField;
@NonNull
public final Map<Integer, String> emptyMapField;
@NonNull
public final Map<Integer, String> valuesMapField;
@Nullable
public final Set<String> nullableSetField;
@NonNull
public final Set<String> emptySetField;
@NonNull
public final Set<String> valuesSetField;
public final int someField;
public final int anotherField;

public ImmutableStructWithFieldConstructorAndCollections(@Nullable final List<Integer> nullableListField, @NonNull final List<Integer> emptyListField, @NonNull final List<Integer> valuesListField, @Nullable final Map<Integer, String> nullableMapField, @NonNull final Map<Integer, String> emptyMapField, @NonNull final Map<Integer, String> valuesMapField, @Nullable final Set<String> nullableSetField, @NonNull final Set<String> emptySetField, @NonNull final Set<String> valuesSetField, final int someField, final int anotherField) {
this.nullableListField = nullableListField;
this.emptyListField = emptyListField;
this.valuesListField = valuesListField;
this.nullableMapField = nullableMapField;
this.emptyMapField = emptyMapField;
this.valuesMapField = valuesMapField;
this.nullableSetField = nullableSetField;
this.emptySetField = emptySetField;
this.valuesSetField = valuesSetField;
this.someField = someField;
this.anotherField = anotherField;
}

public ImmutableStructWithFieldConstructorAndCollections(final int someField, final int anotherField) {
this.someField = someField;
this.anotherField = anotherField;
this.nullableListField = null;
this.emptyListField = new ArrayList<>();
this.valuesListField = new ArrayList<>(Arrays.asList(1, 2, 3));
this.nullableMapField = null;
this.emptyMapField = new HashMap<>();
this.valuesMapField = new HashMapBuilder<Integer, String>().put(9, "baz").put(27, "bar").build();
this.nullableSetField = null;
this.emptySetField = new HashSet<>();
this.valuesSetField = new HashSet<>(Arrays.asList("bar", "baz"));
}


}



}

Loading

0 comments on commit b516e6b

Please sign in to comment.