This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Check preceding char when completion triggers on ':' or '>'
ClosedPublic

Authored by ilya-biryukov on Dec 21 2018, 3:45 AM.

Details

Summary

Only run completion when we were trigerred on '->' and '::', otherwise
send an error code in return.
To avoid automatically invoking completions in cases like 'a >^' or
'a ? b :^'.

Diff Detail

Repository
rL LLVM

Event Timeline

ilya-biryukov created this revision.Dec 21 2018, 3:45 AM

This still needs tests, will add them before committing the change. However, the implementation should be good for review.

hokein added a comment.Jan 2 2019, 3:15 AM

The code looks mostly good to me.

clangd/ClangdLSPServer.cpp
789 ↗(On Diff #179261)

The method name is a bit confusing to me, I didn't get its meaning at the first glance and without reading its comment. Maybe shouldRunCompletion?

811 ↗(On Diff #179261)

Checking Offset is not always right for rare cases like (bar:/*commment*/:), a robust way is to use lexer and get the token at the current position, but I don't think it is worth (these rare cases should not happen when people write code). Maybe add a comment documenting the limitation?

ilya-biryukov marked 3 inline comments as done.
  • Address comments
  • Added a test
clangd/ClangdLSPServer.cpp
811 ↗(On Diff #179261)

Done. Note that bar:/*comment*/: is not actually a qualifier, i.e. a single token cannot be split in half by the comment.
But the comment is totally valid: use the lexer would allow to filter out more things, e.g. we don't want to auto-trigger inside a comment, etc.

hokein accepted this revision.Jan 2 2019, 7:58 AM
hokein added inline comments.
clangd/ClangdLSPServer.cpp
811 ↗(On Diff #179261)

Yeah, you are right a single token cannot be split in half by the comment. Thanks for the clarification.

test/clangd/completion-auto-trigger.test
13 ↗(On Diff #179844)

nit: would be nicer if we add a comment illustrating what this request tests for. For this case, it is a->^, IIUC.

26 ↗(On Diff #179844)

sortText is implementation details, maybe use {{.*}}size, the same below.

This revision is now accepted and ready to land.Jan 2 2019, 7:58 AM

This looks like a work around LSP imperfection indeed.

Are you going to push for change in LSP? Something like CompletionOptions/triggerCharacters -> CompletionOptions/triggerStrings?

export interface CompletionOptions {
	/**
	 * The server provides support to resolve additional
	 * information for a completion item.
	 */
	resolveProvider?: boolean;

	/**
	 * The characters that trigger completion automatically.
	 */
	triggerCharacters?: string[];
}

https://microsoft.github.io/language-server-protocol/specification

hokein added a comment.Jan 3 2019, 1:16 AM

This looks like a work around LSP imperfection indeed.

Are you going to push for change in LSP? Something like CompletionOptions/triggerCharacters -> CompletionOptions/triggerStrings?

export interface CompletionOptions {
	/**
	 * The server provides support to resolve additional
	 * information for a completion item.
	 */
	resolveProvider?: boolean;

	/**
	 * The characters that trigger completion automatically.
	 */
	triggerCharacters?: string[];
}

https://microsoft.github.io/language-server-protocol/specification

I think LSP uses a single character as a trigger character (see CompletionTriggerKind::TriggerCharacter). The string type of triggerCharacter is misleading, a more correct type is char I believe, but char is not the basic type in JSON schema.

ilya-biryukov added a comment.EditedJan 3 2019, 1:43 AM

This looks like a work around LSP imperfection indeed.

Totally.

Are you going to push for change in LSP? Something like CompletionOptions/triggerCharacters -> CompletionOptions/triggerStrings?

This would workaround this particular problem, but I don't expect the triggerStrings to cover all the use-cases we care about in the long-term.
A few examples that need semantic knowledge:

  • Auto-completions inside a comment
int test() {
  std::^ // <-- should trigger here
  // std::^ <-- this is inside a comment, shouldn't trigger here as clang won't provide any useful results anyway.
}
  • Trailing return types
auto foo() ->^ int {}// <-- should not trigger here

@hokein I think you are correct. I meant that it would be possible to make LSP more generic by using trigger strings instead of trigger characters..
@ilya-biryukov Yes, that's true. I would still expect some performance gain in more restrictive filtering on client's side - not sure how big though. Anyway, seems like LSP folks think character + trigger context is good enough. For example here:
https://github.com/Microsoft/language-server-protocol/issues/138

@ilya-biryukov Yes, that's true. I would still expect some performance gain in more restrictive filtering on client's side - not sure how big though. Anyway, seems like LSP folks think character + trigger context is good enough. For example here:
https://github.com/Microsoft/language-server-protocol/issues/138

That would definitely mean less completion requests from the client, I doubt it would be the bottleneck for performance, though.
Thanks for the pointers, an insightful conversation on almost the same issue there.

This revision was automatically updated to reflect the committed changes.