Skip to content

Commit

Permalink
Style cop analyzer (#294)
Browse files Browse the repository at this point in the history
* StyleCop analyzer added, incl. StyleCop.json

* rulesets added, link to StyleCop.json fixed

(see https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md)

* stylecop fixes

* SonarAnalyzer removed; SA1600 deactivated

* stylecop fixes

* stylecop fixes

* stylecop fixes

* TypeInitializerException fixed that was caused by accessing a private field that gets defined in code below
  • Loading branch information
RalfKoban authored Jul 1, 2019
1 parent f468a22 commit 24d08ca
Show file tree
Hide file tree
Showing 223 changed files with 2,492 additions and 808 deletions.
2 changes: 1 addition & 1 deletion MiKo.Analyzer.Tests/Helpers/CodeFixVerifier.Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace TestHelper
{
partial class CodeFixVerifier
public partial class CodeFixVerifier
{
public static readonly IEnumerable<string> TestFixtures = new[]
{
Expand Down
32 changes: 17 additions & 15 deletions MiKo.Analyzer.Tests/Helpers/CodeFixVerifier.Helper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

Expand All @@ -10,15 +10,17 @@
namespace TestHelper
{
/// <summary>
/// Diagnostic Producer class with extra methods dealing with applying codefixes
/// All methods are static
/// Diagnostic Producer class with extra methods dealing with applying codefixes.
/// All methods are static.
/// </summary>
public abstract partial class CodeFixVerifier : DiagnosticVerifier
{
protected static string ToNoun(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return value;
}

if (char.IsLower(value[0]))
{
Expand All @@ -27,13 +29,14 @@ protected static string ToNoun(string value)

return value;
}

/// <summary>
/// Apply the inputted CodeAction to the inputted document.
/// Meant to be used to apply codefixes.
/// </summary>
/// <param name="document">The Document to apply the fix on</param>
/// <param name="document">The Document to apply the fix on.</param>
/// <param name="codeAction">A CodeAction that will be applied to the Document.</param>
/// <returns>A Document with the changes from the CodeAction</returns>
/// <returns>A Document with the changes from the CodeAction.</returns>
private static Document ApplyFix(Document document, CodeAction codeAction)
{
var operations = codeAction.GetOperationsAsync(CancellationToken.None).Result;
Expand All @@ -46,9 +49,9 @@ private static Document ApplyFix(Document document, CodeAction codeAction)
/// 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,
/// this method may not necessarily return the new one.
/// </summary>
/// <param name="diagnostics">The Diagnostics that existed in the code before the CodeFix was applied</param>
/// <param name="newDiagnostics">The Diagnostics that exist in the code after the CodeFix was applied</param>
/// <returns>A list of Diagnostics that only surfaced in the code after the CodeFix was applied</returns>
/// <param name="diagnostics">The Diagnostics that existed in the code before the CodeFix was applied.</param>
/// <param name="newDiagnostics">The Diagnostics that exist in the code after the CodeFix was applied.</param>
/// <returns>A list of Diagnostics that only surfaced in the code after the CodeFix was applied.</returns>
private static IEnumerable<Diagnostic> GetNewDiagnostics(IEnumerable<Diagnostic> diagnostics, IEnumerable<Diagnostic> newDiagnostics)
{
var oldArray = diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();
Expand All @@ -74,18 +77,18 @@ private static IEnumerable<Diagnostic> GetNewDiagnostics(IEnumerable<Diagnostic>
/// <summary>
/// Get the existing compiler diagnostics on the inputted document.
/// </summary>
/// <param name="document">The Document to run the compiler diagnostic analyzers on</param>
/// <returns>The compiler diagnostics that were found in the code</returns>
/// <param name="document">The Document to run the compiler diagnostic analyzers on.</param>
/// <returns>The compiler diagnostics that were found in the code.</returns>
private static IEnumerable<Diagnostic> GetCompilerDiagnostics(Document document)
{
return document.GetSemanticModelAsync().Result.GetDiagnostics();
}

/// <summary>
/// Given a document, turn it into a string based on the syntax root
/// Given a document, turn it into a string based on the syntax root.
/// </summary>
/// <param name="document">The Document to be converted to a string</param>
/// <returns>A string containing the syntax of the Document after formatting</returns>
/// <param name="document">The Document to be converted to a string.</param>
/// <returns>A string containing the syntax of the Document after formatting.</returns>
private static string GetStringFromDocument(Document document)
{
var simplifiedDoc = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result;
Expand All @@ -94,5 +97,4 @@ private static string GetStringFromDocument(Document document)
return root.GetText().ToString();
}
}
}

}
35 changes: 4 additions & 31 deletions MiKo.Analyzer.Tests/Helpers/DiagnosticResult.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,7 @@
using Microsoft.CodeAnalysis;
using System;
using Microsoft.CodeAnalysis;

namespace TestHelper
{
/// <summary>
/// Location where the diagnostic appears, as determined by path, line number, and column number.
/// </summary>
public struct DiagnosticResultLocation
{
public DiagnosticResultLocation(string path, int line, int column)
{
if (line < -1)
{
throw new ArgumentOutOfRangeException(nameof(line), line, "line must be >= -1");
}

if (column < -1)
{
throw new ArgumentOutOfRangeException(nameof(column), column, "column must be >= -1");
}

this.Path = path;
this.Line = line;
this.Column = column;
}

public string Path { get; }
public int Line { get; }
public int Column { get; }
}

/// <summary>
/// Struct that stores information about a Diagnostic appearing in a source
/// </summary>
Expand All @@ -45,6 +17,7 @@ public DiagnosticResultLocation[] Locations
{
this.locations = new DiagnosticResultLocation[] { };
}

return this.locations;
}

Expand All @@ -64,7 +37,7 @@ public string Path
{
get
{
return this.Locations.Length > 0 ? this.Locations[0].Path : "";
return this.Locations.Length > 0 ? this.Locations[0].Path : string.Empty;
}
}

Expand All @@ -84,4 +57,4 @@ public int Column
}
}
}
}
}
33 changes: 33 additions & 0 deletions MiKo.Analyzer.Tests/Helpers/DiagnosticResultLocation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;

namespace TestHelper
{
/// <summary>
/// Location where the diagnostic appears, as determined by path, line number, and column number.
/// </summary>
public struct DiagnosticResultLocation
{
public DiagnosticResultLocation(string path, int line, int column)
{
if (line < -1)
{
throw new ArgumentOutOfRangeException(nameof(line), line, "line must be >= -1");
}

if (column < -1)
{
throw new ArgumentOutOfRangeException(nameof(column), column, "column must be >= -1");
}

Path = path;
Line = line;
Column = column;
}

public string Path { get; }

public int Line { get; }

public int Column { get; }
}
}
104 changes: 49 additions & 55 deletions MiKo.Analyzer.Tests/Helpers/DiagnosticVerifier.Helper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
Expand All @@ -13,11 +13,16 @@
namespace TestHelper
{
/// <summary>
/// Class for turning strings into documents and getting the diagnostics on them
/// All methods are static
/// Class for turning strings into documents and getting the diagnostics on them.
/// All methods are static.
/// </summary>
public abstract partial class DiagnosticVerifier
{
internal const string DefaultFilePathPrefix = "Test";
internal const string CSharpDefaultFileExt = "cs";
internal const string VisualBasicDefaultExt = "vb";
internal const string TestProjectName = "MiKoSolutions.Analyzers.AdHoc.TestProject";

private static readonly MetadataReference CorlibReference = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
private static readonly MetadataReference SystemCoreReference = MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location);
private static readonly MetadataReference SystemWindowsInputReference = MetadataReference.CreateFromFile(typeof(ICommand).Assembly.Location);
Expand All @@ -26,32 +31,13 @@ public abstract partial class DiagnosticVerifier
private static readonly MetadataReference CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location);
private static readonly MetadataReference NUnitReference = MetadataReference.CreateFromFile(typeof(NUnit.Framework.Assert).Assembly.Location);

internal static string DefaultFilePathPrefix = "Test";
internal static string CSharpDefaultFileExt = "cs";
internal static string VisualBasicDefaultExt = "vb";
internal static string TestProjectName = "MiKoSolutions.Analyzers.AdHoc.TestProject";

#region Get Diagnostics

/// <summary>
/// Given classes in the form of strings, their language, and an IDiagnosticAnalyzer to apply to it, return the diagnostics found in the string after converting it to a document.
/// </summary>
/// <param name="sources">Classes in the form of strings</param>
/// <param name="language">The language the source classes are in</param>
/// <param name="analyzer">The analyzer to be run on the sources</param>
/// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns>
private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer)
{
return GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language));
}

/// <summary>
/// Given an analyzer and a document to apply it to, run the analyzer and gather an array of diagnostics found in it.
/// The returned diagnostics are then ordered by location in the source document.
/// </summary>
/// <param name="analyzer">The analyzer to run on the documents</param>
/// <param name="documents">The Documents that the analyzer will be run on</param>
/// <returns>An IEnumerable of Diagnostics that surfaced in the source code, sorted by Location</returns>
/// <param name="analyzer">The analyzer to run on the documents.</param>
/// <param name="documents">The Documents that the analyzer will be run on.</param>
/// <returns>An array of Diagnostics that surfaced in the source code, sorted by Location.</returns>
protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyzer analyzer, Document[] documents)
{
var projects = new HashSet<Project>();
Expand All @@ -73,7 +59,7 @@ protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyz
}
else
{
for (int i = 0; i < documents.Length; i++)
for (var i = 0; i < documents.Length; i++)
{
var document = documents[i];
var tree = document.GetSyntaxTreeAsync().Result;
Expand All @@ -92,24 +78,44 @@ protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyz
}

/// <summary>
/// Sort diagnostics by location in source document
/// Create a Document from a string through creating a project that contains it.
/// </summary>
/// <param name="source">Classes in the form of a string.</param>
/// <param name="language">The language the source code is in.</param>
/// <returns>A Document created from the source string.</returns>
protected static Document CreateDocument(string source, string language = LanguageNames.CSharp)
{
return CreateProject(new[] { source }, language).Documents.First();
}

/// <summary>
/// Given classes in the form of strings, their language, and an IDiagnosticAnalyzer to apply to it, return the diagnostics found in the string after converting it to a document.
/// </summary>
/// <param name="sources">Classes in the form of strings.</param>
/// <param name="language">The language the source classes are in.</param>
/// <param name="analyzer">The analyzer to be run on the sources.</param>
/// <returns>An array of Diagnostics that surfaced in the source code, sorted by Location.</returns>
private static Diagnostic[] GetSortedDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer)
{
return GetSortedDiagnosticsFromDocuments(analyzer, GetDocuments(sources, language));
}

/// <summary>
/// Sort diagnostics by location in source document.
/// </summary>
/// <param name="diagnostics">The list of Diagnostics to be sorted</param>
/// <returns>An IEnumerable containing the Diagnostics in order of Location</returns>
/// <param name="diagnostics">The list of Diagnostics to be sorted.</param>
/// <returns>An IEnumerable containing the Diagnostics in order of Location.</returns>
private static Diagnostic[] SortDiagnostics(IEnumerable<Diagnostic> diagnostics)
{
return diagnostics.OrderBy(d => d.Location.SourceSpan.Start).ToArray();
}

#endregion

#region Set up compilation and documents
/// <summary>
/// Given an array of strings as sources and a language, turn them into a project and return the documents and spans of it.
/// </summary>
/// <param name="sources">Classes in the form of strings</param>
/// <param name="language">The language the source code is in</param>
/// <returns>A Tuple containing the Documents produced from the sources and their TextSpans if relevant</returns>
/// <param name="sources">Classes in the form of strings.</param>
/// <param name="language">The language the source code is in.</param>
/// <returns>A Tuple containing the Documents produced from the sources and their TextSpans if relevant.</returns>
private static Document[] GetDocuments(string[] sources, string language)
{
if (language != LanguageNames.CSharp && language != LanguageNames.VisualBasic)
Expand All @@ -128,27 +134,16 @@ private static Document[] GetDocuments(string[] sources, string language)
return documents;
}

/// <summary>
/// Create a Document from a string through creating a project that contains it.
/// </summary>
/// <param name="source">Classes in the form of a string</param>
/// <param name="language">The language the source code is in</param>
/// <returns>A Document created from the source string</returns>
protected static Document CreateDocument(string source, string language = LanguageNames.CSharp)
{
return CreateProject(new[] { source }, language).Documents.First();
}

/// <summary>
/// Create a project using the inputted strings as sources.
/// </summary>
/// <param name="sources">Classes in the form of strings</param>
/// <param name="language">The language the source code is in</param>
/// <returns>A Project created out of the Documents created from the source strings</returns>
/// <param name="sources">Classes in the form of strings.</param>
/// <param name="language">The language the source code is in.</param>
/// <returns>A Project created out of the Documents created from the source strings.</returns>
private static Project CreateProject(string[] sources, string language = LanguageNames.CSharp)
{
string fileNamePrefix = DefaultFilePathPrefix;
string fileExt = language == LanguageNames.CSharp ? CSharpDefaultFileExt : VisualBasicDefaultExt;
var fileNamePrefix = DefaultFilePathPrefix;
var fileExt = language == LanguageNames.CSharp ? CSharpDefaultFileExt : VisualBasicDefaultExt;

var projectId = ProjectId.CreateNewId(debugName: TestProjectName);

Expand All @@ -163,17 +158,16 @@ private static Project CreateProject(string[] sources, string language = Languag
.AddMetadataReference(projectId, CodeAnalysisReference)
.AddMetadataReference(projectId, NUnitReference);

int count = 0;
var count = 0;
foreach (var source in sources)
{
var newFileName = fileNamePrefix + count + "." + fileExt;
var documentId = DocumentId.CreateNewId(projectId, debugName: newFileName);
solution = solution.AddDocument(documentId, newFileName, SourceText.From(source));
count++;
}

return solution.GetProject(projectId);
}
#endregion
}
}

}
Loading

0 comments on commit 24d08ca

Please sign in to comment.