diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs index 8d649ca1e2..c2e76dfffc 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/AbstractLexer.cs @@ -63,6 +63,7 @@ namespace ICSharpCode.NRefactory.Parser if ((val == '\r' && reader.Peek() != '\n') || val == '\n') { ++line; col = 1; + LineBreak (); } return val; } @@ -230,19 +231,30 @@ namespace ICSharpCode.NRefactory.Parser errors.Error(line, col, String.Format("Invalid hex number '" + digit + "'")); return 0; } - + protected Location lastLineEnd = new Location (1, 1); + protected Location curLineEnd = new Location (1, 1); + protected void LineBreak () + { + lastLineEnd = curLineEnd; + curLineEnd = new Location (col - 1, line); + } protected bool HandleLineEnd(char ch) { // Handle MS-DOS or MacOS line ends. if (ch == '\r') { if (reader.Peek() == '\n') { // MS-DOS line end '\r\n' - ReaderRead(); + ReaderRead(); // LineBreak (); called by ReaderRead (); return true; } else { // assume MacOS line end which is '\r' + LineBreak (); return true; } } - return ch == '\n'; + if (ch == '\n') { + LineBreak (); + return true; + } + return false; } protected void SkipToEndOfLine() diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/ConditionalCompilation.cs b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/ConditionalCompilation.cs index 3b45a985c3..a4c9b92548 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/ConditionalCompilation.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/ConditionalCompilation.cs @@ -12,7 +12,7 @@ using ICSharpCode.NRefactory.Visitors; namespace ICSharpCode.NRefactory.Parser.CSharp { - sealed class ConditionalCompilation : AbstractAstVisitor + public sealed class ConditionalCompilation : AbstractAstVisitor { static readonly object SymbolDefined = new object(); Dictionary symbols = new Dictionary(); diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs index 0e356eb2da..63a85342d3 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs @@ -15,6 +15,8 @@ namespace ICSharpCode.NRefactory.Parser.CSharp { internal sealed class Lexer : AbstractLexer { + bool isAtLineBegin = true; + public Lexer(TextReader reader) : base(reader) { } @@ -24,7 +26,10 @@ namespace ICSharpCode.NRefactory.Parser.CSharp int nextChar; char ch; bool hadLineEnd = false; - if (Line == 1 && Col == 1) hadLineEnd = true; // beginning of document + if (Line == 1 && Col == 1) { + isAtLineBegin = true; + hadLineEnd = true; // beginning of document + } while ((nextChar = ReaderRead()) != -1) { Token token; @@ -42,6 +47,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp } HandleLineEnd((char)nextChar); hadLineEnd = true; + isAtLineBegin = true; continue; case '/': int peek = ReaderPeek(); @@ -49,19 +55,24 @@ namespace ICSharpCode.NRefactory.Parser.CSharp ReadComment(); continue; } else { + isAtLineBegin = false; token = ReadOperator('/'); } break; case '#': ReadPreProcessingDirective(); + isAtLineBegin = false; continue; case '"': token = ReadString(); + isAtLineBegin = false; break; case '\'': token = ReadChar(); + isAtLineBegin = false; break; case '@': + isAtLineBegin = false; int next = ReaderRead(); if (next == -1) { errors.Error(Line, Col, String.Format("EOF after @")); @@ -82,7 +93,8 @@ namespace ICSharpCode.NRefactory.Parser.CSharp } } break; - default: + default: + isAtLineBegin = false; // non-ws chars are handled here ch = (char)nextChar; if (Char.IsLetter(ch) || ch == '_' || ch == '\\') { int x = Col - 1; // Col was incremented above, but we want the start of the identifier @@ -780,6 +792,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp switch (ReaderRead()) { case '*': ReadMultiLineComment(); + isAtLineBegin = false; break; case '/': if (ReaderPeek() == '/') { @@ -788,6 +801,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp } else { ReadSingleLineComment(CommentType.SingleLine); } + isAtLineBegin = true; break; default: errors.Error(Line, Col, String.Format("Error while reading comment")); @@ -820,7 +834,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp if (specialCommentHash.ContainsKey(tag)) { Location p = new Location(Col, Line); string comment = ch + ReadToEndOfLine(); - this.TagComments.Add(new TagComment(tag, comment, p, new Location(Col, Line))); + this.TagComments.Add(new TagComment(tag, comment, isAtLineBegin, p, new Location(Col, Line))); sb.Append(comment); break; } @@ -834,7 +848,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp if (this.SkipAllComments) { SkipToEndOfLine(); } else { - specialTracker.StartComment(commentType, new Location(Col, Line)); + specialTracker.StartComment(commentType, isAtLineBegin, new Location(Col, Line)); specialTracker.AddString(ReadCommentToEOL()); specialTracker.FinishComment(new Location(Col, Line)); } @@ -854,7 +868,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp } } } else { - specialTracker.StartComment(CommentType.Block, new Location(Col, Line)); + specialTracker.StartComment(CommentType.Block, isAtLineBegin, new Location(Col, Line)); // sc* = special comment handling (TO DO markers) string scTag = null; // is set to non-null value when we are inside a comment marker @@ -866,7 +880,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp if (HandleLineEnd(ch)) { if (scTag != null) { - this.TagComments.Add(new TagComment(scTag, scCurWord.ToString(), scStartLocation, new Location(Col, Line))); + this.TagComments.Add(new TagComment(scTag, scCurWord.ToString(), isAtLineBegin, scStartLocation, new Location(Col, Line))); scTag = null; } scCurWord.Length = 0; @@ -877,7 +891,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp // End of multiline comment reached ? if (ch == '*' && ReaderPeek() == '/') { if (scTag != null) { - this.TagComments.Add(new TagComment(scTag, scCurWord.ToString(), scStartLocation, new Location(Col, Line))); + this.TagComments.Add(new TagComment(scTag, scCurWord.ToString(), isAtLineBegin, scStartLocation, new Location(Col, Line))); } ReaderRead(); specialTracker.FinishComment(new Location(Col, Line)); @@ -919,13 +933,16 @@ namespace ICSharpCode.NRefactory.Parser.CSharp lastToken = curToken; curToken = curToken.next; } + isAtLineBegin = true; int nextChar; while ((nextChar = ReaderRead()) != -1) { switch (nextChar) { case '{': + isAtLineBegin = false; braceCount++; break; case '}': + isAtLineBegin = false; if (--braceCount < 0) { curToken = new Token(Tokens.CloseCurlyBrace, Col - 1, Line); return; @@ -936,19 +953,24 @@ namespace ICSharpCode.NRefactory.Parser.CSharp if (peek == '/' || peek == '*') { ReadComment(); } + isAtLineBegin = false; break; case '#': ReadPreProcessingDirective(); + isAtLineBegin = false; break; case '"': ReadString(); + isAtLineBegin = false; break; case '\'': ReadChar(); + isAtLineBegin = false; break; case '\r': case '\n': HandleLineEnd((char)nextChar); + isAtLineBegin = true; break; case '@': int next = ReaderRead(); @@ -957,6 +979,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp } else if (next == '"') { ReadVerbatimString(); } + isAtLineBegin = false; break; } } @@ -1072,7 +1095,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp } SkipToEndOfLine(); // skip comment } - return new PreprocessingDirective(directive, null, start, endLocation) { Expression = expr }; + return new PreprocessingDirective(directive, null, start, endLocation) { Expression = expr, LastLineEnd = lastLineEnd }; } else { Location endLocation = new Location(Col, Line); string arg = ReadToEndOfLine(); @@ -1081,7 +1104,7 @@ namespace ICSharpCode.NRefactory.Parser.CSharp if (pos >= 0) arg = arg.Substring(0, pos); arg = arg.Trim(); - return new PreprocessingDirective(directive, arg, start, endLocation); + return new PreprocessingDirective(directive, arg, start, endLocation) { LastLineEnd = lastLineEnd }; } } diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/Special/Comment.cs b/src/Libraries/NRefactory/Project/Src/Lexer/Special/Comment.cs index 469b9d2884..42fe1a2a35 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/Special/Comment.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/Special/Comment.cs @@ -32,11 +32,21 @@ namespace ICSharpCode.NRefactory } } - public Comment(CommentType commentType, string comment, Location startPosition, Location endPosition) + /// + /// Is true, when the comment is at line start or only whitespaces + /// between line and comment start. + /// + public bool CommentStartsLine { + get; + set; + } + + public Comment(CommentType commentType, string comment, bool commentStartsLine, Location startPosition, Location endPosition) : base(startPosition, endPosition) { this.commentType = commentType; this.comment = comment; + this.CommentStartsLine = commentStartsLine; } public override string ToString() diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs b/src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs index 8f020bf180..e850446ed2 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/Special/PreProcessingDirective.cs @@ -128,6 +128,16 @@ namespace ICSharpCode.NRefactory set { expression = value ?? Ast.Expression.Null; } } + /// + /// The end position of the pre processor directive line. + /// May be != EndPosition. + /// + public Location LastLineEnd { + get; + set; + } + + public override string ToString() { return String.Format("[PreProcessingDirective: Cmd = {0}, Arg = {1}]", diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs b/src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs index 9fce36116b..826681f17f 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/Special/SpecialTracker.cs @@ -18,6 +18,7 @@ namespace ICSharpCode.NRefactory.Parser CommentType currentCommentType; StringBuilder sb = new StringBuilder(); Location startPosition; + bool commentStartsLine; public List CurrentSpecials { get { @@ -53,11 +54,12 @@ namespace ICSharpCode.NRefactory.Parser } // used for comment tracking - public void StartComment(CommentType commentType, Location startPosition) + public void StartComment(CommentType commentType, bool commentStartsLine, Location startPosition) { this.currentCommentType = commentType; this.startPosition = startPosition; this.sb.Length = 0; + this.commentStartsLine = commentStartsLine; } public void AddChar(char c) @@ -72,7 +74,7 @@ namespace ICSharpCode.NRefactory.Parser public void FinishComment(Location endPosition) { - currentSpecials.Add(new Comment(currentCommentType, sb.ToString(), startPosition, endPosition)); + currentSpecials.Add(new Comment(currentCommentType, sb.ToString(), commentStartsLine, startPosition, endPosition)); } } } diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/Special/TagComment.cs b/src/Libraries/NRefactory/Project/Src/Lexer/Special/TagComment.cs index fa625f35e7..a5a0be02c2 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/Special/TagComment.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/Special/TagComment.cs @@ -25,7 +25,7 @@ namespace ICSharpCode.NRefactory.Parser } } - public TagComment(string tag, string comment, Location startPosition, Location endPosition) : base(CommentType.SingleLine, comment, startPosition, endPosition) + public TagComment(string tag, string comment, bool commentStartsLine, Location startPosition, Location endPosition) : base(CommentType.SingleLine, comment, commentStartsLine, startPosition, endPosition) { this.tag = tag; } diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs index 5d13b5a3fa..2d93878bdb 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs @@ -15,6 +15,7 @@ namespace ICSharpCode.NRefactory.Parser.VB internal sealed class Lexer : AbstractLexer { bool lineEnd = true; + bool isAtLineBegin = false; // TODO: handle line begin, if neccessarry public Lexer(TextReader reader) : base(reader) { @@ -576,11 +577,11 @@ namespace ICSharpCode.NRefactory.Parser.VB if (missingApostrophes > 0) { if (ch == '\'' || ch == '\u2018' || ch == '\u2019') { if (--missingApostrophes == 0) { - specialTracker.StartComment(CommentType.Documentation, startPos); + specialTracker.StartComment(CommentType.Documentation, isAtLineBegin, startPos); sb.Length = 0; } } else { - specialTracker.StartComment(CommentType.SingleLine, startPos); + specialTracker.StartComment(CommentType.SingleLine, isAtLineBegin, startPos); missingApostrophes = 0; } } @@ -594,7 +595,7 @@ namespace ICSharpCode.NRefactory.Parser.VB if (specialCommentHash.ContainsKey(tag)) { Location p = new Location(Col, Line); string comment = ch + ReadToEndOfLine(); - this.TagComments.Add(new TagComment(tag, comment, p, new Location(Col, Line))); + this.TagComments.Add(new TagComment(tag, comment, isAtLineBegin, p, new Location(Col, Line))); sb.Append(comment); break; } @@ -602,7 +603,7 @@ namespace ICSharpCode.NRefactory.Parser.VB } } if (missingApostrophes > 0) { - specialTracker.StartComment(CommentType.SingleLine, startPos); + specialTracker.StartComment(CommentType.SingleLine, isAtLineBegin, startPos); } specialTracker.AddString(sb.ToString()); specialTracker.FinishComment(new Location(Col, Line)); diff --git a/src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs b/src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs index 7427b05f79..8f06117908 100644 --- a/src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs +++ b/src/Libraries/NRefactory/Project/Src/Parser/AbstractParser.cs @@ -63,6 +63,7 @@ namespace ICSharpCode.NRefactory.Parser public abstract void Parse(); + public abstract TypeReference ParseTypeReference (); public abstract Expression ParseExpression(); public abstract BlockStatement ParseBlock(); public abstract List ParseTypeMembers(); diff --git a/src/Libraries/NRefactory/Project/Src/Parser/CSharp/CSharpParser.cs b/src/Libraries/NRefactory/Project/Src/Parser/CSharp/CSharpParser.cs index 5265841589..a56142a7a9 100644 --- a/src/Libraries/NRefactory/Project/Src/Parser/CSharp/CSharpParser.cs +++ b/src/Libraries/NRefactory/Project/Src/Parser/CSharp/CSharpParser.cs @@ -56,6 +56,14 @@ namespace ICSharpCode.NRefactory.Parser.CSharp compilationUnit.AcceptVisitor(new SetParentVisitor(), null); } + public override TypeReference ParseTypeReference () + { + lexer.NextToken(); + TypeReference type; + Type(out type); + return type; + } + public override Expression ParseExpression() { lexer.NextToken(); diff --git a/src/Libraries/NRefactory/Project/Src/Parser/IParser.cs b/src/Libraries/NRefactory/Project/Src/Parser/IParser.cs index aa93957246..527bac4825 100644 --- a/src/Libraries/NRefactory/Project/Src/Parser/IParser.cs +++ b/src/Libraries/NRefactory/Project/Src/Parser/IParser.cs @@ -35,6 +35,7 @@ namespace ICSharpCode.NRefactory void Parse(); Expression ParseExpression(); + TypeReference ParseTypeReference (); BlockStatement ParseBlock(); List ParseTypeMembers(); } diff --git a/src/Libraries/NRefactory/Project/Src/Parser/VBNet/VBNetParser.cs b/src/Libraries/NRefactory/Project/Src/Parser/VBNet/VBNetParser.cs index 3bdcdae99d..85f5d1a258 100644 --- a/src/Libraries/NRefactory/Project/Src/Parser/VBNet/VBNetParser.cs +++ b/src/Libraries/NRefactory/Project/Src/Parser/VBNet/VBNetParser.cs @@ -65,6 +65,12 @@ namespace ICSharpCode.NRefactory.Parser.VB compilationUnit.AcceptVisitor(new SetParentVisitor(), null); } + public override TypeReference ParseTypeReference () + { + // TODO + return null; + } + public override Expression ParseExpression() { lexer.NextToken(); diff --git a/src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs b/src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs index e017b00eb9..da779dcbf2 100644 --- a/src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs +++ b/src/Libraries/NRefactory/Project/Src/PrettyPrinter/AbstractOutputFormatter.cs @@ -89,6 +89,11 @@ namespace ICSharpCode.NRefactory.PrettyPrinter } } + public void Reset () + { + text.Length = 0; + } + public void Space() { text.Append(' '); diff --git a/src/Libraries/NRefactory/Project/Src/PrettyPrinter/CSharp/CSharpOutputVisitor.cs b/src/Libraries/NRefactory/Project/Src/PrettyPrinter/CSharp/CSharpOutputVisitor.cs index 74311d582c..30448a8068 100644 --- a/src/Libraries/NRefactory/Project/Src/PrettyPrinter/CSharp/CSharpOutputVisitor.cs +++ b/src/Libraries/NRefactory/Project/Src/PrettyPrinter/CSharp/CSharpOutputVisitor.cs @@ -2607,6 +2607,14 @@ namespace ICSharpCode.NRefactory.PrettyPrinter return node.AcceptVisitor(this, data); } + /// + /// Resets the output formatter, sets Text to string.Empty. + /// + public void Reset () + { + outputFormatter.Reset (); + } + public void AppendCommaSeparatedList(ICollection list) where T : class, INode { if (list != null) {