-
Notifications
You must be signed in to change notification settings - Fork 676
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
[WIP] Move unresolved imports to the language server + related bug fixes #4367
Conversation
- Fix microsoft#4349 for VS Code: LastReportedDiagnostics isn't cleared after document is closed and reopened bug - Fix microsoft#4351 for VS Code: OpenFile._pendingChanges isn't cleared after document is closed - Fix microsoft#4363: Inconsistent behavior when showing errors in project items - Fixed memory leaks in ErrorTaskProvider
@@ -27,8 +27,6 @@ public sealed partial class Server { | |||
await IfTestWaitForAnalysisCompleteAsync(); | |||
|
|||
var uri = @params.textDocument.uri; | |||
// Make sure document is enqueued for processing | |||
var openFile = _openFiles.GetDocument(uri); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't ensure anything, so removed
@@ -49,7 +49,7 @@ sealed class OpenFile { | |||
|
|||
public void DidChangeTextDocument(DidChangeTextDocumentParams @params, Action<IDocument> enqueueAction) { | |||
var changes = @params.contentChanges; | |||
if (changes == null) { | |||
if (changes == null || changes.Length == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VSC can send textDocument/didChange
with no changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For instance, it sometimes happens when file is saved. Version isn't updated as well, so we don't have to do anything here.
|
||
private static bool IsImportError(Expression expr) { | ||
if (expr is NameExpression name) { | ||
return name.Name == "Exception" || name.Name == "BaseException" || name.Name == "ImportError"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Python 3.6 added ModuleNotFoundError
, which we should probably also have here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -49,7 +49,7 @@ sealed class OpenFile { | |||
|
|||
public void DidChangeTextDocument(DidChangeTextDocumentParams @params, Action<IDocument> enqueueAction) { | |||
var changes = @params.contentChanges; | |||
if (changes == null) { | |||
if (changes == null || changes.Length == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙄
if (_clientCaps?.python?.analysisUpdates ?? false) { | ||
pyItem.OnNewAnalysis += ProjectEntry_OnNewAnalysis; | ||
} | ||
pyItem.OnNewAnalysis += (o, e) => OnPythonEntryNewAnalysis(pyItem); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why change the event handler signature? We don't need the lambda and closure here, and for large workspaces it's a cost we may notice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since OnNewAnalysis
is a public API, I can't change its signature and provide correct type in eventArgs
. Type check inside old handler was misleading - there can be no other type, so this code is cleaner and easier to understand (no need to look for all existing implementations of IPythonProjectTree
). Closure contains two reference type fields, so I can't imagine how we may notice it considering hundreds of kilobytes of garbage strings in G2 per every new tree parse.
_clientCaps = new Capabilities(@params.capabilities); | ||
_settings.SetCompletionTimeout(_clientCaps.Python.CompletionsTimeout); | ||
_traceLogging = _clientCaps.Python.TraceLogging; | ||
_analyzer.EnableDiagnostics = _clientCaps.Python.LiveLinting; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LiveLinting
is currently false by default, since we have other messages behind that flag that we do not want to release. If unresolved imports are going there too, we might need an alternative filter somewhere in the analyzer to allow "good" diagnostics.
The LiveLinting
flag is meant to enable experimental stuff, so maybe internally we can change it to EnableExperimentalDiagnostics
and filter those somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, unresolved imports should be default on (as warning). We can expose controls for severity like VS does so user can suppress warnings if they chose to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another alternative is create new structure with flags for assorted diagnostic controls and I can expose it in the VSC settings. We can then keep expanding it as needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_analyzer.EnableDiagnostics
doesn't affect unresolved imports, and yes, they are reported as warnings.
I like the idea of having granulated diagnostics controls on the client side, that we can switch from false
to true
as needed.
LGTM apart from the options setting |
Yep, but let’s make it “from true to false” on the client side. The language server should be able to introduce new warnings without a client update. But I’d still like to have a “give me experimental warnings” option that doesn’t refer to each warning code individually.
|
- Address CR comments - Enable default values population during deserialization
- Remove some dead code - Merge branch 'master' of https://github.com/microsoft/PTVS # Conflicts: # Python/Product/Analysis/LanguageServer/Server.cs # Python/Product/VSCode/AnalysisVsc/LanguageServer.cs
Matching PR in vscode: microsoft/vscode-python#2049 |
@@ -44,6 +44,10 @@ | |||
<PlatformTarget>AnyCPU</PlatformTarget> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<Reference Include="Newtonsoft.Json"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to be very certain that we need dependencies for this assembly before we add them. Right now this assembly has no external dependencies, so let's be 110% sure we need this and it can't be done in some other way (even if it's a little less convenient for us).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making the LSP structures in Analysis.dll a direct representation of the JSON packets is deliberate, and I'm not sure what benefit we get from making them different and adding an external dependency to hide the differences when we could just keep them the same.
@@ -320,23 +324,33 @@ public struct ExecuteCommandCapabilities { public bool dynamicRegistration; } | |||
} | |||
|
|||
[Serializable] | |||
public class TextDocumentClientCapabilities { | |||
public struct TextDocumentClientCapabilities { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this will prevent us from changing the contents of this struct/class in the future. I'd rather it stay as a class (and probably should be sealed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Similar for the other types in this file)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that we need to declare clear rules on how types for serialization are declared, but I'm not sure how classes would help with versioning. To be detached from protocol changes, we need to remove all references to protocol data types from public part of API and/or inject a group of abstractions.
The benefits of structs are that they are not nullable, which saves us from endless null checks, enforces default values and makes null
a real expected value instead of a sign that we haven't serialized something.
The benefit of classes is that they are safely mutable, but I'm against mutable protocol data types. Another benefit is that class loses its default constructor when non-default is presented, which will immediately give us deseriazliation error if default value isn't properly defined.
@MikhailArkhipov , what is your opinion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking more about assemblies that reference us. We can add members to a class without breaking those dependencies, but we can't do that with a value type because it will change the size of the type.
[Serializable] | ||
public struct SynchronizationCapabilities { | ||
[DefaultValue(false)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is implied - no need to specify it.
/// <summary> | ||
/// Client expects analysis progress updates, including notifications | ||
/// when analysis is complete for a particular document version. | ||
/// </summary> | ||
public bool? analysisUpdates; | ||
public readonly bool AnalysisUpdates; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why change these from how the JSON is represented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because inside C# code we don't care about JSON (that's the whole point of these types) and everywhere else public fields and properties are UpperCamelCase (which is also default for C#). Names in constructor match names in JSON. Type isn't serialized in .net, only deserialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the author of these types, I say the whole point is to represent the JSON messages as closely as possible :) (See my comment below for my actual argument about not changing this)
public object experimental; | ||
public PythonClientCapabilities python; | ||
public readonly WorkspaceClientCapabilities Workspace; | ||
public readonly TextDocumentClientCapabilities TextDocument; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These no longer serialize correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK, we don't serialize them - only deserialize.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, now we can't serialize them :) Tests would be the main place I'd expect we'd want to serialize them, but even so, consistency with the rest of this file (where we do serialize values) seems like a good enough reason to keep them consistent.
We can set up parallel (and private) data structures for internal use if we don't want to directly work with the JSON-like types, but I don't have any issue with using them directly.
@@ -0,0 +1,100 @@ | |||
using System; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a copyright header (did you add this or just merge it in from someone else's PR? regardless, copy/paste a header please)
# Conflicts: # Python/Product/PythonTools/PythonTools/Intellisense/ProjectAnalyzer.cs
OpenFile._pendingChanges
isn't cleared after document is closed #4351 for VS Code: OpenFile._pendingChanges isn't cleared after document is closedFixes for #4349 and #4351 for VS require better synchronization between
BufferParser.AddBuffer
andBufferParser.RemoveBuffer
that has to be converted intoasync
to send and await fortextDocument/didOpen
andtextDocument/didClose
.