From 7d4f3a0db3863876cdef7342171b1984218a701e Mon Sep 17 00:00:00 2001 From: Omar Tawfik Date: Mon, 13 Feb 2017 12:42:39 -0800 Subject: [PATCH] Public API Changes --- .../CSharp/Portable/CSharpParseOptions.cs | 107 ++++++---------- .../Portable/CSharpResources.Designer.cs | 27 ++++ .../CSharp/Portable/CSharpResources.resx | 9 ++ .../CommandLine/CSharpCommandLineParser.cs | 8 +- .../Portable/Compilation/CSharpCompilation.cs | 1 + .../CSharp/Portable/Errors/ErrorCode.cs | 8 +- .../CSharp/Portable/Errors/MessageProvider.cs | 4 + .../Core/Portable/Compilation/ParseOptions.cs | 46 ++++++- .../Diagnostic/CommonMessageProvider.cs | 4 + .../Core/Portable/PublicAPI.Unshipped.txt | 2 + src/Compilers/Core/Portable/SourceCodeKind.cs | 18 +++ .../VisualBasicCommandLineParser.vb | 7 +- .../Compilation/VisualBasicCompilation.vb | 1 + .../VisualBasic/Portable/Errors/Errors.vb | 4 + .../Portable/Errors/MessageProvider.vb | 14 +++ .../Portable/VBResources.Designer.vb | 27 ++++ .../VisualBasic/Portable/VBResources.resx | 9 ++ .../Portable/VisualBasicParseOptions.vb | 118 +++++------------- .../Portable/Mocks/TestMessageProvider.cs | 16 +++ 19 files changed, 268 insertions(+), 162 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpParseOptions.cs b/src/Compilers/CSharp/Portable/CSharpParseOptions.cs index 39d66997881..2703b2422f4 100644 --- a/src/Compilers/CSharp/Portable/CSharpParseOptions.cs +++ b/src/Compilers/CSharp/Portable/CSharpParseOptions.cs @@ -50,32 +50,10 @@ public override IEnumerable PreprocessorSymbolNames IEnumerable preprocessorSymbols = null) : this(languageVersion, documentationMode, - kind, - preprocessorSymbols.ToImmutableArrayOrEmpty(), + kind, + preprocessorSymbols.ToImmutableArrayOrEmpty(), ImmutableDictionary.Empty) { - // We test the mapped value, LanguageVersion, rather than the parameter, languageVersion, - // which has not had "Latest" mapped to the latest version yet. - if (!LanguageVersion.IsValid()) - { - throw new ArgumentOutOfRangeException(nameof(languageVersion)); - } - - if (!kind.IsValid()) - { - throw new ArgumentOutOfRangeException(nameof(kind)); - } - - if (preprocessorSymbols != null) - { - foreach (var preprocessorSymbol in preprocessorSymbols) - { - if (!SyntaxFacts.IsValidIdentifier(preprocessorSymbol)) - { - throw new ArgumentException($"{nameof(preprocessorSymbols)} contains a symbol that is not a valid identifier", nameof(preprocessorSymbols)); - } - } - } } internal CSharpParseOptions( @@ -84,14 +62,12 @@ public override IEnumerable PreprocessorSymbolNames SourceCodeKind kind, IEnumerable preprocessorSymbols, ImmutableDictionary features) - : this(languageVersion, documentationMode, kind, preprocessorSymbols) + : base(kind, documentationMode) { - if (features == null) - { - throw new ArgumentNullException(nameof(features)); - } - - _features = features; + this.SpecifiedLanguageVersion = languageVersion; + this.LanguageVersion = languageVersion.MapSpecifiedToEffectiveVersion(); + this.PreprocessorSymbols = preprocessorSymbols.ToImmutableArrayOrEmpty(); + _features = features ?? ImmutableDictionary.Empty; } private CSharpParseOptions(CSharpParseOptions other) : this( @@ -102,38 +78,18 @@ public override IEnumerable PreprocessorSymbolNames features: other.Features.ToImmutableDictionary()) { } - - // No validation - private CSharpParseOptions( - LanguageVersion languageVersion, - DocumentationMode documentationMode, - SourceCodeKind kind, - ImmutableArray preprocessorSymbols, - ImmutableDictionary features) - : base(kind, documentationMode) - { - Debug.Assert(!preprocessorSymbols.IsDefault); - this.SpecifiedLanguageVersion = languageVersion; - this.LanguageVersion = languageVersion.MapSpecifiedToEffectiveVersion(); - this.PreprocessorSymbols = preprocessorSymbols; - _features = features; - } - + public override string Language => LanguageNames.CSharp; public new CSharpParseOptions WithKind(SourceCodeKind kind) { - if (kind == this.Kind) + if (kind == this.SpecifiedKind) { return this; } - if (!kind.IsValid()) - { - throw new ArgumentOutOfRangeException(nameof(kind)); - } - - return new CSharpParseOptions(this) { Kind = kind }; + var effectiveKind = kind.MapSpecifiedToEffectiveKind(); + return new CSharpParseOptions(this) { SpecifiedKind = kind, Kind = effectiveKind }; } public CSharpParseOptions WithLanguageVersion(LanguageVersion version) @@ -144,11 +100,6 @@ public CSharpParseOptions WithLanguageVersion(LanguageVersion version) } var effectiveLanguageVersion = version.MapSpecifiedToEffectiveVersion(); - if (!effectiveLanguageVersion.IsValid()) - { - throw new ArgumentOutOfRangeException(nameof(version)); - } - return new CSharpParseOptions(this) { SpecifiedLanguageVersion = version, LanguageVersion = effectiveLanguageVersion }; } @@ -184,11 +135,6 @@ public new CSharpParseOptions WithDocumentationMode(DocumentationMode documentat return this; } - if (!documentationMode.IsValid()) - { - throw new ArgumentOutOfRangeException(nameof(documentationMode)); - } - return new CSharpParseOptions(this) { DocumentationMode = documentationMode }; } @@ -212,12 +158,11 @@ protected override ParseOptions CommonWithFeatures(IEnumerable public new CSharpParseOptions WithFeatures(IEnumerable> features) { - if (features == null) - { - throw new ArgumentNullException(nameof(features)); - } + ImmutableDictionary dictionary = + features?.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase) + ?? ImmutableDictionary.Empty; - return new CSharpParseOptions(this) { _features = features.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase) }; + return new CSharpParseOptions(this) { _features = dictionary }; } public override IReadOnlyDictionary Features @@ -228,6 +173,28 @@ public new CSharpParseOptions WithFeatures(IEnumerable builder) + { + ValidateOptions(builder, MessageProvider.Instance); + + // Validate LanguageVersion not SpecifiedLanguageVersion, after Latest/Default has been converted: + if (!LanguageVersion.IsValid()) + { + builder.Add(Diagnostic.Create(MessageProvider.Instance, (int)ErrorCode.ERR_BadLanguageVersion, LanguageVersion)); + } + + if (!PreprocessorSymbols.IsDefaultOrEmpty) + { + foreach (var symbol in PreprocessorSymbols) + { + if (!SyntaxFacts.IsValidIdentifier(symbol)) + { + builder.Add(Diagnostic.Create(MessageProvider.Instance, (int)ErrorCode.WRN_DefineIdentifierRequired, symbol)); + } + } + } + } + internal bool IsFeatureEnabled(MessageID feature) { string featureFlag = feature.RequiredFeature(); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 05f0ae7abe2..326a8c4059e 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -1330,6 +1330,15 @@ internal class CSharpResources { } } + /// + /// Looks up a localized string similar to Provided Documentation Mode is unsupported or invalid: '{0}'.. + /// + internal static string ERR_BadDocumentationMode { + get { + return ResourceManager.GetString("ERR_BadDocumentationMode", resourceCulture); + } + } + /// /// Looks up a localized string similar to '{0}': user-defined conversions to or from the dynamic type are not allowed. /// @@ -1618,6 +1627,15 @@ internal class CSharpResources { } } + /// + /// Looks up a localized string similar to Provided Language Version is unsupported or invalid: '{0}'.. + /// + internal static string ERR_BadLanguageVersion { + get { + return ResourceManager.GetString("ERR_BadLanguageVersion", resourceCulture); + } + } + /// /// Looks up a localized string similar to The modifier '{0}' is not valid for this item. /// @@ -1861,6 +1879,15 @@ internal class CSharpResources { } } + /// + /// Looks up a localized string similar to Provided Source Code Kind is unsupported or invalid: '{0}'.. + /// + internal static string ERR_BadSourceCodeKind { + get { + return ResourceManager.GetString("ERR_BadSourceCodeKind", resourceCulture); + } + } + /// /// Looks up a localized string similar to Parameters or locals of type '{0}' cannot be declared in async methods or lambda expressions.. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index f5ced08a92d..a225e6f6a9c 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5020,4 +5020,13 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ It is not legal to use the type 'dynamic' in a pattern. + + Provided Documentation Mode is unsupported or invalid: '{0}'. + + + Provided Source Code Kind is unsupported or invalid: '{0}'. + + + Provided Language Version is unsupported or invalid: '{0}'. + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs index f83230991b3..df9f3784007 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs @@ -1221,7 +1221,10 @@ public new CSharpCommandLineArguments Parse(IEnumerable args, string bas features: parsedFeatures ); - var scriptParseOptions = parseOptions.WithKind(SourceCodeKind.Script); + if (IsScriptRunner) + { + parseOptions = parseOptions.WithKind(SourceCodeKind.Script); + } // We want to report diagnostics with source suppression in the error log file. // However, these diagnostics won't be reported on the command line. @@ -1271,6 +1274,7 @@ public new CSharpCommandLineArguments Parse(IEnumerable args, string bas // add option incompatibility errors if any diagnostics.AddRange(options.Errors); + diagnostics.AddRange(parseOptions.Errors); return new CSharpCommandLineArguments { @@ -1307,7 +1311,7 @@ public new CSharpCommandLineArguments Parse(IEnumerable args, string bas DisplayVersion = displayVersion, ManifestResources = managedResources.AsImmutable(), CompilationOptions = options, - ParseOptions = IsScriptRunner ? scriptParseOptions : parseOptions, + ParseOptions = parseOptions, EmitOptions = emitOptions, ScriptArguments = scriptArgs.AsImmutableOrEmpty(), TouchedFilesPath = touchedFilesPath, diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index f1c43315e27..a175a29c40f 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -1927,6 +1927,7 @@ internal ImmutableArray GetDiagnostics(CompilationStage stage, bool var syntaxTree = syntaxTrees[i]; AppendLoadDirectiveDiagnostics(builder, _syntaxAndDeclarations, syntaxTree); builder.AddRange(syntaxTree.GetDiagnostics(cancellationToken)); + builder.AddRange(syntaxTree.Options.Errors); })); } else diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 3036a614c69..f425028821e 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1439,7 +1439,13 @@ internal enum ErrorCode ERR_DelegateRefMismatch = 8189, #endregion stragglers for C# 7 - // Available = 8190-8195 + #region diagnostics for parse options + ERR_BadSourceCodeKind = 8190, + ERR_BadDocumentationMode = 8191, + ERR_BadLanguageVersion = 8192, + #endregion + + // Available = 8193-8195 #region diagnostics for out var ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList = 8196, diff --git a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs index b7dc8304048..88f4689b56e 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs @@ -146,6 +146,10 @@ public override ReportDiagnostic GetDiagnosticReport(DiagnosticInfo diagnosticIn public override int ERR_CantReadRulesetFile => (int)ErrorCode.ERR_CantReadRulesetFile; public override int ERR_CompileCancelled => (int)ErrorCode.ERR_CompileCancelled; + // parse options: + public override int ERR_BadSourceCodeKind => (int)ErrorCode.ERR_BadSourceCodeKind; + public override int ERR_BadDocumentationMode => (int)ErrorCode.ERR_BadDocumentationMode; + // compilation options: public override int ERR_BadCompilationOptionValue => (int)ErrorCode.ERR_BadCompilationOptionValue; public override int ERR_MutuallyExclusiveOptions => (int)ErrorCode.ERR_MutuallyExclusiveOptions; diff --git a/src/Compilers/Core/Portable/Compilation/ParseOptions.cs b/src/Compilers/Core/Portable/Compilation/ParseOptions.cs index 0de52ad0c25..8d7eaa33417 100644 --- a/src/Compilers/Core/Portable/Compilation/ParseOptions.cs +++ b/src/Compilers/Core/Portable/Compilation/ParseOptions.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.ComponentModel; using System.Linq; using Roslyn.Utilities; @@ -13,11 +14,19 @@ namespace Microsoft.CodeAnalysis /// public abstract class ParseOptions { + private readonly Lazy> _lazyErrors; + /// /// Specifies whether to parse as regular code files, script files or interactive code. /// public SourceCodeKind Kind { get; protected set; } + /// + /// Gets the specified source code kind, which is the value that was specified in + /// the call to the constructor, or modified using the method. + /// + public SourceCodeKind SpecifiedKind { get; protected set; } + /// /// Gets a value indicating whether the documentation comments are parsed. /// @@ -26,8 +35,16 @@ public abstract class ParseOptions internal ParseOptions(SourceCodeKind kind, DocumentationMode documentationMode) { - this.Kind = kind; + this.SpecifiedKind = kind; + this.Kind = kind.MapSpecifiedToEffectiveKind(); this.DocumentationMode = documentationMode; + + _lazyErrors = new Lazy>(() => + { + var builder = ArrayBuilder.GetInstance(); + ValidateOptions(builder); + return builder.ToImmutableAndFree(); + }); } /// @@ -35,6 +52,14 @@ internal ParseOptions(SourceCodeKind kind, DocumentationMode documentationMode) /// public abstract string Language { get; } + /// + /// Errors collection related to an incompatible set of parse options + /// + public ImmutableArray Errors + { + get { return _lazyErrors.Value; } + } + /// /// Creates a new options instance with the specified source code kind. /// @@ -43,6 +68,25 @@ public ParseOptions WithKind(SourceCodeKind kind) return CommonWithKind(kind); } + /// + /// Performs validation of options compatibilities and generates diagnostics if needed + /// + internal abstract void ValidateOptions(ArrayBuilder builder); + + internal void ValidateOptions(ArrayBuilder builder, CommonMessageProvider messageProvider) + { + // Validate SpecifiedKind not Kind, to catch deprecated specified kinds: + if (!SpecifiedKind.IsValid()) + { + builder.Add(messageProvider.CreateDiagnostic(messageProvider.ERR_BadSourceCodeKind, Location.None, SpecifiedKind)); + } + + if (!DocumentationMode.IsValid()) + { + builder.Add(messageProvider.CreateDiagnostic(messageProvider.ERR_BadDocumentationMode, Location.None, DocumentationMode)); + } + } + // It was supposed to be a protected implementation detail. // The "pattern" we have for these is the public With* method is the only public callable one, // and that forwards to the protected Common* like all the other methods in the class. diff --git a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs index 8d729577a96..94182e4719d 100644 --- a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs +++ b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs @@ -159,6 +159,10 @@ public DiagnosticInfo FilterDiagnosticInfo(DiagnosticInfo diagnosticInfo, Compil public abstract int ERR_CantReadRulesetFile { get; } public abstract int ERR_CompileCancelled { get; } + // parse options: + public abstract int ERR_BadSourceCodeKind { get; } + public abstract int ERR_BadDocumentationMode { get; } + // compilation options: public abstract int ERR_BadCompilationOptionValue { get; } public abstract int ERR_MutuallyExclusiveOptions { get; } diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 04a4963d5f8..2c5ea5b0ae9 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -188,6 +188,8 @@ Microsoft.CodeAnalysis.OperationKind.VariableDeclarationStatement = 3 -> Microso Microsoft.CodeAnalysis.OperationKind.WithStatement = 82 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.YieldBreakStatement = 12 -> Microsoft.CodeAnalysis.OperationKind Microsoft.CodeAnalysis.OperationKind.YieldReturnStatement = 16 -> Microsoft.CodeAnalysis.OperationKind +Microsoft.CodeAnalysis.ParseOptions.Errors.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.ParseOptions.SpecifiedKind.get -> Microsoft.CodeAnalysis.SourceCodeKind Microsoft.CodeAnalysis.PortableExecutableReference.GetMetadataId() -> Microsoft.CodeAnalysis.MetadataId Microsoft.CodeAnalysis.SemanticModel.GetOperation(Microsoft.CodeAnalysis.SyntaxNode node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.IOperation Microsoft.CodeAnalysis.Semantics.ArgumentKind diff --git a/src/Compilers/Core/Portable/SourceCodeKind.cs b/src/Compilers/Core/Portable/SourceCodeKind.cs index ea36e0ce340..948623c93d5 100644 --- a/src/Compilers/Core/Portable/SourceCodeKind.cs +++ b/src/Compilers/Core/Portable/SourceCodeKind.cs @@ -32,6 +32,24 @@ public enum SourceCodeKind internal static partial class SourceCodeKindExtensions { + internal static SourceCodeKind MapSpecifiedToEffectiveKind(this SourceCodeKind kind) + { + switch (kind) + { + case SourceCodeKind.Regular: + return SourceCodeKind.Regular; + +#pragma warning disable CS0618 // SourceCodeKind.Interactive is obsolete + case SourceCodeKind.Script: + case SourceCodeKind.Interactive: + return SourceCodeKind.Script; +#pragma warning restore CS0618 // SourceCodeKind.Interactive is obsolete + + default: + throw new NotSupportedException($"SourceCodeKind {kind} not supported"); + } + } + internal static bool IsValid(this SourceCodeKind value) { return value >= SourceCodeKind.Regular && value <= SourceCodeKind.Script; diff --git a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb index 0ff31b101c1..76e327fdf9e 100644 --- a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb +++ b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb @@ -1311,7 +1311,9 @@ lVbRuntimePlus: preprocessorSymbols:=AddPredefinedPreprocessorSymbols(outputKind, defines.AsImmutableOrEmpty()), features:=parsedFeatures) - Dim scriptParseOptions = parseOptions.WithKind(SourceCodeKind.Script) + If IsScriptRunner Then + parseOptions = parseOptions.WithKind(SourceCodeKind.Script) + End If ' We want to report diagnostics with source suppression in the error log file. ' However, these diagnostics won't be reported on the command line. @@ -1357,6 +1359,7 @@ lVbRuntimePlus: ' add option incompatibility errors if any diagnostics.AddRange(options.Errors) + diagnostics.AddRange(parseOptions.Errors) If documentationPath Is GenerateFileNameForDocComment Then documentationPath = PathUtilities.CombineAbsoluteAndRelativePaths(outputDirectory, PathUtilities.RemoveExtension(outputFileName)) @@ -1398,7 +1401,7 @@ lVbRuntimePlus: .DisplayVersion = displayVersion, .ManifestResources = managedResources.AsImmutable(), .CompilationOptions = options, - .ParseOptions = If(IsScriptRunner, scriptParseOptions, parseOptions), + .ParseOptions = parseOptions, .EmitOptions = emitOptions, .ScriptArguments = scriptArgs.AsImmutableOrEmpty(), .TouchedFilesPath = touchedFilesPath, diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb index 499cd9b6671..61cdc63516a 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb @@ -1927,6 +1927,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic For Each tree In SyntaxTrees cancellationToken.ThrowIfCancellationRequested() builder.AddRange(tree.GetDiagnostics(cancellationToken)) + builder.AddRange(tree.Options.Errors) Next End If End If diff --git a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb index 1d21dcb6380..fd3f02cd052 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb @@ -1726,6 +1726,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERR_Merge_conflict_marker_encountered = 37284 + ERR_BadSourceCodeKind = 37285 + ERR_BadDocumentationMode = 37286 + ERR_BadLanguageVersion = 37287 + '// WARNINGS BEGIN HERE WRN_UseOfObsoleteSymbol2 = 40000 WRN_InvalidOverrideDueToTupleNames2 = 40001 diff --git a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb index 8a69e2e5de1..5b8af88023e 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb @@ -232,6 +232,20 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + ' parse options: + + Public Overrides ReadOnly Property ERR_BadSourceCodeKind As Integer + Get + Return ERRID.ERR_BadSourceCodeKind + End Get + End Property + + Public Overrides ReadOnly Property ERR_BadDocumentationMode As Integer + Get + Return ERRID.ERR_BadDocumentationMode + End Get + End Property + ' compilation options: Public Overrides ReadOnly Property ERR_BadCompilationOptionValue As Integer diff --git a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb index d0a6f6a7876..e83b45067a3 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb +++ b/src/Compilers/VisualBasic/Portable/VBResources.Designer.vb @@ -1035,6 +1035,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + ''' + ''' Looks up a localized string similar to Provided Documentation Mode is unsupported or invalid: '{0}'.. + ''' + Friend ReadOnly Property ERR_BadDocumentationMode() As String + Get + Return ResourceManager.GetString("ERR_BadDocumentationMode", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to Enum '{0}' must contain at least one member.. ''' @@ -1278,6 +1287,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + ''' + ''' Looks up a localized string similar to Provided Language Version is unsupported or invalid: '{0}'.. + ''' + Friend ReadOnly Property ERR_BadLanguageVersion() As String + Get + Return ResourceManager.GetString("ERR_BadLanguageVersion", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to '{0}' is not valid on a local constant declaration.. ''' @@ -1485,6 +1503,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + ''' + ''' Looks up a localized string similar to Provided Source Code Kind is unsupported or invalid: '{0}'.. + ''' + Friend ReadOnly Property ERR_BadSourceCodeKind() As String + Get + Return ResourceManager.GetString("ERR_BadSourceCodeKind", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to '{0}' and '{1}' cannot be combined.. ''' diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx index 766722e4338..2cba9692135 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.resx +++ b/src/Compilers/VisualBasic/Portable/VBResources.resx @@ -5467,4 +5467,13 @@ Merge conflict marker encountered + + Provided Documentation Mode is unsupported or invalid: '{0}'. + + + Provided Language Version is unsupported or invalid: '{0}'. + + + Provided Source Code Kind is unsupported or invalid: '{0}'. + \ No newline at end of file diff --git a/src/Compilers/VisualBasic/Portable/VisualBasicParseOptions.vb b/src/Compilers/VisualBasic/Portable/VisualBasicParseOptions.vb index 4549f790d7f..559712921fb 100644 --- a/src/Compilers/VisualBasic/Portable/VisualBasicParseOptions.vb +++ b/src/Compilers/VisualBasic/Portable/VisualBasicParseOptions.vb @@ -40,18 +40,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic kind, If(preprocessorSymbols Is Nothing, DefaultPreprocessorSymbols, ImmutableArray.CreateRange(preprocessorSymbols)), ImmutableDictionary(Of String, String).Empty) - - ' We test the mapped value, _languageVersion, rather than the parameter, languageVersion, - ' which has not had "Latest" mapped to the latest version yet. - If Not _languageVersion.IsValid Then - Throw New ArgumentOutOfRangeException(NameOf(languageVersion)) - End If - - If Not kind.IsValid Then - Throw New ArgumentOutOfRangeException(NameOf(kind)) - End If - - ValidatePreprocessorSymbols(preprocessorSymbols, NameOf(preprocessorSymbols)) End Sub Friend Sub New( @@ -61,65 +49,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic preprocessorSymbols As IEnumerable(Of KeyValuePair(Of String, Object)), features As ImmutableDictionary(Of String, String)) - MyClass.New(languageVersion, - documentationMode, - kind, - If(preprocessorSymbols Is Nothing, DefaultPreprocessorSymbols, ImmutableArray.CreateRange(preprocessorSymbols)), - features) - - ' We test the mapped value, _languageVersion, rather than the parameter, languageVersion, - ' which has not had "Latest" mapped to the latest version yet. - If Not _languageVersion.IsValid Then - Throw New ArgumentOutOfRangeException(NameOf(languageVersion)) - End If - - If Not kind.IsValid Then - Throw New ArgumentOutOfRangeException(NameOf(kind)) - End If - - ValidatePreprocessorSymbols(preprocessorSymbols, NameOf(preprocessorSymbols)) - - If features Is Nothing Then - Throw New ArgumentException(NameOf(features)) - End If - End Sub - - Private Shared Sub ValidatePreprocessorSymbols(preprocessorSymbols As IEnumerable(Of KeyValuePair(Of String, Object)), - parameterName As String) - If preprocessorSymbols Is Nothing Then - Return - End If - - For Each symbol In preprocessorSymbols - If Not IsValidIdentifier(symbol.Key) OrElse - SyntaxFacts.GetKeywordKind(symbol.Key) <> SyntaxKind.None Then - - Throw New ArgumentException(parameterName) - End If - - Debug.Assert(SyntaxFactory.ParseTokens(symbol.Key).Select(Function(t) t.Kind).SequenceEqual({SyntaxKind.IdentifierToken, SyntaxKind.EndOfFileToken})) - - Dim constant = InternalSyntax.CConst.TryCreate(symbol.Value) - If constant Is Nothing Then - Throw New ArgumentException(String.Format(VBResources.IDS_InvalidPreprocessorConstantType, symbol.Key, symbol.Value.GetType()), parameterName) - End If - Next - End Sub - - ' Does not perform validation. - Private Sub New( - languageVersion As LanguageVersion, - documentationMode As DocumentationMode, - kind As SourceCodeKind, - preprocessorSymbols As ImmutableArray(Of KeyValuePair(Of String, Object)), - features As ImmutableDictionary(Of String, String)) - MyBase.New(kind, documentationMode) - Debug.Assert(Not preprocessorSymbols.IsDefault) _specifiedLanguageVersion = languageVersion _languageVersion = languageVersion.MapSpecifiedToEffectiveVersion - _preprocessorSymbols = preprocessorSymbols + _preprocessorSymbols = preprocessorSymbols.ToImmutableArrayOrEmpty _features = features End Sub @@ -200,10 +134,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End If Dim effectiveVersion = version.MapSpecifiedToEffectiveVersion() - If Not effectiveVersion.IsValid Then - Throw New ArgumentOutOfRangeException(NameOf(version)) - End If - Return New VisualBasicParseOptions(Me) With {._specifiedLanguageVersion = version, ._languageVersion = effectiveVersion} End Function @@ -213,15 +143,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The parser source code kind. ''' A new instance of VisualBasicParseOptions if source code kind is different; otherwise current instance. Public Shadows Function WithKind(kind As SourceCodeKind) As VisualBasicParseOptions - If kind = Me.Kind Then + If kind = Me.SpecifiedKind Then Return Me End If - If Not kind.IsValid Then - Throw New ArgumentOutOfRangeException(NameOf(kind)) - End If - - Return New VisualBasicParseOptions(Me) With {.Kind = kind} + Dim effectiveKind = kind.MapSpecifiedToEffectiveKind + Return New VisualBasicParseOptions(Me) With {.SpecifiedKind = kind, .Kind = effectiveKind} End Function ''' @@ -234,10 +161,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return Me End If - If Not documentationMode.IsValid() Then - Throw New ArgumentOutOfRangeException(NameOf(documentationMode)) - End If - Return New VisualBasicParseOptions(Me) With {.DocumentationMode = documentationMode} End Function @@ -273,8 +196,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return Me End If - ValidatePreprocessorSymbols(symbols, NameOf(symbols)) - Return New VisualBasicParseOptions(Me) With {._preprocessorSymbols = symbols} End Function @@ -306,10 +227,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Public Shadows Function WithFeatures(features As IEnumerable(Of KeyValuePair(Of String, String))) As VisualBasicParseOptions ' there are currently no parse options for experimental features If features Is Nothing Then - Throw New ArgumentException(NameOf(features)) + Return New VisualBasicParseOptions(Me) With {._features = ImmutableDictionary(Of String, String).Empty} + Else + Return New VisualBasicParseOptions(Me) With {._features = features.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase)} End If - - Return New VisualBasicParseOptions(Me) With {._features = features.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase)} End Function Public Overrides ReadOnly Property Features As IReadOnlyDictionary(Of String, String) @@ -318,6 +239,31 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + + Friend Overrides Sub ValidateOptions(builder As ArrayBuilder(Of Diagnostic)) + ValidateOptions(builder, MessageProvider.Instance) + + ' Validate LanguageVersion Not SpecifiedLanguageVersion, after Latest/Default has been converted + If Not LanguageVersion.IsValid Then + builder.Add(Diagnostic.Create(MessageProvider.Instance, ERRID.ERR_BadLanguageVersion, LanguageVersion)) + End If + + If Not PreprocessorSymbols.IsDefaultOrEmpty Then + For Each symbol In PreprocessorSymbols + If Not IsValidIdentifier(symbol.Key) OrElse SyntaxFacts.GetKeywordKind(symbol.Key) <> SyntaxKind.None Then + builder.Add(Diagnostic.Create(MessageProvider.Instance, ERRID.ERR_ProjectCCError1, VBResources.ERR_ExpectedIdentifier, symbol.Key)) + End If + + Debug.Assert(SyntaxFactory.ParseTokens(symbol.Key).Select(Function(t) t.Kind).SequenceEqual({SyntaxKind.IdentifierToken, SyntaxKind.EndOfFileToken})) + + Dim constant = InternalSyntax.CConst.TryCreate(symbol.Value) + If constant Is Nothing Then + builder.Add(Diagnostic.Create(MessageProvider.Instance, ERRID.IDS_InvalidPreprocessorConstantType, symbol.Key, symbol.Value.GetType)) + End If + Next + End If + End Sub + ''' ''' Determines whether the current object is equal to another object of the same type. ''' diff --git a/src/Test/Utilities/Portable/Mocks/TestMessageProvider.cs b/src/Test/Utilities/Portable/Mocks/TestMessageProvider.cs index bb48912b1ae..1b7bec1626f 100644 --- a/src/Test/Utilities/Portable/Mocks/TestMessageProvider.cs +++ b/src/Test/Utilities/Portable/Mocks/TestMessageProvider.cs @@ -425,5 +425,21 @@ public override int ERR_BadAssemblyName throw new NotImplementedException(); } } + + public override int ERR_BadSourceCodeKind + { + get + { + throw new NotImplementedException(); + } + } + + public override int ERR_BadDocumentationMode + { + get + { + throw new NotImplementedException(); + } + } } } -- GitLab