Skip to content

Commit 6f6271b

Browse files
committed
add analyzer and codefix
1 parent c7ff6c2 commit 6f6271b

23 files changed

Lines changed: 1591 additions & 7 deletions

Tocsoft.Clock.sln

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio 15
4-
VisualStudioVersion = 15.0.27130.2020
4+
VisualStudioVersion = 15.0.27130.2027
55
MinimumVisualStudioVersion = 10.0.40219.1
6-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tocsoft.DateTimeAbstractions", "Tocsoft.Clock\Tocsoft.DateTimeAbstractions.csproj", "{48B75F8E-2EFC-4A36-8B4C-EB12EA1459E6}"
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tocsoft.DateTimeAbstractions", "Tocsoft.Clock\Tocsoft.DateTimeAbstractions.csproj", "{48B75F8E-2EFC-4A36-8B4C-EB12EA1459E6}"
77
EndProject
8-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tocsoft.DateTimeAbstractions.Tests", "Tocsoft.DateTimeAbstractions.Tests\Tocsoft.DateTimeAbstractions.Tests.csproj", "{F59B2FEE-7E98-4DE5-8BBA-3D628FB2F615}"
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tocsoft.DateTimeAbstractions.Tests", "Tocsoft.DateTimeAbstractions.Tests\Tocsoft.DateTimeAbstractions.Tests.csproj", "{F59B2FEE-7E98-4DE5-8BBA-3D628FB2F615}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tocsoft.DateTimeAbstractions.Analyzer", "Tocsoft.DateTimeAbstractions.Analyzer\Tocsoft.DateTimeAbstractions.Analyzer\Tocsoft.DateTimeAbstractions.Analyzer.csproj", "{C8D8C32F-233C-4700-8050-4A033F470251}"
11+
EndProject
12+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tocsoft.DateTimeAbstractions.Analyzer.Test", "Tocsoft.DateTimeAbstractions.Analyzer\Tocsoft.DateTimeAbstractions.Analyzer.Test\Tocsoft.DateTimeAbstractions.Analyzer.Test.csproj", "{59C195B9-A250-4317-AA51-62AD074EA002}"
913
EndProject
1014
Global
1115
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -21,6 +25,14 @@ Global
2125
{F59B2FEE-7E98-4DE5-8BBA-3D628FB2F615}.Debug|Any CPU.Build.0 = Debug|Any CPU
2226
{F59B2FEE-7E98-4DE5-8BBA-3D628FB2F615}.Release|Any CPU.ActiveCfg = Release|Any CPU
2327
{F59B2FEE-7E98-4DE5-8BBA-3D628FB2F615}.Release|Any CPU.Build.0 = Release|Any CPU
28+
{C8D8C32F-233C-4700-8050-4A033F470251}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29+
{C8D8C32F-233C-4700-8050-4A033F470251}.Debug|Any CPU.Build.0 = Debug|Any CPU
30+
{C8D8C32F-233C-4700-8050-4A033F470251}.Release|Any CPU.ActiveCfg = Release|Any CPU
31+
{C8D8C32F-233C-4700-8050-4A033F470251}.Release|Any CPU.Build.0 = Release|Any CPU
32+
{59C195B9-A250-4317-AA51-62AD074EA002}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33+
{59C195B9-A250-4317-AA51-62AD074EA002}.Debug|Any CPU.Build.0 = Debug|Any CPU
34+
{59C195B9-A250-4317-AA51-62AD074EA002}.Release|Any CPU.ActiveCfg = Release|Any CPU
35+
{59C195B9-A250-4317-AA51-62AD074EA002}.Release|Any CPU.Build.0 = Release|Any CPU
2436
EndGlobalSection
2537
GlobalSection(SolutionProperties) = preSolution
2638
HideSolutionNode = FALSE

Tocsoft.Clock/Clock.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Threading;
4+
using Tocsoft.DateTimeAbstractions.Providers;
45

56
namespace Tocsoft.DateTimeAbstractions
67
{
@@ -14,6 +15,7 @@ public static DateTimeProvider CurrentProvider
1415
{
1516
get
1617
{
18+
clockStack.Value = clockStack.Value ?? ImmutableStack.Create<DateTimeProvider>();
1719
if (!clockStack.Value.IsEmpty)
1820
{
1921
return clockStack.Value.Peek();

Tocsoft.Clock/CurrentDateTimeProvider.cs renamed to Tocsoft.Clock/Providers/CurrentDateTimeProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22

3-
namespace Tocsoft.DateTimeAbstractions
3+
namespace Tocsoft.DateTimeAbstractions.Providers
44
{
55
public class CurrentDateTimeProvider : DateTimeProvider
66
{

Tocsoft.Clock/DateTimeProvider.cs renamed to Tocsoft.Clock/Providers/DateTimeProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22

3-
namespace Tocsoft.DateTimeAbstractions
3+
namespace Tocsoft.DateTimeAbstractions.Providers
44
{
55
public abstract class DateTimeProvider
66
{

Tocsoft.Clock/StaticDateTimeProvider.cs renamed to Tocsoft.Clock/Providers/StaticDateTimeProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22

3-
namespace Tocsoft.DateTimeAbstractions
3+
namespace Tocsoft.DateTimeAbstractions.Providers
44
{
55
public class StaticDateTimeProvider : DateTimeProvider
66
{

Tocsoft.Clock/UtcCurrentDateTimeProvider.cs renamed to Tocsoft.Clock/Providers/UtcCurrentDateTimeProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22

3-
namespace Tocsoft.DateTimeAbstractions
3+
namespace Tocsoft.DateTimeAbstractions.Providers
44
{
55
public class UtcCurrentDateTimeProvider : DateTimeProvider
66
{
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CodeActions;
3+
using Microsoft.CodeAnalysis.Formatting;
4+
using Microsoft.CodeAnalysis.Simplification;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Threading;
8+
9+
namespace TestHelper
10+
{
11+
/// <summary>
12+
/// Diagnostic Producer class with extra methods dealing with applying codefixes
13+
/// All methods are static
14+
/// </summary>
15+
public abstract partial class CodeFixVerifier : DiagnosticVerifier
16+
{
17+
/// <summary>
18+
/// Apply the inputted CodeAction to the inputted document.
19+
/// Meant to be used to apply codefixes.
20+
/// </summary>
21+
/// <param name="document">The Document to apply the fix on</param>
22+
/// <param name="codeAction">A CodeAction that will be applied to the Document.</param>
23+
/// <returns>A Document with the changes from the CodeAction</returns>
24+
private static Document ApplyFix(Document document, CodeAction codeAction)
25+
{
26+
var operations = codeAction.GetOperationsAsync(CancellationToken.None).Result;
27+
var solution = operations.OfType<ApplyChangesOperation>().Single().ChangedSolution;
28+
return solution.GetDocument(document.Id);
29+
}
30+
31+
/// <summary>
32+
/// Compare two collections of Diagnostics,and return a list of any new diagnostics that appear only in the second collection.
33+
/// Note: Considers Diagnostics to be the same if they have the same Ids. In the case of multiple diagnostics with the same Id in a row,
34+
/// this method may not necessarily return the new one.
35+
/// </summary>
36+
/// <param name="diagnostics">The Diagnostics that existed in the code before the CodeFix was applied</param>
37+
/// <param name="newDiagnostics">The Diagnostics that exist in the code after the CodeFix was applied</param>
38+
/// <returns>A list of Diagnostics that only surfaced in the code after the CodeFix was applied</returns>
39+
private static IEnumerable<Diagnostic> GetNewDiagnostics(IEnumerable<Diagnostic> diagnostics, IEnumerable<Diagnostic> newDiagnostics)
40+
{
41+
var oldArray = diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();
42+
var newArray = newDiagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();
43+
44+
int oldIndex = 0;
45+
int newIndex = 0;
46+
47+
while (newIndex < newArray.Length)
48+
{
49+
if (oldIndex < oldArray.Length && oldArray[oldIndex].Id == newArray[newIndex].Id)
50+
{
51+
++oldIndex;
52+
++newIndex;
53+
}
54+
else
55+
{
56+
yield return newArray[newIndex++];
57+
}
58+
}
59+
}
60+
61+
/// <summary>
62+
/// Get the existing compiler diagnostics on the inputted document.
63+
/// </summary>
64+
/// <param name="document">The Document to run the compiler diagnostic analyzers on</param>
65+
/// <returns>The compiler diagnostics that were found in the code</returns>
66+
private static IEnumerable<Diagnostic> GetCompilerDiagnostics(Document document)
67+
{
68+
return document.GetSemanticModelAsync().Result.GetDiagnostics();
69+
}
70+
71+
/// <summary>
72+
/// Given a document, turn it into a string based on the syntax root
73+
/// </summary>
74+
/// <param name="document">The Document to be converted to a string</param>
75+
/// <returns>A string containing the syntax of the Document after formatting</returns>
76+
private static string GetStringFromDocument(Document document)
77+
{
78+
var simplifiedDoc = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result;
79+
var root = simplifiedDoc.GetSyntaxRootAsync().Result;
80+
root = Formatter.Format(root, Formatter.Annotation, simplifiedDoc.Project.Solution.Workspace);
81+
return root.GetText().ToString();
82+
}
83+
}
84+
}
85+
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using Microsoft.CodeAnalysis;
2+
using System;
3+
4+
namespace TestHelper
5+
{
6+
/// <summary>
7+
/// Location where the diagnostic appears, as determined by path, line number, and column number.
8+
/// </summary>
9+
public struct DiagnosticResultLocation
10+
{
11+
public DiagnosticResultLocation(string path, int line, int column)
12+
{
13+
if (line < -1)
14+
{
15+
throw new ArgumentOutOfRangeException(nameof(line), "line must be >= -1");
16+
}
17+
18+
if (column < -1)
19+
{
20+
throw new ArgumentOutOfRangeException(nameof(column), "column must be >= -1");
21+
}
22+
23+
this.Path = path;
24+
this.Line = line;
25+
this.Column = column;
26+
}
27+
28+
public string Path { get; }
29+
public int Line { get; }
30+
public int Column { get; }
31+
}
32+
33+
/// <summary>
34+
/// Struct that stores information about a Diagnostic appearing in a source
35+
/// </summary>
36+
public struct DiagnosticResult
37+
{
38+
private DiagnosticResultLocation[] locations;
39+
40+
public DiagnosticResultLocation[] Locations
41+
{
42+
get
43+
{
44+
if (this.locations == null)
45+
{
46+
this.locations = new DiagnosticResultLocation[] { };
47+
}
48+
return this.locations;
49+
}
50+
51+
set
52+
{
53+
this.locations = value;
54+
}
55+
}
56+
57+
public DiagnosticSeverity Severity { get; set; }
58+
59+
public string Id { get; set; }
60+
61+
public string Message { get; set; }
62+
63+
public string Path
64+
{
65+
get
66+
{
67+
return this.Locations.Length > 0 ? this.Locations[0].Path : "";
68+
}
69+
}
70+
71+
public int Line
72+
{
73+
get
74+
{
75+
return this.Locations.Length > 0 ? this.Locations[0].Line : -1;
76+
}
77+
}
78+
79+
public int Column
80+
{
81+
get
82+
{
83+
return this.Locations.Length > 0 ? this.Locations[0].Column : -1;
84+
}
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)