static ImmutableArray <GeneratedSourceResult> getGeneratorSources(GeneratorState generatorState) { ArrayBuilder <GeneratedSourceResult> sources = ArrayBuilder <GeneratedSourceResult> .GetInstance(generatorState.PostInitTrees.Length + generatorState.GeneratedTrees.Length); foreach (var tree in generatorState.PostInitTrees) { sources.Add(new GeneratedSourceResult(tree.Tree, tree.Text, tree.HintName)); } foreach (var tree in generatorState.GeneratedTrees) { sources.Add(new GeneratedSourceResult(tree.Tree, tree.Text, tree.HintName)); } return(sources.ToImmutableAndFree()); }
private static GeneratorState SetGeneratorException(CommonMessageProvider provider, GeneratorState generatorState, ISourceGenerator generator, Exception e, DiagnosticBag?diagnosticBag, bool isInit = false) { var errorCode = isInit ? provider.WRN_GeneratorFailedDuringInitialization : provider.WRN_GeneratorFailedDuringGeneration; // ISSUE: Diagnostics don't currently allow descriptions with arguments, so we have to manually create the diagnostic description // ISSUE: Exceptions also don't support IFormattable, so will always be in the current UI Culture. // ISSUE: See https://github.com/dotnet/roslyn/issues/46939 var description = string.Format(provider.GetDescription(errorCode).ToString(CultureInfo.CurrentUICulture), e); var descriptor = new DiagnosticDescriptor( provider.GetIdForErrorCode(errorCode), provider.GetTitle(errorCode), provider.GetMessageFormat(errorCode), description: description, category: "Compiler", defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true, customTags: WellKnownDiagnosticTags.AnalyzerException); var diagnostic = Diagnostic.Create(descriptor, Location.None, generator.GetType().Name, e.GetType().Name, e.Message); diagnosticBag?.Add(diagnostic); return(new GeneratorState(generatorState.Info, e, diagnostic)); }
internal GeneratorDriverState RunGeneratorsCore(Compilation compilation, DiagnosticBag?diagnosticsBag, CancellationToken cancellationToken = default) { // with no generators, there is no work to do if (_state.Generators.IsEmpty) { return(_state); } // run the actual generation var state = StateWithPendingEditsApplied(_state); var stateBuilder = ArrayBuilder <GeneratorState> .GetInstance(state.Generators.Length); var walkerBuilder = ArrayBuilder <GeneratorSyntaxWalker?> .GetInstance(state.Generators.Length, fillWithValue : null); // we know there is at max 1 per generator int receiverCount = 0; for (int i = 0; i < state.Generators.Length; i++) { var generator = state.Generators[i]; var generatorState = state.GeneratorStates[i]; // initialize the generator if needed if (!generatorState.Info.Initialized) { var context = new GeneratorInitializationContext(cancellationToken); Exception?ex = null; try { generator.Initialize(context); } catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { ex = e; } generatorState = ex is null ? new GeneratorState(context.InfoBuilder.ToImmutable()) : SetGeneratorException(MessageProvider, GeneratorState.Uninitialized, generator, ex, diagnosticsBag, isInit: true); } // create the syntax receiver if requested if (generatorState.Info.SyntaxReceiverCreator is object) { try { var rx = generatorState.Info.SyntaxReceiverCreator(); walkerBuilder.SetItem(i, new GeneratorSyntaxWalker(rx)); generatorState = generatorState.WithReceiver(rx); receiverCount++; } catch (Exception e) { generatorState = SetGeneratorException(MessageProvider, generatorState, generator, e, diagnosticsBag); } } stateBuilder.Add(generatorState); } // Run a syntax walk if any of the generators requested it if (receiverCount > 0) { foreach (var tree in compilation.SyntaxTrees) { var root = tree.GetRoot(cancellationToken); // https://github.com/dotnet/roslyn/issues/42629: should be possible to parallelize this for (int i = 0; i < walkerBuilder.Count; i++) { var walker = walkerBuilder[i]; if (walker is object) { try { walker.Visit(root); } catch (Exception e) { stateBuilder[i] = SetGeneratorException(MessageProvider, stateBuilder[i], state.Generators[i], e, diagnosticsBag); walkerBuilder.SetItem(i, null); // don't re-visit this walker for any other trees } } } } } walkerBuilder.Free(); // https://github.com/dotnet/roslyn/issues/42629: should be possible to parallelize this for (int i = 0; i < state.Generators.Length; i++) { var generator = state.Generators[i]; var generatorState = stateBuilder[i]; // don't try and generate if initialization or syntax walk failed if (generatorState.Exception is object) { continue; } Debug.Assert(generatorState.Info.Initialized); // we create a new context for each run of the generator. We'll never re-use existing state, only replace anything we have var context = new GeneratorExecutionContext(compilation, state.ParseOptions, state.AdditionalTexts.NullToEmpty(), state.OptionsProvider, generatorState.SyntaxReceiver, CreateSourcesCollection(), cancellationToken); try { generator.Execute(context); } catch (Exception e) when(FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)) { stateBuilder[i] = SetGeneratorException(MessageProvider, generatorState, generator, e, diagnosticsBag); continue; } (var sources, var diagnostics) = context.ToImmutableAndFree(); stateBuilder[i] = new GeneratorState(generatorState.Info, sources, ParseAdditionalSources(generator, sources, cancellationToken), diagnostics); diagnosticsBag?.AddRange(diagnostics); } state = state.With(generatorStates: stateBuilder.ToImmutableAndFree()); return(state); }
private static GeneratorState SetGeneratorException(CommonMessageProvider provider, GeneratorState generatorState, ISourceGenerator generator, Exception e, DiagnosticBag?diagnosticBag, bool isInit = false) { var message = isInit ? provider.WRN_GeneratorFailedDuringInitialization : provider.WRN_GeneratorFailedDuringGeneration; var diagnostic = Diagnostic.Create(provider, message, generator.GetType().Name); diagnosticBag?.Add(diagnostic); return(new GeneratorState(generatorState.Info, e, diagnostic)); }