Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider running debug builds of analyzers/source generators in some build leg #88901

Open
vitek-karas opened this issue Jul 14, 2023 · 3 comments

Comments

@vitek-karas
Copy link
Member

Analyzers are compiled against a specific version of the C# compiler. As such they can only recognize the shapes of the code that version of the compiler supports. With a new version of the compiler new shapes become possible, sometimes these are subtle changes, sometimes they mean adding new node types to representation or new enum values to properties. Since we can't update analyzers in sync with the compiler, the analyzer has to be written such that it can survive most of these changes without too much harm (typically it would simply ignore the new shape).

But that means that we don't get to be notified if such a new shape start occurring and can't fix the analyzer unless we have some other reason to look into that case. There will be cases where the analyzer doesn't work the way it should simply because it wasn't updated to match the latest compiler behavior.

We considered adding a warning into the analyzer to ask the user to file an issue if this happens, but that comes with rather severe downsides:

  • If this happens, it's not an actionable warning (other than filing the bug), the only solution is to suppress the warning code
  • Lot of users treat warnings as errors, so this becomes a blocking problem for them if it happens
  • We're putting burden on our users due to our inability to keep things in sync

(See the discussion in #88836 for some more detail)

For the illink analyzer we decided to change these cases into assertions. But that means we would like to run the debug build of the analyzer on as much code as possible so that we catch these things internally when they happen.

I think it would make sense to do this for all the analyzers where it's possible - there are assertions in their code bases as well which are only exercised on targeted unit tests, but basically never on real-world code.

The same thing applies to source generators as well obviously.

/cc @sbomer @agocke @jkoritzinsky

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 14, 2023
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Jul 14, 2023
@jeffschwMSFT jeffschwMSFT added the area-Tools-ILLink .NET linker development as well as trimming analyzers label Jul 14, 2023
@ghost
Copy link

ghost commented Jul 14, 2023

Tagging subscribers to this area: @agocke, @sbomer, @vitek-karas
See info in area-owners.md if you want to be subscribed.

Issue Details

Analyzers are compiled against a specific version of the C# compiler. As such they can only recognize the shapes of the code that version of the compiler supports. With a new version of the compiler new shapes become possible, sometimes these are subtle changes, sometimes they mean adding new node types to representation or new enum values to properties. Since we can't update analyzers in sync with the compiler, the analyzer has to be written such that it can survive most of these changes without too much harm (typically it would simply ignore the new shape).

But that means that we don't get to be notified if such a new shape start occurring and can't fix the analyzer unless we have some other reason to look into that case. There will be cases where the analyzer doesn't work the way it should simply because it wasn't updated to match the latest compiler behavior.

We considered adding a warning into the analyzer to ask the user to file an issue if this happens, but that comes with rather severe downsides:

  • If this happens, it's not an actionable warning (other than filing the bug), the only solution is to suppress the warning code
  • Lot of users treat warnings as errors, so this becomes a blocking problem for them if it happens
  • We're putting burden on our users due to our inability to keep things in sync

(See the discussion in #88836 for some more detail)

For the illink analyzer we decided to change these cases into assertions. But that means we would like to run the debug build of the analyzer on as much code as possible so that we catch these things internally when they happen.

I think it would make sense to do this for all the analyzers where it's possible - there are assertions in their code bases as well which are only exercised on targeted unit tests, but basically never on real-world code.

The same thing applies to source generators as well obviously.

/cc @sbomer @agocke @jkoritzinsky

Author: vitek-karas
Assignees: -
Labels:

untriaged, area-Tools-ILLink, needs-area-label

Milestone: -

@vcsjones vcsjones removed the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jul 14, 2023
@agocke agocke added this to AppModel Aug 17, 2023
@agocke agocke added this to the Future milestone Aug 17, 2023
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Aug 17, 2023
sbomer added a commit that referenced this issue Oct 20, 2023
In faf883d I inadvertently
turned off the trim analyzer for libraries, because the analyzer
bits don't flow to the consuming project with the ILLink.Tasks
ProjectReference. This adds a separate ProjectReference to use
the live analyzer. This addresses
#88901 for the ILLink
analyzers.

Using the live analyzer uncovered some bugs that are fixed in
this change:

- Invalid assert for field initializers with `throw` statements

- Invalid cast to `IMethodSymbol` for the ContainingSymbol of a
  local. Locals can occur in field initializers, when created
  from out params.

- Wrong warning code produced for assignment to annotated
  property in an initializer. This was being treated as a call to
  the setter instead of an assignment to the underlying field:

  `Type AnnotatedPropertyWithSetter { get; set; } = GetUnknown ();`

- Invalid assert for delegate creation where the delegate is
  created from anything other than a method (for example, a field
  that has an Action or Func type).

- Assert inside GetFlowCaptureValue for the LHS of a compound
  assignment. I couldn't think of a case yet where we actually
  need to model the result of the assignment, so I implemented
  support for at least visiting the LHS by going through the same
  path as normal assignments (avoiding GetFlowCaptureValue).
@sbomer
Copy link
Member

sbomer commented Jun 22, 2024

This was done for the ILLink analyzers in #93259. @agocke @jkoritzinsky are there other analyzers or source generators we should consider?

For the illink analyzer we decided to change these cases into assertions.

Note that in #94888 (comment) we settled on throwing, not asserting (but throwing in Debug builds only). That's important because throwing will surface as an AD0001 warning that can be silenced, whereas asserts aren't easily silenced (see #94858).

@sbomer sbomer removed the area-Tools-ILLink .NET linker development as well as trimming analyzers label Jun 22, 2024
@jkoritzinsky
Copy link
Member

jkoritzinsky commented Jun 22, 2024

We moved all of our assertions into throws (in both debug and release) quite a while ago, so this doesn't apply for the interop generators. Since generally our generators produce code required for a successful compilation (or at least for any meaningful test case to pass), I'm not concerned about suppressions of AD0001.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

No branches or pull requests

6 participants