Browse Source

- fixed infinite loop in VBNetExpressionFinder

- fixed context detection at Inherts/Implements
- removed unused variable from VBNetBracketSearcher
- added InsightWindowHandler
- implemented method insight in VB

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@6322 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
pull/1/head
Siegfried Pammer 15 years ago
parent
commit
a19f10d222
  1. 14
      samples/NRefactoryDemo/NRefactoryDemo.csproj
  2. 2
      src/AddIns/BackendBindings/VBNetBinding/Project/Configuration/AssemblyInfo.cs
  3. 7
      src/AddIns/BackendBindings/VBNetBinding/Project/Src/FormattingStrategy/VBNetFormattingStrategy.cs
  4. 2
      src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetBracketSearcher.cs
  5. 14
      src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs
  6. 23
      src/AddIns/BackendBindings/VBNetBinding/Test/FormattingStrategy/IndentationTests.cs
  7. 4
      src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinder.atg
  8. 4
      src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Parser.cs
  9. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  10. 281
      src/Main/Base/Project/Src/Editor/CodeCompletion/InsightWindowHandler.cs
  11. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/VBNet/VBNetExpressionFinder.cs

14
samples/NRefactoryDemo/NRefactoryDemo.csproj

@ -9,14 +9,17 @@ @@ -9,14 +9,17 @@
<ProjectGuid>{63199047-9D5D-474C-B3CC-62ABBB071B67}</ProjectGuid>
<SourceAnalysisOverrideSettingsFile>C:\Users\Siegfried\AppData\Roaming\ICSharpCode/SharpDevelop3.0\Settings.SourceAnalysis</SourceAnalysisOverrideSettingsFile>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>
<OutputPath>bin\Debug\</OutputPath>
<Optimize>False</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugSymbols>True</DebugSymbols>
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
</PropertyGroup>
@ -30,6 +33,13 @@ @@ -30,6 +33,13 @@
<DebugType>None</DebugType>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<PlatformTarget>x86</PlatformTarget>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<ItemGroup>
<Reference Include="ICSharpCode.NRefactory">
<HintPath>..\..\bin\ICSharpCode.NRefactory.dll</HintPath>

2
src/AddIns/BackendBindings/VBNetBinding/Project/Configuration/AssemblyInfo.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following
// attributes.
@ -18,3 +19,4 @@ using System.Reflection; @@ -18,3 +19,4 @@ using System.Reflection;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: InternalsVisibleTo("ICSharpCode.VBNetBinding.Tests")]

7
src/AddIns/BackendBindings/VBNetBinding/Project/Src/FormattingStrategy/VBNetFormattingStrategy.cs

@ -656,12 +656,7 @@ namespace ICSharpCode.VBNetBinding @@ -656,12 +656,7 @@ namespace ICSharpCode.VBNetBinding
void Indent(ITextEditor editor, Stack<string> indentation)
{
bool useSpaces = editor.Options.ConvertTabsToSpaces;
int indentationSize = editor.Options.IndentationSize;
string addIndent = (useSpaces) ? new string(' ', indentationSize) : "\t";
indentation.Push((indentation.PeekOrDefault() ?? string.Empty) + addIndent);
indentation.Push((indentation.PeekOrDefault() ?? string.Empty) + editor.Options.IndentationString);
}
internal static bool IsBlockStart(ILexer lexer, Token current, Token prev)

2
src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetBracketSearcher.cs

@ -183,7 +183,7 @@ namespace ICSharpCode.VBNetBinding @@ -183,7 +183,7 @@ namespace ICSharpCode.VBNetBinding
}
Token result = null;
Token firstModifier = null;
// Token firstModifier = null;
while ((currentToken = lexer.NextToken()).Kind != Tokens.EOF) {
if (prevToken == null)

14
src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetCompletionBinding.cs

@ -7,6 +7,8 @@ @@ -7,6 +7,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Core;
@ -15,6 +17,8 @@ using ICSharpCode.NRefactory.Parser; @@ -15,6 +17,8 @@ using ICSharpCode.NRefactory.Parser;
using ICSharpCode.NRefactory.Parser.VB;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Dom;
using Dom = ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
using ICSharpCode.SharpDevelop.Dom.VBNet;
using ICSharpCode.SharpDevelop.Editor;
@ -34,6 +38,8 @@ namespace ICSharpCode.VBNetBinding @@ -34,6 +38,8 @@ namespace ICSharpCode.VBNetBinding
}
}
InsightWindowHandler insightHandler = new InsightWindowHandler(SupportedLanguage.VBNet);
public CodeCompletionKeyPressResult HandleKeyPress(ITextEditor editor, char ch)
{
if (IsInComment(editor) || IsInString(editor))
@ -57,11 +63,15 @@ namespace ICSharpCode.VBNetBinding @@ -57,11 +63,15 @@ namespace ICSharpCode.VBNetBinding
case '(':
if (CodeCompletionOptions.InsightEnabled) {
IInsightWindow insightWindow = editor.ShowInsightWindow(new MethodInsightProvider().ProvideInsight(editor));
// if (insightWindow != null)
// InitializeOpenedInsightWindow(editor, insightWindow);
if (insightWindow != null)
insightHandler.InitializeOpenedInsightWindow(editor, insightWindow);
return CodeCompletionKeyPressResult.Completed;
}
break;
case ',':
if (CodeCompletionOptions.InsightRefreshOnComma && CodeCompletionOptions.InsightEnabled && insightHandler.InsightRefreshOnComma(editor, ch))
return CodeCompletionKeyPressResult.Completed;
break;
case '\n':
TryDeclarationTypeInference(editor, editor.Document.GetLineForOffset(editor.Caret.Offset));
break;

23
src/AddIns/BackendBindings/VBNetBinding/Test/FormattingStrategy/IndentationTests.cs

@ -13,7 +13,7 @@ using NUnit.Framework; @@ -13,7 +13,7 @@ using NUnit.Framework;
namespace ICSharpCode.VBNetBinding.Tests
{
[TestFixture]
[TestFixture, Ignore]
public class IndentationTests
{
[Test]
@ -32,6 +32,22 @@ End Interface"; @@ -32,6 +32,22 @@ End Interface";
RunFormatTest(code, expectedCode);
}
[Test]
public void SimpleInterfaceWithModifierTest()
{
string code = @"Public Interface t
Sub Test()
Sub Test2()
End Interface";
string expectedCode = @"Public Interface t
Sub Test()
Sub Test2()
End Interface";
RunFormatTest(code, expectedCode);
}
[Test]
public void InterfaceWithNewLineAtEndTest()
{
@ -135,7 +151,6 @@ End Class"; @@ -135,7 +151,6 @@ End Class";
}
[Test]
[Ignore("Test started failing after merge to SD 4.0")]
public void ElseIfMultiLineContinuationTest()
{
string expected = @"Public Class Test
@ -314,7 +329,9 @@ End Class"; @@ -314,7 +329,9 @@ End Class";
AvalonEditTextEditorAdapter editor = new AvalonEditTextEditorAdapter(new TextEditor());
editor.Document.Text = code;
VBNetFormattingStrategy formattingStrategy = new VBNetFormattingStrategy();
formattingStrategy.IndentLines(editor, 0, editor.Document.TotalNumberOfLines);
formattingStrategy.IndentLines(editor, 1, editor.Document.TotalNumberOfLines);
Console.WriteLine(editor.Document.Text);
Assert.AreEqual(expectedCode, editor.Document.Text);
}

4
src/Libraries/NRefactory/Project/Src/Lexer/VBNet/ExpressionFinder.atg

@ -314,8 +314,8 @@ ClassOrModuleOrStructureTypeDeclaration = @@ -314,8 +314,8 @@ ClassOrModuleOrStructureTypeDeclaration =
(. PushContext(Context.TypeDeclaration, la, t); .)
( "Module" | "Class" | "Structure" ) (. PushContext(Context.Identifier, la, t); .) (.OnEachPossiblePath: SetIdentifierExpected(la); .) Identifier (. PopContext(); .)
[ "(" "Of" GenericTypeParameterDeclaration ")" ] StatementTerminator
[ (. isMissingModifier = false; .) (. PushContext(Context.Type, la, t); .) "Inherits" TypeName (. PopContext(); .) StatementTerminator ]
[ (. isMissingModifier = false; .) (. PushContext(Context.Type, la, t); .) "Implements" TypeName (. PopContext(); .) { "," (. PushContext(Context.Type, la, t); .) TypeName (. PopContext(); .) } StatementTerminator ]
[ (. isMissingModifier = false; .) "Inherits" (. PushContext(Context.Type, la, t); .) TypeName (. PopContext(); .) StatementTerminator ]
[ (. isMissingModifier = false; .) "Implements" (. PushContext(Context.Type, la, t); .) TypeName (. PopContext(); .) { "," (. PushContext(Context.Type, la, t); .) TypeName (. PopContext(); .) } StatementTerminator ]
{
{ AttributeBlock } (.OnEachPossiblePath: isMissingModifier = true; .)
{ TypeOrMemberModifier (. isMissingModifier = false; .) } (. isMissingModifier = false; .)

4
src/Libraries/NRefactory/Project/Src/Lexer/VBNet/Parser.cs

@ -6256,7 +6256,6 @@ partial class ExpressionFinder { @@ -6256,7 +6256,6 @@ partial class ExpressionFinder {
if (la == null) { currentState = 492; break; }
if (la.kind == 140) {
isMissingModifier = false;
PushContext(Context.Type, la, t);
goto case 635;
} else {
goto case 493;
@ -6271,7 +6270,6 @@ partial class ExpressionFinder { @@ -6271,7 +6270,6 @@ partial class ExpressionFinder {
if (la == null) { currentState = 494; break; }
if (la.kind == 136) {
isMissingModifier = false;
PushContext(Context.Type, la, t);
goto case 629;
} else {
goto case 495;
@ -7346,6 +7344,7 @@ partial class ExpressionFinder { @@ -7346,6 +7344,7 @@ partial class ExpressionFinder {
break;
}
case 630: {
PushContext(Context.Type, la, t);
stateStack.Push(631);
goto case 32;
}
@ -7379,6 +7378,7 @@ partial class ExpressionFinder { @@ -7379,6 +7378,7 @@ partial class ExpressionFinder {
break;
}
case 636: {
PushContext(Context.Type, la, t);
stateStack.Push(637);
goto case 32;
}

1
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -96,6 +96,7 @@ @@ -96,6 +96,7 @@
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Src\Editor\CodeCompletion\ICompletionItemHandler.cs" />
<Compile Include="Src\Editor\CodeCompletion\InsightWindowHandler.cs" />
<Compile Include="Src\Editor\CodeCompletion\NRefactoryCompletionItemList.cs" />
<Compile Include="Src\Editor\Commands\ClassBookmarkSubmenuBuilder.cs" />
<Compile Include="Src\Editor\Commands\ClassMemberMenuBuilder.cs" />

281
src/Main/Base/Project/Src/Editor/CodeCompletion/InsightWindowHandler.cs

@ -0,0 +1,281 @@ @@ -0,0 +1,281 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision: 6028 $</version>
// </file>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Parser;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.NRefactoryResolver;
using CSTokens = ICSharpCode.NRefactory.Parser.CSharp.Tokens;
using VBTokens = ICSharpCode.NRefactory.Parser.VB.Tokens;
namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion
{
public class InsightWindowHandler
{
readonly SupportedLanguage language;
readonly int eofToken, commaToken, openParensToken, closeParensToken, openBracketToken, closeBracketToken, openBracesToken, closeBracesToken, statementEndToken;
readonly LanguageProperties languageProperties;
public InsightWindowHandler(SupportedLanguage language)
{
this.language = language;
if (language == SupportedLanguage.CSharp) {
eofToken = CSTokens.EOF;
commaToken = CSTokens.Comma;
openParensToken = CSTokens.OpenParenthesis;
closeParensToken = CSTokens.CloseParenthesis;
openBracketToken = CSTokens.OpenSquareBracket;
closeBracketToken = CSTokens.CloseSquareBracket;
openBracesToken = CSTokens.OpenCurlyBrace;
closeBracesToken = CSTokens.CloseCurlyBrace;
statementEndToken = CSTokens.Semicolon;
languageProperties = LanguageProperties.CSharp;
} else {
eofToken = VBTokens.EOF;
commaToken = VBTokens.Comma;
openParensToken = VBTokens.OpenParenthesis;
closeParensToken = VBTokens.CloseParenthesis;
openBracketToken = -1;
closeBracketToken = -1;
openBracesToken = VBTokens.OpenCurlyBrace;
closeBracesToken = VBTokens.CloseCurlyBrace;
statementEndToken = VBTokens.EOL;
languageProperties = LanguageProperties.VBNet;
}
}
public void InitializeOpenedInsightWindow(ITextEditor editor, IInsightWindow insightWindow)
{
EventHandler<TextChangeEventArgs> onDocumentChanged = delegate {
// whenever the document is changed, recalculate EndOffset
var remainingDocument = editor.Document.CreateReader(insightWindow.StartOffset, editor.Document.TextLength - insightWindow.StartOffset);
using (ILexer lexer = ParserFactory.CreateLexer(language, remainingDocument)) {
lexer.SetInitialLocation(editor.Document.OffsetToPosition(insightWindow.StartOffset));
Token token;
int bracketCount = 0;
while ((token = lexer.NextToken()) != null && token.Kind != eofToken) {
if (token.Kind == openParensToken || token.Kind == openBracketToken || token.Kind == openBracketToken) {
bracketCount++;
} else if (token.Kind == closeParensToken || token.Kind == closeBracketToken || token.Kind == closeBracesToken) {
bracketCount--;
if (bracketCount <= 0) {
MarkInsightWindowEndOffset(insightWindow, editor, token.Location);
break;
}
} else if (token.Kind == statementEndToken) {
MarkInsightWindowEndOffset(insightWindow, editor, token.Location);
break;
}
}
}
};
insightWindow.DocumentChanged += onDocumentChanged;
onDocumentChanged(null, null);
}
void MarkInsightWindowEndOffset(IInsightWindow insightWindow, ITextEditor editor, Location endLocation)
{
insightWindow.EndOffset = editor.Document.PositionToOffset(endLocation.Line, endLocation.Column);
if (editor.Caret.Offset > insightWindow.EndOffset)
insightWindow.Close();
}
class InspectedCall
{
/// <summary>
/// position of the '('
/// </summary>
internal Location start;
/// <summary>
/// list of location of the comma tokens.
/// </summary>
internal List<Location> commas = new List<Location>();
/// <summary>
/// reference back to parent call - used to create a stack of inspected calls
/// </summary>
internal InspectedCall parent;
public InspectedCall(Location start, InspectedCall parent)
{
this.start = start;
this.parent = parent;
}
}
int LocationToOffset(ITextEditor editor, Location loc)
{
if (loc.IsEmpty || loc.Line > editor.Document.TotalNumberOfLines)
return -1;
IDocumentLine seg = editor.Document.GetLine(loc.Line);
return seg.Offset + Math.Min(loc.Column, seg.Length) - 1;
}
IList<ResolveResult> ResolveCallParameters(ITextEditor editor, InspectedCall call)
{
List<ResolveResult> rr = new List<ResolveResult>();
int offset = LocationToOffset(editor, call.start);
string documentText = editor.Document.Text;
int newOffset;
foreach (Location loc in call.commas) {
newOffset = LocationToOffset(editor, loc);
if (newOffset < 0) break;
string text = editor.Document.GetText(offset+1,newOffset-(offset+1));
rr.Add(ParserService.Resolve(new ExpressionResult(text), loc.Line, loc.Column, editor.FileName, documentText));
}
// the last argument is between the last comma and the caret position
newOffset = editor.Caret.Offset;
if (offset < newOffset) {
string text = editor.Document.GetText(offset+1,newOffset-(offset+1));
rr.Add(ParserService.Resolve(new ExpressionResult(text),
editor.Caret.Line,
editor.Caret.Column,
editor.FileName, documentText));
}
return rr;
}
public bool InsightRefreshOnComma(ITextEditor editor, char ch)
{
// Show MethodInsightWindow or IndexerInsightWindow
NRefactoryResolver r = new NRefactoryResolver(languageProperties);
Location cursorLocation = editor.Caret.Position;
if (r.Initialize(ParserService.GetParseInformation(editor.FileName), cursorLocation.Y, cursorLocation.X)) {
TextReader currentMethod = r.ExtractCurrentMethod(editor.Document.Text);
if (currentMethod != null) {
ILexer lexer = ParserFactory.CreateLexer(language, currentMethod);
Token token;
InspectedCall call = new InspectedCall(Location.Empty, null);
call.parent = call;
while ((token = lexer.NextToken()) != null
&& token.Kind != eofToken
&& token.Location < cursorLocation)
{
if (token.Kind == commaToken) {
call.commas.Add(token.Location);
} else if (token.Kind == openParensToken || token.Kind == openBracketToken || token.Kind == openBracesToken) {
call = new InspectedCall(token.Location, call);
} else if (token.Kind == closeParensToken || token.Kind == closeBracketToken || token.Kind == closeBracesToken) {
call = call.parent;
}
}
int offset = LocationToOffset(editor, call.start);
if (offset >= 0 && offset < editor.Document.TextLength) {
char c = editor.Document.GetCharAt(offset);
if (c == '(' || c == '[') {
var insightProvider = new MethodInsightProvider { LookupOffset = offset };
var insightItems = insightProvider.ProvideInsight(editor);
ShowInsight(editor,
insightItems,
ResolveCallParameters(editor, call),
ch);
return true;
} else {
Core.LoggingService.Warn("Expected '(' or '[' at start position");
}
}
}
}
return false;
}
IMethodOrProperty GetMethodFromInsightItem(IInsightItem item)
{
MethodInsightItem mii = item as MethodInsightItem;
if (mii != null) {
return mii.Entity as IMethodOrProperty;
} else {
return null;
}
}
void ShowInsight(ITextEditor editor, IList<IInsightItem> insightItems, ICollection<ResolveResult> parameters, char charTyped)
{
int paramCount = parameters.Count;
if (insightItems == null || insightItems.Count == 0)
return;
bool overloadIsSure;
int defaultIndex;
if (insightItems.Count == 1) {
overloadIsSure = true;
defaultIndex = 0;
} else {
var methods = insightItems.Select(item => GetMethodFromInsightItem(item)).ToList();
IReturnType[] argumentTypes = new IReturnType[paramCount + 1];
int i = 0;
foreach (ResolveResult rr in parameters) {
if (rr != null) {
argumentTypes[i] = rr.ResolvedType;
}
i++;
}
IMethodOrProperty result = Dom.CSharp.OverloadResolution.FindOverload(
methods.Where(m => m != null), argumentTypes, true, false, out overloadIsSure);
defaultIndex = methods.IndexOf(result);
}
IInsightWindow insightWindow = editor.ShowInsightWindow(insightItems);
if (insightWindow != null) {
InitializeOpenedInsightWindow(editor, insightWindow);
insightWindow.SelectedItem = insightItems[defaultIndex];
}
if (overloadIsSure) {
IMethodOrProperty method = GetMethodFromInsightItem(insightItems[defaultIndex]);
if (method != null && paramCount < method.Parameters.Count) {
IParameter param = method.Parameters[paramCount];
ProvideContextCompletion(editor, param.ReturnType, charTyped);
}
}
}
bool ProvideContextCompletion(ITextEditor editor, IReturnType expected, char charTyped)
{
if (expected == null) return false;
IClass c = expected.GetUnderlyingClass();
if (c == null) return false;
if (c.ClassType == ClassType.Enum) {
CtrlSpaceCompletionItemProvider cdp = new NRefactoryCtrlSpaceCompletionItemProvider(languageProperties);
var ctrlSpaceList = cdp.GenerateCompletionList(editor);
if (ctrlSpaceList == null) return false;
ContextCompletionItemList contextList = new ContextCompletionItemList();
contextList.Items.AddRange(ctrlSpaceList.Items);
contextList.activationKey = charTyped;
foreach (CodeCompletionItem item in contextList.Items.OfType<CodeCompletionItem>()) {
IClass itemClass = item.Entity as IClass;
if (itemClass != null && c.FullyQualifiedName == itemClass.FullyQualifiedName && c.TypeParameters.Count == itemClass.TypeParameters.Count) {
contextList.SuggestedItem = item;
break;
}
}
if (contextList.SuggestedItem != null) {
if (charTyped != ' ') contextList.InsertSpace = true;
editor.ShowCompletionWindow(contextList);
return true;
}
}
return false;
}
class ContextCompletionItemList : DefaultCompletionItemList
{
internal char activationKey;
public override CompletionItemListKeyResult ProcessInput(char key)
{
if (key == '=' && activationKey == '=')
return CompletionItemListKeyResult.BeforeStartKey;
activationKey = '\0';
return base.ProcessInput(key);
}
}
}
}

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/VBNet/VBNetExpressionFinder.cs

@ -211,6 +211,8 @@ namespace ICSharpCode.SharpDevelop.Dom.VBNet @@ -211,6 +211,8 @@ namespace ICSharpCode.SharpDevelop.Dom.VBNet
block = p.CurrentBlock;
if (block != null && (block.isClosed || expressionDelimiters.Contains(t.Kind) && block == p.CurrentBlock))
break;
if (t.Kind == Tokens.EOF)
break;
}
if (p.Errors.Any()) {

Loading…
Cancel
Save