Closed mjbvz closed 6 years ago
@mjbvz is that something you see in older versions of tsserver? or is this a recent regression?
Yes but it is significantly worse in 3.0. This may be because we are now making more requests or it could be something else
@mjbvz do your have complete repro code and tsserver log. I am not able to repro this with master branch in vscode/vscode insiders/our test framework.
FYI This test passes correctly
it("reports correct errors on format of a change", () => {
const projectRootPath = "/user/username/projects/project";
const file: File = {
path: `${projectRootPath}/a.ts`,
content: `class C {
public execute(): string {
return "";
}
}`
};
const configFile: File = {
path: `${projectRootPath}/tsconfig.json`,
content: "{}"
};
const files = [file, configFile, libFile];
const host = createServerHost(files);
const session = createSession(host, { canUseEvents: true });
session.executeCommandSeq<protocol.OpenRequest>({
command: protocol.CommandTypes.Open,
arguments: {
file: file.path,
projectRootPath,
fileContent: file.content
}
});
const insertLine = 3;
const insertOffset = 3;
const insertString = "\t\tthis.fileConfigManager.ensureConfigurationForDocument();";
session.executeCommandSeq<protocol.ChangeRequest>({
command: protocol.CommandTypes.Change,
arguments: {
file: file.path,
line: insertLine,
offset: insertOffset,
endLine: insertLine,
endOffset: insertOffset,
insertString
}
});
const formatOptions = clone(server.getDefaultFormatCodeSettings(host));
formatOptions.convertTabsToSpaces = false;
session.executeCommandSeq<protocol.ConfigureRequest>({
command: protocol.CommandTypes.Configure,
arguments: {
file: file.path,
formatOptions
}
});
const formatResponse = session.executeCommandSeq<protocol.FormatRequest>({
command: protocol.CommandTypes.Format,
arguments: {
file: file.path,
line: insertLine,
offset: insertOffset,
endLine: insertLine + 1,
endOffset: 1
}
}).response! as protocol.CodeEdit[];
assert.deepEqual(formatResponse, [{
start: { line: insertLine, offset: 1 },
end: { line: insertLine, offset: 5 },
newText: "\t\t"
}]);
session.executeCommandSeq<protocol.ChangeRequest>({
command: protocol.CommandTypes.Change,
arguments: {
file: file.path,
line: formatResponse[0].start.line,
offset: formatResponse[0].start.offset,
endLine: formatResponse[0].end.line,
endOffset: formatResponse[0].end.offset,
insertString: formatResponse[0].newText
}
});
session.executeCommandSeq<protocol.GeterrRequest>({
command: protocol.CommandTypes.Geterr,
arguments: {
files: [file.path],
delay: 0
}
});
session.clearMessages();
host.checkTimeoutQueueLengthAndRun(1);
checkErrorMessage(session, "syntaxDiag", { file: file.path, diagnostics: [] });
session.clearMessages();
host.runQueuedImmediateCallbacks();
const propertyName = "fileConfigManager";
const startOffset = insertString.indexOf(propertyName) + 1;
checkErrorMessage(session, "semanticDiag", {
file: file.path, diagnostics: [
createDiagnostic({ line: insertLine, offset: startOffset }, { line: insertLine, offset: startOffset + propertyName.length }, Diagnostics.Property_0_does_not_exist_on_type_1, [propertyName, "C"])
]
});
session.clearMessages();
host.runQueuedImmediateCallbacks();
checkErrorMessage(session, "suggestionDiag", { file: file.path, diagnostics: [] });
});
TS Server log from above: https://github.com/Microsoft/TypeScript/files/2191362/tsserver.log
Repo steps that works 50% of the time for me on OSX:
vscode/extensions/typescript-language-features/src/features/organizeImports.ts
this.fileConfigManager.ensureConfigurationForDocument(document, token);
(with spaces)execute
on line 28@sheetalkamat Have you made progress investigating this? Any additional information needed?
@mjbvz Looking into this today. Sorry was oof last few days to look into this.
@mjbvz I am not able to reproduce this in latest vscode-insiders or running just tsserver from either vscode or master of typescript. I also followed exact sequence of commands and still the error reports correctly. (and i do see that in your case the error is returned with expectedColumn+2. The tsserver version shown in your log is Version: 3.0.0-dev. Do you mind checking if you are able to repro this with typescript@next.
Moving this to 3.1.0 after chatting with @mjbvz that this repros only when plugin typescript-lit-html-plugin
is enabled.
@sheetalkamat Can you or someone else on the ts team help look through https://github.com/Microsoft/typescript-template-language-service-decorator to see what may be going wrong here. It almost seems like something in the plugin can cause the language service to use an old version of the ast but I can't track what could be causing this or why this only happens in specific cases.
Possible places to investigate:
Let me know if you have any questions about the code or want to pair on the investigation
@mjbvz Will take a look.
Here is the issue: When getFormattingEditsForRange is called, we do not update the program (since its syntax only operation, we keep program as is and want to just use updated snapshot of changed file and nothing else) and then call const edits = languageService.getFormattingEditsForRange(file, startPosition, endPosition, this.getFormatOptions(file)); which redirects it to getFormattingEditsForRange of template language service and as part of that call, it tries to get All nodes by updating the program in language service. At this point the program in service gets updated but project doesn’t know about it. When next change request is sent, the projectVersion is not updated since the project thinks its still dirty. And as a result when getDiagnostics is called, we miss this change all together and operate on the program when format is called.
I think your language service plugin should not depend on program if its syntax only operation. In the mean time you can pass around the project instead of LS to StandardScriptSourceHelper and call getLanguageServie from there to avoid this. (note that just making project incrementing version all the time is not a good solution because project when its updating program does lot of work and we want it to not miss that). The temporary fix would loose a bit of efficiency since project would be updated on syntax operations that you override which isn’t needed.
Just so you know this is what I did to repro and investigate:
node c:\typescript\built\local\tsserver.js --useInferredProjectPerProjectRoot --globalPlugins typescript-lit-html-plugin --pluginProbeLocations C:\Users\shkamat\.vscode\extensions\bierner.lit-html-1.6.2 --locale en --noGetErrOnBackgroundUpdate
Typed these commants one by one
{"seq":2,"type":"request","command":"open","arguments":{"file":"c:/temp/test4/src/a.ts","fileContent":"class c {\r\n\tpublic execute() {\r\n\r\n\t\tconsole.log(\"in execute\");\r\n\t}\r\n}"}}
{"seq":16,"type":"request","command":"change","arguments":{"insertString":"\t\t\t\tthis.fileConfigManager.ensureConfigurationForDocument(document, token);\r\n","file":"c:/temp/test4/src/a.ts","line":3,"offset":1,"endLine":3,"endOffset":1}}
{"seq":18,"type":"request","command":"format","arguments":{"file":"c:/temp/test4/src/a.ts","line":3,"offset":1,"endLine":4,"endOffset":1}}
{"seq":19,"type":"request","command":"change","arguments":{"insertString":"","file":"c:/temp/test4/src/a.ts","line":3,"offset":3,"endLine":3,"endOffset":5}}
{"seq":21,"type":"request","command":"geterr","arguments":{"delay":0,"files":["c:/temp/test4/src/a.ts"]}}
TypeScript Version: 3.0.0-dev.20180706
Bug In VS Code, when using the
format on paste
setting, I've noticed that we sometimes end up displaying diagnostics at incorrect locations. Editing the file fixes this problem. I've tried tracking this down and believe that the TS server may be returning stale locations in this case.Here's the sequence of events:
User pastes an some code that includes tabs onto an existing line.
Here I've pasting a line:
\t\tthis.fileConfigManager.ensureConfigurationForDocument(document, token);\n
into code that looks like:This triggers a change against tsserver
Back in vscode, we run
format
and send tsserver anotherchange
request after applying the edit. In this case the change remove the two extra tabs that were added from the pasteWe then kick off a
geterr
request a little later.I believe this request returns errors at stale locations. The full text of the line in VS Code is now:
with the err span returned from character 10 - 27, which works out to be:
In the editor here is what I see:
Here is a complete ts server log for this case: tsserver.log