1 | // |
---|
2 | // report.cs: report errors and warnings. |
---|
3 | // |
---|
4 | // Author: Miguel de Icaza (miguel@ximian.com) |
---|
5 | // Marek Safar (marek.safar@gmail.com) |
---|
6 | // |
---|
7 | // Copyright 2001 Ximian, Inc. (http://www.ximian.com) |
---|
8 | // Copyright 2011 Xamarin, Inc (http://www.xamarin.com) |
---|
9 | // |
---|
10 | |
---|
11 | using System; |
---|
12 | using System.IO; |
---|
13 | using System.Text; |
---|
14 | using System.Collections.Generic; |
---|
15 | using System.Diagnostics; |
---|
16 | |
---|
17 | namespace Mono.CSharp { |
---|
18 | |
---|
19 | // |
---|
20 | // Errors and warnings manager |
---|
21 | // |
---|
22 | public class Report |
---|
23 | { |
---|
24 | public const int RuntimeErrorId = 10000; |
---|
25 | |
---|
26 | Dictionary<int, WarningRegions> warning_regions_table; |
---|
27 | |
---|
28 | ReportPrinter printer; |
---|
29 | |
---|
30 | int reporting_disabled; |
---|
31 | |
---|
32 | readonly CompilerSettings settings; |
---|
33 | |
---|
34 | /// <summary> |
---|
35 | /// List of symbols related to reported error/warning. You have to fill it before error/warning is reported. |
---|
36 | /// </summary> |
---|
37 | List<string> extra_information = new List<string> (); |
---|
38 | |
---|
39 | // |
---|
40 | // IF YOU ADD A NEW WARNING YOU HAVE TO ADD ITS ID HERE |
---|
41 | // |
---|
42 | public static readonly int[] AllWarnings = new int[] { |
---|
43 | 28, 67, 78, |
---|
44 | 105, 108, 109, 114, 162, 164, 168, 169, 183, 184, 197, |
---|
45 | 219, 251, 252, 253, 278, 282, |
---|
46 | 402, 414, 419, 420, 429, 436, 437, 440, 458, 464, 465, 467, 469, 472, 473, |
---|
47 | 612, 618, 626, 628, 642, 649, 652, 657, 658, 659, 660, 661, 665, 672, 675, 693, |
---|
48 | 728, |
---|
49 | 809, 824, |
---|
50 | 1030, 1058, 1060, 1066, |
---|
51 | 1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592, |
---|
52 | 1607, 1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692, 1695, 1696, 1697, 1699, |
---|
53 | 1700, 1701, 1702, 1709, 1711, 1717, 1718, 1720, 1735, |
---|
54 | 1901, 1956, 1981, 1998, |
---|
55 | 2002, 2023, 2029, |
---|
56 | 3000, 3001, 3002, 3003, 3005, 3006, 3007, 3008, 3009, |
---|
57 | 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019, |
---|
58 | 3021, 3022, 3023, 3024, 3026, 3027, |
---|
59 | 4014, 4024, 4025, 4026, |
---|
60 | 7035, 7080, 7081, 7082, 7095, |
---|
61 | 8009, |
---|
62 | }; |
---|
63 | |
---|
64 | static HashSet<int> AllWarningsHashSet; |
---|
65 | |
---|
66 | public Report (CompilerContext context, ReportPrinter printer) |
---|
67 | { |
---|
68 | if (context == null) |
---|
69 | throw new ArgumentNullException ("settings"); |
---|
70 | if (printer == null) |
---|
71 | throw new ArgumentNullException ("printer"); |
---|
72 | |
---|
73 | this.settings = context.Settings; |
---|
74 | this.printer = printer; |
---|
75 | } |
---|
76 | |
---|
77 | public void DisableReporting () |
---|
78 | { |
---|
79 | ++reporting_disabled; |
---|
80 | } |
---|
81 | |
---|
82 | public void EnableReporting () |
---|
83 | { |
---|
84 | --reporting_disabled; |
---|
85 | } |
---|
86 | |
---|
87 | public void FeatureIsNotAvailable (CompilerContext compiler, Location loc, string feature) |
---|
88 | { |
---|
89 | string version; |
---|
90 | switch (compiler.Settings.Version) { |
---|
91 | case LanguageVersion.ISO_1: |
---|
92 | version = "1.0"; |
---|
93 | break; |
---|
94 | case LanguageVersion.ISO_2: |
---|
95 | version = "2.0"; |
---|
96 | break; |
---|
97 | case LanguageVersion.V_3: |
---|
98 | version = "3.0"; |
---|
99 | break; |
---|
100 | case LanguageVersion.V_4: |
---|
101 | version = "4.0"; |
---|
102 | break; |
---|
103 | case LanguageVersion.V_5: |
---|
104 | version = "5.0"; |
---|
105 | break; |
---|
106 | case LanguageVersion.V_6: |
---|
107 | version = "6.0"; |
---|
108 | break; |
---|
109 | default: |
---|
110 | throw new InternalErrorException ("Invalid feature version", compiler.Settings.Version); |
---|
111 | } |
---|
112 | |
---|
113 | Error (1644, loc, |
---|
114 | "Feature `{0}' cannot be used because it is not part of the C# {1} language specification", |
---|
115 | feature, version); |
---|
116 | } |
---|
117 | |
---|
118 | public void FeatureIsNotSupported (Location loc, string feature) |
---|
119 | { |
---|
120 | Error (1644, loc, |
---|
121 | "Feature `{0}' is not supported in Mono mcs1 compiler. Consider using the `gmcs' compiler instead", |
---|
122 | feature); |
---|
123 | } |
---|
124 | |
---|
125 | public void RuntimeMissingSupport (Location loc, string feature) |
---|
126 | { |
---|
127 | Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature); |
---|
128 | } |
---|
129 | |
---|
130 | /// <summary> |
---|
131 | /// In most error cases is very useful to have information about symbol that caused the error. |
---|
132 | /// Call this method before you call Report.Error when it makes sense. |
---|
133 | /// </summary> |
---|
134 | public void SymbolRelatedToPreviousError (Location loc, string symbol) |
---|
135 | { |
---|
136 | SymbolRelatedToPreviousError (loc.ToString ()); |
---|
137 | } |
---|
138 | |
---|
139 | public void SymbolRelatedToPreviousError (MemberSpec ms) |
---|
140 | { |
---|
141 | if (reporting_disabled > 0 || !printer.HasRelatedSymbolSupport) |
---|
142 | return; |
---|
143 | |
---|
144 | var mc = ms.MemberDefinition as MemberCore; |
---|
145 | while (ms is ElementTypeSpec) { |
---|
146 | ms = ((ElementTypeSpec) ms).Element; |
---|
147 | mc = ms.MemberDefinition as MemberCore; |
---|
148 | } |
---|
149 | |
---|
150 | if (mc != null) { |
---|
151 | SymbolRelatedToPreviousError (mc); |
---|
152 | } else { |
---|
153 | if (ms.DeclaringType != null) |
---|
154 | ms = ms.DeclaringType; |
---|
155 | |
---|
156 | var imported_type = ms.MemberDefinition as ImportedTypeDefinition; |
---|
157 | if (imported_type != null) { |
---|
158 | var iad = imported_type.DeclaringAssembly as ImportedAssemblyDefinition; |
---|
159 | SymbolRelatedToPreviousError (iad.Location); |
---|
160 | } |
---|
161 | } |
---|
162 | } |
---|
163 | |
---|
164 | public void SymbolRelatedToPreviousError (MemberCore mc) |
---|
165 | { |
---|
166 | SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ()); |
---|
167 | } |
---|
168 | |
---|
169 | public void SymbolRelatedToPreviousError (string loc) |
---|
170 | { |
---|
171 | string msg = String.Format ("{0} (Location of the symbol related to previous ", loc); |
---|
172 | if (extra_information.Contains (msg)) |
---|
173 | return; |
---|
174 | |
---|
175 | extra_information.Add (msg); |
---|
176 | } |
---|
177 | |
---|
178 | public bool CheckWarningCode (int code, Location loc) |
---|
179 | { |
---|
180 | if (AllWarningsHashSet == null) |
---|
181 | AllWarningsHashSet = new HashSet<int> (AllWarnings); |
---|
182 | |
---|
183 | if (AllWarningsHashSet.Contains (code)) |
---|
184 | return true; |
---|
185 | |
---|
186 | Warning (1691, 1, loc, "`{0}' is not a valid warning number", code); |
---|
187 | return false; |
---|
188 | } |
---|
189 | |
---|
190 | public void ExtraInformation (Location loc, string msg) |
---|
191 | { |
---|
192 | extra_information.Add (String.Format ("{0} {1}", loc, msg)); |
---|
193 | } |
---|
194 | |
---|
195 | public WarningRegions RegisterWarningRegion (Location location) |
---|
196 | { |
---|
197 | WarningRegions regions; |
---|
198 | if (warning_regions_table == null) { |
---|
199 | regions = null; |
---|
200 | warning_regions_table = new Dictionary<int, WarningRegions> (); |
---|
201 | } else { |
---|
202 | warning_regions_table.TryGetValue (location.File, out regions); |
---|
203 | } |
---|
204 | |
---|
205 | if (regions == null) { |
---|
206 | regions = new WarningRegions (); |
---|
207 | warning_regions_table.Add (location.File, regions); |
---|
208 | } |
---|
209 | |
---|
210 | return regions; |
---|
211 | } |
---|
212 | |
---|
213 | public void Warning (int code, int level, Location loc, string message) |
---|
214 | { |
---|
215 | if (reporting_disabled > 0) |
---|
216 | return; |
---|
217 | |
---|
218 | if (!settings.IsWarningEnabled (code, level)) |
---|
219 | return; |
---|
220 | |
---|
221 | if (warning_regions_table != null && !loc.IsNull) { |
---|
222 | WarningRegions regions; |
---|
223 | if (warning_regions_table.TryGetValue (loc.File, out regions) && !regions.IsWarningEnabled (code, loc.Row)) |
---|
224 | return; |
---|
225 | } |
---|
226 | |
---|
227 | AbstractMessage msg; |
---|
228 | if (settings.IsWarningAsError (code)) { |
---|
229 | message = "Warning as Error: " + message; |
---|
230 | msg = new ErrorMessage (code, loc, message, extra_information); |
---|
231 | } else { |
---|
232 | msg = new WarningMessage (code, loc, message, extra_information); |
---|
233 | } |
---|
234 | |
---|
235 | extra_information.Clear (); |
---|
236 | printer.Print (msg, settings.ShowFullPaths); |
---|
237 | } |
---|
238 | |
---|
239 | public void Warning (int code, int level, Location loc, string format, string arg) |
---|
240 | { |
---|
241 | Warning (code, level, loc, String.Format (format, arg)); |
---|
242 | } |
---|
243 | |
---|
244 | public void Warning (int code, int level, Location loc, string format, string arg1, string arg2) |
---|
245 | { |
---|
246 | Warning (code, level, loc, String.Format (format, arg1, arg2)); |
---|
247 | } |
---|
248 | |
---|
249 | public void Warning (int code, int level, Location loc, string format, params object[] args) |
---|
250 | { |
---|
251 | Warning (code, level, loc, String.Format (format, args)); |
---|
252 | } |
---|
253 | |
---|
254 | public void Warning (int code, int level, string message) |
---|
255 | { |
---|
256 | Warning (code, level, Location.Null, message); |
---|
257 | } |
---|
258 | |
---|
259 | public void Warning (int code, int level, string format, string arg) |
---|
260 | { |
---|
261 | Warning (code, level, Location.Null, format, arg); |
---|
262 | } |
---|
263 | |
---|
264 | public void Warning (int code, int level, string format, string arg1, string arg2) |
---|
265 | { |
---|
266 | Warning (code, level, Location.Null, format, arg1, arg2); |
---|
267 | } |
---|
268 | |
---|
269 | public void Warning (int code, int level, string format, params string[] args) |
---|
270 | { |
---|
271 | Warning (code, level, Location.Null, String.Format (format, args)); |
---|
272 | } |
---|
273 | |
---|
274 | // |
---|
275 | // Warnings encountered so far |
---|
276 | // |
---|
277 | public int Warnings { |
---|
278 | get { return printer.WarningsCount; } |
---|
279 | } |
---|
280 | |
---|
281 | public void Error (int code, Location loc, string error) |
---|
282 | { |
---|
283 | if (reporting_disabled > 0) |
---|
284 | return; |
---|
285 | |
---|
286 | ErrorMessage msg = new ErrorMessage (code, loc, error, extra_information); |
---|
287 | extra_information.Clear (); |
---|
288 | |
---|
289 | printer.Print (msg, settings.ShowFullPaths); |
---|
290 | |
---|
291 | if (settings.Stacktrace) |
---|
292 | Console.WriteLine (FriendlyStackTrace (new StackTrace (true))); |
---|
293 | |
---|
294 | if (printer.ErrorsCount == settings.FatalCounter) |
---|
295 | throw new FatalException (msg.Text); |
---|
296 | } |
---|
297 | |
---|
298 | public void Error (int code, Location loc, string format, string arg) |
---|
299 | { |
---|
300 | Error (code, loc, String.Format (format, arg)); |
---|
301 | } |
---|
302 | |
---|
303 | public void Error (int code, Location loc, string format, string arg1, string arg2) |
---|
304 | { |
---|
305 | Error (code, loc, String.Format (format, arg1, arg2)); |
---|
306 | } |
---|
307 | |
---|
308 | public void Error (int code, Location loc, string format, params string[] args) |
---|
309 | { |
---|
310 | Error (code, loc, String.Format (format, args)); |
---|
311 | } |
---|
312 | |
---|
313 | public void Error (int code, string error) |
---|
314 | { |
---|
315 | Error (code, Location.Null, error); |
---|
316 | } |
---|
317 | |
---|
318 | public void Error (int code, string format, string arg) |
---|
319 | { |
---|
320 | Error (code, Location.Null, format, arg); |
---|
321 | } |
---|
322 | |
---|
323 | public void Error (int code, string format, string arg1, string arg2) |
---|
324 | { |
---|
325 | Error (code, Location.Null, format, arg1, arg2); |
---|
326 | } |
---|
327 | |
---|
328 | public void Error (int code, string format, params string[] args) |
---|
329 | { |
---|
330 | Error (code, Location.Null, String.Format (format, args)); |
---|
331 | } |
---|
332 | |
---|
333 | // |
---|
334 | // Errors encountered so far |
---|
335 | // |
---|
336 | public int Errors { |
---|
337 | get { return printer.ErrorsCount; } |
---|
338 | } |
---|
339 | |
---|
340 | public bool IsDisabled { |
---|
341 | get { |
---|
342 | return reporting_disabled > 0; |
---|
343 | } |
---|
344 | } |
---|
345 | |
---|
346 | public ReportPrinter Printer { |
---|
347 | get { return printer; } |
---|
348 | } |
---|
349 | |
---|
350 | public ReportPrinter SetPrinter (ReportPrinter printer) |
---|
351 | { |
---|
352 | ReportPrinter old = this.printer; |
---|
353 | this.printer = printer; |
---|
354 | return old; |
---|
355 | } |
---|
356 | |
---|
357 | [Conditional ("MCS_DEBUG")] |
---|
358 | static public void Debug (string message, params object[] args) |
---|
359 | { |
---|
360 | Debug (4, message, args); |
---|
361 | } |
---|
362 | |
---|
363 | [Conditional ("MCS_DEBUG")] |
---|
364 | static public void Debug (int category, string message, params object[] args) |
---|
365 | { |
---|
366 | // if ((category & DebugFlags) == 0) |
---|
367 | // return; |
---|
368 | |
---|
369 | StringBuilder sb = new StringBuilder (message); |
---|
370 | |
---|
371 | if ((args != null) && (args.Length > 0)) { |
---|
372 | sb.Append (": "); |
---|
373 | |
---|
374 | bool first = true; |
---|
375 | foreach (object arg in args) { |
---|
376 | if (first) |
---|
377 | first = false; |
---|
378 | else |
---|
379 | sb.Append (", "); |
---|
380 | if (arg == null) |
---|
381 | sb.Append ("null"); |
---|
382 | // else if (arg is ICollection) |
---|
383 | // sb.Append (PrintCollection ((ICollection) arg)); |
---|
384 | else |
---|
385 | sb.Append (arg); |
---|
386 | } |
---|
387 | } |
---|
388 | |
---|
389 | Console.WriteLine (sb.ToString ()); |
---|
390 | } |
---|
391 | /* |
---|
392 | static public string PrintCollection (ICollection collection) |
---|
393 | { |
---|
394 | StringBuilder sb = new StringBuilder (); |
---|
395 | |
---|
396 | sb.Append (collection.GetType ()); |
---|
397 | sb.Append ("("); |
---|
398 | |
---|
399 | bool first = true; |
---|
400 | foreach (object o in collection) { |
---|
401 | if (first) |
---|
402 | first = false; |
---|
403 | else |
---|
404 | sb.Append (", "); |
---|
405 | sb.Append (o); |
---|
406 | } |
---|
407 | |
---|
408 | sb.Append (")"); |
---|
409 | return sb.ToString (); |
---|
410 | } |
---|
411 | */ |
---|
412 | static string FriendlyStackTrace (StackTrace t) |
---|
413 | { |
---|
414 | StringBuilder sb = new StringBuilder (); |
---|
415 | |
---|
416 | bool foundUserCode = false; |
---|
417 | |
---|
418 | for (int i = 0; i < t.FrameCount; i++) { |
---|
419 | StackFrame f = t.GetFrame (i); |
---|
420 | var mb = f.GetMethod (); |
---|
421 | |
---|
422 | if (!foundUserCode && mb.ReflectedType == typeof (Report)) |
---|
423 | continue; |
---|
424 | |
---|
425 | foundUserCode = true; |
---|
426 | |
---|
427 | sb.Append ("\tin "); |
---|
428 | |
---|
429 | if (f.GetFileLineNumber () > 0) |
---|
430 | sb.AppendFormat ("(at {0}:{1}) ", f.GetFileName (), f.GetFileLineNumber ()); |
---|
431 | |
---|
432 | sb.AppendFormat ("{0}.{1} (", mb.ReflectedType.Name, mb.Name); |
---|
433 | |
---|
434 | bool first = true; |
---|
435 | foreach (var pi in mb.GetParameters ()) { |
---|
436 | if (!first) |
---|
437 | sb.Append (", "); |
---|
438 | first = false; |
---|
439 | |
---|
440 | sb.Append (pi.ParameterType.FullName); |
---|
441 | } |
---|
442 | sb.Append (")\n"); |
---|
443 | } |
---|
444 | |
---|
445 | return sb.ToString (); |
---|
446 | } |
---|
447 | } |
---|
448 | |
---|
449 | public abstract class AbstractMessage |
---|
450 | { |
---|
451 | readonly string[] extra_info; |
---|
452 | protected readonly int code; |
---|
453 | protected readonly Location location; |
---|
454 | readonly string message; |
---|
455 | |
---|
456 | protected AbstractMessage (int code, Location loc, string msg, List<string> extraInfo) |
---|
457 | { |
---|
458 | this.code = code; |
---|
459 | if (code < 0) |
---|
460 | this.code = 8000 - code; |
---|
461 | |
---|
462 | this.location = loc; |
---|
463 | this.message = msg; |
---|
464 | if (extraInfo.Count != 0) { |
---|
465 | this.extra_info = extraInfo.ToArray (); |
---|
466 | } |
---|
467 | } |
---|
468 | |
---|
469 | protected AbstractMessage (AbstractMessage aMsg) |
---|
470 | { |
---|
471 | this.code = aMsg.code; |
---|
472 | this.location = aMsg.location; |
---|
473 | this.message = aMsg.message; |
---|
474 | this.extra_info = aMsg.extra_info; |
---|
475 | } |
---|
476 | |
---|
477 | public int Code { |
---|
478 | get { return code; } |
---|
479 | } |
---|
480 | |
---|
481 | public override bool Equals (object obj) |
---|
482 | { |
---|
483 | AbstractMessage msg = obj as AbstractMessage; |
---|
484 | if (msg == null) |
---|
485 | return false; |
---|
486 | |
---|
487 | return code == msg.code && location.Equals (msg.location) && message == msg.message; |
---|
488 | } |
---|
489 | |
---|
490 | public override int GetHashCode () |
---|
491 | { |
---|
492 | return code.GetHashCode (); |
---|
493 | } |
---|
494 | |
---|
495 | public abstract bool IsWarning { get; } |
---|
496 | |
---|
497 | public Location Location { |
---|
498 | get { return location; } |
---|
499 | } |
---|
500 | |
---|
501 | public abstract string MessageType { get; } |
---|
502 | |
---|
503 | public string[] RelatedSymbols { |
---|
504 | get { return extra_info; } |
---|
505 | } |
---|
506 | |
---|
507 | public string Text { |
---|
508 | get { return message; } |
---|
509 | } |
---|
510 | } |
---|
511 | |
---|
512 | sealed class WarningMessage : AbstractMessage |
---|
513 | { |
---|
514 | public WarningMessage (int code, Location loc, string message, List<string> extra_info) |
---|
515 | : base (code, loc, message, extra_info) |
---|
516 | { |
---|
517 | } |
---|
518 | |
---|
519 | public override bool IsWarning { |
---|
520 | get { return true; } |
---|
521 | } |
---|
522 | |
---|
523 | public override string MessageType { |
---|
524 | get { |
---|
525 | return "warning"; |
---|
526 | } |
---|
527 | } |
---|
528 | } |
---|
529 | |
---|
530 | sealed class ErrorMessage : AbstractMessage |
---|
531 | { |
---|
532 | public ErrorMessage (int code, Location loc, string message, List<string> extraInfo) |
---|
533 | : base (code, loc, message, extraInfo) |
---|
534 | { |
---|
535 | } |
---|
536 | |
---|
537 | public ErrorMessage (AbstractMessage aMsg) |
---|
538 | : base (aMsg) |
---|
539 | { |
---|
540 | } |
---|
541 | |
---|
542 | public override bool IsWarning { |
---|
543 | get { return false; } |
---|
544 | } |
---|
545 | |
---|
546 | public override string MessageType { |
---|
547 | get { |
---|
548 | return "error"; |
---|
549 | } |
---|
550 | } |
---|
551 | } |
---|
552 | |
---|
553 | // |
---|
554 | // Generic base for any message writer |
---|
555 | // |
---|
556 | public abstract class ReportPrinter |
---|
557 | { |
---|
558 | protected HashSet<ITypeDefinition> reported_missing_definitions; |
---|
559 | |
---|
560 | #region Properties |
---|
561 | |
---|
562 | public int ErrorsCount { get; protected set; } |
---|
563 | |
---|
564 | public int WarningsCount { get; private set; } |
---|
565 | |
---|
566 | // |
---|
567 | // When (symbols related to previous ...) can be used |
---|
568 | // |
---|
569 | public virtual bool HasRelatedSymbolSupport { |
---|
570 | get { return true; } |
---|
571 | } |
---|
572 | |
---|
573 | #endregion |
---|
574 | |
---|
575 | |
---|
576 | protected virtual string FormatText (string txt) |
---|
577 | { |
---|
578 | return txt; |
---|
579 | } |
---|
580 | |
---|
581 | public virtual void Print (AbstractMessage msg, bool showFullPath) |
---|
582 | { |
---|
583 | if (msg.IsWarning) { |
---|
584 | ++WarningsCount; |
---|
585 | } else { |
---|
586 | ++ErrorsCount; |
---|
587 | } |
---|
588 | } |
---|
589 | |
---|
590 | protected void Print (AbstractMessage msg, TextWriter output, bool showFullPath) |
---|
591 | { |
---|
592 | StringBuilder txt = new StringBuilder (); |
---|
593 | if (!msg.Location.IsNull) { |
---|
594 | if (showFullPath) |
---|
595 | txt.Append (msg.Location.ToStringFullName ()); |
---|
596 | else |
---|
597 | txt.Append (msg.Location.ToString ()); |
---|
598 | |
---|
599 | txt.Append (" "); |
---|
600 | } |
---|
601 | |
---|
602 | txt.AppendFormat ("{0} CS{1:0000}: {2}", msg.MessageType, msg.Code, msg.Text); |
---|
603 | |
---|
604 | if (!msg.IsWarning) |
---|
605 | output.WriteLine (FormatText (txt.ToString ())); |
---|
606 | else |
---|
607 | output.WriteLine (txt.ToString ()); |
---|
608 | |
---|
609 | if (msg.RelatedSymbols != null) { |
---|
610 | foreach (string s in msg.RelatedSymbols) |
---|
611 | output.WriteLine (s + msg.MessageType + ")"); |
---|
612 | } |
---|
613 | } |
---|
614 | |
---|
615 | // |
---|
616 | // Tracks reported missing types. It needs to be session specific |
---|
617 | // because we can run in probing mode |
---|
618 | // |
---|
619 | public bool MissingTypeReported (ITypeDefinition typeDefinition) |
---|
620 | { |
---|
621 | if (reported_missing_definitions == null) |
---|
622 | reported_missing_definitions = new HashSet<ITypeDefinition> (); |
---|
623 | |
---|
624 | if (reported_missing_definitions.Contains (typeDefinition)) |
---|
625 | return true; |
---|
626 | |
---|
627 | reported_missing_definitions.Add (typeDefinition); |
---|
628 | return false; |
---|
629 | } |
---|
630 | |
---|
631 | public void Reset () |
---|
632 | { |
---|
633 | // HACK: Temporary hack for broken repl flow |
---|
634 | ErrorsCount = WarningsCount = 0; |
---|
635 | } |
---|
636 | } |
---|
637 | |
---|
638 | sealed class NullReportPrinter : ReportPrinter |
---|
639 | { |
---|
640 | } |
---|
641 | |
---|
642 | // |
---|
643 | // Default message recorder, it uses two types of message groups. |
---|
644 | // Common messages: messages reported in all sessions. |
---|
645 | // Merged messages: union of all messages in all sessions. |
---|
646 | // |
---|
647 | // Used by the Lambda expressions to compile the code with various |
---|
648 | // parameter values, or by attribute resolver |
---|
649 | // |
---|
650 | class SessionReportPrinter : ReportPrinter |
---|
651 | { |
---|
652 | List<AbstractMessage> session_messages; |
---|
653 | // |
---|
654 | // A collection of exactly same messages reported in all sessions |
---|
655 | // |
---|
656 | List<AbstractMessage> common_messages; |
---|
657 | |
---|
658 | // |
---|
659 | // A collection of unique messages reported in all sessions |
---|
660 | // |
---|
661 | List<AbstractMessage> merged_messages; |
---|
662 | |
---|
663 | bool showFullPaths; |
---|
664 | |
---|
665 | public void ClearSession () |
---|
666 | { |
---|
667 | session_messages = null; |
---|
668 | } |
---|
669 | |
---|
670 | public override void Print (AbstractMessage msg, bool showFullPath) |
---|
671 | { |
---|
672 | // |
---|
673 | // This line is useful when debugging recorded messages |
---|
674 | // |
---|
675 | // Console.WriteLine ("RECORDING: {0}", msg.Text); |
---|
676 | |
---|
677 | if (session_messages == null) |
---|
678 | session_messages = new List<AbstractMessage> (); |
---|
679 | |
---|
680 | session_messages.Add (msg); |
---|
681 | |
---|
682 | this.showFullPaths = showFullPath; |
---|
683 | base.Print (msg, showFullPath); |
---|
684 | } |
---|
685 | |
---|
686 | public void EndSession () |
---|
687 | { |
---|
688 | if (session_messages == null) |
---|
689 | return; |
---|
690 | |
---|
691 | // |
---|
692 | // Handles the first session |
---|
693 | // |
---|
694 | if (common_messages == null) { |
---|
695 | common_messages = new List<AbstractMessage> (session_messages); |
---|
696 | merged_messages = session_messages; |
---|
697 | session_messages = null; |
---|
698 | return; |
---|
699 | } |
---|
700 | |
---|
701 | // |
---|
702 | // Store common messages if any |
---|
703 | // |
---|
704 | for (int i = 0; i < common_messages.Count; ++i) { |
---|
705 | AbstractMessage cmsg = common_messages[i]; |
---|
706 | bool common_msg_found = false; |
---|
707 | foreach (AbstractMessage msg in session_messages) { |
---|
708 | if (cmsg.Equals (msg)) { |
---|
709 | common_msg_found = true; |
---|
710 | break; |
---|
711 | } |
---|
712 | } |
---|
713 | |
---|
714 | if (!common_msg_found) |
---|
715 | common_messages.RemoveAt (i); |
---|
716 | } |
---|
717 | |
---|
718 | // |
---|
719 | // Merge session and previous messages |
---|
720 | // |
---|
721 | for (int i = 0; i < session_messages.Count; ++i) { |
---|
722 | AbstractMessage msg = session_messages[i]; |
---|
723 | bool msg_found = false; |
---|
724 | for (int ii = 0; ii < merged_messages.Count; ++ii) { |
---|
725 | if (msg.Equals (merged_messages[ii])) { |
---|
726 | msg_found = true; |
---|
727 | break; |
---|
728 | } |
---|
729 | } |
---|
730 | |
---|
731 | if (!msg_found) |
---|
732 | merged_messages.Add (msg); |
---|
733 | } |
---|
734 | } |
---|
735 | |
---|
736 | public bool IsEmpty { |
---|
737 | get { |
---|
738 | return merged_messages == null && common_messages == null; |
---|
739 | } |
---|
740 | } |
---|
741 | |
---|
742 | // |
---|
743 | // Prints collected messages, common messages have a priority |
---|
744 | // |
---|
745 | public bool Merge (ReportPrinter dest) |
---|
746 | { |
---|
747 | var messages_to_print = merged_messages; |
---|
748 | if (common_messages != null && common_messages.Count > 0) { |
---|
749 | messages_to_print = common_messages; |
---|
750 | } |
---|
751 | |
---|
752 | if (messages_to_print == null) |
---|
753 | return false; |
---|
754 | |
---|
755 | bool error_msg = false; |
---|
756 | foreach (AbstractMessage msg in messages_to_print) { |
---|
757 | dest.Print (msg, showFullPaths); |
---|
758 | error_msg |= !msg.IsWarning; |
---|
759 | } |
---|
760 | |
---|
761 | if (reported_missing_definitions != null) { |
---|
762 | foreach (var missing in reported_missing_definitions) |
---|
763 | dest.MissingTypeReported (missing); |
---|
764 | } |
---|
765 | |
---|
766 | return error_msg; |
---|
767 | } |
---|
768 | } |
---|
769 | |
---|
770 | public class StreamReportPrinter : ReportPrinter |
---|
771 | { |
---|
772 | readonly TextWriter writer; |
---|
773 | |
---|
774 | public StreamReportPrinter (TextWriter writer) |
---|
775 | { |
---|
776 | this.writer = writer; |
---|
777 | } |
---|
778 | |
---|
779 | public override void Print (AbstractMessage msg, bool showFullPath) |
---|
780 | { |
---|
781 | Print (msg, writer, showFullPath); |
---|
782 | base.Print (msg, showFullPath); |
---|
783 | } |
---|
784 | } |
---|
785 | |
---|
786 | public class ConsoleReportPrinter : StreamReportPrinter |
---|
787 | { |
---|
788 | static readonly string prefix, postfix; |
---|
789 | |
---|
790 | static ConsoleReportPrinter () |
---|
791 | { |
---|
792 | string term = Environment.GetEnvironmentVariable ("TERM"); |
---|
793 | bool xterm_colors = false; |
---|
794 | |
---|
795 | switch (term){ |
---|
796 | case "xterm": |
---|
797 | case "rxvt": |
---|
798 | case "rxvt-unicode": |
---|
799 | if (Environment.GetEnvironmentVariable ("COLORTERM") != null){ |
---|
800 | xterm_colors = true; |
---|
801 | } |
---|
802 | break; |
---|
803 | |
---|
804 | case "xterm-color": |
---|
805 | case "xterm-256color": |
---|
806 | xterm_colors = true; |
---|
807 | break; |
---|
808 | } |
---|
809 | if (!xterm_colors) |
---|
810 | return; |
---|
811 | |
---|
812 | if (!(UnixUtils.isatty (1) && UnixUtils.isatty (2))) |
---|
813 | return; |
---|
814 | |
---|
815 | string config = Environment.GetEnvironmentVariable ("MCS_COLORS"); |
---|
816 | if (config == null){ |
---|
817 | config = "errors=red"; |
---|
818 | //config = "brightwhite,red"; |
---|
819 | } |
---|
820 | |
---|
821 | if (config == "disable") |
---|
822 | return; |
---|
823 | |
---|
824 | if (!config.StartsWith ("errors=")) |
---|
825 | return; |
---|
826 | |
---|
827 | config = config.Substring (7); |
---|
828 | |
---|
829 | int p = config.IndexOf (","); |
---|
830 | if (p == -1) |
---|
831 | prefix = GetForeground (config); |
---|
832 | else |
---|
833 | prefix = GetBackground (config.Substring (p+1)) + GetForeground (config.Substring (0, p)); |
---|
834 | postfix = "\x001b[0m"; |
---|
835 | } |
---|
836 | |
---|
837 | public ConsoleReportPrinter () |
---|
838 | : base (Console.Error) |
---|
839 | { |
---|
840 | } |
---|
841 | |
---|
842 | public ConsoleReportPrinter (TextWriter writer) |
---|
843 | : base (writer) |
---|
844 | { |
---|
845 | } |
---|
846 | |
---|
847 | static int NameToCode (string s) |
---|
848 | { |
---|
849 | switch (s) { |
---|
850 | case "black": |
---|
851 | return 0; |
---|
852 | case "red": |
---|
853 | return 1; |
---|
854 | case "green": |
---|
855 | return 2; |
---|
856 | case "yellow": |
---|
857 | return 3; |
---|
858 | case "blue": |
---|
859 | return 4; |
---|
860 | case "magenta": |
---|
861 | return 5; |
---|
862 | case "cyan": |
---|
863 | return 6; |
---|
864 | case "grey": |
---|
865 | case "white": |
---|
866 | return 7; |
---|
867 | } |
---|
868 | return 7; |
---|
869 | } |
---|
870 | |
---|
871 | // |
---|
872 | // maps a color name to its xterm color code |
---|
873 | // |
---|
874 | static string GetForeground (string s) |
---|
875 | { |
---|
876 | string highcode; |
---|
877 | |
---|
878 | if (s.StartsWith ("bright")) { |
---|
879 | highcode = "1;"; |
---|
880 | s = s.Substring (6); |
---|
881 | } else |
---|
882 | highcode = ""; |
---|
883 | |
---|
884 | return "\x001b[" + highcode + (30 + NameToCode (s)).ToString () + "m"; |
---|
885 | } |
---|
886 | |
---|
887 | static string GetBackground (string s) |
---|
888 | { |
---|
889 | return "\x001b[" + (40 + NameToCode (s)).ToString () + "m"; |
---|
890 | } |
---|
891 | |
---|
892 | protected override string FormatText (string txt) |
---|
893 | { |
---|
894 | if (prefix != null) |
---|
895 | return prefix + txt + postfix; |
---|
896 | |
---|
897 | return txt; |
---|
898 | } |
---|
899 | } |
---|
900 | |
---|
901 | class TimeReporter |
---|
902 | { |
---|
903 | public enum TimerType |
---|
904 | { |
---|
905 | ParseTotal, |
---|
906 | AssemblyBuilderSetup, |
---|
907 | CreateTypeTotal, |
---|
908 | ReferencesLoading, |
---|
909 | ReferencesImporting, |
---|
910 | PredefinedTypesInit, |
---|
911 | ModuleDefinitionTotal, |
---|
912 | EmitTotal, |
---|
913 | CloseTypes, |
---|
914 | Resouces, |
---|
915 | OutputSave, |
---|
916 | DebugSave, |
---|
917 | } |
---|
918 | |
---|
919 | readonly Stopwatch[] timers; |
---|
920 | Stopwatch total; |
---|
921 | |
---|
922 | public TimeReporter (bool enabled) |
---|
923 | { |
---|
924 | if (!enabled) |
---|
925 | return; |
---|
926 | |
---|
927 | timers = new Stopwatch[System.Enum.GetValues(typeof (TimerType)).Length]; |
---|
928 | } |
---|
929 | |
---|
930 | public void Start (TimerType type) |
---|
931 | { |
---|
932 | if (timers != null) { |
---|
933 | var sw = new Stopwatch (); |
---|
934 | timers[(int) type] = sw; |
---|
935 | sw.Start (); |
---|
936 | } |
---|
937 | } |
---|
938 | |
---|
939 | public void StartTotal () |
---|
940 | { |
---|
941 | total = new Stopwatch (); |
---|
942 | total.Start (); |
---|
943 | } |
---|
944 | |
---|
945 | public void Stop (TimerType type) |
---|
946 | { |
---|
947 | if (timers != null) { |
---|
948 | timers[(int) type].Stop (); |
---|
949 | } |
---|
950 | } |
---|
951 | |
---|
952 | public void StopTotal () |
---|
953 | { |
---|
954 | total.Stop (); |
---|
955 | } |
---|
956 | |
---|
957 | public void ShowStats () |
---|
958 | { |
---|
959 | if (timers == null) |
---|
960 | return; |
---|
961 | |
---|
962 | Dictionary<TimerType, string> timer_names = new Dictionary<TimerType,string> { |
---|
963 | { TimerType.ParseTotal, "Parsing source files" }, |
---|
964 | { TimerType.AssemblyBuilderSetup, "Assembly builder setup" }, |
---|
965 | { TimerType.CreateTypeTotal, "Compiled types created" }, |
---|
966 | { TimerType.ReferencesLoading, "Referenced assemblies loading" }, |
---|
967 | { TimerType.ReferencesImporting, "Referenced assemblies importing" }, |
---|
968 | { TimerType.PredefinedTypesInit, "Predefined types initialization" }, |
---|
969 | { TimerType.ModuleDefinitionTotal, "Module definition" }, |
---|
970 | { TimerType.EmitTotal, "Resolving and emitting members blocks" }, |
---|
971 | { TimerType.CloseTypes, "Module types closed" }, |
---|
972 | { TimerType.Resouces, "Embedding resources" }, |
---|
973 | { TimerType.OutputSave, "Writing output file" }, |
---|
974 | { TimerType.DebugSave, "Writing debug symbols file" }, |
---|
975 | }; |
---|
976 | |
---|
977 | int counter = 0; |
---|
978 | double percentage = (double) total.ElapsedMilliseconds / 100; |
---|
979 | long subtotal = total.ElapsedMilliseconds; |
---|
980 | foreach (var timer in timers) { |
---|
981 | string msg = timer_names[(TimerType) counter++]; |
---|
982 | var ms = timer == null ? 0 : timer.ElapsedMilliseconds; |
---|
983 | Console.WriteLine ("{0,4:0.0}% {1,5}ms {2}", ms / percentage, ms, msg); |
---|
984 | subtotal -= ms; |
---|
985 | } |
---|
986 | |
---|
987 | Console.WriteLine ("{0,4:0.0}% {1,5}ms Other tasks", subtotal / percentage, subtotal); |
---|
988 | Console.WriteLine (); |
---|
989 | Console.WriteLine ("Total elapsed time: {0}", total.Elapsed); |
---|
990 | } |
---|
991 | } |
---|
992 | |
---|
993 | public class InternalErrorException : Exception { |
---|
994 | public InternalErrorException (MemberCore mc, Exception e) |
---|
995 | : base (mc.Location + " " + mc.GetSignatureForError (), e) |
---|
996 | { |
---|
997 | } |
---|
998 | |
---|
999 | public InternalErrorException () |
---|
1000 | : base ("Internal error") |
---|
1001 | { |
---|
1002 | } |
---|
1003 | |
---|
1004 | public InternalErrorException (string message) |
---|
1005 | : base (message) |
---|
1006 | { |
---|
1007 | } |
---|
1008 | |
---|
1009 | public InternalErrorException (string message, params object[] args) |
---|
1010 | : base (String.Format (message, args)) |
---|
1011 | { |
---|
1012 | } |
---|
1013 | |
---|
1014 | public InternalErrorException (Exception exception, string message, params object[] args) |
---|
1015 | : base (String.Format (message, args), exception) |
---|
1016 | { |
---|
1017 | } |
---|
1018 | |
---|
1019 | public InternalErrorException (Exception e, Location loc) |
---|
1020 | : base (loc.ToString (), e) |
---|
1021 | { |
---|
1022 | } |
---|
1023 | } |
---|
1024 | |
---|
1025 | class FatalException : Exception |
---|
1026 | { |
---|
1027 | public FatalException (string message) |
---|
1028 | : base (message) |
---|
1029 | { |
---|
1030 | } |
---|
1031 | } |
---|
1032 | |
---|
1033 | /// <summary> |
---|
1034 | /// Handles #pragma warning |
---|
1035 | /// </summary> |
---|
1036 | public class WarningRegions { |
---|
1037 | |
---|
1038 | abstract class PragmaCmd |
---|
1039 | { |
---|
1040 | public int Line; |
---|
1041 | |
---|
1042 | protected PragmaCmd (int line) |
---|
1043 | { |
---|
1044 | Line = line; |
---|
1045 | } |
---|
1046 | |
---|
1047 | public abstract bool IsEnabled (int code, bool previous); |
---|
1048 | } |
---|
1049 | |
---|
1050 | class Disable : PragmaCmd |
---|
1051 | { |
---|
1052 | int code; |
---|
1053 | public Disable (int line, int code) |
---|
1054 | : base (line) |
---|
1055 | { |
---|
1056 | this.code = code; |
---|
1057 | } |
---|
1058 | |
---|
1059 | public override bool IsEnabled (int code, bool previous) |
---|
1060 | { |
---|
1061 | return this.code != code && previous; |
---|
1062 | } |
---|
1063 | } |
---|
1064 | |
---|
1065 | class DisableAll : PragmaCmd |
---|
1066 | { |
---|
1067 | public DisableAll (int line) |
---|
1068 | : base (line) {} |
---|
1069 | |
---|
1070 | public override bool IsEnabled(int code, bool previous) |
---|
1071 | { |
---|
1072 | return false; |
---|
1073 | } |
---|
1074 | } |
---|
1075 | |
---|
1076 | class Enable : PragmaCmd |
---|
1077 | { |
---|
1078 | int code; |
---|
1079 | public Enable (int line, int code) |
---|
1080 | : base (line) |
---|
1081 | { |
---|
1082 | this.code = code; |
---|
1083 | } |
---|
1084 | |
---|
1085 | public override bool IsEnabled(int code, bool previous) |
---|
1086 | { |
---|
1087 | return this.code == code || previous; |
---|
1088 | } |
---|
1089 | } |
---|
1090 | |
---|
1091 | class EnableAll : PragmaCmd |
---|
1092 | { |
---|
1093 | public EnableAll (int line) |
---|
1094 | : base (line) {} |
---|
1095 | |
---|
1096 | public override bool IsEnabled(int code, bool previous) |
---|
1097 | { |
---|
1098 | return true; |
---|
1099 | } |
---|
1100 | } |
---|
1101 | |
---|
1102 | |
---|
1103 | List<PragmaCmd> regions = new List<PragmaCmd> (); |
---|
1104 | |
---|
1105 | public void WarningDisable (int line) |
---|
1106 | { |
---|
1107 | regions.Add (new DisableAll (line)); |
---|
1108 | } |
---|
1109 | |
---|
1110 | public void WarningDisable (Location location, int code, Report Report) |
---|
1111 | { |
---|
1112 | if (Report.CheckWarningCode (code, location)) |
---|
1113 | regions.Add (new Disable (location.Row, code)); |
---|
1114 | } |
---|
1115 | |
---|
1116 | public void WarningEnable (int line) |
---|
1117 | { |
---|
1118 | regions.Add (new EnableAll (line)); |
---|
1119 | } |
---|
1120 | |
---|
1121 | public void WarningEnable (Location location, int code, CompilerContext context) |
---|
1122 | { |
---|
1123 | if (!context.Report.CheckWarningCode (code, location)) |
---|
1124 | return; |
---|
1125 | |
---|
1126 | if (context.Settings.IsWarningDisabledGlobally (code)) |
---|
1127 | context.Report.Warning (1635, 1, location, "Cannot restore warning `CS{0:0000}' because it was disabled globally", code); |
---|
1128 | |
---|
1129 | regions.Add (new Enable (location.Row, code)); |
---|
1130 | } |
---|
1131 | |
---|
1132 | public bool IsWarningEnabled (int code, int src_line) |
---|
1133 | { |
---|
1134 | bool result = true; |
---|
1135 | foreach (PragmaCmd pragma in regions) { |
---|
1136 | if (src_line < pragma.Line) |
---|
1137 | break; |
---|
1138 | |
---|
1139 | result = pragma.IsEnabled (code, result); |
---|
1140 | } |
---|
1141 | return result; |
---|
1142 | } |
---|
1143 | } |
---|
1144 | } |
---|