Last active
August 29, 2015 13:56
-
-
Save icalvo/9235756 to your computer and use it in GitHub Desktop.
Class for collecting calls to given targets in your C# source code, using Roslyn.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Icm | |
{ | |
using System.Collections.Generic; | |
using System.Linq; | |
using Roslyn.Compilers.CSharp; | |
/// <summary> | |
/// This syntax walker collects all the calls to the specified targets. | |
/// </summary> | |
public class CallsCollector : SyntaxWalker | |
{ | |
private readonly IEnumerable<string> targets; | |
private readonly IList<MemberAccessExpressionSyntax> calls; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="CallsCollector"/> class. | |
/// </summary> | |
/// <param name="targets">The targets.</param> | |
public CallsCollector(params string[] targets) | |
{ | |
this.calls = new List<MemberAccessExpressionSyntax>(); | |
this.targets = targets; | |
} | |
/// <summary> | |
/// Gets the calls found to the specified targets. | |
/// </summary> | |
/// <value> | |
/// The calls found to the specified targets. | |
/// </value> | |
public IEnumerable<MemberAccessExpressionSyntax> Calls | |
{ | |
get | |
{ | |
return this.calls; | |
} | |
} | |
/// <summary> | |
/// Determines whether the specified target is called. | |
/// </summary> | |
/// <param name="target">The target.</param> | |
/// <returns></returns> | |
public bool IsCalled(string target) | |
{ | |
return this.calls.Any(call => ((IdentifierNameSyntax)call.Expression).Identifier.ValueText == target); | |
} | |
/// <summary> | |
/// Called when the visitor visits a MemberAccessExpressionSyntax node. | |
/// </summary> | |
/// <param name="node">The node.</param> | |
public override void VisitMemberAccessExpression(MemberAccessExpressionSyntax node) | |
{ | |
var identifierName = node.Expression as IdentifierNameSyntax; | |
if (identifierName != null) | |
{ | |
if (this.targets.Contains(identifierName.Identifier.ValueText)) | |
{ | |
this.calls.Add(node); | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Icm | |
{ | |
using System.IO; | |
using Microsoft.VisualStudio.TestTools.UnitTesting; | |
using Roslyn.Compilers.CSharp; | |
[TestClass] | |
public class ConventionsTests | |
{ | |
/// <summary> | |
/// Tests that there are no calls to File or Directory in the code. | |
/// </summary> | |
[TestMethod] | |
public void FileDirectoryCallsForbidden() | |
{ | |
var solutionRootPath = Path.GetFullPath(@"..\..\.."); | |
foreach (string sourceFileName in Directory.GetFiles(solutionRootPath, "*.cs", SearchOption.AllDirectories)) | |
{ | |
SyntaxTree tree = SyntaxTree.ParseFile(sourceFileName); | |
CompilationUnitSyntax root = tree.GetRoot(); | |
var collector = new CallsCollector("File", "Directory"); | |
collector.Visit(root); | |
Assert.IsFalse(collector.IsCalled("File"), "System.IO.File is called at " + sourceFileName.Substring(solutionRootPath.Length) + ". Please use an IFileSystem dependency instead."); | |
Assert.IsFalse(collector.IsCalled("Directory"), "System.IO.Directory is called at " + sourceFileName.Substring(solutionRootPath.Length) + ". Please use an IFileSystem dependency instead."); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment