Fix compilation of array initializer used inside field initializer of an anonymous...
[mono.git] / mcs / mcs / location.cs
index 2d41da0019b339468a092ab1a8296dd6ad99dd71..921141b9b36042244d987886a5c172045cf841e9 100644 (file)
@@ -4,15 +4,18 @@
 // Author:
 //   Miguel de Icaza
 //   Atsushi Enomoto  <atsushi@ximian.com>
+//   Marek Safar (marek.safar@gmail.com)
 //
-// (C) 2001 Ximian, Inc.
-// (C) 2005 Novell, Inc.
+// Copyright 2001 Ximian, Inc.
+// Copyright 2005 Novell, Inc.
 //
 
 using System;
 using System.IO;
-using System.Collections;
+using System.Collections.Generic;
 using Mono.CompilerServices.SymbolWriter;
+using System.Diagnostics;
+using System.Linq;
 
 namespace Mono.CSharp {
        /// <summary>
@@ -22,28 +25,144 @@ namespace Mono.CSharp {
        ///   This is intentionally a class and not a struct since we need
        ///   to pass this by reference.
        /// </remarks>
-       public sealed class SourceFile : ISourceFile {
+       public class SourceFile : ISourceFile, IEquatable<SourceFile>
+       {
                public readonly string Name;
-               public readonly string Path;
+               public readonly string FullPathName;
                public readonly int Index;
-               public SourceFileEntry SourceFileEntry;
-               public bool HasLineDirective;
+               public bool AutoGenerated;
+
+               SourceFileEntry file;
+               byte[] guid, checksum;
 
                public SourceFile (string name, string path, int index)
                {
                        this.Index = index;
                        this.Name = name;
-                       this.Path = path;
+                       this.FullPathName = path;
+               }
+
+               public SourceFileEntry SourceFileEntry {
+                       get { return file; }
                }
 
                SourceFileEntry ISourceFile.Entry {
-                       get { return SourceFileEntry; }
+                       get { return file; }
+               }
+
+               public void SetChecksum (byte[] guid, byte[] checksum)
+               {
+                       this.guid = guid;
+                       this.checksum = checksum;
+               }
+
+               public virtual void DefineSymbolInfo (MonoSymbolWriter symwriter)
+               {
+                       if (guid != null)
+                               file = symwriter.DefineDocument (FullPathName, guid, checksum);
+                       else {
+                               file = symwriter.DefineDocument (FullPathName);
+                               if (AutoGenerated)
+                                       file.SetAutoGenerated ();
+                       }
+               }
+
+               public bool Equals (SourceFile other)
+               {
+                       return FullPathName == other.FullPathName;
                }
 
                public override string ToString ()
                {
                        return String.Format ("SourceFile ({0}:{1}:{2}:{3})",
-                                             Name, Path, Index, SourceFileEntry);
+                                                 Name, FullPathName, Index, SourceFileEntry);
+               }
+       }
+
+       public class CompilationSourceFile : SourceFile, ICompileUnit
+       {
+               CompileUnitEntry comp_unit;
+               Dictionary<string, SourceFile> include_files;
+               Dictionary<string, bool> conditionals;
+               NamespaceContainer ns_container;
+
+               public CompilationSourceFile (string name, string fullPathName, int index)
+                       : base (name, fullPathName, index)
+               {
+               }
+
+               CompileUnitEntry ICompileUnit.Entry {
+                       get { return comp_unit; }
+               }
+
+               public CompileUnitEntry CompileUnitEntry {
+                       get { return comp_unit; }
+               }
+
+               public NamespaceContainer NamespaceContainer {
+                       get {
+                               return ns_container;
+                       }
+                       set {
+                               ns_container = value;
+                       }
+               }
+
+               public void AddIncludeFile (SourceFile file)
+               {
+                       if (file == this)
+                               return;
+                       
+                       if (include_files == null)
+                               include_files = new Dictionary<string, SourceFile> ();
+
+                       if (!include_files.ContainsKey (file.FullPathName))
+                               include_files.Add (file.FullPathName, file);
+               }
+
+               public void AddDefine (string value)
+               {
+                       if (conditionals == null)
+                               conditionals = new Dictionary<string, bool> (2);
+
+                       conditionals [value] = true;
+               }
+
+               public void AddUndefine (string value)
+               {
+                       if (conditionals == null)
+                               conditionals = new Dictionary<string, bool> (2);
+
+                       conditionals [value] = false;
+               }
+
+               public override void DefineSymbolInfo (MonoSymbolWriter symwriter)
+               {
+                       base.DefineSymbolInfo (symwriter);
+
+                       comp_unit = symwriter.DefineCompilationUnit (SourceFileEntry);
+
+                       if (include_files != null) {
+                               foreach (SourceFile include in include_files.Values) {
+                                       include.DefineSymbolInfo (symwriter);
+                                       comp_unit.AddFile (include.SourceFileEntry);
+                               }
+                       }
+               }
+
+               public bool IsConditionalDefined (CompilerContext ctx, string value)
+               {
+                       if (conditionals != null) {
+                               bool res;
+                               if (conditionals.TryGetValue (value, out res))
+                                       return res;
+                               
+                               // When conditional was undefined
+                               if (conditionals.ContainsKey (value))
+                                       return false;                                   
+                       }
+
+                       return ctx.Settings.IsConditionalSymbolDefined (value);
                }
        }
 
@@ -63,77 +182,65 @@ namespace Mono.CSharp {
        ///
        ///   http://lists.ximian.com/pipermail/mono-devel-list/2004-December/009508.html
        /// </remarks>
-       public struct Location {
-               int token; 
-
+       public struct Location : IEquatable<Location>
+       {
                struct Checkpoint {
                        public readonly int LineOffset;
+                       public readonly int CompilationUnit;
                        public readonly int File;
 
-                       public Checkpoint (int file, int line)
+                       public Checkpoint (int compile_unit, int file, int line)
                        {
                                File = file;
+                               CompilationUnit = compile_unit;
                                LineOffset = line - (int) (line % (1 << line_delta_bits));
                        }
                }
 
-               static ArrayList source_list;
-               static Hashtable source_files;
-               static int checkpoint_bits;
-               static int source_count;
+#if FULL_AST
+               long token;
+
+               const int column_bits = 24;
+               const int line_delta_bits = 24;
+#else
+               int token;
+
+               const int column_bits = 8;
+               const int line_delta_bits = 8;
+#endif
+               const int checkpoint_bits = 16;
+
+               // -2 because the last one is used for hidden
+               const int max_column = (1 << column_bits) - 2;
+               const int column_mask = (1 << column_bits) - 1;
+
+               static List<SourceFile> source_list;
                static int current_source;
-               static int line_delta_bits;
-               static int line_delta_mask;
-               static int column_bits;
-               static int column_mask;
+               static int current_compile_unit;
                static Checkpoint [] checkpoints;
                static int checkpoint_index;
-
+               
                public readonly static Location Null = new Location (-1);
+               public static bool InEmacs;
                
                static Location ()
                {
-                       source_files = new Hashtable ();
-                       source_list = new ArrayList ();
-                       current_source = 0;
-                       checkpoints = new Checkpoint [10];
+                       Reset ();
                }
 
                public static void Reset ()
                {
-                       source_files = new Hashtable ();
-                       source_list = new ArrayList ();
+                       source_list = new List<SourceFile> ();
                        current_source = 0;
-                       source_count = 0;
+                       current_compile_unit = 0;
+                       checkpoint_index = 0;
                }
 
-               // <summary>
-               //   This must be called before parsing/tokenizing any files.
-               // </summary>
-               static public void AddFile (string name)
+               public static SourceFile AddFile (string name, string fullName)
                {
-                       string path = Path.GetFullPath (name);
-
-                       if (source_files.Contains (path)){
-                               int id = (int) source_files [path];
-                               string other_name = ((SourceFile) source_list [id - 1]).Name;
-                               if (name.Equals (other_name))
-                                       Report.Warning (2002, "Source file `{0}' specified multiple times", name);
-                               else
-                                       Report.Warning (2002, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", name, other_name, path);
-                               return;
-                       }
-
-                       source_files.Add (path, ++source_count);
-                       source_list.Add (new SourceFile (name, path, source_count));
-               }
-
-               static public SourceFile[] SourceFiles {
-                       get {
-                               SourceFile[] retval = new SourceFile [source_list.Count];
-                               source_list.CopyTo (retval, 0);
-                               return retval;
-                       }
+                       var source = new SourceFile (name, fullName, source_list.Count + 1);
+                       source_list.Add (source);
+                       return source;
                }
 
                // <summary>
@@ -142,57 +249,25 @@ namespace Mono.CSharp {
                //   source file.  We reserve some extra space for files we encounter via #line
                //   directives while parsing.
                // </summary>
-               static public void Initialize ()
+               static public void Initialize (List<CompilationSourceFile> files)
                {
-                       checkpoints = new Checkpoint [source_list.Count * 2];
-                       checkpoints [0] = new Checkpoint (0, 0);
+#if NET_4_0
+                       source_list.AddRange (files);
+#else
+                       source_list.AddRange (files.ToArray ());
+#endif
 
-                       column_bits = 8;
-                       column_mask = 0xFF;
-                       line_delta_bits = 8;
-                       line_delta_mask = 0xFF00;
-                       checkpoint_index = 0;
-                       checkpoint_bits = 16;
-               }
-
-               // <remarks>
-               //   This is used when we encounter a #line preprocessing directive.
-               // </remarks>
-               static public SourceFile LookupFile (string name)
-               {
-                       string path = name == "" ? "" : Path.GetFullPath (name);
-
-                       if (!source_files.Contains (path)) {
-                               if (source_count >= (1 << checkpoint_bits))
-                                       return new SourceFile (name, path, 0);
-
-                               source_files.Add (path, ++source_count);
-                               SourceFile retval = new SourceFile (name, path, source_count);
-                               source_list.Add (retval);
-                               return retval;
-                       }
-
-                       int index = (int) source_files [path];
-                       return (SourceFile) source_list [index - 1];
+                       checkpoints = new Checkpoint [source_list.Count * 2];
+                       if (checkpoints.Length > 0)
+                               checkpoints [0] = new Checkpoint (0, 0, 0);
                }
 
-               static public void Push (SourceFile file, int line)
+               static public void Push (CompilationSourceFile compile_unit, SourceFile file)
                {
-                       current_source = file.Index;
+                       current_source = file != null ? file.Index : -1;
+                       current_compile_unit = compile_unit != null ? compile_unit.Index : -1;
                        // File is always pushed before being changed.
                }
-
-               // <remarks>
-               //   If we're compiling with debugging support, this is called between parsing
-               //   and code generation to register all the source files with the
-               //   symbol writer.
-               // </remarks>
-               static public void DefineSymbolDocuments (SymbolWriter symwriter)
-               {
-                       foreach (SourceFile file in source_list) {
-                               file.SourceFileEntry = symwriter.DefineDocument (file.Path);
-                       }
-               }
                
                public Location (int row)
                        : this (row, 0)
@@ -204,9 +279,15 @@ namespace Mono.CSharp {
                        if (row <= 0)
                                token = 0;
                        else {
-                               column &= column_mask;
-                               int target = -1;
-                               int delta = 0;
+                               if (column > max_column)
+                                       column = max_column;
+                               else if (column < 0)
+                                       column = max_column + 1;
+
+                               long target = -1;
+                               long delta = 0;
+
+                               // FIXME: This value is certainly wrong but what was the intension
                                int max = checkpoint_index < 10 ?
                                        checkpoint_index : 10;
                                for (int i = 0; i < max; i++) {
@@ -220,34 +301,52 @@ namespace Mono.CSharp {
                                        }
                                }
                                if (target == -1) {
-                                       AddCheckpoint (current_source, row);
+                                       AddCheckpoint (current_compile_unit, current_source, row);
                                        target = checkpoint_index;
                                        delta = row % (1 << line_delta_bits);
                                }
+
                                long l = column +
-                                       (long) (delta << column_bits) +
-                                       (long) (target << (line_delta_bits + column_bits));
+                                       (delta << column_bits) +
+                                       (target << (line_delta_bits + column_bits));
+#if FULL_AST
+                               token = l;
+#else
                                token = l > 0xFFFFFFFF ? 0 : (int) l;
+#endif
                        }
                }
 
-               static void AddCheckpoint (int file, int row)
+               public static Location operator - (Location loc, int columns)
+               {
+                       return new Location (loc.Row, loc.Column - columns);
+               }
+
+               static void AddCheckpoint (int compile_unit, int file, int row)
                {
                        if (checkpoints.Length == ++checkpoint_index) {
-                               Checkpoint [] tmp = new Checkpoint [checkpoint_index * 2];
-                               Array.Copy (checkpoints, tmp, checkpoints.Length);
-                               checkpoints = tmp;
+                               Array.Resize (ref checkpoints, checkpoint_index * 2);
                        }
-                       checkpoints [checkpoint_index] = new Checkpoint (file, row);
+                       checkpoints [checkpoint_index] = new Checkpoint (compile_unit, file, row);
                }
 
+               string FormatLocation (string fileName)
+               {
+                       if (column_bits == 0 || InEmacs)
+                               return fileName + "(" + Row.ToString () + "):";
+
+                       return fileName + "(" + Row.ToString () + "," + Column.ToString () +
+                               (Column == max_column ? "+):" : "):");
+               }
+               
                public override string ToString ()
                {
-                       if (column_bits == 0)
-                               return Name + "(" + Row + "):";
-                       else
-                               return Name + "(" + Row + "," + Column +
-                                       (Column == column_mask ? "+):" : "):");
+                       return FormatLocation (Name);
+               }
+
+               public string ToStringFullName ()
+               {
+                       return FormatLocation (NameFullPath);
                }
                
                /// <summary>
@@ -263,20 +362,37 @@ namespace Mono.CSharp {
                                if (token == 0 || index == 0)
                                        return "Internal";
 
-                               SourceFile file = (SourceFile) source_list [index - 1];
+                               SourceFile file = source_list [index - 1];
                                return file.Name;
                        }
                }
 
+               public string NameFullPath {
+                       get {
+                               int index = File;
+                               if (token == 0 || index == 0)
+                                       return "Internal";
+
+                               return source_list[index - 1].FullPathName;
+                       }
+               }
+
                int CheckpointIndex {
-                       get { return (int) ((token & 0xFFFF0000) >> (line_delta_bits + column_bits)); }
+                       get {
+                               const int checkpoint_mask = (1 << checkpoint_bits) - 1;
+                               return ((int) (token >> (line_delta_bits + column_bits))) & checkpoint_mask;
+                       }
                }
 
                public int Row {
                        get {
                                if (token == 0)
                                        return 1;
-                               return checkpoints [CheckpointIndex].LineOffset + ((token & line_delta_mask) >> column_bits);
+
+                               int offset = checkpoints[CheckpointIndex].LineOffset;
+
+                               const int line_delta_mask = (1 << column_bits) - 1;
+                               return offset + (((int)(token >> column_bits)) & line_delta_mask);
                        }
                }
 
@@ -284,7 +400,23 @@ namespace Mono.CSharp {
                        get {
                                if (token == 0)
                                        return 1;
-                               return (int) (token & column_mask);
+                               int col = (int) (token & column_mask);
+                               return col > max_column ? 1 : col;
+                       }
+               }
+
+               public bool Hidden {
+                       get {
+                               return (int) (token & column_mask) == max_column + 1;
+                       }
+               }
+
+               public int CompilationUnitIndex {
+                       get {
+                               if (token == 0)
+                                       return 0;
+if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("Should not happen. Token is {0:X04}, checkpoints are {1}, index is {2}", token, checkpoints.Length, CheckpointIndex));
+                               return checkpoints [CheckpointIndex].CompilationUnit;
                        }
                }
 
@@ -317,22 +449,126 @@ if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("
                                return (SourceFile) source_list [index - 1];
                        }
                }
+
+               public CompilationSourceFile CompilationUnit {
+                       get {
+                               int index = CompilationUnitIndex;
+                               if (index == 0)
+                                       return null;
+                               return (CompilationSourceFile) source_list [index - 1];
+                       }
+               }
+
+               #region IEquatable<Location> Members
+
+               public bool Equals (Location other)
+               {
+                       return this.token == other.token;
+               }
+
+               #endregion
        }
 
-       public class LocatedToken
+       //
+       // A bag of additional locations to support full ast tree
+       //
+       public class LocationsBag
        {
-               public readonly Location Location;
-               public readonly string Value;
+               public class MemberLocations
+               {
+                       public readonly IList<Tuple<Modifiers, Location>> Modifiers;
+                       Location[] locations;
+
+                       public MemberLocations (IList<Tuple<Modifiers, Location>> mods, Location[] locs)
+                       {
+                               Modifiers = mods;
+                               locations = locs;
+                       }
+
+                       #region Properties
+
+                       public Location this [int index] {
+                               get {
+                                       return locations [index];
+                               }
+                       }
+                       
+                       public int Count {
+                               get {
+                                       return locations.Length;
+                               }
+                       }
+
+                       #endregion
+
+                       public void AddLocations (params Location[] additional)
+                       {
+                               if (locations == null) {
+                                       locations = additional;
+                               } else {
+                                       int pos = locations.Length;
+                                       Array.Resize (ref locations, pos + additional.Length);
+                                       additional.CopyTo (locations, pos);
+                               }
+                       }
+               }
+
+               Dictionary<object, Location[]> simple_locs = new Dictionary<object, Location[]> (ReferenceEquality<object>.Default);
+               Dictionary<MemberCore, MemberLocations> member_locs = new Dictionary<MemberCore, MemberLocations> (ReferenceEquality<MemberCore>.Default);
 
-               public LocatedToken (Location loc, string value)
+               [Conditional ("FULL_AST")]
+               public void AddLocation (object element, params Location[] locations)
                {
-                       Location = loc;
-                       Value = value;
+                       simple_locs.Add (element, locations);
                }
 
-               public override string ToString ()
+               [Conditional ("FULL_AST")]
+               public void AddStatement (object element, params Location[] locations)
+               {
+                       if (locations.Length == 0)
+                               throw new ArgumentException ("Statement is missing semicolon location");
+
+                       simple_locs.Add (element, locations);
+               }
+
+               [Conditional ("FULL_AST")]
+               public void AddMember (MemberCore member, IList<Tuple<Modifiers, Location>> modLocations, params Location[] locations)
+               {
+                       member_locs.Add (member, new MemberLocations (modLocations, locations));
+               }
+
+               [Conditional ("FULL_AST")]
+               public void AppendTo (object existing, params Location[] locations)
+               {
+                       Location[] locs;
+                       if (simple_locs.TryGetValue (existing, out locs)) {
+                               simple_locs [existing] = locs.Concat (locations).ToArray ();
+                               return;
+                       }
+               }
+
+               [Conditional ("FULL_AST")]
+               public void AppendToMember (MemberCore existing, params Location[] locations)
+               {
+                       MemberLocations member;
+                       if (member_locs.TryGetValue (existing, out member)) {
+                               member.AddLocations (locations);
+                               return;
+                       }
+               }
+
+               public Location[] GetLocations (object element)
+               {
+                       Location[] found;
+                       simple_locs.TryGetValue (element, out found);
+                       return found;
+               }
+
+               public MemberLocations GetMemberLocation (MemberCore element)
                {
-                       return Location.ToString () + Value;
+                       MemberLocations found;
+                       member_locs.TryGetValue (element, out found);
+                       return found;
                }
        }
 }