Skip to content

Commit 145b8fe

Browse files
committed
Compile time check to forbid return IEnumerator from relations.
1 parent 49b5b70 commit 145b8fe

7 files changed

+174
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//HintName: IUserNoticeTable.g.cs
2+
// <auto-generated/>
3+
#pragma warning disable 612,618
4+
#nullable enable
5+
using System;
6+
using System.Runtime.CompilerServices;
7+
// Name: IUserNoticeTable
8+
// Field: UserId ulong
9+
// PrimaryIndex: 1
10+
// Field: NoticeId ulong
11+
// PrimaryIndex: 2
12+
// SecondaryIndex NoticeId: 0
13+
[CompilerGenerated]
14+
static file class IUserNoticeTableRegistration
15+
{
16+
[ModuleInitializer]
17+
internal static unsafe void Register4BTDB()
18+
{
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//HintName: UserNotice.g.cs
2+
// <auto-generated/>
3+
#pragma warning disable 612,618
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
7+
[CompilerGenerated]
8+
static file class UserNoticeRegistration
9+
{
10+
[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
11+
extern static global::UserNotice Creator();
12+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<UserId>k__BackingField")]
13+
extern static ref ulong Field1(global::UserNotice @this);
14+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<NoticeId>k__BackingField")]
15+
extern static ref ulong Field2(global::UserNotice @this);
16+
[ModuleInitializer]
17+
internal static unsafe void Register4BTDB()
18+
{
19+
global::BTDB.IOC.IContainer.RegisterFactory(typeof(global::UserNotice), (container, ctx) =>
20+
{
21+
return (container2, ctx2) =>
22+
{
23+
var res = new global::UserNotice();
24+
return res;
25+
};
26+
});
27+
var metadata = new global::BTDB.Serialization.ClassMetadata();
28+
metadata.Name = "UserNotice";
29+
metadata.Type = typeof(global::UserNotice);
30+
metadata.Namespace = "";
31+
metadata.Implements = [];
32+
metadata.Creator = &Creator;
33+
var dummy = Unsafe.As<global::UserNotice>(metadata);
34+
metadata.Fields = new global::BTDB.Serialization.FieldMetadata[]
35+
{
36+
new global::BTDB.Serialization.FieldMetadata
37+
{
38+
Name = "UserId",
39+
Type = typeof(ulong),
40+
ByteOffset = global::BTDB.Serialization.RawData.CalcOffset(dummy, ref Field1(dummy)),
41+
},
42+
new global::BTDB.Serialization.FieldMetadata
43+
{
44+
Name = "NoticeId",
45+
Type = typeof(ulong),
46+
ByteOffset = global::BTDB.Serialization.RawData.CalcOffset(dummy, ref Field2(dummy)),
47+
},
48+
};
49+
global::BTDB.Serialization.ReflectionMetadata.Register(metadata);
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
Diagnostics: [
3+
{
4+
Location: /*
5+
void Insert(UserNotice un);
6+
IEnumerator<UserNotice> ListByNoticeId(AdvancedEnumeratorParam<ulong> noticeId);
7+
^^^^^^^^^^^^^^
8+
}
9+
*/
10+
: (16,28)-(16,42),
11+
Message: Cannot use IEnumerator<> as return type in ListByNoticeId,
12+
Severity: Error,
13+
Descriptor: {
14+
Id: BTDB0009,
15+
Title: Cannot use IEnumerator<> as return type in ListByNoticeId,
16+
MessageFormat: Cannot use IEnumerator<> as return type in ListByNoticeId,
17+
Category: BTDB,
18+
DefaultSeverity: Error,
19+
IsEnabledByDefault: true
20+
}
21+
}
22+
]
23+
}

BTDB.SourceGenerator.Test/RelationTests.VerifyThatTwoSecondaryKeysCannotHaveSameOrder.verified.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public interface IPersonTable : IRelation<Person>
1111
Message: Cannot have multiple SecondaryKey with same order in S1Also as in S1,
1212
Severity: Error,
1313
Descriptor: {
14-
Id: BTDB0007,
14+
Id: BTDB0008,
1515
Title: Cannot have multiple SecondaryKey with same order in S1Also as in S1,
1616
MessageFormat: Cannot have multiple SecondaryKey with same order in S1Also as in S1,
1717
Category: BTDB,

BTDB.SourceGenerator.Test/RelationTests.cs

+54
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,58 @@ public interface IPersonTable : IRelation<Person>
190190
191191
""");
192192
}
193+
194+
[Fact]
195+
public Task VerifyThatIEnumerableIsOk()
196+
{
197+
// language=cs
198+
return VerifySourceGenerator("""
199+
using System.Collections.Generic;
200+
using BTDB.ODBLayer;
201+
202+
public class UserNotice
203+
{
204+
[PrimaryKey(1)] public ulong UserId { get; set; }
205+
206+
[PrimaryKey(2)]
207+
[SecondaryKey("NoticeId")]
208+
public ulong NoticeId { get; set; }
209+
}
210+
211+
[PersistedName("UserNotice")]
212+
public interface IUserNoticeTable : IRelation<UserNotice>
213+
{
214+
void Insert(UserNotice un);
215+
IEnumerable<UserNotice> ListByNoticeId(AdvancedEnumeratorParam<ulong> noticeId);
216+
}
217+
218+
""");
219+
}
220+
221+
[Fact]
222+
public Task VerifyThatIEnumeratorIsError()
223+
{
224+
// language=cs
225+
return VerifySourceGenerator("""
226+
using System.Collections.Generic;
227+
using BTDB.ODBLayer;
228+
229+
public class UserNotice
230+
{
231+
[PrimaryKey(1)] public ulong UserId { get; set; }
232+
233+
[PrimaryKey(2)]
234+
[SecondaryKey("NoticeId")]
235+
public ulong NoticeId { get; set; }
236+
}
237+
238+
[PersistedName("UserNotice")]
239+
public interface IUserNoticeTable : IRelation<UserNotice>
240+
{
241+
void Insert(UserNotice un);
242+
IEnumerator<UserNotice> ListByNoticeId(AdvancedEnumeratorParam<ulong> noticeId);
243+
}
244+
245+
""");
246+
}
193247
}

BTDB.SourceGenerator/Main.cs

+22-1
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,27 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
149149
if (generationInfo is not { GenType: GenerationType.Class }) return null;
150150
var detectedError = DetectErrors(generationInfo.Fields.AsSpan(),
151151
((InterfaceDeclarationSyntax)syntaxContext.Node).Identifier.GetLocation());
152+
// Get all methods
153+
var methods = symbol.GetMembers().OfType<IMethodSymbol>().ToArray();
154+
foreach (var method in methods)
155+
{
156+
if (method.ReturnType.TypeKind == TypeKind.Interface)
157+
{
158+
// Check is return type is IEnumerator<>
159+
if (method.ReturnType.OriginalDefinition.SpecialType ==
160+
SpecialType.System_Collections_Generic_IEnumerator_T)
161+
{
162+
return GenerationError("BTDB0009",
163+
"Cannot use IEnumerator<> as return type in " + method.Name,
164+
method.Locations[0]);
165+
}
166+
}
167+
}
168+
169+
// Get method return types and skip void
170+
var methodReturnTypes = methods.Select(m => m.ReturnType)
171+
.Where(t => t.SpecialType != SpecialType.System_Void).ToArray();
172+
152173
if (detectedError != null)
153174
return detectedError;
154175
return new(GenerationType.RelationIface, namespaceName, interfaceName,
@@ -364,7 +385,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
364385

365386
if (order2Index.ContainsKey(index.Order))
366387
{
367-
return GenerationError("BTDB0007",
388+
return GenerationError("BTDB0008",
368389
"Cannot have multiple SecondaryKey with same order in " + f.Name + " as in " +
369390
fields[order2Index[index.Order]].Name, location);
370391
}

BTDBTest/ObjectDbTableTest.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1533,7 +1533,7 @@ public interface IProductionInvalidTable : IRelation<ProductionTrackingDaily>
15331533
{
15341534
void Insert(ProductionTrackingDaily productionTrackingDaily);
15351535

1536-
IEnumerator<ProductionTrackingDaily> FindByProductionDateWithCompanyId(ulong companyId,
1536+
IEnumerable<ProductionTrackingDaily> FindByProductionDateWithCompanyId(ulong companyId,
15371537
AdvancedEnumeratorParam<DateTime> productionDate);
15381538
}
15391539

@@ -1950,7 +1950,7 @@ public override int GetHashCode()
19501950
public interface IPersonTableSuperfluousParameter : IRelation<Person>
19511951
{
19521952
void Insert(Person person);
1953-
IEnumerator<Person> ListByName(ulong tenantId, string name, AdvancedEnumeratorParam<int> param);
1953+
IEnumerable<Person> ListByName(ulong tenantId, string name, AdvancedEnumeratorParam<int> param);
19541954
}
19551955

19561956
[Fact]
@@ -1965,7 +1965,7 @@ public void ReportErrorForSuperfluousMethodParameter()
19651965
public interface IPersonTableWrongTypeParameter : IRelation<Person>
19661966
{
19671967
void Insert(Person person);
1968-
IEnumerator<Person> ListByName(ulong tenantId, AdvancedEnumeratorParam<int> param);
1968+
IEnumerable<Person> ListByName(ulong tenantId, AdvancedEnumeratorParam<int> param);
19691969
}
19701970

19711971
[Fact]

0 commit comments

Comments
 (0)