Skip to content

Commit

Permalink
Implement compiler /warnversion flag and one "wave" warning
Browse files Browse the repository at this point in the history
  • Loading branch information
Neal Gafter committed Jul 7, 2020
1 parent a75d0d6 commit d49e2af
Show file tree
Hide file tree
Showing 23 changed files with 398 additions and 22 deletions.
94 changes: 88 additions & 6 deletions src/Compilers/CSharp/Portable/CSharpCompilationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ public sealed class CSharpCompilationOptions : CompilationOptions, IEquatable<CS
/// </summary>
public override NullableContextOptions NullableContextOptions { get; protected set; }

/// <summary>
/// The warning version, which indicates which set of warnings should be produced by the compiler.
/// </summary>
/// <remarks>
/// Most warnings are produced by the compiler unconditionally, but warnings that are controlled by a version
/// are only produced when the WarningVersion value is greater than or equal to the warning version
/// associated with the warning. Use zero to get none of the versioned warnings, or a large number like 9999
/// to get all of the versioned warnings. The first version that enables some warnings is version 5.
/// </remarks>
public decimal WarningVersion { get; private set; }

// Defaults correspond to the compiler's defaults or indicate that the user did not specify when that is significant.
// That's significant when one option depends on another's setting. SubsystemVersion depends on Platform and Target.
public CSharpCompilationOptions(
Expand Down Expand Up @@ -71,7 +82,58 @@ public CSharpCompilationOptions(
StrongNameProvider? strongNameProvider = null,
bool publicSign = false,
MetadataImportOptions metadataImportOptions = MetadataImportOptions.Public,
NullableContextOptions nullableContextOptions = NullableContextOptions.Disable)
NullableContextOptions nullableContextOptions = NullableContextOptions.Disable,
decimal warningVersion = 0m)
: this(outputKind, reportSuppressedDiagnostics, moduleName, mainTypeName, scriptClassName,
usings, optimizationLevel, checkOverflow, allowUnsafe,
cryptoKeyContainer, cryptoKeyFile, cryptoPublicKey, delaySign, platform,
generalDiagnosticOption, warningLevel,
specificDiagnosticOptions, concurrentBuild, deterministic,
currentLocalTime: default,
debugPlusMode: false,
xmlReferenceResolver: xmlReferenceResolver,
sourceReferenceResolver: sourceReferenceResolver,
metadataReferenceResolver: metadataReferenceResolver,
assemblyIdentityComparer: assemblyIdentityComparer,
strongNameProvider: strongNameProvider,
metadataImportOptions: metadataImportOptions,
referencesSupersedeLowerVersions: false,
publicSign: publicSign,
topLevelBinderFlags: BinderFlags.None,
nullableContextOptions: nullableContextOptions,
warningVersion: warningVersion)
{
}

// 16.8 BACKCOMPAT OVERLOAD -- DO NOT TOUCH
public CSharpCompilationOptions(
OutputKind outputKind,
bool reportSuppressedDiagnostics,
string? moduleName,
string? mainTypeName,
string? scriptClassName,
IEnumerable<string>? usings,
OptimizationLevel optimizationLevel,
bool checkOverflow,
bool allowUnsafe,
string? cryptoKeyContainer,
string? cryptoKeyFile,
ImmutableArray<byte> cryptoPublicKey,
bool? delaySign,
Platform platform,
ReportDiagnostic generalDiagnosticOption,
int warningLevel,
IEnumerable<KeyValuePair<string, ReportDiagnostic>>? specificDiagnosticOptions,
bool concurrentBuild,
bool deterministic,
XmlReferenceResolver? xmlReferenceResolver,
SourceReferenceResolver? sourceReferenceResolver,
MetadataReferenceResolver? metadataReferenceResolver,
AssemblyIdentityComparer? assemblyIdentityComparer,
StrongNameProvider? strongNameProvider,
bool publicSign,
MetadataImportOptions metadataImportOptions,
NullableContextOptions nullableContextOptions)
: this(outputKind, reportSuppressedDiagnostics, moduleName, mainTypeName, scriptClassName,
usings, optimizationLevel, checkOverflow, allowUnsafe,
cryptoKeyContainer, cryptoKeyFile, cryptoPublicKey, delaySign, platform,
Expand Down Expand Up @@ -211,7 +273,8 @@ internal CSharpCompilationOptions(
bool referencesSupersedeLowerVersions,
bool publicSign,
BinderFlags topLevelBinderFlags,
NullableContextOptions nullableContextOptions)
NullableContextOptions nullableContextOptions,
decimal warningVersion = 0m)
: base(outputKind, reportSuppressedDiagnostics, moduleName, mainTypeName, scriptClassName,
cryptoKeyContainer, cryptoKeyFile, cryptoPublicKey, delaySign, publicSign, optimizationLevel, checkOverflow,
platform, generalDiagnosticOption, warningLevel, specificDiagnosticOptions.ToImmutableDictionaryOrEmpty(),
Expand All @@ -223,6 +286,7 @@ internal CSharpCompilationOptions(
this.AllowUnsafe = allowUnsafe;
this.TopLevelBinderFlags = topLevelBinderFlags;
this.NullableContextOptions = nullableContextOptions;
this.WarningVersion = warningVersion;
}

private CSharpCompilationOptions(CSharpCompilationOptions other) : this(
Expand Down Expand Up @@ -256,7 +320,8 @@ private CSharpCompilationOptions(CSharpCompilationOptions other) : this(
reportSuppressedDiagnostics: other.ReportSuppressedDiagnostics,
publicSign: other.PublicSign,
topLevelBinderFlags: other.TopLevelBinderFlags,
nullableContextOptions: other.NullableContextOptions)
nullableContextOptions: other.NullableContextOptions,
warningVersion: other.WarningVersion)
{
}

Expand Down Expand Up @@ -493,6 +558,16 @@ public CSharpCompilationOptions WithWarningLevel(int warningLevel)
return new CSharpCompilationOptions(this) { WarningLevel = warningLevel };
}

public CSharpCompilationOptions WithWarningVersion(decimal warningVersion)
{
if (warningVersion == this.WarningVersion)
{
return this;
}

return new CSharpCompilationOptions(this) { WarningVersion = warningVersion };
}

public new CSharpCompilationOptions WithConcurrentBuild(bool concurrentBuild)
{
if (concurrentBuild == this.ConcurrentBuild)
Expand Down Expand Up @@ -688,6 +763,11 @@ internal override void ValidateOptions(ArrayBuilder<Diagnostic> builder)
builder.Add(Diagnostic.Create(MessageProvider.Instance, (int)ErrorCode.ERR_BadCompilationOptionValue, nameof(WarningLevel), WarningLevel));
}

if (WarningVersion < 0m)
{
builder.Add(Diagnostic.Create(MessageProvider.Instance, (int)ErrorCode.ERR_BadCompilationOptionValue, nameof(WarningVersion), WarningVersion));
}

if (Usings != null && Usings.Any(u => !u.IsValidClrNamespaceName()))
{
builder.Add(Diagnostic.Create(MessageProvider.Instance, (int)ErrorCode.ERR_BadCompilationOptionValue, nameof(Usings), Usings.Where(u => !u.IsValidClrNamespaceName()).First() ?? "null"));
Expand Down Expand Up @@ -722,8 +802,9 @@ public bool Equals(CSharpCompilationOptions? other)

return this.AllowUnsafe == other.AllowUnsafe &&
this.TopLevelBinderFlags == other.TopLevelBinderFlags &&
(this.Usings == null ? other.Usings == null : this.Usings.SequenceEqual(other.Usings, StringComparer.Ordinal) &&
this.NullableContextOptions == other.NullableContextOptions);
(this.Usings == null ? other.Usings == null : this.Usings.SequenceEqual(other.Usings, StringComparer.Ordinal)) &&
this.NullableContextOptions == other.NullableContextOptions &&
this.WarningVersion == other.WarningVersion;
}

public override bool Equals(object? obj)
Expand All @@ -736,7 +817,8 @@ public override int GetHashCode()
return Hash.Combine(base.GetHashCodeHelper(),
Hash.Combine(this.AllowUnsafe,
Hash.Combine(Hash.CombineValues(this.Usings, StringComparer.Ordinal),
Hash.Combine(TopLevelBinderFlags.GetHashCode(), this.NullableContextOptions.GetHashCode()))));
Hash.Combine(this.WarningVersion.GetHashCode(),
Hash.Combine(TopLevelBinderFlags.GetHashCode(), this.NullableContextOptions.GetHashCode())))));
}

internal override Diagnostic FilterDiagnostic(Diagnostic diagnostic)
Expand Down
7 changes: 6 additions & 1 deletion src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -3235,6 +3235,9 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
<data name="ERR_BadWarningLevel" xml:space="preserve">
<value>Warning level must be in the range 0-4</value>
</data>
<data name="ERR_BadWarningVersion" xml:space="preserve">
<value>Warning version must be greater than or equal to '0'.</value>
</data>
<data name="ERR_BadDebugType" xml:space="preserve">
<value>Invalid option '{0}' for /debug; must be 'portable', 'embedded', 'full' or 'pdbonly'</value>
</data>
Expand Down Expand Up @@ -4617,7 +4620,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
-warnaserror[+|-] Report all warnings as errors
-warnaserror[+|-]:&lt;warn list&gt; Report specific warnings as errors
(use "nullable" for all nullability warnings)
-warn:&lt;n&gt; Set warning level (0-4) (Short form: -w)
-warnversion:&lt;n&gt; Enable recently introduced warnings. Default '0'.
To enable warnings introduced through this version, use '5'.
Use '9999' to enable all current and future warning waves.
-nowarn:&lt;warn list&gt; Disable specific warning messages
(use "nullable" for all nullability warnings)
-ruleset:&lt;file&gt; Specify a ruleset file that disables specific
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar
bool publicSign = false;
string? sourceLink = null;
string? ruleSetPath = null;
decimal warningVersion = 0m;

// Process ruleset files first so that diagnostic severity settings specified on the command line via
// /nowarn and /warnaserror can override diagnostic severity settings specified in the ruleset file.
Expand Down Expand Up @@ -905,6 +906,24 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar
}
continue;

case "warnversion":
value = RemoveQuotesAndSlashes(value);
decimal newWarningVersion;
if (string.IsNullOrEmpty(value) ||
!decimal.TryParse(value, out newWarningVersion))
{
AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsNumber, name);
}
else if (newWarningVersion < 0m)
{
AddDiagnostic(diagnostics, ErrorCode.ERR_BadWarningVersion, name);
}
else
{
warningVersion = newWarningVersion;
}
continue;

case "nowarn":
if (value == null)
{
Expand Down Expand Up @@ -1419,7 +1438,8 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable<string> ar
warningLevel: warningLevel,
specificDiagnosticOptions: diagnosticOptions,
reportSuppressedDiagnostics: reportSuppressedDiagnostics,
publicSign: publicSign
publicSign: publicSign,
warningVersion: warningVersion
);

if (debugPlus)
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1837,6 +1837,7 @@ internal enum ErrorCode

ERR_8821 = 8821, // used by features/static-lambdas

ERR_BadWarningVersion = 8848,
ERR_ExpressionTreeContainsWithExpression = 8849,
ERR_BadRecordDeclaration = 8850,
ERR_DuplicateRecordConstructor = 8851,
Expand Down
23 changes: 23 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp
{
Expand Down Expand Up @@ -206,6 +207,28 @@ private static System.Resources.ResourceManager ResourceManager
}
}

/// <summary>
/// For each warning that is linked to a warning "wave" (/warnversion), the number of
/// the warning wave in which it was introduced.
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
internal static decimal GetWarningVersion(this ErrorCode code)
{
switch (code)
{
case ErrorCode.WRN_NubExprIsConstBool2:
return 5m;
// If you introduce a new warning "wave" version, please update
// CSharpResources.resx to include documentation for the "latest"
// warning version in "IDS_CSCHelp" under "-warnversion". Note that
// it is our intention that warning wave version numbers correspond
// to the dotnet platform with which the compiler is released.
default:
throw ExceptionUtilities.UnexpectedValue(code);
}
}

internal static int GetWarningLevel(ErrorCode code)
{
if (IsInfo(code) || IsHidden(code))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ private void CheckLiftedBinOp(BoundBinaryOperator node)

string always = node.OperatorKind.Operator() == BinaryOperatorKind.NotEqual ? "true" : "false";

if (_compilation.FeatureStrictEnabled || !node.OperatorKind.IsUserDefined())
if (_compilation.FeatureStrictEnabled || !node.OperatorKind.IsUserDefined() || ErrorCode.WRN_NubExprIsConstBool2.GetWarningVersion() <= this._compilation.Options.WarningVersion)
{
if (node.Right.NullableNeverHasValue() && node.Left.NullableAlwaysHasValue())
{
Expand Down
4 changes: 4 additions & 0 deletions src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.ObjectCreationExpressionSyntax.ArgumentList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax
*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.ObjectCreationExpressionSyntax.Initializer.get -> Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax
*REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.ObjectCreationExpressionSyntax.NewKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions.CSharpCompilationOptions(Microsoft.CodeAnalysis.OutputKind outputKind, bool reportSuppressedDiagnostics = false, string moduleName = null, string mainTypeName = null, string scriptClassName = null, System.Collections.Generic.IEnumerable<string> usings = null, Microsoft.CodeAnalysis.OptimizationLevel optimizationLevel = Microsoft.CodeAnalysis.OptimizationLevel.Debug, bool checkOverflow = false, bool allowUnsafe = false, string cryptoKeyContainer = null, string cryptoKeyFile = null, System.Collections.Immutable.ImmutableArray<byte> cryptoPublicKey = default(System.Collections.Immutable.ImmutableArray<byte>), bool? delaySign = null, Microsoft.CodeAnalysis.Platform platform = Microsoft.CodeAnalysis.Platform.AnyCpu, Microsoft.CodeAnalysis.ReportDiagnostic generalDiagnosticOption = Microsoft.CodeAnalysis.ReportDiagnostic.Default, int warningLevel = 4, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, Microsoft.CodeAnalysis.ReportDiagnostic>> specificDiagnosticOptions = null, bool concurrentBuild = true, bool deterministic = false, Microsoft.CodeAnalysis.XmlReferenceResolver xmlReferenceResolver = null, Microsoft.CodeAnalysis.SourceReferenceResolver sourceReferenceResolver = null, Microsoft.CodeAnalysis.MetadataReferenceResolver metadataReferenceResolver = null, Microsoft.CodeAnalysis.AssemblyIdentityComparer assemblyIdentityComparer = null, Microsoft.CodeAnalysis.StrongNameProvider strongNameProvider = null, bool publicSign = false, Microsoft.CodeAnalysis.MetadataImportOptions metadataImportOptions = Microsoft.CodeAnalysis.MetadataImportOptions.Public, Microsoft.CodeAnalysis.NullableContextOptions nullableContextOptions = Microsoft.CodeAnalysis.NullableContextOptions.Disable, decimal warningVersion = 0) -> void
Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions.CSharpCompilationOptions(Microsoft.CodeAnalysis.OutputKind outputKind, bool reportSuppressedDiagnostics, string moduleName, string mainTypeName, string scriptClassName, System.Collections.Generic.IEnumerable<string> usings, Microsoft.CodeAnalysis.OptimizationLevel optimizationLevel, bool checkOverflow, bool allowUnsafe, string cryptoKeyContainer, string cryptoKeyFile, System.Collections.Immutable.ImmutableArray<byte> cryptoPublicKey, bool? delaySign, Microsoft.CodeAnalysis.Platform platform, Microsoft.CodeAnalysis.ReportDiagnostic generalDiagnosticOption, int warningLevel, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, Microsoft.CodeAnalysis.ReportDiagnostic>> specificDiagnosticOptions, bool concurrentBuild, bool deterministic, Microsoft.CodeAnalysis.XmlReferenceResolver xmlReferenceResolver, Microsoft.CodeAnalysis.SourceReferenceResolver sourceReferenceResolver, Microsoft.CodeAnalysis.MetadataReferenceResolver metadataReferenceResolver, Microsoft.CodeAnalysis.AssemblyIdentityComparer assemblyIdentityComparer, Microsoft.CodeAnalysis.StrongNameProvider strongNameProvider, bool publicSign, Microsoft.CodeAnalysis.MetadataImportOptions metadataImportOptions, Microsoft.CodeAnalysis.NullableContextOptions nullableContextOptions) -> void
Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions.WarningVersion.get -> decimal
Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions.WithWarningVersion(decimal warningVersion) -> Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions
Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.AddArgumentListArguments(params Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax.ArgumentList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax
Expand Down
Loading

0 comments on commit d49e2af

Please sign in to comment.