Skip to content

Instantly share code, notes, and snippets.

@tebeco
Created October 19, 2023 21:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tebeco/cf13f3fa8e3a1071a15a46db646f8cea to your computer and use it in GitHub Desktop.
Save tebeco/cf13f3fa8e3a1071a15a46db646f8cea to your computer and use it in GitHub Desktop.
AttrocityDetector
using System.Data.Common;
using System.Reflection.Metadata;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.MSBuild;
MSBuildLocator.RegisterDefaults();
using var workspace = MSBuildWorkspace.Create();
var solution = await workspace.OpenSolutionAsync(args[0]);
var apiProject = solution.Projects.Single(project => project.Name == args[1]);
var compilation = await apiProject.GetCompilationAsync();
ArgumentNullException.ThrowIfNull(compilation);
var baseControllerSymbol = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.ControllerBase");
var httpGetSymbol = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.HttpGetAttribute");
var httpPostSymbol = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.HttpPostAttribute");
var httpPutSymbol = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.HttpPutAttribute");
var httpDeleteSymbol = compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.HttpDeleteAttribute");
var assemblyReference = compilation.References
.OfType<MetadataReference>()
.First(reference => reference.Display == args[2]);
var bannedAssemblySymbol = compilation.GetAssemblyOrModuleSymbol(assemblyReference);
var controllerFiles = compilation.SyntaxTrees.Where(tree => tree.FilePath.Contains("Controller.cs"));
var parameterSymbols = new List<(IMethodSymbol, IParameterSymbol)>();
foreach (var controllerFile in controllerFiles)
{
var semanticModel = compilation.GetSemanticModel(controllerFile);
var fileRoot = await controllerFile.GetRootAsync();
var classDeclarations = fileRoot.DescendantNodes().OfType<ClassDeclarationSyntax>();
foreach (var classDeclaration in classDeclarations)
{
var classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration) as ITypeSymbol;
if (classSymbol?.BaseType?.Equals(baseControllerSymbol, SymbolEqualityComparer.Default) == true)
{
var endpoints = classSymbol
.GetMembers()
.OfType<IMethodSymbol>()
.Where(member =>
member.DeclaredAccessibility == Accessibility.Public
&& member.GetAttributes().Any(attribute =>
attribute.AttributeClass?.Equals(httpGetSymbol, SymbolEqualityComparer.Default) == true
|| attribute.AttributeClass?.Equals(httpPostSymbol, SymbolEqualityComparer.Default) == true
|| attribute.AttributeClass?.Equals(httpPutSymbol, SymbolEqualityComparer.Default) == true
|| attribute.AttributeClass?.Equals(httpDeleteSymbol, SymbolEqualityComparer.Default) == true))
.Where(endpoint => endpoint.Parameters.Any())
.SelectMany(endpoint => endpoint.Parameters.Select(parameter => (endpoint, parameter)))
;
foreach (var result in endpoints)
{
var (method, parameter) = result;
Console.WriteLine(method.ContainingType.Name);
Console.WriteLine($"\t {method.Name}:");
if (parameter.Type.ContainingAssembly.Equals(bannedAssemblySymbol, SymbolEqualityComparer.Default))
{
Console.ForegroundColor = ConsoleColor.Red;
}
Console.WriteLine($"\t\t {parameter.Type.Name} {parameter.Name} - {parameter.Type.ContainingAssembly.Name}");
Console.ForegroundColor = ConsoleColor.Gray;
};
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment