File: System\Activities\Debugger\SourceLocation.cs
Project: ndp\cdf\src\NetFx40\System.Activities\System.Activities.csproj (System.Activities)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
namespace System.Activities.Debugger
{
    using System;
    using System.Activities.Debugger.Symbol;
    using System.Diagnostics;
    using System.Linq;
    using System.Runtime;
 
    // Identifies a specific location in the target source code.
    //
    // This source information is used in creating PDBs, which will be passed to the debugger,
    // which will resolve the source file based off its own source paths.
    // Source ranges can:
    // * refer to just an entire single line.
    // * can be a subset within a single line (when StartLine == EndLine)
    // * can also span multiple lines.
    // When column info is provided, the debugger will highlight the characters starting at the start line and start column,
    // and going up to but not including the character specified by the end line and end column.
    [Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - Our partial trust mechanisms require that this class remain Immutable. Do not add code that allows an instance of this class to change after creation without strict review.")]
    [DebuggerNonUserCode]
    [Serializable]
    [Fx.Tag.XamlVisible(false)]
    public class SourceLocation
    {
        string fileName;
        int startLine;
        int endLine;
        int startColumn;
        int endColumn;
        byte[] checksum;
 
        // Define a source location from a filename and line-number (1-based).
        // This is a convenience constructor to specify the entire line.
        // This does not load the source file to determine column ranges.
        public SourceLocation(string fileName, int line)
            : this(fileName, line, 1, line, int.MaxValue)
        {
        }
 
        public SourceLocation(
           string fileName,
           int startLine,
           int startColumn,
           int endLine,
           int endColumn)
            : this(fileName, null, startLine, startColumn, endLine, endColumn)
        {
        }
 
        // Define a source location in a file.
        // Line/Column are 1-based.
        internal SourceLocation(
            string fileName,
            byte[] checksum,
            int startLine,
            int startColumn,
            int endLine,
            int endColumn)
        {
            if (startLine <= 0)
            {
                throw FxTrace.Exception.Argument("startLine", SR.InvalidSourceLocationLineNumber("startLine", startLine));
            }
 
            if (startColumn <= 0)
            {
                throw FxTrace.Exception.Argument("startColumn", SR.InvalidSourceLocationColumn("startColumn", startColumn));
            }
 
            if (endLine <= 0)
            {
                throw FxTrace.Exception.Argument("endLine", SR.InvalidSourceLocationLineNumber("endLine", endLine));
            }
 
            if (endColumn <= 0)
            {
                throw FxTrace.Exception.Argument("endColumn", SR.InvalidSourceLocationColumn("endColumn", endColumn));
            }
 
            if (startLine > endLine)
            {
                throw FxTrace.Exception.ArgumentOutOfRange("endLine", endLine, SR.OutOfRangeSourceLocationEndLine(startLine));
            }
 
            if ((startLine == endLine) && (startColumn > endColumn))
            {
                throw FxTrace.Exception.ArgumentOutOfRange("endColumn", endColumn, SR.OutOfRangeSourceLocationEndColumn(startColumn));
            }
 
            this.fileName = (fileName != null) ? fileName.ToUpperInvariant() : null;
            this.startLine = startLine;
            this.endLine = endLine;
            this.startColumn = startColumn;
            this.endColumn = endColumn;
            this.checksum = checksum;
        }
 
        public string FileName
        {
            get { return this.fileName; }
        }
 
        // Get the 1-based start line.
        public int StartLine
        {
            get { return this.startLine; }
        }
 
        // Get the 1-based starting column.
        public int StartColumn
        {
            get { return this.startColumn; }
        }
 
        // Get the 1-based end line. This should be greater or equal to StartLine.
        public int EndLine
        {
            get { return this.endLine; }
        }
 
        // Get the 1-based ending column.
        public int EndColumn
        {
            get { return this.endColumn; }
        }
 
        // get the checksum of the source file
        internal byte[] Checksum
        {
            get { return this.checksum; }
        }
 
        public bool IsSingleWholeLine
        {
            get
            {
                return this.endColumn == int.MaxValue && this.startLine == this.endLine && this.startColumn == 1;
            }
        }
 
        // Equality comparison function. This checks for strict equality and
        // not for superset or subset relationships.
        public override bool Equals(object obj)
        {
            SourceLocation rsl = obj as SourceLocation;
            if (rsl == null)
            {
                return false;
            }
 
            if (this.FileName != rsl.FileName)
            {
                return false;
            }            
 
            if (this.StartLine != rsl.StartLine ||
                this.StartColumn != rsl.StartColumn ||
                this.EndLine != rsl.EndLine ||
                this.EndColumn != rsl.EndColumn)
            {
                return false;
            }
 
            if (this.Checksum == null ^ rsl.Checksum == null)
            {
                return false;
            }
            else if ((this.Checksum != null && rsl.Checksum != null) && !this.Checksum.SequenceEqual(rsl.Checksum))
            {
                return false;
            }
 
            // everything matches
            return true;
        }
 
        // Get a hash code.
        public override int GetHashCode()
        {
            return (string.IsNullOrEmpty(this.FileName) ? 0 : this.FileName.GetHashCode()) ^
                    this.StartLine.GetHashCode() ^
                    this.StartColumn.GetHashCode() ^
                    ((this.Checksum == null) ? 0 : SymbolHelper.GetHexStringFromChecksum(this.Checksum).GetHashCode());
        }
 
        internal static bool IsValidRange(int startLine, int startColumn, int endLine, int endColumn)
        {
            return
                (startLine > 0) && (startColumn > 0) && (endLine > 0) && (endColumn > 0) &&
                ((startLine < endLine) || (startLine == endLine) && (startColumn < endColumn));
 
        }
    }
}