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);
        }
Beispiel #2
0
        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());
        }
Beispiel #3
0
        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());
                }
            }
        }