Merge pull request #819 from brendanzagaeski/patch-1
[mono.git] / mcs / mcs / location.cs
index a507c59b8afb297ffc758d7420eec5ce2cb86d7f..e7daa53ce0bd98a5f86aeba6f18d632b7f65690f 100644 (file)
 //
 
 using System;
-using System.IO;
 using System.Collections.Generic;
 using Mono.CompilerServices.SymbolWriter;
 using System.Diagnostics;
 using System.Linq;
 
-namespace Mono.CSharp {
-       /// <summary>
-       ///   This is one single source file.
-       /// </summary>
-       /// <remarks>
-       ///   This is intentionally a class and not a struct since we need
-       ///   to pass this by reference.
-       /// </remarks>
-       public class SourceFile : ISourceFile, IEquatable<SourceFile>
+namespace Mono.CSharp
+{
+       //
+       //  This is one single source file.
+       //
+       public class SourceFile : IEquatable<SourceFile>
        {
+               //
+               // Used by #line directive to track hidden sequence point
+               // regions
+               //
+               struct LocationRegion : IComparable<LocationRegion>
+               {
+                       public readonly Location Start;
+                       public readonly Location End;
+
+                       public LocationRegion (Location start, Location end)
+                       {
+                               this.Start = start;
+                               this.End = end;
+                       }
+
+                       public int CompareTo (LocationRegion other)
+                       {
+                               if (Start.Row == other.Start.Row)
+                                       return Start.Column.CompareTo (other.Start.Column);
+
+                               return Start.Row.CompareTo (other.Start.Row);
+                       }
+
+                       public override string ToString ()
+                       {
+                               return Start.ToString () + " - " + End.ToString ();
+                       }
+               }
+
+               static readonly byte[] MD5Algorith = { 96, 166, 110, 64, 207, 100, 130, 76, 182, 240, 66, 212, 129, 114, 167, 153 };
+
                public readonly string Name;
                public readonly string FullPathName;
                public readonly int Index;
                public bool AutoGenerated;
 
                SourceFileEntry file;
-               byte[] guid, checksum;
+               byte[] algGuid, checksum;
+               List<LocationRegion> hidden_lines;
 
                public SourceFile (string name, string path, int index)
                {
@@ -42,127 +70,79 @@ namespace Mono.CSharp {
                        this.FullPathName = path;
                }
 
-               public SourceFileEntry SourceFileEntry {
-                       get { return file; }
-               }
-
-               SourceFileEntry ISourceFile.Entry {
-                       get { return file; }
+               public byte[] Checksum {
+                       get {
+                               return checksum;
+                       }
                }
 
-               public void SetChecksum (byte[] guid, byte[] checksum)
-               {
-                       this.guid = guid;
-                       this.checksum = checksum;
+               public bool HasChecksum {
+                       get {
+                               return checksum != null;
+                       }
                }
 
-               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 SourceFileEntry SourceFileEntry {
+                       get {
+                               return file;
                        }
                }
 
-               public bool Equals (SourceFile other)
+               public void SetChecksum (byte[] checksum)
                {
-                       return FullPathName == other.FullPathName;
+                       SetChecksum (MD5Algorith, checksum);
                }
 
-               public override string ToString ()
+               public void SetChecksum (byte[] algorithmGuid, byte[] checksum)
                {
-                       return String.Format ("SourceFile ({0}:{1}:{2}:{3})",
-                                                 Name, FullPathName, Index, SourceFileEntry);
+                       this.algGuid = algorithmGuid;
+                       this.checksum = checksum;
                }
-       }
 
-       public class CompilationSourceFile : SourceFile, ICompileUnit
-       {
-               CompileUnitEntry comp_unit;
-               Dictionary<string, SourceFile> include_files;
-               Dictionary<string, bool> conditionals;
-               NamespaceEntry ns_container;
-
-               public CompilationSourceFile (string name, string fullPathName, int index)
-                       : base (name, fullPathName, index)
+               public SourceFileEntry CreateSymbolInfo (MonoSymbolFile symwriter)
                {
-               }
-
-               CompileUnitEntry ICompileUnit.Entry {
-                       get { return comp_unit; }
-               }
+                       if (hidden_lines != null)
+                               hidden_lines.Sort ();
 
-               public CompileUnitEntry CompileUnitEntry {
-                       get { return comp_unit; }
-               }
+                       file = new SourceFileEntry (symwriter, FullPathName, algGuid, checksum);
+                       if (AutoGenerated)
+                               file.SetAutoGenerated ();
 
-               public NamespaceEntry NamespaceContainer {
-                       get {
-                               return ns_container;
-                       }
-                       set {
-                               ns_container = value;
-                       }
+                       return file;
                }
 
-               public void AddIncludeFile (SourceFile file)
+               public bool Equals (SourceFile other)
                {
-                       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);
+                       return FullPathName == other.FullPathName;
                }
 
-               public void AddDefine (string value)
+               public bool IsHiddenLocation (Location loc)
                {
-                       if (conditionals == null)
-                               conditionals = new Dictionary<string, bool> (2);
-
-                       conditionals [value] = true;
-               }
+                       if (hidden_lines == null)
+                               return false;
 
-               public void AddUndefine (string value)
-               {
-                       if (conditionals == null)
-                               conditionals = new Dictionary<string, bool> (2);
+                       int index = hidden_lines.BinarySearch (new LocationRegion (loc, loc));
+                       index = ~index;
+                       if (index > 0) {
+                               var found = hidden_lines[index - 1];
+                               if (loc.Row < found.End.Row)
+                                       return true;
+                       }
 
-                       conditionals [value] = false;
+                       return false;
                }
 
-               public override void DefineSymbolInfo (MonoSymbolWriter symwriter)
+               public void RegisterHiddenScope (Location start, Location end)
                {
-                       base.DefineSymbolInfo (symwriter);
+                       if (hidden_lines == null)
+                               hidden_lines = new List<LocationRegion> ();
 
-                       comp_unit = symwriter.DefineCompilationUnit (SourceFileEntry);
-
-                       if (include_files != null) {
-                               foreach (SourceFile include in include_files.Values) {
-                                       include.DefineSymbolInfo (symwriter);
-                                       comp_unit.AddFile (include.SourceFileEntry);
-                               }
-                       }
+                       hidden_lines.Add (new LocationRegion (start, end));
                }
 
-               public bool IsConditionalDefined (CompilerContext ctx, string value)
+               public override string ToString ()
                {
-                       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);
+                       return String.Format ("SourceFile ({0}:{1}:{2})", Name, FullPathName, Index);
                }
        }
 
@@ -186,41 +166,36 @@ namespace Mono.CSharp {
        {
                struct Checkpoint {
                        public readonly int LineOffset;
-                       public readonly int CompilationUnit;
                        public readonly int File;
 
-                       public Checkpoint (int compile_unit, int file, int line)
+                       public Checkpoint (int file, int line)
                        {
                                File = file;
-                               CompilationUnit = compile_unit;
                                LineOffset = line - (int) (line % (1 << line_delta_bits));
                        }
                }
 
 #if FULL_AST
-               long token;
+               readonly long token;
 
                const int column_bits = 24;
                const int line_delta_bits = 24;
 #else
-               int token;
+               readonly 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;
+               const int max_column = column_mask;
 
                static List<SourceFile> source_list;
-               static int current_source;
-               static int current_compile_unit;
                static Checkpoint [] checkpoints;
                static int checkpoint_index;
                
-               public readonly static Location Null = new Location (-1);
+               public readonly static Location Null = new Location ();
                public static bool InEmacs;
                
                static Location ()
@@ -231,16 +206,12 @@ namespace Mono.CSharp {
                public static void Reset ()
                {
                        source_list = new List<SourceFile> ();
-                       current_source = 0;
-                       current_compile_unit = 0;
                        checkpoint_index = 0;
                }
 
-               public static SourceFile AddFile (string name, string fullName)
+               public static void AddFile (SourceFile file)
                {
-                       var source = new SourceFile (name, fullName, source_list.Count + 1);
-                       source_list.Add (source);
-                       return source;
+                       source_list.Add (file);
                }
 
                // <summary>
@@ -249,44 +220,33 @@ namespace Mono.CSharp {
                //   source file.  We reserve some extra space for files we encounter via #line
                //   directives while parsing.
                // </summary>
-               static public void Initialize (List<CompilationSourceFile> files)
+               static public void Initialize (List<SourceFile> files)
                {
-#if NET_4_0
+#if NET_4_0 || MOBILE_DYNAMIC
                        source_list.AddRange (files);
 #else
                        source_list.AddRange (files.ToArray ());
 #endif
 
-                       checkpoints = new Checkpoint [source_list.Count * 2];
+                       checkpoints = new Checkpoint [System.Math.Max (1, source_list.Count * 2)];
                        if (checkpoints.Length > 0)
-                               checkpoints [0] = new Checkpoint (0, 0, 0);
+                               checkpoints [0] = new Checkpoint (0, 0);
                }
 
-               static public void Push (CompilationSourceFile compile_unit, SourceFile file)
-               {
-                       current_source = file != null ? file.Index : -1;
-                       current_compile_unit = compile_unit != null ? compile_unit.Index : -1;
-                       // File is always pushed before being changed.
-               }
-               
-               public Location (int row)
-                       : this (row, 0)
-               {
-               }
-
-               public Location (int row, int column)
+               public Location (SourceFile file, int row, int column)
                {
                        if (row <= 0)
                                token = 0;
                        else {
                                if (column > max_column)
                                        column = max_column;
-                               else if (column < 0)
-                                       column = max_column + 1;
 
                                long target = -1;
                                long delta = 0;
 
+                               // TODO: For eval only, need better handling of empty
+                               int file_index = file == null ? 0 : file.Index;
+
                                // FIXME: This value is certainly wrong but what was the intension
                                int max = checkpoint_index < 10 ?
                                        checkpoint_index : 10;
@@ -295,13 +255,13 @@ namespace Mono.CSharp {
                                        delta = row - offset;
                                        if (delta >= 0 &&
                                                delta < (1 << line_delta_bits) &&
-                                               checkpoints [checkpoint_index - i].File == current_source) {
+                                               checkpoints[checkpoint_index - i].File == file_index) {
                                                target = checkpoint_index - i;
                                                break;
                                        }
                                }
                                if (target == -1) {
-                                       AddCheckpoint (current_compile_unit, current_source, row);
+                                       AddCheckpoint (file_index, row);
                                        target = checkpoint_index;
                                        delta = row % (1 << line_delta_bits);
                                }
@@ -319,15 +279,15 @@ namespace Mono.CSharp {
 
                public static Location operator - (Location loc, int columns)
                {
-                       return new Location (loc.Row, loc.Column - columns);
+                       return new Location (loc.SourceFile, loc.Row, loc.Column - columns);
                }
 
-               static void AddCheckpoint (int compile_unit, int file, int row)
+               static void AddCheckpoint (int file, int row)
                {
                        if (checkpoints.Length == ++checkpoint_index) {
                                Array.Resize (ref checkpoints, checkpoint_index * 2);
                        }
-                       checkpoints [checkpoint_index] = new Checkpoint (compile_unit, file, row);
+                       checkpoints [checkpoint_index] = new Checkpoint (file, row);
                }
 
                string FormatLocation (string fileName)
@@ -359,8 +319,8 @@ namespace Mono.CSharp {
                public string Name {
                        get {
                                int index = File;
-                               if (token == 0 || index == 0)
-                                       return "Internal";
+                               if (token == 0 || index <= 0)
+                                       return null;
 
                                SourceFile file = source_list [index - 1];
                                return file.Name;
@@ -370,8 +330,8 @@ namespace Mono.CSharp {
                public string NameFullPath {
                        get {
                                int index = File;
-                               if (token == 0 || index == 0)
-                                       return "Internal";
+                               if (token == 0 || index <= 0)
+                                       return null;
 
                                return source_list[index - 1].FullPathName;
                        }
@@ -400,23 +360,7 @@ namespace Mono.CSharp {
                        get {
                                if (token == 0)
                                        return 1;
-                               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;
+                               return (int) (token & column_mask);
                        }
                }
 
@@ -446,16 +390,7 @@ if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("
                                int index = File;
                                if (index == 0)
                                        return null;
-                               return (SourceFile) source_list [index - 1];
-                       }
-               }
-
-               public CompilationSourceFile CompilationUnit {
-                       get {
-                               int index = CompilationUnitIndex;
-                               if (index == 0)
-                                       return null;
-                               return (CompilationSourceFile) source_list [index - 1];
+                               return source_list [index - 1];
                        }
                }
 
@@ -477,11 +412,28 @@ if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("
                public class MemberLocations
                {
                        public readonly IList<Tuple<Modifiers, Location>> Modifiers;
-                       Location[] locations;
+                       List<Location> locations;
 
-                       public MemberLocations (IList<Tuple<Modifiers, Location>> mods, Location[] locs)
+                       public MemberLocations (IList<Tuple<Modifiers, Location>> mods)
                        {
                                Modifiers = mods;
+                       }
+
+                       public MemberLocations (IList<Tuple<Modifiers, Location>> mods, Location loc)
+                               : this (mods)
+                       {
+                               AddLocations (loc);
+                       }
+
+                       public MemberLocations (IList<Tuple<Modifiers, Location>> mods, Location[] locs)
+                               : this (mods)
+                       {
+                               AddLocations (locs);
+                       }
+
+                       public MemberLocations (IList<Tuple<Modifiers, Location>> mods, List<Location> locs)
+                               : this (mods)
+                       {
                                locations = locs;
                        }
 
@@ -495,31 +447,50 @@ if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("
                        
                        public int Count {
                                get {
-                                       return locations.Length;
+                                       return locations.Count;
                                }
                        }
 
                        #endregion
 
+                       public void AddLocations (Location loc)
+                       {
+                               if (locations == null) {
+                                       locations = new List<Location> ();
+                               }
+
+                               locations.Add (loc);
+                       }
+
                        public void AddLocations (params Location[] additional)
                        {
                                if (locations == null) {
-                                       locations = additional;
+                                       locations = new List<Location> (additional);
                                } else {
-                                       int pos = locations.Length;
-                                       Array.Resize (ref locations, pos + additional.Length);
-                                       additional.CopyTo (locations, pos);
+                                       locations.AddRange (additional);
                                }
                        }
                }
 
-               Dictionary<object, Location[]> simple_locs = new Dictionary<object, Location[]> (ReferenceEquality<object>.Default);
+               Dictionary<object, List<Location>> simple_locs = new Dictionary<object, List<Location>> (ReferenceEquality<object>.Default);
                Dictionary<MemberCore, MemberLocations> member_locs = new Dictionary<MemberCore, MemberLocations> (ReferenceEquality<MemberCore>.Default);
 
                [Conditional ("FULL_AST")]
                public void AddLocation (object element, params Location[] locations)
                {
-                       simple_locs.Add (element, locations);
+                       simple_locs.Add (element, new List<Location> (locations));
+               }
+
+               [Conditional ("FULL_AST")]
+               public void InsertLocation (object element, int index, Location location)
+               {
+                       List<Location> found;
+                       if (!simple_locs.TryGetValue (element, out found)) {
+                               found = new List<Location> ();
+                               simple_locs.Add (element, found);
+                       }
+
+                       found.Insert (index, location);
                }
 
                [Conditional ("FULL_AST")]
@@ -528,7 +499,19 @@ if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("
                        if (locations.Length == 0)
                                throw new ArgumentException ("Statement is missing semicolon location");
 
-                       simple_locs.Add (element, locations);
+                       AddLocation (element, locations);
+               }
+
+               [Conditional ("FULL_AST")]
+               public void AddMember (MemberCore member, IList<Tuple<Modifiers, Location>> modLocations)
+               {
+                       member_locs.Add (member, new MemberLocations (modLocations));
+               }
+
+               [Conditional ("FULL_AST")]
+               public void AddMember (MemberCore member, IList<Tuple<Modifiers, Location>> modLocations, Location location)
+               {
+                       member_locs.Add (member, new MemberLocations (modLocations, location));
                }
 
                [Conditional ("FULL_AST")]
@@ -538,13 +521,21 @@ if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("
                }
 
                [Conditional ("FULL_AST")]
-               public void AppendTo (object existing, params Location[] locations)
+               public void AddMember (MemberCore member, IList<Tuple<Modifiers, Location>> modLocations, List<Location> locations)
                {
-                       Location[] locs;
-                       if (simple_locs.TryGetValue (existing, out locs)) {
-                               simple_locs [existing] = locs.Concat (locations).ToArray ();
-                               return;
+                       member_locs.Add (member, new MemberLocations (modLocations, locations));
+               }
+
+               [Conditional ("FULL_AST")]
+               public void AppendTo (object element, Location location)
+               {
+                       List<Location> found;
+                       if (!simple_locs.TryGetValue (element, out found)) {
+                               found = new List<Location> ();
+                               simple_locs.Add (element, found);
                        }
+
+                       found.Add (location);
                }
 
                [Conditional ("FULL_AST")]
@@ -557,9 +548,9 @@ if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("
                        }
                }
 
-               public Location[] GetLocations (object element)
+               public List<Location> GetLocations (object element)
                {
-                       Location[] found;
+                       List<Location> found;
                        simple_locs.TryGetValue (element, out found);
                        return found;
                }