private void WriteUCFG <TDeclarationSyntax>(SyntaxNodeAnalysisContext context, Func <TDeclarationSyntax, CSharpSyntaxNode> getBody) where TDeclarationSyntax : SyntaxNode { var declaration = (TDeclarationSyntax)context.Node; var symbol = context.SemanticModel.GetDeclaredSymbol(declaration); var methodSymbol = (symbol is IPropertySymbol propertySymbol) ? propertySymbol.GetMethod // We are in PropertyDeclarationSyntax : symbol as IMethodSymbol; // all other are methods if (methodSymbol == null || methodSymbol.IsAbstract || methodSymbol.IsExtern || !CSharpControlFlowGraph.TryGet(getBody(declaration), context.SemanticModel, out var cfg)) { return; } var ucfg = new UniversalControlFlowGraphBuilder() .Build(context.SemanticModel, declaration, methodSymbol, cfg); if (IsValid(ucfg)) { var fileName = $"{projectBuildId}_{Interlocked.Increment(ref protobufFileIndex)}"; WriteProtobuf(ucfg, Path.Combine(protobufDirectory, $"ucfg_{fileName}.pb")); if (ShouldGenerateDot) { WriteDot(Path.Combine(protobufDirectory, $"ucfg_{fileName}.dot"), writer => UcfgSerializer.Serialize(ucfg, writer)); WriteDot(Path.Combine(protobufDirectory, $"cfg_{fileName}.dot"), writer => CfgSerializer.Serialize(ucfg.MethodId, cfg, writer)); } } }
public void GetMethodId_Explicit_Interface_Implementations() { const string code = @" using System; using System.Collections.Generic; namespace Namespace { public class Bar : IBar { void IBar.Foo(string s) { } public void Foo(string s) { } } public interface IBar { void Foo(string s); } } "; var(syntaxTree, semanticModel) = TestHelper.Compile(code); MethodId("Foo").Should().Be("Namespace.IBar.Foo(string)"); MethodId("Foo", skip: 1).Should().Be("Namespace.Bar.Foo(string)"); string MethodId(string methodName, int skip = 0) => UniversalControlFlowGraphBuilder.GetMethodId(semanticModel.GetDeclaredSymbol(syntaxTree.GetMethod(methodName, skip))); }
private void WriteUCFG <TDeclarationSyntax>(SyntaxNodeAnalysisContext context, Func <TDeclarationSyntax, CSharpSyntaxNode> getBody) where TDeclarationSyntax : SyntaxNode { var declaration = (TDeclarationSyntax)context.Node; var symbol = context.SemanticModel.GetDeclaredSymbol(declaration); var methodSymbol = (symbol is IPropertySymbol propertySymbol) ? propertySymbol.GetMethod // We are in PropertyDeclarationSyntax : symbol as IMethodSymbol; // all other are methods if (methodSymbol == null || methodSymbol.IsAbstract || methodSymbol.IsExtern || !CSharpControlFlowGraph.TryGet(getBody(declaration), context.SemanticModel, out var cfg)) { return; } var ucfg = new UniversalControlFlowGraphBuilder() .Build(context.SemanticModel, declaration, methodSymbol, cfg); if (!IsValid(ucfg)) { return; } var path = Path.Combine(protobufDirectory, $"ucfg_{projectBuildId}_{Interlocked.Increment(ref protobufFileIndex)}.pb"); using (var stream = File.Create(path)) { ucfg.WriteTo(stream); } }
protected UCFG GetUcfgForMethod(string code, string methodName) { (var method, var semanticModel) = TestHelper.Compile(code, Verifier.SystemWebMvcAssembly).GetMethod(methodName); var builder = new UniversalControlFlowGraphBuilder(); return(builder.Build(semanticModel, method, semanticModel.GetDeclaredSymbol(method), CSharpControlFlowGraph.Create(method.Body, semanticModel))); }
private static UCFG CreateUcfgForConstructor(string code, string name) { var(syntaxTree, semanticModel) = TestHelper.Compile(code, Verifier.SystemWebMvcAssembly); var ctor = syntaxTree.GetRoot() .DescendantNodes() .OfType <ConstructorDeclarationSyntax>() .First(m => m.Identifier.ValueText == name); var builder = new UniversalControlFlowGraphBuilder(); var ucfg = builder.Build(semanticModel, ctor, semanticModel.GetDeclaredSymbol(ctor), CSharpControlFlowGraph.Create(ctor.Body, semanticModel)); return(ucfg); }
public void GetMethodId_Constructors() { const string code = @" using System; namespace Namespace { public class Class1 { public Class1() { } public Class1(string s) { } } } "; var(syntaxTree, semanticModel) = TestHelper.Compile(code); CtorId("Class1").Should().Be("Namespace.Class1.Class1()"); CtorId("Class1", skip: 1).Should().Be("Namespace.Class1.Class1(string)"); string CtorId(string className, int skip = 0) => UniversalControlFlowGraphBuilder.GetMethodId(semanticModel.GetDeclaredSymbol(syntaxTree.GetConstructor(className, skip))); }
public void GetMethodId_Methods() { const string code = @" using System; using System.Collections.Generic; namespace Namespace { public class Class1 { public void PrimitiveTypes1(string s) { } public void PrimitiveTypes2(String s) { } public void PrimitiveTypes3(System.String s) { } public void ArrayTypes1(string[] s) { } public void ArrayTypes2(string[,] s) { } public void ArrayTypes3(string[][] s) { } public void UserType(Class1 s) { } public void SystemType(Uri uri) { } public void GenericMethod1<T1,T2>(T1 x) { } public void Nullables(int? x, Nullable<int> y) { } public void GenericArgument(IEnumerable<string> strings) { } public void Overload1(string s) { } public void Overload1(string s, string s) { } public void NestedMethods() { void Foo() { } // We don't really support nested, but we should not throw } public class Class2 { public void InnerClass(Class2 s) { } } } public class GenericClass<T1> { public void GenericMethod2(T1 x) { } public void GenericMethod3<T2>(T1 x, T2 y) { } } public class BaseClass<T1> { public virtual void Method1(T1 x) { } public virtual void Method2(T1 x) { } } public class Descendant : BaseClass<string> { public override void Method1(string x) { } } namespace Inner { public class Class2 { public string InnerNamespace() { } } } } public class Class3 { public void NoNamespace(Class3 s) { } } public static class Extensions { public static void Extension(this string s, int x) { } }"; var(syntaxTree, semanticModel) = TestHelper.Compile(code); MethodId("PrimitiveTypes1").Should().Be("Namespace.Class1.PrimitiveTypes1(string)"); MethodId("PrimitiveTypes2").Should().Be("Namespace.Class1.PrimitiveTypes2(string)"); MethodId("PrimitiveTypes3").Should().Be("Namespace.Class1.PrimitiveTypes3(string)"); MethodId("ArrayTypes1").Should().Be("Namespace.Class1.ArrayTypes1(string[])"); MethodId("ArrayTypes2").Should().Be("Namespace.Class1.ArrayTypes2(string[*,*])"); MethodId("ArrayTypes3").Should().Be("Namespace.Class1.ArrayTypes3(string[][])"); MethodId("UserType").Should().Be("Namespace.Class1.UserType(Namespace.Class1)"); MethodId("SystemType").Should().Be("Namespace.Class1.SystemType(System.Uri)"); MethodId("GenericMethod1").Should().Be("Namespace.Class1.GenericMethod1<T1, T2>(T1)"); MethodId("Nullables").Should().Be("Namespace.Class1.Nullables(int?, int?)"); MethodId("GenericArgument").Should().Be("Namespace.Class1.GenericArgument(System.Collections.Generic.IEnumerable<string>)"); MethodId("Overload1").Should().Be("Namespace.Class1.Overload1(string)"); MethodId("Overload1", skip: 1).Should().Be("Namespace.Class1.Overload1(string, string)"); MethodId("GenericMethod2").Should().Be("Namespace.GenericClass<T1>.GenericMethod2(T1)"); MethodId("GenericMethod3").Should().Be("Namespace.GenericClass<T1>.GenericMethod3<T2>(T1, T2)"); MethodId("InnerClass").Should().Be("Namespace.Class1.Class2.InnerClass(Namespace.Class1.Class2)"); MethodId("Method1").Should().Be("Namespace.BaseClass<T1>.Method1(T1)"); MethodId("Method1", skip: 1).Should().Be("Namespace.Descendant.Method1(string)"); MethodId("InnerNamespace").Should().Be("Namespace.Inner.Class2.InnerNamespace()"); MethodId("NoNamespace").Should().Be("Class3.NoNamespace(Class3)"); MethodId("Extension").Should().Be("Extensions.Extension(string, int)"); string MethodId(string methodName, int skip = 0) => UniversalControlFlowGraphBuilder.GetMethodId(semanticModel.GetDeclaredSymbol(syntaxTree.GetMethod(methodName, skip))); }
public void GetMethodId_Properties() { const string code = @" using System; namespace Namespace { public class Class1 { public string Property1 { get { return null; } set { } } public string Property2 => null; } public class GenericClass<T1> { public T1 Property3 { get; set; } } public class BaseClass<T1> { public virtual T1 Property4 { get { return default(T1); } set { } } } public class Descendant : BaseClass<string> { public override string Property4 { get { return null; } set { } } } namespace Inner { public class Class2 { public string Property5 { get; set; } } } } public class Class3 { public string Property6 { get; set; } }"; var(syntaxTree, semanticModel) = TestHelper.Compile(code); PropertyGetId("Property1").Should().Be("Namespace.Class1.Property1.get"); PropertySetId("Property1").Should().Be("Namespace.Class1.Property1.set"); PropertyGetId("Property2").Should().Be("Namespace.Class1.Property2.get"); PropertySetId("Property2").Should().Be(KnownMethodId.Unknown); PropertyGetId("Property3").Should().Be("Namespace.GenericClass<T1>.Property3.get"); PropertySetId("Property3").Should().Be("Namespace.GenericClass<T1>.Property3.set"); PropertyGetId("Property4").Should().Be("Namespace.BaseClass<T1>.Property4.get"); PropertySetId("Property4").Should().Be("Namespace.BaseClass<T1>.Property4.set"); PropertyGetId("Property4", 1).Should().Be("Namespace.Descendant.Property4.get"); PropertySetId("Property4", 1).Should().Be("Namespace.Descendant.Property4.set"); PropertyGetId("Property5").Should().Be("Namespace.Inner.Class2.Property5.get"); PropertySetId("Property5").Should().Be("Namespace.Inner.Class2.Property5.set"); PropertyGetId("Property6").Should().Be("Class3.Property6.get"); PropertySetId("Property6").Should().Be("Class3.Property6.set"); string PropertyGetId(string propertyName, int skip = 0) => UniversalControlFlowGraphBuilder.GetMethodId(semanticModel.GetDeclaredSymbol(syntaxTree.GetProperty(propertyName, skip)).GetMethod); string PropertySetId(string propertyName, int skip = 0) => UniversalControlFlowGraphBuilder.GetMethodId(semanticModel.GetDeclaredSymbol(syntaxTree.GetProperty(propertyName, skip)).SetMethod); }