Merge pull request #702 from jtattermusch/visual_studio_build_static_runtime

Link runtime statically for VS build
diff --git a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
index c8326d8..54c44e4 100644
--- a/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
+++ b/csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
@@ -320,38 +320,18 @@
 

             Assert.Throws<InvalidProtocolBufferException>(() => TestRecursiveMessage.Parser.ParseFrom(data65));

 

-            CodedInputStream input = data64.CreateCodedInput();

-            input.SetRecursionLimit(8);

+            CodedInputStream input = CodedInputStream.CreateWithLimits(new MemoryStream(data64.ToByteArray()), 1000000, 63);

             Assert.Throws<InvalidProtocolBufferException>(() => TestRecursiveMessage.Parser.ParseFrom(input));

         }

 

-        /*

         [Test]

         public void SizeLimit()

         {

             // Have to use a Stream rather than ByteString.CreateCodedInput as SizeLimit doesn't

             // apply to the latter case.

-            MemoryStream ms = new MemoryStream(TestUtil.GetAllSet().ToByteString().ToByteArray());

-            CodedInputStream input = new CodedInputStream(ms);

-            input.SetSizeLimit(16);

-

-            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.ParseFrom(input));

-        }*/

-

-        [Test]

-        public void ResetSizeCounter()

-        {

-            CodedInputStream input = new CodedInputStream(

-                new SmallBlockInputStream(new byte[256], 8));

-            input.SetSizeLimit(16);

-            input.ReadRawBytes(16);

-

-            Assert.Throws<InvalidProtocolBufferException>(() => input.ReadRawByte());

-

-            input.ResetSizeCounter();

-            input.ReadRawByte(); // No exception thrown.

-

-            Assert.Throws<InvalidProtocolBufferException>(() => input.ReadRawBytes(16));

+            MemoryStream ms = new MemoryStream(SampleMessages.CreateFullTestAllTypes().ToByteArray());

+            CodedInputStream input = CodedInputStream.CreateWithLimits(ms, 16, 100);

+            Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(input));

         }

 

         /// <summary>

@@ -423,7 +403,7 @@
                 output.Flush();

 

                 ms.Position = 0;

-                CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2]);

+                CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0);

 

                 uint tag = input.ReadTag();

                 Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag));

@@ -528,5 +508,23 @@
             Assert.AreEqual(WireFormat.MakeTag(1, WireFormat.WireType.StartGroup), input.ReadTag());

             Assert.Throws<InvalidProtocolBufferException>(() => input.SkipLastField());

         }

+

+        [Test]

+        public void Construction_Invalid()

+        {

+            Assert.Throws<ArgumentNullException>(() => new CodedInputStream((byte[]) null));

+            Assert.Throws<ArgumentNullException>(() => new CodedInputStream(null, 0, 0));

+            Assert.Throws<ArgumentNullException>(() => new CodedInputStream((Stream) null));

+            Assert.Throws<ArgumentOutOfRangeException>(() => new CodedInputStream(new byte[10], 100, 0));

+            Assert.Throws<ArgumentOutOfRangeException>(() => new CodedInputStream(new byte[10], 5, 10));

+        }

+

+        [Test]

+        public void CreateWithLimits_InvalidLimits()

+        {

+            var stream = new MemoryStream();

+            Assert.Throws<ArgumentOutOfRangeException>(() => CodedInputStream.CreateWithLimits(stream, 0, 1));

+            Assert.Throws<ArgumentOutOfRangeException>(() => CodedInputStream.CreateWithLimits(stream, 1, 0));

+        }

     }

 }
\ No newline at end of file
diff --git a/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs
index c1bf7bd..3297fe8 100644
--- a/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs
+++ b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs
@@ -334,7 +334,7 @@
             }

             // Now test Input stream:

             {

-                CodedInputStream cin = new CodedInputStream(new MemoryStream(bytes), new byte[50]);

+                CodedInputStream cin = new CodedInputStream(new MemoryStream(bytes), new byte[50], 0, 0);

                 Assert.AreEqual(0, cin.Position);

                 // Field 1:

                 uint tag = cin.ReadTag();

diff --git a/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs b/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
index c62ac04..29c4c2a 100644
--- a/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs
@@ -477,6 +477,91 @@
             Assert.IsTrue(new MapField<int, int?>(true).AllowsNullValues);
         }
 
+        [Test]
+        public void KeysReturnsLiveView()
+        {
+            var map = new MapField<string, string>();
+            var keys = map.Keys;
+            CollectionAssert.AreEqual(new string[0], keys);
+            map["foo"] = "bar";
+            map["x"] = "y";
+            CollectionAssert.AreEqual(new[] { "foo", "x" }, keys);
+        }
+
+        [Test]
+        public void ValuesReturnsLiveView()
+        {
+            var map = new MapField<string, string>();
+            var values = map.Values;
+            CollectionAssert.AreEqual(new string[0], values);
+            map["foo"] = "bar";
+            map["x"] = "y";
+            CollectionAssert.AreEqual(new[] { "bar", "y" }, values);
+        }
+
+        // Just test keys - we know the implementation is the same for values
+        [Test]
+        public void ViewsAreReadOnly()
+        {
+            var map = new MapField<string, string>();
+            var keys = map.Keys;
+            Assert.IsTrue(keys.IsReadOnly);
+            Assert.Throws<NotSupportedException>(() => keys.Clear());
+            Assert.Throws<NotSupportedException>(() => keys.Remove("a"));
+            Assert.Throws<NotSupportedException>(() => keys.Add("a"));
+        }
+
+        // Just test keys - we know the implementation is the same for values
+        [Test]
+        public void ViewCopyTo()
+        {
+            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            var keys = map.Keys;
+            var array = new string[4];
+            Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
+            Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
+            keys.CopyTo(array, 1);
+            CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
+        }
+        
+        // Just test keys - we know the implementation is the same for values
+        [Test]
+        public void NonGenericViewCopyTo()
+        {
+            IDictionary map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            ICollection keys = map.Keys;
+            // Note the use of the Array type here rather than string[]
+            Array array = new string[4];
+            Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
+            Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
+            keys.CopyTo(array, 1);
+            CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
+        }
+
+        [Test]
+        public void KeysContains()
+        {
+            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            var keys = map.Keys;
+            Assert.IsTrue(keys.Contains("foo"));
+            Assert.IsFalse(keys.Contains("bar")); // It's a value!
+            Assert.IsFalse(keys.Contains("1"));
+            // Keys can't be null, so we should prevent contains check
+            Assert.Throws<ArgumentNullException>(() => keys.Contains(null));
+        }
+
+        [Test]
+        public void ValuesContains()
+        {
+            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
+            var values = map.Values;
+            Assert.IsTrue(values.Contains("bar"));
+            Assert.IsFalse(values.Contains("foo")); // It's a key!
+            Assert.IsFalse(values.Contains("1"));
+            // Values can be null, so this makes sense
+            Assert.IsFalse(values.Contains(null));
+        }
+
         private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
         {
             return new KeyValuePair<TKey, TValue>(key, value);
diff --git a/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs
index 6e1d804..936e41c 100644
--- a/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs
+++ b/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs
@@ -213,6 +213,6 @@
             var descriptor = TestAllTypes.Descriptor;
             Assert.Throws<KeyNotFoundException>(() => descriptor.Fields[999999].ToString());
             Assert.Throws<KeyNotFoundException>(() => descriptor.Fields["not found"].ToString());
-        }
+        }        
     }
 }
diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs
index c8b33b3..82c6cea 100644
--- a/csharp/src/Google.Protobuf/CodedInputStream.cs
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -53,16 +53,13 @@
     /// </remarks>

     public sealed class CodedInputStream

     {

-        // TODO(jonskeet): Consider whether recursion and size limits shouldn't be readonly,

-        // set at construction time.

-

         /// <summary>

         /// Buffer of data read from the stream or provided at construction time.

         /// </summary>

         private readonly byte[] buffer;

 

         /// <summary>

-        /// The number of valid bytes in the buffer.

+        /// The index of the buffer at which we need to refill from the stream (if there is one).

         /// </summary>

         private int bufferSize;

 

@@ -106,62 +103,104 @@
         /// </summary> 

         private int currentLimit = int.MaxValue;

 

-        /// <summary>

-        /// <see cref="SetRecursionLimit"/>

-        /// </summary>

         private int recursionDepth = 0;

 

-        private int recursionLimit = DefaultRecursionLimit;

-

-        /// <summary>

-        /// <see cref="SetSizeLimit"/>

-        /// </summary>

-        private int sizeLimit = DefaultSizeLimit;

+        private readonly int recursionLimit;

+        private readonly int sizeLimit;

 

         #region Construction

+        // Note that the checks are performed such that we don't end up checking obviously-valid things

+        // like non-null references for arrays we've just created.

+

         /// <summary>

-        /// Creates a new CodedInputStream reading data from the given

-        /// byte array.

+        /// Creates a new CodedInputStream reading data from the given byte array.

         /// </summary>

-        public CodedInputStream(byte[] buf) : this(buf, 0, buf.Length)

-        {

+        public CodedInputStream(byte[] buffer) : this(null, Preconditions.CheckNotNull(buffer, "buffer"), 0, buffer.Length)

+        {            

         }

 

         /// <summary>

-        /// Creates a new CodedInputStream that reads from the given

-        /// byte array slice.

+        /// Creates a new CodedInputStream that reads from the given byte array slice.

         /// </summary>

         public CodedInputStream(byte[] buffer, int offset, int length)

-        {

-            this.buffer = buffer;

-            this.bufferPos = offset;

-            this.bufferSize = offset + length;

-            this.input = null;

+            : this(null, Preconditions.CheckNotNull(buffer, "buffer"), offset, offset + length)

+        {            

+            if (offset < 0 || offset > buffer.Length)

+            {

+                throw new ArgumentOutOfRangeException("offset", "Offset must be within the buffer");

+            }

+            if (length < 0 || offset + length > buffer.Length)

+            {

+                throw new ArgumentOutOfRangeException("length", "Length must be non-negative and within the buffer");

+            }

         }

 

         /// <summary>

         /// Creates a new CodedInputStream reading data from the given stream.

         /// </summary>

-        public CodedInputStream(Stream input)

+        public CodedInputStream(Stream input) : this(input, new byte[BufferSize], 0, 0)

         {

-            this.buffer = new byte[BufferSize];

-            this.bufferSize = 0;

-            this.input = input;

+            Preconditions.CheckNotNull(input, "input");

         }

 

         /// <summary>

         /// Creates a new CodedInputStream reading data from the given

-        /// stream, with a pre-allocated buffer.

+        /// stream and buffer, using the default limits.

         /// </summary>

-        internal CodedInputStream(Stream input, byte[] buffer)

+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize)

         {

-            this.buffer = buffer;

-            this.bufferSize = 0;

             this.input = input;

+            this.buffer = buffer;

+            this.bufferPos = bufferPos;

+            this.bufferSize = bufferSize;

+            this.sizeLimit = DefaultSizeLimit;

+            this.recursionLimit = DefaultRecursionLimit;

+        }

+

+        /// <summary>

+        /// Creates a new CodedInputStream reading data from the given

+        /// stream and buffer, using the specified limits.

+        /// </summary>

+        /// <remarks>

+        /// This chains to the version with the default limits instead of vice versa to avoid

+        /// having to check that the default values are valid every time.

+        /// </remarks>

+        internal CodedInputStream(Stream input, byte[] buffer, int bufferPos, int bufferSize, int sizeLimit, int recursionLimit)

+            : this(input, buffer, bufferPos, bufferSize)

+        {

+            if (sizeLimit <= 0)

+            {

+                throw new ArgumentOutOfRangeException("sizeLimit", "Size limit must be positive");

+            }

+            if (recursionLimit <= 0)

+            {

+                throw new ArgumentOutOfRangeException("recursionLimit!", "Recursion limit must be positive");

+            }

+            this.sizeLimit = sizeLimit;

+            this.recursionLimit = recursionLimit;

         }

         #endregion

 

         /// <summary>

+        /// Creates a <see cref="CodedInputStream"/> with the specified size and recursion limits, reading

+        /// from an input stream.

+        /// </summary>

+        /// <remarks>

+        /// This method exists separately from the constructor to reduce the number of constructor overloads.

+        /// It is likely to be used considerably less frequently than the constructors, as the default limits

+        /// are suitable for most use cases.

+        /// </remarks>

+        /// <param name="input">The input stream to read from</param>

+        /// <param name="sizeLimit">The total limit of data to read from the stream.</param>

+        /// <param name="recursionLimit">The maximum recursion depth to allow while reading.</param>

+        /// <returns>A <c>CodedInputStream</c> reading from <paramref name="input"/> with the specified size

+        /// and recursion limits.</returns>

+        public static CodedInputStream CreateWithLimits(Stream input, int sizeLimit, int recursionLimit)

+        {

+            return new CodedInputStream(input, new byte[BufferSize], 0, 0, sizeLimit, recursionLimit);

+        }

+

+        /// <summary>

         /// Returns the current position in the input stream, or the position in the input buffer

         /// </summary>

         public long Position 

@@ -182,59 +221,30 @@
         /// </summary>

         internal uint LastTag { get { return lastTag; } }

 

-        #region Limits for recursion and length

         /// <summary>

-        /// Set the maximum message recursion depth.

+        /// Returns the size limit for this stream.

         /// </summary>

         /// <remarks>

-        /// In order to prevent malicious

-        /// messages from causing stack overflows, CodedInputStream limits

-        /// how deeply messages may be nested.  The default limit is 64.

+        /// This limit is applied when reading from the underlying stream, as a sanity check. It is

+        /// not applied when reading from a byte array data source without an underlying stream.

+        /// The default value is 64MB.

         /// </remarks>

-        public int SetRecursionLimit(int limit)

-        {

-            if (limit < 0)

-            {

-                throw new ArgumentOutOfRangeException("Recursion limit cannot be negative: " + limit);

-            }

-            int oldLimit = recursionLimit;

-            recursionLimit = limit;

-            return oldLimit;

-        }

+        /// <value>

+        /// The size limit.

+        /// </value>

+        public int SizeLimit { get { return sizeLimit; } }

 

         /// <summary>

-        /// Set the maximum message size.

+        /// Returns the recursion limit for this stream. This limit is applied whilst reading messages,

+        /// to avoid maliciously-recursive data.

         /// </summary>

         /// <remarks>

-        /// In order to prevent malicious messages from exhausting memory or

-        /// causing integer overflows, CodedInputStream limits how large a message may be.

-        /// The default limit is 64MB.  You should set this limit as small

-        /// as you can without harming your app's functionality.  Note that

-        /// size limits only apply when reading from an InputStream, not

-        /// when constructed around a raw byte array (nor with ByteString.NewCodedInput).

-        /// If you want to read several messages from a single CodedInputStream, you

-        /// can call ResetSizeCounter() after each message to avoid hitting the

-        /// size limit.

+        /// The default limit is 64.

         /// </remarks>

-        public int SetSizeLimit(int limit)

-        {

-            if (limit < 0)

-            {

-                throw new ArgumentOutOfRangeException("Size limit cannot be negative: " + limit);

-            }

-            int oldLimit = sizeLimit;

-            sizeLimit = limit;

-            return oldLimit;

-        }

-

-        /// <summary>

-        /// Resets the current size counter to zero (see <see cref="SetSizeLimit"/>).

-        /// </summary>

-        public void ResetSizeCounter()

-        {

-            totalBytesRetired = 0;

-        }

-        #endregion

+        /// <value>

+        /// The recursion limit for this stream.

+        /// </value>

+        public int RecursionLimit { get { return recursionLimit; } }

 

         #region Validation

         /// <summary>

diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
index dc4b04c..0fa63be 100644
--- a/csharp/src/Google.Protobuf/Collections/MapField.cs
+++ b/csharp/src/Google.Protobuf/Collections/MapField.cs
@@ -136,6 +136,12 @@
             return map.ContainsKey(key);
         }
 
+        private bool ContainsValue(TValue value)
+        {
+            var comparer = EqualityComparer<TValue>.Default;
+            return list.Any(pair => comparer.Equals(pair.Value, value));
+        }
+
         /// <summary>
         /// Removes the entry identified by the given key from the map.
         /// </summary>
@@ -221,17 +227,15 @@
             }
         }
 
-        // TODO: Make these views?
-
         /// <summary>
         /// Gets a collection containing the keys in the map.
         /// </summary>
-        public ICollection<TKey> Keys { get { return list.Select(t => t.Key).ToList(); } }
+        public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pair => pair.Key, ContainsKey); } }
 
         /// <summary>
         /// Gets a collection containing the values in the map.
         /// </summary>
-        public ICollection<TValue> Values { get { return list.Select(t => t.Value).ToList(); } }
+        public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }
 
         /// <summary>
         /// Adds the specified entries to the map.
@@ -658,5 +662,92 @@
                 MessageDescriptor IMessage.Descriptor { get { return null; } }
             }
         }
+
+        private class MapView<T> : ICollection<T>, ICollection
+        {
+            private readonly MapField<TKey, TValue> parent;
+            private readonly Func<KeyValuePair<TKey, TValue>, T> projection;
+            private readonly Func<T, bool> containsCheck;
+
+            internal MapView(
+                MapField<TKey, TValue> parent,
+                Func<KeyValuePair<TKey, TValue>, T> projection,
+                Func<T, bool> containsCheck)
+            {
+                this.parent = parent;
+                this.projection = projection;
+                this.containsCheck = containsCheck;
+            }
+
+            public int Count { get { return parent.Count; } }
+
+            public bool IsReadOnly { get { return true; } }
+
+            public bool IsSynchronized { get { return false; } }
+
+            public object SyncRoot { get { return parent; } }
+
+            public void Add(T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            public void Clear()
+            {
+                throw new NotSupportedException();
+            }
+
+            public bool Contains(T item)
+            {
+                return containsCheck(item);
+            }
+
+            public void CopyTo(T[] array, int arrayIndex)
+            {
+                if (arrayIndex < 0)
+                {
+                    throw new ArgumentOutOfRangeException("arrayIndex");
+                }
+                if (arrayIndex + Count  >= array.Length)
+                {
+                    throw new ArgumentException("Not enough space in the array", "array");
+                }
+                foreach (var item in this)
+                {
+                    array[arrayIndex++] = item;
+                }
+            }
+
+            public IEnumerator<T> GetEnumerator()
+            {
+                return parent.list.Select(projection).GetEnumerator();
+            }
+
+            public bool Remove(T item)
+            {
+                throw new NotSupportedException();
+            }
+
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                return GetEnumerator();
+            }
+
+            public void CopyTo(Array array, int index)
+            {
+                if (index < 0)
+                {
+                    throw new ArgumentOutOfRangeException("index");
+                }
+                if (index + Count >= array.Length)
+                {
+                    throw new ArgumentException("Not enough space in the array", "array");
+                }
+                foreach (var item in this)
+                {
+                    array.SetValue(item, index++);
+                }
+            }
+        }
     }
 }
diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
index 033edfb..a17bf81 100644
--- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj
+++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj
@@ -83,6 +83,7 @@
     <Compile Include="Compatibility\TypeExtensions.cs" />

     <Compile Include="FieldCodec.cs" />

     <Compile Include="FrameworkPortability.cs" />

+    <Compile Include="IDeepCloneable.cs" />

     <Compile Include="JsonFormatter.cs" />

     <Compile Include="MessageExtensions.cs" />

     <Compile Include="IMessage.cs" />

diff --git a/csharp/src/Google.Protobuf/IDeepCloneable.cs b/csharp/src/Google.Protobuf/IDeepCloneable.cs
new file mode 100644
index 0000000..c9c71bb
--- /dev/null
+++ b/csharp/src/Google.Protobuf/IDeepCloneable.cs
@@ -0,0 +1,54 @@
+#region Copyright notice and license
+// Protocol Buffers - Google's data interchange format
+// Copyright 2015 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+
+namespace Google.Protobuf
+{
+    /// <summary>
+    /// Generic interface for a deeply cloneable type.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// All generated messages implement this interface, but so do some non-message types.
+    /// Additionally, due to the type constraint on <c>T</c> in <see cref="IMessage{T}"/>,
+    /// it is simpler to keep this as a separate interface.
+    /// </para>
+    /// </remarks>
+    /// <typeparam name="T">The type itself, returned by the <see cref="Clone"/> method.</typeparam>
+    public interface IDeepCloneable<T>
+    {
+        /// <summary>
+        /// Creates a deep clone of this object.
+        /// </summary>
+        /// <returns>A deep clone of this object.</returns>
+        T Clone();
+    }
+}
diff --git a/csharp/src/Google.Protobuf/IMessage.cs b/csharp/src/Google.Protobuf/IMessage.cs
index 773845f..d089f94 100644
--- a/csharp/src/Google.Protobuf/IMessage.cs
+++ b/csharp/src/Google.Protobuf/IMessage.cs
@@ -35,8 +35,6 @@
 

 namespace Google.Protobuf

 {

-    // TODO(jonskeet): Split these interfaces into separate files when we're happy with them.

-

     /// <summary>

     /// Interface for a Protocol Buffers message, supporting

     /// basic operations required for serialization.

@@ -86,24 +84,4 @@
         /// <param name="message">The message to merge with this one. Must not be null.</param>

         void MergeFrom(T message);

     }

-

-    /// <summary>

-    /// Generic interface for a deeply cloneable type.

-    /// </summary>

-    /// <remarks>

-    /// <para>

-    /// All generated messages implement this interface, but so do some non-message types.

-    /// Additionally, due to the type constraint on <c>T</c> in <see cref="IMessage{T}"/>,

-    /// it is simpler to keep this as a separate interface.

-    /// </para>

-    /// </remarks>

-    /// <typeparam name="T">The type itself, returned by the <see cref="Clone"/> method.</typeparam>

-    public interface IDeepCloneable<T>

-    {

-        /// <summary>

-        /// Creates a deep clone of this object.

-        /// </summary>

-        /// <returns>A deep clone of this object.</returns>

-        T Clone();

-    }

 }

diff --git a/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs b/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs
index 157ea40..759955e 100644
--- a/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs
+++ b/csharp/src/Google.Protobuf/Reflection/DescriptorPool.cs
@@ -257,10 +257,12 @@
         /// or unqualified. C++-like name lookup semantics are used to search for the
         /// matching descriptor.
         /// </summary>
+        /// <remarks>
+        /// This isn't heavily optimized, but it's only used during cross linking anyway.
+        /// If it starts being used more widely, we should look at performance more carefully.
+        /// </remarks>
         internal IDescriptor LookupSymbol(string name, IDescriptor relativeTo)
         {
-            // TODO(jonskeet):  This could be optimized in a number of ways.
-
             IDescriptor result;
             if (name.StartsWith("."))
             {
@@ -282,7 +284,6 @@
                 {
                     // Chop off the last component of the scope.
 
-                    // TODO(jonskeet): Make this more efficient. May not be worth using StringBuilder at all
                     int dotpos = scopeToTry.ToString().LastIndexOf(".");
                     if (dotpos == -1)
                     {
diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
index bb8e9bb..901cbf4 100644
--- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
+++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
@@ -168,14 +168,16 @@
             get { return fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry; }
         }
 
-        // TODO(jonskeet): Check whether this is correct with proto3, where we default to packed...
-
         /// <summary>
         /// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
         /// </summary>
         public bool IsPacked
         {
-            get { return Proto.Options != null && Proto.Options.Packed; }
+            // Note the || rather than && here - we're effectively defaulting to packed, because that *is*
+            // the default in proto3, which is all we support. We may give the wrong result for the protos
+            // within descriptor.proto, but that's okay, as they're never exposed and we don't use IsPacked
+            // within the runtime.
+            get { return Proto.Options == null || Proto.Options.Packed; }
         }        
 
         /// <summary>
diff --git a/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs b/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs
index c7ed434..8c055d6 100644
--- a/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs
+++ b/csharp/src/Google.Protobuf/Reflection/PartialClasses.cs
@@ -44,4 +44,16 @@
             OneofIndex = -1;

         }

     }

+

+    internal partial class FieldOptions

+    {

+        // We can't tell the difference between "explicitly set to false" and "not set"

+        // in proto3, but we need to tell the difference for FieldDescriptor.IsPacked.

+        // This won't work if we ever need to support proto2, but at that point we'll be

+        // able to remove this hack and use field presence instead. 

+        partial void OnConstruction()

+        {

+            Packed = true;

+        }

+    }

 }
\ No newline at end of file
diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h
index 050f85f..28442fb 100644
--- a/objectivec/GPBWellKnownTypes.h
+++ b/objectivec/GPBWellKnownTypes.h
@@ -30,11 +30,9 @@
 
 #import <Foundation/Foundation.h>
 
-#import "google/protobuf/Any.pbobjc.h"
 #import "google/protobuf/Duration.pbobjc.h"
 #import "google/protobuf/Timestamp.pbobjc.h"
 
-
 NS_ASSUME_NONNULL_BEGIN
 
 // Extension to GPBTimestamp to work with standard Foundation time/date types.
@@ -51,22 +49,4 @@
 - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970;
 @end
 
-// Extension to GPBAny to support packing and unpacking for arbitrary messages.
-@interface GPBAny (GPBWellKnownTypes)
-// Initialize GPBAny instance with the given message. e.g., for google.protobuf.foo, type
-// url will be "type.googleapis.com/google.protobuf.foo" and value will be serialized foo.
-- (instancetype)initWithMessage:(GPBMessage*)message;
-// Serialize the given message to the value in GPBAny. Type url will also be updated.
-- (void)setMessage:(GPBMessage*)message;
-// Parse the value in GPBAny to the given message. If messageClass message doesn't match the
-// type url in GPBAny, nil is returned.
-- (GPBMessage*)messageOfClass:(Class)messageClass;
-// True if the given type matches the type url in GPBAny.
-- (BOOL)wrapsMessageOfClass:(Class)messageClass;
-@end
-
-// Common prefix of type url in GPBAny, which is @"type.googleapis.com/". All valid
-// type urls in any should start with this prefix.
-extern NSString *const GPBTypeGoogleApisComPrefix;
-
 NS_ASSUME_NONNULL_END
diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m
index b48f8a5..fe02f5d 100644
--- a/objectivec/GPBWellKnownTypes.m
+++ b/objectivec/GPBWellKnownTypes.m
@@ -115,52 +115,3 @@
 }
 
 @end
-
-NSString *const GPBTypeGoogleApisComPrefix = @"type.googleapis.com/";
-
-@implementation GPBAny (GBPWellKnownTypes)
-
-- (instancetype)initWithMessage:(GPBMessage*)message {
-  self = [super init];
-  if (self) {
-    [self setMessage:message];
-  }
-  return self;
-}
-
-- (NSString*)typeName {
-  NSAssert([self.typeURL hasPrefix:GPBTypeGoogleApisComPrefix],
-           @"Invalid any type url (%@).", self.typeURL);
-  if (![self.typeURL hasPrefix:GPBTypeGoogleApisComPrefix]) {
-    return nil;
-  }
-  return [self.typeURL substringFromIndex:[GPBTypeGoogleApisComPrefix length]];
-}
-
-- (void)setMessage:(GPBMessage*)message {
-  self.typeURL = [GPBTypeGoogleApisComPrefix stringByAppendingString:message.descriptor.name];
-  self.value = message.data;
-}
-
-- (GPBMessage*)messageOfClass:(Class)messageClass {
-  if ([self wrapsMessageOfClass:messageClass]) {
-    GPBMessage* message = [messageClass message];
-    [message mergeFromData:self.value extensionRegistry:nil];
-    return message;
-  } else {
-    return nil;
-  }
-}
-
-- (BOOL)wrapsMessageOfClass:(Class)messageClass {
-  NSAssert([messageClass isSubclassofClass:[GPBMessage class]],
-           @"Given class (%@) is not a subclass of GPBMessage",
-           [messageClass name]);
-  if (![messageClass isSubclassOfClass:[GPBMessage class]]) {
-    return NO;
-  }
-  return [[self typeName] isEqualToString:messageClass.descriptor.name];
-}
-
-@end
-
diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m
index 48c875a..78f4e63 100644
--- a/objectivec/Tests/GPBWellKnownTypesTest.m
+++ b/objectivec/Tests/GPBWellKnownTypesTest.m
@@ -28,9 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#import "google/protobuf/Unittest.pbobjc.h"
 #import "GPBWellKnownTypes.h"
-#import "GPBTestUtilities.h"
 
 #import <XCTest/XCTest.h>
 
@@ -40,7 +38,7 @@
 // Nanosecond time accuracy
 static const NSTimeInterval kTimeAccuracy = 1e-9;
 
-@interface WellKnownTypesTest : GPBTestCase
+@interface WellKnownTypesTest : XCTestCase
 @end
 
 @implementation WellKnownTypesTest
@@ -101,53 +99,4 @@
   [duration2 release];
 }
 
-- (void)testAnyPackingAndUnpacking {
-  TestAllTypes *from = [TestAllTypes message];
-  [self setAllFields:from repeatedCount:1];
-  NSData *data = from.data;
-
-  // Test initWithMessage
-  GPBAny *anyInited = [[GPBAny alloc] initWithMessage:from];
-  XCTAssertEqualObjects(
-      [GPBTypeGoogleApisComPrefix stringByAppendingString:from.descriptor.name],
-      anyInited.typeURL);
-  XCTAssertEqualObjects(data, anyInited.value);
-  [anyInited release];
-
-  // Test setMessage.
-  GPBAny *any = [GPBAny message];
-  [any setMessage:from];
-  XCTAssertEqualObjects(
-      [GPBTypeGoogleApisComPrefix stringByAppendingString:from.descriptor.name],
-      any.typeURL);
-  XCTAssertEqualObjects(data, any.value);
-
-  // Test messageOfClass
-  TestAllTypes *to = (TestAllTypes*)[any messageOfClass:[TestAllTypes class]];
-  XCTAssertEqualObjects(from, to);
-  XCTAssertEqual([any messageOfClass:[ForeignMessage class]], nil);
-  XCTAssertEqual([[GPBAny message] messageOfClass:[TestAllTypes class]], nil);
-
-  // Test setMessage with another type.
-  ForeignMessage *from2 = [ForeignMessage message];
-  [any setMessage:from2];
-  XCTAssertEqualObjects(
-      [GPBTypeGoogleApisComPrefix stringByAppendingString:from2.descriptor.name],
-      any.typeURL);
-  XCTAssertEqual(0UL, [any.value length]);
-
-  // Test wrapsMessageOfClass
-  XCTAssertTrue([any wrapsMessageOfClass:[from2 class]]);
-  XCTAssertFalse([any wrapsMessageOfClass:[from class]]);
-#if !defined(NS_BLOCK_ASSERTIONS)
-  // If assert is enabled, throw exception when the passed message class to
-  // wrapsMessageOfClass is not a child of GPBMessage.
-  XCTAssertThrows([any wrapsMessageOfClass:[NSString class]]);
-#else
-  // If assert is disabled, return false when the passed message class to
-  // wrapsMessageOfClass is not a child of GPBMessage.
-  XCTAssertFalse([any wrapsMessageOfClass:[NSString class]]);
-#endif
-}
-
 @end
diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
index 7e3bbee..cd29bcf 100644
--- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc
@@ -59,7 +59,7 @@
   // repeated fields varies by wire format. The wire format is encoded in the bottom 3 bits, which
   // never effects the tag size.
   int tag_size = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type());
-  uint tag = FixedMakeTag(descriptor_);
+  uint tag = internal::WireFormat::MakeTag(descriptor_);
   uint8 tag_array[5];
   io::CodedOutputStream::WriteTagToArray(tag, tag_array);
   string tag_bytes = SimpleItoa(tag_array[0]);
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
index 46f4fc3..d25dcba 100644
--- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc
@@ -338,17 +338,6 @@
   return StringToBase64(fdp_bytes);
 }
 
-// TODO(jonskeet): Remove this when internal::WireFormat::MakeTag works
-// properly...
-// Workaround for issue #493
-uint FixedMakeTag(const FieldDescriptor* field) {
-  internal::WireFormatLite::WireType field_type = field->is_packed()
-      ? internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED
-      : internal::WireFormat::WireTypeForFieldType(field->type());
-
-  return internal::WireFormatLite::MakeTag(field->number(), field_type);
-}
-
 FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
                                          int fieldOrdinal) {
   switch (descriptor->type()) {