Skip to content

Commit 1a24c25

Browse files
ehedborPaddiM8AnHeuermann
authored
Goto declaration (#26)
* Implement goto declaration --------- Co-authored-by: PaddiM8 <hi@bakk.dev> Co-authored-by: AnHeuermann <38031952+AnHeuermann@users.noreply.github.com>
1 parent 7b3e890 commit 1a24c25

20 files changed

Lines changed: 1604 additions & 26 deletions

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ features:
1818

1919
![Outline](images/outline_demo.png)
2020

21+
- Goto declarations.
22+
23+
![Goto Declaration](images/goto_declaration_demo.png)
24+
2125
## Installation
2226

2327
### Via Marketplace
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* This file is part of OpenModelica.
3+
*
4+
* Copyright (c) 1998-2024, Open Source Modelica Consortium (OSMC),
5+
* c/o Linköpings universitet, Department of Computer and Information Science,
6+
* SE-58183 Linköping, Sweden.
7+
*
8+
* All rights reserved.
9+
*
10+
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11+
* THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12+
* ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13+
* RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14+
* VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15+
*
16+
* The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17+
* Public License (OSMC-PL) are obtained from OSMC, either from the above
18+
* address, from the URLs:
19+
* http://www.openmodelica.org or
20+
* https://github.com/OpenModelica/ or
21+
* http://www.ida.liu.se/projects/OpenModelica,
22+
* and in the OpenModelica distribution.
23+
*
24+
* GNU AGPL version 3 is obtained from:
25+
* https://www.gnu.org/licenses/licenses.html#GPL
26+
*
27+
* This program is distributed WITHOUT ANY WARRANTY; without
28+
* even the implied warranty of MERCHANTABILITY or FITNESS
29+
* FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30+
* IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31+
*
32+
* See the full OSMC Public License conditions for more details.
33+
*
34+
*/
35+
36+
import * as vscode from 'vscode';
37+
import * as assert from 'assert';
38+
import { getDocUri, activate } from './helper';
39+
40+
suite('Goto Declaration', () => {
41+
test('onDeclaration()', async () => {
42+
const docUri = getDocUri('MyLibrary.mo');
43+
await activate(docUri);
44+
45+
const position = new vscode.Position(4, 18);
46+
const actualLocations = await vscode.commands.executeCommand<vscode.LocationLink[]>(
47+
'vscode.executeDeclarationProvider',
48+
docUri,
49+
position,
50+
);
51+
52+
assert.strictEqual(actualLocations.length, 1);
53+
54+
const actualLocation = actualLocations[0];
55+
assert.strictEqual(actualLocation.targetUri.toString(), docUri.toString());
56+
assert.strictEqual(actualLocation.targetRange.start.line, 2);
57+
assert.strictEqual(actualLocation.targetRange.start.character, 4);
58+
assert.strictEqual(actualLocation.targetRange.end.line, 2);
59+
assert.strictEqual(actualLocation.targetRange.end.character, 37);
60+
});
61+
});

images/goto_declaration_demo.png

89.4 KB
Loading

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"language-server"
2020
],
2121
"homepage": "https://github.com/OpenModelica/modelica-language-server",
22-
"icon": "images/Modelica_Language_marging.jpg",
22+
"icon": "images/Modelica_Language_margin.jpg",
2323
"bugs": "https://github.com/OpenModelica/modelica-language-server/issues",
2424
"engines": {
2525
"vscode": "^1.75.0"
@@ -53,7 +53,7 @@
5353
"test:e2e": "run-script-os",
5454
"test:e2e:win32": "npm run test-compile && powershell -File ./scripts/e2e.ps1",
5555
"test:e2e:default": "npm run test-compile && sh ./scripts/e2e.sh",
56-
"test:server": "cd server && npx mocha -r ts-node/register src/test/**/*.test.ts src/project/test/**/*.test.ts src/util/test/**/*.test.ts",
56+
"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",
5757
"all": "npm run postinstall && npm run esbuild && npm run lint && npm run test:server && npm run test:e2e && npm run vscode:prepublish"
5858
},
5959
"devDependencies": {

server/src/analysis/reference.ts

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/*
2+
* This file is part of OpenModelica.
3+
*
4+
* Copyright (c) 1998-2024, Open Source Modelica Consortium (OSMC),
5+
* c/o Linköpings universitet, Department of Computer and Information Science,
6+
* SE-58183 Linköping, Sweden.
7+
*
8+
* All rights reserved.
9+
*
10+
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11+
* THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12+
* ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13+
* RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14+
* VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15+
*
16+
* The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17+
* Public License (OSMC-PL) are obtained from OSMC, either from the above
18+
* address, from the URLs:
19+
* http://www.openmodelica.org or
20+
* https://github.com/OpenModelica/ or
21+
* http://www.ida.liu.se/projects/OpenModelica,
22+
* and in the OpenModelica distribution.
23+
*
24+
* GNU AGPL version 3 is obtained from:
25+
* https://www.gnu.org/licenses/licenses.html#GPL
26+
*
27+
* This program is distributed WITHOUT ANY WARRANTY; without
28+
* even the implied warranty of MERCHANTABILITY or FITNESS
29+
* FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30+
* IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31+
*
32+
* See the full OSMC Public License conditions for more details.
33+
*
34+
*/
35+
36+
import { ModelicaDocument } from '../project/document';
37+
import Parser from 'web-tree-sitter';
38+
39+
export type ReferenceKind = 'class' | 'variable';
40+
41+
export abstract class BaseUnresolvedReference {
42+
/**
43+
* The path to the symbol reference.
44+
*/
45+
public readonly symbols: string[];
46+
47+
public readonly kind: ReferenceKind | undefined;
48+
49+
public constructor(symbols: string[], kind?: ReferenceKind) {
50+
if (symbols.length === 0) {
51+
throw new Error('Symbols length must be greater tham 0');
52+
}
53+
54+
this.symbols = symbols;
55+
this.kind = kind;
56+
}
57+
58+
public abstract isAbsolute(): this is UnresolvedAbsoluteReference;
59+
60+
public abstract equals(other: unknown): boolean;
61+
}
62+
63+
export class UnresolvedRelativeReference extends BaseUnresolvedReference {
64+
/**
65+
* The document that contains the `node`.
66+
*/
67+
public readonly document: ModelicaDocument;
68+
69+
/**
70+
* A `SyntaxNode` in which the symbol is in scope.
71+
*/
72+
public readonly node: Parser.SyntaxNode;
73+
74+
public constructor(
75+
document: ModelicaDocument,
76+
node: Parser.SyntaxNode,
77+
symbols: string[],
78+
kind?: ReferenceKind,
79+
) {
80+
super(symbols, kind);
81+
this.document = document;
82+
this.node = node;
83+
}
84+
85+
public isAbsolute(): this is UnresolvedAbsoluteReference {
86+
return false;
87+
}
88+
89+
public equals(other: unknown): boolean {
90+
if (!(other instanceof UnresolvedRelativeReference)) {
91+
return false;
92+
}
93+
94+
return (
95+
this.document.uri === other.document.uri &&
96+
this.node.equals(other.node) &&
97+
this.symbols.length === other.symbols.length &&
98+
this.symbols.every((s, i) => s === other.symbols[i]) &&
99+
this.kind === other.kind
100+
);
101+
}
102+
103+
public toString(): string {
104+
const start = this.node.startPosition;
105+
return (
106+
`UnresolvedReference { ` +
107+
`symbols: ${this.symbols.join('.')}, ` +
108+
`kind: ${this.kind}, ` +
109+
`position: ${start.row + 1}:${start.column + 1}, ` +
110+
`document: "${this.document.path}" ` +
111+
`}`
112+
);
113+
}
114+
}
115+
116+
export class UnresolvedAbsoluteReference extends BaseUnresolvedReference {
117+
public constructor(symbols: string[], kind?: ReferenceKind) {
118+
super(symbols, kind);
119+
}
120+
121+
public isAbsolute(): this is UnresolvedAbsoluteReference {
122+
return true;
123+
}
124+
125+
public equals(other: unknown): boolean {
126+
if (!(other instanceof UnresolvedAbsoluteReference)) {
127+
return false;
128+
}
129+
130+
return (
131+
this.symbols.length === other.symbols.length &&
132+
this.symbols.every((s, i) => s === other.symbols[i]) &&
133+
this.kind === other.kind
134+
);
135+
}
136+
137+
public toString(): string {
138+
return (
139+
`UnresolvedReference { ` +
140+
`symbols: <global>.${this.symbols.join('.')}, ` +
141+
`kind: ${this.kind} ` +
142+
`}`
143+
);
144+
}
145+
}
146+
147+
/**
148+
* A possibly-valid reference to a symbol that must be resolved before use.
149+
*/
150+
export type UnresolvedReference = UnresolvedRelativeReference | UnresolvedAbsoluteReference;
151+
152+
/**
153+
* A valid, absolute reference to a symbol.
154+
*/
155+
export class ResolvedReference {
156+
/**
157+
* The document that contains the `node`.
158+
*/
159+
readonly document: ModelicaDocument;
160+
161+
/**
162+
* The node that declares/defines this symbol.
163+
*/
164+
readonly node: Parser.SyntaxNode;
165+
166+
/**
167+
* The full, absolute path to the symbol.
168+
*/
169+
readonly symbols: string[];
170+
171+
readonly kind: ReferenceKind;
172+
173+
public constructor(
174+
document: ModelicaDocument,
175+
node: Parser.SyntaxNode,
176+
symbols: string[],
177+
kind: ReferenceKind,
178+
) {
179+
if (symbols.length === 0) {
180+
throw new Error('Symbols length must be greater than 0.');
181+
}
182+
183+
this.document = document;
184+
this.node = node;
185+
this.symbols = symbols;
186+
this.kind = kind;
187+
}
188+
189+
public equals(other: unknown): boolean {
190+
if (!(other instanceof ResolvedReference)) {
191+
return false;
192+
}
193+
194+
return (
195+
this.document.uri === other.document.uri &&
196+
this.node.equals(other.node) &&
197+
this.symbols.length === other.symbols.length &&
198+
this.symbols.every((s, i) => s === other.symbols[i]) &&
199+
this.kind === other.kind
200+
);
201+
}
202+
203+
public toString(): string {
204+
return `Reference { symbols: <global>.${this.symbols.join('.')}, kind: ${this.kind} }`;
205+
}
206+
}

0 commit comments

Comments
 (0)