2009-12-10 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / location.cs
index 2861d7a5bcba5580f539c2963cf0c9f303b1dc36..9565345bf8d9652e213be9287bc6f66efbdc54ef 100644 (file)
@@ -5,13 +5,13 @@
 //   Miguel de Icaza
 //   Atsushi Enomoto  <atsushi@ximian.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;
 
 namespace Mono.CSharp {
@@ -22,22 +22,47 @@ 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 {
                public readonly string Name;
                public readonly string Path;
                public readonly int Index;
-               public SourceFileEntry SourceFileEntry;
-               public bool HasLineDirective;
+               public bool AutoGenerated;
+               public bool IsIncludeFile;
 
-               public SourceFile (string name, string path, int index)
+               SourceFileEntry file;
+               byte[] guid, checksum;
+
+               public SourceFile (string name, string path, int index, bool is_include)
                {
                        this.Index = index;
                        this.Name = name;
                        this.Path = path;
+                       this.IsIncludeFile = is_include;
+               }
+
+               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 (Path, guid, checksum);
+                       else {
+                               file = symwriter.DefineDocument (Path);
+                               if (AutoGenerated)
+                                       file.SetAutoGenerated ();
+                       }
                }
 
                public override string ToString ()
@@ -47,6 +72,82 @@ namespace Mono.CSharp {
                }
        }
 
+       public class CompilationUnit : SourceFile, ICompileUnit
+       {
+               CompileUnitEntry comp_unit;
+               Dictionary<string, SourceFile> include_files;
+               Dictionary<string, bool> conditionals;
+
+               public CompilationUnit (string name, string path, int index)
+                       : base (name, path, index, false)
+               { }
+
+               public void AddFile (SourceFile file)
+               {
+                       if (file == this)
+                               return;
+                       
+                       if (include_files == null)
+                               include_files = new Dictionary<string, SourceFile> ();
+
+                       if (!include_files.ContainsKey (file.Path))
+                               include_files.Add (file.Path, 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;
+               }
+
+               CompileUnitEntry ICompileUnit.Entry {
+                       get { return comp_unit; }
+               }
+
+               public CompileUnitEntry CompileUnitEntry {
+                       get { return comp_unit; }
+               }
+
+               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 (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 RootContext.IsConditionalDefined (value);
+               }
+       }
+
        /// <summary>
        ///   Keeps track of the location in the program
        /// </summary>
@@ -68,20 +169,24 @@ namespace Mono.CSharp {
 
                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 List<SourceFile> source_list;
+               static List<CompilationUnit> compile_units;
+               static Dictionary<string, int> source_files;
                static int checkpoint_bits;
                static int source_count;
                static int current_source;
+               static int current_compile_unit;
                static int line_delta_bits;
                static int line_delta_mask;
                static int column_bits;
@@ -94,46 +199,45 @@ namespace Mono.CSharp {
                
                static Location ()
                {
-                       source_files = new Hashtable ();
-                       source_list = new ArrayList ();
-                       current_source = 0;
+                       Reset ();
                        checkpoints = new Checkpoint [10];
                }
 
                public static void Reset ()
                {
-                       source_files = new Hashtable ();
-                       source_list = new ArrayList ();
+                       source_files = new Dictionary<string, int> ();
+                       source_list = new List<SourceFile> ();
+                       compile_units = new List<CompilationUnit> ();
                        current_source = 0;
+                       current_compile_unit = 0;
                        source_count = 0;
                }
 
                // <summary>
                //   This must be called before parsing/tokenizing any files.
                // </summary>
-               static public void AddFile (string name)
+               static public void AddFile (Report r, string name)
                {
                        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;
+                       int id;
+                       if (source_files.TryGetValue (path, out id)){
+                               string other_name = source_list [id - 1].Name;
                                if (name.Equals (other_name))
-                                       Report.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name);
+                                       r.Warning (2002, 1, "Source file `{0}' specified multiple times", other_name);
                                else
-                                       Report.Warning (2002, 1, "Source filenames `{0}' and `{1}' both refer to the same file: {2}", name, other_name, path);
+                                       r.Warning (2002, 1, "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));
+                       CompilationUnit unit = new CompilationUnit (name, path, source_count);
+                       source_list.Add (unit);
+                       compile_units.Add (unit);
                }
 
-               static public SourceFile[] SourceFiles {
+               public static IList<CompilationUnit> SourceFiles {
                        get {
-                               SourceFile[] retval = new SourceFile [source_list.Count];
-                               source_list.CopyTo (retval, 0);
-                               return retval;
+                               return compile_units;
                        }
                }
 
@@ -147,7 +251,7 @@ namespace Mono.CSharp {
                {
                        checkpoints = new Checkpoint [source_list.Count * 2];
                        if (checkpoints.Length > 0)
-                               checkpoints [0] = new Checkpoint (0, 0);
+                               checkpoints [0] = new Checkpoint (0, 0, 0);
 
                        column_bits = 8;
                        column_mask = 0xFF;
@@ -160,16 +264,21 @@ namespace Mono.CSharp {
                // <remarks>
                //   This is used when we encounter a #line preprocessing directive.
                // </remarks>
-               static public SourceFile LookupFile (string name)
+               static public SourceFile LookupFile (CompilationUnit comp_unit, string name)
                {
-                       string path = name.Length == 0 ? "" : Path.GetFullPath (name);
-
-                       if (!source_files.Contains (path)) {
+                       string path;
+                       if (!Path.IsPathRooted (name)) {
+                               string root = Path.GetDirectoryName (comp_unit.Path);
+                               path = Path.Combine (root, name);
+                       } else
+                               path = name;
+
+                       if (!source_files.ContainsKey (path)) {
                                if (source_count >= (1 << checkpoint_bits))
-                                       return new SourceFile (name, path, 0);
+                                       return new SourceFile (name, path, 0, true);
 
                                source_files.Add (path, ++source_count);
-                               SourceFile retval = new SourceFile (name, path, source_count);
+                               SourceFile retval = new SourceFile (name, path, source_count, true);
                                source_list.Add (retval);
                                return retval;
                        }
@@ -178,9 +287,10 @@ namespace Mono.CSharp {
                        return (SourceFile) source_list [index - 1];
                }
 
-               static public void Push (SourceFile file)
+               static public void Push (CompilationUnit 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.
                }
 
@@ -189,11 +299,10 @@ namespace Mono.CSharp {
                //   and code generation to register all the source files with the
                //   symbol writer.
                // </remarks>
-               static public void DefineSymbolDocuments (SymbolWriter symwriter)
+               static public void DefineSymbolDocuments (MonoSymbolWriter symwriter)
                {
-                       foreach (SourceFile file in source_list) {
-                               file.SourceFileEntry = symwriter.DefineDocument (file.Path);
-                       }
+                       foreach (CompilationUnit unit in compile_units)
+                               unit.DefineSymbolInfo (symwriter);
                }
                
                public Location (int row)
@@ -206,7 +315,9 @@ namespace Mono.CSharp {
                        if (row <= 0)
                                token = 0;
                        else {
-                               if (column > 255)
+                               if (column > 254)
+                                       column = 254;
+                               if (column < 0)
                                        column = 255;
                                int target = -1;
                                int delta = 0;
@@ -223,7 +334,7 @@ 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);
                                }
@@ -234,22 +345,22 @@ namespace Mono.CSharp {
                        }
                }
 
-               static void AddCheckpoint (int file, int row)
+               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;
                        }
-                       checkpoints [checkpoint_index] = new Checkpoint (file, row);
+                       checkpoints [checkpoint_index] = new Checkpoint (compile_unit, file, row);
                }
-
+               
                public override string ToString ()
                {
                        if (column_bits == 0 || InEmacs)
-                               return Name + "(" + Row + "):";
+                               return Name + "(" + Row.ToString () + "):";
                        else
-                               return Name + "(" + Row + "," + Column +
+                               return Name + "(" + Row.ToString () + "," + Column.ToString () +
                                        (Column == column_mask ? "+):" : "):");
                }
                
@@ -287,7 +398,23 @@ namespace Mono.CSharp {
                        get {
                                if (token == 0)
                                        return 1;
-                               return (int) (token & column_mask);
+                               int col = (int) (token & column_mask);
+                               return col == 255 ? 1 : col;
+                       }
+               }
+
+               public bool Hidden {
+                       get {
+                               return (int) (token & column_mask) == 255;
+                       }
+               }
+
+               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;
                        }
                }
 
@@ -320,22 +447,14 @@ if (checkpoints.Length <= CheckpointIndex) throw new Exception (String.Format ("
                                return (SourceFile) source_list [index - 1];
                        }
                }
-       }
-
-       public class LocatedToken
-       {
-               public readonly Location Location;
-               public readonly string Value;
-
-               public LocatedToken (Location loc, string value)
-               {
-                       Location = loc;
-                       Value = value;
-               }
 
-               public override string ToString ()
-               {
-                       return Location.ToString () + Value;
+               public CompilationUnit CompilationUnit {
+                       get {
+                               int index = CompilationUnitIndex;
+                               if (index == 0)
+                                       return null;
+                               return (CompilationUnit) source_list [index - 1];
+                       }
                }
        }
 }