|
19 | 19 | // along with Fusion Transpiler. If not, see http://www.gnu.org/licenses/
|
20 | 20 |
|
21 | 21 | import * as vscode from "vscode";
|
22 |
| -import { FuParser, FuProgram, FuSystem, FuSema, FuSemaHost, FuSymbolReferenceVisitor, FuStatement, FuSymbol, FuContainerType, FuEnum, FuMember, FuField, FuMethod } from "./fucheck.js"; |
| 22 | +import { FuParser, FuProgram, FuSystem, FuSema, FuSemaHost, FuSymbolReferenceVisitor, FuStatement, FuSymbol, FuContainerType, FuEnum, FuClass, FuMember, FuField, FuMethod } from "./fucheck.js"; |
23 | 23 |
|
24 | 24 | class VsCodeHost extends FuSemaHost
|
25 | 25 | {
|
@@ -73,29 +73,6 @@ class VsCodeHost extends FuSemaHost
|
73 | 73 | sema.setHost(this);
|
74 | 74 | sema.process();
|
75 | 75 | }
|
76 |
| - |
77 |
| - async findSymbol(document: vscode.TextDocument, position: vscode.Position): Promise<FuSymbol | null> |
78 |
| - { |
79 |
| - const parser = this.createParser(); |
80 |
| - const filename = document.uri.toString(); |
81 |
| - parser.findName(filename, position.line, position.character); |
82 |
| - const files = await vscode.workspace.findFiles("*.fu"); |
83 |
| - if (files.some(uri => uri.toString() == filename)) |
84 |
| - await this.parseFolder(files, parser); |
85 |
| - else |
86 |
| - this.parseDocument(document, parser); |
87 |
| - this.doSema(); |
88 |
| - return parser.getFoundDefinition(); |
89 |
| - } |
90 |
| - |
91 |
| - toLocation(statement: FuStatement): vscode.Location | null |
92 |
| - { |
93 |
| - if (statement.loc <= 0) |
94 |
| - return null; |
95 |
| - const line = this.program.getLine(statement.loc); |
96 |
| - const file = this.program.getSourceFile(line); |
97 |
| - return new vscode.Location(vscode.Uri.parse(file.filename), new vscode.Position(line - file.line, statement.loc - this.program.lineLocs[line])); |
98 |
| - } |
99 | 76 | }
|
100 | 77 |
|
101 | 78 | class VsCodeDiagnostics extends VsCodeHost
|
@@ -159,39 +136,87 @@ class VsCodeDiagnostics extends VsCodeHost
|
159 | 136 | }
|
160 | 137 | }
|
161 | 138 |
|
162 |
| -class VsCodeDefinitionProvider extends VsCodeHost |
163 |
| -{ |
164 |
| - async findDefinition(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.Location | null> |
165 |
| - { |
166 |
| - const symbol = await this.findSymbol(document, position); |
167 |
| - return symbol == null ? null : this.toLocation(symbol); |
168 |
| - } |
169 |
| -} |
170 |
| - |
171 | 139 | class VsCodeReferenceCollector extends FuSymbolReferenceVisitor
|
172 | 140 | {
|
173 |
| - host: VsCodeHost; |
| 141 | + provider: VsCodeGotoProvider; |
174 | 142 | result: vscode.Location[] = [];
|
175 | 143 |
|
176 |
| - constructor(host: VsCodeHost) |
| 144 | + constructor(provider: VsCodeGotoProvider) |
177 | 145 | {
|
178 | 146 | super();
|
179 |
| - this.host = host; |
| 147 | + this.provider = provider; |
180 | 148 | }
|
181 | 149 |
|
182 | 150 | visitFound(reference: FuStatement): void
|
183 | 151 | {
|
184 |
| - const location = this.host.toLocation(reference); |
185 |
| - if (location != null) |
186 |
| - this.result.push(location); |
| 152 | + this.provider.pushLocation(this.result, reference); |
187 | 153 | }
|
188 | 154 | }
|
189 | 155 |
|
190 |
| -class VsCodeReferenceProvider extends VsCodeHost |
| 156 | +class VsCodeGotoProvider extends VsCodeHost |
191 | 157 | {
|
| 158 | + async #findSymbol(document: vscode.TextDocument, position: vscode.Position): Promise<FuSymbol | null> |
| 159 | + { |
| 160 | + const parser = this.createParser(); |
| 161 | + const filename = document.uri.toString(); |
| 162 | + parser.findName(filename, position.line, position.character); |
| 163 | + const files = await vscode.workspace.findFiles("*.fu"); |
| 164 | + if (files.some(uri => uri.toString() == filename)) |
| 165 | + await this.parseFolder(files, parser); |
| 166 | + else |
| 167 | + this.parseDocument(document, parser); |
| 168 | + this.doSema(); |
| 169 | + return parser.getFoundDefinition(); |
| 170 | + } |
| 171 | + |
| 172 | + #toLocation(statement: FuStatement): vscode.Location | null |
| 173 | + { |
| 174 | + if (statement.loc <= 0) |
| 175 | + return null; |
| 176 | + const line = this.program.getLine(statement.loc); |
| 177 | + const file = this.program.getSourceFile(line); |
| 178 | + return new vscode.Location(vscode.Uri.parse(file.filename), new vscode.Position(line - file.line, statement.loc - this.program.lineLocs[line])); |
| 179 | + } |
| 180 | + |
| 181 | + pushLocation(result: vscode.Location[], statement: FuStatement): void |
| 182 | + { |
| 183 | + const location = this.#toLocation(statement); |
| 184 | + if (location != null) |
| 185 | + result.push(location); |
| 186 | + } |
| 187 | + |
| 188 | + async findDefinition(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.Location | null> |
| 189 | + { |
| 190 | + const symbol = await this.#findSymbol(document, position); |
| 191 | + return symbol == null ? null : this.#toLocation(symbol); |
| 192 | + } |
| 193 | + |
| 194 | + async findImplementations(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.Location[]> |
| 195 | + { |
| 196 | + const symbol = await this.#findSymbol(document, position); |
| 197 | + const result: vscode.Location[] = []; |
| 198 | + if (symbol != null) { |
| 199 | + if (symbol instanceof FuClass) { |
| 200 | + for (const subclass of this.program.classes) { |
| 201 | + if (symbol.isSameOrBaseOf(subclass)) |
| 202 | + this.pushLocation(result, subclass); |
| 203 | + } |
| 204 | + } |
| 205 | + else if (symbol instanceof FuMethod && symbol.isAbstractVirtualOrOverride()) { |
| 206 | + for (const subclass of this.program.classes) { |
| 207 | + if (symbol.parent.isSameOrBaseOf(subclass) && subclass.contains(symbol)) |
| 208 | + this.pushLocation(result, subclass.tryLookup(symbol.name, false)); |
| 209 | + } |
| 210 | + } |
| 211 | + else |
| 212 | + this.pushLocation(result, symbol); |
| 213 | + } |
| 214 | + return result; |
| 215 | + } |
| 216 | + |
192 | 217 | async findReferences(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.Location[]>
|
193 | 218 | {
|
194 |
| - const symbol = await this.findSymbol(document, position); |
| 219 | + const symbol = await this.#findSymbol(document, position); |
195 | 220 | if (symbol == null)
|
196 | 221 | return [];
|
197 | 222 | const collector = new VsCodeReferenceCollector(this);
|
@@ -250,12 +275,17 @@ export function activate(context: vscode.ExtensionContext): void
|
250 | 275 | context.subscriptions.push(vscode.workspace.onDidCloseTextDocument(document => diagnostics.delete(document)));
|
251 | 276 | vscode.languages.registerDefinitionProvider("fusion", {
|
252 | 277 | provideDefinition(document, position, token) {
|
253 |
| - return new VsCodeDefinitionProvider().findDefinition(document, position); |
| 278 | + return new VsCodeGotoProvider().findDefinition(document, position); |
| 279 | + } |
| 280 | + }); |
| 281 | + vscode.languages.registerImplementationProvider("fusion", { |
| 282 | + provideImplementation(document, position, token) { |
| 283 | + return new VsCodeGotoProvider().findImplementations(document, position); |
254 | 284 | }
|
255 | 285 | });
|
256 | 286 | vscode.languages.registerReferenceProvider("fusion", {
|
257 | 287 | provideReferences(document, position, context, token) {
|
258 |
| - return new VsCodeReferenceProvider().findReferences(document, position); |
| 288 | + return new VsCodeGotoProvider().findReferences(document, position); |
259 | 289 | }
|
260 | 290 | });
|
261 | 291 | vscode.languages.registerDocumentSymbolProvider("fusion", {
|
|
0 commit comments