Пример #1
0
        public void ParseOptions_Are_Passed_To_Generator()
        {
            var         source       = @"
class C 
{
}
";
            var         parseOptions = TestOptions.Regular;
            Compilation compilation  = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions);

            compilation.VerifyDiagnostics();
            Assert.Single(compilation.SyntaxTrees);

            ParseOptions?passedOptions = null;
            var          testGenerator = new CallbackGenerator(
                onInit: (i) => { },
                onExecute: (e) => { passedOptions = e.ParseOptions; }
                );

            GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { testGenerator }, parseOptions: parseOptions);

            driver.RunGeneratorsAndUpdateCompilation(compilation, out _, out _);

            Assert.Same(parseOptions, passedOptions);
        }
Пример #2
0
        public MetadataAsSourceGeneratedFileInfo(
            string rootPath,
            Project sourceProject,
            INamedTypeSymbol topLevelNamedType,
            bool allowDecompilation
            )
        {
            this.SourceProjectId = sourceProject.Id;
            this.Workspace       = sourceProject.Solution.Workspace;
            this.LanguageName    = allowDecompilation ? LanguageNames.CSharp : sourceProject.Language;
            if (sourceProject.Language == LanguageName)
            {
                _parseOptions = sourceProject.ParseOptions;
            }
            else
            {
                _parseOptions = Workspace.Services
                                .GetLanguageServices(LanguageName)
                                .GetRequiredService <ISyntaxTreeFactoryService>()
                                .GetDefaultParseOptionsWithLatestLanguageVersion();
            }

            this.References       = sourceProject.MetadataReferences.ToImmutableArray();
            this.AssemblyIdentity = topLevelNamedType.ContainingAssembly.Identity;

            var extension = LanguageName == LanguageNames.CSharp ? ".cs" : ".vb";

            var directoryName = Guid.NewGuid().ToString("N");

            this.TemporaryFilePath = Path.Combine(
                rootPath,
                directoryName,
                topLevelNamedType.Name + extension
                );
        }
Пример #3
0
        protected void AssertFormatWithTransformation(
            Workspace workspace,
            string expected,
            SyntaxNode root,
            IEnumerable <TextSpan> spans,
            OptionSet optionSet,
            bool treeCompare          = true,
            ParseOptions?parseOptions = null
            )
        {
            var newRootNode = Formatter.Format(
                root,
                spans,
                workspace,
                optionSet,
                CancellationToken.None
                );

            Assert.Equal(expected, newRootNode.ToFullString());

            // test doesn't use parsing option. add one if needed later
            var newRootNodeFromString = ParseCompilation(expected, parseOptions);

            if (treeCompare)
            {
                // simple check to see whether two nodes are equivalent each other.
                Assert.True(newRootNodeFromString.IsEquivalentTo(newRootNode));
            }
        }
Пример #4
0
 private SourceGeneratedDocumentState(
     HostLanguageServices languageServices,
     SolutionServices solutionServices,
     IDocumentServiceProvider?documentServiceProvider,
     DocumentInfo.DocumentAttributes attributes,
     ParseOptions?options,
     SourceText?sourceText,
     ValueSource <TextAndVersion> textSource,
     TreeAndVersion treeAndVersion,
     ISourceGenerator sourceGenerator,
     string hintName
     )
     : base(
         languageServices,
         solutionServices,
         documentServiceProvider,
         attributes,
         options,
         sourceText,
         textSource,
         new ConstantValueSource <TreeAndVersion>(treeAndVersion)
         )
 {
     SourceGenerator = sourceGenerator;
     HintName        = hintName;
 }
Пример #5
0
        internal void UsingStatement(string text, ParseOptions?options, params DiagnosticDescription[] expectedErrors)
        {
            var node = SyntaxFactory.ParseStatement(text, options: options);

            Validate(text, node, expectedErrors);
            UsingNode(node);
        }
Пример #6
0
 public static ProjectInfo Create(
     ProjectId id,
     VersionStamp version,
     string name,
     string assemblyName,
     string language,
     string?filePath       = null,
     string?outputFilePath = null,
     CompilationOptions?compilationOptions              = null,
     ParseOptions?parseOptions                          = null,
     IEnumerable <DocumentInfo>?documents               = null,
     IEnumerable <ProjectReference>?projectReferences   = null,
     IEnumerable <MetadataReference>?metadataReferences = null,
     IEnumerable <AnalyzerReference>?analyzerReferences = null,
     IEnumerable <DocumentInfo>?additionalDocuments     = null,
     bool isSubmission        = false,
     Type?hostObjectType      = null,
     string?outputRefFilePath = null)
 {
     return(Create(
                id, version, name, assemblyName, language,
                filePath, outputFilePath, outputRefFilePath, defaultNamespace: null, compilationOptions, parseOptions,
                documents, projectReferences, metadataReferences, analyzerReferences, additionalDocuments, analyzerConfigDocuments: null,
                isSubmission, hostObjectType, hasAllInformation: true, runAnalyzers: true));
 }
Пример #7
0
        public DocumentState(
            DocumentInfo info,
            ParseOptions?options,
            ValueSource <AnalyzerConfigSet> analyzerConfigSetSource,
            HostLanguageServices languageServices,
            SolutionServices services)
            : base(info, services)
        {
            _languageServices        = languageServices;
            _options                 = options;
            _analyzerConfigSetSource = analyzerConfigSetSource;

            // If this is document that doesn't support syntax, then don't even bother holding
            // onto any tree source.  It will never be used to get a tree, and can only hurt us
            // by possibly holding onto data that might cause a slow memory leak.
            if (!this.SupportsSyntaxTree)
            {
                _treeSource = ValueSource <TreeAndVersion> .Empty;
            }
            else
            {
                Contract.ThrowIfNull(options);
                _treeSource = CreateLazyFullyParsedTree(
                    base.TextAndVersionSource,
                    info.Id.ProjectId,
                    GetSyntaxTreeFilePath(info.Attributes),
                    options,
                    analyzerConfigSetSource,
                    languageServices);
            }
        }
Пример #8
0
 public static ProjectInfo Create(
     ProjectId id,
     VersionStamp version,
     string name,
     string assemblyName,
     string language,
     string?filePath       = null,
     string?outputFilePath = null,
     CompilationOptions?compilationOptions              = null,
     ParseOptions?parseOptions                          = null,
     IEnumerable <DocumentInfo>?documents               = null,
     IEnumerable <ProjectReference>?projectReferences   = null,
     IEnumerable <MetadataReference>?metadataReferences = null,
     IEnumerable <AnalyzerReference>?analyzerReferences = null,
     IEnumerable <DocumentInfo>?additionalDocuments     = null,
     bool isSubmission        = false,
     Type?hostObjectType      = null,
     string?outputRefFilePath = null)
 {
     return(new ProjectInfo(
                new ProjectAttributes(
                    id ?? throw new ArgumentNullException(nameof(id)),
                    version,
                    name ?? throw new ArgumentNullException(nameof(name)),
                    assemblyName ?? throw new ArgumentNullException(nameof(assemblyName)),
                    language ?? throw new ArgumentNullException(nameof(language)),
                    filePath,
                    outputFilePath,
                    outputRefFilePath,
                    compilationOutputFilePaths: default,
Пример #9
0
        public void ParseOptions_Are_Passed_To_Generator()
        {
            var         source       = @"
class C 
{
}
";
            var         parseOptions = TestOptions.Regular;
            Compilation compilation  = CreateCompilation(source, options: TestOptions.DebugDll, parseOptions: parseOptions);

            compilation.VerifyDiagnostics();
            Assert.Single(compilation.SyntaxTrees);

            ParseOptions?passedOptions = null;
            var          testGenerator = new CallbackGenerator(
                onInit: (i) => { },
                onExecute: (e) => { passedOptions = e.ParseOptions; }
                );

            GeneratorDriver driver = new CSharpGeneratorDriver(parseOptions, ImmutableArray.Create <ISourceGenerator>(testGenerator), CompilerAnalyzerConfigOptionsProvider.Empty, ImmutableArray <AdditionalText> .Empty);

            driver.RunFullGeneration(compilation, out _, out _);

            Assert.Same(parseOptions, passedOptions);
        }
Пример #10
0
        public CompileUnitSyntax ParseFile(string filePath, ParseOptions?options = null)
        {
            using var reader = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read));
            var lexer = new Lexer(reader);

            return(ParseCompileUnit(lexer));
        }
Пример #11
0
 internal GeneratorDriverState With(
     ImmutableArray <ISourceGenerator>?sourceGenerators           = null,
     ImmutableArray <IIncrementalGenerator>?incrementalGenerators = null,
     ImmutableArray <GeneratorState>?generatorStates = null,
     ImmutableArray <AdditionalText>?additionalTexts = null,
     DriverStateTable?stateTable = null,
     SyntaxStore?syntaxStore     = null,
     ParseOptions?parseOptions   = null,
     AnalyzerConfigOptionsProvider?optionsProvider  = null,
     IncrementalGeneratorOutputKind?disabledOutputs = null,
     TimeSpan?runTime = null)
 {
     return(new GeneratorDriverState(
                parseOptions ?? this.ParseOptions,
                optionsProvider ?? this.OptionsProvider,
                sourceGenerators ?? this.Generators,
                incrementalGenerators ?? this.IncrementalGenerators,
                additionalTexts ?? this.AdditionalTexts,
                generatorStates ?? this.GeneratorStates,
                stateTable ?? this.StateTable,
                syntaxStore ?? this.SyntaxStore,
                disabledOutputs ?? this.DisabledOutputs,
                runTime ?? this.RunTime,
                this.TrackIncrementalSteps
                ));
 }
Пример #12
0
 protected async Task TestAsync(
     string code,
     TestHost testHost,
     ParseOptions?parseOptions,
     params FormattedClassification[] expected)
 {
     await TestAsync(code, code, testHost, parseOptions, expected);
 }
Пример #13
0
 internal void UsingExpression(
     string text,
     ParseOptions?options,
     params DiagnosticDescription[] expectedErrors
     )
 {
     UsingNode(text, SyntaxFactory.ParseExpression(text, options: options), expectedErrors);
 }
 private async Task TestWithAllCodeStyleOff(
     string initialMarkup, string expectedMarkup,
     ParseOptions?parseOptions = null, int index = 0)
 {
     await TestAsync(
         initialMarkup, expectedMarkup, parseOptions,
         index : index,
         options : AllCodeStyleOff);
 }
Пример #15
0
        internal DocumentState CreateDocument(DocumentInfo documentInfo, ParseOptions?parseOptions)
        {
            var doc = new DocumentState(documentInfo, parseOptions, _lazyAnalyzerConfigSet, _languageServices, _solutionServices);

            if (doc.SourceCodeKind != documentInfo.SourceCodeKind)
            {
                doc = doc.UpdateSourceCodeKind(documentInfo.SourceCodeKind);
            }

            return(doc);
        }
Пример #16
0
        internal void UsingStatement(string text, ParseOptions?options, params DiagnosticDescription[] expectedErrors)
        {
            var node = SyntaxFactory.ParseStatement(text, options: options);

            // we validate the text roundtrips
            Assert.Equal(text, node.ToFullString());
            var actualErrors = node.GetDiagnostics();

            actualErrors.Verify(expectedErrors);
            UsingNode(node);
        }
Пример #17
0
        /// <summary>
        /// The helper method for equality comparison of the base class' fields.
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        protected bool EqualsHelper([NotNullWhen(true)] ParseOptions?other)
        {
            if (other is null)
            {
                return(false);
            }

            return
                (DocumentationMode == other.DocumentationMode &&
                 Features.SequenceEqual(other.Features));
        }
Пример #18
0
        protected bool EqualsHelper([NotNullWhen(true)] ParseOptions?other)
        {
            if (object.ReferenceEquals(other, null))
            {
                return(false);
            }

            return
                (this.SpecifiedKind == other.SpecifiedKind &&
                 this.DocumentationMode == other.DocumentationMode &&
                 this.Features.SequenceEqual(other.Features) &&
                 (this.PreprocessorSymbolNames == null ? other.PreprocessorSymbolNames == null : this.PreprocessorSymbolNames.SequenceEqual(other.PreprocessorSymbolNames, StringComparer.Ordinal)));
        }
Пример #19
0
        private static SyntaxNode GetDeclarationSyntaxWithoutMembers(
            INamespaceSymbol @namespace,
            INamespaceSymbol innermostNamespace,
            string name,
            CodeGenerationDestination destination,
            CodeGenerationOptions options,
            ParseOptions?parseOptions)
        {
            var reusableSyntax = GetReuseableSyntaxNodeForSymbol <SyntaxNode>(@namespace, options);

            return(reusableSyntax == null
                ? GenerateNamespaceDeclarationWorker(name, innermostNamespace, destination, options, parseOptions)
                : RemoveAllMembers(reusableSyntax));
        }
Пример #20
0
        private ProjectInfo With(
            ProjectAttributes?attributes                       = null,
            CompilationOptions?compilationOptions              = null,
            ParseOptions?parseOptions                          = null,
            IEnumerable <DocumentInfo>?documents               = null,
            IEnumerable <ProjectReference>?projectReferences   = null,
            IEnumerable <MetadataReference>?metadataReferences = null,
            IEnumerable <AnalyzerReference>?analyzerReferences = null,
            IEnumerable <DocumentInfo>?additionalDocuments     = null,
            IEnumerable <DocumentInfo>?analyzerConfigDocuments = null,
            Optional <Type?> hostObjectType                    = default)
        {
            var newAttributes              = attributes ?? Attributes;
            var newCompilationOptions      = compilationOptions ?? CompilationOptions;
            var newParseOptions            = parseOptions ?? ParseOptions;
            var newDocuments               = documents ?? Documents;
            var newProjectReferences       = projectReferences ?? ProjectReferences;
            var newMetadataReferences      = metadataReferences ?? MetadataReferences;
            var newAnalyzerReferences      = analyzerReferences ?? AnalyzerReferences;
            var newAdditionalDocuments     = additionalDocuments ?? AdditionalDocuments;
            var newAnalyzerConfigDocuments = analyzerConfigDocuments ?? AnalyzerConfigDocuments;
            var newHostObjectType          = hostObjectType.HasValue ? hostObjectType.Value : HostObjectType;

            if (newAttributes == Attributes &&
                newCompilationOptions == CompilationOptions &&
                newParseOptions == ParseOptions &&
                newDocuments == Documents &&
                newProjectReferences == ProjectReferences &&
                newMetadataReferences == MetadataReferences &&
                newAnalyzerReferences == AnalyzerReferences &&
                newAdditionalDocuments == AdditionalDocuments &&
                newAnalyzerConfigDocuments == AnalyzerConfigDocuments &&
                newHostObjectType == HostObjectType)
            {
                return(this);
            }

            return(new ProjectInfo(
                       newAttributes,
                       newCompilationOptions,
                       newParseOptions,
                       newDocuments,
                       newProjectReferences,
                       newMetadataReferences,
                       newAnalyzerReferences,
                       newAdditionalDocuments,
                       newAnalyzerConfigDocuments,
                       newHostObjectType));
        }
Пример #21
0
 private DocumentState(
     HostLanguageServices languageServices,
     SolutionServices solutionServices,
     IDocumentServiceProvider?documentServiceProvider,
     DocumentInfo.DocumentAttributes attributes,
     ParseOptions?options,
     SourceText?sourceText,
     ValueSource <TextAndVersion> textSource,
     ValueSource <TreeAndVersion>?treeSource)
     : base(solutionServices, documentServiceProvider, attributes, sourceText, textSource)
 {
     _languageServices = languageServices;
     _options          = options;
     _treeSource       = treeSource;
 }
Пример #22
0
        internal void UsingDeclaration(string text, int offset = 0, ParseOptions?options = null, bool consumeFullText = true, params DiagnosticDescription[] expectedErrors)
        {
            var node = SyntaxFactory.ParseMemberDeclaration(text, offset, options, consumeFullText);

            if (consumeFullText)
            {
                // we validate the text roundtrips
                Assert.Equal(text, node.ToFullString());
            }

            var actualErrors = node.GetDiagnostics();

            actualErrors.Verify(expectedErrors);
            UsingNode(node);
        }
Пример #23
0
        /// <summary>
        /// Parses a .StormReplay file.
        /// </summary>
        /// <param name="fileName">The file name which may contain the path.</param>
        /// <param name="parseOptions">Sets the parsing options. If <see cref="ParseOptions.AllowPTR"/> is <see langword="false"/> the result status will be <see cref="StormReplayParseStatus.PTRRegion"/> if the replay is successfully parsed.</param>
        /// <returns>A <see cref="StormReplayResult"/>.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="fileName"/> is null.</exception>
        public static StormReplayResult Parse(string fileName, ParseOptions?parseOptions = null)
        {
            if (fileName is null)
            {
                throw new ArgumentNullException(nameof(fileName));
            }

            if (parseOptions is null)
            {
                parseOptions = ParseOptions.DefaultParsing;
            }

            StormReplay stormReplay = ParseStormReplay(fileName, parseOptions);

            return(new StormReplayResult(stormReplay, _stormReplayParseResult, fileName, _failedReplayException));
        }
Пример #24
0
 internal static ProjectInfo Create(
     ProjectId id,
     VersionStamp version,
     string name,
     string assemblyName,
     string language,
     string?filePath,
     string?outputFilePath,
     string?outputRefFilePath,
     string?defaultNamespace,
     CompilationOptions?compilationOptions,
     ParseOptions?parseOptions,
     IEnumerable <DocumentInfo>?documents,
     IEnumerable <ProjectReference>?projectReferences,
     IEnumerable <MetadataReference>?metadataReferences,
     IEnumerable <AnalyzerReference>?analyzerReferences,
     IEnumerable <DocumentInfo>?additionalDocuments,
     IEnumerable <DocumentInfo>?analyzerConfigDocuments,
     bool isSubmission,
     Type?hostObjectType,
     bool hasAllInformation,
     bool runAnalyzers)
 {
     return(new ProjectInfo(
                new ProjectAttributes(
                    id,
                    version,
                    name,
                    assemblyName,
                    language,
                    filePath,
                    outputFilePath,
                    outputRefFilePath,
                    defaultNamespace,
                    isSubmission,
                    hasAllInformation,
                    runAnalyzers),
                compilationOptions,
                parseOptions,
                documents,
                projectReferences,
                metadataReferences,
                analyzerReferences,
                additionalDocuments,
                analyzerConfigDocuments,
                hostObjectType));
 }
Пример #25
0
 internal GeneratorDriverState With(
     ParseOptions?parseOptions = null,
     ImmutableArray <ISourceGenerator>?generators = null,
     ImmutableDictionary <ISourceGenerator, GeneratorState>?generatorStates = null,
     ImmutableArray <AdditionalText>?additionalTexts = null,
     ImmutableArray <PendingEdit>?edits = null,
     bool?editsFailed = null)
 {
     return(new GeneratorDriverState(
                parseOptions ?? this.ParseOptions,
                generators ?? this.Generators,
                additionalTexts ?? this.AdditionalTexts,
                generatorStates ?? this.GeneratorStates,
                edits ?? this.Edits,
                editsFailed ?? this.EditsFailed
                ));
 }
Пример #26
0
        private protected async Task AssertFormatAsync(
            string expected,
            string code,
            IEnumerable <TextSpan> spans,
            string language,
#pragma warning disable IDE0060 // Remove unused parameter - https://github.com/dotnet/roslyn/issues/44225
            bool debugMode = false,
#pragma warning restore IDE0060 // Remove unused parameter
            OptionsCollection?changedOptionSet = null,
            bool treeCompare          = true,
            ParseOptions?parseOptions = null)
        {
            using (var workspace = new AdhocWorkspace())
            {
                var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", language);
                if (parseOptions != null)
                {
                    project = project.WithParseOptions(parseOptions);
                }

                var document = project.AddDocument("Document", SourceText.From(code));

                var syntaxTree = await document.GetRequiredSyntaxTreeAsync(CancellationToken.None);

                var optionSet = workspace.Options;
                if (changedOptionSet != null)
                {
                    foreach (var entry in changedOptionSet)
                    {
                        optionSet = optionSet.WithChangedOption(entry.Key, entry.Value);
                    }
                }

                var root = await syntaxTree.GetRootAsync();

                var options = SyntaxFormattingOptions.Create(optionSet, workspace.Services, root.Language);

                await AssertFormatAsync(workspace.Services, expected, root, spans.AsImmutable(), options, await document.GetTextAsync());

                // format with node and transform
                AssertFormatWithTransformation(workspace.Services, expected, root, spans, options, treeCompare, parseOptions);
            }
        }
Пример #27
0
 public static ProjectInfo Create(
     ProjectId id,
     VersionStamp version,
     string name,
     string assemblyName,
     string language,
     string?filePath       = null,
     string?outputFilePath = null,
     CompilationOptions?compilationOptions              = null,
     ParseOptions?parseOptions                          = null,
     IEnumerable <DocumentInfo>?documents               = null,
     IEnumerable <ProjectReference>?projectReferences   = null,
     IEnumerable <MetadataReference>?metadataReferences = null,
     IEnumerable <AnalyzerReference>?analyzerReferences = null,
     IEnumerable <DocumentInfo>?additionalDocuments     = null,
     bool isSubmission        = false,
     Type?hostObjectType      = null,
     string?outputRefFilePath = null)
 {
     return(new ProjectInfo(
                new ProjectAttributes(
                    id ?? throw new ArgumentNullException(nameof(id)),
                    version,
                    name ?? throw new ArgumentNullException(nameof(name)),
                    assemblyName ?? throw new ArgumentNullException(nameof(assemblyName)),
                    language ?? throw new ArgumentNullException(nameof(language)),
                    filePath,
                    outputFilePath,
                    outputRefFilePath,
                    defaultNamespace: null,
                    isSubmission,
                    hasAllInformation: true,
                    runAnalyzers: true),
                compilationOptions,
                parseOptions,
                documents.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(documents)),
                projectReferences.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(projectReferences)),
                metadataReferences.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(metadataReferences)),
                analyzerReferences.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(analyzerReferences)),
                additionalDocuments.AsBoxedImmutableArrayWithNonNullItems() ?? throw new ArgumentNullException(nameof(additionalDocuments)),
                analyzerConfigDocuments: SpecializedCollections.EmptyBoxedImmutableArray <DocumentInfo>(),
                hostObjectType));
 }
Пример #28
0
 internal GeneratorDriverState With(
     ImmutableArray <ISourceGenerator>?sourceGenerators           = null,
     ImmutableArray <IIncrementalGenerator>?incrementalGenerators = null,
     ImmutableArray <GeneratorState>?generatorStates = null,
     ImmutableArray <AdditionalText>?additionalTexts = null,
     DriverStateTable?stateTable = null,
     ParseOptions?parseOptions   = null,
     AnalyzerConfigOptionsProvider?optionsProvider = null)
 {
     return(new GeneratorDriverState(
                parseOptions ?? this.ParseOptions,
                optionsProvider ?? this.OptionsProvider,
                sourceGenerators ?? this.Generators,
                incrementalGenerators ?? this.IncrementalGenerators,
                additionalTexts ?? this.AdditionalTexts,
                generatorStates ?? this.GeneratorStates,
                stateTable ?? this.StateTable,
                this.EnableIncremental
                ));
 }
Пример #29
0
        internal static SyntaxNode GenerateNamespaceDeclaration(
            ICodeGenerationService service,
            INamespaceSymbol @namespace,
            CodeGenerationDestination destination,
            CodeGenerationOptions options,
            ParseOptions?parseOptions,
            CancellationToken cancellationToken)
        {
            options ??= CodeGenerationOptions.Default;
            GetNameAndInnermostNamespace(@namespace, options, out var name, out var innermostNamespace);

            var declaration = GetDeclarationSyntaxWithoutMembers(
                @namespace, innermostNamespace, name, destination, options, parseOptions);

            declaration = options.GenerateMembers
                ? service.AddMembers(declaration, innermostNamespace.GetMembers(), options, cancellationToken)
                : declaration;

            return(AddFormatterAndCodeGeneratorAnnotationsTo(declaration));
        }
Пример #30
0
        protected async Task AssertFormatAsync(
            string expected,
            string code,
            IEnumerable <TextSpan> spans,
            string language,
            bool debugMode = false,
            Dictionary <OptionKey, object>?changedOptionSet = null,
            bool treeCompare          = true,
            ParseOptions?parseOptions = null)
        {
            using (var workspace = new AdhocWorkspace())
            {
                var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", language);
                if (parseOptions != null)
                {
                    project = project.WithParseOptions(parseOptions);
                }

                var document = project.AddDocument("Document", SourceText.From(code));

                var syntaxTree = await document.GetRequiredSyntaxTreeAsync(CancellationToken.None);

                var options = workspace.Options;
                if (changedOptionSet != null)
                {
                    foreach (var entry in changedOptionSet)
                    {
                        options = options.WithChangedOption(entry.Key, entry.Value);
                    }
                }

                var root = await syntaxTree.GetRootAsync();

                AssertFormat(workspace, expected, root, spans, options, await document.GetTextAsync());

                // format with node and transform
                AssertFormatWithTransformation(workspace, expected, root, spans, options, treeCompare, parseOptions);
            }
        }