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

Defend HelpCompletion from null message from VSCode #1236

Merged
merged 3 commits into from
Mar 27, 2018

Conversation

rjmholt
Copy link
Contributor

@rjmholt rjmholt commented Mar 21, 2018

Small change to ensure that null messages from VSCode don't cause errors, to fix #1230.

Copy link
Contributor

@rkeithhill rkeithhill left a comment

Choose a reason for hiding this comment

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

Defensive programming FTW! However I wish we knew why we sometimes get an undefined changeEvent.

Copy link
Contributor

@rkeithhill rkeithhill left a comment

Choose a reason for hiding this comment

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

Actually, the error is that contentChanges[0] is undefined. I wonder if you need to check for that before accessing the text property.

@rjmholt
Copy link
Contributor Author

rjmholt commented Mar 21, 2018

Ah, I see. This particular nasty seems to crop up a bit. I'll see if I consolidate the reports here. I'd love to know what VSCode is sending us (I tried to install Wireshark, but apparently there's extra stuff you need to install on Windows if you want to listen to localhost/loopback...)

@rjmholt
Copy link
Contributor Author

rjmholt commented Mar 21, 2018

So in addition to #1230, there is also #1189 and #1043. Do we think they are the same bug?

@rkeithhill
Copy link
Contributor

It certainly looks that way. My only concern is if the dev tools console err msg is just a harmless coincidence instead of what is actually causing the Intellisense problem in #1189.

@TylerLeonhardt
Copy link
Member

I tried to install Wireshark, but apparently there's extra stuff you need to install on Windows if you want to listen to localhost/loopback...

@rjmholt maybe fiddler can do this?

Copy link
Member

@TylerLeonhardt TylerLeonhardt left a comment

Choose a reason for hiding this comment

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

watch this fix all of the DocumentChangeEvent bugs lol

LGTM

if (!changeEvent) {
return;
}

this.helpCompletionProvider.updateState(
changeEvent.document,
changeEvent.contentChanges[0].text,
Copy link
Contributor

@rkeithhill rkeithhill Mar 22, 2018

Choose a reason for hiding this comment

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

Don't forget to check contentChanges[0] for undefined. If changeEvent itself was getting thru as undefined then we should have gotten an error on changeEvent.document first.

@rjmholt rjmholt force-pushed the null-msg-error-1230 branch from d0ee7cb to c0d0386 Compare March 22, 2018 17:24
@rjmholt
Copy link
Contributor Author

rjmholt commented Mar 22, 2018

I've added a logger call to document bad messages we receive

@rkeithhill
Copy link
Contributor

rkeithhill commented Mar 24, 2018

So I'm running this change and I see this log message during debugging of the extension:

typeDefinition.js:18
Bad change event message: {"document":{"uri":{"$mid":1,"fsPath":"c:\\Users\\Keith\\Documents\\WindowsPowerShell\\Profile.ps1","external":"file:///c%3A/Users/Keith/Documents/WindowsPowerShell/Profile.ps1","path":"/C:/Users/Keith/Documents/WindowsPowerShell/Profile.ps1","scheme":"file"},"fileName":"c:\\Users\\Keith\\Documents\\WindowsPowerShell\\Profile.ps1","isUntitled":false,"languageId":"powershell","version":2,"isClosed":false,"isDirty":true,"eol":2,"lineCount":31},"contentChanges":[]}

In looking at the docs I see this explanation of the onDidChangeTextDocument() method:

An event that is emitted when a text document is changed. This usually happens when the contents changes but also when other things like the dirty-state changes.

I get this when I add a space to the end of a line but because I have VSCode set to trim trailing whitespace, I get this event but the contentChanges array is empty (0 length). So I think the current code will generate many incorrect "bad change" messages.

Here is what I recommend we change this to:

    public onEvent(changeEvent: TextDocumentChangeEvent): void {
        if (!(changeEvent && changeEvent.contentChanges)) {
            this.log.write(`Bad TextDocumentChangeEvent message: ${JSON.stringify(changeEvent)}`);
            return;
        }

        if (changeEvent.contentChanges.length > 0) {
            this.helpCompletionProvider.updateState(
                changeEvent.document,
                changeEvent.contentChanges[0].text,
                changeEvent.contentChanges[0].range);

            // Todo raise an event when trigger is found, and attach complete() to the event.
            if (this.helpCompletionProvider.triggerFound) {
                this.helpCompletionProvider.complete().then(() => this.helpCompletionProvider.reset());
            }
        }
    }

@rjmholt
Copy link
Contributor Author

rjmholt commented Mar 24, 2018

Aha! Man what an edge case! Yeah, I will implement that 😄 Thanks @rkeithhill!

@rkeithhill
Copy link
Contributor

rkeithhill commented Mar 24, 2018

Ya know, given this TypeScript def of TextDocumentChangeEvent:

	export interface TextDocumentChangeEvent {

		/**
		 * The affected document.
		 */
		document: TextDocument;

		/**
		 * An array of content changes.
		 */
		contentChanges: TextDocumentContentChangeEvent[];
	}

Doesn't this mean those two fields can't be null or undefined - cc @daviwil ? Admittedly my TypeScript skillz are still pretty weak so I'm not 100% sure on that. If it is true, we might as well just get rid of that first null check since it should never be invoked.

@TylerLeonhardt
Copy link
Member

@rkeithhill good find on the edge case! FWIW, I'm pretty sure and empty array is falsey so changeEvent.contentChanges.length > 0 doesn't need the length check but it's easier to read so I'm cool with that. Just thought I'd point that out.

Also, I'm pretty sure that those two fields can still be null just like in a C# class. I don't think they can be undefined. I'm like 85% confident in this statement.

@rkeithhill
Copy link
Contributor

After a quick experiment, it looks like you're right so leave the null check in. But in the future, C# 8 won't allow null assignment unless the type is defined as nullable. I'm looking forward to this. :-)

@rjmholt
Copy link
Contributor Author

rjmholt commented Mar 24, 2018

Yeah, TypeScript's interface explanation page isn't very helpful. I think it's a compile-time check, which doesn't help much from arbitrary deserialised network messages, just gives completions on them. (I think the intent is that you use an interface to describe the JSON you're expecting, then you feed it into a constructor of a full TypeScript object to rehydrate it and give it methods, etc.).

Had no idea C# was planning that — finally we won't have to do null checks all the way down, and hopefully the CLR will be able to use the information to run quicker.

@rkeithhill
Copy link
Contributor

Check out this MSDN article on C# 8 - Nullable Reference Types.

It is actually very common that contentChanges array is length 0 so let's not gen a message to the log.
@rkeithhill
Copy link
Contributor

Time to merge this one.

@rkeithhill rkeithhill merged commit 02198db into PowerShell:master Mar 27, 2018
@rjmholt rjmholt deleted the null-msg-error-1230 branch December 11, 2019 21:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Error] TypeError: Cannot read property 'text' of undefined at HelpCompletionFeature.onEvent
3 participants