From 01ddddbf6a8813523384563aaefc057056965802 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 30 Jan 2005 20:51:50 +0000 Subject: [PATCH] Fixed Lexer bug (both C#/VB): OverflowException was thrown when dot was at end of expression. Fixed Lexer bug (C#): OverflowException was thrown when integer literal was at end of expression. Added unit tests for literals. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@77 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../NRefactory/Project/NRefactory.csproj | 4 +- .../Project/Src/Lexer/CSharp/Lexer.cs | 362 +++++++++--------- .../Project/Src/Lexer/VBNet/Lexer.cs | 12 +- .../Test/Lexer/CSharp/NumberLexerTest.cs | 78 ++++ .../Test/Lexer/VBNet/LiteralsTests.cs | 86 +++++ .../NRefactory/Test/NRefactoryTests.csproj | 318 +++++---------- .../Test/NRefactoryTests.csproj.user | 16 +- .../GlobalScope/TypeDeclarationTests.cs | 16 + .../Project/ICSharpCode.SharpDevelop.csproj | 2 +- .../IndexerInsightDataProvider.cs | 55 ++- .../MethodInsightDataProvider.cs | 7 +- src/Main/Base/Test/NRefactoryResolverTests.cs | 35 +- 12 files changed, 536 insertions(+), 455 deletions(-) create mode 100644 src/Libraries/NRefactory/Test/Lexer/CSharp/NumberLexerTest.cs create mode 100644 src/Libraries/NRefactory/Test/Lexer/VBNet/LiteralsTests.cs diff --git a/src/Libraries/NRefactory/Project/NRefactory.csproj b/src/Libraries/NRefactory/Project/NRefactory.csproj index 6cbb56fb14..4e787f1295 100644 --- a/src/Libraries/NRefactory/Project/NRefactory.csproj +++ b/src/Libraries/NRefactory/Project/NRefactory.csproj @@ -4,7 +4,7 @@ AnyCPU 8.0.41115 2.0 - {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195} + {3a9ae6aa-bc07-4a2f-972c-581e3ae2f195} NewProject ICSharpCode.NRefactory Library @@ -18,7 +18,7 @@ True - True + False False True TEST diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs index e55703e70a..1b81fedeff 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/CSharp/Lexer.cs @@ -129,65 +129,25 @@ namespace ICSharpCode.NRefactory.Parser.CSharp Token ReadDigit(char ch, int x) { - int y = line; - ++col; - sb.Length = 0; - sb.Append(ch); - string prefix = null; - string suffix = null; - - bool ishex = false; - bool isunsigned = false; - bool islong = false; - bool isfloat = false; - bool isdouble = false; - bool isdecimal = false; - - char peek = (char)reader.Peek(); - - if (ch == '.') { - isdouble = true; + unchecked { // prevent exception when Peek() = -1 is cast to char + int y = line; ++col; + sb.Length = 0; + sb.Append(ch); + string prefix = null; + string suffix = null; - while (Char.IsDigit((char)reader.Peek())) { // read decimal digits beyond the dot - sb.Append((char)reader.Read()); - ++col; - } - peek = (char)reader.Peek(); - } else if (ch == '0' && (peek == 'x' || peek == 'X')) { - reader.Read(); // skip 'x' - sb.Length = 0; // Remove '0' from 0x prefix from the stringvalue - ++col; - while (IsHex((char)reader.Peek())) { - sb.Append(Char.ToUpper((char)reader.Read())); - ++col; - } - ishex = true; - prefix = "0x"; - peek = (char)reader.Peek(); - } else { - while (Char.IsDigit((char)reader.Peek())) { - sb.Append((char)reader.Read()); - ++col; - } - peek = (char)reader.Peek(); - } - - Token nextToken = null; // if we accedently read a 'dot' - if (peek == '.') { // read floating point number - reader.Read(); - peek = (char)reader.Peek(); - if (!Char.IsDigit(peek)) { - nextToken = new Token(Tokens.Dot, x, y); - peek = '.'; - } else { - isdouble = true; // double is default - if (ishex) { - errors.Error(y, x, String.Format("No hexadecimal floating point values allowed")); - } - sb.Append('.'); - - + bool ishex = false; + bool isunsigned = false; + bool islong = false; + bool isfloat = false; + bool isdouble = false; + bool isdecimal = false; + + char peek = (char)reader.Peek(); + + if (ch == '.') { + isdouble = true; ++col; while (Char.IsDigit((char)reader.Peek())) { // read decimal digits beyond the dot @@ -195,147 +155,189 @@ namespace ICSharpCode.NRefactory.Parser.CSharp ++col; } peek = (char)reader.Peek(); - } - } - - if (peek == 'e' || peek == 'E') { // read exponent - isdouble = true; - sb.Append((char)reader.Read()); - ++col; - peek = (char)reader.Peek(); - if (peek == '-' || peek == '+') { - sb.Append((char)reader.Read()); - ++col; - } - while (Char.IsDigit((char)reader.Peek())) { // read exponent value - sb.Append((char)reader.Read()); + } else if (ch == '0' && (peek == 'x' || peek == 'X')) { + reader.Read(); // skip 'x' + sb.Length = 0; // Remove '0' from 0x prefix from the stringvalue ++col; + while (IsHex((char)reader.Peek())) { + sb.Append(Char.ToUpper((char)reader.Read())); + ++col; + } + ishex = true; + prefix = "0x"; + peek = (char)reader.Peek(); + } else { + while (Char.IsDigit((char)reader.Peek())) { + sb.Append((char)reader.Read()); + ++col; + } + peek = (char)reader.Peek(); } - isunsigned = true; - peek = (char)reader.Peek(); - } - - if (peek == 'f' || peek == 'F') { // float value - reader.Read(); - suffix = "f"; - ++col; - isfloat = true; - } else if (peek == 'd' || peek == 'D') { // double type suffix (obsolete, double is default) - reader.Read(); - suffix = "d"; - ++col; - isdouble = true; - } else if (peek == 'm' || peek == 'M') { // decimal value - reader.Read(); - suffix = "m"; - ++col; - isdecimal = true; - } else if (!isdouble) { - if (peek == 'u' || peek == 'U') { + + Token nextToken = null; // if we accedently read a 'dot' + if (peek == '.') { // read floating point number reader.Read(); - suffix = "u"; + peek = (char)reader.Peek(); + if (!Char.IsDigit(peek)) { + nextToken = new Token(Tokens.Dot, x, y); + peek = '.'; + } else { + isdouble = true; // double is default + if (ishex) { + errors.Error(y, x, String.Format("No hexadecimal floating point values allowed")); + } + sb.Append('.'); + + + ++col; + + while (Char.IsDigit((char)reader.Peek())) { // read decimal digits beyond the dot + sb.Append((char)reader.Read()); + ++col; + } + peek = (char)reader.Peek(); + } + } + + if (peek == 'e' || peek == 'E') { // read exponent + isdouble = true; + sb.Append((char)reader.Read()); ++col; + peek = (char)reader.Peek(); + if (peek == '-' || peek == '+') { + sb.Append((char)reader.Read()); + ++col; + } + while (Char.IsDigit((char)reader.Peek())) { // read exponent value + sb.Append((char)reader.Read()); + ++col; + } isunsigned = true; peek = (char)reader.Peek(); } - if (peek == 'l' || peek == 'L') { + if (peek == 'f' || peek == 'F') { // float value reader.Read(); - peek = (char)reader.Peek(); + suffix = "f"; + ++col; + isfloat = true; + } else if (peek == 'd' || peek == 'D') { // double type suffix (obsolete, double is default) + reader.Read(); + suffix = "d"; ++col; - islong = true; - if (!isunsigned && (peek == 'u' || peek == 'U')) { + isdouble = true; + } else if (peek == 'm' || peek == 'M') { // decimal value + reader.Read(); + suffix = "m"; + ++col; + isdecimal = true; + } else if (!isdouble) { + if (peek == 'u' || peek == 'U') { reader.Read(); - suffix = "lu"; + suffix = "u"; ++col; isunsigned = true; - } else { - suffix = isunsigned ? "ul" : "l"; + peek = (char)reader.Peek(); + } + + if (peek == 'l' || peek == 'L') { + reader.Read(); + peek = (char)reader.Peek(); + ++col; + islong = true; + if (!isunsigned && (peek == 'u' || peek == 'U')) { + reader.Read(); + suffix = "lu"; + ++col; + isunsigned = true; + } else { + suffix = isunsigned ? "ul" : "l"; + } } } - } - - string digit = sb.ToString(); - string stringValue = prefix + digit + suffix; - - if (isfloat) { - try { - return new Token(Tokens.Literal, x, y, stringValue, Single.Parse(digit, CultureInfo.InvariantCulture)); - } catch (Exception) { - errors.Error(y, x, String.Format("Can't parse float {0}", digit)); - return new Token(Tokens.Literal, x, y, stringValue, 0f); - } - } - if (isdecimal) { - try { - return new Token(Tokens.Literal, x, y, stringValue, Decimal.Parse(digit, CultureInfo.InvariantCulture)); - } catch (Exception) { - errors.Error(y, x, String.Format("Can't parse decimal {0}", digit)); - return new Token(Tokens.Literal, x, y, stringValue, 0m); - } - } - if (isdouble) { - try { - return new Token(Tokens.Literal, x, y, stringValue, Double.Parse(digit, CultureInfo.InvariantCulture)); - } catch (Exception) { - errors.Error(y, x, String.Format("Can't parse double {0}", digit)); - return new Token(Tokens.Literal, x, y, stringValue, 0d); - } - } - - // Try to determine a parsable value using ranges. (Quick hack!) - double d = 0; - if (!ishex && !Double.TryParse(digit,NumberStyles.Integer, null, out d)) { - errors.Error(y, x, String.Format("Can't parse integral constant {0}", digit)); - return new Token(Tokens.Literal, x, y, stringValue.ToString(), 0); - } - - if (d < long.MinValue || d > long.MaxValue) { - islong = true; - isunsigned = true; - } else if (d < uint.MinValue || d > uint.MaxValue) { - islong = true; - } else if (d < int.MinValue || d > int.MaxValue) { - isunsigned = true; - } - - Token token; - - if (islong) { - if (isunsigned) { + + string digit = sb.ToString(); + string stringValue = prefix + digit + suffix; + + if (isfloat) { try { - token = new Token(Tokens.Literal, x, y, stringValue, UInt64.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number)); + return new Token(Tokens.Literal, x, y, stringValue, Single.Parse(digit, CultureInfo.InvariantCulture)); } catch (Exception) { - errors.Error(y, x, String.Format("Can't parse unsigned long {0}", digit)); - token = new Token(Tokens.Literal, x, y, stringValue, 0UL); + errors.Error(y, x, String.Format("Can't parse float {0}", digit)); + return new Token(Tokens.Literal, x, y, stringValue, 0f); } - } else { + } + if (isdecimal) { try { - token = new Token(Tokens.Literal, x, y, stringValue, Int64.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number)); + return new Token(Tokens.Literal, x, y, stringValue, Decimal.Parse(digit, CultureInfo.InvariantCulture)); } catch (Exception) { - errors.Error(y, x, String.Format("Can't parse long {0}", digit)); - token = new Token(Tokens.Literal, x, y, stringValue, 0L); + errors.Error(y, x, String.Format("Can't parse decimal {0}", digit)); + return new Token(Tokens.Literal, x, y, stringValue, 0m); } } - } else { - if (isunsigned) { + if (isdouble) { try { - token = new Token(Tokens.Literal, x, y, stringValue, UInt32.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number)); + return new Token(Tokens.Literal, x, y, stringValue, Double.Parse(digit, CultureInfo.InvariantCulture)); } catch (Exception) { - errors.Error(y, x, String.Format("Can't parse unsigned int {0}", digit)); - token = new Token(Tokens.Literal, x, y, stringValue, 0U); + errors.Error(y, x, String.Format("Can't parse double {0}", digit)); + return new Token(Tokens.Literal, x, y, stringValue, 0d); + } + } + + // Try to determine a parsable value using ranges. (Quick hack!) + double d = 0; + if (!ishex && !Double.TryParse(digit,NumberStyles.Integer, null, out d)) { + errors.Error(y, x, String.Format("Can't parse integral constant {0}", digit)); + return new Token(Tokens.Literal, x, y, stringValue.ToString(), 0); + } + + if (d < long.MinValue || d > long.MaxValue) { + islong = true; + isunsigned = true; + } else if (d < uint.MinValue || d > uint.MaxValue) { + islong = true; + } else if (d < int.MinValue || d > int.MaxValue) { + isunsigned = true; + } + + Token token; + + if (islong) { + if (isunsigned) { + try { + token = new Token(Tokens.Literal, x, y, stringValue, UInt64.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number)); + } catch (Exception) { + errors.Error(y, x, String.Format("Can't parse unsigned long {0}", digit)); + token = new Token(Tokens.Literal, x, y, stringValue, 0UL); + } + } else { + try { + token = new Token(Tokens.Literal, x, y, stringValue, Int64.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number)); + } catch (Exception) { + errors.Error(y, x, String.Format("Can't parse long {0}", digit)); + token = new Token(Tokens.Literal, x, y, stringValue, 0L); + } } } else { - try { - token = new Token(Tokens.Literal, x, y, stringValue, Int32.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number)); - } catch (Exception) { - errors.Error(y, x, String.Format("Can't parse int {0}", digit)); - token = new Token(Tokens.Literal, x, y, stringValue, 0); + if (isunsigned) { + try { + token = new Token(Tokens.Literal, x, y, stringValue, UInt32.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number)); + } catch (Exception) { + errors.Error(y, x, String.Format("Can't parse unsigned int {0}", digit)); + token = new Token(Tokens.Literal, x, y, stringValue, 0U); + } + } else { + try { + token = new Token(Tokens.Literal, x, y, stringValue, Int32.Parse(digit, ishex ? NumberStyles.HexNumber : NumberStyles.Number)); + } catch (Exception) { + errors.Error(y, x, String.Format("Can't parse int {0}", digit)); + token = new Token(Tokens.Literal, x, y, stringValue, 0); + } } } + token.next = nextToken; + return token; } - token.next = nextToken; - return token; } Token ReadString() @@ -631,16 +633,14 @@ namespace ICSharpCode.NRefactory.Parser.CSharp switch (reader.Peek()) { case '<': reader.Read(); - if (reader.Peek() != -1) { - switch ((char)reader.Peek()) { - case '=': - reader.Read(); - col += 2; - return new Token(Tokens.ShiftLeftAssign, x, y); - default: - ++col; - break; - } + switch (reader.Peek()) { + case '=': + reader.Read(); + col += 2; + return new Token(Tokens.ShiftLeftAssign, x, y); + default: + ++col; + break; } return new Token(Tokens.ShiftLeft, x, y); case '=': @@ -686,7 +686,9 @@ namespace ICSharpCode.NRefactory.Parser.CSharp case ',': return new Token(Tokens.Comma, x, y); case '.': - if (Char.IsDigit((char)reader.Peek())) { + // Prevent OverflowException when Peek returns -1 + int tmp = reader.Peek(); + if (tmp > 0 && Char.IsDigit((char)tmp)) { col -= 2; return ReadDigit('.', col + 1); } diff --git a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs index 9f838ca9b7..8ed4cc7415 100644 --- a/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs +++ b/src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Lexer.cs @@ -220,7 +220,7 @@ namespace ICSharpCode.NRefactory.Parser.VB if (s.Length != 1) { errors.Error(line, col, String.Format("Chars can only have Length 1 ")); } - return new Token(Tokens.LiteralCharacter, x, y, '"' + s + "\"C", s[0].ToString()); + return new Token(Tokens.LiteralCharacter, x, y, '"' + s + "\"C", s[0]); } return new Token(Tokens.LiteralString, x, y, '"' + s + '"', s); } @@ -325,7 +325,7 @@ namespace ICSharpCode.NRefactory.Parser.VB } } - if (reader.Peek() != -1 && "%&SIL".IndexOf(Char.ToUpper((char)reader.Peek())) != -1 || ishex || isokt) { + if (reader.Peek() != -1 && ("%&SIL".IndexOf(Char.ToUpper((char)reader.Peek())) != -1 || ishex || isokt)) { ch = (char)reader.Peek(); sb.Append(ch); ch = Char.ToUpper(ch); @@ -370,9 +370,9 @@ namespace ICSharpCode.NRefactory.Parser.VB } } Token nextToken = null; // if we accedently read a 'dot' - if (!isdouble && reader.Peek() != -1 && reader.Peek() == '.') { // read floating point number + if (!isdouble && reader.Peek() == '.') { // read floating point number reader.Read(); - if (Char.IsDigit((char)reader.Peek())) { + if (reader.Peek() != -1 && Char.IsDigit((char)reader.Peek())) { isdouble = true; // double is default if (ishex || isokt) { errors.Error(line, col, String.Format("No hexadecimal or oktadecimal floating point values allowed")); @@ -662,7 +662,9 @@ namespace ICSharpCode.NRefactory.Parser.VB case ',': return new Token(Tokens.Comma, x, y); case '.': - if (Char.IsDigit((char)reader.Peek())) { + // Prevent OverflowException when Peek returns -1 + int tmp = reader.Peek(); + if (tmp > 0 && Char.IsDigit((char)tmp)) { --col; return ReadDigit('.', col); } diff --git a/src/Libraries/NRefactory/Test/Lexer/CSharp/NumberLexerTest.cs b/src/Libraries/NRefactory/Test/Lexer/CSharp/NumberLexerTest.cs new file mode 100644 index 0000000000..1e2a6bd482 --- /dev/null +++ b/src/Libraries/NRefactory/Test/Lexer/CSharp/NumberLexerTest.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using NUnit.Framework; +using ICSharpCode.NRefactory.Parser; +using ICSharpCode.NRefactory.Parser.CSharp; +using ICSharpCode.NRefactory.PrettyPrinter; + +namespace ICSharpCode.NRefactory.Tests.Lexer.CSharp +{ + [TestFixture] + public sealed class NumberLexerTests + { + ILexer GenerateLexer(StringReader sr) + { + return ParserFactory.CreateLexer(SupportedLanguages.CSharp, sr); + } + + Token GetSingleToken(string text) + { + ILexer lexer = GenerateLexer(new StringReader(text)); + Token t = lexer.NextToken(); + Assert.AreEqual(Tokens.EOF, lexer.NextToken().kind, "Tokens.EOF"); + return t; + } + + void CheckToken(string text, object val) + { + Token t = GetSingleToken(text); + Assert.AreEqual(Tokens.Literal, t.kind, "Tokens.Literal"); + Assert.IsNotNull(t.literalValue, "literalValue is null"); + Assert.AreEqual(val, t.literalValue, "literalValue"); + } + + [Test] + public void TestSingleDigit() + { + CheckToken("5", 5); + } + + [Test] + public void TestZero() + { + CheckToken("0", 0); + } + + [Test] + public void TestInteger() + { + CheckToken("66", 66); + } + + [Test] + public void TestOctalInteger() + { + CheckToken("077", 077); + CheckToken("056", 056); + } + + [Test] + public void TestHexadecimalInteger() + { + CheckToken("0x99F", 0x99F); + CheckToken("0xAB1f", 0xAB1f); + } + + [Test] + public void TestDouble() + { + CheckToken("1.0", 1.0); + } + + [Test] + public void TestFloat() + { + CheckToken("1.0f", 1.0f); + } + } +} diff --git a/src/Libraries/NRefactory/Test/Lexer/VBNet/LiteralsTests.cs b/src/Libraries/NRefactory/Test/Lexer/VBNet/LiteralsTests.cs new file mode 100644 index 0000000000..21c67efe3f --- /dev/null +++ b/src/Libraries/NRefactory/Test/Lexer/VBNet/LiteralsTests.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; +using NUnit.Framework; +using ICSharpCode.NRefactory.Parser; +using ICSharpCode.NRefactory.Parser.VB; +using ICSharpCode.NRefactory.PrettyPrinter; + +namespace ICSharpCode.NRefactory.Tests.Lexer.VB +{ + [TestFixture] + public sealed class LiteralsTests + { + ILexer GenerateLexer(StringReader sr) + { + return ParserFactory.CreateLexer(SupportedLanguages.VBNet, sr); + } + + Token GetSingleToken(string text) + { + ILexer lexer = GenerateLexer(new StringReader(text)); + Token t = lexer.NextToken(); + Assert.AreEqual(Tokens.EOL, lexer.NextToken().kind, "Tokens.EOL"); + Assert.AreEqual(Tokens.EOF, lexer.NextToken().kind, "Tokens.EOF"); + return t; + } + + void CheckToken(string text, int tokenType, object val) + { + Token t = GetSingleToken(text); + Assert.AreEqual(tokenType, t.kind, "Tokens.Literal"); + Assert.IsNotNull(t.literalValue, "literalValue is null"); + Assert.AreEqual(val, t.literalValue, "literalValue"); + } + + [Test] + public void TestSingleDigit() + { + CheckToken("5", Tokens.LiteralInteger, 5); + } + + [Test] + public void TestZero() + { + CheckToken("0", Tokens.LiteralInteger, 0); + } + + [Test] + public void TestInteger() + { + CheckToken("15", Tokens.LiteralInteger, 15); + CheckToken("8581", Tokens.LiteralInteger, 8581); + } + + [Test] + public void TestHexadecimalInteger() + { + CheckToken("&H10", Tokens.LiteralInteger, 0x10); + CheckToken("&H10&", Tokens.LiteralInteger, 0x10); + CheckToken("&h3ff&", Tokens.LiteralInteger, 0x3ff); + } + + [Test] + public void TestStringLiterals() + { + CheckToken("\"\"", Tokens.LiteralString, ""); + CheckToken("\"Hello, World!\"", Tokens.LiteralString, "Hello, World!"); + CheckToken("\"\"\"\"", Tokens.LiteralString, "\""); + } + + [Test] + public void TestCharacterLiterals() + { + CheckToken("\" \"c", Tokens.LiteralCharacter, ' '); + CheckToken("\"!\"c", Tokens.LiteralCharacter, '!'); + CheckToken("\"\"\"\"c", Tokens.LiteralCharacter, '"'); + } + + /* + * TODO : Test the following: + public const int LiteralDouble = 6; + public const int LiteralSingle = 7; + public const int LiteralDecimal = 8; + public const int LiteralDate = 9; + */ + } +} diff --git a/src/Libraries/NRefactory/Test/NRefactoryTests.csproj b/src/Libraries/NRefactory/Test/NRefactoryTests.csproj index 0a78100034..be3d28f772 100644 --- a/src/Libraries/NRefactory/Test/NRefactoryTests.csproj +++ b/src/Libraries/NRefactory/Test/NRefactoryTests.csproj @@ -1,4 +1,4 @@ - + Debug AnyCPU @@ -8,20 +8,10 @@ ICSharpCode.NRefactory.Tests ICSharpCode.NRefactory.Tests Library - - 4 - - - - False False OnSuccessfulBuild - - - - True @@ -37,220 +27,118 @@ True False False - - ..\..\..\..\bin\ True - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + {3a9ae6aa-bc07-4a2f-972c-581e3ae2f195} - {00000000-0000-0000-0000-000000000000} ICSharpCode.NRefactory - - + \ No newline at end of file diff --git a/src/Libraries/NRefactory/Test/NRefactoryTests.csproj.user b/src/Libraries/NRefactory/Test/NRefactoryTests.csproj.user index 0aec38c3cd..c818d818c8 100644 --- a/src/Libraries/NRefactory/Test/NRefactoryTests.csproj.user +++ b/src/Libraries/NRefactory/Test/NRefactoryTests.csproj.user @@ -1,14 +1,4 @@ - - - - - - - - - - - - - + + + \ No newline at end of file diff --git a/src/Libraries/NRefactory/Test/Parser/GlobalScope/TypeDeclarationTests.cs b/src/Libraries/NRefactory/Test/Parser/GlobalScope/TypeDeclarationTests.cs index dc5f0c7062..f460d3d353 100644 --- a/src/Libraries/NRefactory/Test/Parser/GlobalScope/TypeDeclarationTests.cs +++ b/src/Libraries/NRefactory/Test/Parser/GlobalScope/TypeDeclarationTests.cs @@ -157,6 +157,22 @@ public abstract class MyClass : MyBase, Interface1, My.Test.Interface2 Assert.AreEqual("TestClass", td.Name); Assert.AreEqual(Types.Class, td.Type); + Assert.AreEqual(1, td.StartLocation.Y, "start line"); + Assert.AreEqual(2, td.EndLocation.Y, "end line"); +// Assert.IsFalse(td.IsPartialType); + } + + [Test] + public void VBNetSimpleClassTypeDeclarationWithoutLastNewLineTest() + { + string program = "Class TestClass\n" + + "End Class"; + TypeDeclaration td = (TypeDeclaration)ParseUtilVBNet.ParseGlobal(program, typeof(TypeDeclaration)); + + Assert.AreEqual("TestClass", td.Name); + Assert.AreEqual(Types.Class, td.Type); + Assert.AreEqual(1, td.StartLocation.Y, "start line"); + Assert.AreEqual(2, td.EndLocation.Y, "end line"); // Assert.IsFalse(td.IsPartialType); } diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 3b260cf8bc..06b01ae284 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -16,7 +16,7 @@ True - True + False True ..\..\..\..\bin\ True diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/IndexerInsightDataProvider.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/IndexerInsightDataProvider.cs index 90a5865518..9ed82420ce 100644 --- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/IndexerInsightDataProvider.cs +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/IndexerInsightDataProvider.cs @@ -42,9 +42,9 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor IAmbience conv = AmbienceService.CurrentAmbience; conv.ConversionFlags = ConversionFlags.StandardConversionFlags; string documentation = ParserService.CurrentProjectContent.GetXmlDocumentation(method.DocumentationTag); - return conv.Convert(method) + - "\n" + - CodeCompletionData.GetDocumentation(documentation); // new (by G.B.) + return conv.Convert(method) + + "\n" + + CodeCompletionData.GetDocumentation(documentation); // new (by G.B.) } int initialOffset; @@ -55,39 +55,32 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor this.textArea = textArea; initialOffset = textArea.Caret.Offset; - // TODO: Change this for the new resolver, or better merge IndexerInsight and MethodInsight. - - /* IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(fileName); - string word = expressionFinder == null ? TextUtilities.GetExpressionBeforeOffset(textArea, textArea.Caret.Offset) : expressionFinder.FindExpression(textArea.Document.TextContent, textArea.Caret.Offset - 1); - - string methodObject = word; + string word = expressionFinder == null ? TextUtilities.GetExpressionBeforeOffset(textArea, textArea.Caret.Offset) : expressionFinder.FindExpression(textArea.Document.TextContent, textArea.Caret.Offset - 1); + word = word.Trim(); // the parser works with 1 based coordinates - int caretLineNumber = document.GetLineNumberForOffset(textArea.Caret.Offset) + 1; - int caretColumn = textArea.Caret.Offset - document.GetLineSegment(caretLineNumber - 1).Offset + 1; - ResolveResult results = ParserService.Resolve(methodObject, - caretLineNumber, - caretColumn, - fileName, - document.TextContent); - if (results != null && results.Type != null) { - foreach (IClass c in results.Type.ClassInheritanceTree) { - foreach (IIndexer indexer in c.Indexer) { - methods.Add(indexer); - } + int caretLineNumber = document.GetLineNumberForOffset(textArea.Caret.Offset) + 1; + int caretColumn = textArea.Caret.Offset - document.GetLineSegment(caretLineNumber).Offset + 1; + + ResolveResult result = ParserService.Resolve(word, caretLineNumber, caretColumn, fileName, document.TextContent); + if (result == null) + return; + IReturnType type = result.ResolvedType; + if (type == null) + return; + IProjectContent projectContent = ParserService.CurrentProjectContent; + if (projectContent == null) + return; + IClass c = projectContent.GetClass(type.FullyQualifiedName); + bool canViewProtected = c.IsTypeInInheritanceTree(result.CallingClass); + if (c == null) + return; + foreach (IIndexer i in c.Indexer) { + if (i.IsAccessible(result.CallingClass, canViewProtected)) { + methods.Add(i); } -// foreach (object o in results.ResolveContents) { -// if (o is IClass) { -// foreach (IClass c in ((IClass)o).ClassInheritanceTree) { -// foreach (IIndexer indexer in c.Indexer) { -// methods.Add(indexer); -// } -// } -// } -// } } - */ } public bool CaretOffsetChanged() diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs index c3888b9e9e..e7d677f31a 100644 --- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs @@ -30,9 +30,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor TextArea textArea = null; List methods = new List(); - int caretLineNumber; - int caretColumn; - public int InsightDataCount { get { return methods.Count; @@ -64,8 +61,8 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor word = word.Trim(); // the parser works with 1 based coordinates - caretLineNumber = document.GetLineNumberForOffset(textArea.Caret.Offset) + 1; - caretColumn = textArea.Caret.Offset - document.GetLineSegment(caretLineNumber).Offset + 1; + int caretLineNumber = document.GetLineNumberForOffset(textArea.Caret.Offset) + 1; + int caretColumn = textArea.Caret.Offset - document.GetLineSegment(caretLineNumber).Offset + 1; bool constructorInsight = false; if (word.ToLower().StartsWith("new ")) { diff --git a/src/Main/Base/Test/NRefactoryResolverTests.cs b/src/Main/Base/Test/NRefactoryResolverTests.cs index 86901fa9ed..c7fd633dc9 100644 --- a/src/Main/Base/Test/NRefactoryResolverTests.cs +++ b/src/Main/Base/Test/NRefactoryResolverTests.cs @@ -131,7 +131,6 @@ End Class Assert.AreEqual("System.String", result.ResolvedType.FullyQualifiedName); } - // Issue SD-265 [Test] public void VBNetStaticMembersonObjectTest() @@ -141,7 +140,8 @@ End Class Dim a As String End Sub -End Class"; +End Class +"; ResolveResult result = ResolveVB(program, "a", 4, 24); Assert.IsNotNull(result, "result"); ArrayList arr = result.GetCompletionData(lastPC); @@ -164,7 +164,8 @@ End Class"; Dim t As String() End Sub -End Module"; +End Module +"; ResolveResult result = ResolveVB(program, "t", 4, 24); Assert.IsNotNull(result, "result"); Assert.IsTrue(result is LocalResolveResult, "result is LocalResolveResult"); @@ -208,5 +209,33 @@ End Module"; } Assert.Fail("private field not visible from inner class"); } + + [Test] + public void InheritedInterfaceResolveTest() + { + string program = @"class A { + void Method(IInterface1 a) { + + } +} +interface IInterface1 : IInterface2 { + void Method1(); +} +interface IInterface2 { + void Method2(); +} +"; + ResolveResult result = Resolve(program, "a", 3, 24); + Assert.IsNotNull(result, "result"); + Assert.IsTrue(result is LocalResolveResult, "result is LocalResolveResult"); + ArrayList arr = result.GetCompletionData(lastPC); + Assert.IsNotNull(arr, "arr"); + Assert.AreEqual(2, arr.Count, "Number of CC results"); + foreach (IMethod m in arr) { + if (m.Name == "Method2") + return; + } + Assert.Fail("Method2 not found"); + } } }