@@ -40,7 +40,7 @@ static void Main(string[] args)
4040 }
4141
4242 [ TestMethod ]
43- public void UsageOfImplicitConversionInComparison_ProducesWarningMessage ( )
43+ public void UsageOfImplicitConversionInComparison_DateTimeToDateTimeOffset_ProducesWarningMessage ( )
4444 {
4545 string source = @"
4646using System;
@@ -53,15 +53,40 @@ internal class Program
5353 static void Main(string[] args)
5454 {
5555 DateTime first = DateTime.Now;
56+ DateTimeOffset second = DateTimeOffset.Now;
57+ _ = first < second;
58+ }
59+ }
60+ }" ;
5661
57- Thread.Sleep(10);
62+ VerifyCSharpDiagnostic ( source ,
63+ new DiagnosticResult
64+ {
65+ Id = "INTL0202" ,
66+ Severity = DiagnosticSeverity . Warning ,
67+ Message = "Using 'DateTimeOffset.implicit operator DateTimeOffset(DateTime)' or 'new DateTimeOffset(DateTime)' can result in unpredictable behavior" ,
68+ Locations =
69+ [ new DiagnosticResultLocation ( "Test0.cs" , 13 , 17 ) ]
70+ } ) ;
5871
59- DateTimeOffset second = DateTimeOffset.Now;
72+ }
6073
61- if (first < second)
62- {
63- Console.WriteLine(""Time has passed..."");
64- }
74+ [ TestMethod ]
75+ public void UsageOfImplicitConversionInComparison_DateTimeOffsetToDateTime_ProducesWarningMessage ( )
76+ {
77+ string source = @"
78+ using System;
79+ using System.Threading;
80+
81+ namespace ConsoleApp1
82+ {
83+ internal class Program
84+ {
85+ static void Main(string[] args)
86+ {
87+ DateTimeOffset first = DateTimeOffset.Now;
88+ DateTime second = DateTime.Now;
89+ _ = first < second;
6590 }
6691 }
6792}" ;
@@ -73,13 +98,152 @@ static void Main(string[] args)
7398 Severity = DiagnosticSeverity . Warning ,
7499 Message = "Using 'DateTimeOffset.implicit operator DateTimeOffset(DateTime)' or 'new DateTimeOffset(DateTime)' can result in unpredictable behavior" ,
75100 Locations =
76- [
77- new DiagnosticResultLocation ( "Test0.cs" , 17 , 17 )
78- ]
101+ [ new DiagnosticResultLocation ( "Test0.cs" , 13 , 25 ) ]
79102 } ) ;
80103
81104 }
82105
106+ [ TestMethod ]
107+ public void UsageOfImplicitConversionInComparison_NullableDateTimeOffsetToDateTime_ProducesWarningMessage ( )
108+ {
109+ string source = @"
110+ using System;
111+ using System.Threading;
112+
113+ namespace ConsoleApp1
114+ {
115+ internal class Program
116+ {
117+ static void Main(string[] args)
118+ {
119+ DateTimeOffset? first = DateTimeOffset.Now;
120+ DateTime second = DateTime.Now;
121+ _ = first < second;
122+ }
123+ }
124+ }" ;
125+
126+ VerifyCSharpDiagnostic (
127+ source ,
128+ new DiagnosticResult
129+ {
130+ Id = "INTL0202" ,
131+ Severity = DiagnosticSeverity . Warning ,
132+ Message = "Using 'DateTimeOffset.implicit operator DateTimeOffset(DateTime)' or 'new DateTimeOffset(DateTime)' can result in unpredictable behavior" ,
133+ Locations = [ new DiagnosticResultLocation ( "Test0.cs" , 13 , 25 ) ]
134+ }
135+ ) ;
136+ }
137+
138+ [ Ignore ( "Property-based conversion detection not yet implemented - requires Roslyn IOperation tree investigation" ) ]
139+ [ TestMethod ]
140+ public void UsageOfImplicitConversion_WithProperties_ProducesWarningMessage ( )
141+ {
142+ string source = @"
143+ using System;
144+ using System.Collections.Generic;
145+ using System.Linq;
146+
147+ namespace ConsoleApp1
148+ {
149+ internal class Pair(DateTimeOffset DateTimeOffset, DateTime DateTime);
150+
151+ internal class Program
152+ {
153+ static void Main(string[] args)
154+ {
155+ Pair pair = new(DateTimeOffset.Now, DateTime.Now);
156+ _ = pair.DateTimeOffset < pair.DateTime;
157+ }
158+ }
159+ }" ;
160+
161+ VerifyCSharpDiagnostic (
162+ source ,
163+ new DiagnosticResult
164+ {
165+ Id = "INTL0202" ,
166+ Severity = DiagnosticSeverity . Warning ,
167+ Message = "Using 'DateTimeOffset.implicit operator DateTimeOffset(DateTime)' or 'new DateTimeOffset(DateTime)' can result in unpredictable behavior" ,
168+ Locations = [ new DiagnosticResultLocation ( "Test0.cs" , 14 , 29 ) ]
169+ }
170+ ) ;
171+ }
172+
173+ [ Ignore ( "Property-based conversion detection not yet implemented - requires Roslyn IOperation tree investigation" ) ]
174+ [ TestMethod ]
175+ public void UsageOfImplicitConversion_WithPropertiesInLinq_ProducesWarningMessage ( )
176+ {
177+ string source = @"
178+ using System;
179+ using System.Collections.Generic;
180+ using System.Linq;
181+
182+ namespace ConsoleApp1
183+ {
184+ internal class Pair(DateTimeOffset DateTimeOffset, DateTime DateTime);
185+
186+ internal class Program
187+ {
188+ static void Main(string[] args)
189+ {
190+ List<Pair> list = new(){ new(DateTimeOffset.Now, DateTime.Now) };
191+ _ = list.Where(pair => pair.DateTimeOffset < pair.DateTime);
192+ }
193+ }
194+ }" ;
195+
196+ VerifyCSharpDiagnostic (
197+ source ,
198+ new DiagnosticResult
199+ {
200+ Id = "INTL0202" ,
201+ Severity = DiagnosticSeverity . Warning ,
202+ Message = "Using 'DateTimeOffset.implicit operator DateTimeOffset(DateTime)' or 'new DateTimeOffset(DateTime)' can result in unpredictable behavior" ,
203+ Locations = [ new DiagnosticResultLocation ( "Test0.cs" , 14 , 42 ) ]
204+ }
205+ ) ;
206+ }
207+
208+ [ Ignore ( "Property-based conversion detection not yet implemented - requires Roslyn IOperation tree investigation" ) ]
209+ [ TestMethod ]
210+ public void UsageOfImplicitConversion_InLinqWithVariables_ProducesWarningMessage ( )
211+ {
212+ string source = @"
213+ using System;
214+ using System.Collections.Generic;
215+ using System.Linq;
216+
217+ namespace ConsoleApp1
218+ {
219+ internal class Pair(DateTimeOffset DateTimeOffset, DateTime DateTime);
220+
221+ internal class Program
222+ {
223+ static void Main(string[] args)
224+ {
225+ List<Pair> list = new(){ new(DateTimeOffset.Now, DateTime.Now) };
226+ _ = list.Where(pair => {
227+ DateTimeOffset first = pair.DateTimeOffset;
228+ DateTime second = pair.DateTime;
229+ return first < second;
230+ });
231+ }
232+ }
233+ }" ;
234+
235+ VerifyCSharpDiagnostic (
236+ source ,
237+ new DiagnosticResult
238+ {
239+ Id = "INTL0202" ,
240+ Severity = DiagnosticSeverity . Warning ,
241+ Message = "Using 'DateTimeOffset.implicit operator DateTimeOffset(DateTime)' or 'new DateTimeOffset(DateTime)' can result in unpredictable behavior" ,
242+ Locations = [ new DiagnosticResultLocation ( "Test0.cs" , 18 , 24 ) ]
243+ }
244+ ) ;
245+ }
246+
83247 [ TestMethod ]
84248 public void UsageOfExplicitConversion_ProducesNothing ( )
85249 {
@@ -101,6 +265,52 @@ static void Main(string[] args)
101265
102266 }
103267
268+ [ Ignore ( "Property-based conversion detection not yet implemented - requires Roslyn IOperation tree investigation" ) ]
269+ [ TestMethod ]
270+ public void UsageInLambdaWithDateProperty_ProducesWarningMessage ( )
271+ {
272+ // This test matches the original issue scenario
273+ string source = @"
274+ using System;
275+ using System.Linq;
276+
277+ namespace Test
278+ {
279+ public class TimeEntry
280+ {
281+ public DateTimeOffset EndDate { get; set; }
282+ public DateTimeOffset StartDate { get; set; }
283+ }
284+
285+ public class DataSource
286+ {
287+ public IQueryable<TimeEntry> GetQuery(DateTime startDate, DateTime endDate)
288+ {
289+ return Enumerable.Empty<TimeEntry>().AsQueryable()
290+ .Where(te =>
291+ te.EndDate <= endDate.Date.AddDays(1).AddTicks(-1) &&
292+ te.StartDate >= startDate.Date);
293+ }
294+ }
295+ }" ;
296+
297+ VerifyCSharpDiagnostic ( source ,
298+ new DiagnosticResult
299+ {
300+ Id = "INTL0202" ,
301+ Severity = DiagnosticSeverity . Warning ,
302+ Message = "Using 'DateTimeOffset.implicit operator DateTimeOffset(DateTime)' or 'new DateTimeOffset(DateTime)' can result in unpredictable behavior" ,
303+ Locations = [ new DiagnosticResultLocation ( "Test0.cs" , 18 , 35 ) ]
304+ } ,
305+ new DiagnosticResult
306+ {
307+ Id = "INTL0202" ,
308+ Severity = DiagnosticSeverity . Warning ,
309+ Message = "Using 'DateTimeOffset.implicit operator DateTimeOffset(DateTime)' or 'new DateTimeOffset(DateTime)' can result in unpredictable behavior" ,
310+ Locations = [ new DiagnosticResultLocation ( "Test0.cs" , 19 , 38 ) ]
311+ } ) ;
312+ }
313+
104314 [ TestMethod ]
105315 public void UsageOfDateTimeOffsetConstructorWithDateTime_ProducesWarningMessage ( )
106316 {
0 commit comments