Skip to content

Commit

Permalink
Goto declaration (#26)
Browse files Browse the repository at this point in the history
* Implement goto declaration

---------

Co-authored-by: PaddiM8 <[email protected]>
Co-authored-by: AnHeuermann <[email protected]>
  • Loading branch information
3 people authored Jun 27, 2024
1 parent 7b3e890 commit 1a24c25
Show file tree
Hide file tree
Showing 20 changed files with 1,604 additions and 26 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ features:

![Outline](images/outline_demo.png)

- Goto declarations.

![Goto Declaration](images/goto_declaration_demo.png)

## Installation

### Via Marketplace
Expand Down
61 changes: 61 additions & 0 deletions client/src/test/gotoDeclaration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* This file is part of OpenModelica.
*
* Copyright (c) 1998-2024, Open Source Modelica Consortium (OSMC),
* c/o Linköpings universitet, Department of Computer and Information Science,
* SE-58183 Linköping, Sweden.
*
* All rights reserved.
*
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
* THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
* ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
* RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
* VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
*
* The OpenModelica software and the OSMC (Open Source Modelica Consortium)
* Public License (OSMC-PL) are obtained from OSMC, either from the above
* address, from the URLs:
* http://www.openmodelica.org or
* https://github.com/OpenModelica/ or
* http://www.ida.liu.se/projects/OpenModelica,
* and in the OpenModelica distribution.
*
* GNU AGPL version 3 is obtained from:
* https://www.gnu.org/licenses/licenses.html#GPL
*
* This program is distributed WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
* IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
*
* See the full OSMC Public License conditions for more details.
*
*/

import * as vscode from 'vscode';
import * as assert from 'assert';
import { getDocUri, activate } from './helper';

suite('Goto Declaration', () => {
test('onDeclaration()', async () => {
const docUri = getDocUri('MyLibrary.mo');
await activate(docUri);

const position = new vscode.Position(4, 18);
const actualLocations = await vscode.commands.executeCommand<vscode.LocationLink[]>(
'vscode.executeDeclarationProvider',
docUri,
position,
);

assert.strictEqual(actualLocations.length, 1);

const actualLocation = actualLocations[0];
assert.strictEqual(actualLocation.targetUri.toString(), docUri.toString());
assert.strictEqual(actualLocation.targetRange.start.line, 2);
assert.strictEqual(actualLocation.targetRange.start.character, 4);
assert.strictEqual(actualLocation.targetRange.end.line, 2);
assert.strictEqual(actualLocation.targetRange.end.character, 37);
});
});
File renamed without changes
Binary file added images/goto_declaration_demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"language-server"
],
"homepage": "https://github.com/OpenModelica/modelica-language-server",
"icon": "images/Modelica_Language_marging.jpg",
"icon": "images/Modelica_Language_margin.jpg",
"bugs": "https://github.com/OpenModelica/modelica-language-server/issues",
"engines": {
"vscode": "^1.75.0"
Expand Down Expand Up @@ -53,7 +53,7 @@
"test:e2e": "run-script-os",
"test:e2e:win32": "npm run test-compile && powershell -File ./scripts/e2e.ps1",
"test:e2e:default": "npm run test-compile && sh ./scripts/e2e.sh",
"test:server": "cd server && npx mocha -r ts-node/register src/test/**/*.test.ts src/project/test/**/*.test.ts src/util/test/**/*.test.ts",
"test:server": "cd server && npx mocha -r ts-node/register src/test/**/*.test.ts src/project/test/**/*.test.ts src/util/test/**/*.test.ts src/analysis/test/**/*.test.ts",
"all": "npm run postinstall && npm run esbuild && npm run lint && npm run test:server && npm run test:e2e && npm run vscode:prepublish"
},
"devDependencies": {
Expand Down
206 changes: 206 additions & 0 deletions server/src/analysis/reference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* This file is part of OpenModelica.
*
* Copyright (c) 1998-2024, Open Source Modelica Consortium (OSMC),
* c/o Linköpings universitet, Department of Computer and Information Science,
* SE-58183 Linköping, Sweden.
*
* All rights reserved.
*
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
* THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
* ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
* RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
* VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
*
* The OpenModelica software and the OSMC (Open Source Modelica Consortium)
* Public License (OSMC-PL) are obtained from OSMC, either from the above
* address, from the URLs:
* http://www.openmodelica.org or
* https://github.com/OpenModelica/ or
* http://www.ida.liu.se/projects/OpenModelica,
* and in the OpenModelica distribution.
*
* GNU AGPL version 3 is obtained from:
* https://www.gnu.org/licenses/licenses.html#GPL
*
* This program is distributed WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
* IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
*
* See the full OSMC Public License conditions for more details.
*
*/

import { ModelicaDocument } from '../project/document';
import Parser from 'web-tree-sitter';

export type ReferenceKind = 'class' | 'variable';

export abstract class BaseUnresolvedReference {
/**
* The path to the symbol reference.
*/
public readonly symbols: string[];

public readonly kind: ReferenceKind | undefined;

public constructor(symbols: string[], kind?: ReferenceKind) {
if (symbols.length === 0) {
throw new Error('Symbols length must be greater tham 0');
}

this.symbols = symbols;
this.kind = kind;
}

public abstract isAbsolute(): this is UnresolvedAbsoluteReference;

public abstract equals(other: unknown): boolean;
}

export class UnresolvedRelativeReference extends BaseUnresolvedReference {
/**
* The document that contains the `node`.
*/
public readonly document: ModelicaDocument;

/**
* A `SyntaxNode` in which the symbol is in scope.
*/
public readonly node: Parser.SyntaxNode;

public constructor(
document: ModelicaDocument,
node: Parser.SyntaxNode,
symbols: string[],
kind?: ReferenceKind,
) {
super(symbols, kind);
this.document = document;
this.node = node;
}

public isAbsolute(): this is UnresolvedAbsoluteReference {
return false;
}

public equals(other: unknown): boolean {
if (!(other instanceof UnresolvedRelativeReference)) {
return false;
}

return (
this.document.uri === other.document.uri &&
this.node.equals(other.node) &&
this.symbols.length === other.symbols.length &&
this.symbols.every((s, i) => s === other.symbols[i]) &&
this.kind === other.kind
);
}

public toString(): string {
const start = this.node.startPosition;
return (
`UnresolvedReference { ` +
`symbols: ${this.symbols.join('.')}, ` +
`kind: ${this.kind}, ` +
`position: ${start.row + 1}:${start.column + 1}, ` +
`document: "${this.document.path}" ` +
`}`
);
}
}

export class UnresolvedAbsoluteReference extends BaseUnresolvedReference {
public constructor(symbols: string[], kind?: ReferenceKind) {
super(symbols, kind);
}

public isAbsolute(): this is UnresolvedAbsoluteReference {
return true;
}

public equals(other: unknown): boolean {
if (!(other instanceof UnresolvedAbsoluteReference)) {
return false;
}

return (
this.symbols.length === other.symbols.length &&
this.symbols.every((s, i) => s === other.symbols[i]) &&
this.kind === other.kind
);
}

public toString(): string {
return (
`UnresolvedReference { ` +
`symbols: <global>.${this.symbols.join('.')}, ` +
`kind: ${this.kind} ` +
`}`
);
}
}

/**
* A possibly-valid reference to a symbol that must be resolved before use.
*/
export type UnresolvedReference = UnresolvedRelativeReference | UnresolvedAbsoluteReference;

/**
* A valid, absolute reference to a symbol.
*/
export class ResolvedReference {
/**
* The document that contains the `node`.
*/
readonly document: ModelicaDocument;

/**
* The node that declares/defines this symbol.
*/
readonly node: Parser.SyntaxNode;

/**
* The full, absolute path to the symbol.
*/
readonly symbols: string[];

readonly kind: ReferenceKind;

public constructor(
document: ModelicaDocument,
node: Parser.SyntaxNode,
symbols: string[],
kind: ReferenceKind,
) {
if (symbols.length === 0) {
throw new Error('Symbols length must be greater than 0.');
}

this.document = document;
this.node = node;
this.symbols = symbols;
this.kind = kind;
}

public equals(other: unknown): boolean {
if (!(other instanceof ResolvedReference)) {
return false;
}

return (
this.document.uri === other.document.uri &&
this.node.equals(other.node) &&
this.symbols.length === other.symbols.length &&
this.symbols.every((s, i) => s === other.symbols[i]) &&
this.kind === other.kind
);
}

public toString(): string {
return `Reference { symbols: <global>.${this.symbols.join('.')}, kind: ${this.kind} }`;
}
}
Loading

0 comments on commit 1a24c25

Please sign in to comment.