Esempio n. 1
0
        public static BicepFile CreateBicepFile(Uri fileUri, string fileContents)
        {
            var parser     = new Parser(fileContents);
            var lineStarts = TextCoordinateConverter.GetLineStarts(fileContents);

            return(new BicepFile(fileUri, lineStarts, parser.Program()));
        }
Esempio n. 2
0
        public static SyntaxTree Create(string filePath, string fileContents)
        {
            var parser     = new Parser.Parser(fileContents);
            var lineStarts = TextCoordinateConverter.GetLineStarts(fileContents);

            return(new SyntaxTree(filePath, lineStarts, parser.Program()));
        }
Esempio n. 3
0
        private static (string, IEnumerable <object>) CompileInternal(string content)
        {
            try
            {
                var lineStarts      = TextCoordinateConverter.GetLineStarts(content);
                var compilation     = GetCompilation(content);
                var emitterSettings = new EmitterSettings(features);
                var emitter         = new TemplateEmitter(compilation.GetEntrypointSemanticModel(), emitterSettings);

                // memory stream is not ideal for frequent large allocations
                using var stream = new MemoryStream();
                var emitResult = emitter.Emit(stream);

                if (emitResult.Status != EmitStatus.Failed)
                {
                    // compilation was successful or had warnings - return the compiled template
                    stream.Position = 0;
                    return(ReadStreamToEnd(stream), emitResult.Diagnostics.Select(d => ToMonacoDiagnostic(d, lineStarts)));
                }

                // compilation failed
                return("Compilation failed!", emitResult.Diagnostics.Select(d => ToMonacoDiagnostic(d, lineStarts)));
            }
            catch (Exception exception)
            {
                return(exception.ToString(), Enumerable.Empty <object>());
            }
        }
Esempio n. 4
0
        public void GetLineStarts_MixedEndOfLines_ReturnsCorrectLineStarts(string contents, int[] expectedLineStarts)
        {
            IReadOnlyList <int> lineStarts = TextCoordinateConverter.GetLineStarts(contents);

            lineStarts.Should().HaveCount(expectedLineStarts.Length);
            lineStarts.Should().BeEquivalentTo(expectedLineStarts);
        }
Esempio n. 5
0
        public async Task RenamingFunctionsShouldProduceEmptyEdit(DataSet dataSet)
        {
            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var validFunctionCallPairs = symbolTable
                                         .Where(pair => pair.Value.Kind == SymbolKind.Function)
                                         .Select(pair => pair.Key);

            foreach (var syntax in validFunctionCallPairs)
            {
                var edit = await client.RequestRename(new RenameParams
                {
                    NewName      = "NewIdentifier",
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = IntegrationTestHelper.GetPosition(lineStarts, syntax)
                });

                edit.DocumentChanges.Should().BeNullOrEmpty();
                edit.Changes.Should().BeNull();
            }
        }
Esempio n. 6
0
        public static string AddDiagsToSourceText <T>(string bicepOutput, string newlineSequence, IEnumerable <T> items, Func <T, TextSpan> getSpanFunc, Func <T, string> diagsFunc)
        {
            var lineStarts = TextCoordinateConverter.GetLineStarts(bicepOutput);

            var itemsByLine = items
                              .Select(item => {
                var(line, character) = TextCoordinateConverter.GetPosition(lineStarts, getSpanFunc(item).Position);
                return(line, character, item);
            })
                              .ToLookup(t => t.line);

            var sourceTextLines = bicepOutput.Split(newlineSequence);
            var stringBuilder   = new StringBuilder();

            for (var i = 0; i < sourceTextLines.Length; i++)
            {
                stringBuilder.Append(sourceTextLines[i]);
                stringBuilder.Append(newlineSequence);
                foreach (var(line, character, item) in itemsByLine[i])
                {
                    var escapedDiagsText = EscapeWhitespace(diagsFunc(item));
                    stringBuilder.Append($"//@[{character}:{character + getSpanFunc(item).Length}) {escapedDiagsText}");
                    stringBuilder.Append(newlineSequence);
                }
            }

            return(stringBuilder.ToString());
        }
Esempio n. 7
0
        public async Task GoToDefinitionRequestOnUnsupportedOrInvalidSyntaxNodeShouldReturnEmptyResponse(DataSet dataSet)
        {
            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithText(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var undeclaredSymbolBindings = symbolTable.Where(pair => !(pair.Value is DeclaredSymbol));

            foreach (var(syntax, _) in undeclaredSymbolBindings)
            {
                var response = await client.RequestDefinition(new DefinitionParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = PositionHelper.GetPosition(lineStarts, syntax.Span.Position)
                });

                // go to definition on a symbol that isn't declared by the user (like error or function symbol)
                // should produce an empty response
                response.Should().BeEmpty();
            }
        }
Esempio n. 8
0
        public void GetLineStarts_SingleLine_ReturnsZero()
        {
            IReadOnlyList <int> lineStarts = TextCoordinateConverter.GetLineStarts("The quick brown fox jumps over the lazy dog");

            lineStarts.Should().HaveCount(1);
            lineStarts[0].Should().Be(0);
        }
Esempio n. 9
0
        public void GetLineStarts_EmptyContents_ReturnsZero()
        {
            IReadOnlyList <int> lineStarts = TextCoordinateConverter.GetLineStarts(string.Empty);

            lineStarts.Should().HaveCount(1);
            lineStarts[0].Should().Be(0);
        }
Esempio n. 10
0
        private void BuildManyFilesToStdOut(IDiagnosticLogger logger, string[] bicepPaths)
        {
            using var writer = new JsonTextWriter(this.outputWriter)
                  {
                      Formatting = Formatting.Indented
                  };

            if (bicepPaths.Length > 1)
            {
                writer.WriteStartArray();
            }
            foreach (var bicepPath in bicepPaths)
            {
                string text       = File.ReadAllText(bicepPath);
                var    lineStarts = TextCoordinateConverter.GetLineStarts(text);

                var compilation = new Compilation(SyntaxFactory.CreateFromText(text));

                var emitter = new TemplateEmitter(compilation.GetSemanticModel());

                var result = emitter.Emit(writer);

                foreach (var diagnostic in result.Diagnostics)
                {
                    logger.LogDiagnostic(bicepPath, diagnostic, lineStarts);
                }
            }
            if (bicepPaths.Length > 1)
            {
                writer.WriteEndArray();
            }
        }
Esempio n. 11
0
        public async Task HighlightsShouldShowAllReferencesOfTheSymbol(DataSet dataSet)
        {
            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var symbolToSyntaxLookup = symbolTable
                                       .Where(pair => pair.Value.Kind != SymbolKind.Error)
                                       .ToLookup(pair => pair.Value, pair => pair.Key);

            foreach (var(syntax, symbol) in symbolTable.Where(s => s.Value.Kind != SymbolKind.Error))
            {
                var highlights = await client.RequestDocumentHighlight(new DocumentHighlightParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = IntegrationTestHelper.GetPosition(lineStarts, syntax)
                });

                // calculate expected highlights
                var expectedHighlights = symbolToSyntaxLookup[symbol].Select(node => CreateExpectedHighlight(lineStarts, node));

                // ranges should match what we got from our own symbol table
                highlights.Should().BeEquivalentTo(expectedHighlights);
            }
        }
Esempio n. 12
0
        public void ProgramsShouldProduceExpectedUserDeclaredSymbols(DataSet dataSet)
        {
            var compilation = new Compilation(TestResourceTypeProvider.CreateRegistrar(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var model       = compilation.GetSemanticModel();

            var symbols = SymbolCollector
                          .CollectSymbols(model)
                          .OfType <DeclaredSymbol>();

            var lineStarts = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            string getLoggingString(DeclaredSymbol symbol)
            {
                (_, var startChar) = TextCoordinateConverter.GetPosition(lineStarts, symbol.DeclaringSyntax.Span.Position);

                return($"{symbol.Kind} {symbol.Name}. Type: {symbol.Type}. Declaration start char: {startChar}, length: {symbol.DeclaringSyntax.Span.Length}");
            }

            var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(dataSet, symbols, symb => symb.NameSyntax.Span, getLoggingString);
            var resultsFile         = FileHelper.SaveResultFile(this.TestContext !, Path.Combine(dataSet.Name, DataSet.TestFileMainSymbols), sourceTextWithDiags);

            sourceTextWithDiags.Should().EqualWithLineByLineDiffOutput(
                dataSet.Symbols,
                expectedLocation: OutputHelper.GetBaselineUpdatePath(dataSet, DataSet.TestFileMainSymbols),
                actualLocation: resultsFile);
        }
Esempio n. 13
0
        public CompilationContext Create(string text)
        {
            var lineStarts = TextCoordinateConverter.GetLineStarts(text);

            var parser  = new Parser(text);
            var program = parser.Program();

            var compilation = new Compilation(program);

            return(new CompilationContext(compilation, lineStarts));
        }
        public static IList <CompletionTrigger> GetTriggers(string text)
        {
            var program    = ParserHelper.Parse(text);
            var lineStarts = TextCoordinateConverter.GetLineStarts(text);
            var triggers   = new List <CompletionTrigger>();

            var visitor = new CompletionTriggerCollector(triggers, lineStarts);

            visitor.Visit(program);

            return(triggers);
        }
Esempio n. 15
0
        public async Task RequestingCodeActionWithFixableDiagnosticsShouldProduceQuickFixes(DataSet dataSet)
        {
            var uri    = DocumentUri.From($"/{dataSet.Name}");
            var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri);

            // construct a parallel compilation
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);
            var fixables    = compilation.GetSemanticModel().GetAllDiagnostics().OfType <IFixable>();

            foreach (IFixable fixable in fixables)
            {
                foreach (var span in GetOverlappingSpans(fixable.Span))
                {
                    CommandOrCodeActionContainer?quickFixes = await client.RequestCodeAction(new CodeActionParams
                    {
                        TextDocument = new TextDocumentIdentifier(uri),
                        Range        = span.ToRange(lineStarts)
                    });

                    // Assert.
                    quickFixes.Should().NotBeNull();

                    var quickFixList = quickFixes.ToList();
                    var bicepFixList = fixable.Fixes.ToList();

                    quickFixList.Should().HaveSameCount(bicepFixList);

                    for (int i = 0; i < quickFixList.Count; i++)
                    {
                        var quickFix = quickFixList[i];
                        var bicepFix = bicepFixList[i];

                        quickFix.IsCodeAction.Should().BeTrue();
                        quickFix.CodeAction.Kind.Should().Be(CodeActionKind.QuickFix);
                        quickFix.CodeAction.Title.Should().Be(bicepFix.Description);
                        quickFix.CodeAction.Edit.Changes.Should().ContainKey(uri);

                        var textEditList    = quickFix.CodeAction.Edit.Changes[uri].ToList();
                        var replacementList = bicepFix.Replacements.ToList();

                        for (int j = 0; j < textEditList.Count; j++)
                        {
                            var textEdit    = textEditList[j];
                            var replacement = replacementList[j];

                            textEdit.Range.Should().Be(replacement.ToRange(lineStarts));
                            textEdit.NewText.Should().Be(replacement.Text);
                        }
                    }
                }
            }
        }
Esempio n. 16
0
        private IEnumerable <string> GetAllDiagnostics(string text, string bicepFilePath)
        {
            var compilation = new Compilation(SyntaxFactory.CreateFromText(text));
            var lineStarts  = TextCoordinateConverter.GetLineStarts(text);

            return(compilation.GetSemanticModel()
                   .GetAllDiagnostics()
                   .Select(d =>
            {
                var(line, character) = TextCoordinateConverter.GetPosition(lineStarts, d.Span.Position);
                return $"{bicepFilePath}({line + 1},{character + 1}) : {d.Level} {d.Code}: {d.Message}";
            }));
        }
Esempio n. 17
0
        private static void BuildSingleFile(IDiagnosticLogger logger, string bicepPath, string outputPath)
        {
            string text       = File.ReadAllText(bicepPath);
            var    lineStarts = TextCoordinateConverter.GetLineStarts(text);

            var compilation = new Compilation(SyntaxFactory.CreateFromText(text));

            var emitter = new TemplateEmitter(compilation.GetSemanticModel());

            var result = emitter.Emit(outputPath);

            foreach (var diagnostic in result.Diagnostics)
            {
                logger.LogDiagnostic(bicepPath, diagnostic, lineStarts);
            }
        }
        private string?GetSelectedTextFromFile(DocumentUri uri, Range?range)
        {
            if (range is null)
            {
                return(null);
            }

            var contents   = File.ReadAllText(uri.GetFileSystemPath());
            var lineStarts = TextCoordinateConverter.GetLineStarts(contents);
            var start      = TextCoordinateConverter.GetOffset(lineStarts, range.Start.Line, range.Start.Character);
            var end        = TextCoordinateConverter.GetOffset(lineStarts, range.End.Line, range.End.Character);

            var selectedText = contents.Substring(start, end - start);

            return(selectedText);
        }
Esempio n. 19
0
        public async Task RenamingIdentifierAccessOrDeclarationShouldRenameDeclarationAndAllReferences(DataSet dataSet)
        {
            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var symbolToSyntaxLookup = symbolTable
                                       .Where(pair => pair.Value.Kind != SymbolKind.Error)
                                       .ToLookup(pair => pair.Value, pair => pair.Key);

            var validVariableAccessPairs = symbolTable
                                           .Where(pair => (pair.Key is VariableAccessSyntax || pair.Key is IDeclarationSyntax) &&
                                                  pair.Value.Kind != SymbolKind.Error &&
                                                  pair.Value.Kind != SymbolKind.Function &&
                                                  pair.Value.Kind != SymbolKind.Namespace
                                                  // symbols whose identifiers have parse errors will have a name like <error> or <missing>
                                                  && pair.Value.Name.Contains("<") == false);

            const string expectedNewText = "NewIdentifier";

            foreach (var(syntax, symbol) in validVariableAccessPairs)
            {
                var edit = await client.RequestRename(new RenameParams
                {
                    NewName      = expectedNewText,
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = IntegrationTestHelper.GetPosition(lineStarts, syntax)
                });

                edit.DocumentChanges.Should().BeNullOrEmpty();
                edit.Changes.Should().HaveCount(1);
                edit.Changes.Should().ContainKey(uri);

                var textEdits = edit.Changes[uri];
                textEdits.Should().NotBeEmpty();

                var expectedEdits = symbolToSyntaxLookup[symbol]
                                    .Select(node => CreateExpectedTextEdit(lineStarts, expectedNewText, node));

                textEdits.Should().BeEquivalentTo(expectedEdits);
            }
        }
Esempio n. 20
0
        private void BuildSingleFile(IDiagnosticLogger logger, string bicepPath, string outputPath)
        {
            string text       = ReadFile(bicepPath);
            var    lineStarts = TextCoordinateConverter.GetLineStarts(text);

            var compilation = new Compilation(resourceTypeProvider, SyntaxFactory.CreateFromText(text));

            var emitter = new TemplateEmitter(compilation.GetSemanticModel());

            using var outputStream = CreateFileStream(outputPath);
            var result = emitter.Emit(outputStream);

            foreach (var diagnostic in result.Diagnostics)
            {
                logger.LogDiagnostic(bicepPath, diagnostic, lineStarts);
            }
        }
Esempio n. 21
0
        public async Task RenamingNonSymbolsShouldProduceEmptyEdit(DataSet dataSet)
        {
            // local function
            bool IsWrongNode(SyntaxBase node) => !(node is ISymbolReference) && !(node is IDeclarationSyntax) && !(node is Token);

            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var symbolToSyntaxLookup = symbolTable
                                       .Where(pair => pair.Value.Kind != SymbolKind.Error)
                                       .ToLookup(pair => pair.Value, pair => pair.Key);

            var wrongNodes = SyntaxAggregator.Aggregate(
                compilation.ProgramSyntax,
                new List <SyntaxBase>(),
                (accumulated, node) =>
            {
                if (IsWrongNode(node) && !(node is ProgramSyntax))
                {
                    accumulated.Add(node);
                }

                return(accumulated);
            },
                accumulated => accumulated,
                (accumulated, node) => IsWrongNode(node));

            foreach (var syntax in wrongNodes)
            {
                var edit = await client.RequestRename(new RenameParams
                {
                    NewName      = "NewIdentifier",
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = IntegrationTestHelper.GetPosition(lineStarts, syntax)
                });

                edit.DocumentChanges.Should().BeNullOrEmpty();
                edit.Changes.Should().BeNull();
            }
        }
Esempio n. 22
0
        public static string AddDiagsToSourceText <T>(string bicepOutput, string newlineSequence, IEnumerable <T> items, Func <T, TextSpan> getSpanFunc, Func <T, string> diagsFunc)
        {
            var lineStarts = TextCoordinateConverter.GetLineStarts(bicepOutput);

            var diagsByLine = items
                              .Select(item =>
            {
                var span             = getSpanFunc(item);
                var(line, startChar) = TextCoordinateConverter.GetPosition(lineStarts, span.Position);
                var endChar          = startChar + span.Length;

                var escapedText = EscapeWhitespace(diagsFunc(item));

                return(line, startChar, endChar, escapedText);
            })
                              .ToLookup(t => t.line);

            var diags = diagsByLine.SelectMany(x => x);

            var startCharPadding = diags.Any() ? CountDigits(diags.Max(x => x.startChar)) : 0;
            var endCharPadding   = diags.Any() ? CountDigits(diags.Max(x => x.endChar)) : 0;

            var sourceTextLines = bicepOutput.Split(newlineSequence);
            var stringBuilder   = new StringBuilder();

            for (var i = 0; i < sourceTextLines.Length; i++)
            {
                stringBuilder.Append(sourceTextLines[i]);
                stringBuilder.Append(newlineSequence);
                foreach (var diag in diagsByLine[i])
                {
                    var startCharPadded = diag.startChar.ToString().PadLeft(startCharPadding, '0');
                    var endCharPadded   = diag.endChar.ToString().PadLeft(endCharPadding, '0');

                    // Pad the start & end char with zeros to ensure that the escaped text always starts at the same place
                    // This makes it easier to compare lines visually
                    stringBuilder.Append($"//@[{startCharPadded}:{endCharPadded}) {diag.escapedText}");
                    stringBuilder.Append(newlineSequence);
                }
            }

            return(stringBuilder.ToString());
        }
Esempio n. 23
0
        public async Task FindReferencesOnNonSymbolsShouldProduceEmptyResult(DataSet dataSet)
        {
            // local function
            bool IsWrongNode(SyntaxBase node) => !(node is ISymbolReference) && !(node is IDeclarationSyntax) && !(node is Token);

            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithText(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var wrongNodes = SyntaxAggregator.Aggregate(
                compilation.ProgramSyntax,
                new List <SyntaxBase>(),
                (accumulated, node) =>
            {
                if (IsWrongNode(node) && !(node is ProgramSyntax))
                {
                    accumulated.Add(node);
                }

                return(accumulated);
            },
                accumulated => accumulated,
                (accumulated, node) => IsWrongNode(node));

            foreach (var syntax in wrongNodes)
            {
                var locations = await client.RequestReferences(new ReferenceParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Context      = new ReferenceContext
                    {
                        IncludeDeclaration = false
                    },
                    Position = PositionHelper.GetPosition(lineStarts, syntax.Span.Position)
                });

                locations.Should().BeEmpty();
            }
        }
Esempio n. 24
0
        public async Task GoToDefinitionOnUnboundSyntaxNodeShouldReturnEmptyResponse(DataSet dataSet)
        {
            // local function
            bool IsUnboundNode(IDictionary <SyntaxBase, Symbol> dictionary, SyntaxBase syntax) => dictionary.ContainsKey(syntax) == false && !(syntax is Token);

            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithText(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var unboundNodes = SyntaxAggregator.Aggregate(
                source: compilation.ProgramSyntax,
                seed: new List <SyntaxBase>(),
                function: (accumulated, syntax) =>
            {
                if (IsUnboundNode(symbolTable, syntax) && !(syntax is ProgramSyntax))
                {
                    // only collect unbound nodes non-program nodes
                    accumulated.Add(syntax);
                }

                return(accumulated);
            },
                resultSelector: accumulated => accumulated,
                // visit children only if current node is not bound
                continuationFunction: (accumulated, syntax) => IsUnboundNode(symbolTable, syntax));

            foreach (var syntax in unboundNodes)
            {
                var response = await client.RequestDefinition(new DefinitionParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = PositionHelper.GetPosition(lineStarts, syntax.Span.Position)
                });

                // go to definition on a syntax node that isn't bound to a symbol should produce an empty response
                response.Should().BeEmpty();
            }
        }
Esempio n. 25
0
        public async Task HoveringOverSymbolReferencesAndDeclarationsShouldProduceHovers(DataSet dataSet)
        {
            var uri    = DocumentUri.From($"/{dataSet.Name}");
            var client = await IntegrationTestHelper.StartServerWithText(dataSet.Bicep, uri);

            // construct a parallel compilation
            var compilation = new Compilation(TestResourceTypeProvider.CreateRegistrar(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var symbolReferences = SyntaxAggregator.Aggregate(
                compilation.ProgramSyntax,
                new List <SyntaxBase>(),
                (accumulated, node) =>
            {
                if (node is ISymbolReference || node is IDeclarationSyntax)
                {
                    accumulated.Add(node);
                }

                return(accumulated);
            },
                accumulated => accumulated);

            foreach (SyntaxBase symbolReference in symbolReferences)
            {
                var hover = await client.RequestHover(new HoverParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = PositionHelper.GetPosition(lineStarts, symbolReference.Span.Position)
                });

                if (symbolTable.TryGetValue(symbolReference, out var symbol) == false)
                {
                    // symbol ref not bound to a symbol
                    ValidateEmptyHover(hover);
                    continue;
                }

                switch (symbol !.Kind)
                {
Esempio n. 26
0
        public object GetSemanticTokens(string content)
        {
            var lineStarts  = TextCoordinateConverter.GetLineStarts(content);
            var compilation = new Compilation(SyntaxFactory.CreateFromText(content));
            var tokens      = SemanticTokenVisitor.BuildSemanticTokens(compilation.ProgramSyntax, lineStarts);

            var           data      = new List <int>();
            SemanticToken?prevToken = null;

            foreach (var token in tokens)
            {
                if (prevToken == null)
                {
                    data.Add(token.Line);
                    data.Add(token.Character);
                    data.Add(token.Length);
                }
                else if (prevToken.Line != token.Line)
                {
                    data.Add(token.Line - prevToken.Line);
                    data.Add(token.Character);
                    data.Add(token.Length);
                }
                else
                {
                    data.Add(0);
                    data.Add(token.Character - prevToken.Character);
                    data.Add(token.Length);
                }

                data.Add((int)token.TokenType);
                data.Add(0);

                prevToken = token;
            }

            return(new {
                data = data.ToArray(),
            });
        }
Esempio n. 27
0
        public async Task FindReferencesWithoutDeclarationsShouldProduceCorrectResults(DataSet dataSet)
        {
            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithText(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var symbolToSyntaxLookup = symbolTable
                                       .Where(pair => pair.Value.Kind != SymbolKind.Error)
                                       .ToLookup(pair => pair.Value, pair => pair.Key);

            foreach (var(syntax, symbol) in symbolTable.Where(s => s.Value.Kind != SymbolKind.Error))
            {
                var locations = await client.RequestReferences(new ReferenceParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Context      = new ReferenceContext
                    {
                        IncludeDeclaration = false
                    },
                    Position = PositionHelper.GetPosition(lineStarts, syntax.Span.Position)
                });

                // all URIs should be the same in the results
                locations.Select(r => r.Uri).Should().AllBeEquivalentTo(uri);

                // exclude declarations when calculating expected ranges
                var expectedRanges = symbolToSyntaxLookup[symbol]
                                     .Where(node => !(node is IDeclarationSyntax))
                                     .Select(node => PositionHelper.GetNameRange(lineStarts, node));

                // ranges should match what we got from our own symbol table
                locations.Select(l => l.Range).Should().BeEquivalentTo(expectedRanges);
            }
        }
Esempio n. 28
0
        public async Task GoToDefinitionRequestOnValidSymbolReferenceShouldReturnLocationOfDeclaredSymbol(DataSet dataSet)
        {
            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithText(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            // filter out symbols that don't have locations
            var declaredSymbolBindings = symbolTable
                                         .Where(pair => pair.Value is DeclaredSymbol)
                                         .Select(pair => new KeyValuePair <SyntaxBase, DeclaredSymbol>(pair.Key, (DeclaredSymbol)pair.Value));

            foreach (var(syntax, symbol) in declaredSymbolBindings)
            {
                var response = await client.RequestDefinition(new DefinitionParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = PositionHelper.GetPosition(lineStarts, syntax.Span.Position)
                });

                var link = ValidateDefinitionResponse(response);

                // document should match the requested document
                link.TargetUri.Should().Be(uri);

                // target range should be the whole span of the symbol
                link.TargetRange.Should().Be(symbol.DeclaringSyntax.Span.ToRange(lineStarts));

                // selection range should be the span of the identifier of the symbol
                link.TargetSelectionRange.Should().Be(symbol.NameSyntax.Span.ToRange(lineStarts));

                // origin selection range should be the span of the syntax node that references the symbol
                link.OriginSelectionRange.Should().Be(syntax.ToRange(lineStarts));
            }
        }
Esempio n. 29
0
        public async Task RequestingHighlightsForWrongNodeShouldProduceNoHighlights(DataSet dataSet)
        {
            // local function
            bool IsWrongNode(SyntaxBase node) => !(node is ISymbolReference) && !(node is IDeclarationSyntax) && !(node is Token);

            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithText(dataSet.Bicep, uri);

            var compilation = new Compilation(SyntaxFactory.CreateFromText(dataSet.Bicep));
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var wrongNodes = SyntaxAggregator.Aggregate(
                compilation.ProgramSyntax,
                new List <SyntaxBase>(),
                (accumulated, node) =>
            {
                if (IsWrongNode(node) && !(node is ProgramSyntax))
                {
                    accumulated.Add(node);
                }

                return(accumulated);
            },
                accumulated => accumulated,
                (accumulated, node) => IsWrongNode(node));

            foreach (var syntax in wrongNodes)
            {
                var highlights = await client.RequestDocumentHighlight(new DocumentHighlightParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = PositionHelper.GetPosition(lineStarts, syntax.Span.Position)
                });

                highlights.Should().BeEmpty();
            }
        }
Esempio n. 30
0
        public async Task RequestingCodeActionWithNonFixableDiagnosticsShouldProduceEmptyQuickFixes(DataSet dataSet)
        {
            var uri    = DocumentUri.From($"/{dataSet.Name}");
            var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri);

            // construct a parallel compilation
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);
            var nonFixables = compilation.GetSemanticModel().GetAllDiagnostics().Where(diagnostic => !(diagnostic is IFixable));

            foreach (var nonFixable in nonFixables)
            {
                CommandOrCodeActionContainer?quickFixes = await client.RequestCodeAction(new CodeActionParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Range        = nonFixable.Span.ToRange(lineStarts)
                });

                // Assert.
                quickFixes.Should().NotBeNull();
                quickFixes.Should().BeEmpty();
            }
        }