public void Get_Should_ExamineAllClassesFromAssemblies() { var assemblyFilter = new Mock <IFilteredAssemblies>().Object; var classReaderMock = new Mock <IClassReader>(); var c1 = new Mock <IClassInfo>().Object; var c2 = new Mock <IClassInfo>().Object; var classes = new IClassInfo[] { c1, c2 }; classReaderMock.Setup(c => c.LoadFromAssemblies(assemblyFilter)).Returns(classes); var classInfoCollectorMock = new Mock <IClassInfoCollector>(); var examinedClasses = new List <IClassInfo>(); classInfoCollectorMock.Setup(c => c.Examine(It.IsAny <IClassInfo>())).Callback <IClassInfo>(c => examinedClasses.Add(c)); var sut = new ClassCollector(classReaderMock.Object, classInfoCollectorMock.Object); sut.Assemblies = assemblyFilter; var actualClasses = sut.Get().ToArray(); Assert.IsTrue(examinedClasses.Count == 2); Assert.IsTrue(examinedClasses.Contains(c1)); Assert.IsTrue(examinedClasses.Contains(c2)); Assert.IsTrue(actualClasses.Length == 2); Assert.IsTrue(actualClasses.Contains(c1)); Assert.IsTrue(actualClasses.Contains(c2)); }
public void TypedInheritanceTest() { const string baseClasses = "IController<Controller>"; var tree = CSharpSyntaxTree.ParseText(@" public class A : IController<Controller> { public void AMember() { } }" ); var root = (CompilationUnitSyntax)tree.GetRoot(); var classCollector = new ClassCollector(); classCollector.VisitClassDeclaration(root.DescendantNodes().OfType <ClassDeclarationSyntax>().First()); Assert.IsNotNull(classCollector.Items); Assert.AreEqual(classCollector.Items.First().BaseClasses, baseClasses); }
public void BasicMethodInClass() { var tree = CSharpSyntaxTree.ParseText(@" public class Cheese { public void Consume() {} private void Dispose() {} }" ); var root = (CompilationUnitSyntax)tree.GetRoot(); var classCollector = new ClassCollector(); classCollector.Visit(root); Assert.AreEqual(classCollector.Items.Count, 1); Assert.AreEqual(classCollector.Items.First().ClassName, "Cheese"); Assert.AreEqual(classCollector.Items.First().Methods.Count(), 1); Assert.AreEqual(classCollector.Items.First().Methods.First().Name, "Consume"); Assert.AreEqual(classCollector.Items.First().Methods.First().ReturnType, "void"); Assert.AreEqual(classCollector.Items.First().Methods.First().Params.Any(), false); }
static void Main(string[] args) { var classContents = File.ReadAllText(@"C:\Users\spoel\source\playground\roslyntest\Models\SomeDomainObject.cs"); var tree = CSharpSyntaxTree.ParseText(classContents); var sourceRoot = (CompilationUnitSyntax)tree.GetRoot(); var classCollector = new ClassCollector(); classCollector.Visit(sourceRoot); foreach (var classDeclaration in classCollector.classDeclarations) { var namespaceDeclarationSyntax = classDeclaration.Parent as NamespaceDeclarationSyntax; if (namespaceDeclarationSyntax == null) { continue; } var testDataBuilderTypeName = $"{classDeclaration.Identifier.Text}TestDataBuilder"; Console.WriteLine($"Generating {testDataBuilderTypeName}"); var testDataBuilderClass = SyntaxFactory.ClassDeclaration(testDataBuilderTypeName); testDataBuilderClass = testDataBuilderClass.AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)); foreach (ConstructorDeclarationSyntax constructorDeclaration in classDeclaration.ChildNodes().Where(c => c.GetType() == typeof(ConstructorDeclarationSyntax))) { testDataBuilderClass = AddPrivateFields(testDataBuilderClass, constructorDeclaration); testDataBuilderClass = AddBuildMethod(classDeclaration.Identifier.Text, testDataBuilderClass, constructorDeclaration); testDataBuilderClass = AddBuilderMethods(testDataBuilderTypeName, testDataBuilderClass, constructorDeclaration); } sourceRoot = sourceRoot.ReplaceNode(namespaceDeclarationSyntax, namespaceDeclarationSyntax.AddMembers(testDataBuilderClass)); } Console.WriteLine(sourceRoot.NormalizeWhitespace().ToFullString()); }
static void Main(string[] args) { IEnumerable <string> files = Directory.EnumerateFiles(@"..\..\..\..\Jurassic", "*.cs", SearchOption.AllDirectories); files = files.Union(Directory.EnumerateFiles(@"..\..\..\..\Jurassic.Extensions", "*.cs", SearchOption.AllDirectories)); foreach (var csFilePath in files) { var syntaxTree = CSharpSyntaxTree.ParseText(File.ReadAllText(csFilePath)); var classCollector = new ClassCollector(); classCollector.Visit(syntaxTree.GetRoot()); // Construct the output file. var output = new StringBuilder(); output.AppendLine("/*"); output.AppendLine(" * This file is auto-generated, do not modify directly."); output.AppendLine(" */"); output.AppendLine(); output.AppendLine("using System.Collections.Generic;"); output.AppendLine("using Jurassic;"); if (classCollector.Classes.Any(classSyntax => ((NamespaceDeclarationSyntax)classSyntax.Parent).Name.ToString() != "Jurassic.Library")) { output.AppendLine("using Jurassic.Library;"); } output.AppendLine(); bool outputFile = false; foreach (var classSyntax in classCollector.Classes) { // Find all the methods with [JSInternalFunction], [JSCallFunction], [JSConstructorFunction], [JSProperty] or [JSField]. var memberCollector = new ClassMembersCollector(); memberCollector.Visit(classSyntax); if (memberCollector.JSInternalFunctionMethods.Any() == false && memberCollector.JSCallFunctionMethods.Any() == false && memberCollector.JSConstructorFunctionMethods.Any() == false && memberCollector.JSProperties.Any() == false && memberCollector.JSFields.Any() == false) { continue; } Console.WriteLine($"Generating stubs for {classSyntax.Identifier.ToString()}"); outputFile = true; var methodGroups = JSMethodGroup.FromMethods(memberCollector.JSInternalFunctionMethods); output.AppendLine($"namespace {((NamespaceDeclarationSyntax)classSyntax.Parent).Name}"); output.AppendLine("{"); output.AppendLine(); output.AppendLine($"\t{classSyntax.Modifiers} class {classSyntax.Identifier}"); output.AppendLine("\t{"); // Output the PopulateStubs method. if (memberCollector.JSInternalFunctionMethods.Any() || memberCollector.JSProperties.Any() || memberCollector.JSFields.Any()) { output.AppendLine("\t\tprivate static List<PropertyNameAndValue> GetDeclarativeProperties(ScriptEngine engine)"); output.AppendLine("\t\t{"); output.AppendLine($"\t\t\treturn new List<PropertyNameAndValue>({memberCollector.JSInternalFunctionMethods.Count + memberCollector.JSFields.Count + 4})"); output.AppendLine("\t\t\t{"); foreach (var field in memberCollector.JSFields) { foreach (var variable in field.Declaration.Variables) { output.AppendLine($"\t\t\t\tnew PropertyNameAndValue(\"{variable.Identifier.ToString()}\", {variable.Identifier.ToString()}, PropertyAttributes.Sealed),"); } } foreach (var property in memberCollector.JSProperties.Select(p => new JSProperty(p))) { if (property.SetterStubName == null) { output.AppendLine($"\t\t\t\tnew PropertyNameAndValue({property.PropertyKey}, new PropertyDescriptor(" + $"new ClrStubFunction(engine, \"get {property.FunctionName}\", 0, {property.GetterStubName}), " + $"null, {property.JSPropertyAttributes})),"); } else { output.AppendLine($"\t\t\t\tnew PropertyNameAndValue({property.PropertyKey}, new PropertyDescriptor(" + $"new ClrStubFunction(engine, \"get {property.FunctionName}\", 0, {property.GetterStubName}), " + $"new ClrStubFunction(engine, \"set {property.FunctionName}\", 0, {property.GetterStubName}), " + $"{property.JSPropertyAttributes})),"); } } foreach (var methodGroup in methodGroups) { output.AppendLine($"\t\t\t\tnew PropertyNameAndValue({methodGroup.PropertyKey}, " + $"new ClrStubFunction(engine, \"{methodGroup.FunctionName}\", " + $"{methodGroup.JSLength}, {methodGroup.StubName}), {methodGroup.JSPropertyAttributes}),"); } output.AppendLine("\t\t\t};"); output.AppendLine("\t\t}"); } if (memberCollector.JSCallFunctionMethods.Any()) { GenerateMethodStub(output, classSyntax, new JSMethodGroup(memberCollector.JSCallFunctionMethods.Select(mds => new JSMethod(mds)))); } if (memberCollector.JSConstructorFunctionMethods.Any()) { GenerateMethodStub(output, classSyntax, new JSMethodGroup(memberCollector.JSConstructorFunctionMethods.Select(mds => new JSMethod(mds))), "ObjectInstance"); } foreach (var property in memberCollector.JSProperties.Select(p => new JSProperty(p))) { output.AppendLine(); output.AppendLine($"\t\tprivate static object {property.GetterStubName}(ScriptEngine engine, object thisObj, object[] args)"); output.AppendLine("\t\t{"); output.AppendLine($"\t\t\tthisObj = TypeConverter.ToObject(engine, thisObj);"); output.AppendLine($"\t\t\tif (!(thisObj is {classSyntax.Identifier.ToString()}))"); output.AppendLine($"\t\t\t\tthrow new JavaScriptException(engine, ErrorType.TypeError, \"The method 'get {property.FunctionName}' is not generic.\");"); output.AppendLine($"\t\t\treturn (({classSyntax.Identifier.ToString()})thisObj).{property.PropertyName};"); output.AppendLine("\t\t}"); if (property.SetterStubName != null) { output.AppendLine(); output.AppendLine($"\t\tprivate static object {property.SetterStubName}(ScriptEngine engine, object thisObj, object[] args)"); output.AppendLine("\t\t{"); output.AppendLine($"\t\t\tthisObj = TypeConverter.ToObject(engine, thisObj);"); output.AppendLine($"\t\t\tif (!(thisObj is {classSyntax.Identifier.ToString()}))"); output.AppendLine($"\t\t\t\tthrow new JavaScriptException(engine, ErrorType.TypeError, \"The method 'set {property.FunctionName}' is not generic.\");"); output.AppendLine($"\t\t\t(({classSyntax.Identifier.ToString()})thisObj).{property.PropertyName} = {ConvertTo("args.Length > 0 ? args[0] : Undefined.Value", property.ReturnType, null)};"); output.AppendLine("\t\t}"); } } foreach (var methodGroup in methodGroups) { GenerateMethodStub(output, classSyntax, methodGroup); } output.AppendLine("\t}"); output.AppendLine(); output.AppendLine("}"); } if (outputFile) { // Write the output file. File.WriteAllText(Path.Combine(Path.GetDirectoryName(csFilePath), Path.GetFileNameWithoutExtension(csFilePath) + ".g.cs"), output.ToString()); } } }