Browse Source

Fixed parameter completion bug.

newNRvisualizers
Mike Krüger 14 years ago
parent
commit
374f1cb716
  1. 129
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs
  2. 143
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs
  3. 64
      ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs
  4. 27
      ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs

129
ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// CSharpCompletionEngine.cs
//
// Author:
@ -2515,132 +2515,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -2515,132 +2515,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return document.GetText(i, endOffset - i);
}
bool GetParameterCompletionCommandOffset(out int cpos)
{
// Start calculating the parameter offset from the beginning of the
// current member, instead of the beginning of the file.
cpos = offset - 1;
var mem = currentMember;
if (mem == null || (mem is IType)) {
return false;
}
int startPos = document.GetOffset(mem.Region.BeginLine, mem.Region.BeginColumn);
int parenDepth = 0;
int chevronDepth = 0;
while (cpos > startPos) {
char c = document.GetCharAt(cpos);
if (c == ')') {
parenDepth++;
}
if (c == '>') {
chevronDepth++;
}
if (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<') {
int p = GetCurrentParameterIndex(cpos + 1, startPos);
if (p != -1) {
cpos++;
return true;
} else {
return false;
}
}
if (c == '(') {
parenDepth--;
}
if (c == '<') {
chevronDepth--;
}
cpos--;
}
return false;
}
int GetCurrentParameterIndex(int offset, int memberStart)
{
int cursor = this.offset;
int i = offset;
if (i > cursor) {
return -1;
}
if (i == cursor) {
return 1;
}
// parameters are 1 based
int index = memberStart + 1;
int parentheses = 0;
int bracket = 0;
bool insideQuote = false, insideString = false, insideSingleLineComment = false, insideMultiLineComment = false;
do {
char c = document.GetCharAt(i - 1);
switch (c) {
case '\\':
if (insideString || insideQuote) {
i++;
}
break;
case '\'':
if (!insideString && !insideSingleLineComment && !insideMultiLineComment) {
insideQuote = !insideQuote;
}
break;
case '"':
if (!insideQuote && !insideSingleLineComment && !insideMultiLineComment) {
insideString = !insideString;
}
break;
case '/':
if (!insideQuote && !insideString && !insideMultiLineComment) {
if (document.GetCharAt(i) == '/') {
insideSingleLineComment = true;
}
if (document.GetCharAt(i) == '*') {
insideMultiLineComment = true;
}
}
break;
case '*':
if (insideMultiLineComment && document.GetCharAt(i) == '/') {
insideMultiLineComment = false;
}
break;
case '\n':
case '\r':
insideSingleLineComment = false;
break;
case '{':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) {
bracket++;
}
break;
case '}':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) {
bracket--;
}
break;
case '(':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) {
parentheses++;
}
break;
case ')':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) {
parentheses--;
}
break;
case ',':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment && parentheses == 1 && bracket == 0) {
index++;
}
break;
}
i++;
} while (i <= cursor && parentheses >= 0);
return parentheses != 1 || bracket > 0 ? -1 : index;
}
#endregion
#region Preprocessor

143
ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs

@ -100,7 +100,150 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -100,7 +100,150 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
var provider = MemberProvider ?? new DefaultMemberProvider (this);
provider.GetCurrentMembers (offset, out currentType, out currentMember);
}
protected bool GetParameterCompletionCommandOffset(out int cpos)
{
// Start calculating the parameter offset from the beginning of the
// current member, instead of the beginning of the file.
cpos = offset - 1;
var mem = currentMember;
if (mem == null || (mem is IType)) {
return false;
}
int startPos = document.GetOffset(mem.Region.BeginLine, mem.Region.BeginColumn);
int parenDepth = 0;
int chevronDepth = 0;
Stack<int> indexStack = new Stack<int>();
while (cpos > startPos) {
char c = document.GetCharAt(cpos);
if (c == ')') {
parenDepth++;
}
if (c == '>') {
chevronDepth++;
}
if (c == '}') {
if (indexStack.Count > 0) {
parenDepth = indexStack.Pop();
} else {
parenDepth = 0;
}
chevronDepth = 0;
}
if (indexStack.Count == 0 && (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<')) {
int p = GetCurrentParameterIndex (cpos + 1, startPos);
if (p != -1) {
cpos++;
return true;
} else {
return false;
}
}
if (c == '(') {
parenDepth--;
}
if (c == '<') {
chevronDepth--;
}
if (c == '{') {
indexStack.Push (parenDepth);
chevronDepth = 0;
}
cpos--;
}
return false;
}
protected int GetCurrentParameterIndex (int offset, int memberStart)
{
int cursor = this.offset;
int i = offset;
if (i > cursor) {
return -1;
}
if (i == cursor) {
return 1;
}
// parameters are 1 based
int index = memberStart + 1;
int parentheses = 0;
int bracket = 0;
bool insideQuote = false, insideString = false, insideSingleLineComment = false, insideMultiLineComment = false;
Stack<int> indexStack = new Stack<int> ();
do {
char c = document.GetCharAt (i - 1);
switch (c) {
case '\\':
if (insideString || insideQuote) {
i++;
}
break;
case '\'':
if (!insideString && !insideSingleLineComment && !insideMultiLineComment) {
insideQuote = !insideQuote;
}
break;
case '"':
if (!insideQuote && !insideSingleLineComment && !insideMultiLineComment) {
insideString = !insideString;
}
break;
case '/':
if (!insideQuote && !insideString && !insideMultiLineComment) {
if (document.GetCharAt (i) == '/') {
insideSingleLineComment = true;
}
if (document.GetCharAt (i) == '*') {
insideMultiLineComment = true;
}
}
break;
case '*':
if (insideMultiLineComment && document.GetCharAt (i) == '/') {
insideMultiLineComment = false;
}
break;
case '\n':
case '\r':
insideSingleLineComment = false;
break;
case '{':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) {
bracket++;
indexStack.Push (index);
}
break;
case '}':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) {
bracket--;
if (indexStack.Count > 0)
index = indexStack.Pop ();
}
break;
case '(':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) {
parentheses++;
}
break;
case ')':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment) {
parentheses--;
}
break;
case ',':
if (!insideQuote && !insideString && !insideSingleLineComment && !insideMultiLineComment && parentheses == 1 && bracket == 0) {
index++;
}
break;
}
i++;
} while (i <= cursor && parentheses >= 0);
Console.WriteLine (indexStack.Count >= 0 || parentheses != 1 || bracket > 0 ? -1 : index);
return indexStack.Count >= 0 || parentheses != 1 || bracket > 0 ? -1 : index;
}
#region Context helper methods
protected bool IsInsideCommentOrString ()
{

64
ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs

@ -217,6 +217,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -217,6 +217,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
if (invoke == null) {
invoke = GetTypeBeforeCursor();
if (invoke != null) {
if (GetCurrentParameterIndex(document.GetOffset(invoke.Node.StartLocation), offset) < 0)
return null;
var typeExpression = ResolveExpression(invoke);
if (typeExpression == null || typeExpression.Item1 == null || typeExpression.Item1.IsError) {
return null;
@ -226,6 +228,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -226,6 +228,8 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
return null;
}
if (GetCurrentParameterIndex(document.GetOffset(invoke.Node.StartLocation), offset) < 0)
return null;
if (invoke.Node is ObjectCreateExpression) {
var createType = ResolveExpression(((ObjectCreateExpression)invoke.Node).Type, invoke.Unit);
return factory.CreateConstructorProvider(document.GetOffset(invoke.Node.StartLocation), createType.Item1.Type);
@ -334,17 +338,35 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -334,17 +338,35 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
return 0;
}
var parameter = new Stack<int>();
var bracketStack = new Stack<Stack<int>>();
bool inSingleComment = false, inString = false, inVerbatimString = false, inChar = false, inMultiLineComment = false;
for (int i = triggerOffset; i < endOffset; i++) {
char ch = document.GetCharAt(i);
char nextCh = i + 1 < document.TextLength ? document.GetCharAt(i + 1) : '\0';
switch (ch) {
case '{':
if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
break;
}
bracketStack.Push(parameter);
parameter = new Stack<int>();
break;
case '(':
if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
break;
}
parameter.Push(0);
break;
case '}':
if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
break;
}
if (bracketStack.Count > 0) {
parameter = bracketStack.Pop();
} else {
return -1;
}
break;
case ')':
if (inString || inChar || inVerbatimString || inSingleComment || inMultiLineComment) {
break;
@ -440,51 +462,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -440,51 +462,11 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
break;
}
}
if (parameter.Count == 0) {
if (parameter.Count == 0 || bracketStack.Count > 0) {
return -1;
}
return parameter.Pop() + 1;
}
/*
public override bool GetParameterCompletionCommandOffset (out int cpos)
{
// Start calculating the parameter offset from the beginning of the
// current member, instead of the beginning of the file.
cpos = textEditorData.Caret.Offset - 1;
var parsedDocument = Document.ParsedDocument;
if (parsedDocument == null)
return false;
IMember mem = currentMember;
if (mem == null || (mem is IType))
return false;
int startPos = textEditorData.LocationToOffset (mem.Region.BeginLine, mem.Region.BeginColumn);
int parenDepth = 0;
int chevronDepth = 0;
while (cpos > startPos) {
char c = textEditorData.GetCharAt (cpos);
if (c == ')')
parenDepth++;
if (c == '>')
chevronDepth++;
if (parenDepth == 0 && c == '(' || chevronDepth == 0 && c == '<') {
int p = MethodParameterDataProvider.GetCurrentParameterIndex (CompletionWidget, cpos + 1, startPos);
if (p != -1) {
cpos++;
return true;
} else {
return false;
}
}
if (c == '(')
parenDepth--;
if (c == '<')
chevronDepth--;
cpos--;
}
return false;
}*/
}
}

27
ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs

@ -902,9 +902,9 @@ namespace Test @@ -902,9 +902,9 @@ namespace Test
/// Bug 3991 - constructor argument completion not working for attributes applied to methods or parameters
/// </summary>
[Test()]
public void TestBug3991 ()
public void TestBug3991()
{
IParameterDataProvider provider = CreateProvider (
IParameterDataProvider provider = CreateProvider(
@"using System;
namespace Test
{
@ -917,8 +917,27 @@ namespace Test @@ -917,8 +917,27 @@ namespace Test
}
}
");
Assert.IsNotNull (provider, "provider was not created.");
Assert.Greater (provider.Count, 0);
Assert.IsNotNull(provider, "provider was not created.");
Assert.Greater(provider.Count, 0);
}
/// <summary>
/// Bug 4087 - code completion handles object and collection initializers (braces) incorrectly in method calls
/// </summary>
[Test()]
public void TestBug4087()
{
IParameterDataProvider provider = CreateProvider(
@"using System;
class TestClass
{
TestClass()
{
$Console.WriteLine (new int[]{ 4, 5,$
}
}
");
Assert.IsTrue (provider == null || provider.Count == 0);
}
}
}
Loading…
Cancel
Save