20 changed files with 635 additions and 216 deletions
@ -0,0 +1,112 @@
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// 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 System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
class InsertMissingTokensDecorator : DecoratingTokenWriter |
||||
{ |
||||
readonly Stack<List<AstNode>> nodes = new Stack<List<AstNode>>(); |
||||
List<AstNode> currentList; |
||||
readonly ILocatable locationProvider; |
||||
|
||||
public InsertMissingTokensDecorator(TokenWriter writer, ILocatable locationProvider) |
||||
: base(writer) |
||||
{ |
||||
this.locationProvider = locationProvider; |
||||
currentList = new List<AstNode>(); |
||||
} |
||||
|
||||
public override void StartNode(AstNode node) |
||||
{ |
||||
currentList.Add(node); |
||||
nodes.Push(currentList); |
||||
currentList = new List<AstNode>(); |
||||
base.StartNode(node); |
||||
} |
||||
|
||||
public override void EndNode(AstNode node) |
||||
{ |
||||
System.Diagnostics.Debug.Assert(currentList != null); |
||||
foreach (var removable in node.Children.Where(n => n is CSharpTokenNode)) { |
||||
removable.Remove(); |
||||
} |
||||
foreach (var child in currentList) { |
||||
System.Diagnostics.Debug.Assert(child.Parent == null || node == child.Parent); |
||||
child.Remove(); |
||||
node.AddChildWithExistingRole(child); |
||||
} |
||||
currentList = nodes.Pop(); |
||||
base.EndNode(node); |
||||
} |
||||
|
||||
public override void WriteToken(Role role, string token) |
||||
{ |
||||
CSharpTokenNode t = new CSharpTokenNode(locationProvider.Location, (TokenRole)role); |
||||
currentList.Add(t); |
||||
base.WriteToken(role, token); |
||||
} |
||||
|
||||
public override void WriteKeyword(Role role, string keyword) |
||||
{ |
||||
TextLocation start = locationProvider.Location; |
||||
CSharpTokenNode t = null; |
||||
if (role is TokenRole) |
||||
t = new CSharpTokenNode(start, (TokenRole)role); |
||||
else if (role == EntityDeclaration.ModifierRole) |
||||
t = new CSharpModifierToken(start, CSharpModifierToken.GetModifierValue(keyword)); |
||||
else if (keyword == "this") { |
||||
ThisReferenceExpression node = nodes.Peek().LastOrDefault() as ThisReferenceExpression; |
||||
if (node != null) |
||||
node.Location = start; |
||||
} |
||||
if (t != null) currentList.Add(t); |
||||
base.WriteKeyword(role, keyword); |
||||
} |
||||
|
||||
public override void WriteIdentifier(Identifier identifier) |
||||
{ |
||||
identifier.SetStartLocation(locationProvider.Location); |
||||
currentList.Add(identifier); |
||||
base.WriteIdentifier(identifier); |
||||
} |
||||
|
||||
public override void WritePrimitiveValue(object value, string literalValue = null) |
||||
{ |
||||
Expression node = nodes.Peek().LastOrDefault() as Expression; |
||||
if (node is PrimitiveExpression) { |
||||
((PrimitiveExpression)node).SetStartLocation(locationProvider.Location); |
||||
} |
||||
if (node is NullReferenceExpression) { |
||||
((NullReferenceExpression)node).SetStartLocation(locationProvider.Location); |
||||
} |
||||
base.WritePrimitiveValue(value, literalValue); |
||||
} |
||||
|
||||
public override void WritePrimitiveType(string type) |
||||
{ |
||||
PrimitiveType node = nodes.Peek().LastOrDefault() as PrimitiveType; |
||||
if (node != null) |
||||
node.SetStartLocation(locationProvider.Location); |
||||
base.WritePrimitiveType(type); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,87 @@
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using ICSharpCode.NRefactory.Editor; |
||||
using NUnit.Framework; |
||||
using ICSharpCode.NRefactory.CSharp.Parser; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp |
||||
{ |
||||
/// <summary>
|
||||
/// Description of InsertMissingTokensDecoratorTests.
|
||||
/// </summary>
|
||||
[TestFixture] |
||||
public class InsertMissingTokensDecoratorTests |
||||
{ |
||||
string[] fileNames; |
||||
|
||||
[TestFixtureSetUp] |
||||
public void SetUp() |
||||
{ |
||||
string path = Path.GetFullPath (Path.Combine ("..", "..")); |
||||
if (!File.Exists(Path.Combine(path, "NRefactory.sln"))) |
||||
throw new InvalidOperationException("Test cannot find the NRefactory source code in " + path); |
||||
fileNames = Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories); |
||||
} |
||||
|
||||
static void RemoveTokens(AstNode node) |
||||
{ |
||||
foreach (var child in node.Descendants) { |
||||
if (child is CSharpTokenNode && !(child is CSharpModifierToken)) |
||||
child.Remove(); |
||||
else if (child.NodeType == NodeType.Whitespace) |
||||
child.Remove(); |
||||
} |
||||
} |
||||
|
||||
void AssertOutput(AstNode node) |
||||
{ |
||||
RemoveTokens(node); |
||||
StringWriter w = new StringWriter(); |
||||
w.NewLine = "\n"; |
||||
node.AcceptVisitor(new CSharpOutputVisitor(TokenWriter.CreateWriterThatSetsLocationsInAST(w), FormattingOptionsFactory.CreateSharpDevelop())); |
||||
var doc = new ReadOnlyDocument(w.ToString()); |
||||
ConsistencyChecker.CheckMissingTokens(node, "test.cs", doc); |
||||
ConsistencyChecker.CheckPositionConsistency(node, "test.cs", doc); |
||||
} |
||||
|
||||
[Test] |
||||
public void SimpleClass() |
||||
{ |
||||
var code = @"class Test
|
||||
{ |
||||
} |
||||
";
|
||||
var unit = SyntaxTree.Parse(code); |
||||
AssertOutput(unit); |
||||
} |
||||
|
||||
[Test] |
||||
public void SimpleMethod() |
||||
{ |
||||
var code = @"class Test
|
||||
{ |
||||
void A () |
||||
{ |
||||
} |
||||
} |
||||
";
|
||||
var unit = SyntaxTree.Parse(code); |
||||
AssertOutput(unit); |
||||
} |
||||
|
||||
[Test] |
||||
public void SelfTest() |
||||
{ |
||||
foreach (var file in fileNames) { |
||||
Console.WriteLine("processing {0}...", file); |
||||
var node = SyntaxTree.Parse(File.ReadAllText(file), file); |
||||
AssertOutput(node); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.IO; |
||||
using ICSharpCode.NRefactory.Editor; |
||||
using NUnit.Framework; |
||||
|
||||
namespace ICSharpCode.NRefactory.CSharp.Parser |
||||
{ |
||||
/// <summary>
|
||||
/// Provides utilities to check whether positions and/or tokens in an AST are valid.
|
||||
/// </summary>
|
||||
public static class ConsistencyChecker |
||||
{ |
||||
static void PrintNode (AstNode node) |
||||
{ |
||||
Console.WriteLine ("Parent:" + node.GetType ()); |
||||
Console.WriteLine ("Children:"); |
||||
foreach (var c in node.Children) |
||||
Console.WriteLine (c.GetType () +" at:"+ c.StartLocation +"-"+ c.EndLocation + " Role: "+ c.Role); |
||||
Console.WriteLine ("----"); |
||||
} |
||||
|
||||
public static void CheckPositionConsistency (AstNode node, string currentFileName, IDocument currentDocument = null) |
||||
{ |
||||
if (currentDocument == null) |
||||
currentDocument = new ReadOnlyDocument(File.ReadAllText(currentFileName)); |
||||
string comment = "(" + node.GetType ().Name + " at " + node.StartLocation + " in " + currentFileName + ")"; |
||||
var pred = node.StartLocation <= node.EndLocation; |
||||
if (!pred) |
||||
PrintNode (node); |
||||
Assert.IsTrue(pred, "StartLocation must be before EndLocation " + comment); |
||||
var prevNodeEnd = node.StartLocation; |
||||
var prevNode = node; |
||||
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { |
||||
bool assertion = child.StartLocation >= prevNodeEnd; |
||||
if (!assertion) { |
||||
PrintNode (prevNode); |
||||
PrintNode (node); |
||||
} |
||||
Assert.IsTrue(assertion, currentFileName + ": Child " + child.GetType () +" (" + child.StartLocation + ")" +" must start after previous sibling " + prevNode.GetType () + "(" + prevNode.StartLocation + ")"); |
||||
CheckPositionConsistency(child, currentFileName, currentDocument); |
||||
prevNodeEnd = child.EndLocation; |
||||
prevNode = child; |
||||
} |
||||
Assert.IsTrue(prevNodeEnd <= node.EndLocation, "Last child must end before parent node ends " + comment); |
||||
} |
||||
|
||||
public static void CheckMissingTokens(AstNode node, string currentFileName, IDocument currentDocument = null) |
||||
{ |
||||
if (currentDocument == null) |
||||
currentDocument = new ReadOnlyDocument(File.ReadAllText(currentFileName)); |
||||
if (node is CSharpTokenNode) { |
||||
Assert.IsNull(node.FirstChild, "Token nodes should not have children"); |
||||
} else { |
||||
var prevNodeEnd = node.StartLocation; |
||||
var prevNode = node; |
||||
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { |
||||
CheckWhitespace(prevNode, prevNodeEnd, child, child.StartLocation, currentFileName, currentDocument); |
||||
CheckMissingTokens(child, currentFileName, currentDocument); |
||||
prevNode = child; |
||||
prevNodeEnd = child.EndLocation; |
||||
} |
||||
CheckWhitespace(prevNode, prevNodeEnd, node, node.EndLocation, currentFileName, currentDocument); |
||||
} |
||||
} |
||||
|
||||
static void CheckWhitespace(AstNode startNode, TextLocation whitespaceStart, AstNode endNode, TextLocation whitespaceEnd, string currentFileName, IDocument currentDocument) |
||||
{ |
||||
Assert.Greater(whitespaceStart.Line, 0); |
||||
Assert.Greater(whitespaceStart.Column, 0); |
||||
Assert.Greater(whitespaceEnd.Line, 0); |
||||
Assert.Greater(whitespaceEnd.Column, 0); |
||||
if (whitespaceStart == whitespaceEnd || startNode == endNode) |
||||
return; |
||||
int start = currentDocument.GetOffset(whitespaceStart.Line, whitespaceStart.Column); |
||||
int end = currentDocument.GetOffset(whitespaceEnd.Line, whitespaceEnd.Column); |
||||
string text = currentDocument.GetText(start, end - start); |
||||
bool assertion = string.IsNullOrWhiteSpace(text); |
||||
if (!assertion) { |
||||
if (startNode.Parent != endNode.Parent) |
||||
PrintNode (startNode.Parent); |
||||
PrintNode (endNode.Parent); |
||||
} |
||||
Assert.IsTrue(assertion, "Expected whitespace between " + startNode.GetType () +":" + whitespaceStart + " and " + endNode.GetType () + ":" + whitespaceEnd |
||||
+ ", but got '" + text + "' (in " + currentFileName + " parent:" + startNode.Parent.GetType () +")"); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue