context: //
  // report.cs: report errors and warnings.
  //
  // Author: Miguel de Icaza (miguel@ximian.com)
  //         Marek Safar (marek.safar@seznam.cz)         
  //
  // Copyright 2001 Ximian, Inc. (http://www.ximian.com)
  //
  
  using System;
  using System.IO;
  using System.Text;
  using System.Collections.Generic;
  using System.Diagnostics;
  
  namespace Mono.CSharp {
  
  	//
  	// Errors and warnings manager
  	//
  	public class Report
  	{
  		/// <summary>  
  		///   Whether warnings should be considered errors
  		/// </summary>
  		public bool WarningsAreErrors;
  		List<int> warnings_as_error;
  		List<int> warnings_only;
  
  		public const int RuntimeErrorId = 10000;
  
  		//
  		// Keeps track of the warnings that we are ignoring
  		//
  		HashSet<int> warning_ignore_table;
  
  		Dictionary<int, WarningRegions> warning_regions_table;
  
  		int warning_level;
  
  		ReportPrinter printer;
  
  		int reporting_disabled;
  		
  		/// <summary>
  		/// List of symbols related to reported error/warning. You have to fill it before error/warning is reported.
  		/// </summary>
  		List<string> extra_information = new List<string> ();
  
  		// 
  		// IF YOU ADD A NEW WARNING YOU HAVE TO ADD ITS ID HERE
  		//
  		public static readonly int[] AllWarnings = new int[] {
  			28, 67, 78,
  			105, 108, 109, 114, 162, 164, 168, 169, 183, 184, 197,
  			219, 251, 252, 253, 278, 282,
  			402, 414, 419, 420, 429, 436, 437, 440, 458, 464, 465, 467, 469, 472,
  			612, 618, 626, 628, 642, 649, 652, 657, 658, 659, 660, 661, 665, 672, 675, 693,
  			728,
  			809, 824,
  			1030, 1058, 1066,
  			1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592,
  			1607, 1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692, 1695, 1696, 1699,
  			1700, 1701, 1702, 1709, 1717, 1718, 1720,
  			1901, 1981,
  			2002, 2023, 2029,
  			3000, 3001, 3002, 3003, 3005, 3006, 3007, 3008, 3009,
  			3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019,
  			3021, 3022, 3023, 3024, 3026, 3027
  		};
  
  		static HashSet<int> AllWarningsHashSet;
  
  		public Report (ReportPrinter printer)
  		{
  			if (printer == null)
  				throw new ArgumentNullException ("printer");
  
  			this.printer = printer;
  			warning_level = 4;
  		}
  
  		public void DisableReporting ()
  		{
  			++reporting_disabled;
  		}
  
  		public void EnableReporting ()
  		{
  			--reporting_disabled;
  		}
  
  		public void FeatureIsNotAvailable (CompilerContext compiler, Location loc, string feature)
  		{
  			string version;
  			switch (compiler.Settings.Version) {
  			case LanguageVersion.ISO_1:
  				version = "1.0";
  				break;
  			case LanguageVersion.ISO_2:
  				version = "2.0";
  				break;
  			case LanguageVersion.V_3:
  				version = "3.0";
  				break;
  			default:
  				throw new InternalErrorException ("Invalid feature version", compiler.Settings.Version);
  			}
  
  			Error (1644, loc,
  				"Feature `{0}' cannot be used because it is not part of the C# {1} language specification",
  				      feature, version);
  		}
  
  		public void FeatureIsNotSupported (Location loc, string feature)
  		{
  			Error (1644, loc,
  				"Feature `{0}' is not supported in Mono mcs1 compiler. Consider using the `gmcs' compiler instead",
  				feature);
  		}
  		
  		bool IsWarningEnabled (int code, int level, Location loc)
  		{
  			if (WarningLevel < level)
  				return false;
  
  			if (IsWarningDisabledGlobally (code))
  				return false;
  
  			if (warning_regions_table == null || loc.IsNull)
  				return true;
  
  			WarningRegions regions;
  			if (!warning_regions_table.TryGetValue (loc.File, out regions))
  				return true;
  
  			return regions.IsWarningEnabled (code, loc.Row);
  		}
  
  		public bool IsWarningDisabledGlobally (int code)
  		{
  			return warning_ignore_table != null && warning_ignore_table.Contains (code);
  		}
  
  		bool IsWarningAsError (int code)
  		{
  			bool is_error = WarningsAreErrors;
  
  			// Check specific list
  			if (warnings_as_error != null)
  				is_error |= warnings_as_error.Contains (code);
  
  			// Ignore excluded warnings
  			if (warnings_only != null && warnings_only.Contains (code))
  				is_error = false;
  
  			return is_error;
  		}
  		        
  		public void RuntimeMissingSupport (Location loc, string feature) 
  		{
  			Error (-88, loc, "Your .NET Runtime does not support `{0}'. Please use the latest Mono runtime instead.", feature);
  		}
  
  		/// <summary>
  		/// In most error cases is very useful to have information about symbol that caused the error.
  		/// Call this method before you call Report.Error when it makes sense.
  		/// </summary>
  		public void SymbolRelatedToPreviousError (Location loc, string symbol)
  		{
  			SymbolRelatedToPreviousError (loc.ToString ());
  		}
  
  		public void SymbolRelatedToPreviousError (MemberSpec ms)
  		{
  			if (reporting_disabled > 0 || !printer.HasRelatedSymbolSupport)
  				return;
  
  			var mc = ms.MemberDefinition as MemberCore;
  			while (ms is ElementTypeSpec) {
  				ms = ((ElementTypeSpec) ms).Element;
  				mc = ms.MemberDefinition as MemberCore;
  			}
  
  			if (mc != null) {
  				SymbolRelatedToPreviousError (mc);
  			} else {
  				if (ms.DeclaringType != null)
  					ms = ms.DeclaringType;
  
  				var imported_type = ms.MemberDefinition as ImportedTypeDefinition;
  				if (imported_type != null) {
  					var iad = imported_type.DeclaringAssembly as ImportedAssemblyDefinition;
  					SymbolRelatedToPreviousError (iad.Location);
  				}
  			}
  		}
  
  		public void SymbolRelatedToPreviousError (MemberCore mc)
  		{
  			SymbolRelatedToPreviousError (mc.Location, mc.GetSignatureForError ());
  		}
  
  		public void SymbolRelatedToPreviousError (string loc)
  		{
  			string msg = String.Format ("{0} (Location of the symbol related to previous ", loc);
  			if (extra_information.Contains (msg))
  				return;
  
  			extra_information.Add (msg);
  		}
  
  		public void AddWarningAsError (string warningId)
  		{
  			int id;
  			try {
  				id = int.Parse (warningId);
  			} catch {
  				CheckWarningCode (warningId, Location.Null);
  				return;
  			}
  
  			if (!CheckWarningCode (id, Location.Null))
  				return;
  
  			if (warnings_as_error == null)
  				warnings_as_error = new List<int> ();
  			
  			warnings_as_error.Add (id);
  		}
  
  		public void RemoveWarningAsError (string warningId)
  		{
  			int id;
  			try {
  				id = int.Parse (warningId);
  			} catch {
  				CheckWarningCode (warningId, Location.Null);
  				return;
  			}
  
  			if (!CheckWarningCode (id, Location.Null))
  				return;
  
  			if (warnings_only == null)
  				warnings_only = new List<int> ();
  
  			warnings_only.Add (id);
  		}
  
  		public bool CheckWarningCode (string code, Location loc)
  		{
  			Warning (1691, 1, loc, "`{0}' is not a valid warning number", code);
  			return false;
  		}
  
  		public bool CheckWarningCode (int code, Location loc)
  		{
  			if (AllWarningsHashSet == null)
  				AllWarningsHashSet = new HashSet<int> (AllWarnings);
  
  			if (AllWarningsHashSet.Contains (code))
  				return true;
  
  			return CheckWarningCode (code.ToString (), loc);
  		}
  
  		public void ExtraInformation (Location loc, string msg)
  		{
  			extra_information.Add (String.Format ("{0} {1}", loc, msg));
  		}
  
  		public WarningRegions RegisterWarningRegion (Location location)
  		{
  			WarningRegions regions;
  			if (warning_regions_table == null) {
  				regions = null;
  				warning_regions_table = new Dictionary<int, WarningRegions> ();
  			} else {
  				warning_regions_table.TryGetValue (location.File, out regions);
  			}
  
  			if (regions == null) {
  				regions = new WarningRegions ();
  				warning_regions_table.Add (location.File, regions);
  			}
  
  			return regions;
  		}
  
  		public void Warning (int code, int level, Location loc, string message)
  		{
  			if (reporting_disabled > 0)
  				return;
  
  			if (!IsWarningEnabled (code, level, loc))
  				return;
  
  			AbstractMessage msg;
  			if (IsWarningAsError (code)) {
  				message = "Warning as Error: " + message;
  				msg = new ErrorMessage (code, loc, message, extra_information);
  			} else {
  				msg = new WarningMessage (code, loc, message, extra_information);
  			}
  
  			extra_information.Clear ();
  			printer.Print (msg);
  		}
  
  		public void Warning (int code, int level, Location loc, string format, string arg)
  		{
  			Warning (code, level, loc, String.Format (format, arg));
  		}
  
  		public void Warning (int code, int level, Location loc, string format, string arg1, string arg2)
  		{
  			Warning (code, level, loc, String.Format (format, arg1, arg2));
  		}
  
  		public void Warning (int code, int level, Location loc, string format, params object[] args)
  		{
  			Warning (code, level, loc, String.Format (format, args));
  		}
  
  		public void Warning (int code, int level, string message)
  		{
  			Warning (code, level, Location.Null, message);
  		}
  
  		public void Warning (int code, int level, string format, string arg)
  		{
  			Warning (code, level, Location.Null, format, arg);
  		}
  
  		public void Warning (int code, int level, string format, string arg1, string arg2)
  		{
  			Warning (code, level, Location.Null, format, arg1, arg2);
  		}
  
  		public void Warning (int code, int level, string format, params string[] args)
  		{
  			Warning (code, level, Location.Null, String.Format (format, args));
  		}
  
  		//
  		// Warnings encountered so far
  		//
  		public int Warnings {
  			get { return printer.WarningsCount; }
  		}
  
  		public void Error (int code, Location loc, string error)
  		{
  			if (reporting_disabled > 0)
  				return;
  
  			ErrorMessage msg = new ErrorMessage (code, loc, error, extra_information);
  			extra_information.Clear ();
  
  			printer.Print (msg);
  		}
  
  		public void Error (int code, Location loc, string format, string arg)
  		{
  			Error (code, loc, String.Format (format, arg));
  		}
  
  		public void Error (int code, Location loc, string format, string arg1, string arg2)
  		{
  			Error (code, loc, String.Format (format, arg1, arg2));
  		}
  
  		public void Error (int code, Location loc, string format, params string[] args)
  		{
  			Error (code, loc, String.Format (format, args));
  		}
  
  		public void Error (int code, string error)
  		{
  			Error (code, Location.Null, error);
  		}
  
  		public void Error (int code, string format, string arg)
  		{
  			Error (code, Location.Null, format, arg);
  		}
  
  		public void Error (int code, string format, string arg1, string arg2)
  		{
  			Error (code, Location.Null, format, arg1, arg2);
  		}
  
  		public void Error (int code, string format, params string[] args)
  		{
  			Error (code, Location.Null, String.Format (format, args));
  		}
  
  		//
  		// Errors encountered so far
  		//
  		public int Errors {
  			get { return printer.ErrorsCount; }
  		}
  
  		public bool IsDisabled {
  			get {
  				return reporting_disabled > 0;
  			}
  		}
  
  		public ReportPrinter Printer {
  			get { return printer; }
  		}
  
  		public void SetIgnoreWarning (int code)
  		{
  			if (warning_ignore_table == null)
  				warning_ignore_table = new HashSet<int> ();
  
  			warning_ignore_table.Add (code);
  		}
  
  		public ReportPrinter SetPrinter (ReportPrinter printer)
  		{
  			ReportPrinter old = this.printer;
  			this.printer = printer;
  			return old;
  		}
  
  		public int WarningLevel {
  			get {
  				return warning_level;
  			}
  			set {
  				warning_level = value;
  			}
  		}
  
  		[Conditional ("MCS_DEBUG")]
  		static public void Debug (string message, params object[] args)
  		{
  
gt: 			Debug (4, message, args);