Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 17 additions & 22 deletions src/Exercism.Analyzers.CSharp/Analysis.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using System.Collections.Generic;

using Exercism.Analyzers.CSharp.Analyzers;

using Microsoft.CodeAnalysis;
Expand All @@ -12,14 +10,11 @@ internal record Analysis(List<Comment> Comments, List<string> Tags)
public static Analysis Empty => new(new List<Comment>(), new List<string>());
}

internal abstract class Analyzer : CSharpSyntaxWalker
internal abstract class Analyzer(Submission submission, SyntaxWalkerDepth syntaxWalkerDepth = SyntaxWalkerDepth.Token)
: CSharpSyntaxWalker(syntaxWalkerDepth)
{
private readonly Submission _submission;
private SemanticModel _semanticModel;
private Analysis _analysis;

protected Analyzer(Submission submission, SyntaxWalkerDepth syntaxWalkerDepth = SyntaxWalkerDepth.Token) : base(syntaxWalkerDepth) =>
_submission = submission;
private SemanticModel? _semanticModel;
private Analysis? _analysis;

public static Analysis Analyze(Submission submission)
{
Expand All @@ -34,21 +29,21 @@ public static Analysis Analyze(Submission submission)
return analysis;
}

protected void AddComment(Comment comment) => _analysis.Comments.Add(comment);
protected void AddComment(Comment comment) => _analysis!.Comments.Add(comment);

protected void AddTags(params string[] tags)
{
foreach (var tag in tags)
_analysis.Tags.Add(tag);
_analysis!.Tags.Add(tag);
}

private void Analyze(Analysis analysis)
{
_analysis = analysis;

foreach (var syntaxTree in _submission.Compilation.SyntaxTrees)
foreach (var syntaxTree in submission.Compilation.SyntaxTrees)
{
_semanticModel = _submission.Compilation.GetSemanticModel(syntaxTree);
_semanticModel = submission.Compilation.GetSemanticModel(syntaxTree);
Visit(syntaxTree.GetRoot());
}
}
Expand Down Expand Up @@ -102,17 +97,17 @@ public static IEnumerable<Analyzer> CreateAnalyzers(Submission submission)
}
}

protected SymbolInfo GetSymbolInfo(SyntaxNode node) => _semanticModel.GetSymbolInfo(node);
protected ISymbol GetSymbol(SyntaxNode node) => GetSymbolInfo(node).Symbol;
protected string GetSymbolName(SyntaxNode node) => GetSymbol(node)?.ToDisplayString();
protected SymbolInfo GetSymbolInfo(SyntaxNode node) => _semanticModel!.GetSymbolInfo(node);
protected ISymbol? GetSymbol(SyntaxNode node) => GetSymbolInfo(node).Symbol;
protected string? GetSymbolName(SyntaxNode node) => GetSymbol(node)?.ToDisplayString();

protected ISymbol GetDeclaredSymbol(SyntaxNode node) => _semanticModel.GetDeclaredSymbol(node);
protected string GetDeclaredSymbolName(SyntaxNode node) => GetDeclaredSymbol(node)?.ToDisplayString();
protected ISymbol? GetDeclaredSymbol(SyntaxNode node) => _semanticModel!.GetDeclaredSymbol(node);
protected string? GetDeclaredSymbolName(SyntaxNode node) => GetDeclaredSymbol(node)?.ToDisplayString();

protected TypeInfo GetTypeInfo(SyntaxNode node) => _semanticModel.GetTypeInfo(node);
protected IOperation GetOperation(SyntaxNode node) => _semanticModel.GetOperation(node);
protected TypeInfo GetTypeInfo(SyntaxNode node) => _semanticModel!.GetTypeInfo(node);
protected IOperation? GetOperation(SyntaxNode node) => _semanticModel!.GetOperation(node);

protected IMethodSymbol GetConstructedFromSymbol(SyntaxNode node) =>
protected IMethodSymbol? GetConstructedFromSymbol(SyntaxNode node) =>
GetSymbol(node) is IMethodSymbol methodSymbol ? methodSymbol.ConstructedFrom : null;
protected string GetConstructedFromSymbolName(SyntaxNode node) => GetConstructedFromSymbol(node)?.ToDisplayString();
protected string? GetConstructedFromSymbolName(SyntaxNode node) => GetConstructedFromSymbol(node)?.ToDisplayString();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class CollatzConjectureAnalyzer : Analyzer
internal class CollatzConjectureAnalyzer(Submission submission) : Analyzer(submission)
{
public CollatzConjectureAnalyzer(Submission submission) : base(submission)
{
}

public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
if (GetConstructedFromSymbolName(node) == "System.Collections.Generic.IEnumerable<TSource>.Count<TSource>()")
Expand Down
11 changes: 2 additions & 9 deletions src/Exercism.Analyzers.CSharp/Analyzers/CommonAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
using System.Collections.Generic;
using System.Linq;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class CommonAnalyzer : Analyzer
internal class CommonAnalyzer(Submission submission) : Analyzer(submission)
{
public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
{
Expand Down Expand Up @@ -90,10 +87,6 @@ public override void VisitAssignmentExpression(AssignmentExpressionSyntax node)
"Console.Out.WriteLine"
};

public CommonAnalyzer(Submission submission) : base(submission)
{
}

private static class Comments
{
public static readonly Comment DoNotUseMainMethod = new("csharp.general.has_main_method", CommentType.Essential);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
using System.Linq;

using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class DifferenceOfSquaresAnalyzer : Analyzer
internal class DifferenceOfSquaresAnalyzer(Submission submission) : Analyzer(submission)
{
public DifferenceOfSquaresAnalyzer(Submission submission) : base(submission)
{
}

public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
{
if (node.DescendantNodes()
.OfType<InvocationExpressionSyntax>()
.Select(GetSymbol)
.Where(invocationSymbol => invocationSymbol is not null)
.All(invocationSymbol => invocationSymbol.ContainingType.ToDisplayString() == "System.Math"))
.All(invocationSymbol => invocationSymbol?.ContainingType.ToDisplayString() == "System.Math"))
AddTags(Tags.TechniqueMath);

base.VisitMethodDeclaration(node);
Expand Down
10 changes: 2 additions & 8 deletions src/Exercism.Analyzers.CSharp/Analyzers/GigasecondAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
using System.Linq;

using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class GigasecondAnalyzer : Analyzer
internal class GigasecondAnalyzer(Submission submission) : Analyzer(submission)
{
public GigasecondAnalyzer(Submission submission) : base(submission)
{
}

public override void VisitCompilationUnit(CompilationUnitSyntax node)
{
if (node.DescendantNodes()
.OfType<InvocationExpressionSyntax>()
.Select(GetSymbol)
.Where(symbol => symbol is not null)
.All(symbol => symbol.ToDisplayString() != "System.DateTime.AddSeconds(double)"))
.All(symbol => symbol?.ToDisplayString() != "System.DateTime.AddSeconds(double)"))
AddComment(Comments.UseAddSeconds);

base.VisitCompilationUnit(node);
Expand Down
6 changes: 1 addition & 5 deletions src/Exercism.Analyzers.CSharp/Analyzers/GrainsAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class GrainsAnalyzer : Analyzer
internal class GrainsAnalyzer(Submission submission) : Analyzer(submission)
{
public GrainsAnalyzer(Submission submission) : base(submission)
{
}

public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
if (GetSymbolName(node.Expression) == "System.Math.Pow(double, double)")
Expand Down
8 changes: 2 additions & 6 deletions src/Exercism.Analyzers.CSharp/Analyzers/IsogramAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class IsogramAnalyzer : Analyzer
{
public IsogramAnalyzer(Submission submission) : base(submission)
{
}

internal class IsogramAnalyzer(Submission submission) : Analyzer(submission)
{
public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
if (GetSymbolInfo(node).Symbol is IMethodSymbol methodSymbol)
Expand Down
10 changes: 2 additions & 8 deletions src/Exercism.Analyzers.CSharp/Analyzers/LeapAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
using System.Linq;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class LeapAnalyzer : Analyzer
internal class LeapAnalyzer(Submission submission) : Analyzer(submission)
{
public LeapAnalyzer(Submission submission) : base(submission)
{
}

public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
{
if (GetDeclaredSymbolName(node) == "Leap.IsLeapYear(int)" &&
Expand Down
8 changes: 2 additions & 6 deletions src/Exercism.Analyzers.CSharp/Analyzers/PangramAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class PangramAnalyzer : Analyzer
{
public PangramAnalyzer(Submission submission) : base(submission)
{
}

internal class PangramAnalyzer(Submission submission) : Analyzer(submission)
{
public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
switch (GetSymbolName(node))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class ProteinTranslationAnalyzer : Analyzer
{
public ProteinTranslationAnalyzer(Submission submission) : base(submission)
{
}

internal class ProteinTranslationAnalyzer(Submission submission) : Analyzer(submission)
{
public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
switch (GetSymbolName(node))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class RaindropsAnalyzer : Analyzer
internal class RaindropsAnalyzer(Submission submission) : Analyzer(submission)
{
public RaindropsAnalyzer(Submission submission) : base(submission)
{
}

public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
if (GetSymbol(node) is IMethodSymbol methodSymbol &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class ReverseStringAnalyzer : Analyzer
internal class ReverseStringAnalyzer(Submission submission) : Analyzer(submission)
{
public ReverseStringAnalyzer(Submission submission) : base(submission)
{
}

public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
if (GetConstructedFromSymbolName(node) == "System.Array.Reverse<T>(T[])")
Expand Down
12 changes: 2 additions & 10 deletions src/Exercism.Analyzers.CSharp/Analyzers/TagAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Operations;

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class TagAnalyzer : Analyzer
internal class TagAnalyzer(Submission submission) : Analyzer(submission, SyntaxWalkerDepth.Trivia)
{
public TagAnalyzer(Submission submission) : base(submission, SyntaxWalkerDepth.Trivia)
{
}

public override void VisitForStatement(ForStatementSyntax node)
{
AddTags(Tags.ConstructForLoop, Tags.TechniqueLooping);
Expand Down Expand Up @@ -204,7 +196,7 @@ public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
AddTags(Tags.ConstructInvocation, Tags.ConstructMethod);

if (GetSymbol(node) is not null && GetSymbol(node).ContainingNamespace.ToDisplayString() == "System.Linq")
if (GetSymbol(node)?.ContainingNamespace.ToDisplayString() == "System.Linq")
AddTags(Tags.ConstructLinq, Tags.ParadigmFunctional);

if (GetSymbolName(node) == "object.GetType()")
Expand Down
6 changes: 1 addition & 5 deletions src/Exercism.Analyzers.CSharp/Analyzers/TwoFerAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class TwoFerAnalyzer : Analyzer
internal class TwoFerAnalyzer(Submission submission) : Analyzer(submission)
{
public TwoFerAnalyzer(Submission submission) : base(submission)
{
}

public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
{
switch (GetDeclaredSymbolName(node))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
using System.Linq;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace Exercism.Analyzers.CSharp.Analyzers;

internal class WeighingMachineAnalyzer : Analyzer
internal class WeighingMachineAnalyzer(Submission submission) : Analyzer(submission)
{
public WeighingMachineAnalyzer(Submission submission) : base(submission)
{
}

public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node)
{
switch (GetDeclaredSymbolName(node))
{
case "WeighingMachine.DisplayWeight":
{
SyntaxNode getter = node.ExpressionBody == null
SyntaxNode? getter = node.ExpressionBody == null
? node.DescendantNodes()
.OfType<AccessorDeclarationSyntax>()
.FirstOrDefault(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<TargetFramework>net10.0</TargetFramework>
<OutputType>Exe</OutputType>
<PublishReadyToRun>true</PublishReadyToRun>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
Expand Down
9 changes: 2 additions & 7 deletions src/Exercism.Analyzers.CSharp/Loader.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand Down Expand Up @@ -51,7 +46,7 @@ private static HashSet<string> NonSubmissionFiles(Options options)

return nonSubmissionFileKeys
.Where(filesConfig.ContainsKey)
.SelectMany(key => filesConfig[key].Deserialize<IEnumerable<string>>())
.SelectMany(key => filesConfig[key].Deserialize<IEnumerable<string>>()!)
.Select(relativePath => Path.Combine(options.InputDirectory, relativePath))
.ToHashSet();
}
Expand All @@ -77,7 +72,7 @@ private static CSharpCompilationOptions CompilationOptions() =>
new(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug);

private static IEnumerable<MetadataReference> References() =>
((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES"))!.Split(Path.PathSeparator)
((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")!).Split(Path.PathSeparator)
.Select(p => MetadataReference.CreateFromFile(p));
}
}
4 changes: 0 additions & 4 deletions src/Exercism.Analyzers.CSharp/Output.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
Expand Down
Loading
Loading