Beispiel #1
0
        public void UpdateErrors(ITextSnapshot currentSnapshot, LintingErrorsSnapshot lintingErrors)
        {
            var oldLintingErrors = _snapshot;

            _snapshot = lintingErrors;


            // Raise a single tags changed event over the span that could have been affected by the change in the errors.
            var start = int.MaxValue;
            var end   = int.MinValue;

            if (oldLintingErrors?.Errors.Count > 0)
            {
                start = oldLintingErrors.Errors[0].Span.Start.TranslateTo(currentSnapshot, PointTrackingMode.Negative);
                end   = oldLintingErrors.Errors[oldLintingErrors.Errors.Count - 1].Span.End.TranslateTo(currentSnapshot, PointTrackingMode.Positive);
            }

            if (lintingErrors.Count > 0)
            {
                start = Math.Min(start, lintingErrors.Errors[0].Span.Start.Position);
                end   = Math.Max(end, lintingErrors.Errors[lintingErrors.Errors.Count - 1].Span.End.Position);
            }

            if (start < end)
            {
                TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(new SnapshotSpan(currentSnapshot, Span.FromBounds(start, end))));
            }
        }
Beispiel #2
0
        public LintTagger(LintChecker lintChecker)
        {
            _lintChecker = lintChecker;
            _snapshot    = lintChecker.LastErrorsSnapshot;

            lintChecker.AddTagger(this);
        }
        private void UpdateLintingErrors(LintingErrorsSnapshot lintSnapshot)
        {
            // Tell our factory to snap to a new snapshot.
            this.Factory.UpdateErrors(lintSnapshot);

            // Tell the provider to mark all the sinks dirty (so, as a side-effect, they will start an update pass that will get the new snapshot
            // from the factory).
            _provider.NotifyAllSinks();

            foreach (var tagger in _activeTaggers)
            {
                tagger.UpdateErrors(_currentSnapshot, lintSnapshot);
            }

            this.LastErrorsSnapshot = lintSnapshot;
            Updated?.Invoke(this, EventArgs.Empty);
        }
        private void OnBufferChange(object sender, TextContentChangedEventArgs e)
        {
            _currentSnapshot = e.After;

            // Translate all of the old dirty spans to the new snapshot.
            NormalizedSnapshotSpanCollection newDirtySpans = _dirtySpans.CloneAndTrackTo(e.After, SpanTrackingMode.EdgeInclusive);

            // Dirty all the spans that changed.
            foreach (var change in e.Changes)
            {
                newDirtySpans = NormalizedSnapshotSpanCollection.Union(newDirtySpans, new NormalizedSnapshotSpanCollection(e.After, change.NewSpan));
            }

            // Translate all the linting errors to the new snapshot (and remove anything that is a dirty region since we will need to check that again).
            var oldErrors = this.Factory.CurrentSnapshot;
            var newErrors = new LintingErrorsSnapshot(oldErrors.Document, oldErrors.VersionNumber + 1);

            // Copy all of the old errors to the new errors unless the error was affected by the text change
            foreach (var error in oldErrors.Errors)
            {
                Debug.Assert(error.NextIndex == -1);

                var newError = LintError.CloneAndTranslateTo(error, e.After);

                if (newError != null)
                {
                    Debug.Assert(newError.Span.Length == error.Span.Length);

                    error.NextIndex = newErrors.Errors.Count;
                    newErrors.Errors.Add(newError);
                }
            }

            this.UpdateLintingErrors(newErrors);

            _dirtySpans = newDirtySpans;

            // Start processing the dirty spans (which no-ops if we're already doing it).
            if (_dirtySpans.Count != 0)
            {
                this.RunLinter();
            }
        }
        public async Task DoUpdateAsync()
        {
            if (IsDisposed)
            {
                return;
            }

            var buffer = _currentSnapshot;
            var path   = _document.FilePath;

            // replace with user token
            var token    = _cts.Token;
            var instance = await FsLintVsPackage.Instance.WithCancellation(token);

            // this acts as a throttle
            await Task.Delay(200, token);

            if (Project == null)
            {
                await instance.JoinableTaskFactory.SwitchToMainThreadAsync();

                var project = instance.Dte.Solution.FindProjectItem(path)?.ContainingProject;

                if (project == null)
                {
                    return;
                }

                if (instance.SolutionService.GetProjectOfUniqueName(project.UniqueName, out var vsHierarchy) != VSConstants.S_OK)
                {
                    return;
                }

                if (instance.SolutionService.GetGuidOfProject(vsHierarchy, out var guid) != VSConstants.S_OK)
                {
                    return;
                }

                Project = new LintProjectInfo(project.Name, guid, vsHierarchy);
            }

            await Task.Yield();

            var connectionString = SqlAnalyzer.tryFindConnectionString(path);

            if (string.IsNullOrWhiteSpace(connectionString))
            {
                return;
            }

            var loadedSchema = SqlAnalysis.databaseSchema(connectionString);

            if (loadedSchema.IsError)
            {
                return;
            }

            var source     = _currentSnapshot.GetText();
            var sourceText = SourceText.ofString(source);

            var getProjectOptions = _provider.CheckerInstance.GetProjectOptionsFromScript(
                filename: path,
                sourceText: sourceText,
                assumeDotNetFramework: false,
                useSdkRefs: true,
                useFsiAuxLib: true,
                previewEnabled: true,
                otherFlags: new string[] { "--targetprofile:netstandard" },
                loadedTimeStamp: FSharpOption <DateTime> .None,
                extraProjectInfo: FSharpOption <object> .None,
                optionsStamp: FSharpOption <long> .None,
                userOpName: FSharpOption <string> .None
                );

            var(options, errors) = await FSharpAsync.StartAsTask(getProjectOptions, null, token);

            if (errors.Any())
            {
                return;
            }

            var performParseAndCheck = _provider.CheckerInstance.ParseAndCheckFileInProject(
                filename: path,
                fileversion: 1,
                sourceText: sourceText,
                options: options,
                textSnapshotInfo: FSharpOption <object> .None,
                userOpName: FSharpOption <string> .None
                );

            var(parseResults, checkAnswer) = await FSharpAsync.StartAsTask(performParseAndCheck, null, token);

            if (parseResults.ParseHadErrors || checkAnswer.IsAborted)
            {
                return;
            }

            var checkResults = SqlAnalyzer.checkAnswerResult(checkAnswer).Value;

            var context = new SqlAnalyzerContext(
                fileName: path,
                content: source.Split('\n'),
                parseTree: parseResults.ParseTree.Value,
                symbols: SqlAnalyzer.getSymbols(checkResults)
                );

            var databaseSchema = loadedSchema.ResultValue;

            var errorMessages =
                from operation in SyntacticAnalysis.findSqlOperations(context)
                from analysisOutput in SqlAnalysis.analyzeOperation(operation, connectionString, databaseSchema)
                select analysisOutput;

            var oldLintingErrors = this.Factory.CurrentSnapshot;
            var newLintErrors    = new LintingErrorsSnapshot(_document, oldLintingErrors.VersionNumber + 1);

            foreach (var error in errorMessages)
            {
                var span = RangeToSpan(error.Range, buffer);
                newLintErrors.Errors.Add(new LintError(span, error, Project));
            }

            await instance.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (token.IsCancellationRequested)
            {
                return;
            }

            UpdateLintingErrors(newLintErrors);
        }
Beispiel #6
0
 public void UpdateErrors(LintingErrorsSnapshot lintingErrors)
 {
     this.CurrentSnapshot.NextSnapshot = lintingErrors;
     this.CurrentSnapshot = lintingErrors;
 }
Beispiel #7
0
 public LintTableSnapshotFactory(LintingErrorsSnapshot lintErrors)
 {
     this.CurrentSnapshot = lintErrors;
 }
Beispiel #8
0
        public async Task DoUpdateAsync()
        {
            if (IsDisposed)
            {
                return;
            }

            var buffer = _currentSnapshot;
            var path   = _document.FilePath;

            // replace with user token
            var token    = _cts.Token;
            var instance = await FsLintVsPackage.Instance.WithCancellation(token);

            // this acts as a throttle
            await Task.Delay(200, token);

            if (Project == null)
            {
                await instance.JoinableTaskFactory.SwitchToMainThreadAsync();

                var project = instance.Dte.Solution.FindProjectItem(path)?.ContainingProject;

                if (project == null)
                {
                    return;
                }

                if (instance.SolutionService.GetProjectOfUniqueName(project.UniqueName, out var vsHierarchy) != VSConstants.S_OK)
                {
                    return;
                }

                if (instance.SolutionService.GetGuidOfProject(vsHierarchy, out var guid) != VSConstants.S_OK)
                {
                    return;
                }

                Project = new LintProjectInfo(project.Name, guid, vsHierarchy);
            }

            await Task.Yield();

            var connectionString = SqlAnalyzer.tryFindConnectionString(path);

            if (string.IsNullOrWhiteSpace(connectionString))
            {
                return;
            }



            var source     = _currentSnapshot.GetText();
            var sourceText = SourceText.ofString(source);

            var getProjectOptions = _provider.CheckerInstance.GetProjectOptionsFromScript(
                filename: path,
                source: sourceText,
                assumeDotNetFramework: false,
                useSdkRefs: true,
                useFsiAuxLib: true,
                previewEnabled: true,
                otherFlags: new string[] { "--targetprofile:netstandard" },
                loadedTimeStamp: FSharpOption <DateTime> .None,
                extraProjectInfo: FSharpOption <object> .None,
                optionsStamp: FSharpOption <long> .None,
                userOpName: FSharpOption <string> .None,
                sdkDirOverride: FSharpOption <string> .None
                );

            var(options, errors) = await FSharpAsync.StartAsTask(getProjectOptions, null, token);

            if (errors.Any())
            {
                return;
            }

            var performParseAndCheck = _provider.CheckerInstance.ParseAndCheckFileInProject(
                filename: path,
                fileVersion: 1,
                sourceText: sourceText,
                options: options,
                userOpName: FSharpOption <string> .None
                );

            var(parseResults, checkAnswer) = await FSharpAsync.StartAsTask(performParseAndCheck, null, token);

            if (parseResults.ParseHadErrors || checkAnswer.IsAborted)
            {
                return;
            }

            var checkResults = SqlAnalyzer.checkAnswerResult(checkAnswer).Value;

            var context = new SqlAnalyzerContext(
                fileName: path,
                content: source.Split('\n'),
                parseTree: parseResults.ParseTree.Value,
                symbols: SqlAnalyzer.getSymbols(checkResults)
                );

            var operationBlocks = SyntacticAnalysis.findSqlOperations(context);
            var loadedSchema    = SqlAnalysis.databaseSchema(connectionString);

            var errorMessages = new List <Message>();

            if (loadedSchema.IsError)
            {
                foreach (var operation in operationBlocks)
                {
                    var containsSkipAnalysis = operation.blocks.Any(block => block.IsSkipAnalysis);
                    foreach (var block in operation.blocks)
                    {
                        var blockRange = block.Range();
                        if ((block.IsQuery || block.IsTransaction) && OptionModule.IsSome(blockRange) && !containsSkipAnalysis)
                        {
                            var internalError = (loadedSchema.ErrorValue ?? "").Replace("3D000:", "").Replace("28P01:", "");
                            var fullError     = $"Error occured while trying to connect to the database using the configured connection string in NPGSQL_FSHARP in order to perform static analysis:{internalError}";
                            var errorMessage  = new Message(
                                type: "Error",
                                message: fullError,
                                code: "SQL101",
                                severity: Severity.Warning,
                                range: blockRange.Value,
                                fixes: Microsoft.FSharp.Collections.FSharpList <Fix> .Empty
                                );

                            errorMessages.Add(errorMessage);
                        }
                    }
                }
            }
            else
            {
                var databaseSchema = loadedSchema.ResultValue;
                foreach (var operation in operationBlocks)
                {
                    foreach (var analysisOutput in SqlAnalysis.analyzeOperation(operation, connectionString, databaseSchema))
                    {
                        errorMessages.Add(analysisOutput);
                    }
                }
            }

            var oldLintingErrors = this.Factory.CurrentSnapshot;
            var newLintErrors    = new LintingErrorsSnapshot(_document, oldLintingErrors.VersionNumber + 1);

            foreach (var error in errorMessages)
            {
                var span = RangeToSpan(error.Range, buffer);
                newLintErrors.Errors.Add(new LintError(span, error, Project));
            }

            await instance.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (token.IsCancellationRequested)
            {
                return;
            }

            UpdateLintingErrors(newLintErrors);
        }