Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Basic Goto Declaration Support #22

Closed
wants to merge 24 commits into from
Closed

Conversation

ehedbor
Copy link
Contributor

@ehedbor ehedbor commented May 13, 2024

Adds a first draft of goto declaration. Also adds support for multiple files and incremental parsing.

There are some known issues with the implementation:

  1. Some language features like encapsulated packages and array indices in component expressions are not handled. These were not implemented due to lack of time.
  2. Components' superclasses are ignored in nested component accesses (e.g in foo.bar, bar will not be found if it was declared in a superclass of whatever foo is). This is due to a bug that caused infinite recursion when the feature was enabled.
  3. In case of a conflict, goto declaration will simply return the first declaration it finds. This may affect things like multiple inheritance (this begs the question: if multiple classes declare the same component, which one should be used?).
  4. In the case of import aliases, it was debated if goto declaration should take the user to the alias or to the original symbol. Right now the algorithm does the latter.
  5. We use LSP.LocationLinks to return the position of symbols we find. The advantage of this is that it allows one to separately specify both the declaration (VS Code shows this in tooltips) and the symbol being defined (VS Code highlights this when going to the declaration). However, we did not have time to define
  6. Although it is enabled, goto definition is not supported. Known differences include import aliases (see 4) and inner/outer declarations.

ehedbor and others added 21 commits April 11, 2024 15:59
Co-authored-by: PaddiM8 <hi@bakk.dev>
Co-authored-by: PaddiM8 <hi@bakk.dev>
Co-authored-by: PaddiM8 <hi@bakk.dev>
Co-authored-by: PaddiM8 <hi@bakk.dev>
Co-authored-by: PaddiM8 <hi@bakk.dev>
Co-authored-by: PaddiM8 <hi@bakk.dev>
Co-authored-by: PaddiM8 <hi@bakk.dev>
Co-authored-by: PaddiM8 <hi@bakk.dev>
Co-authored-by: PaddiM8 <hi@bakk.dev>
Co-authored-by: PaddiM8 <hi@bakk.dev>
@CLAassistant
Copy link

CLAassistant commented May 13, 2024

CLA assistant check
All committers have signed the CLA.

@AnHeuermann AnHeuermann self-requested a review May 13, 2024 14:23
@AnHeuermann
Copy link
Member

In case of a conflict, goto declaration will simply return the first declaration it finds. This may affect things like multiple inheritance (this begs the question: if multiple classes declare the same component, which one should be used?).

The C++ language server extension from Microsoft will open a small view with a list of all definitions. We could at some point do something similar:
grafik

Copy link
Member

@AnHeuermann AnHeuermann left a comment

Choose a reason for hiding this comment

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

I'm not sure on what example to test this pull request. I did open the Modelica Standard Library directory /home/user/.openmodelica/libraries/Modelica 4.0.0+maint.om. I can see that the LS is detecting and loading all the mo files but I couldn't get the jump to definition part working.

Can you provide:

  1. Unit tests for each new major class you added to the server part. Then we can check that they are working as expected and we don't break them in the future. For example one test for the incremental parsing. One test for the file detection part. One test for the jump to definition in a single file. One test for jump to definition with multiple (maybe two) files. Some parts you don't want to test can be mocked.
  2. End to end tests for the client. Open a workspace containing some Modelica files or library and run jump to definition on one or two locations.

With these tests I might be able to see what I did wrong. Or maybe provide an example where you can demonstrate that your feature is indeed working.

And then this PR is very large. Ideally it is one pull request for one issue you are trying to solve. So for example the incremental parsing part and the file detection part are very nice. If you can split them in two separate PRs (and add tests) we can already merge them and you can concentrate on this large go to declaration feature.
If it's a lot of work to split this PR into three parts we can keep it this way.

Finally the end to end test is failing. No idea why. Looks like I broke that one on the main branch.

Comment on lines +46 to +47
readonly #parser: Parser;
readonly #libraries: ModelicaLibrary[];
Copy link
Member

Choose a reason for hiding this comment

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

I wasn't aware that ECMAScript private fields are a thing. Only shows that I'm not a JS/TS developer 😆

const maybeVariable = reference.kind === "variable" || reference.kind === undefined;

if (maybeClass) {
// logger.debug("findReferenceInDocument: Checking if this node is a class...");
Copy link
Member

@AnHeuermann AnHeuermann May 14, 2024

Choose a reason for hiding this comment

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

If the prints are not needed any more remove them.

}

public analyze(document: TextDocument): LSP.Diagnostic[] {
logger.debug('analyze:');
public async loadLibrary(uri: LSP.URI, isWorkspace: boolean): Promise<void> {
Copy link
Member

Choose a reason for hiding this comment

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

Add documentation. It's one of the top-level functions run at initialization of the parser.
And will it load libraries / files if I add them after some time while the language server is already running?

);
}

public async update(text: string, range?: LSP.Range): Promise<void> {
Copy link
Member

Choose a reason for hiding this comment

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

If I understand this correctly this is the incremental parsing part.
Is it possible to move this into a different PR to get one PR for one issue?

* See the full OSMC Public License conditions for more details.
*
*/

Copy link
Member

Choose a reason for hiding this comment

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

And this is probably the "handle-multiple-files" part. Can this become a separate PR as well?

// the node pathToFileURL uses ':' anyways. Manually fix this here.
// This is a bit hacky but we should ideally only be working with the URIs from LSP anyways.
return uri.slice(0, 5) + uri.slice(5).replace(":", "%3A");
}
Copy link
Member

Choose a reason for hiding this comment

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

I have

  "files.insertFinalNewline": true,
  "files.trimTrailingWhitespace": true,

in my VS Code settings.json, so I always add new lines at the end of documents. If you are also using VS Code this can be usefull.

* @param node The node to check. Must be a declaration.
* @returns The identifiers.
*/
export function getDeclaredIdentifiers(node: SyntaxNode): string[] {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe it's simpler to use queries at this point. See https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax

ehedbor and others added 2 commits May 21, 2024 14:41
Co-authored-by: PaddiM8 <hi@bakk.dev>
@ehedbor ehedbor marked this pull request as draft May 21, 2024 14:49
@ehedbor
Copy link
Contributor Author

ehedbor commented May 21, 2024

Edit: added links to draft pull requests

We have more time to work on fixing the PR now. We plan on splitting things up into multiple pull requests as you requested. This means we'll have to basically manually rewrite the git history but it was a mess anyways so no harm there. Currently planning on the following:

  1. Add Prettier/other config stuff (see Add prettier #23)
  2. Multi-file support (see Add support for multiple files #24)
  3. Incremental updates (see Add incremental parsing support #25)
  4. Goto declaration (WIP)

]
],
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
Copy link
Member

Choose a reason for hiding this comment

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

I think @AnHeuermann meant that you can add this to your VS code settings so the code you write is always formatted without trailing whitespaces. I don't think he meant to add these settings to the project.

Copy link
Member

Choose a reason for hiding this comment

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

Indeed 😆

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Surely it would be a good idea to add these to the project settings anyways, right? Doing that would help to ensure a more consistent style across contributors.

Copy link
Member

Choose a reason for hiding this comment

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

Not everyone uses VS Code, so I usually don't add the .vscode directory. For a VS Code extension this might be different.
Both is fine with me.

@ehedbor ehedbor closed this Jun 17, 2024
@PaddiM8
Copy link
Contributor

PaddiM8 commented Jun 17, 2024

Replaced by #26

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants