From 3d049cb12f654a89f4ae723da8a495029d455439 Mon Sep 17 00:00:00 2001 From: Marius Ungureanu Date: Tue, 30 Apr 2019 07:09:38 +0200 Subject: Update main/src/addins/VBNetBinding/Project/VBNetParsedDocument.cs Co-Authored-By: mkrueger --- .../VBNetBinding/Project/VBNetParsedDocument.cs | 665 +++++++++++---------- 1 file changed, 333 insertions(+), 332 deletions(-) (limited to 'main/src/addins/VBNetBinding') diff --git a/main/src/addins/VBNetBinding/Project/VBNetParsedDocument.cs b/main/src/addins/VBNetBinding/Project/VBNetParsedDocument.cs index 73cbaca827..921754b73f 100644 --- a/main/src/addins/VBNetBinding/Project/VBNetParsedDocument.cs +++ b/main/src/addins/VBNetBinding/Project/VBNetParsedDocument.cs @@ -1,181 +1,181 @@ -// -// CSharpParsedDocument.cs -// -// Author: -// Mike Krüger -// -// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using MonoDevelop.Ide.TypeSystem; -using Microsoft.CodeAnalysis; -using System.Collections.Generic; -using System.Linq; -using MonoDevelop.Ide.Editor; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using MonoDevelop.Core; -using MonoDevelop.Core.Text; -using MonoDevelop.Ide; - -namespace MonoDevelop.VBNetBinding -{ - class VBNetParsedDocument : ParsedDocument - { - static string[] tagComments; - - internal DocumentId DocumentId { - get; - set; - } - internal SyntaxTree ParsedUnit { - get; - set; - } - - static VBNetParsedDocument () - { - UpdateTags (); - MonoDevelop.Ide.Tasks.CommentTag.SpecialCommentTagsChanged += delegate { - UpdateTags (); - }; - } - - static void UpdateTags () - { - tagComments = MonoDevelop.Ide.Tasks.CommentTag.SpecialCommentTags.Select (t => t.Tag).ToArray (); - } - bool isAdHocProject; - - public VBNetParsedDocument (Ide.TypeSystem.ParseOptions options, string fileName) : base (fileName) - { - isAdHocProject = options.IsAdhocProject; - Flags |= ParsedDocumentFlags.SkipFoldings; - } - - #region implemented abstract members of ParsedDocument - - IReadOnlyList comments; - SemaphoreSlim commentLock = new SemaphoreSlim (1, 1); - - public override Task> GetCommentsAsync (CancellationToken cancellationToken = default(CancellationToken)) - { - if (comments == null) { - return Task.Run (async delegate { - bool locked = await commentLock.WaitAsync (Timeout.Infinite, cancellationToken).ConfigureAwait (false); - await commentLock.WaitAsync (); - try { - if (comments == null) { - var visitor = new CommentVisitor (cancellationToken); - var unit = await GetParsedSyntaxTreeAsync (cancellationToken); - if (unit != null) { - try { +// +// CSharpParsedDocument.cs +// +// Author: +// Mike Krüger +// +// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using MonoDevelop.Ide.TypeSystem; +using Microsoft.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; +using MonoDevelop.Ide.Editor; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using MonoDevelop.Core; +using MonoDevelop.Core.Text; +using MonoDevelop.Ide; + +namespace MonoDevelop.VBNetBinding +{ + class VBNetParsedDocument : ParsedDocument + { + static string[] tagComments; + + internal DocumentId DocumentId { + get; + set; + } + internal SyntaxTree ParsedUnit { + get; + set; + } + + static VBNetParsedDocument () + { + UpdateTags (); + MonoDevelop.Ide.Tasks.CommentTag.SpecialCommentTagsChanged += delegate { + UpdateTags (); + }; + } + + static void UpdateTags () + { + tagComments = MonoDevelop.Ide.Tasks.CommentTag.SpecialCommentTags.Select (t => t.Tag).ToArray (); + } + bool isAdHocProject; + + public VBNetParsedDocument (Ide.TypeSystem.ParseOptions options, string fileName) : base (fileName) + { + isAdHocProject = options.IsAdhocProject; + Flags |= ParsedDocumentFlags.SkipFoldings; + } + + #region implemented abstract members of ParsedDocument + + IReadOnlyList comments; + SemaphoreSlim commentLock = new SemaphoreSlim (1, 1); + + public override Task> GetCommentsAsync (CancellationToken cancellationToken = default(CancellationToken)) + { + if (comments == null) { + return Task.Run (async delegate { + bool locked = await commentLock.WaitAsync (Timeout.Infinite, cancellationToken).ConfigureAwait (false); + await commentLock.WaitAsync (); + try { + if (comments == null) { + var visitor = new CommentVisitor (cancellationToken); + var unit = await GetParsedSyntaxTreeAsync (cancellationToken); + if (unit != null) { + try { var syntaxRoot = await unit.GetRootAsync (cancellationToken); visitor.Visit (syntaxRoot); } catch (OperationCanceledException) { - } - } - comments = visitor.Comments; - } - } finally { - if (locked) - commentLock.Release (); - } - return comments; - }); - } - return Task.FromResult (comments); - - async Task GetParsedSyntaxTreeAsync (CancellationToken token) - { - if (ParsedUnit == null && DocumentId != null) { - var document = IdeServices.TypeSystemService.GetCodeAnalysisDocument (DocumentId, token); - ParsedUnit = await document.GetSyntaxTreeAsync (token); - } - return ParsedUnit; - } - } - - - class CommentVisitor : CSharpSyntaxWalker - { - public readonly List Comments = new List (); - - CancellationToken cancellationToken; - - public CommentVisitor (CancellationToken cancellationToken) : base(SyntaxWalkerDepth.Trivia) - { - this.cancellationToken = cancellationToken; - } - - DocumentRegion GetRegion (SyntaxTrivia trivia) - { - var fullSpan = trivia.FullSpan; + } + } + comments = visitor.Comments; + } + } finally { + if (locked) + commentLock.Release (); + } + return comments; + }); + } + return Task.FromResult (comments); + + async Task GetParsedSyntaxTreeAsync (CancellationToken token) + { + if (ParsedUnit == null && DocumentId != null) { + var document = IdeServices.TypeSystemService.GetCodeAnalysisDocument (DocumentId, token); + ParsedUnit = await document.GetSyntaxTreeAsync (token); + } + return ParsedUnit; + } + } + + + class CommentVisitor : CSharpSyntaxWalker + { + public readonly List Comments = new List (); + + CancellationToken cancellationToken; + + public CommentVisitor (CancellationToken cancellationToken) : base(SyntaxWalkerDepth.Trivia) + { + this.cancellationToken = cancellationToken; + } + + DocumentRegion GetRegion (SyntaxTrivia trivia) + { + var fullSpan = trivia.FullSpan; if (fullSpan.Length > 2) { - var text = trivia.SyntaxTree.GetText (cancellationToken); - if (text [fullSpan.End - 2] == '\r' && text [fullSpan.End - 1] == '\n') - fullSpan = new Microsoft.CodeAnalysis.Text.TextSpan (fullSpan.Start, fullSpan.Length - 2); - else if (NewLine.IsNewLine (text [fullSpan.End - 1])) - fullSpan = new Microsoft.CodeAnalysis.Text.TextSpan (fullSpan.Start, fullSpan.Length - 1); - } - try { - var lineSpan = trivia.SyntaxTree.GetLineSpan (fullSpan); - return (DocumentRegion)lineSpan; - } catch (Exception) { - return DocumentRegion.Empty; - } - } - - public override void VisitBlock (BlockSyntax node) - { - cancellationToken.ThrowIfCancellationRequested (); - base.VisitBlock (node); - } - - bool StartsLine (SyntaxTrivia trivia) - { - var sourceText = trivia.SyntaxTree.GetText (cancellationToken); - Microsoft.CodeAnalysis.Text.TextLine textLine; - try { - textLine = sourceText.Lines.GetLineFromPosition (trivia.SpanStart); - } catch (ArgumentOutOfRangeException) { - return false; - } - //We need start of trivia.FullSpan and not trivia.SpanStart - //because in case of documentation /// > GetTagCommentsAsync (CancellationToken cancellationToken = default(CancellationToken)) - { - return Task.FromResult> (null); - } - - sealed class SemanticTagVisitor : CSharpSyntaxWalker - { - public List Tags = new List (); - CancellationToken cancellationToken; - - public SemanticTagVisitor () : base (SyntaxWalkerDepth.Trivia) - { - } - - public SemanticTagVisitor (CancellationToken cancellationToken) : base (SyntaxWalkerDepth.Trivia) - { - this.cancellationToken = cancellationToken; - } - - public override void VisitBlock (BlockSyntax node) - { - cancellationToken.ThrowIfCancellationRequested (); - base.VisitBlock (node); - } - - public override void VisitTrivia (SyntaxTrivia trivia) - { - cancellationToken.ThrowIfCancellationRequested (); - if (trivia.IsKind (SyntaxKind.SingleLineCommentTrivia) || - trivia.IsKind (SyntaxKind.MultiLineCommentTrivia) || - trivia.IsKind (SyntaxKind.SingleLineDocumentationCommentTrivia)) { - var trimmedContent = trivia.ToString ().TrimStart ('/', ' ', '*'); - foreach (string tag in tagComments) { - if (!trimmedContent.StartsWith (tag, StringComparison.Ordinal)) - continue; - var loc = trivia.GetLocation ().GetLineSpan (); - Tags.Add (new Tag (tag, trimmedContent, new DocumentRegion (loc.StartLinePosition, loc.EndLinePosition))); - break; - } - } - } - - public override void VisitThrowStatement (Microsoft.CodeAnalysis.CSharp.Syntax.ThrowStatementSyntax node) - { - cancellationToken.ThrowIfCancellationRequested (); - base.VisitThrowStatement (node); - var createExpression = node.Expression as ObjectCreationExpressionSyntax; - if (createExpression == null) - return; - var st = createExpression.Type.ToString (); - if (st == "NotImplementedException" || st == "System.NotImplementedException") { - var loc = node.GetLocation ().GetLineSpan (); - if (createExpression.ArgumentList.Arguments.Count > 0) { - Tags.Add (new Tag ("High", GettextCatalog.GetString ("NotImplementedException({0}) thrown.", createExpression.ArgumentList.Arguments.First ().ToString ()), new DocumentRegion (loc.StartLinePosition, loc.EndLinePosition))); - } else { - Tags.Add (new Tag ("High", GettextCatalog.GetString ("NotImplementedException thrown."), new DocumentRegion (loc.StartLinePosition, loc.EndLinePosition))); - } - } - } - } - - static readonly Task> foldings = Task.FromResult((IReadOnlyList)new FoldingRegion[0]); - - public override Task> GetFoldingsAsync (CancellationToken cancellationToken = default (CancellationToken)) => foldings; - - SemaphoreSlim errorLock = new SemaphoreSlim (1, 1); - - static readonly IReadOnlyList emptyErrors = Array.Empty (); - public override async Task> GetErrorsAsync (CancellationToken cancellationToken = default(CancellationToken)) - { - if (Ide.IdeApp.Preferences.EnableSourceAnalysis || DocumentId is null) - return emptyErrors; - - // FIXME: remove this fallback, error squiggles should always be handled via the source analysis mechanism - var document = IdeServices.TypeSystemService.GetCodeAnalysisDocument (DocumentId, cancellationToken); - var model = await document.GetSemanticModelAsync (cancellationToken); - - bool locked = await errorLock.WaitAsync (Timeout.Infinite, cancellationToken).ConfigureAwait (false); - IReadOnlyList errors; + } + + public override void VisitTrivia (SyntaxTrivia trivia) + { + cancellationToken.ThrowIfCancellationRequested (); + base.VisitTrivia (trivia); + switch (trivia.Kind ()) { + case SyntaxKind.MultiLineCommentTrivia: + case SyntaxKind.MultiLineDocumentationCommentTrivia: + { + var cmt = new Comment (CropStart (trivia, "/*")); + cmt.CommentStartsLine = StartsLine(trivia); + cmt.CommentType = CommentType.Block; + cmt.OpenTag = "/*"; + cmt.ClosingTag = "*/"; + cmt.Region = GetRegion (trivia); + Comments.Add (cmt); + break; + } + case SyntaxKind.SingleLineCommentTrivia: + { + var cmt = new Comment (CropStart (trivia, "//")); + cmt.CommentStartsLine = StartsLine(trivia); + cmt.CommentType = CommentType.SingleLine; + cmt.OpenTag = "//"; + cmt.Region = GetRegion (trivia); + Comments.Add (cmt); + break; + } + case SyntaxKind.SingleLineDocumentationCommentTrivia: + { + var cmt = new Comment (CropStart (trivia, "///")); + cmt.CommentStartsLine = StartsLine(trivia); + cmt.IsDocumentation = true; + cmt.CommentType = CommentType.Documentation; + cmt.OpenTag = "///"; + cmt.ClosingTag = "///"; + cmt.Region = GetRegion (trivia); + Comments.Add (cmt); + break; + } + + } + + } + } + + // Tags are done via Ide.Tasks.CommentTasksProvider. + public override Task> GetTagCommentsAsync (CancellationToken cancellationToken = default(CancellationToken)) + { + return Task.FromResult> (null); + } + + sealed class SemanticTagVisitor : CSharpSyntaxWalker + { + public List Tags = new List (); + CancellationToken cancellationToken; + + public SemanticTagVisitor () : base (SyntaxWalkerDepth.Trivia) + { + } + + public SemanticTagVisitor (CancellationToken cancellationToken) : base (SyntaxWalkerDepth.Trivia) + { + this.cancellationToken = cancellationToken; + } + + public override void VisitBlock (BlockSyntax node) + { + cancellationToken.ThrowIfCancellationRequested (); + base.VisitBlock (node); + } + + public override void VisitTrivia (SyntaxTrivia trivia) + { + cancellationToken.ThrowIfCancellationRequested (); + if (trivia.IsKind (SyntaxKind.SingleLineCommentTrivia) || + trivia.IsKind (SyntaxKind.MultiLineCommentTrivia) || + trivia.IsKind (SyntaxKind.SingleLineDocumentationCommentTrivia)) { + var trimmedContent = trivia.ToString ().TrimStart ('/', ' ', '*'); + foreach (string tag in tagComments) { + if (!trimmedContent.StartsWith (tag, StringComparison.Ordinal)) + continue; + var loc = trivia.GetLocation ().GetLineSpan (); + Tags.Add (new Tag (tag, trimmedContent, new DocumentRegion (loc.StartLinePosition, loc.EndLinePosition))); + break; + } + } + } + + public override void VisitThrowStatement (Microsoft.CodeAnalysis.CSharp.Syntax.ThrowStatementSyntax node) + { + cancellationToken.ThrowIfCancellationRequested (); + base.VisitThrowStatement (node); + var createExpression = node.Expression as ObjectCreationExpressionSyntax; + if (createExpression == null) + return; + var st = createExpression.Type.ToString (); + if (st == "NotImplementedException" || st == "System.NotImplementedException") { + var loc = node.GetLocation ().GetLineSpan (); + if (createExpression.ArgumentList.Arguments.Count > 0) { + Tags.Add (new Tag ("High", GettextCatalog.GetString ("NotImplementedException({0}) thrown.", createExpression.ArgumentList.Arguments.First ().ToString ()), new DocumentRegion (loc.StartLinePosition, loc.EndLinePosition))); + } else { + Tags.Add (new Tag ("High", GettextCatalog.GetString ("NotImplementedException thrown."), new DocumentRegion (loc.StartLinePosition, loc.EndLinePosition))); + } + } + } + } + + static readonly Task> foldings = Task.FromResult((IReadOnlyList)new FoldingRegion[0]); + + public override Task> GetFoldingsAsync (CancellationToken cancellationToken = default (CancellationToken)) => foldings; + + SemaphoreSlim errorLock = new SemaphoreSlim (1, 1); + + static readonly IReadOnlyList emptyErrors = Array.Empty (); + public override async Task> GetErrorsAsync (CancellationToken cancellationToken = default(CancellationToken)) + { + if (Ide.IdeApp.Preferences.EnableSourceAnalysis || DocumentId is null) + return emptyErrors; + + // FIXME: remove this fallback, error squiggles should always be handled via the source analysis mechanism + var document = IdeServices.TypeSystemService.GetCodeAnalysisDocument (DocumentId, cancellationToken); + var model = await document.GetSemanticModelAsync (cancellationToken); + + bool locked = await errorLock.WaitAsync (Timeout.Infinite, cancellationToken).ConfigureAwait (false); + IReadOnlyList errors; try { try { errors = model .GetDiagnostics (null, cancellationToken) .Select ((Diagnostic diag) => new Error (GetErrorType (diag.Severity), diag.Id, diag.GetMessage (), GetRegion (diag)) { Tag = diag }) - .ToList (); + .ToList (); } catch (OperationCanceledException) { errors = emptyErrors; } catch (Exception e) { LoggingService.LogError ("Error while getting diagnostics.", e); errors = emptyErrors; } - } finally { - if (locked) - errorLock.Release (); } - - return errors; - } - - static DocumentRegion GetRegion (Diagnostic diagnostic) - { - try { - var lineSpan = diagnostic.Location.GetLineSpan (); - return new DocumentRegion (lineSpan.StartLinePosition, lineSpan.EndLinePosition); - } catch (Exception) { - return DocumentRegion.Empty; - } - } - - static ErrorType GetErrorType (DiagnosticSeverity severity) - { - switch (severity) { - case DiagnosticSeverity.Error: - return ErrorType.Error; - case DiagnosticSeverity.Warning: - return ErrorType.Warning; - } - return ErrorType.Unknown; - } - - #endregion - } -} \ No newline at end of file + } finally { + if (locked) + errorLock.Release (); + } + + return errors; + } + + static DocumentRegion GetRegion (Diagnostic diagnostic) + { + try { + var lineSpan = diagnostic.Location.GetLineSpan (); + return new DocumentRegion (lineSpan.StartLinePosition, lineSpan.EndLinePosition); + } catch (Exception) { + return DocumentRegion.Empty; + } + } + + static ErrorType GetErrorType (DiagnosticSeverity severity) + { + switch (severity) { + case DiagnosticSeverity.Error: + return ErrorType.Error; + case DiagnosticSeverity.Warning: + return ErrorType.Warning; + } + return ErrorType.Unknown; + } + + #endregion + } +} -- cgit v1.2.3