Browse Source

[Completion] Member provider now needs to be given in the constructor.

newNRvisualizers
Mike Krüger 13 years ago
parent
commit
d60aaebc8a
  1. 2
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs
  2. 141
      ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngineBase.cs
  3. 2
      ICSharpCode.NRefactory.CSharp/Completion/CSharpParameterCompletionEngine.cs
  4. 124
      ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs
  5. 67
      ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs
  6. 52
      ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/ParameterCompletionTests.cs

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

@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
public bool CloseOnSquareBrackets;
#endregion
public CSharpCompletionEngine(IDocument document, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, ctx, unit, parsedFile)
public CSharpCompletionEngine(IDocument document, IMemberProvider memberProvider, ICompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, unit, parsedFile)
{
if (document == null) {
throw new ArgumentNullException("document");

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

@ -68,18 +68,21 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -68,18 +68,21 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
#endregion
protected CSharpCompletionEngineBase (IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile)
protected CSharpCompletionEngineBase(IProjectContent content, IMemberProvider memberProvider, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile)
{
if (content == null)
throw new ArgumentNullException ("content");
throw new ArgumentNullException("content");
if (ctx == null)
throw new ArgumentNullException ("ctx");
throw new ArgumentNullException("ctx");
if (unit == null)
throw new ArgumentNullException ("unit");
throw new ArgumentNullException("unit");
if (parsedFile == null)
throw new ArgumentNullException ("parsedFile");
throw new ArgumentNullException("parsedFile");
if (memberProvider == null)
throw new ArgumentNullException("memberProvider");
this.ProjectContent = content;
this.MemberProvider = memberProvider;
this.ctx = ctx;
this.Unit = unit;
this.CSharpParsedFile = parsedFile;
@ -88,7 +91,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -88,7 +91,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
public IMemberProvider MemberProvider {
get;
set;
private set;
}
public void SetOffset (int offset)
@ -97,8 +100,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -97,8 +100,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
this.offset = offset;
this.location = document.GetLocation (offset);
var provider = MemberProvider ?? new DefaultMemberProvider (this);
provider.GetCurrentMembers (offset, out currentType, out currentMember);
MemberProvider.GetCurrentMembers (offset, out currentType, out currentMember);
}
public bool GetParameterCompletionCommandOffset (out int cpos)
@ -839,128 +841,5 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -839,128 +841,5 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
}
#endregion
class DefaultMemberProvider : IMemberProvider
{
CSharpCompletionEngineBase engine;
public DefaultMemberProvider (CSharpCompletionEngineBase engine)
{
this.engine = engine;
}
public void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember)
{
//var document = engine.document;
var location = engine.location;
currentType = null;
foreach (var type in engine.CSharpParsedFile.TopLevelTypeDefinitions) {
if (type.Region.Begin < location)
currentType = type;
}
currentType = FindInnerType (currentType, location);
// location is beyond last reported end region, now we need to check, if the end region changed
if (currentType != null && currentType.Region.End < location) {
if (!IsInsideType (currentType, location))
currentType = null;
}
currentMember = null;
if (currentType != null) {
foreach (var member in currentType.Members) {
if (member.Region.Begin < location && (currentMember == null || currentMember.Region.Begin < member.Region.Begin))
currentMember = member;
}
}
// location is beyond last reported end region, now we need to check, if the end region changed
// NOTE: Enums are a special case, there the "last" field needs to be treated as current member
if (currentMember != null && currentMember.Region.End < location && currentType.Kind != TypeKind.Enum) {
if (!IsInsideType (currentMember, location))
currentMember = null;
}
var stack = GetBracketStack (engine.GetMemberTextToCaret ().Item1);
if (stack.Count == 0)
currentMember = null;
}
IUnresolvedTypeDefinition FindInnerType (IUnresolvedTypeDefinition parent, TextLocation location)
{
if (parent == null)
return null;
var currentType = parent;
foreach (var type in parent.NestedTypes) {
if (type.Region.Begin < location && location < type.Region.End)
currentType = FindInnerType (type, location);
}
return currentType;
}
bool IsInsideType (IUnresolvedEntity currentType, TextLocation location)
{
var document = engine.document;
int startOffset = document.GetOffset (currentType.Region.Begin);
int endOffset = document.GetOffset (location);
//bool foundEndBracket = false;
var bracketStack = new Stack<char> ();
bool isInString = false, isInChar = false;
bool isInLineComment = false, isInBlockComment = false;
for (int i = startOffset; i < endOffset; i++) {
char ch = document.GetCharAt (i);
switch (ch) {
case '(':
case '[':
case '{':
if (!isInString && !isInChar && !isInLineComment && !isInBlockComment)
bracketStack.Push (ch);
break;
case ')':
case ']':
case '}':
if (!isInString && !isInChar && !isInLineComment && !isInBlockComment)
if (bracketStack.Count > 0)
bracketStack.Pop ();
break;
case '\r':
case '\n':
isInLineComment = false;
break;
case '/':
if (isInBlockComment) {
if (i > 0 && document.GetCharAt (i - 1) == '*')
isInBlockComment = false;
} else if (!isInString && !isInChar && i + 1 < document.TextLength) {
char nextChar = document.GetCharAt (i + 1);
if (nextChar == '/')
isInLineComment = true;
if (!isInLineComment && nextChar == '*')
isInBlockComment = true;
}
break;
case '"':
if (!(isInChar || isInLineComment || isInBlockComment))
isInString = !isInString;
break;
case '\'':
if (!(isInString || isInLineComment || isInBlockComment))
isInChar = !isInChar;
break;
default :
break;
}
}
return bracketStack.Any (t => t == '{');
}
}
}
}

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

@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
{
internal IParameterCompletionDataFactory factory;
public CSharpParameterCompletionEngine(IDocument document, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, ctx, unit, parsedFile)
public CSharpParameterCompletionEngine(IDocument document, IMemberProvider memberProvider, IParameterCompletionDataFactory factory, IProjectContent content, CSharpTypeResolveContext ctx, CompilationUnit unit, CSharpParsedFile parsedFile) : base (content, memberProvider, ctx, unit, parsedFile)
{
if (document == null) {
throw new ArgumentNullException("document");

124
ICSharpCode.NRefactory.CSharp/Completion/IMemberProvider.cs

@ -36,5 +36,129 @@ namespace ICSharpCode.NRefactory.CSharp.Completion @@ -36,5 +36,129 @@ namespace ICSharpCode.NRefactory.CSharp.Completion
{
void GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember);
}
public class DefaultMemberProvider : IMemberProvider
{
readonly IDocument document;
readonly CSharpParsedFile parsedFile;
public DefaultMemberProvider (IDocument document, CSharpParsedFile parsedFile)
{
if (document == null)
throw new ArgumentNullException("document");
if (parsedFile == null)
throw new ArgumentNullException("parsedFile");
this.document = document;
this.parsedFile = parsedFile;
}
public void GetCurrentMembers(int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember)
{
//var document = engine.document;
var location = document.GetLocation(offset);
currentType = null;
foreach (var type in parsedFile.TopLevelTypeDefinitions) {
if (type.Region.Begin < location)
currentType = type;
}
currentType = FindInnerType (currentType, location);
// location is beyond last reported end region, now we need to check, if the end region changed
if (currentType != null && currentType.Region.End < location) {
if (!IsInsideType (currentType, location))
currentType = null;
}
currentMember = null;
if (currentType != null) {
foreach (var member in currentType.Members) {
if (member.Region.Begin < location && (currentMember == null || currentMember.Region.Begin < member.Region.Begin))
currentMember = member;
}
}
// location is beyond last reported end region, now we need to check, if the end region changed
// NOTE: Enums are a special case, there the "last" field needs to be treated as current member
if (currentMember != null && currentMember.Region.End < location && currentType.Kind != TypeKind.Enum) {
if (!IsInsideType (currentMember, location))
currentMember = null;
}/*
var stack = GetBracketStack (engine.GetMemberTextToCaret ().Item1);
if (stack.Count == 0)
currentMember = null;*/
}
IUnresolvedTypeDefinition FindInnerType (IUnresolvedTypeDefinition parent, TextLocation location)
{
if (parent == null)
return null;
var currentType = parent;
foreach (var type in parent.NestedTypes) {
if (type.Region.Begin < location && location < type.Region.End)
currentType = FindInnerType (type, location);
}
return currentType;
}
bool IsInsideType (IUnresolvedEntity currentType, TextLocation location)
{
int startOffset = document.GetOffset (currentType.Region.Begin);
int endOffset = document.GetOffset (location);
//bool foundEndBracket = false;
var bracketStack = new Stack<char> ();
bool isInString = false, isInChar = false;
bool isInLineComment = false, isInBlockComment = false;
for (int i = startOffset; i < endOffset; i++) {
char ch = document.GetCharAt (i);
switch (ch) {
case '(':
case '[':
case '{':
if (!isInString && !isInChar && !isInLineComment && !isInBlockComment)
bracketStack.Push (ch);
break;
case ')':
case ']':
case '}':
if (!isInString && !isInChar && !isInLineComment && !isInBlockComment)
if (bracketStack.Count > 0)
bracketStack.Pop ();
break;
case '\r':
case '\n':
isInLineComment = false;
break;
case '/':
if (isInBlockComment) {
if (i > 0 && document.GetCharAt (i - 1) == '*')
isInBlockComment = false;
} else if (!isInString && !isInChar && i + 1 < document.TextLength) {
char nextChar = document.GetCharAt (i + 1);
if (nextChar == '/')
isInLineComment = true;
if (!isInLineComment && nextChar == '*')
isInBlockComment = true;
}
break;
case '"':
if (!(isInChar || isInLineComment || isInBlockComment))
isInString = !isInString;
break;
case '\'':
if (!(isInString || isInLineComment || isInBlockComment))
isInChar = !isInChar;
break;
default :
break;
}
}
return bracketStack.Any (t => t == '{');
}
}
}

67
ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs

@ -199,46 +199,48 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion @@ -199,46 +199,48 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
#endregion
}
static CompletionDataList CreateProvider (string text, bool isCtrlSpace)
static CompletionDataList CreateProvider(string text, bool isCtrlSpace)
{
string parsedText;
string editorText;
int cursorPosition = text.IndexOf ('$');
int endPos = text.IndexOf ('$', cursorPosition + 1);
int cursorPosition = text.IndexOf('$');
int endPos = text.IndexOf('$', cursorPosition + 1);
if (endPos == -1) {
parsedText = editorText = text.Substring (0, cursorPosition) + text.Substring (cursorPosition + 1);
parsedText = editorText = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1);
} else {
parsedText = text.Substring (0, cursorPosition) + new string (' ', endPos - cursorPosition) + text.Substring (endPos + 1);
editorText = text.Substring (0, cursorPosition) + text.Substring (cursorPosition + 1, endPos - cursorPosition - 1) + text.Substring (endPos + 1);
parsedText = text.Substring(0, cursorPosition) + new string(' ', endPos - cursorPosition) + text.Substring(endPos + 1);
editorText = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1, endPos - cursorPosition - 1) + text.Substring(endPos + 1);
cursorPosition = endPos - 1;
}
var doc = new ReadOnlyDocument (editorText);
var doc = new ReadOnlyDocument(editorText);
IProjectContent pctx = new CSharpProjectContent ();
pctx = pctx.AddAssemblyReferences (new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore });
IProjectContent pctx = new CSharpProjectContent();
pctx = pctx.AddAssemblyReferences(new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore });
var compilationUnit = new CSharpParser ().Parse (parsedText, "program.cs");
compilationUnit.Freeze ();
var compilationUnit = new CSharpParser().Parse(parsedText, "program.cs");
compilationUnit.Freeze();
var parsedFile = compilationUnit.ToTypeSystem ();
pctx = pctx.UpdateProjectContent (null, parsedFile);
var parsedFile = compilationUnit.ToTypeSystem();
pctx = pctx.UpdateProjectContent(null, parsedFile);
var cmp = pctx.CreateCompilation ();
var loc = doc.GetLocation (cursorPosition);
var cmp = pctx.CreateCompilation();
var loc = doc.GetLocation(cursorPosition);
var rctx = new CSharpTypeResolveContext (cmp.MainAssembly);
rctx = rctx.WithUsingScope (parsedFile.GetUsingScope (loc).Resolve (cmp));
var rctx = new CSharpTypeResolveContext(cmp.MainAssembly);
rctx = rctx.WithUsingScope(parsedFile.GetUsingScope(loc).Resolve(cmp));
var curDef = parsedFile.GetInnermostTypeDefinition (loc);
var curDef = parsedFile.GetInnermostTypeDefinition(loc);
if (curDef != null) {
var resolvedDef = curDef.Resolve (rctx).GetDefinition ();
rctx = rctx.WithCurrentTypeDefinition (resolvedDef);
var curMember = resolvedDef.Members.FirstOrDefault (m => m.Region.Begin <= loc && loc < m.BodyRegion.End);
if (curMember != null)
rctx = rctx.WithCurrentMember (curMember);
var resolvedDef = curDef.Resolve(rctx).GetDefinition();
rctx = rctx.WithCurrentTypeDefinition(resolvedDef);
var curMember = resolvedDef.Members.FirstOrDefault(m => m.Region.Begin <= loc && loc < m.BodyRegion.End);
if (curMember != null) {
rctx = rctx.WithCurrentMember(curMember);
}
}
var engine = new CSharpCompletionEngine (doc, new TestFactory (), pctx, rctx, compilationUnit, parsedFile);
var mb = new DefaultMemberProvider(doc, parsedFile);
var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, rctx, compilationUnit, parsedFile);
engine.EolMarker = Environment.NewLine;
engine.FormattingPolicy = FormattingOptionsFactory.CreateMono ();
@ -253,17 +255,18 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion @@ -253,17 +255,18 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
};
}
Tuple<ReadOnlyDocument, CSharpCompletionEngine> GetContent (string text, CompilationUnit compilationUnit)
Tuple<ReadOnlyDocument, CSharpCompletionEngine> GetContent(string text, CompilationUnit compilationUnit)
{
var doc = new ReadOnlyDocument (text);
IProjectContent pctx = new CSharpProjectContent ();
pctx = pctx.AddAssemblyReferences (new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore });
var parsedFile = compilationUnit.ToTypeSystem ();
var doc = new ReadOnlyDocument(text);
IProjectContent pctx = new CSharpProjectContent();
pctx = pctx.AddAssemblyReferences(new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore });
var parsedFile = compilationUnit.ToTypeSystem();
pctx = pctx.UpdateProjectContent (null, parsedFile);
var cmp = pctx.CreateCompilation ();
pctx = pctx.UpdateProjectContent(null, parsedFile);
var cmp = pctx.CreateCompilation();
var engine = new CSharpCompletionEngine (doc, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly), compilationUnit, parsedFile);
var mb = new DefaultMemberProvider(doc, parsedFile);
var engine = new CSharpCompletionEngine (doc, mb, new TestFactory (), pctx, new CSharpTypeResolveContext (cmp.MainAssembly), compilationUnit, parsedFile);
engine.EolMarker = Environment.NewLine;
engine.FormattingPolicy = FormattingOptionsFactory.CreateMono ();
return Tuple.Create (doc, engine);

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

@ -254,43 +254,45 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion @@ -254,43 +254,45 @@ namespace ICSharpCode.NRefactory.CSharp.CodeCompletion
#endregion
}
internal static IParameterDataProvider CreateProvider (string text)
internal static IParameterDataProvider CreateProvider(string text)
{
string parsedText;
string editorText;
int cursorPosition = text.IndexOf ('$');
int endPos = text.IndexOf ('$', cursorPosition + 1);
if (endPos == -1)
parsedText = editorText = text.Substring (0, cursorPosition) + text.Substring (cursorPosition + 1);
else {
parsedText = text.Substring (0, cursorPosition) + new string (' ', endPos - cursorPosition) + text.Substring (endPos + 1);
editorText = text.Substring (0, cursorPosition) + text.Substring (cursorPosition + 1, endPos - cursorPosition - 1) + text.Substring (endPos + 1);
int cursorPosition = text.IndexOf('$');
int endPos = text.IndexOf('$', cursorPosition + 1);
if (endPos == -1) {
parsedText = editorText = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1);
} else {
parsedText = text.Substring(0, cursorPosition) + new string(' ', endPos - cursorPosition) + text.Substring(endPos + 1);
editorText = text.Substring(0, cursorPosition) + text.Substring(cursorPosition + 1, endPos - cursorPosition - 1) + text.Substring(endPos + 1);
cursorPosition = endPos - 1;
}
var doc = new ReadOnlyDocument (editorText);
var doc = new ReadOnlyDocument(editorText);
IProjectContent pctx = new CSharpProjectContent ();
pctx = pctx.AddAssemblyReferences (new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore });
IProjectContent pctx = new CSharpProjectContent();
pctx = pctx.AddAssemblyReferences(new [] { CecilLoaderTests.Mscorlib, CecilLoaderTests.SystemCore });
var compilationUnit = new CSharpParser ().Parse (parsedText, "program.cs");
compilationUnit.Freeze ();
var compilationUnit = new CSharpParser().Parse(parsedText, "program.cs");
compilationUnit.Freeze();
var parsedFile = compilationUnit.ToTypeSystem ();
pctx = pctx.UpdateProjectContent (null, parsedFile);
var cmp = pctx.CreateCompilation ();
var loc = doc.GetLocation (cursorPosition);
var parsedFile = compilationUnit.ToTypeSystem();
pctx = pctx.UpdateProjectContent(null, parsedFile);
var cmp = pctx.CreateCompilation();
var loc = doc.GetLocation(cursorPosition);
var rctx = new CSharpTypeResolveContext (cmp.MainAssembly);
rctx = rctx.WithUsingScope (parsedFile.GetUsingScope (loc).Resolve (cmp));
var curDef = parsedFile.GetInnermostTypeDefinition (loc);
var rctx = new CSharpTypeResolveContext(cmp.MainAssembly);
rctx = rctx.WithUsingScope(parsedFile.GetUsingScope(loc).Resolve(cmp));
var curDef = parsedFile.GetInnermostTypeDefinition(loc);
if (curDef != null) {
rctx = rctx.WithCurrentTypeDefinition (curDef.Resolve (rctx).GetDefinition ());
var curMember = parsedFile.GetMember (loc);
if (curMember != null)
rctx = rctx.WithCurrentMember (curMember.CreateResolved (rctx));
rctx = rctx.WithCurrentTypeDefinition(curDef.Resolve(rctx).GetDefinition());
var curMember = parsedFile.GetMember(loc);
if (curMember != null) {
rctx = rctx.WithCurrentMember(curMember.CreateResolved(rctx));
}
}
var engine = new CSharpParameterCompletionEngine (doc, new TestFactory (pctx), pctx, rctx, compilationUnit, parsedFile);
var mb = new DefaultMemberProvider(doc, parsedFile);
var engine = new CSharpParameterCompletionEngine (doc, mb, new TestFactory (pctx), pctx, rctx, compilationUnit, parsedFile);
return engine.GetParameterDataProvider (cursorPosition, doc.GetCharAt (cursorPosition - 1));
}

Loading…
Cancel
Save