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

Initial stubs for an LSIF generator that runs as part of the normal compilation pass. #49046

Conversation

CyrusNajmabadi
Copy link
Member

@CyrusNajmabadi CyrusNajmabadi commented Oct 29, 2020

Should be reviewed one commit at a time. The basic idea, after talking to @jasonmalinowski @chsienki is to allow analyzers to add additional source files to a compilation that can be written out if the user supplies a generated-output directory to the compiler.

This way they run as a post pass during the analyzer pass (so after source generators), seeing the entire real compilation. They also only generate addtional-files, not source-files, so they have no impact on the meaning of any symbols.

This should be reviewed one commit at a time. Sending out now so i can get feedback before digging myself into too deep a hole.

lock (generatedAdditionalFiles)
generatedAdditionalFiles.Add(tuple);
};
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this part is new.

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray<DiagnosticDescriptor>.Empty;

public sealed override void Initialize(AnalysisContext context)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sealed as we do not want the subclasses to control this at all. they only override the various GenerateArtifacts overloads.

Microsoft.CodeAnalysis.Diagnostics.ArtifactContext.WriteArtifact(string! fileName, string! source) -> void
Microsoft.CodeAnalysis.Diagnostics.ArtifactContext.WriteArtifact(string! fileName, System.Action<System.IO.Stream!>! writeStream) -> void
Microsoft.CodeAnalysis.Diagnostics.ArtifactContext.WriteArtifact(string! fileName, System.Text.StringBuilder! builder) -> void
Microsoft.CodeAnalysis.Diagnostics.IArtifactProducer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't exist any more right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird! vs didn't give me any errors about this. removed.

@jasonmalinowski
Copy link
Member

FYI there's a file called "git" at the root which, being empty, means GitHub won't let me comment on the file:

image

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API shape seems quite good to me other than a potential concern making ArtifactContext a struct (discussed in a comment). and also some concerns about whether file locking is sufficient/wise to prevent multiple writing to artifacts. The former I'm not convinced myself whether changing is better or if it's a problem, and the latter is an implementation detail that doesn't impact the API shape.

(I want a button on GitHub which is "approve with comments but I also really didn't look at how the implementation of this all hooks up with existing code so don't pretend I reviewed that.")

@@ -9811,7 +9811,7 @@ private static int OccurrenceCount(string source, string word)

if (expectedInfoCount == 0)
{
Assert.DoesNotContain("info", output, StringComparison.Ordinal);
Assert.DoesNotContain("info", output.Split('\n').First(), StringComparison.Ordinal);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's going on with this change here? Could this now cause tests to miss something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. the problem was that you might get something like a stack-trace in a compiler message (i.e. when analyzers crash we include their stack in the message). But we don't want to search that stack for things like 'info/warn/error' because the stack trace message may contain that. Instead, we just check the first line of the compiler diagnostic message as that is the part where the compiler itself prints out if this is a warning/info/error.

note: this is a major hack in teh first place as all these tests run the compiler then grok the console output. this just makes us resilient to that problem (which i was hitting).

Comment on lines +18 to +19
/// supported. In general that will only be when a compiler is invoked with the <c>generatedartifactsout</c>
/// argument.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might have to be careful if people start trying to write code that emits diagnostics because of a failure of this method. People might think "oh, I don't want people to forget to set /generatedartifactsout, let me be helpful by emitting a diagnostic!" and now they're getting diagnostics in the IDE. I'm not sure it's worth putting docs here, but maybe in any sort of guide we write up for this.

src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs Outdated Show resolved Hide resolved
src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs Outdated Show resolved Hide resolved
src/Compilers/Core/Portable/CommandLine/CommonCompiler.cs Outdated Show resolved Hide resolved
@CyrusNajmabadi
Copy link
Member Author

Feedbak addressed.

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API looks good from my perspective; IDE and compiler folks should still review the actual changes to the diagnostics engine that react to it.

@CyrusNajmabadi
Copy link
Member Author

Design meetings questions and conclusions:

  1. Should we have the string builder overload?

Yes. There is no safety concern here as we are not taking ownership of the string builder. Instead, we are copying the data over the lifetime of the call and writing it to the stream. This saves expensive allocations and is more convenient than forcing the user to make the stream, and copy to it themselves. This does force us to doc that copying/writing is done immediately. However, that is not a bad thing, and is actually important for this domain as the purpose is to allow large scale artifacts to be written without high memory costs.

  1. Should we ensure that file-names provided are relative only?

Yes. All writes must be under the artifact-production dir. Absolute paths are not allowed. And using .. should be prevented. We may have existing mechanisms to help here that we can reuse.

  1. Need to plug this into GeneratorContext with same semantics as AnalysisContext.
  2. Add cancellation support to these apis.
  3. Add support for ReadOnlySpan
  4. Move to TryCreateStream so plugins can gracefully fail if we cannot make a stream (e.g. 'out of handles').
  5. Allow fine grained customization of destination directory. Multiple output paths per producer shoudl be supported.
  6. REmove the Action callback form of teh api.

@chsienki chsienki changed the base branch from main to features/artifact-producer March 12, 2021 17:56
Copy link
Contributor

@chsienki chsienki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created a feature branch for this work.

I'm happy with the code as-is right now, modulo the design review questions, which we will address in future PRs

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

Successfully merging this pull request may close these issues.

6 participants