예제 #1
0
        private static (ImmutableArray <Diagnostic>, string) GetGeneratedOutput(string source)
        {
            var syntaxTree = CSharpSyntaxTree.ParseText(source);

            var references = new List <MetadataReference>();

            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var assembly in assemblies)
            {
                if (!assembly.IsDynamic)
                {
                    references.Add(MetadataReference.CreateFromFile(assembly.Location));
                }
            }

            var compilation = CSharpCompilation.Create("foo", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            // TODO: Uncomment these lines if you want to return immediately if the injected program isn't valid _before_ running generators
            //
            // ImmutableArray<Diagnostic> compilationDiagnostics = compilation.GetDiagnostics();
            //
            // if (diagnostics.Any())
            // {
            //     return (diagnostics, "");
            // }

            var generator = new Generator();

            var driver = CSharpGeneratorDriver.Create(generator);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generateDiagnostics);

            return(generateDiagnostics, outputCompilation.SyntaxTrees.Last().ToString());
        }
예제 #2
0
        private static (ImmutableArray <Diagnostic>, string) GetGeneratedOutput(string source)
        {
            var syntaxTree = CSharpSyntaxTree.ParseText(source);

            var references = new List <MetadataReference>();

            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var assembly in assemblies)
            {
                if (!assembly.IsDynamic)
                {
                    references.Add(MetadataReference.CreateFromFile(assembly.Location));
                }
            }

            var compilation = CSharpCompilation.Create("foo", new SyntaxTree[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            ImmutableArray <Diagnostic> diagnostics = compilation.GetDiagnostics();

            if (diagnostics.Any())
            {
                return(diagnostics, "");
            }

            ISourceGenerator generator = new Generator();

            var driver = CSharpGeneratorDriver.Create(generator);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out diagnostics);

            return(diagnostics, outputCompilation.SyntaxTrees.Last().ToString());
        }
예제 #3
0
        public EvaluationResult Evaluate(Dictionary <VariableSymbol, object> variables)
        {
            var parseDiagnostics = SyntaxTrees.SelectMany(st => st.Diagnostics);

            var diagnostics = parseDiagnostics.Concat(GlobalScope.Diagnostics).ToImmutableArray();

            if (diagnostics.Any())
            {
                return(new EvaluationResult(diagnostics, null));
            }

            var program = GetProgram();

            // var appPath = Environment.GetCommandLineArgs()[0];
            // var appDirectory = Path.GetDirectoryName(appPath);
            // var cfgPath = Path.Combine(appDirectory, "cfg.dot");
            // var cfgStatement = !program.Statement.Statements.Any() && program.Functions.Any()
            //                       ? program.Functions.Last().Value
            //                       : program.Statement;
            // var cfg = ControlFlowGraph.Create(cfgStatement);
            // using (var streamWriter = new StreamWriter(cfgPath))
            //     cfg.WriteTo(streamWriter);

            if (program.Diagnostics.Any())
            {
                return(new EvaluationResult(program.Diagnostics.ToImmutableArray(), null));
            }

            var evaluator = new Evaluator(program, variables);
            var value     = evaluator.Evaluate();

            return(new EvaluationResult(ImmutableArray <Diagnostic> .Empty, value));
        }
예제 #4
0
        // TODO: References should be part of the compilation, not arguments for Emit
        public ImmutableArray <Diagnostic> Emit(string moduleName, string[] references, string outputPath)
        {
            var parseDiagnostics = SyntaxTrees.SelectMany(st => st.Diagnostics);
            var diagnostics      = parseDiagnostics.Concat(GlobalScope.Diagnostics).ToImmutableArray();

            if (diagnostics.HasErrors())
            {
                return(diagnostics);
            }

            var program = GetProgram();

            return(Emitter.Emit(program, moduleName, references, outputPath));
        }
예제 #5
0
        // TODO: References should be part of the compilation, not arguments for Emit
        public ImmutableArray <Diagnostic> Emit(string moduleName, string[] references, string outputPath)
        {
            var parseDiagnostics = SyntaxTrees.SelectMany(st => st.Diagnostics);
            var diagnostics      = parseDiagnostics.Concat(GlobalScope.Diagnostics).ToImmutableArray();

            if (diagnostics.HasErrors())
            {
                return(diagnostics);
            }

            // TODO: implement warning system
            if (diagnostics.HasWarnings())
            {
                Console.Out.WriteLine(diagnostics);
            }

            var program = GetProgram();

            return(ILEmitter.Emit(program, moduleName, references, outputPath));
        }
예제 #6
0
        public EvaluationResult Evaluate(Dictionary <VariableSymbol, object> variables)
        {
            var parseDiagnostics = SyntaxTrees.SelectMany(st => st.Diagnostics);

            var diagnostics = parseDiagnostics.Concat(GlobalScope.Diagnostics).ToImmutableArray();

            if (diagnostics.Any())
            {
                return(new EvaluationResult(diagnostics, null));
            }

            var program = GetProgram();

            if (program.Diagnostics.Any())
            {
                return(new EvaluationResult(program.Diagnostics.ToImmutableArray(), null));
            }

            var evaluator = new Evaluator(program, variables);
            var value     = evaluator.Evaluate();

            return(new EvaluationResult(ImmutableArray <Diagnostic> .Empty, value));
        }
예제 #7
0
        public override void Init(LoggerProvider p, bool reInit = false)
        {
            if (this.Initialized && !reInit)
            {
                return;
            }
            this.Logger = p;
            this.Types  = new List <NamedTypeBase>();

            this.symbols        = new List <ISymbol>();
            this.SemanticModels = new Dictionary <ISymbol, SemanticModel>();
            this.TreeModels     = new Dictionary <SyntaxTree, SemanticModel>();
            this.SyntaxTrees    = new Dictionary <ISymbol, SyntaxTree>();

            List <Tuple <ISymbol, SemanticModel> > tempSymbols = new List <Tuple <ISymbol, SemanticModel> >();

            using (ProfilerService.Current.Section("Getting symbols"))
            {
                for (int i = 0; i < Compilations.Count; i++)
                {
                    var comp      = Compilations[i];
                    var compTrees = comp.SyntaxTrees.ToList();
                    for (int j = 0; j < compTrees.Count; j++)
                    {
                        tempSymbols.AddRange(GetSymbols(compTrees[j], comp));
                    }
                }
            }

            using (ProfilerService.Current.Section("Building symbol info"))
            {
                this.symbols = tempSymbols.Select(t => t.Item1).ToList();
                for (int i = 0; i < tempSymbols.Count; i++)
                {
                    if (tempSymbols[i].Item1.Locations.Length > 0 && tempSymbols[i].Item1.Locations[0].IsInSource)
                    {
                        var sTree = tempSymbols[i].Item1.Locations[0].SourceTree;

                        if (!this.SemanticModels.ContainsKey(tempSymbols[i].Item1))
                        {
                            SyntaxTrees.Add(tempSymbols[i].Item1, sTree);
                        }

                        var sComp = Compilations.SingleOrDefault(c => c.SyntaxTrees.Contains(sTree));

                        if (sComp == null)
                        {
                            Logger.WriteToLog(string.Format("Cannot find compilation for tree {0}", sTree.FilePath));
                        }
                        else
                        {
                            if (!this.SemanticModels.ContainsKey(tempSymbols[i].Item1))
                            {
                                this.SemanticModels.Add(tempSymbols[i].Item1, sComp.GetSemanticModel(sTree));
                            }
                            if (!this.TreeModels.ContainsKey(sTree))
                            {
                                this.TreeModels.Add(sTree, sComp.GetSemanticModel(sTree));
                            }
                        }
                    }
                    else
                    {
                        if (!this.SemanticModels.ContainsKey(tempSymbols[i].Item1))
                        {
                            this.SemanticModels.Add(tempSymbols[i].Item1, tempSymbols[i].Item2);
                        }
                    }
                }
            }


            CSharpModelBuilder.InitLogger(p);

            using (ProfilerService.Current.Method("BuildTypeList"))
            {
                CSharpModelBuilder.BuildTypeList(Types, symbols.Where(s => s.Kind == SymbolKind.NamedType).Distinct().Cast <INamedTypeSymbol>());
            }

            this.Types = this.Types.Distinct(new TypeComparer()).ToList();

            using (ProfilerService.Current.Method("BuildArrayTypeList"))
            {
                CSharpModelBuilder.BuildArrayTypeList(Types, symbols.Where(s => s.Kind == SymbolKind.ArrayType).Distinct().Cast <IArrayTypeSymbol>());
            }

            using (ProfilerService.Current.Method("BuildMethodList"))
            {
                CSharpModelBuilder.BuildMethodList(Types, symbols.Where(s => s.Kind == SymbolKind.Method).Distinct().Cast <IMethodSymbol>()
                                                   .Where(s => s.MethodKind == MethodKind.Ordinary || s.MethodKind == MethodKind.Constructor || s.MethodKind == MethodKind.PropertyGet || s.MethodKind == MethodKind.PropertySet), this.SemanticModels);
            }

            using (ProfilerService.Current.Method("BuildFieldList"))
            {
                CSharpModelBuilder.BuildFieldList(Types, symbols.Where(s => s.Kind == SymbolKind.Field).Distinct().Cast <IFieldSymbol>(), symbols.Where(s => s.Kind == SymbolKind.Property).Cast <IPropertySymbol>(), this.SemanticModels);
            }

            using (ProfilerService.Current.Method("BuildCallGraph"))
            {
                this.CallGraph = CSharpModelBuilder.BuildCallGraph(this.TreeModels, this.Types, this.Logger);
            }

            this.Initialized = true;

            using (var fs = File.Create(string.Join(".", this.Name, "bin")))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(fs, this.Types);
            }
        }
예제 #8
0
    /// <summary>
    /// 将 SyntaxTrees 中的语法树编译到程序集.如果不成功会抛出 NatashaException.
    /// </summary>
    /// <remarks>
    /// <example>
    /// <code>
    ///
    ///     //程序集的域加载行为, 该行为决定了编译后的程序集随着依赖加载到域中的处理结果.
    ///     //和加载插件原理相同.
    ///     builder.CompileWithAssemblyLoadBehavior(enum);
    ///
    ///     //编译单元的引用加载行为, 遇到同名不同版本的引用该如何处理.
    ///     builder.CompileWithReferenceLoadBehavior(enum);
    ///     builder.CompileWithReferencesFilter(func);
    ///
    /// </code>
    /// </example>
    /// </remarks>
    public Assembly GetAssembly()
    {
#if DEBUG
        Stopwatch stopwatch = new();
        stopwatch.Start();
#endif

        //Mark : 26ms
        if (_compileReferenceBehavior == LoadBehaviorEnum.None)
        {
            _compilerOptions.SetSupersedeLowerVersions(true);
        }

        var options     = _compilerOptions.GetCompilationOptions();
        var references  = Domain.GetReferences(_compileReferenceBehavior, _referencePickFunc);
        var compilation = CSharpCompilation.Create(AssemblyName, SyntaxTrees, references, options);

#if DEBUG
        stopwatch.RestartAndShowCategoreInfo("[Compiler]", "获取编译单元", 2);
#endif


        if (EnableSemanticHandler)
        {
            foreach (var item in _semanticAnalysistor)
            {
                compilation = item(this, compilation);
            }
            lock (SyntaxTrees)
            {
                SyntaxTrees.Clear();
                SyntaxTrees.AddRange(compilation.SyntaxTrees);
            }
        }

#if DEBUG
        stopwatch.RestartAndShowCategoreInfo("[Semantic]", "语义处理", 2);
#endif

        Stream dllStream;
        Stream pdbStream;
        Stream?xmlStream = null;
        if (DllFilePath != string.Empty)
        {
            dllStream = File.Create(DllFilePath);
        }
        else
        {
            dllStream = new MemoryStream();
        }

        if (PdbFilePath != string.Empty)
        {
            pdbStream = File.Create(PdbFilePath);
        }
        else
        {
            pdbStream = new MemoryStream();
        }

        if (XmlFilePath != string.Empty)
        {
            xmlStream = File.Create(XmlFilePath);
        }

        var compileResult = compilation.Emit(
            dllStream,
            pdbStream: pdbStream,
            xmlDocumentationStream: xmlStream,
            options: new EmitOptions(pdbFilePath: PdbFilePath == string.Empty ? null : PdbFilePath, debugInformationFormat: DebugInformationFormat.PortablePdb));


        LogCompilationEvent?.Invoke(compilation.GetNatashaLog());

        Assembly?assembly = null;
        if (compileResult.Success)
        {
            dllStream.Seek(0, SeekOrigin.Begin);
            pdbStream?.Seek(0, SeekOrigin.Begin);
            Domain.SetAssemblyLoadBehavior(_compileAssemblyBehavior);
            assembly = Domain.LoadAssemblyFromStream(dllStream, pdbStream);
            CompileSucceedEvent?.Invoke(compilation, assembly !);
        }
        dllStream.Dispose();
        pdbStream?.Dispose();
        xmlStream?.Dispose();

#if DEBUG
        stopwatch.StopAndShowCategoreInfo("[  Emit  ]", "编译时长", 2);
#endif

        if (!compileResult.Success)
        {
            CompileFailedEvent?.Invoke(compilation, compileResult.Diagnostics);
            throw NatashaExceptionAnalyzer.GetCompileException(compilation, compileResult.Diagnostics);
        }

        return(assembly !);
    }