Warning Waves #1580

Open
gafter opened this Issue Mar 25, 2015 · 11 comments
@gafter
Member
gafter commented Mar 25, 2015

Over the course of its few years of development, the Roslyn compiler team implemented a handful of valuable new diagnostics for situations in user code that almost certainly indicate errors, and which would be very expensive to implement outside the compiler. One typical example was the comparison of a struct value against null

    void M(..., CancellationToken token)
    {
        if (token == null) { ... }
    }

The test token == null must always fail (a struct value, when boxed into an object, is never null). This almost certainly indicates an error in the user's program. And indeed, this diagnostic alerted us to dozens of real bugs in the Roslyn code base. Other new warnings similarly alerted us to other problems.

Since compiler warnings are enabled by default, any project that upgrades to the new version of the compiler may be "broken" (e.g. if configured to treat warnings as errors) by the presence of newly implemented diagnostics at a time when changing the code or the build infrastructure is inconvenient. Due to this concern previous releases of the compiler have avoided adding diagnostics for existing code scenarios. We wanted to allow Roslyn, it its first release and in subsequent releases, to add value by adding additional warnings for likely code problems that are difficult to detect outside the compiler. But how could we do it without breaking compatibility?

A few years ago we considered adding the concept of "warning waves" to the compilers. The compiler would know in which compiler version support for each warning was added. The compiler command-line would specify a version for which warnings to allow; the compiler would then report only warnings that were implemented up until the specified "warning version". We held meetings and produced a detailed design.

Two years ago we dropped the idea of adding a specific "warning waves" flag to the compiler because we "realized" that the new mechanisms to control the diagnostics (such as ruleset files) are fine-grained enough to provide the same value.

Unfortunately we did not complete the work to address the scenario. Consequently all of the new warnings implemented in Roslyn have since been removed from the compilers due to compatibility concerns.

It is time for us to revisit the issue, to design and implement a solution that addresses the original problem. Users should be able to specify a version of the compiler that represents the set of warnings they are willing to have reported.

@gafter gafter added this to the 1.1 milestone Mar 25, 2015
@jaredpar jaredpar modified the milestone: 2.0, 1.1 Jul 31, 2015
@AnthonyDGreen
Contributor

We discussed this offline to come up with what we feel is a sensible design and some principles for this feature:

Definitions

  • A wave is defined to be a set of new diagnostic IDs and/or new circumstances for reporting existing diagnostics. i.e. either introducing a brand new warning or correctly reporting an existing warning in a new case that we hadn't reported it before due to a bug would be gated by this feature.

Principles

  • Warning waves are not intended to be a general mechanism that applies equally to Analyzers; this is a non-goal. Analyzers have NuGet semantic versioning as their primary vehicle for controlling the introduction of new warnings.
  • Warning waves must be decoupled from language versions; customers must be able to opt into the goodness of new language features without also forcing upon themselves the pain of new diagnostics.

Design

  • There shall be a flag which can be passed to the compiler which will enable any warnings introduced up to a specified warn-version or wave.
  • The flag shall have the syntax /warnversion:
    • This flag may control errors as well but given that the vast majority of cases will be warnings it makes more sense to call it /warnversion rather than /warnorerrorversion or /diagnosticversion.
  • The format of the version string shall match what /langversion accepts—the minor version will be incremented with each update, e.g. 6.1/14.1.
  • The default in the absence of this flag shall be the latest wave.
  • MSBuild will pass the value in the project file if specified; otherwise it will pass version 6/14 to maintain back compat for existing customers.
  • There should be a NOSEATBELTS option that explicitly opts into the latest wave.
@svick
Contributor
svick commented Sep 14, 2015

@AnthonyDGreen Since project.json is already used to version analyzers and the framework (at least for some project types), could it make sense to also use it to version the compiler and warning waves?

@gafter
Member
gafter commented Sep 15, 2015

Should that be ALLSEATBELTS 😉 ?

@AnthonyDGreen AnthonyDGreen removed their assignment Sep 20, 2015
@gafter gafter self-assigned this Feb 15, 2016
@gafter gafter modified the milestone: 2.0 (RC), 2.0 (Preview) Mar 7, 2016
@gafter gafter added the 2 - Ready label Mar 31, 2016
@srivatsn srivatsn removed the Area-Analyzers label Apr 1, 2016
@gafter gafter modified the milestone: 2.0 (RC), 3.0 Apr 4, 2016
@gafter gafter modified the milestone: 2.1, 3.0 Nov 16, 2016
@gafter
Member
gafter commented Nov 16, 2016

Moving to milestone 2.1 as that is when we'd like to consider the new warning on tuple name rearrangement #14217.

@alrz
Contributor
alrz commented Dec 12, 2016

Do we need to retain backward compatibility in future versions of warning wave? Since this is an opt-in feature I think it should be possible to add useful warnings that did not exist in the first version.

@jnm2
jnm2 commented Dec 12, 2016

Yes. And before anyone brings them up, the warnings-as-errors folks by definition would want their build to break when new warnings are added.

@eyalsk
eyalsk commented Dec 21, 2016 edited

Correct me if I'm wrong but does this feature mean we will have a strict version of C#? where some code that currently gets compiled will no longer compile iff the code violates the rules? I'm not sure if the comparison make sense but is it something like JavaScript "use strict"?

@DavidArno
DavidArno commented Dec 21, 2016 edited

@eyalsk,

My reading of @AnthonyDGreen's description suggestions it wouldn't be a simple dichotomy like JS's not-strict/strict modes. Instead, v16.1 of the compiler might introduce warnings around unused variables (as suggested by @alrz in #15695), then v16.2 might introduce warnings when contextual keywords are used as type or variable names. Even when v17 of the compiler comes out, I could then choose /warnversion=16.1 to not use the keyword warnings or /warnversion=ALLSEATBELTS to automatically get the latest warnings as the compiler advances.

So in JS terms, this would be like having use strict, use stricter..., or use strictest to get the latest.

@DavidArno

For the record, my vote for a warning in the first wave would be Don't write C# as if it were Java for when someone uses the K&R bracing style 😁

@eyalsk
eyalsk commented Dec 21, 2016

@DavidArno Thank you for explaining it to me! sounds good. 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment