diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
index 572249b346afc68976826ea6c4994c771ed4d0d7..c7dbd03b04bff33f229eeac3cba35b6c3cde8feb 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
+++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
@@ -8125,6 +8125,15 @@ internal class CSharpResources {
}
}
+ ///
+ /// Looks up a localized string similar to Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals..
+ ///
+ internal static string ERR_TooManyUserStrings {
+ get {
+ return ResourceManager.GetString("ERR_TooManyUserStrings", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to A format specifier may not contain trailing whitespace..
///
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index 84721832f6d45946bafc464f6f475da5d766ab63..1d96642596d6c61325fe6867b685c3d3661c2d57 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -4672,4 +4672,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Syntax tree should be created from a submission.
+
+ Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals.
+
\ No newline at end of file
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index d04f2ee42fa4cbd2ab2d80f7a07291730b3bccef..729180bee5ef743f743c960146263b4cb9667538 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -1319,5 +1319,6 @@ internal enum ErrorCode
ERR_BadAwaitInStaticVariableInitializer = 8100,
ERR_InvalidPathMap = 8101,
ERR_PublicSignButNoKey = 8102,
+ ERR_TooManyUserStrings = 8103,
}
}
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs
index 50305e95cf87cb84b20cedbd1aa5a5cad9fec789..4a4d0ff96aac294715613a3ccd942484a7987ac6 100644
--- a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs
+++ b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs
@@ -201,6 +201,7 @@ public override void ReportDuplicateMetadataReferenceWeak(DiagnosticBag diagnost
// PE Writer:
public override int ERR_MetadataNameTooLong { get { return (int)ErrorCode.ERR_MetadataNameTooLong; } }
public override int ERR_EncReferenceToAddedMember { get { return (int)ErrorCode.ERR_EncReferenceToAddedMember; } }
+ public override int ERR_TooManyUserStrings { get { return (int)ErrorCode.ERR_TooManyUserStrings; } }
public override void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute)
{
diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs
index 58122d4def6903ea70bbe47da40795cd4ba25ece..02da9e4e21284c4caed44983de919654c1815491 100644
--- a/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs
@@ -300,6 +300,37 @@ public static int Main ()
Diagnostic(ErrorCode.ERR_TooManyLocals, "Main"));
}
+ [Fact, WorkItem(8287, "https://github.com/dotnet/roslyn/issues/8287")]
+ public void ToManyUserStrings()
+ {
+ var builder = new System.Text.StringBuilder();
+ builder.Append(@"
+public class A
+{
+ public static void Main ()
+ {
+");
+ for (int i = 0; i < 11; i++)
+ {
+ builder.Append("System.Console.WriteLine(\"");
+ builder.Append((char)('A' + i), 1000000);
+ builder.Append("\");");
+ builder.AppendLine();
+ }
+
+ builder.Append(@"
+ }
+}
+");
+
+ var compilation = CreateCompilationWithMscorlib(builder.ToString());
+
+ compilation.VerifyEmitDiagnostics(
+ // error CS8103: Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals.
+ Diagnostic(ErrorCode.ERR_TooManyUserStrings).WithLocation(1, 1)
+ );
+ }
+
#endregion
}
}
diff --git a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs
index dfc35a5d3842ac307c1d188b2f684634935804e7..573ecf52a0cc27742586b17bd5fd48cfd7642737 100644
--- a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs
+++ b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs
@@ -202,6 +202,7 @@ public DiagnosticInfo FilterDiagnosticInfo(DiagnosticInfo diagnosticInfo, Compil
// PE writing:
public abstract int ERR_MetadataNameTooLong { get; }
public abstract int ERR_EncReferenceToAddedMember { get; }
+ public abstract int ERR_TooManyUserStrings { get; }
public abstract void ReportInvalidAttributeArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int parameterIndex, AttributeData attribute);
public abstract void ReportInvalidNamedArgument(DiagnosticBag diagnostics, SyntaxNode attributeSyntax, int namedArgumentIndex, ITypeSymbol attributeClass, string parameterName);
diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataHeapsBuilder.cs b/src/Compilers/Core/Portable/PEWriter/MetadataHeapsBuilder.cs
index 12f4acc0797de29ce1247a9d34daa041bfee2874..e03c475b0fc0d4ceb3d12f4a63bcdca9980e0b33 100644
--- a/src/Compilers/Core/Portable/PEWriter/MetadataHeapsBuilder.cs
+++ b/src/Compilers/Core/Portable/PEWriter/MetadataHeapsBuilder.cs
@@ -261,7 +261,7 @@ public int ResolveBlobIndex(BlobIdx index)
return (index.HeapPosition == 0) ? 0 : _blobHeapStartOffset + index.HeapPosition;
}
- public int GetUserStringToken(string str)
+ public bool TryGetUserStringToken(string str, out int token)
{
int index;
if (!_userStrings.TryGetValue(str, out index))
@@ -269,6 +269,14 @@ public int GetUserStringToken(string str)
Debug.Assert(!_streamsAreComplete);
index = _userStringWriter.Position + _userStringHeapStartOffset;
+
+ // User strings are referenced by metadata tokens (8 bits of which are used for the token type) leaving only 24 bits for the offset.
+ if ((index & 0xFF000000) != 0)
+ {
+ token = 0;
+ return false;
+ }
+
_userStrings.Add(str, index);
_userStringWriter.WriteCompressedInteger((uint)str.Length * 2 + 1);
@@ -327,7 +335,8 @@ public int GetUserStringToken(string str)
_userStringWriter.WriteByte(stringKind);
}
- return 0x70000000 | index;
+ token = 0x70000000 | index;
+ return true;
}
public void Complete()
diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs
index 327e59b685697b4aeeae37a428dc11a90bda8188..e0adf6778db264b56f1ba694b86520327da46163 100644
--- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs
+++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs
@@ -422,6 +422,7 @@ private bool IsMinimalDelta
private int[] _pseudoSymbolTokenToTokenMap;
private IReference[] _pseudoSymbolTokenToReferenceMap;
private int[] _pseudoStringTokenToTokenMap;
+ private bool _userStringTokenOverflow;
private List _pseudoStringTokenToStringMap;
private ReferenceIndexer _referenceVisitor;
@@ -4479,7 +4480,23 @@ private int ResolveStringTokenFromPseudoStringToken(int pseudoStringToken)
var str = _pseudoStringTokenToStringMap[index];
if (str != null)
{
- var token = heaps.GetUserStringToken(str);
+ const int overflowToken = 0x70000000; // 0x70 is a token type for a user string
+ int token;
+ if (!_userStringTokenOverflow)
+ {
+ if(!heaps.TryGetUserStringToken(str, out token))
+ {
+ this.Context.Diagnostics.Add(this.messageProvider.CreateDiagnostic(this.messageProvider.ERR_TooManyUserStrings,
+ NoLocation.Singleton));
+ _userStringTokenOverflow = true;
+ token = overflowToken;
+ }
+ }
+ else
+ {
+ token = overflowToken;
+ }
+
_pseudoStringTokenToTokenMap[index] = token;
_pseudoStringTokenToStringMap[index] = null; // Set to null to bypass next lookup
return token;
diff --git a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb
index 10da36f5cef45ec5d951c38308edfd64c132655a..14ee1be641237f34356a3b4e65cbff05a8e4759b 100644
--- a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb
+++ b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb
@@ -1681,6 +1681,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
ERR_DebugEntryPointNotSourceMethodDefinition = 37252
ERR_InvalidPathMap = 37253
ERR_PublicSignNoKey = 37254
+ ERR_TooManyUserStrings = 37255
ERR_LastPlusOne
diff --git a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb
index 10fec0ee5a902df742e0abae3fb7db3123675865..9d03f9a7ca288afd3fc225f4acc61fef3fdd816c 100644
--- a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb
+++ b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb
@@ -491,6 +491,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return ERRID.ERR_EncReferenceToAddedMember
End Get
End Property
+
+ Public Overrides ReadOnly Property ERR_TooManyUserStrings As Integer
+ Get
+ Return ERRID.ERR_TooManyUserStrings
+ End Get
+ End Property
End Class
End Namespace
diff --git a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb
index a6e95c3ead87a229b6070cd360fe442682903c44..05d122330a6875262b8f2c72159443a3a794d43d 100644
--- a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb
+++ b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb
@@ -10253,6 +10253,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Get
End Property
+ '''
+ ''' Looks up a localized string similar to Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string or XML literals..
+ '''
+ Friend ReadOnly Property ERR_TooManyUserStrings() As String
+ Get
+ Return ResourceManager.GetString("ERR_TooManyUserStrings", resourceCulture)
+ End Get
+ End Property
+
'''
''' Looks up a localized string similar to Method cannot contain both a 'Try' statement and an 'On Error' or 'Resume' statement..
'''
diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx
index 466e80fab4216fab08c0d750e05e8e95f079f183..a9dcac8d3a5c60be083ca388436529498741c413 100644
--- a/src/Compilers/VisualBasic/Portable/VBResources.resx
+++ b/src/Compilers/VisualBasic/Portable/VBResources.resx
@@ -5344,4 +5344,7 @@
Syntax tree should be created from a submission.
+
+ Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string or XML literals.
+
\ No newline at end of file
diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitErrorTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitErrorTests.vb
index cfe055ac6ddabb4b2578a2c1df8efc84f55b4036..42f729c18b62f43e0f908a8099f2f30c2088827e 100644
--- a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitErrorTests.vb
+++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitErrorTests.vb
@@ -574,6 +574,35 @@ BC35000: Requested operation is not available because the runtime library functi
]]>)
End Sub
+
+ Public Sub ToManyUserStrings()
+
+ Dim source As New System.Text.StringBuilder()
+ source.Append("
+Module C
+ Sub Main()
+")
+
+ For i As Integer = 1 To 11
+ source.Append(
+" System.Console.WriteLine(""")
+ source.Append(ChrW(AscW("A"c) + i), 1000000)
+ source.Append(""")
+")
+ Next
+
+ source.Append("
+ End Sub
+End Module")
+
+ Dim compilation = CreateCompilationWithReferences(VisualBasicSyntaxTree.ParseText(source.ToString()), {MscorlibRef, SystemRef, MsvbRef})
+
+ AssertTheseEmitDiagnostics(compilation,
+
+BC37255: Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string or XML literals.
+)
+ End Sub
+
#End Region
End Class
diff --git a/src/Test/Utilities/Shared/Mocks/TestMessageProvider.cs b/src/Test/Utilities/Shared/Mocks/TestMessageProvider.cs
index 7f84d161c656f51fbd7f79edb9c4d4fde7a884a2..4e459dcebf6e1f7ccc60de3ca8fa76ab193ebc6f 100644
--- a/src/Test/Utilities/Shared/Mocks/TestMessageProvider.cs
+++ b/src/Test/Utilities/Shared/Mocks/TestMessageProvider.cs
@@ -354,5 +354,13 @@ public override int ERR_BadCompilationOptionValue
throw new NotImplementedException();
}
}
+
+ public override int ERR_TooManyUserStrings
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
}
}