~ubuntu-branches/ubuntu/saucy/monodevelop/saucy-proposed

« back to all changes in this revision

Viewing changes to src/addins/CSharpBinding/MonoDevelop.CSharp.Resolver/TextEditorResolverProvider.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2010-09-10 16:54:48 UTC
  • mfrom: (19.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20100910165448-0rybfk25zd4o9431
Tags: 2.4+dfsg-2
* debian/patches/inject_Mono.Debugger.Soft_source.patch,
  debian/patches/use_system_Mono.Debugger.Soft.patch,
  debian/control:
  + Build against system Soft Debugger, since we now have a new
    enough Mono to match MonoDevelop's required API

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// 
 
2
// TextEditorResolverProvider.cs
 
3
//  
 
4
// Author:
 
5
//       Mike Krüger <mkrueger@novell.com>
 
6
// 
 
7
// Copyright (c) 2010 Novell, Inc (http://www.novell.com)
 
8
// 
 
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
 
10
// of this software and associated documentation files (the "Software"), to deal
 
11
// in the Software without restriction, including without limitation the rights
 
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
13
// copies of the Software, and to permit persons to whom the Software is
 
14
// furnished to do so, subject to the following conditions:
 
15
// 
 
16
// The above copyright notice and this permission notice shall be included in
 
17
// all copies or substantial portions of the Software.
 
18
// 
 
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
25
// THE SOFTWARE.
 
26
using System;
 
27
using MonoDevelop.Ide.Gui.Content;
 
28
using MonoDevelop.Core;
 
29
using MonoDevelop.Projects.Dom.Parser;
 
30
using MonoDevelop.Projects.Dom;
 
31
using Mono.TextEditor;
 
32
using System.Text;
 
33
using MonoDevelop.Ide.Gui;
 
34
using MonoDevelop.Projects.Dom.Output;
 
35
using MonoDevelop.Ide;
 
36
 
 
37
namespace MonoDevelop.CSharp.Resolver
 
38
{
 
39
        public class TextEditorResolverProvider : ITextEditorResolverProvider
 
40
        {
 
41
                #region ITextEditorResolverProvider implementation
 
42
                
 
43
                public MonoDevelop.Projects.Dom.ResolveResult GetLanguageItem (ProjectDom dom, Mono.TextEditor.TextEditorData data, int offset)
 
44
                {
 
45
                        string fileName = data.Document.FileName;
 
46
                        
 
47
                        IParser parser = ProjectDomService.GetParser (fileName, data.Document.MimeType);
 
48
                        if (parser == null)
 
49
                                return null;
 
50
                        
 
51
                        MonoDevelop.Ide.Gui.Document doc = IdeApp.Workbench.ActiveDocument;
 
52
                        if (doc == null)
 
53
                                return null;
 
54
                        
 
55
                        IResolver         resolver = parser.CreateResolver (dom, doc, fileName);
 
56
                        IExpressionFinder expressionFinder = parser.CreateExpressionFinder (dom);
 
57
                        if (resolver == null || expressionFinder == null) 
 
58
                                return null;
 
59
                        
 
60
                        string txt = data.Document.Text;
 
61
                        int wordEnd = offset;
 
62
                        while (wordEnd < txt.Length && (Char.IsLetterOrDigit (txt[wordEnd]) || txt[wordEnd] == '_'))
 
63
                                wordEnd++;
 
64
                        
 
65
                        ExpressionResult expressionResult = expressionFinder.FindExpression (txt, wordEnd);
 
66
                        if (expressionResult == null)
 
67
                                return null;
 
68
                        ResolveResult resolveResult;
 
69
                        DocumentLocation loc = data.Document.OffsetToLocation (offset);
 
70
                        string savedExpression = null;
 
71
                        
 
72
                        // special handling for 'var' "keyword"
 
73
                        if (expressionResult.ExpressionContext == ExpressionContext.IdentifierExpected && expressionResult.Expression != null && expressionResult.Expression.Trim () == "var") {
 
74
                                int endOffset = data.Document.LocationToOffset (expressionResult.Region.End.Line - 1, expressionResult.Region.End.Column - 1);
 
75
                                StringBuilder identifer = new StringBuilder ();
 
76
                                for (int i = endOffset; i >= 0 && i < data.Document.Length; i++) {
 
77
                                        char ch = data.Document.GetCharAt (i);
 
78
                                        if (Char.IsWhiteSpace (ch))
 
79
                                                continue;
 
80
                                        if (ch == '=')
 
81
                                                break;
 
82
                                        if (Char.IsLetterOrDigit (ch) || ch =='_') {
 
83
                                                identifer.Append (ch);
 
84
                                                continue;
 
85
                                        }
 
86
                                        identifer.Length = 0;
 
87
                                        break;
 
88
                                }
 
89
                                if (identifer.Length > 0) {
 
90
                                        expressionResult.Expression = identifer.ToString ();
 
91
                                        resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line + 1, loc.Column + 1));
 
92
                                        if (resolveResult != null) {
 
93
                                                resolveResult = new MemberResolveResult (dom.GetType (resolveResult.ResolvedType));
 
94
                                                return resolveResult;
 
95
                                        }
 
96
                                }
 
97
                        }
 
98
                        
 
99
                        if (expressionResult.ExpressionContext == ExpressionContext.Attribute) {
 
100
                                savedExpression = expressionResult.Expression;
 
101
                                expressionResult.Expression += "Attribute";
 
102
                                expressionResult.ExpressionContext = ExpressionContext.ObjectCreation;
 
103
                        } 
 
104
                        resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line + 1, loc.Column + 1));
 
105
                        
 
106
                        if (savedExpression != null && resolveResult == null) {
 
107
                                expressionResult.Expression = savedExpression;
 
108
                                resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line + 1, loc.Column + 1));
 
109
                        }
 
110
                        // Search for possible generic parameters.
 
111
//                      if (this.resolveResult == null || this.resolveResult.ResolvedType == null || String.IsNullOrEmpty (this.resolveResult.ResolvedType.Name)) {
 
112
                        if (!expressionResult.Region.IsEmpty) {
 
113
                                int j = data.Document.LocationToOffset (expressionResult.Region.End.Line - 1, expressionResult.Region.End.Column - 1);
 
114
                                int bracket = 0;
 
115
                                for (int i = j; i >= 0 && i < data.Document.Length; i++) {
 
116
                                        char ch = data.Document.GetCharAt (i);
 
117
                                        if (Char.IsWhiteSpace (ch))
 
118
                                                continue;
 
119
                                        if (ch == '<') {
 
120
                                                bracket++;
 
121
                                        } else if (ch == '>') {
 
122
                                                bracket--;
 
123
                                                if (bracket == 0) {
 
124
                                                        expressionResult.Expression += data.Document.GetTextBetween (j, i + 1);
 
125
                                                        expressionResult.ExpressionContext = ExpressionContext.ObjectCreation;
 
126
                                                        resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line + 1, loc.Column + 1));
 
127
                                                        break;
 
128
                                                }
 
129
                                        } else {
 
130
                                                if (bracket == 0)
 
131
                                                        break;
 
132
                                        }
 
133
                                }
 
134
                        }
 
135
                        
 
136
                        // To resolve method overloads the full expression must be parsed.
 
137
                        // ex.: Overload (1)/ Overload("one") - parsing "Overload" gives just a MethodResolveResult
 
138
                        // and for constructor initializers it's tried too to to resolve constructor overloads.
 
139
                        if (resolveResult is ThisResolveResult || 
 
140
                            resolveResult is BaseResolveResult || 
 
141
                            resolveResult is MethodResolveResult && ((MethodResolveResult)resolveResult).Methods.Count > 1) {
 
142
                                // put the search offset at the end of the invocation to be able to find the full expression
 
143
                                // the resolver finds it itself if spaces are between the method name and the argument opening parentheses.
 
144
                                while (wordEnd < txt.Length - 1 && Char.IsWhiteSpace (txt[wordEnd]))
 
145
                                        wordEnd++;
 
146
                                if (txt[wordEnd] == '(') {
 
147
                                        int matchingBracket = data.Document.GetMatchingBracketOffset (wordEnd);
 
148
                                        if (matchingBracket > 0)
 
149
                                                wordEnd = matchingBracket;
 
150
                                }
 
151
                                //Console.WriteLine (expressionFinder.FindFullExpression (txt, wordEnd));
 
152
                                ResolveResult possibleResult = resolver.Resolve (expressionFinder.FindFullExpression (txt, wordEnd), new DomLocation (loc.Line + 1, loc.Column + 1)) ?? resolveResult;
 
153
                                //Console.WriteLine ("possi:" + resolver.Resolve (expressionFinder.FindFullExpression (txt, wordEnd), new DomLocation (loc.Line + 1, loc.Column + 1)));
 
154
                                if (possibleResult is MethodResolveResult)
 
155
                                        resolveResult = possibleResult;
 
156
                        }
 
157
                        return resolveResult;
 
158
                }
 
159
                
 
160
                public MonoDevelop.Projects.Dom.ResolveResult GetLanguageItem (ProjectDom dom, Mono.TextEditor.TextEditorData data, int offset, string expression)
 
161
                {
 
162
                        string fileName = data.Document.FileName;
 
163
                        MonoDevelop.Ide.Gui.Document doc = IdeApp.Workbench.ActiveDocument;
 
164
                        if (doc == null)
 
165
                                return null;
 
166
                        
 
167
                        IParser parser = ProjectDomService.GetParser (fileName, data.Document.MimeType);
 
168
                        if (parser == null)
 
169
                                return null;
 
170
                        
 
171
                        IResolver         resolver = parser.CreateResolver (dom, doc, fileName);
 
172
                        IExpressionFinder expressionFinder = parser.CreateExpressionFinder (dom);
 
173
                        if (resolver == null || expressionFinder == null) 
 
174
                                return null;
 
175
                        string txt = data.Document.Text;
 
176
                        int wordEnd = offset;
 
177
                        while (wordEnd < txt.Length && (Char.IsLetterOrDigit (txt[wordEnd]) || txt[wordEnd] == '_'))
 
178
                                wordEnd++;
 
179
                        ExpressionResult expressionResult = new ExpressionResult (expression);
 
180
                        expressionResult.ExpressionContext = ExpressionContext.MethodBody;
 
181
                        
 
182
                        DocumentLocation loc = data.Document.OffsetToLocation (offset);
 
183
                        string savedExpression = null;
 
184
                        ResolveResult resolveResult;
 
185
                        
 
186
                        if (expressionResult.ExpressionContext == ExpressionContext.Attribute) {
 
187
                                savedExpression = expressionResult.Expression;
 
188
                                expressionResult.Expression += "Attribute";
 
189
                                expressionResult.ExpressionContext = ExpressionContext.ObjectCreation;
 
190
                        } 
 
191
                        resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line + 1, loc.Column + 1));
 
192
                        if (savedExpression != null && resolveResult == null) {
 
193
                                expressionResult.Expression = savedExpression;
 
194
                                resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line + 1, loc.Column + 1));
 
195
                        }
 
196
                        // Search for possible generic parameters.
 
197
//                      if (this.resolveResult == null || this.resolveResult.ResolvedType == null || String.IsNullOrEmpty (this.resolveResult.ResolvedType.Name)) {
 
198
                                int j = data.Document.LocationToOffset (expressionResult.Region.End.Line - 1, expressionResult.Region.End.Column - 1);
 
199
                                int bracket = 0;
 
200
                                for (int i = j; i >= 0 && i < data.Document.Length; i++) {
 
201
                                        char ch = data.Document.GetCharAt (i);
 
202
                                        if (Char.IsWhiteSpace (ch))
 
203
                                                continue;
 
204
                                        if (ch == '<') {
 
205
                                                bracket++;
 
206
                                        } else if (ch == '>') {
 
207
                                                bracket--;
 
208
                                                if (bracket == 0) {
 
209
                                                        expressionResult.Expression += data.Document.GetTextBetween (j, i + 1);
 
210
                                                        expressionResult.ExpressionContext = ExpressionContext.ObjectCreation;
 
211
                                                        resolveResult = resolver.Resolve (expressionResult, new DomLocation (loc.Line + 1, loc.Column + 1));
 
212
                                                        break;
 
213
                                                }
 
214
                                        } else {
 
215
                                                if (bracket == 0)
 
216
                                                        break;
 
217
                                        }
 
218
                                }
 
219
//                      }
 
220
                        
 
221
                        // To resolve method overloads the full expression must be parsed.
 
222
                        // ex.: Overload (1)/ Overload("one") - parsing "Overload" gives just a MethodResolveResult
 
223
                        if (resolveResult is MethodResolveResult) 
 
224
                                resolveResult = resolver.Resolve (expressionFinder.FindFullExpression (txt, wordEnd), new DomLocation (loc.Line + 1, loc.Column + 1)) ?? resolveResult;
 
225
                        return resolveResult;
 
226
                }
 
227
                
 
228
                
 
229
                static string paramStr = GettextCatalog.GetString ("Parameter");
 
230
                static string localStr = GettextCatalog.GetString ("Local variable");
 
231
                static string fieldStr = GettextCatalog.GetString ("Field");
 
232
                static string propertyStr = GettextCatalog.GetString ("Property");
 
233
                static string methodStr = GettextCatalog.GetString ("Method");
 
234
                static string typeStr = GettextCatalog.GetString ("Type");
 
235
                static string namespaceStr = GettextCatalog.GetString ("Namespace");
 
236
                
 
237
                public string CreateTooltip (ProjectDom dom, ICompilationUnit unit, MonoDevelop.Projects.Dom.ResolveResult result, string errorInformations, Ambience ambience, Gdk.ModifierType modifierState)
 
238
                {
 
239
                        OutputSettings settings = new OutputSettings (OutputFlags.ClassBrowserEntries | OutputFlags.IncludeParameterName | OutputFlags.IncludeKeywords | OutputFlags.IncludeMarkup | OutputFlags.UseFullName);
 
240
                        if ((Gdk.ModifierType.ShiftMask & modifierState) == Gdk.ModifierType.ShiftMask) {
 
241
                                settings.EmitNameCallback = delegate(INode domVisitable, ref string outString) {
 
242
                                        // crop used namespaces.
 
243
                                        if (unit != null) {
 
244
                                                int len = 0;
 
245
                                                foreach (IUsing u in unit.Usings) {
 
246
                                                        foreach (string ns in u.Namespaces) {
 
247
                                                                if (outString.StartsWith (ns + ".")) {
 
248
                                                                        len = Math.Max (len, ns.Length + 1);
 
249
                                                                }
 
250
                                                        }
 
251
                                                }
 
252
                                                string newName = outString.Substring (len);
 
253
                                                int count = 0;
 
254
                                                // check if there is a name clash.
 
255
                                                if (dom.GetType (newName) != null)
 
256
                                                        count++;
 
257
                                                foreach (IUsing u in unit.Usings) {
 
258
                                                        foreach (string ns in u.Namespaces) {
 
259
                                                                if (dom.GetType (ns + "." + newName) != null)
 
260
                                                                        count++;
 
261
                                                        }
 
262
                                                }
 
263
 
 
264
                                                if (len > 0 && count == 1)
 
265
                                                        outString = newName;
 
266
                                        }
 
267
                                };
 
268
                        }
 
269
 
 
270
                        // Approximate value for usual case
 
271
                        StringBuilder s = new StringBuilder (150);
 
272
                        string doc = null;
 
273
                        if (result != null) {
 
274
                                if (result is AggregatedResolveResult)
 
275
                                        result = ((AggregatedResolveResult)result).PrimaryResult;
 
276
                                if (result is ParameterResolveResult) {
 
277
                                        s.Append ("<small><i>");
 
278
                                        s.Append (paramStr);
 
279
                                        s.Append ("</i></small>\n");
 
280
                                        s.Append (ambience.GetString (((ParameterResolveResult)result).Parameter, settings));
 
281
                                } else if (result is LocalVariableResolveResult) {
 
282
                                        s.Append ("<small><i>");
 
283
                                        s.Append (localStr);
 
284
                                        s.Append ("</i></small>\n");
 
285
                                        s.Append (ambience.GetString (((LocalVariableResolveResult)result).ResolvedType, settings));
 
286
                                        s.Append (" ");
 
287
                                        s.Append (((LocalVariableResolveResult)result).LocalVariable.Name);
 
288
                                } else if (result is UnresolvedMemberResolveResult) {
 
289
                                        s.Append (String.Format (GettextCatalog.GetString ("Unresolved member '{0}'"), ((UnresolvedMemberResolveResult)result).MemberName));
 
290
                                } else if (result is MethodResolveResult) {
 
291
                                        MethodResolveResult mrr = (MethodResolveResult)result;
 
292
                                        s.Append("<small><i>");
 
293
                                        s.Append(methodStr);
 
294
                                        s.Append("</i></small>\n");
 
295
                                        s.Append(ambience.GetString(mrr.MostLikelyMethod, settings));
 
296
                                        if (mrr.Methods.Count > 1) {
 
297
                                                int overloadCount = mrr.Methods.Count - 1;
 
298
                                                s.Append(string.Format(GettextCatalog.GetPluralString(" (+{0} overload)", " (+{0} overloads)", overloadCount), overloadCount));
 
299
                                        }
 
300
                                        doc = AmbienceService.GetDocumentationSummary(((MethodResolveResult)result).MostLikelyMethod);
 
301
                                } else if (result is MemberResolveResult) {
 
302
                                        IMember member = ((MemberResolveResult)result).ResolvedMember;
 
303
                                        if (member == null) {
 
304
                                                IReturnType returnType = ((MemberResolveResult)result).ResolvedType;
 
305
                                                if (returnType != null) {
 
306
                                                        IType type = dom.GetType (returnType);
 
307
                                                        if (type != null) {
 
308
                                                                s.Append ("<small><i>");
 
309
                                                                s.Append (typeStr);
 
310
                                                                s.Append ("</i></small>\n");
 
311
                                                                s.Append (ambience.GetString (type, settings));
 
312
                                                                doc = AmbienceService.GetDocumentationSummary (type);
 
313
                                                        }
 
314
                                                }
 
315
                                        } else {
 
316
                                                if (member is IField) {
 
317
                                                        s.Append ("<small><i>");
 
318
                                                        s.Append (fieldStr);
 
319
                                                        s.Append ("</i></small>\n");
 
320
                                                } else if (member is IProperty) {
 
321
                                                        s.Append ("<small><i>");
 
322
                                                        s.Append (propertyStr);
 
323
                                                        s.Append ("</i></small>\n");
 
324
                                                }
 
325
                                                s.Append (ambience.GetString (member, settings));
 
326
                                                doc = AmbienceService.GetDocumentationSummary (member);
 
327
                                        }
 
328
                                } else if (result is NamespaceResolveResult) {
 
329
                                        s.Append ("<small><i>");
 
330
                                        s.Append (namespaceStr);
 
331
                                        s.Append ("</i></small>\n");
 
332
                                        s.Append (ambience.GetString (new Namespace (((NamespaceResolveResult)result).Namespace), settings));
 
333
                                } else {
 
334
                                        s.Append (ambience.GetString (result.ResolvedType, settings));
 
335
                                }
 
336
 
 
337
 
 
338
                                if (!string.IsNullOrEmpty (doc)) {
 
339
                                        s.Append ("\n<small>");
 
340
                                        s.Append (AmbienceService.GetDocumentationMarkup ( "<summary>" + doc +  "</summary>"));
 
341
                                        s.Append ("</small>");
 
342
                                }
 
343
                        }
 
344
                        
 
345
                        if (!string.IsNullOrEmpty (errorInformations)) {
 
346
                                if (s.Length != 0)
 
347
                                        s.Append ("\n\n");
 
348
                                s.Append ("<small>");
 
349
                                s.Append (errorInformations);
 
350
                                s.Append ("</small>");
 
351
                        }
 
352
                        return s.ToString ();
 
353
                }
 
354
                
 
355
                #endregion
 
356
        }
 
357
}
 
358