Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.

Commit 0c7ba63

Browse files
fix #498: Additional problems in DebuggerDotCompletion
fix #460: Debugger console: No completion inside constructors
1 parent b4f4f71 commit 0c7ba63

12 files changed

Lines changed: 388 additions & 388 deletions

File tree

src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
<Compile Include="Src\CSharpSemanticHighlighterVisitor.cs">
9292
<DependentUpon>CSharpSemanticHighlighter.cs</DependentUpon>
9393
</Compile>
94+
<Compile Include="Src\CSharpTextEditorExtension.cs" />
9495
<Compile Include="Src\FormattingStrategy\CSharpFormattingOptionsContainer.cs" />
9596
<Compile Include="Src\FormattingStrategy\CSharpFormatter.cs" />
9697
<Compile Include="Src\FormattingStrategy\CSharpFormattingPolicies.cs" />

src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs

Lines changed: 80 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,18 @@
2020
using System.Collections.Generic;
2121

2222
using System.ComponentModel;
23+
using System.Linq;
2324
using System.Reflection;
2425
using System.Threading;
2526
using ICSharpCode.AvalonEdit;
2627
using ICSharpCode.AvalonEdit.Highlighting;
2728
using ICSharpCode.NRefactory;
29+
using ICSharpCode.NRefactory.CSharp;
30+
using ICSharpCode.NRefactory.CSharp.Refactoring;
31+
using ICSharpCode.NRefactory.Editor;
2832
using ICSharpCode.NRefactory.TypeSystem;
2933
using ICSharpCode.SharpDevelop.Editor.CodeCompletion;
34+
using ICSharpCode.SharpDevelop.Project;
3035
using CSharpBinding.Completion;
3136
using CSharpBinding.FormattingStrategy;
3237
using CSharpBinding.Refactoring;
@@ -50,223 +55,98 @@ public CSharpLanguageBinding()
5055
this.container.AddService(typeof(System.CodeDom.Compiler.CodeDomProvider), new Microsoft.CSharp.CSharpCodeProvider());
5156
}
5257

53-
public override ICodeCompletionBinding CreateCompletionBinding(FileName fileName, TextLocation currentLocation, ICSharpCode.NRefactory.Editor.ITextSource fileContent)
58+
public override ICodeCompletionBinding CreateCompletionBinding(string expressionToComplete, FileName fileName, TextLocation location, ICodeContext context)
5459
{
5560
if (fileName == null)
5661
throw new ArgumentNullException("fileName");
57-
return new CSharpCompletionBinding(fileName, currentLocation, fileContent);
58-
}
59-
}
60-
61-
public class CSharpTextEditorExtension : ITextEditorExtension
62-
{
63-
ITextEditor editor;
64-
IssueManager inspectionManager;
65-
IList<IContextActionProvider> contextActionProviders;
66-
CodeManipulation codeManipulation;
67-
CaretReferenceHighlightRenderer renderer;
68-
CodeEditorFormattingOptionsAdapter options;
69-
TextEditorOptions originalEditorOptions;
70-
71-
public void Attach(ITextEditor editor)
72-
{
73-
this.editor = editor;
74-
inspectionManager = new IssueManager(editor);
75-
codeManipulation = new CodeManipulation(editor);
76-
renderer = new CaretReferenceHighlightRenderer(editor);
77-
78-
// Patch editor options (indentation) to project-specific settings
79-
if (!editor.ContextActionProviders.IsReadOnly) {
80-
contextActionProviders = AddInTree.BuildItems<IContextActionProvider>("/SharpDevelop/ViewContent/TextEditor/C#/ContextActions", null);
81-
editor.ContextActionProviders.AddRange(contextActionProviders);
82-
}
83-
84-
// Create instance of options adapter and register it as service
85-
var formattingPolicy = CSharpFormattingPolicies.Instance.GetProjectOptions(
86-
SD.ProjectService.FindProjectContainingFile(editor.FileName));
87-
var textEditor = editor.GetService<TextEditor>();
88-
if (textEditor != null) {
89-
options = new CodeEditorFormattingOptionsAdapter(textEditor.Options, editor.Options, formattingPolicy.OptionsContainer);
90-
var textViewServices = textEditor.TextArea.TextView.Services;
91-
92-
// Unregister any previous ITextEditorOptions instance from editor, if existing, register our impl.
93-
textViewServices.RemoveService(typeof(ITextEditorOptions));
94-
textViewServices.AddService(typeof(ITextEditorOptions), options);
95-
96-
// Set TextEditor's options to same object
97-
originalEditorOptions = textEditor.Options;
98-
textEditor.Options = options.TextEditorOptions;
99-
}
62+
if (context == null)
63+
throw new ArgumentNullException("context");
64+
string content = GeneratePartialClassContextStub(fileName, location, context);
65+
const string caretPoint = "$__Caret_Point__$;";
66+
int caretOffset = content.IndexOf(caretPoint, StringComparison.Ordinal) + expressionToComplete.Length;
67+
SD.Log.DebugFormatted("context used for dot completion: {0}", content.Replace(caretPoint, "$" + expressionToComplete + "|$"));
68+
var doc = new ReadOnlyDocument(content.Replace(caretPoint, expressionToComplete));
69+
return new CSharpCompletionBinding(fileName, doc.GetLocation(caretOffset), doc.CreateSnapshot());
10070
}
10171

102-
public void Detach()
72+
static string GeneratePartialClassContextStub(FileName fileName, TextLocation location, ICodeContext context)
10373
{
104-
var textEditor = editor.GetService<TextEditor>();
105-
if (textEditor != null) {
106-
var textView = textEditor.TextArea.TextView;
107-
108-
// Unregister our ITextEditorOptions instance from editor
109-
var optionsService = textView.GetService<ITextEditorOptions>();
110-
if ((optionsService != null) && (optionsService == options))
111-
textView.Services.RemoveService(typeof(ITextEditorOptions));
112-
113-
// Reset TextEditor options, too?
114-
if ((textEditor.Options != null) && (textEditor.Options == options.TextEditorOptions))
115-
textEditor.Options = originalEditorOptions;
116-
}
117-
118-
codeManipulation.Dispose();
119-
if (inspectionManager != null) {
120-
inspectionManager.Dispose();
121-
inspectionManager = null;
122-
}
123-
if (contextActionProviders != null) {
124-
editor.ContextActionProviders.RemoveAll(contextActionProviders.Contains);
74+
var compilation = SD.ParserService.GetCompilationForFile(fileName);
75+
var file = SD.ParserService.GetExistingUnresolvedFile(fileName);
76+
if (compilation == null || file == null)
77+
return "";
78+
var unresolvedMember = file.GetMember(location);
79+
if (unresolvedMember == null)
80+
return "";
81+
var member = unresolvedMember.Resolve(new SimpleTypeResolveContext(compilation.MainAssembly));
82+
if (member == null)
83+
return "";
84+
var builder = new TypeSystemAstBuilder();
85+
MethodDeclaration decl;
86+
if (unresolvedMember is IMethod) {
87+
// If it's a method, convert it directly (including parameters + type parameters)
88+
decl = (MethodDeclaration)builder.ConvertEntity(member);
89+
} else {
90+
// Otherwise, create a method anyways, and copy the parameters
91+
decl = new MethodDeclaration();
92+
if (member is IParameterizedMember) {
93+
foreach (var p in ((IParameterizedMember)member).Parameters) {
94+
decl.Parameters.Add(builder.ConvertParameter(p));
95+
}
96+
}
12597
}
126-
renderer.Dispose();
127-
options = null;
128-
this.editor = null;
129-
}
130-
}
131-
132-
class CodeEditorFormattingOptionsAdapter : ITextEditorOptions, INotifyPropertyChanged
133-
{
134-
CSharpFormattingOptionsContainer container;
135-
readonly TextEditorOptions avalonEditOptions;
136-
readonly TextEditorOptions originalAvalonEditOptions;
137-
readonly ITextEditorOptions originalSDOptions;
138-
139-
public CodeEditorFormattingOptionsAdapter(TextEditorOptions originalAvalonEditOptions, ITextEditorOptions originalSDOptions, CSharpFormattingOptionsContainer container)
140-
{
141-
if (originalAvalonEditOptions == null)
142-
throw new ArgumentNullException("originalAvalonEditOptions");
143-
if (originalSDOptions == null)
144-
throw new ArgumentNullException("originalSDOptions");
145-
if (container == null)
146-
throw new ArgumentNullException("container");
147-
148-
this.originalAvalonEditOptions = originalAvalonEditOptions;
149-
this.avalonEditOptions = new TextEditorOptions(originalAvalonEditOptions);
150-
this.originalSDOptions = originalSDOptions;
151-
this.container = container;
152-
153-
// Update overridden options once
154-
UpdateOverriddenProperties();
155-
156-
CSharpFormattingPolicies.Instance.FormattingPolicyUpdated += OnFormattingPolicyUpdated;
157-
this.originalAvalonEditOptions.PropertyChanged += OnOrigAvalonOptionsPropertyChanged;
158-
this.originalSDOptions.PropertyChanged += OnSDOptionsPropertyChanged;
159-
}
160-
161-
void OnFormattingPolicyUpdated(object sender, CSharpBinding.FormattingStrategy.CSharpFormattingPolicyUpdateEventArgs e)
162-
{
163-
// Update editor options from changed policy
164-
UpdateOverriddenProperties();
165-
166-
OnPropertyChanged("IndentationSize");
167-
OnPropertyChanged("IndentationString");
168-
OnPropertyChanged("ConvertTabsToSpaces");
98+
decl.Name = "__DebuggerStub__";
99+
decl.ReturnType = builder.ConvertType(member.ReturnType);
100+
decl.Modifiers = unresolvedMember.IsStatic ? Modifiers.Static : Modifiers.None;
101+
// Make the method look like an explicit interface implementation so that it doesn't appear in CC
102+
decl.PrivateImplementationType = new SimpleType("__DummyType__");
103+
decl.Body = GenerateBodyFromContext(builder, context.LocalVariables.ToArray());
104+
return WrapInType(unresolvedMember.DeclaringTypeDefinition, decl).ToString();
169105
}
170-
171-
void UpdateOverriddenProperties()
106+
107+
static BlockStatement GenerateBodyFromContext(TypeSystemAstBuilder builder, IVariable[] variables)
172108
{
173-
avalonEditOptions.IndentationSize = container.GetEffectiveIndentationSize() ?? originalSDOptions.IndentationSize;
174-
avalonEditOptions.ConvertTabsToSpaces = container.GetEffectiveConvertTabsToSpaces() ?? originalSDOptions.ConvertTabsToSpaces;
109+
var body = new BlockStatement();
110+
foreach (var v in variables)
111+
body.Statements.Add(new VariableDeclarationStatement(builder.ConvertType(v.Type), v.Name));
112+
body.Statements.Add(new ExpressionStatement(new IdentifierExpression("$__Caret_Point__$")));
113+
return body;
175114
}
176115

177-
void OnOrigAvalonOptionsPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
116+
static AstNode WrapInType(IUnresolvedTypeDefinition entity, EntityDeclaration decl)
178117
{
179-
if ((e.PropertyName != "IndentationSize") && (e.PropertyName != "IndentationString") && (e.PropertyName != "ConvertTabsToSpaces")) {
180-
// Update values in our own TextEditorOptions instance
181-
PropertyInfo propertyInfo = typeof(TextEditorOptions).GetProperty(e.PropertyName);
182-
if (propertyInfo != null) {
183-
propertyInfo.SetValue(avalonEditOptions, propertyInfo.GetValue(originalAvalonEditOptions));
118+
if (entity == null)
119+
return decl;
120+
// Wrap decl in TypeDeclaration
121+
decl = new TypeDeclaration {
122+
ClassType = GetClassType(entity),
123+
Modifiers = Modifiers.Partial,
124+
Name = entity.Name,
125+
Members = { decl }
126+
};
127+
if (entity.DeclaringTypeDefinition != null) {
128+
// Handle nested types
129+
return WrapInType(entity.DeclaringTypeDefinition, decl);
130+
}
131+
if (string.IsNullOrEmpty(entity.Namespace))
132+
return decl;
133+
return new NamespaceDeclaration(entity.Namespace) {
134+
Members = {
135+
decl
184136
}
185-
} else {
186-
UpdateOverriddenProperties();
187-
}
188-
OnPropertyChanged(e.PropertyName);
137+
};
189138
}
190139

191-
void OnSDOptionsPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
192-
{
193-
OnPropertyChanged(e.PropertyName);
194-
}
195-
196-
public event PropertyChangedEventHandler PropertyChanged;
197-
198-
void OnPropertyChanged(string propertyName)
199-
{
200-
if (PropertyChanged != null) {
201-
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
202-
}
203-
}
204-
205-
public TextEditorOptions TextEditorOptions
140+
static ClassType GetClassType(IUnresolvedTypeDefinition entity)
206141
{
207-
get {
208-
return avalonEditOptions;
209-
}
210-
}
211-
212-
#region Overridden properties
213-
214-
public int IndentationSize {
215-
get {
216-
// Get value from own TextEditorOptions instance
217-
return avalonEditOptions.IndentationSize;
218-
}
219-
}
220-
221-
public string IndentationString {
222-
get {
223-
// Get value from own TextEditorOptions instance
224-
return avalonEditOptions.IndentationString;
225-
}
226-
}
227-
228-
public bool ConvertTabsToSpaces {
229-
get {
230-
// Get value from own TextEditorOptions instance
231-
return avalonEditOptions.ConvertTabsToSpaces;
232-
}
233-
}
234-
235-
#endregion
236-
237-
#region Rest of ITextEditorOptions implementation
238-
239-
public bool AutoInsertBlockEnd {
240-
get {
241-
return originalSDOptions.AutoInsertBlockEnd;
242-
}
243-
}
244-
245-
public int VerticalRulerColumn {
246-
get {
247-
return originalSDOptions.VerticalRulerColumn;
142+
switch (entity.Kind) {
143+
case TypeKind.Interface:
144+
return ClassType.Interface;
145+
case TypeKind.Struct:
146+
return ClassType.Struct;
147+
default:
148+
return ClassType.Class;
248149
}
249150
}
250-
251-
public bool UnderlineErrors {
252-
get {
253-
return originalSDOptions.UnderlineErrors;
254-
}
255-
}
256-
257-
public string FontFamily {
258-
get {
259-
return originalSDOptions.FontFamily;
260-
}
261-
}
262-
263-
public double FontSize {
264-
get {
265-
return originalSDOptions.FontSize;
266-
}
267-
}
268-
269-
#endregion
270-
271151
}
272152
}

0 commit comments

Comments
 (0)