diff options
Diffstat (limited to 'main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser')
3 files changed, 532 insertions, 390 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpFoldingParser.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpFoldingParser.cs index f87390b709..776abe4a87 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpFoldingParser.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpFoldingParser.cs @@ -26,9 +26,7 @@ using System; using System.Collections.Generic; using MonoDevelop.Ide.TypeSystem; -using ICSharpCode.NRefactory; -using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.CSharp; +using MonoDevelop.Ide.Editor; namespace MonoDevelop.CSharp.Parser { @@ -94,14 +92,14 @@ namespace MonoDevelop.CSharp.Parser public unsafe ParsedDocument Parse (string fileName, string content) { - var regionStack = new Stack<Tuple<string, TextLocation>> (); + var regionStack = new Stack<Tuple<string, DocumentLocation>> (); var result = new DefaultParsedDocument (fileName); bool inSingleComment = false, inMultiLineComment = false; bool inString = false, inVerbatimString = false; bool inChar = false; bool inLineStart = true, hasStartedAtLine = false; int line = 1, column = 1; - var startLoc = TextLocation.Empty; + var startLoc = DocumentLocation.Empty; fixed (char* startPtr = content) { char* endPtr = startPtr + content.Length; @@ -116,7 +114,7 @@ namespace MonoDevelop.CSharp.Parser ptr++; if (StartsIdentifier (ptr, endPtr, "region")) { - var regionLocation = new TextLocation (line, column); + var regionLocation = new DocumentLocation (line, column); column++; ptr += "region".Length; column += "region".Length; @@ -131,7 +129,7 @@ namespace MonoDevelop.CSharp.Parser var beginRegion = regionStack.Pop (); result.Add (new FoldingRegion ( beginRegion.Item1, - new DomRegion (beginRegion.Item2.Line, beginRegion.Item2.Column, line, column), + new DocumentRegion (beginRegion.Item2.Line, beginRegion.Item2.Column, line, column), FoldType.UserRegion, true)); } @@ -150,14 +148,14 @@ namespace MonoDevelop.CSharp.Parser if (nextCh == '/') { hasStartedAtLine = inLineStart; beginPtr = ptr + 2; - startLoc = new TextLocation (line, column); + startLoc = new DocumentLocation (line, column); ptr++; column++; inSingleComment = true; } else if (nextCh == '*') { hasStartedAtLine = inLineStart; beginPtr = ptr + 2; - startLoc = new TextLocation (line, column); + startLoc = new DocumentLocation (line, column); ptr++; column++; inMultiLineComment = true; @@ -175,7 +173,7 @@ namespace MonoDevelop.CSharp.Parser column += 2; inMultiLineComment = false; result.Add (new MonoDevelop.Ide.TypeSystem.Comment () { - Region = new DomRegion (startLoc, new TextLocation (line, column)), + Region = new DocumentRegion (startLoc, new DocumentLocation (line, column)), OpenTag = "/*", CommentType = MonoDevelop.Ide.TypeSystem.CommentType.Block, Text = content.Substring ((int)(beginPtr - startPtr), (int)(ptr - beginPtr)), @@ -202,7 +200,7 @@ namespace MonoDevelop.CSharp.Parser beginPtr++; result.Add (new MonoDevelop.Ide.TypeSystem.Comment () { - Region = new DomRegion (startLoc, new TextLocation (line, column)), + Region = new DocumentRegion (startLoc, new DocumentLocation (line, column)), CommentType = MonoDevelop.Ide.TypeSystem.CommentType.SingleLine, OpenTag = "//", Text = content.Substring ((int)(beginPtr - startPtr), (int)(ptr - beginPtr)), @@ -254,7 +252,7 @@ namespace MonoDevelop.CSharp.Parser ptr++; } } - foreach (var fold in result.Comments.ToFolds ()) { + foreach (var fold in result.GetCommentsAsync().Result.ToFolds ()) { result.Add (fold); } return result; diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs new file mode 100644 index 0000000000..db4c99f3c8 --- /dev/null +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs @@ -0,0 +1,444 @@ +// +// CSharpParsedDocument.cs +// +// Author: +// Mike Krüger <mkrueger@xamarin.com> +// +// 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; + +namespace MonoDevelop.CSharp.Parser +{ + class CSharpParsedDocument : ParsedDocument + { + internal SyntaxTree Unit { + get; + set; + } + + public CSharpParsedDocument (string fileName) : base (fileName) + { + } + + + #region implemented abstract members of ParsedDocument + + + WeakReference<IReadOnlyList<Comment>> weakComments; + + public override Task<IReadOnlyList<Comment>> GetCommentsAsync (CancellationToken cancellationToken = default(CancellationToken)) + { + IReadOnlyList<Comment> result; + if (weakComments == null || !weakComments.TryGetTarget (out result)) { + var visitor = new CommentVisitor (cancellationToken); + if (Unit != null) + visitor.Visit (Unit.GetRoot (cancellationToken)); + result = visitor.Comments; + + var newRef = new WeakReference<IReadOnlyList<Comment>> (result); + var oldRef = weakComments; + while (Interlocked.CompareExchange (ref weakComments, newRef, oldRef) == oldRef) { + } + } + return Task.FromResult (result); + } + + + class CommentVisitor : CSharpSyntaxWalker + { + public readonly List<Comment> Comments = new List<Comment> (); + + CancellationToken cancellationToken; + + public CommentVisitor (CancellationToken cancellationToken) : base(SyntaxWalkerDepth.Trivia) + { + this.cancellationToken = cancellationToken; + } + + static DocumentRegion GetRegion (SyntaxTrivia trivia) + { + var fullSpan = trivia.FullSpan; + var text = trivia.ToString (); + if (text.Length > 2) { + if (text [text.Length - 2] == '\r' && text [text.Length - 1] == '\n') + fullSpan = new Microsoft.CodeAnalysis.Text.TextSpan (fullSpan.Start, fullSpan.Length - 2); + else if (ICSharpCode.NRefactory6.NewLine.IsNewLine (text [text.Length - 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 /// <summary... + //trivia.SpanStart is space after /// and not 1st / + //so with trivia.FullSpan.Start we get index of 1st / + var startSpan = trivia.FullSpan.Start; + for (int i = textLine.Start; i < startSpan; i++) { + char ch = sourceText [i]; + if (!char.IsWhiteSpace (ch)) + return false; + } + return true; + } + + static string CropStart (string text, string crop) + { + text = text.Trim (); + if (text.StartsWith (crop)) + return text.Substring (crop.Length).TrimStart (); + return text; + } + + public override void VisitTrivia (SyntaxTrivia trivia) + { + base.VisitTrivia (trivia); + switch (trivia.Kind ()) { + case SyntaxKind.MultiLineCommentTrivia: + case SyntaxKind.MultiLineDocumentationCommentTrivia: + { + var cmt = new Comment (CropStart (trivia.ToString (), "/*")); + 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.ToString (), "//")); + 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.ToString (), "///")); + cmt.CommentStartsLine = StartsLine(trivia); + cmt.IsDocumentation = true; + cmt.CommentType = CommentType.Documentation; + cmt.OpenTag = "///"; + cmt.ClosingTag = "*/"; + cmt.Region = GetRegion (trivia); + Comments.Add (cmt); + break; + } + + } + + } + } + + WeakReference<IReadOnlyList<Tag>> weakTags; + + public override Task<IReadOnlyList<Tag>> GetTagCommentsAsync (CancellationToken cancellationToken = default(CancellationToken)) + { + IReadOnlyList<Tag> result; + if (weakTags == null || !weakTags.TryGetTarget (out result)) { + var visitor = new SemanticTagVisitor (cancellationToken); + if (Unit != null) { + try { + visitor.Visit (Unit.GetRoot (cancellationToken)); + } catch { + } + } + result = visitor.Tags; + + var newRef = new WeakReference<IReadOnlyList<Tag>> (result); + var oldRef = weakTags; + while (Interlocked.CompareExchange (ref weakTags, newRef, oldRef) == oldRef) { + } + } + return Task.FromResult (result); + } + + sealed class SemanticTagVisitor : CSharpSyntaxWalker + { + string[] tagComments; + public List<Tag> Tags = new List<Tag> (); + CancellationToken cancellationToken; + + public SemanticTagVisitor () : base (SyntaxWalkerDepth.Trivia) + { + tagComments = MonoDevelop.Ide.Tasks.CommentTag.SpecialCommentTags.Select (t => t.Tag).ToArray (); + + } + + public SemanticTagVisitor (CancellationToken cancellationToken) + { + 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)) { + foreach (string tag in tagComments) { + var trimmedContent = trivia.ToString ().TrimStart ('/', ' ', '*'); + if (!trimmedContent.StartsWith (tag)) + 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))); + } + } + } + } + + WeakReference<IReadOnlyList<FoldingRegion>> weakFoldings; + + public override Task<IReadOnlyList<FoldingRegion>> GetFoldingsAsync (CancellationToken cancellationToken = default(CancellationToken)) + { + IReadOnlyList<FoldingRegion> result; + if (weakFoldings == null || !weakFoldings.TryGetTarget (out result)) { + + result = GenerateFoldings (cancellationToken).ToList (); + + var newRef = new WeakReference<IReadOnlyList<FoldingRegion>> (result); + var oldRef = weakFoldings; + while (Interlocked.CompareExchange (ref weakFoldings, newRef, oldRef) == oldRef) { + } + } + + return Task.FromResult (result); + } + + IEnumerable<FoldingRegion> GenerateFoldings (CancellationToken cancellationToken) + { + foreach (var fold in GetCommentsAsync().Result.ToFolds ()) + yield return fold; + + var visitor = new FoldingVisitor (cancellationToken); + if (Unit != null) { + try { + visitor.Visit (Unit.GetRoot (cancellationToken)); + } catch (Exception) { } + } + foreach (var fold in visitor.Foldings) + yield return fold; + } + + class FoldingVisitor : CSharpSyntaxWalker + { + public readonly List<FoldingRegion> Foldings = new List<FoldingRegion> (); + CancellationToken cancellationToken; + + public FoldingVisitor (CancellationToken cancellationToken) + { + this.cancellationToken = cancellationToken; + } + + void AddUsings (SyntaxNode parent) + { + SyntaxNode firstChild = null, lastChild = null; + foreach (var child in parent.ChildNodes ()) { + if (child is UsingDirectiveSyntax) { + if (firstChild == null) { + firstChild = child; + } + lastChild = child; + continue; + } + if (firstChild != null) + break; + } + + if (firstChild != null && firstChild != lastChild) { + var first = firstChild.GetLocation ().GetLineSpan (); + var last = lastChild.GetLocation ().GetLineSpan (); + + Foldings.Add (new FoldingRegion (new DocumentRegion (first.StartLinePosition, last.EndLinePosition), FoldType.Undefined)); + } + } + + public override void VisitCompilationUnit (Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax node) + { + AddUsings (node); + base.VisitCompilationUnit (node); + } + + void AddFolding (SyntaxToken openBrace, SyntaxToken closeBrace) + { + openBrace = openBrace.GetPreviousToken (false, false, true, true); + + try { + var first = openBrace.GetLocation ().GetLineSpan (); + var last = closeBrace.GetLocation ().GetLineSpan (); + + if (first.EndLinePosition.Line != last.EndLinePosition.Line) + Foldings.Add (new FoldingRegion (new DocumentRegion (first.EndLinePosition, last.EndLinePosition), FoldType.Undefined)); + } catch (ArgumentOutOfRangeException) {} + } + + public override void VisitNamespaceDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax node) + { + AddUsings (node); + AddFolding (node.OpenBraceToken, node.CloseBraceToken); + base.VisitNamespaceDeclaration (node); + } + + public override void VisitClassDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax node) + { + AddFolding (node.OpenBraceToken, node.CloseBraceToken); + base.VisitClassDeclaration (node); + } + + public override void VisitStructDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax node) + { + AddFolding (node.OpenBraceToken, node.CloseBraceToken); + base.VisitStructDeclaration (node); + } + + public override void VisitInterfaceDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.InterfaceDeclarationSyntax node) + { + AddFolding (node.OpenBraceToken, node.CloseBraceToken); + base.VisitInterfaceDeclaration (node); + } + + public override void VisitEnumDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.EnumDeclarationSyntax node) + { + AddFolding (node.OpenBraceToken, node.CloseBraceToken); + base.VisitEnumDeclaration (node); + } + + public override void VisitBlock (Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax node) + { + cancellationToken.ThrowIfCancellationRequested (); + AddFolding (node.OpenBraceToken, node.CloseBraceToken); + base.VisitBlock (node); + } + } + + static readonly IReadOnlyList<Error> emptyErrors = new Error[0]; + WeakReference<IReadOnlyList<Error>> weakErrors; + + public override Task<IReadOnlyList<Error>> GetErrorsAsync (CancellationToken cancellationToken = default(CancellationToken)) + { + var model = GetAst<SemanticModel> (); + if (model == null) + return Task.FromResult (emptyErrors); + + IReadOnlyList<Error> result; + if (weakErrors == null || !weakErrors.TryGetTarget (out result)) { + try { + result = model + .GetDiagnostics (null, cancellationToken) + .Where (diag => diag.Severity == DiagnosticSeverity.Error || diag.Severity == DiagnosticSeverity.Warning) + .Select ((Diagnostic diag) => new Error (GetErrorType (diag.Severity), diag.Id, diag.GetMessage (), GetRegion (diag)) { Tag = diag }) + .ToList (); + var newRef = new WeakReference<IReadOnlyList<Error>> (result); + var oldRef = weakErrors; + while (Interlocked.CompareExchange (ref weakErrors, newRef, oldRef) == oldRef) { + } + } catch (OperationCanceledException) { + return Task.FromResult (emptyErrors); + } catch (Exception e) { + LoggingService.LogError ("Error while getting diagnostics.", e); + return Task.FromResult (emptyErrors); + } + } + return Task.FromResult (result); + } + + 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 diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/TypeSystemProvider.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/TypeSystemProvider.cs index 498d98544f..037656f295 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/TypeSystemProvider.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/TypeSystemProvider.cs @@ -25,375 +25,90 @@ // THE SOFTWARE. using System; using MonoDevelop.Ide.TypeSystem; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.TypeSystem; using System.Collections.Generic; using MonoDevelop.Projects; using MonoDevelop.CSharp.Project; -using MonoDevelop.Ide.Tasks; using Mono.CSharp; using System.Linq; -using ICSharpCode.NRefactory; -using MonoDevelop.CSharp.Refactoring.CodeActions; using MonoDevelop.Core; -using ICSharpCode.NRefactory.CSharp.Resolver; +using MonoDevelop.Ide.Editor; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using MonoDevelop.Core.Text; +using System.Threading.Tasks; namespace MonoDevelop.CSharp.Parser { - public class TypeSystemParser : MonoDevelop.Ide.TypeSystem.TypeSystemParser + sealed class TypeSystemParser : MonoDevelop.Ide.TypeSystem.TypeSystemParser { - public override ParsedDocument Parse (bool storeAst, string fileName, System.IO.TextReader content, MonoDevelop.Projects.Project project = null) + static readonly List<Error> emptyList = new List<Error> (); + public override System.Threading.Tasks.Task<ParsedDocument> Parse (MonoDevelop.Ide.TypeSystem.ParseOptions options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { - var parser = new ICSharpCode.NRefactory.CSharp.CSharpParser (GetCompilerArguments (project)); - parser.GenerateTypeSystemMode = !storeAst; - var result = new ParsedDocumentDecorator (); + var fileName = options.FileName; + var project = options.Project; + var result = new CSharpParsedDocument (fileName); if (project != null) { + var projectFile = project.Files.GetFile (fileName); if (projectFile != null && !TypeSystemParserNode.IsCompileBuildAction (projectFile.BuildAction)) result.Flags |= ParsedDocumentFlags.NonSerializable; } - var tagComments = CommentTag.SpecialCommentTags.Select (t => t.Tag).ToArray (); - - parser.CompilationUnitCallback = delegate (CompilerCompilationUnit top) { - foreach (var special in top.SpecialsBag.Specials) { - var comment = special as SpecialsBag.Comment; - if (comment != null) { - VisitComment (result, comment, tagComments); - } else { - if (storeAst) { - var ppd = special as SpecialsBag.PreProcessorDirective; - if (ppd != null) - VisitPreprocessorDirective (result, ppd); - } - } - } - }; - - var unit = parser.Parse (content, fileName); - unit.Freeze (); - var pf = unit.ToTypeSystem (); - try { - pf.LastWriteTime = System.IO.File.GetLastWriteTimeUtc (fileName); - } catch (Exception) { - pf.LastWriteTime = DateTime.UtcNow; - } - - result.LastWriteTimeUtc = pf.LastWriteTime.Value; - result.ParsedFile = pf; - result.Add (GetSemanticTags (unit)); - - result.CreateRefactoringContext = delegate (MonoDevelop.Ide.Gui.Document doc, System.Threading.CancellationToken token) { - var task = MDRefactoringContext.Create (doc, doc.Editor.Caret.Location, token); - try { - task.Wait (5000, token); - } catch (AggregateException ae) { - ae.Flatten ().Handle (aex => aex is OperationCanceledException); - return null; - } catch (OperationCanceledException) { - return null; - } - if (!task.IsCompleted) - return null; - return task.Result; - }; - result.CreateRefactoringContextWithEditor = (data, resolver, token) => new MDRefactoringContext ((DotNetProject)project, data, result, (CSharpAstResolver)resolver, TextLocation.Empty, token); + var compilerArguments = GetCompilerArguments (project); + SyntaxTree unit = null; - if (storeAst) { - result.Ast = unit; - result.Add (GenerateFoldings (unit, result)); - } - return result; - } - - IEnumerable<FoldingRegion> GenerateFoldings (SyntaxTree unit, ParsedDocument doc) - { - foreach (var fold in doc.ConditionalRegions.ToFolds ()) - yield return fold; - - foreach (var fold in doc.Comments.ToFolds ()) - yield return fold; - - var visitor = new FoldingVisitor (); - unit.AcceptVisitor (visitor, null); - foreach (var fold in visitor.Foldings) - yield return fold; - } - - class FoldingVisitor : DepthFirstAstVisitor<object, object> - { - public readonly List<FoldingRegion> Foldings = new List<FoldingRegion> (); - - void AddUsings (AstNode parent) - { - var firstChild = parent.Children.FirstOrDefault (child => child is UsingDeclaration || child is UsingAliasDeclaration); - var node = firstChild; - while (node != null) { - var next = node.GetNextNode (); - if (next is UsingDeclaration || next is UsingAliasDeclaration) { - node = next; - } else { - break; + if (project != null) { + var curDoc = options.RoslynDocument; + if (curDoc == null) { + var curProject = TypeSystemService.GetCodeAnalysisProject (project); + if (curProject != null) { + var documentId = TypeSystemService.GetDocumentId (project, fileName); + if (documentId != null) + curDoc = curProject.GetDocument (documentId); } } - if (firstChild != node) { - Foldings.Add (new FoldingRegion (new DomRegion (firstChild.StartLocation, node.EndLocation), FoldType.Undefined)); - } - } - public override object VisitSyntaxTree (SyntaxTree unit, object data) - { - AddUsings (unit); - return base.VisitSyntaxTree (unit, data); - } - - static TextLocation CorrectEnd (AstNode token) - { - return new TextLocation (token.EndLocation.Line, token.EndLocation.Column + 1); - } - - static bool LastToken(AstNode arg) - { - return !(arg.Role == Roles.NewLine || arg.Role == Roles.Whitespace || arg.Role == Roles.Comment); - } - - public override object VisitNamespaceDeclaration (NamespaceDeclaration namespaceDeclaration, object data) - { - AddUsings (namespaceDeclaration); - if (!namespaceDeclaration.RBraceToken.IsNull && namespaceDeclaration.LBraceToken.StartLocation.Line != namespaceDeclaration.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (namespaceDeclaration.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (namespaceDeclaration.RBraceToken)), FoldType.Undefined)); - return base.VisitNamespaceDeclaration (namespaceDeclaration, data); - } - - public override object VisitTypeDeclaration (TypeDeclaration typeDeclaration, object data) - { - if (!typeDeclaration.RBraceToken.IsNull && typeDeclaration.LBraceToken.StartLocation.Line != typeDeclaration.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (typeDeclaration.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (typeDeclaration.RBraceToken)), FoldType.Type)); - return base.VisitTypeDeclaration (typeDeclaration, data); - } - - public override object VisitMethodDeclaration (MethodDeclaration methodDeclaration, object data) - { - if (!methodDeclaration.Body.IsNull && methodDeclaration.Body.LBraceToken.StartLocation.Line != methodDeclaration.Body.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (methodDeclaration.Body.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (methodDeclaration.Body.RBraceToken)), FoldType.Member)); - return base.VisitMethodDeclaration (methodDeclaration, data); - } - - public override object VisitConstructorDeclaration (ConstructorDeclaration constructorDeclaration, object data) - { - if (!constructorDeclaration.Body.IsNull && constructorDeclaration.Body.LBraceToken.StartLocation.Line != constructorDeclaration.Body.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (constructorDeclaration.Body.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (constructorDeclaration.Body.RBraceToken)), FoldType.Member)); - return base.VisitConstructorDeclaration (constructorDeclaration, data); - } - - public override object VisitDestructorDeclaration (DestructorDeclaration destructorDeclaration, object data) - { - if (!destructorDeclaration.Body.IsNull && destructorDeclaration.Body.LBraceToken.StartLocation.Line != destructorDeclaration.Body.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (destructorDeclaration.Body.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (destructorDeclaration.Body.RBraceToken)), FoldType.Member)); - return base.VisitDestructorDeclaration (destructorDeclaration, data); - } - - public override object VisitOperatorDeclaration (OperatorDeclaration operatorDeclaration, object data) - { - if (!operatorDeclaration.Body.IsNull && operatorDeclaration.Body.LBraceToken.StartLocation.Line != operatorDeclaration.Body.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (operatorDeclaration.Body.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (operatorDeclaration.Body.RBraceToken)), FoldType.Member)); - return base.VisitOperatorDeclaration (operatorDeclaration, data); - } - - public override object VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration, object data) - { - if (!propertyDeclaration.LBraceToken.IsNull && propertyDeclaration.LBraceToken.StartLocation.Line != propertyDeclaration.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (propertyDeclaration.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (propertyDeclaration.RBraceToken)), FoldType.Member)); - return base.VisitPropertyDeclaration (propertyDeclaration, data); - } - - public override object VisitIndexerDeclaration (IndexerDeclaration indexerDeclaration, object data) - { - if (!indexerDeclaration.LBraceToken.IsNull && indexerDeclaration.LBraceToken.StartLocation.Line != indexerDeclaration.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (indexerDeclaration.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (indexerDeclaration.RBraceToken)), FoldType.Member)); - return base.VisitIndexerDeclaration (indexerDeclaration, data); - } - - public override object VisitCustomEventDeclaration (CustomEventDeclaration eventDeclaration, object data) - { - if (!eventDeclaration.LBraceToken.IsNull && eventDeclaration.LBraceToken.StartLocation.Line != eventDeclaration.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (eventDeclaration.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (eventDeclaration.RBraceToken)), FoldType.Member)); - return base.VisitCustomEventDeclaration (eventDeclaration, data); - } - - public override object VisitSwitchStatement (SwitchStatement switchStatement, object data) - { - if (!switchStatement.RBraceToken.IsNull && switchStatement.LBraceToken.StartLocation.Line != switchStatement.RBraceToken.StartLocation.Line) - Foldings.Add (new FoldingRegion (new DomRegion (switchStatement.LBraceToken.GetPrevNode (LastToken).EndLocation, CorrectEnd (switchStatement.RBraceToken)), FoldType.Member)); - return base.VisitSwitchStatement (switchStatement, data); - } - - public override object VisitBlockStatement (BlockStatement blockStatement, object data) - { - if (!(blockStatement.Parent is EntityDeclaration) && blockStatement.EndLocation.Line - blockStatement.StartLocation.Line > 2) { - Foldings.Add (new FoldingRegion (new DomRegion (blockStatement.GetPrevNode (LastToken).EndLocation, CorrectEnd (blockStatement.RBraceToken)), FoldType.Undefined)); - } - - return base.VisitBlockStatement (blockStatement, data); - } - } - - static IEnumerable<Tag> GetSemanticTags (SyntaxTree unit) - { - var visitor = new SemanticTagVisitor (); - unit.AcceptVisitor (visitor); - foreach (var fold in visitor.Tags) - yield return fold; - } - - public class SemanticTagVisitor : DepthFirstAstVisitor - { - public List<Tag> Tags = new List<Tag> (); - - public override void VisitThrowStatement (ThrowStatement throwStatement) - { - var createExpression = throwStatement.Expression as ObjectCreateExpression; - if (createExpression == null) - return; - var st = createExpression.Type as SimpleType; - var mt = createExpression.Type as MemberType; - if (st != null && st.Identifier == "NotImplementedException" || - mt != null && mt.MemberName == "NotImplementedException" && mt.Target.ToString () == "System") { - - if (createExpression.Arguments.Any ()) { - Tags.Add (new Tag ("High", GettextCatalog.GetString ("NotImplementedException({0}) thrown.", createExpression.Arguments.First ().ToString ()), new DomRegion (throwStatement.StartLocation, throwStatement.EndLocation))); - } else { - Tags.Add (new Tag ("High", GettextCatalog.GetString ("NotImplementedException thrown."), new DomRegion (throwStatement.StartLocation, throwStatement.EndLocation))); + if (curDoc != null) { + try { + var model = curDoc.GetSemanticModelAsync (cancellationToken).Result; + unit = model.SyntaxTree; + result.Ast = model; + } catch (AggregateException ae) { + ae.Flatten ().Handle (x => x is OperationCanceledException); + return Task.FromResult ((ParsedDocument)result); + } catch (OperationCanceledException) { + return Task.FromResult ((ParsedDocument)result); + } catch (Exception e) { + LoggingService.LogError ("Error while getting the semantic model for " + fileName, e); } } } - } - void VisitMcsUnit () - { - } - - void VisitComment (ParsedDocument result, SpecialsBag.Comment comment, string[] tagComments) - { - var cmt = new MonoDevelop.Ide.TypeSystem.Comment (comment.Content); - cmt.CommentStartsLine = comment.StartsLine; - switch (comment.CommentType) { - case SpecialsBag.CommentType.Multi: - cmt.CommentType = MonoDevelop.Ide.TypeSystem.CommentType.Block; - cmt.OpenTag = "/*"; - cmt.ClosingTag = "*/"; - break; - case SpecialsBag.CommentType.Single: - cmt.CommentType = MonoDevelop.Ide.TypeSystem.CommentType.SingleLine; - cmt.OpenTag = "//"; - break; - case SpecialsBag.CommentType.Documentation: - cmt.CommentType = MonoDevelop.Ide.TypeSystem.CommentType.Documentation; - cmt.IsDocumentation = true; - cmt.OpenTag = "///"; - break; - } - cmt.Region = new DomRegion (comment.Line, comment.Col, comment.EndLine, comment.EndCol); - result.Comments.Add (cmt); - var trimmedContent = comment.Content.TrimStart (); - foreach (string tag in tagComments) { - if (!trimmedContent.StartsWith (tag)) - continue; - result.Add (new Tag (tag, comment.Content, cmt.Region)); - } - } - - Stack<SpecialsBag.PreProcessorDirective> regions = new Stack<SpecialsBag.PreProcessorDirective> (); - Stack<SpecialsBag.PreProcessorDirective> ifBlocks = new Stack<SpecialsBag.PreProcessorDirective> (); - List<SpecialsBag.PreProcessorDirective> elifBlocks = new List<SpecialsBag.PreProcessorDirective> (); - SpecialsBag.PreProcessorDirective elseBlock = null; - - Stack<ConditionalRegion> conditionalRegions = new Stack<ConditionalRegion> (); - ConditionalRegion ConditionalRegion { - get { - return conditionalRegions.Count > 0 ? conditionalRegions.Peek () : null; - } - } + if (unit == null) { + unit = CSharpSyntaxTree.ParseText (SourceText.From (options.Content.Text), compilerArguments, fileName); + } - void CloseConditionBlock (TextLocation loc) - { - if (ConditionalRegion == null || ConditionalRegion.ConditionBlocks.Count == 0 || !ConditionalRegion.ConditionBlocks[ConditionalRegion.ConditionBlocks.Count - 1].End.IsEmpty) - return; - ConditionalRegion.ConditionBlocks[ConditionalRegion.ConditionBlocks.Count - 1].End = loc; - } + result.Unit = unit; - void AddCurRegion (ParsedDocument result, int line, int col) - { - if (ConditionalRegion == null) - return; - ConditionalRegion.End = new TextLocation (line, col); - result.Add (ConditionalRegion); - conditionalRegions.Pop (); - } - - void VisitPreprocessorDirective (ParsedDocument result, SpecialsBag.PreProcessorDirective directive) - { - TextLocation loc = new TextLocation (directive.Line, directive.Col); - switch (directive.Cmd) { - case Tokenizer.PreprocessorDirective.If: - conditionalRegions.Push (new ConditionalRegion (directive.Arg)); - ifBlocks.Push (directive); - ConditionalRegion.Start = loc; - break; - case Tokenizer.PreprocessorDirective.Elif: - CloseConditionBlock (new TextLocation (directive.EndLine, directive.EndCol)); - if (ConditionalRegion != null) - ConditionalRegion.ConditionBlocks.Add (new ConditionBlock (directive.Arg, loc)); - break; - case Tokenizer.PreprocessorDirective.Else: - CloseConditionBlock (new TextLocation (directive.EndLine, directive.EndCol)); - if (ConditionalRegion != null) - ConditionalRegion.ElseBlock = new DomRegion (loc, TextLocation.Empty); - break; - case Tokenizer.PreprocessorDirective.Endif: - TextLocation endLoc = new TextLocation (directive.EndLine, directive.EndCol); - CloseConditionBlock (endLoc); - if (ConditionalRegion != null && !ConditionalRegion.ElseBlock.Begin.IsEmpty) - ConditionalRegion.ElseBlock = new DomRegion (ConditionalRegion.ElseBlock.Begin, endLoc); - AddCurRegion (result, directive.EndLine, directive.EndCol); - if (ifBlocks.Count > 0) { - var ifBlock = ifBlocks.Pop (); - var ifRegion = new DomRegion (ifBlock.Line, ifBlock.Col, directive.EndLine, directive.EndCol); - result.Add (new FoldingRegion ("#if " + ifBlock.Arg.Trim (), ifRegion, FoldType.UserRegion, false)); - foreach (var d in elifBlocks) { - var elIlfRegion = new DomRegion (d.Line, d.Col, directive.EndLine, directive.EndCol); - result.Add (new FoldingRegion ("#elif " + ifBlock.Arg.Trim (), elIlfRegion, FoldType.UserRegion, false)); - } - if (elseBlock != null) { - var elseBlockRegion = new DomRegion (elseBlock.Line, elseBlock.Col, elseBlock.Line, elseBlock.Col); - result.Add (new FoldingRegion ("#else", elseBlockRegion, FoldType.UserRegion, false)); - } - } - elseBlock = null; - break; - case Tokenizer.PreprocessorDirective.Define: - result.Add (new PreProcessorDefine (directive.Arg, loc)); - break; - case Tokenizer.PreprocessorDirective.Region: - regions.Push (directive); - break; - case Tokenizer.PreprocessorDirective.Endregion: - if (regions.Count > 0) { - var start = regions.Pop (); - DomRegion dr = new DomRegion (start.Line, start.Col, directive.EndLine, directive.EndCol); - result.Add (new FoldingRegion (start.Arg, dr, FoldType.UserRegion, true)); - } - break; + DateTime time; + try { + time = System.IO.File.GetLastWriteTimeUtc (fileName); + } catch (Exception) { + time = DateTime.UtcNow; } + result.LastWriteTimeUtc = time; + return Task.FromResult ((ParsedDocument)result); } - public static ICSharpCode.NRefactory.CSharp.CompilerSettings GetCompilerArguments (MonoDevelop.Projects.Project project) + public static CSharpParseOptions GetCompilerArguments (MonoDevelop.Projects.Project project) { - var compilerArguments = new ICSharpCode.NRefactory.CSharp.CompilerSettings (); + var compilerArguments = new CSharpParseOptions (); // compilerArguments.TabSize = 1; if (project == null || MonoDevelop.Ide.IdeApp.Workspace == null) { - compilerArguments.AllowUnsafeBlocks = true; + // compilerArguments.AllowUnsafeBlocks = true; return compilerArguments; } @@ -401,69 +116,54 @@ namespace MonoDevelop.CSharp.Parser if (configuration == null) return compilerArguments; - foreach (var sym in configuration.GetDefineSymbols ()) - compilerArguments.ConditionalSymbols.Add (sym); + compilerArguments = compilerArguments.WithPreprocessorSymbols (configuration.GetDefineSymbols ()); var par = configuration.CompilationParameters as CSharpCompilerParameters; if (par == null) return compilerArguments; - - compilerArguments.AllowUnsafeBlocks = par.UnsafeCode; - compilerArguments.LanguageVersion = ConvertLanguageVersion (par.LangVersion); - compilerArguments.CheckForOverflow = par.GenerateOverflowChecks; - compilerArguments.WarningLevel = par.WarningLevel; - compilerArguments.TreatWarningsAsErrors = par.TreatWarningsAsErrors; - if (!string.IsNullOrEmpty (par.NoWarnings)) { - foreach (var warning in par.NoWarnings.Split (';', ',', ' ', '\t')) { - int w; - try { - w = int.Parse (warning); - } catch (Exception) { - continue; - } - compilerArguments.DisabledWarnings.Add (w); - } - } + + + // compilerArguments.AllowUnsafeBlocks = par.UnsafeCode; + compilerArguments = compilerArguments.WithLanguageVersion (ConvertLanguageVersion (par.LangVersion)); +// compilerArguments.CheckForOverflow = par.GenerateOverflowChecks; + +// compilerArguments.WarningLevel = par.WarningLevel; +// compilerArguments.TreatWarningsAsErrors = par.TreatWarningsAsErrors; +// if (!string.IsNullOrEmpty (par.NoWarnings)) { +// foreach (var warning in par.NoWarnings.Split (';', ',', ' ', '\t')) { +// int w; +// try { +// w = int.Parse (warning); +// } catch (Exception) { +// continue; +// } +// compilerArguments.DisabledWarnings.Add (w); +// } +// } return compilerArguments; } - internal static Version ConvertLanguageVersion (LangVersion ver) + internal static Microsoft.CodeAnalysis.CSharp.LanguageVersion ConvertLanguageVersion (LangVersion ver) { switch (ver) { case LangVersion.ISO_1: - return new Version (1, 0, 0, 0); + return Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp1; case LangVersion.ISO_2: - return new Version (2, 0, 0, 0); + return Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp2; case LangVersion.Version3: - return new Version (3, 0, 0, 0); + return Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp3; case LangVersion.Version4: - return new Version (4, 0, 0, 0); + return Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp4; case LangVersion.Version5: - return new Version (5, 0, 0, 0); + return Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp5; case LangVersion.Version6: - return new Version (6, 0, 0, 0); + return Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp6; case LangVersion.Default: break; } - return new Version (6, 0, 0, 0);; + return Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp6; } } - - static class FoldingUtils - { - public static IEnumerable<FoldingRegion> ToFolds (this IEnumerable<ConditionalRegion> conditionalRegions) - { - foreach (ConditionalRegion region in conditionalRegions) { - yield return new FoldingRegion ("#if " + region.Flag, region.Region, FoldType.ConditionalDefine); - foreach (ConditionBlock block in region.ConditionBlocks) { - yield return new FoldingRegion ("#elif " + block.Flag, block.Region, - FoldType.ConditionalDefine); - } - if (!region.ElseBlock.IsEmpty) - yield return new FoldingRegion ("#else", region.ElseBlock, FoldType.ConditionalDefine); - } - } - } } |