Compare commits

...
22 Commits
Author SHA1 Message Date
dholle ab5a6b06b1 Version bump 2026-07-16 14:07:35 +02:00
dholle ce2f9aae86 Fix duplicate insert points for Methods 2026-07-02 16:35:12 +02:00
dholle 1cc679afb4 Improvements 2026-06-25 15:59:09 +02:00
dholle 40e5549062 Correctly strip off package names 2026-06-24 14:49:11 +02:00
dholle 4e4eb45842 Update plugin 2026-06-24 14:23:50 +02:00
dholle c0a30af6ef Fix old api usage 2026-04-29 10:31:54 +02:00
dholle 68843eac17 delimiter, not sep 2025-11-26 18:15:32 +01:00
dholle 2c4ff6e237 Update version 2025-11-26 18:14:27 +01:00
dholle c9d878cf30 Fix path delimiter for windows 2025-11-26 18:12:53 +01:00
dholle 75943a8d95 Resolve file paths in emacs client 2025-11-12 13:24:26 +01:00
dholle 53e6d94180 README 2025-10-29 13:34:53 +01:00
dholle d6db2d70e7 Move file 2025-10-22 11:41:30 +02:00
dholle 3bc2340a0c Add emacs mode and fix some incompatibilities 2025-10-22 11:40:32 +02:00
dholle b691d6e0e3 Resolve path 2025-10-09 17:48:00 +02:00
dholle 6917c43c33 Specify compiler path in extension settings 2025-10-02 18:10:50 +02:00
Vic Nightfall 1a0596ca71 Version bump 2025-09-28 14:20:59 +02:00
RubenKraft a9bbe834cc Update README.md 2025-09-24 14:43:07 +00:00
Ruben 4fbf9133a5 fix: bump version 2025-09-23 18:38:31 +02:00
Ruben 972d9014ba fix: bump version 2025-09-23 18:38:01 +02:00
Ruben 4f4404d366 fix: cleanup and fixes 2025-09-23 18:37:37 +02:00
Ruben 2dfbef6d7f fix: except VerifyError in Catch Clause 2025-09-23 18:26:58 +02:00
Ruben 7e6e968b0f feat: do not show 100 times the insert 2025-09-22 18:22:05 +02:00
24 changed files with 3176 additions and 990 deletions
+2571 -632
View File
File diff suppressed because it is too large Load Diff
+14 -1
View File
@@ -3,7 +3,7 @@
"name": "java-tx-language-extension", "name": "java-tx-language-extension",
"displayName": "Java-TX Language Extension", "displayName": "Java-TX Language Extension",
"description": "The Language Extension for Java-TX with Typehints and Syntax Checks", "description": "The Language Extension for Java-TX with Typehints and Syntax Checks",
"version": "0.0.11", "version": "0.0.22",
"engines": { "engines": {
"vscode": "^1.94.0" "vscode": "^1.94.0"
}, },
@@ -20,6 +20,18 @@
"command": "tx.restartLanguageServer", "command": "tx.restartLanguageServer",
"title": "TX: Restart Language Server" "title": "TX: Restart Language Server"
} }
],
"configuration": [
{
"title": "JavaTX Language Server Plugin",
"properties": {
"tx.compilerLocation": {
"type": "string",
"format": "file",
"description": "JavaTX Compiler Location"
}
}
}
] ]
}, },
"scripts": { "scripts": {
@@ -42,6 +54,7 @@
"typescript": "^5.6.2" "typescript": "^5.6.2"
}, },
"dependencies": { "dependencies": {
"@vscode/vsce": "^3.6.1",
"vscode-languageclient": "^9.0.1" "vscode-languageclient": "^9.0.1"
} }
} }
+58 -21
View File
@@ -1,28 +1,67 @@
import path from 'path';
import os from "os";
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { import {
Executable,
LanguageClient, LanguageClient,
LanguageClientOptions, LanguageClientOptions,
ServerOptions ServerOptions
} from 'vscode-languageclient/node'; } from 'vscode-languageclient/node';
let homeDirectory: string;
let currentUser: string;
function untildify(pathWithTilde: string) {
if (homeDirectory === undefined) {
homeDirectory = os.homedir();
}
// Handle regular ~ expansion (current user)
if (homeDirectory && /^~(?=$|\/|\\)/.test(pathWithTilde)) {
return pathWithTilde.replace(/^~/, homeDirectory);
}
// Handle ~username expansion (only for current user)
const userMatch = pathWithTilde.match(/^~([^/\\]+)(.*)/);
if (userMatch) {
if (currentUser === undefined) {
currentUser = os.userInfo().username;
}
if (currentUser) {
const username = userMatch[1];
const rest = userMatch[2];
if (username === currentUser) {
return homeDirectory + rest;
}
}
}
// Return unchanged if no expansion occurred
return pathWithTilde;
}
let client: LanguageClient | undefined; // <— global, damit wir neu starten können let client: LanguageClient | undefined; // <— global, damit wir neu starten können
function createClient(context: vscode.ExtensionContext): LanguageClient { function createClient(context: vscode.ExtensionContext): LanguageClient | null {
const workspaceFolder = context.extensionPath; const workspaceFolder = context.extensionPath;
const config = vscode.workspace.getConfiguration("tx");
let compiler = config.get<string>("compilerLocation");
if (!compiler || compiler.trim() === "") {
vscode.window.showErrorMessage("Bitte konfiguriere den Pfad des Java-TX Compilers in den Einstellungen!");
return null;
}
compiler = path.resolve(untildify(compiler));
const cmd: Executable = {
command: 'java',
args: ['-Xss10m', '-cp', `${compiler}${path.delimiter}${workspaceFolder}/JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar`, "de.dhbw.JavaTXLanguageServerLauncher"],
};
const serverOptions: ServerOptions = { const serverOptions: ServerOptions = {
run: { run: cmd,
command: 'java', debug: cmd
args: ['-Xss10m', '-jar', workspaceFolder + "/JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar"],
},
debug: {
command: 'java',
args: [
'-Xss10m',
'-jar',
workspaceFolder + '/JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar',
],
}
}; };
const clientOptions: LanguageClientOptions = { const clientOptions: LanguageClientOptions = {
@@ -42,7 +81,9 @@ function createClient(context: vscode.ExtensionContext): LanguageClient {
} }
export async function activate(context: vscode.ExtensionContext) { export async function activate(context: vscode.ExtensionContext) {
client = createClient(context); const c = createClient(context);
if (!c) return;
client = c;
client.start() client.start()
.then(() => console.log("Language Client erfolgreich gestartet")) .then(() => console.log("Language Client erfolgreich gestartet"))
@@ -50,12 +91,6 @@ export async function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "tx" is now active!'); console.log('Congratulations, your extension "tx" is now active!');
// Beispiel-Command aus deinem Code bleibt
const hello = vscode.commands.registerCommand('lspclient.helloWorld', () => {
vscode.window.showInformationMessage('Hello World from TX!');
});
context.subscriptions.push(hello);
// *** NEU: Restart-Command *** // *** NEU: Restart-Command ***
const restart = vscode.commands.registerCommand('tx.restartLanguageServer', async () => { const restart = vscode.commands.registerCommand('tx.restartLanguageServer', async () => {
if (!client) { if (!client) {
@@ -68,7 +103,9 @@ export async function activate(context: vscode.ExtensionContext) {
} catch (e) { } catch (e) {
console.error('Fehler beim Stoppen des Language Clients:', e); console.error('Fehler beim Stoppen des Language Clients:', e);
} }
client = createClient(context); // komplett neu erzeugen const c = createClient(context); // komplett neu erzeugen
if (!c) return;
client = c;
try { try {
await client.start(); await client.start();
vscode.window.showInformationMessage('Java-TX Language Server neu gestartet.'); vscode.window.showInformationMessage('Java-TX Language Server neu gestartet.');
+11
View File
@@ -0,0 +1,11 @@
## Install emacs plugin:
Edit your .emacs file and add the following:
```
(use-package javatx-mode
:custom
(javatx-compiler-path "$PATH_TO_COMPILER$")
(javatx-lsp-server-path "$PATH_TO_LSP$")
:load-path "~/.emacs.d/lisp")
```
+84
View File
@@ -0,0 +1,84 @@
;;; javatx-mode.el --- Major mode for .jav files -*- lexical-binding: t; -*-
(defvar javatx-mode-hook nil
"Hook called when entering `javatx-mode`.")
;; Define the mode
(define-derived-mode javatx-mode java-mode "Javatx"
"Major mode for editing `.jav` files.")
;; Automatically use javatx-mode for .jav files
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.jav\\'" . javatx-mode))
(provide 'javatx-mode)
;;; javatx-mode.el ends here
;; Initialize package sources
(require 'package)
(setq package-archives
'(("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")))
(package-initialize)
;; Refresh package contents if needed
(unless package-archive-contents
(package-refresh-contents))
;; Install use-package if not installed
(unless (package-installed-p 'use-package)
(package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t) ;; automatically install packages if missing
(use-package lsp-mode
:hook (prog-mode . lsp)
:commands lsp
:config
(setq lsp-prefer-flymake nil)) ;; use flycheck instead of flymake
(use-package lsp-ui
:commands lsp-ui-mode
:hook (lsp-mode . lsp-ui-mode)
:config
(setq lsp-ui-sideline-show-hover t
lsp-ui-sideline-show-code-actions t
lsp-ui-sideline-show-diagnostics t))
(defcustom javatx-compiler-path nil
"Path to the JavaTX Compiler jar."
:type 'string
:group 'javatx)
(defcustom javatx-lsp-server-path nil
"Path to the JavaTX Language Server jar."
:type 'string
:group 'javatx)
;;register javatx-mode lsp
(with-eval-after-load 'lsp-mode
(message "Compiler path: %s" javatx-compiler-path)
(message "Server path: %s" javatx-lsp-server-path)
(add-to-list 'lsp-language-id-configuration '(javatx-mode . "Java-TX"))
(lsp-register-client
(make-lsp-client
:new-connection (lsp-stdio-connection (lambda () `("java" "-cp" ,(format "%s:%s" (expand-file-name javatx-compiler-path) (expand-file-name javatx-lsp-server-path)) "de.dhbw.JavaTXLanguageServerLauncher")))
:major-modes '(javatx-mode)
:server-id 'javatx-lsp-proxy)))
(add-hook 'javatx-mode-hook #'lsp) ;; start LSP automatically for .jav files
;; Automatically enable inlay hints for javatx-mode
(add-hook 'javatx-mode-hook
(lambda ()
;; Replace 'lsp-inlay-hints-mode' with whatever inlay hints function you use
(when (fboundp 'lsp-inlay-hints-mode)
(lsp-inlay-hints-mode 1))))
(setq lsp-log-io t) ;; enable logging of LSP messages
(with-eval-after-load 'lsp-mode
(define-key lsp-mode-map (kbd "C-c a") 'lsp-execute-code-action))
+29 -45
View File
@@ -14,61 +14,22 @@
<version>4.11</version> <version>4.11</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.antlr/antlr4 -->
<dependency> <dependency>
<groupId>org.antlr</groupId> <groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId> <artifactId>antlr4</artifactId>
<version>4.11.1</version> <version>4.13.2</version>
</dependency> </dependency>
<dependency>
<groupId>io.github.java-diff-utils</groupId>
<artifactId>java-diff-utils</artifactId>
<version>4.12</version>
</dependency>
<dependency> <dependency>
<groupId>log4j</groupId> <groupId>log4j</groupId>
<artifactId>log4j</artifactId> <artifactId>log4j</artifactId>
<version>1.2.17</version> <version>1.2.17</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId> <artifactId>junit-jupiter</artifactId>
<version>5.10.0</version> <version>5.14.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
<version>4.8.172</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.0-jre</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.5</version>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.lsp4j</groupId> <groupId>org.eclipse.lsp4j</groupId>
<artifactId>org.eclipse.lsp4j</artifactId> <artifactId>org.eclipse.lsp4j</artifactId>
@@ -78,6 +39,7 @@
<groupId>de.dhbwstuttgart</groupId> <groupId>de.dhbwstuttgart</groupId>
<artifactId>JavaTXcompiler</artifactId> <artifactId>JavaTXcompiler</artifactId>
<version>0.1</version> <version>0.1</version>
<scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<properties> <properties>
@@ -110,7 +72,6 @@
<release>21</release> <release>21</release>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
@@ -134,6 +95,29 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>copy-fat-jar</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<mkdir dir="${project.basedir}/../Clients/VisualStudioCode"/>
<copy
file="${project.build.directory}/${project.build.finalName}-jar-with-dependencies.jar"
todir="${project.basedir}/../Clients/VisualStudioCode"
overwrite="true"/>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>
@@ -1,7 +1,5 @@
package de.dhbw; package de.dhbw;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.eclipse.lsp4j.*; import org.eclipse.lsp4j.*;
import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.services.TextDocumentService; import org.eclipse.lsp4j.services.TextDocumentService;
@@ -16,7 +14,7 @@ import java.util.concurrent.CompletableFuture;
* *
* */ * */
public class JavaTXLanguageServer implements LanguageServer { public class JavaTXLanguageServer implements LanguageServer {
private static final Logger logger = LogManager.getLogger(JavaTXLanguageServer.class); public static ClientCapabilities capabilities;
private LanguageClient client; private LanguageClient client;
public void connect(LanguageClient client) { public void connect(LanguageClient client) {
@@ -24,7 +22,7 @@ public class JavaTXLanguageServer implements LanguageServer {
textDocumentService.setClient(client); textDocumentService.setClient(client);
} }
private final JavaTXTextDocumentService textDocumentService = new JavaTXTextDocumentService(); public final JavaTXTextDocumentService textDocumentService = new JavaTXTextDocumentService();
private final JavaTXWorkspaceService workspaceService = new JavaTXWorkspaceService(); private final JavaTXWorkspaceService workspaceService = new JavaTXWorkspaceService();
@Override @Override
@@ -48,6 +46,7 @@ public class JavaTXLanguageServer implements LanguageServer {
if(params.getWorkspaceFolders() != null && !params.getWorkspaceFolders().isEmpty()) { if(params.getWorkspaceFolders() != null && !params.getWorkspaceFolders().isEmpty()) {
textDocumentService.setFileRoot(params.getWorkspaceFolders()); textDocumentService.setFileRoot(params.getWorkspaceFolders());
} }
JavaTXLanguageServer.capabilities = params.getCapabilities();
return CompletableFuture.supplyAsync(() -> new InitializeResult(capabilities)); return CompletableFuture.supplyAsync(() -> new InitializeResult(capabilities));
} }
@@ -13,11 +13,11 @@ import org.eclipse.lsp4j.services.LanguageClient;
* */ * */
public class JavaTXLanguageServerLauncher { public class JavaTXLanguageServerLauncher {
private static final Logger logger = LogManager.getLogger(JavaTXLanguageServerLauncher.class); public static JavaTXLanguageServer server;
public static void main(String[] args) { public static void main(String[] args) {
try { try {
JavaTXLanguageServer server = new JavaTXLanguageServer(); server = new JavaTXLanguageServer();
var launcher = LSPLauncher.createServerLauncher(server, System.in, System.out); var launcher = LSPLauncher.createServerLauncher(server, System.in, System.out);
LanguageClient client = launcher.getRemoteProxy(); LanguageClient client = launcher.getRemoteProxy();
@@ -30,7 +30,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
private final ParserService parserService; private final ParserService parserService;
private final TypeResolver typeResolver; private final TypeResolver typeResolver;
private final de.dhbw.service.TextDocumentService textDocumentService; private final de.dhbw.service.TextDocumentService textDocumentService;
private final LogService logService; public final LogService logService;
private final ClientService clientService; private final ClientService clientService;
private final CacheService cacheService; private final CacheService cacheService;
private final ConversionHelper conversionHelper; private final ConversionHelper conversionHelper;
@@ -46,13 +46,13 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
Boolean singleFileOpened = false; Boolean singleFileOpened = false;
public JavaTXTextDocumentService() { public JavaTXTextDocumentService() {
this.clientService = new ClientService(null);
this.logService = new LogService(clientService);
this.textHelper = new TextHelper(); this.textHelper = new TextHelper();
this.cacheService = new CacheService(); this.cacheService = new CacheService();
this.clientService = new ClientService(null);
this.typeResolver = new TypeResolver(); this.typeResolver = new TypeResolver();
this.textDocumentService = new de.dhbw.service.TextDocumentService(); this.textDocumentService = new de.dhbw.service.TextDocumentService();
this.conversionHelper = new ConversionHelper(textHelper, textDocumentService); this.conversionHelper = new ConversionHelper(textHelper, textDocumentService);
this.logService = new LogService(clientService);
this.formattingHandler = new FormattingHandler(textDocumentService); this.formattingHandler = new FormattingHandler(textDocumentService);
this.parserService = new ParserService(conversionHelper, clientService, cacheService); this.parserService = new ParserService(conversionHelper, clientService, cacheService);
this.codeActionHandler = new CodeActionHandler(textHelper, textDocumentService, cacheService, typeResolver, logService, conversionHelper); this.codeActionHandler = new CodeActionHandler(textHelper, textDocumentService, cacheService, typeResolver, logService, conversionHelper);
@@ -113,8 +113,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
if (!syntaxErrors.isEmpty()) { if (!syntaxErrors.isEmpty()) {
clientService.publishDiagnostics(params.getTextDocument().getUri(), syntaxErrors); clientService.publishDiagnostics(params.getTextDocument().getUri(), syntaxErrors);
} }
client.refreshDiagnostics(); clientService.updateClient();
client.refreshInlayHints();
textDocuments.put(params.getTextDocument().getUri(), params.getTextDocument().getText()); textDocuments.put(params.getTextDocument().getUri(), params.getTextDocument().getText());
textDocumentService.saveFileWithUri(params.getTextDocument().getUri(), params.getTextDocument().getText()); textDocumentService.saveFileWithUri(params.getTextDocument().getUri(), params.getTextDocument().getText());
} }
@@ -154,10 +153,10 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
@Override @Override
public void didSave(DidSaveTextDocumentParams didSaveTextDocumentParams) { public void didSave(DidSaveTextDocumentParams didSaveTextDocumentParams) {
logService.log("[didSave] Client triggered didSave-Event."); logService.log("[didSave] Client triggered didSave-Event.");
clientService.startLoading("compile-task", "Inferring types...", client); clientService.startLoading("compile-task", "Inferring types...");
saveHandler.handleSave(didSaveTextDocumentParams); saveHandler.handleSave(didSaveTextDocumentParams);
clientService.stopLoading("compile-task", "Types successfully inferred", client); clientService.stopLoading("compile-task", "Types successfully inferred");
clientService.updateClient(client); clientService.updateClient();
} }
@Override @Override
@@ -298,7 +297,9 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
logService.log("[codeAction] Client requested Insert at Line [" + params.getRange().getStart().getLine() + "] and from Char [" + params.getRange().getStart().getCharacter() + "] to [" + params.getRange().getEnd().getCharacter() + "].", MessageType.Info); logService.log("[codeAction] Client requested Insert at Line [" + params.getRange().getStart().getLine() + "] and from Char [" + params.getRange().getStart().getCharacter() + "] to [" + params.getRange().getEnd().getCharacter() + "].", MessageType.Info);
logService.log("Code-Action Context was: " + params.getContext().getTriggerKind().name(), MessageType.Info); var triggerKind = params.getContext().getTriggerKind();
if (triggerKind != null)
logService.log("Code-Action Context was: " + triggerKind.name(), MessageType.Info);
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
return codeActionHandler.handleNewCodeAction(params); return codeActionHandler.handleNewCodeAction(params);
@@ -3,6 +3,7 @@ package de.dhbw.handler;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import de.dhbw.helper.ConversionHelper; import de.dhbw.helper.ConversionHelper;
import de.dhbw.helper.TypeResolver; import de.dhbw.helper.TypeResolver;
import de.dhbw.helper.TypeResolver.InferenceResult;
import de.dhbw.model.*; import de.dhbw.model.*;
import de.dhbw.service.*; import de.dhbw.service.*;
import de.dhbwstuttgart.syntaxtree.factory.NameGenerator; import de.dhbwstuttgart.syntaxtree.factory.NameGenerator;
@@ -80,6 +81,8 @@ public class ChangeHandler {
if (!syntaxErrors.isEmpty()) { if (!syntaxErrors.isEmpty()) {
clientService.publishDiagnostics(params.getTextDocument().getUri(), syntaxErrors); clientService.publishDiagnostics(params.getTextDocument().getUri(), syntaxErrors);
}else {
clientService.updateClient();
} }
logService.log("Found [" + syntaxErrors.size() + "] Syntax Errors in Document."); logService.log("Found [" + syntaxErrors.size() + "] Syntax Errors in Document.");
@@ -105,110 +108,102 @@ public class ChangeHandler {
logService.log("Should Calculate is: " + shouldCalculate); logService.log("Should Calculate is: " + shouldCalculate);
if (false) {
/*try {
File tempDir = new File(System.getProperty("java.io.tmpdir"));
File tempFile = File.createTempFile("newText", ".tmp", tempDir);
FileWriter fileWriter = new FileWriter(tempFile, true);
System.out.println(tempFile.getAbsolutePath());
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(summedUp.get());
bw.close();
typeResolver.updateAst(tempFile.toURI().getPath());
tempFile.delete();
} catch (Exception e) {
logService.log(e.getMessage());
}
var sWatch = Stopwatch.createUnstarted();
sWatch.start();
try {
ArrayList<LSPVariable> typesOfMethodAndParameters = typeResolver.infereChangeInput();
DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehints(typesOfMethodAndParameters, params.getTextDocument().getUri());
List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints();
List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics();
cacheService.updateGlobalMaps(diagnostics, typeHint, params.getTextDocument().getUri());
} catch (Exception e) {
logService.log("[didChange] Error trying to get Inlay-Hints and Diagnostics for Client: " + e.getMessage(), MessageType.Error);
for (var stackTrace : e.getStackTrace()) {
logService.log(stackTrace.toString());
}
clientService.showMessage(MessageType.Error, e.getMessage());
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.getTextDocument().getUri());
} finally {
sWatch.stop();
logService.log("[didChange] Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]", MessageType.Info);
}
List<Diagnostic> typeDiagnostics = cacheService.getGlobalDiagnosticsMap().get(params.getTextDocument().getUri());
ArrayList<Diagnostic> allDiagnostics = new ArrayList<>(typeDiagnostics);
clientService.publishDiagnostics(params.getTextDocument().getUri(), allDiagnostics);*/
logService.log("Calculating again.");
var sWatch = Stopwatch.createUnstarted();
sWatch.start();
try {
File tempFile2 = null;
try { try {
File tempDir = new File(System.getProperty("java.io.tmpdir")); File tempDir2 = Path.of(new URI(params.getTextDocument().getUri())).getParent().toFile();
File tempFile = File.createTempFile("newText", ".tmp", tempDir); tempFile2 = File.createTempFile("jtx_temp", ".tmp", tempDir2);
FileWriter fileWriter = new FileWriter(tempFile, true); FileWriter fileWriter = new FileWriter(tempFile2, true);
System.out.println(tempFile.getAbsolutePath());
BufferedWriter bw = new BufferedWriter(fileWriter); BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(summedUp.get()); bw.write(input);
bw.close(); bw.close();
typeResolver.updateAst(tempFile.toURI().getPath());
tempFile.delete();
} catch (Exception e) {
logService.log(e.getMessage());
}
var sWatch = Stopwatch.createUnstarted();
sWatch.start();
try {
ArrayList<LSPVariable> typesOfMethodAndParameters = typeResolver.infereChangeInput();
DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehints(typesOfMethodAndParameters, params.getTextDocument().getUri());
List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints();
List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics();
cacheService.updateGlobalMaps(diagnostics, typeHint, params.getTextDocument().getUri());
} catch (Exception e) {
logService.log("[didChange] Error trying to get Inlay-Hints and Diagnostics for Client: " + e.getMessage(), MessageType.Error);
for (var stackTrace : e.getStackTrace()) {
logService.log(stackTrace.toString());
}
clientService.showMessage(MessageType.Error, e.getMessage());
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.getTextDocument().getUri());
} finally {
sWatch.stop();
logService.log("[didChange] Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]", MessageType.Info);
}
List<Diagnostic> typeDiagnostics = cacheService.getGlobalDiagnosticsMap().get(params.getTextDocument().getUri());
ArrayList<Diagnostic> allDiagnostics = new ArrayList<>(typeDiagnostics);
clientService.publishDiagnostics(params.getTextDocument().getUri(), allDiagnostics);
} else {
logService.log("Calculating again.");
var sWatch = Stopwatch.createUnstarted();
sWatch.start();
try {
try { try {
File tempDir2 = Path.of(new URI(params.getTextDocument().getUri())).getParent().toFile(); InferenceResult inferenceResult = typeResolver.infereInput(tempFile2.toURI().toString(), input);
File tempFile2 = File.createTempFile("jtx_temp", ".tmp", tempDir2); cacheService.setVariables(inferenceResult.variables());
FileWriter fileWriter = new FileWriter(tempFile2, true);
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(input);
bw.close();
try { DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehintsWithInput(inferenceResult, input);
ArrayList<LSPVariable> variables = typeResolver.infereInput(tempFile2.toURI().toString(), input, true);
cacheService.setVariables(variables);
DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehintsWithInput(variables, input); List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints();
List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics();
List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints(); cacheService.updateGlobalMaps(diagnostics, typeHint, params.getTextDocument().getUri());
List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics();
cacheService.updateGlobalMaps(diagnostics, typeHint, params.getTextDocument().getUri()); List<Diagnostic> allDiagnostics = new ArrayList<>(diagnostics);
List<Diagnostic> allDiagnostics = new ArrayList<>(diagnostics); clientService.publishDiagnostics(params.getTextDocument().getUri(), allDiagnostics);
allDiagnostics.addAll(parserService.getDiagnosticsOfErrors(input, params.getTextDocument().getUri())); } catch (Exception | VerifyError f) {
logService.log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + f.getMessage(), MessageType.Error);
clientService.publishDiagnostics(params.getTextDocument().getUri(), allDiagnostics); for (StackTraceElement elem : f.getStackTrace()) {
} catch (Exception f) {
logService.log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + f.getMessage(), MessageType.Error);
for (StackTraceElement elem : f.getStackTrace()) {
logService.log(elem.toString());
}
clientService.showMessage(MessageType.Error, f.getMessage() == null ? "null" : f.getMessage());
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.getTextDocument().getUri());
}
tempFile2.delete();
} catch (Exception e) {
logService.log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + e.getMessage(), MessageType.Error);
for (StackTraceElement elem : e.getStackTrace()) {
logService.log(elem.toString()); logService.log(elem.toString());
} }
clientService.showMessage(MessageType.Error, e.getMessage() == null ? "null" : e.getMessage()); clientService.showMessage(MessageType.Error, f.getMessage() == null ? "null" : f.getMessage());
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.getTextDocument().getUri()); cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.getTextDocument().getUri());
} finally {
sWatch.stop();
logService.log("[didSave] Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]", MessageType.Info);
} }
} catch (Exception e) { } catch (Exception e) {
logService.log(e.getMessage()); logService.log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + e.getMessage(), MessageType.Error);
clientService.showMessage(MessageType.Error, e.getMessage() == null ? "null" : e.getMessage());
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.getTextDocument().getUri());
} finally {
sWatch.stop();
logService.log("[didSave] Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]", MessageType.Info);
if (tempFile2 != null) tempFile2.delete();
} }
} catch (Exception e) {
logService.log(e.getMessage());
} }
} }
} }
} }
@@ -1,6 +1,8 @@
package de.dhbw.handler; package de.dhbw.handler;
import de.dhbw.helper.ASTTransformationHelper;
import de.dhbw.helper.ConversionHelper; import de.dhbw.helper.ConversionHelper;
import de.dhbw.helper.InsertPoint;
import de.dhbw.helper.TextHelper; import de.dhbw.helper.TextHelper;
import de.dhbw.helper.TypeResolver; import de.dhbw.helper.TypeResolver;
import de.dhbw.service.CacheService; import de.dhbw.service.CacheService;
@@ -68,8 +70,8 @@ public class CodeActionHandler {
} }
public static <V> Map<String, V> getOverlapping( public static <V> Map<InsertPoint, V> getOverlapping(
Map<String, V> map, Map<InsertPoint, V> map,
int line, int line,
int startChar, int startChar,
int endChar int endChar
@@ -83,20 +85,13 @@ public class CodeActionHandler {
final int s = startChar, e = endChar; final int s = startChar, e = endChar;
return map.entrySet().stream() return map.entrySet().stream()
.filter(entry -> { .filter(entry -> {
String key = entry.getKey(); InsertPoint key = entry.getKey();
String[] parts = key.split("\\s+"); int kLine = key.line();
if (parts.length != 2) return false; int kChar = key.character();
try { return kLine == line && kChar >= s && kChar <= e;
int kLine = Integer.parseInt(parts[0]); })
int kChar = Integer.parseInt(parts[1]); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return kLine == line && kChar >= s && kChar <= e;
} catch (NumberFormatException ex) {
// Key nicht im erwarteten Format
return false;
}
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
} }
@@ -107,9 +102,9 @@ public class CodeActionHandler {
if (typeResolver.getInserts() != null) { if (typeResolver.getInserts() != null) {
//All Diagnostics that are in range of the hover -> All Diagnostics of the selected Variable and thus all Types of the Variable //All Diagnostics that are in range of the hover -> All Diagnostics of the selected Variable and thus all Types of the Variable
Map<String, List<PlaceholderVariable>> typeInsertsOverlapping = getOverlapping(typeResolver.getInserts(), rangeOfInsert.getStart().getLine() + 1, rangeOfInsert.getStart().getCharacter(), rangeOfInsert.getEnd().getCharacter()); Map<InsertPoint, List<PlaceholderVariable>> typeInsertsOverlapping = getOverlapping(typeResolver.getInserts(), rangeOfInsert.getStart().getLine() + 1, rangeOfInsert.getStart().getCharacter(), rangeOfInsert.getEnd().getCharacter());
logService.log("Inserts are:"); logService.log("Inserts are:");
typeResolver.getInserts().forEach((key, value) -> logService.log(key)); typeResolver.getInserts().forEach((key, value) -> logService.log(key.toString()));
logService.log("Size is: " + typeInsertsOverlapping.size()); logService.log("Size is: " + typeInsertsOverlapping.size());
logService.log("Range is: " + rangeOfInsert.getStart().getLine() + " -> " + rangeOfInsert.getStart().getCharacter() + " - " + rangeOfInsert.getEnd().getCharacter()); logService.log("Range is: " + rangeOfInsert.getStart().getLine() + " -> " + rangeOfInsert.getStart().getCharacter() + " - " + rangeOfInsert.getEnd().getCharacter());
List<Either<Command, CodeAction>> actions = new ArrayList<>(); List<Either<Command, CodeAction>> actions = new ArrayList<>();
@@ -125,18 +120,24 @@ public class CodeActionHandler {
listOfChanges.add(new TextEdit(wholeDocumentRange(textDocumentService.getFileOfUri(documentUri)), typeWithReplacedVariable)); listOfChanges.add(new TextEdit(wholeDocumentRange(textDocumentService.getFileOfUri(documentUri)), typeWithReplacedVariable));
var isTypeImported = false;
Map<String, List<TextEdit>> changes = new HashMap<>(); Map<String, List<TextEdit>> changes = new HashMap<>();
changes.put(documentUri, listOfChanges); changes.put(documentUri, listOfChanges);
WorkspaceEdit edit = new WorkspaceEdit(); WorkspaceEdit edit = new WorkspaceEdit();
edit.setChanges(changes); edit.setChanges(changes);
CodeAction action = new CodeAction("Insert " + conversionHelper.cleanType(typeInsert.getInsertString())); var constraints = typeInsert.getConstraints();
var genericsString = "";
if (constraints != null && !constraints.isEmpty()) {
genericsString = ASTTransformationHelper.createConstraintsString(constraints);
}
CodeAction action = new CodeAction("Insert " + ConversionHelper.cleanType(typeInsert.getInsertString()) + genericsString);
action.setKind(CodeActionKind.QuickFix); action.setKind(CodeActionKind.QuickFix);
action.setEdit(edit); action.setEdit(edit);
actions.add(Either.forRight(action));
if(!actions.stream().map(el -> el.getRight().getTitle()).toList().contains(action.getTitle())){
actions.add(Either.forRight(action));
}
} catch (Exception e) { } catch (Exception e) {
logService.log("Error creating Actions, returning empty List. The Error was: " + e.getMessage(), MessageType.Error); logService.log("Error creating Actions, returning empty List. The Error was: " + e.getMessage(), MessageType.Error);
} }
@@ -1,10 +1,12 @@
package de.dhbw.handler; package de.dhbw.handler;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.google.common.base.Verify;
import de.dhbw.model.DiagnosticsAndTypehints; import de.dhbw.model.DiagnosticsAndTypehints;
import de.dhbw.service.*; import de.dhbw.service.*;
import de.dhbw.helper.ConversionHelper; import de.dhbw.helper.ConversionHelper;
import de.dhbw.helper.TypeResolver; import de.dhbw.helper.TypeResolver;
import de.dhbw.helper.TypeResolver.InferenceResult;
import de.dhbw.model.LSPVariable; import de.dhbw.model.LSPVariable;
import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface; import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface;
import de.dhbwstuttgart.languageServerInterface.model.ParserError; import de.dhbwstuttgart.languageServerInterface.model.ParserError;
@@ -51,22 +53,23 @@ public class SaveHandler {
List<Diagnostic> syntaxErrors = parserService.getDiagnosticsOfErrors(fileInput, didSaveTextDocumentParams.getTextDocument().getUri()); List<Diagnostic> syntaxErrors = parserService.getDiagnosticsOfErrors(fileInput, didSaveTextDocumentParams.getTextDocument().getUri());
if (!syntaxErrors.isEmpty()) { if (!syntaxErrors.isEmpty()) {
clientService.publishDiagnostics(didSaveTextDocumentParams.getTextDocument().getUri(), syntaxErrors); clientService.publishDiagnostics(didSaveTextDocumentParams.getTextDocument().getUri(), syntaxErrors);
}else {
clientService.updateClient();
} }
logService.log("Found [" + syntaxErrors.size() + "] Syntax Errors in Document."); logService.log("Found [" + syntaxErrors.size() + "] Syntax Errors in Document.");
if (syntaxErrors.isEmpty()) { if (syntaxErrors.isEmpty()) {
cacheService.getLastSavedFiles().put(didSaveTextDocumentParams.getTextDocument().getUri(), fileInput); cacheService.getLastSavedFiles().put(didSaveTextDocumentParams.getTextDocument().getUri(), fileInput);
//typeResolver.getCompilerInput(didSaveTextDocumentParams.getTextDocument().getUri(), fileInput);
if (fileInput == null) { if (fileInput == null) {
logService.log("[didSave] Input of Text Document is null in TextDocument-Hashmap.", MessageType.Error); logService.log("[didSave] Input of Text Document is null in TextDocument-Hashmap.", MessageType.Error);
} }
ArrayList<LSPVariable> variables = typeResolver.infereInput(didSaveTextDocumentParams.getTextDocument().getUri(), fileInput, false); InferenceResult inferenceResult = typeResolver.infereInput(didSaveTextDocumentParams.getTextDocument().getUri(), fileInput);
cacheService.setVariables(variables); cacheService.setVariables(inferenceResult.variables());
DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehints(variables, didSaveTextDocumentParams.getTextDocument().getUri()); DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehints(inferenceResult, didSaveTextDocumentParams.getTextDocument().getUri());
List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints(); List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints();
List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics(); List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics();
@@ -79,16 +82,13 @@ public class SaveHandler {
} }
} catch (Exception e) { } catch (Exception | VerifyError e) {
logService.log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + e.getMessage(), MessageType.Error); logService.log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + e.getMessage(), MessageType.Error);
for (StackTraceElement elem : e.getStackTrace()) {
logService.log(elem.toString());
}
clientService.showMessage(MessageType.Error, e.getMessage() == null ? "null" : e.getMessage()); clientService.showMessage(MessageType.Error, e.getMessage() == null ? "null" : e.getMessage());
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), didSaveTextDocumentParams.getTextDocument().getUri()); cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), didSaveTextDocumentParams.getTextDocument().getUri());
}
} finally { finally {
sWatch.stop(); sWatch.stop();
logService.log("[didSave] Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]", MessageType.Info); logService.log("[didSave] Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]", MessageType.Info);
} }
@@ -3,6 +3,7 @@ package de.dhbw.helper;
import de.dhbw.model.PlaceholderPoint; import de.dhbw.model.PlaceholderPoint;
import de.dhbw.model.PlaceholderType; import de.dhbw.model.PlaceholderType;
import de.dhbw.model.PlaceholderVariable; import de.dhbw.model.PlaceholderVariable;
import de.dhbw.service.LogService;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface; import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Method; import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.SourceFile; import de.dhbwstuttgart.syntaxtree.SourceFile;
@@ -15,41 +16,40 @@ import de.dhbwstuttgart.typeinference.result.*;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set; import java.util.Set;
public class ASTTransformationHelper { public class ASTTransformationHelper {
public static Set<PlaceholderVariable> createTypeInsertPoints(SourceFile forSourcefile, ResultSet withResults, GenericsResult generics) { public static Set<PlaceholderVariable> createTypeInsertPoints(SourceFile forSourcefile, List<GenericsResult> generics) {
return new PlaceholderPlacer().getTypeInserts(forSourcefile, withResults, generics); return new PlaceholderPlacer(forSourcefile, generics).getTypeInserts();
} }
public static PlaceholderVariable createInsertPoints(RefTypeOrTPHOrWildcardOrGeneric type, Token offset, ClassOrInterface cl, Method m, public static PlaceholderVariable createInsertPoints(RefTypeOrTPHOrWildcardOrGeneric type, Token offset, ClassOrInterface cl, Method m,
ResultSet resultSet, GenericsResultSet constraints, GenericsResultSet classConstraints) { ResultSet resultSet, GenericsResultSet constraints, GenericsResultSet classConstraints) {
ResolvedType resolvedType = resultSet.resolveType(type);
PlaceholderPoint insertPoint = new PlaceholderPoint(offset, var resolvedType = constraints.getGenerics().getType(type);
new PlaceholderToInsertString(resolvedType.resolvedType, constraints, classConstraints).insert, PlaceholderType.NORMAL_INSERT); if (resolvedType == null) {
return new PlaceholderVariable(insertPoint, createGenericInsert(constraints, classConstraints, cl, m, resultSet, offset), resolvedType.getResultPair()); resolvedType = classConstraints.getGenerics().getType(type);
} }
PlaceholderPoint insertPoint = new PlaceholderPoint(offset,
new PlaceholderToInsertString(resolvedType, constraints, classConstraints).insert, PlaceholderType.NORMAL_INSERT);
return new PlaceholderVariable(insertPoint, createGenericInsert(constraints, classConstraints, cl, m, offset), type, constraints);
}
private static synchronized Set<PlaceholderPoint> createGenericInsert(GenericsResultSet methodConstraints, GenericsResultSet classConstraints, ClassOrInterface cl, Method m, ResultSet resultSet, Token mOffset){ private static synchronized Set<PlaceholderPoint> createGenericInsert(GenericsResultSet methodConstraints, GenericsResultSet classConstraints, ClassOrInterface cl, Method m, Token mOffset){
Set<PlaceholderPoint> result = createGenericClassInserts(classConstraints, cl); Set<PlaceholderPoint> result = createGenericClassInserts(classConstraints, cl);
if (m != null) { if (m != null) {
result.addAll(createMethodConstraints(methodConstraints, m.getOffset() != null ? m.getOffset() : mOffset)); createMethodConstraints(methodConstraints, m.getOffset() != null ? m.getOffset() : mOffset).ifPresent(result::add);
} }
return result; return result;
} }
private static Set<PlaceholderPoint> createMethodConstraints(GenericsResultSet constraints, Token mOffset) {
Set<PlaceholderPoint> result = new HashSet<>();
Token offset = mOffset;
if (constraints.size() == 0) { public static String createConstraintsString(GenericsResultSet constraints) {
return result;
}
String insert = " <"; String insert = " <";
for (var genericInsertConstraint : constraints) { for (var genericInsertConstraint : constraints) {
@@ -63,9 +63,16 @@ public class ASTTransformationHelper {
insert = insert.substring(0, insert.length() -2); insert = insert.substring(0, insert.length() -2);
insert += ">"; insert += ">";
result.add(new PlaceholderPoint(offset, insert, PlaceholderType.GENERERIC_METHOD_INSERT)); return insert;
return result; }
private static Optional<PlaceholderPoint> createMethodConstraints(GenericsResultSet constraints, Token mOffset) {
Token offset = mOffset;
if (constraints.size() == 0) {
return Optional.empty();
}
return Optional.of(new PlaceholderPoint(offset, createConstraintsString(constraints), PlaceholderType.GENERERIC_METHOD_INSERT));
} }
private static Set<PlaceholderPoint> createGenericClassInserts(GenericsResultSet classConstraints, ClassOrInterface cl) { private static Set<PlaceholderPoint> createGenericClassInserts(GenericsResultSet classConstraints, ClassOrInterface cl) {
@@ -75,23 +82,7 @@ public class ASTTransformationHelper {
if (classConstraints == null || classConstraints.size() == 0) { if (classConstraints == null || classConstraints.size() == 0) {
return result; return result;
} }
result.add(new PlaceholderPoint(offset, createConstraintsString(classConstraints), PlaceholderType.GENERIC_CLASS_INSERT));
String insert = " <";
for (var genericInsertConstraint : classConstraints) {
if (genericInsertConstraint instanceof GenerateGenerics.PairEQ peq) {
insert += peq.left.resolve().getName();
} else if (genericInsertConstraint instanceof GenerateGenerics.PairLT psm) {
insert += psm.left.resolve().getName() + " extends " + psm.right.resolve().getName();
}
insert += ", ";
}
insert = insert.substring(0, insert.length() -2);
insert += ">";
result.add(new PlaceholderPoint(offset, insert, PlaceholderType.GENERIC_CLASS_INSERT));
return result; return result;
} }
} }
@@ -1,9 +1,11 @@
package de.dhbw.helper; package de.dhbw.helper;
import de.dhbw.helper.TypeResolver.InferenceResult;
import de.dhbw.model.DiagnosticsAndTypehints; import de.dhbw.model.DiagnosticsAndTypehints;
import de.dhbw.service.TextDocumentService; import de.dhbw.service.TextDocumentService;
import de.dhbw.model.LSPVariable; import de.dhbw.model.LSPVariable;
import de.dhbw.model.Type; import de.dhbw.model.Type;
import de.dhbwstuttgart.exceptions.CompilerWarning;
import de.dhbwstuttgart.languageServerInterface.model.ParserError; import de.dhbwstuttgart.languageServerInterface.model.ParserError;
import org.eclipse.lsp4j.*; import org.eclipse.lsp4j.*;
@@ -20,8 +22,9 @@ public class ConversionHelper {
this.textDocumentService = textDocumentService; this.textDocumentService = textDocumentService;
} }
public String cleanType(String type){ public static String cleanType(String type) {
return type.replaceAll("java.lang.", "").replaceAll("java.util.", ""); // Strip package from type string for better readability in diagnostics and inlay hints
return type.replaceAll("\\b(?:[A-Za-z_]\\w*\\.)+(\\w+)\\b", "$1");
} }
public InlayHint getInlayHint(LSPVariable variable) { public InlayHint getInlayHint(LSPVariable variable) {
@@ -29,7 +32,7 @@ public class ConversionHelper {
String typeDisplay = ""; String typeDisplay = "";
for (Type type : variable.getPossibleTypes()) { for (Type type : variable.getPossibleTypes()) {
typeDisplay += " | " + cleanType(type.getType().replaceAll("GTV ", "")); typeDisplay += "| " + cleanType(type.getType().replaceAll("GTV ", ""));
} }
@@ -90,11 +93,35 @@ public class ConversionHelper {
}).toList(); }).toList();
} }
public DiagnosticsAndTypehints variablesToDiagnosticsAndTypehints(ArrayList<LSPVariable> typesOfMethodAndParameters, String uri) { public DiagnosticsAndTypehints addWarningsToDiagnostics(DiagnosticsAndTypehints diagnosticsAndTypehints, List<CompilerWarning> warnings) {
List<Diagnostic> diagnostics = new ArrayList<>(diagnosticsAndTypehints.getDiagnostics());
for (var warning : warnings) {
var offset = warning.getOffset();
Range warningRange = new Range(
new Position(offset.getLine() - 1, offset.getCharPositionInLine()),
new Position(offset.getLine() - 1, offset.getCharPositionInLine() + offset.getText().length())
);
Diagnostic diagnostic = new Diagnostic(
warningRange,
warning.getMessage(),
DiagnosticSeverity.Warning,
"JavaTX Language Server"
);
diagnostics.add(diagnostic);
}
return new DiagnosticsAndTypehints(diagnostics, diagnosticsAndTypehints.getInlayHints());
}
public DiagnosticsAndTypehints variablesToDiagnosticsAndTypehints(InferenceResult inferenceResult, String uri) {
var diagnosticsAndTypehints = variablesToDiagnosticsAndTypehints(inferenceResult.variables(), uri);
return addWarningsToDiagnostics(diagnosticsAndTypehints, inferenceResult.warnings());
}
public DiagnosticsAndTypehints variablesToDiagnosticsAndTypehints(ArrayList<LSPVariable> variables, String uri) {
List<InlayHint> typeHint = new ArrayList<>(); List<InlayHint> typeHint = new ArrayList<>();
ArrayList<Diagnostic> diagnostics = new ArrayList<>(); ArrayList<Diagnostic> diagnostics = new ArrayList<>();
for (var variable : typesOfMethodAndParameters) { for (var variable : variables) {
InlayHint inlayHint = getInlayHint(variable); InlayHint inlayHint = getInlayHint(variable);
typeHint.add(inlayHint); typeHint.add(inlayHint);
@@ -108,11 +135,11 @@ public class ConversionHelper {
return new DiagnosticsAndTypehints(diagnostics, typeHint); return new DiagnosticsAndTypehints(diagnostics, typeHint);
} }
public DiagnosticsAndTypehints variablesToDiagnosticsAndTypehintsWithInput(ArrayList<LSPVariable> typesOfMethodAndParameters, String input) { public DiagnosticsAndTypehints variablesToDiagnosticsAndTypehintsWithInput(InferenceResult inferenceResult, String input) {
List<InlayHint> typeHint = new ArrayList<>(); List<InlayHint> typeHint = new ArrayList<>();
ArrayList<Diagnostic> diagnostics = new ArrayList<>(); ArrayList<Diagnostic> diagnostics = new ArrayList<>();
for (var variable : typesOfMethodAndParameters) { for (var variable : inferenceResult.variables()) {
InlayHint inlayHint = getInlayHint(variable); InlayHint inlayHint = getInlayHint(variable);
typeHint.add(inlayHint); typeHint.add(inlayHint);
@@ -123,6 +150,6 @@ public class ConversionHelper {
} }
} }
return new DiagnosticsAndTypehints(diagnostics, typeHint); return addWarningsToDiagnostics(new DiagnosticsAndTypehints(diagnostics, typeHint), inferenceResult.warnings());
} }
} }
@@ -0,0 +1,3 @@
package de.dhbw.helper;
public record InsertPoint(int line, int character) {}
@@ -1,31 +1,43 @@
package de.dhbw.helper; package de.dhbw.helper;
import de.dhbw.JavaTXLanguageServerLauncher;
import de.dhbw.model.PlaceholderVariable; import de.dhbw.model.PlaceholderVariable;
import de.dhbw.service.LogService;
import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter;
import de.dhbwstuttgart.target.generate.GenericsResult; import de.dhbwstuttgart.target.generate.GenericsResult;
import de.dhbwstuttgart.typeinference.result.ResultSet; import de.dhbwstuttgart.typeinference.typeAlgo.TYPE;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
public class PlaceholderPlacer extends AbstractASTWalker { public class PlaceholderPlacer extends AbstractASTWalker {
Set<PlaceholderVariable> inserts = new HashSet<>(); Set<PlaceholderVariable> inserts = new HashSet<>();
private ResultSet withResults;
String pkgName; String pkgName;
private GenericsResult genericsResult; private List<GenericsResult> genericsResult;
private SourceFile forSourceFile;
public Set<PlaceholderVariable> getTypeInserts(SourceFile forSourceFile, ResultSet withResults, GenericsResult genericsResult){ public PlaceholderPlacer(SourceFile forSourceFile, List<GenericsResult> genericsResult) {
this.withResults = withResults; this.forSourceFile = forSourceFile;
this.genericsResult = genericsResult; this.genericsResult = genericsResult;
pkgName = forSourceFile.getPkgName(); this.pkgName = forSourceFile.getPkgName();
forSourceFile.accept(this); }
inserts.forEach(el -> el.reducePackage());
return inserts; public Set<PlaceholderVariable> getTypeInserts() {
this.inserts = new HashSet<>();
this.forSourceFile.accept(this);
this.inserts.forEach(el -> el.reducePackage());
return this.inserts;
} }
@Override @Override
public void visit(ClassOrInterface classOrInterface) { public void visit(ClassOrInterface classOrInterface) {
de.dhbw.helper.PlaceholderPlacerClass cl = new de.dhbw.helper.PlaceholderPlacerClass(classOrInterface, withResults, genericsResult); var logService = JavaTXLanguageServerLauncher.server.textDocumentService.logService;
var text = ASTPrinter.print(forSourceFile);
logService.log(text);
de.dhbw.helper.PlaceholderPlacerClass cl = new de.dhbw.helper.PlaceholderPlacerClass(classOrInterface, genericsResult);
this.inserts.addAll(cl.inserts); this.inserts.addAll(cl.inserts);
} }
} }
@@ -1,19 +1,39 @@
package de.dhbw.helper; package de.dhbw.helper;
import de.dhbw.JavaTXLanguageServer;
import de.dhbw.JavaTXLanguageServerLauncher;
import de.dhbw.model.PlaceholderVariable; import de.dhbw.model.PlaceholderVariable;
import de.dhbw.service.ClientService;
import de.dhbw.service.LogService;
import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression; import de.dhbwstuttgart.syntaxtree.statement.LambdaExpression;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder; import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.target.generate.BoundsList;
import de.dhbwstuttgart.target.generate.GenericsResult; import de.dhbwstuttgart.target.generate.GenericsResult;
import de.dhbwstuttgart.target.generate.GenericsResultSet; import de.dhbwstuttgart.target.generate.GenericsResultSet;
import de.dhbwstuttgart.target.generate.ASTToTargetAST.Generics;
import de.dhbwstuttgart.typeinference.result.ResultSet; import de.dhbwstuttgart.typeinference.result.ResultSet;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
class PlaceholderPlacerClass extends AbstractASTWalker{ import org.apache.log4j.LogManager;
protected final ResultSet results; import org.apache.log4j.Logger;
private GenericsResult generatedGenerics;
class PlaceholderPlacerClass extends AbstractASTWalker {
private final LogService logger;
private List<GenericsResult> generatedGenerics;
private GenericsResult current;
protected final ClassOrInterface cl; protected final ClassOrInterface cl;
public final Set<PlaceholderVariable> inserts = new HashSet<>(); public final Set<PlaceholderVariable> inserts = new HashSet<>();
private Method method; private Method method;
@@ -21,40 +41,114 @@ class PlaceholderPlacerClass extends AbstractASTWalker{
GenericsResultSet constraints; GenericsResultSet constraints;
GenericsResultSet classConstraints; GenericsResultSet classConstraints;
PlaceholderPlacerClass(ClassOrInterface forClass, ResultSet withResults, GenericsResult generatedGenerics){ PlaceholderPlacerClass(ClassOrInterface forClass, List<GenericsResult> generatedGenerics) {
this.logger = JavaTXLanguageServerLauncher.server.textDocumentService.logService;
this.cl = forClass; this.cl = forClass;
this.method = null; this.method = null;
this.results = withResults;
this.generatedGenerics = generatedGenerics; this.generatedGenerics = generatedGenerics;
forClass.accept(this); forClass.accept(this);
} }
// TODO Should these be moved into the Compiler?
private static boolean isTypeEqual(RefTypeOrTPHOrWildcardOrGeneric a, RefTypeOrTPHOrWildcardOrGeneric b) {
if (a instanceof RefType ra && b instanceof RefType rb) {
if (!ra.getName().equals(rb.getName())) return false;
if (ra.getParaList().size() != rb.getParaList().size()) return false;
for (int i = 0; i < ra.getParaList().size(); i++) {
if (!isTypeEqual(ra.getParaList().get(i), rb.getParaList().get(i))) return false;
}
return true;
} else if (a instanceof TypePlaceholder && b instanceof TypePlaceholder) {
return true; // Type placeholders are considered equal regardless of their names
}
return Objects.equals(a, b);
}
private static class MethodBounds extends AbstractList<BoundsList> {
private final List<BoundsList> bounds;
MethodBounds(List<BoundsList> bounds) {
this.bounds = Collections.unmodifiableList(bounds);
}
@Override
public int size() { return bounds.size(); }
@Override
public BoundsList get(int index) { return bounds.get(index); }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MethodBounds that)) return false;
if (this.size() != that.size()) return false;
for (int i = 0; i < this.size(); i++) {
var a = this.get(i);
var b = that.get(i);
if (!isTypeEqual(a.base, b.base)) return false;
if (!a.equals(b)) return false;
}
return true;
}
}
private static MethodBounds boundsForParameters(ClassOrInterface clazz, Method method, GenericsResult result) {
var bounds = new ArrayList<BoundsList>();
bounds.add(result.getBounds(method.getReturnType(), clazz, method));
for (var para : method.getParameterList().getFormalparalist()) {
bounds.add(result.getBounds(para.getType(), clazz, method));
}
return new MethodBounds(bounds);
}
@Override
public void visit(Constructor constructor) {
this.visit((Method) constructor);
}
@Override @Override
public void visit(Method method) { public void visit(Method method) {
this.method = method; this.method = method;
constraints = generatedGenerics.get(method); var allMethodBounds = new HashSet<MethodBounds>();
classConstraints = generatedGenerics.get(cl);
if(method.getReturnType() instanceof TypePlaceholder) for (var generics : generatedGenerics) {
inserts.add(ASTTransformationHelper.createInsertPoints( current = generics;
method.getReturnType(), method.getReturnType().getOffset(), cl, method, results, constraints, classConstraints));
super.visit(method); var bounds = boundsForParameters(cl, method, generics);
if (allMethodBounds.contains(bounds)) continue;
allMethodBounds.add(bounds);
constraints = generics.get(cl, method);
classConstraints = generics.get(cl);
if (method.getReturnType() instanceof TypePlaceholder) {
if (!(method instanceof Constructor)) {
logger.log(generics.getGenerics().getResultSet().toString());
inserts.add(ASTTransformationHelper.createInsertPoints(
method.getReturnType(), method.getReturnType().getOffset(), cl, method, generics.getGenerics().getResultSet(), constraints, classConstraints));
}
super.visit(method);
}
}
} }
@Override @Override
public void visit(Field field) { public void visit(Field field) {
if(field.getType() instanceof TypePlaceholder){ if (field.getType() instanceof TypePlaceholder) {
classConstraints = generatedGenerics.get(cl); for (var generics : generatedGenerics) {
classConstraints = generics.get(cl);
inserts.add(ASTTransformationHelper.createInsertPoints( inserts.add(ASTTransformationHelper.createInsertPoints(
field.getType(), field.getType().getOffset(), cl, method, results, null, classConstraints)); field.getType(), field.getType().getOffset(), cl, method, generics.getGenerics().getResultSet(), null, classConstraints));
}
} }
super.visit(field);
} }
@Override @Override
public void visit(FormalParameter param) { public void visit(FormalParameter param) {
if(param.getType() instanceof TypePlaceholder) if(param.getType() instanceof TypePlaceholder)
inserts.add(ASTTransformationHelper.createInsertPoints( inserts.add(ASTTransformationHelper.createInsertPoints(
param.getType(), param.getType().getOffset(), cl, method, results, constraints, classConstraints)); param.getType(), param.getType().getOffset(), cl, method, current.getGenerics().getResultSet(), constraints, classConstraints));
super.visit(param); super.visit(param);
} }
@@ -1,6 +1,7 @@
package de.dhbw.helper; package de.dhbw.helper;
import de.dhbwstuttgart.syntaxtree.type.*; import de.dhbwstuttgart.syntaxtree.type.*;
import de.dhbwstuttgart.target.generate.GenerateGenerics;
import de.dhbwstuttgart.target.generate.GenericsResultSet; import de.dhbwstuttgart.target.generate.GenericsResultSet;
import de.dhbwstuttgart.typeinference.result.*; import de.dhbwstuttgart.typeinference.result.*;
@@ -60,14 +61,14 @@ public class PlaceholderToInsertString implements ResultSetVisitor{
@Override @Override
public void visit(TypePlaceholder typePlaceholder) { public void visit(TypePlaceholder typePlaceholder) {
ResultPair<?, ?> resultPair = null; GenerateGenerics.Pair resultPair = null;
if (constraints != null) if (constraints != null)
resultPair = constraints.getResultPairFor(typePlaceholder).orElse(null); resultPair = constraints.getResultPairFor(typePlaceholder).orElse(null);
if (resultPair == null) if (resultPair == null)
resultPair = classConstraints.getResultPairFor(typePlaceholder).orElse(null); resultPair = classConstraints.getResultPairFor(typePlaceholder).orElse(null);
if (resultPair != null) if (resultPair != null)
insert += ((TypePlaceholder)resultPair.getLeft()).getName(); insert += resultPair.left.toString();
} }
@Override @Override
@@ -1,32 +1,24 @@
package de.dhbw.helper; package de.dhbw.helper;
import de.dhbw.JavaTXLanguageServer;
import de.dhbw.JavaTXLanguageServerLauncher;
import de.dhbw.model.*; import de.dhbw.model.*;
import de.dhbw.model.PlaceholderVariable; import de.dhbwstuttgart.exceptions.CompilerWarning;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface; import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface;
import de.dhbwstuttgart.languageServerInterface.model.LanguageServerTransferObject; import de.dhbwstuttgart.languageServerInterface.model.LanguageServerTransferObject;
import de.dhbwstuttgart.parser.scope.JavaClassName;
import de.dhbwstuttgart.syntaxtree.SourceFile; import de.dhbwstuttgart.syntaxtree.SourceFile;
import de.dhbwstuttgart.syntaxtree.factory.NameGenerator;
import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter; import de.dhbwstuttgart.syntaxtree.visual.ASTPrinter;
import de.dhbwstuttgart.target.generate.GenericsResult; import de.dhbwstuttgart.target.generate.GenericsResult;
import de.dhbwstuttgart.typedeployment.TypeInsert;
import de.dhbwstuttgart.typeinference.result.ResultSet;
import org.apache.log4j.LogManager; import org.apache.log4j.LogManager;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*; import java.util.*;
/** /**
* Helper-Class for finding the Type of a selected Word * Helper-Class for finding the Type of a selected Word
*/ */
@@ -37,10 +29,9 @@ public class TypeResolver {
private final DuplicationUtils duplicationUtils; private final DuplicationUtils duplicationUtils;
private final boolean ENABLE_GENERICS = true; private final boolean ENABLE_GENERICS = true;
private List<GenericsResult> generatedGenerics = null; private List<GenericsResult> generatedGenerics = null;
private HashMap<String, List<PlaceholderVariable>> inserts; private HashMap<InsertPoint, List<PlaceholderVariable>> inserts;
public HashMap<InsertPoint, List<PlaceholderVariable>> getInserts() {
public HashMap<String, List<PlaceholderVariable>> getInserts() {
return inserts; return inserts;
} }
@@ -50,9 +41,7 @@ public class TypeResolver {
private LanguageServerTransferObject current; private LanguageServerTransferObject current;
public void reset() { public void reset() {
HashMap<String, List<TypeInsert>> inserts = null; this.current = null;
List<GenericsResult> generatedGenerics = null;
current = null;
} }
@@ -80,44 +69,54 @@ public class TypeResolver {
return true; return true;
} }
public void getCompilerInput(String path, String input) throws IOException, URISyntaxException, ClassNotFoundException { /*public void getCompilerInput(String path, String input) throws IOException, URISyntaxException, ClassNotFoundException {
LanguageServerInterface languageServer = new LanguageServerInterface(); LanguageServerInterface languageServer = new LanguageServerInterface();
var transferObj = languageServer.getResultSetAndAbastractSyntax(path, RESET_TO_LETTER); var transferObj = languageServer.getResultSetAndAbstractSyntax(path, RESET_TO_LETTER);
current = transferObj; current = transferObj;
} }
public LanguageServerTransferObject updateIfNotPresent(String path, String input) throws IOException, URISyntaxException, ClassNotFoundException { public LanguageServerTransferObject updateIfNotPresent(String path, String input) throws IOException, URISyntaxException, ClassNotFoundException {
if (current == null) { if (current == null) {
LanguageServerInterface languageServer = new LanguageServerInterface(); LanguageServerInterface languageServer = new LanguageServerInterface();
LanguageServerTransferObject transferObj = languageServer.getResultSetAndAbstractSyntax(path); LanguageServerTransferObject transferObj = languageServer.getResultSetAndAbstractSyntax(path, RESET_TO_LETTER);
return transferObj; return transferObj;
} }
return current; return current;
} }*/
public ArrayList<LSPVariable> infereChangeInput() throws IOException, ClassNotFoundException, URISyntaxException { public ArrayList<LSPVariable> infereChangeInput() throws IOException, ClassNotFoundException, URISyntaxException {
Set<PlaceholderVariable> tips = new HashSet<>(); Set<PlaceholderVariable> tips = new HashSet<>();
for (int i = 0; i < current.getResultSets().size(); i++) { tips.addAll(ASTTransformationHelper.createTypeInsertPoints(current.getAst(), generatedGenerics));
ResultSet tiResult = current.getResultSets().get(i);
tips.addAll(ASTTransformationHelper.createTypeInsertPoints(current.getAst(), tiResult, generatedGenerics.get(i)));
} HashMap<InsertPoint, List<PlaceholderVariable>> insertsOnLines = new HashMap<>();
HashMap<String, List<PlaceholderVariable>> insertsOnLines = new HashMap<>();
for (PlaceholderVariable insert : tips) { for (PlaceholderVariable insert : tips) {
if (!insertsOnLines.containsKey(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine())) { var insertPoint = new InsertPoint(insert.point.point.getLine(), insert.point.point.getCharPositionInLine());
insertsOnLines.put(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine(), new ArrayList<>(List.of(insert))); if (!insertsOnLines.containsKey(insertPoint)) {
insertsOnLines.put(insertPoint, new ArrayList<>(List.of(insert)));
} else { } else {
insertsOnLines.get(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine()).add(insert); insertsOnLines.get(insertPoint).add(insert);
} }
} }
inserts = insertsOnLines; inserts = insertsOnLines;
ArrayList<LSPVariable> variables = new ArrayList<>(insertsOnLines.entrySet().stream().map(el -> new LSPVariable("test", new ArrayList<>(el.getValue().stream().map(typeinsert -> new Type(typeinsert.getInsertString(), typeinsert.point.isGenericClassInsertPoint())).toList()), el.getValue().getFirst().point.point.getLine(), el.getValue().getFirst().point.point.getCharPositionInLine(), el.getValue().get(0).point.point.getStopIndex(), el.getValue().get(0).getResultPair().getLeft())).toList()); ArrayList<LSPVariable> variables = new ArrayList<>(
insertsOnLines.entrySet().stream().map(el -> {
var v = el.getValue().getFirst();
return new LSPVariable("test",
new ArrayList<>(el.getValue().stream()
.map(typeinsert -> new Type(typeinsert.getInsertString(), typeinsert.point.isGenericClassInsertPoint()))
.toList()),
v.point.point.getLine(),
v.point.point.getCharPositionInLine(),
v.point.point.getStopIndex(),
v.getType());
}
).toList()
);
for (var variable : variables) { for (var variable : variables) {
@@ -140,31 +139,30 @@ public class TypeResolver {
return variables; return variables;
} }
public ArrayList<LSPVariable> infereInput(String pathString, String input, boolean a) throws IOException, ClassNotFoundException, URISyntaxException { public record InferenceResult(ArrayList<LSPVariable> variables, List<CompilerWarning> warnings) {}
public InferenceResult infereInput(String pathString, String input) throws IOException, ClassNotFoundException, URISyntaxException {
System.setOut(new PrintStream(OutputStream.nullOutputStream())); System.setOut(new PrintStream(OutputStream.nullOutputStream()));
LanguageServerInterface languageServerInterface = new LanguageServerInterface(); LanguageServerInterface languageServerInterface = new LanguageServerInterface();
LanguageServerTransferObject lsTransfer = languageServerInterface.getResultSetAndAbstractSyntax(pathString); LanguageServerTransferObject lsTransfer = languageServerInterface.getResultSetAndAbstractSyntax(pathString, RESET_TO_LETTER);
var parsedSource = lsTransfer.getAst(); var parsedSource = lsTransfer.getAst();
var tiResults = lsTransfer.getResultSets();
Set<PlaceholderVariable> tips = new HashSet<>(); Set<PlaceholderVariable> tips = new HashSet<>();
generatedGenerics = lsTransfer.getGeneratedGenerics().get(lsTransfer.getAst()); generatedGenerics = lsTransfer.getGeneratedGenerics().get(lsTransfer.getAst());
for (int i = 0; i < tiResults.size(); i++) { tips.addAll(ASTTransformationHelper.createTypeInsertPoints(parsedSource, generatedGenerics));
ResultSet tiResult = tiResults.get(i);
tips.addAll(ASTTransformationHelper.createTypeInsertPoints(parsedSource, tiResult, lsTransfer.getGeneratedGenerics().get(lsTransfer.getAst()).get(i)));
}
System.setOut(System.out); System.setOut(System.out);
this.current = lsTransfer; this.current = lsTransfer;
HashMap<String, List<PlaceholderVariable>> insertsOnLines = new HashMap<>(); HashMap<InsertPoint, List<PlaceholderVariable>> insertsOnLines = new HashMap<>();
for (PlaceholderVariable insert : tips) { for (PlaceholderVariable insert : tips) {
if (!insertsOnLines.containsKey(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine())) { var insertPoint = new InsertPoint(insert.point.point.getLine(), insert.point.point.getCharPositionInLine());
insertsOnLines.put(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine(), new ArrayList<>(List.of(insert))); if (!insertsOnLines.containsKey(insertPoint)) {
insertsOnLines.put(insertPoint, new ArrayList<>(List.of(insert)));
} else { } else {
insertsOnLines.get(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine()).add(insert); insertsOnLines.get(insertPoint).add(insert);
} }
} }
@@ -181,8 +179,13 @@ public class TypeResolver {
for(PlaceholderVariable typeinsert : entrySet.getValue()){ for(PlaceholderVariable typeinsert : entrySet.getValue()){
typesOfVariable.add(new Type(typeinsert.getInsertString(), typeinsert.point.isGenericClassInsertPoint())); typesOfVariable.add(new Type(typeinsert.getInsertString(), typeinsert.point.isGenericClassInsertPoint()));
} }
variables.add(new LSPVariable("test",typesOfVariable , entrySet.getValue().getFirst().point.point.getLine(), entrySet.getValue().getFirst().point.point.getCharPositionInLine(), entrySet.getValue().get(0).point.point.getStopIndex(), entrySet.getValue().get(0).getResultPair().getLeft())); var variable = entrySet.getValue().getFirst();
variables.add(new LSPVariable("test", typesOfVariable,
variable.point.point.getLine(),
variable.point.point.getCharPositionInLine(),
variable.point.point.getStopIndex(),
variable.getType()));
} }
@@ -203,26 +206,7 @@ public class TypeResolver {
} }
return variables; return new InferenceResult(variables, lsTransfer.getWarnings());
}
public void reduceCurrent(HashMap<LineCharPosition, String> combinedList, List<LSPVariable> variables) {
for (var lines : combinedList.entrySet()) {
var contentChange = lines.getValue();
for (LSPVariable variable : variables) {
for (Type typeOfVariable : variable.getPossibleTypes()) {
if (typeOfVariable.getType().equalsIgnoreCase(contentChange.replaceAll(" ", ""))) {
if (variable.getLine() - 1 == lines.getKey().line && variable.getCharPosition() == lines.getKey().charPosition) {
current.getResultSets().removeIf(el -> !el.resolveType(variable.getOriginalTphName()).resolvedType.toString().equalsIgnoreCase(contentChange.replaceAll(" ", "")));
return;
}
}
}
}
}
} }
public SourceFile getNewAst(String uri) throws IOException, URISyntaxException, ClassNotFoundException { public SourceFile getNewAst(String uri) throws IOException, URISyntaxException, ClassNotFoundException {
@@ -233,7 +217,7 @@ public class TypeResolver {
public void updateAst(String uri) throws IOException, URISyntaxException, ClassNotFoundException { public void updateAst(String uri) throws IOException, URISyntaxException, ClassNotFoundException {
logger.info("Old AST:"); logger.info("Old AST:");
logger.info(ASTPrinter.print(this.current.getAst())); logger.info(ASTPrinter.print(this.current.getAst()));
this.current = new LanguageServerTransferObject(current.getResultSets(), getNewAst(uri), "", current.getGeneratedGenerics()); this.current = new LanguageServerTransferObject(getNewAst(uri), "", current.getConstraints(), current.getGeneratedGenerics(), current.getWarnings());
logger.info("NEW AST:"); logger.info("NEW AST:");
logger.info(ASTPrinter.print(current.getAst())); logger.info(ASTPrinter.print(current.getAst()));
@@ -1,5 +1,8 @@
package de.dhbw.model; package de.dhbw.model;
import de.dhbw.helper.ConversionHelper;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.target.generate.GenericsResultSet;
import de.dhbwstuttgart.typeinference.result.ResultPair; import de.dhbwstuttgart.typeinference.result.ResultPair;
import java.util.*; import java.util.*;
@@ -10,13 +13,14 @@ public class PlaceholderVariable {
*/ */
public final PlaceholderPoint point; public final PlaceholderPoint point;
Set<PlaceholderPoint> inserts; Set<PlaceholderPoint> inserts;
ResultPair<?, ?> resultPair; RefTypeOrTPHOrWildcardOrGeneric type;
private final GenericsResultSet constraints;
public PlaceholderVariable(PlaceholderPoint point, Set<PlaceholderPoint> additionalPoints, RefTypeOrTPHOrWildcardOrGeneric type, GenericsResultSet constraints) {
public PlaceholderVariable(PlaceholderPoint point, Set<PlaceholderPoint> additionalPoints, ResultPair<?, ?> resultPair) {
this.point = point; this.point = point;
this.constraints = constraints;
inserts = additionalPoints; inserts = additionalPoints;
this.resultPair = resultPair; this.type = type;
} }
public String insert(String intoSource) { public String insert(String intoSource) {
@@ -43,11 +47,11 @@ public class PlaceholderVariable {
} }
public void reducePackage() { public void reducePackage() {
point.setInsertString(point.getInsertString().replaceAll("java\\.lang\\.", "").replaceAll("java\\.util\\.", "")); point.setInsertString(ConversionHelper.cleanType(point.getInsertString()));
} }
public ResultPair<?, ?> getResultPair() { public RefTypeOrTPHOrWildcardOrGeneric getType() {
return this.resultPair; return this.type;
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
@@ -73,4 +77,8 @@ public class PlaceholderVariable {
public String toString() { public String toString() {
return point.toString(); return point.toString();
} }
public GenericsResultSet getConstraints() {
return constraints;
}
} }
@@ -36,7 +36,7 @@ public class CacheService {
this.typeInserts = typeInserts; this.typeInserts = typeInserts;
} }
public void reset(){ public void reset() {
globalInlayHintMap = new HashMap<>(); globalInlayHintMap = new HashMap<>();
lastSavedFiles = new HashMap<>(); lastSavedFiles = new HashMap<>();
currentlyCalculating = false; currentlyCalculating = false;
@@ -3,8 +3,12 @@ package de.dhbw.service;
import org.eclipse.lsp4j.*; import org.eclipse.lsp4j.*;
import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.services.LanguageServer;
import de.dhbw.JavaTXLanguageServer;
import java.util.List; import java.util.List;
import java.util.Map;
public class ClientService { public class ClientService {
@@ -39,21 +43,18 @@ public class ClientService {
this.client = client; this.client = client;
} }
public void updateClient(LanguageClient client) {
client.refreshInlayHints();
client.refreshDiagnostics();
}
public void updateClient() { public void updateClient() {
client.refreshInlayHints(); if (JavaTXLanguageServer.capabilities.getWorkspace().getInlayHint() != null)
client.refreshDiagnostics(); client.refreshInlayHints();
if (JavaTXLanguageServer.capabilities.getWorkspace().getDiagnostics() != null)
client.refreshDiagnostics();
} }
public LanguageClient getClient() { public LanguageClient getClient() {
return client; return client;
} }
public void startLoading(String taskName, String title, LanguageClient client) { public void startLoading(String taskName, String title) {
Either<String, Integer> token = Either.forLeft(taskName); Either<String, Integer> token = Either.forLeft(taskName);
client.createProgress(new WorkDoneProgressCreateParams(token)); client.createProgress(new WorkDoneProgressCreateParams(token));
@@ -67,7 +68,7 @@ public class ClientService {
} }
public void stopLoading(String taskName, String title, LanguageClient client) { public void stopLoading(String taskName, String title) {
Either<String, Integer> token = Either.forLeft(taskName); Either<String, Integer> token = Either.forLeft(taskName);
WorkDoneProgressEnd end = new WorkDoneProgressEnd(); WorkDoneProgressEnd end = new WorkDoneProgressEnd();
end.setMessage(title); end.setMessage(title);
+2 -1
View File
@@ -63,7 +63,8 @@ The Language Server in itself can be used for any Client. The Clients task is to
If you make changes in the Compiler Interface, you have to change the jar and therefore the Dependency in the Java TX Language Server If you make changes in the Compiler Interface, you have to change the jar and therefore the Dependency in the Java TX Language Server
You can follow this steps: You can follow this steps:
1. package the JavaTX Compiler 1. package the JavaTX Compiler
2. take the Jar-File and copy it into the /lib Folder 2. create a lib Folder at ./LangaugeServer -> ./LanguageServer/lib
2. take the Jar-File and copy it into the /lib Folder at
3. execute this Maven command to add the Jar in your local Repository: ```mvn install:install-file -Dfile=lib/JavaTXcompiler-0.1-jar-with-dependencies.jar -DgroupId=de.dhbwstuttgart -DartifactId=JavaTXcompiler -Dversion=0.1 -Dpackaging=jar``` 3. execute this Maven command to add the Jar in your local Repository: ```mvn install:install-file -Dfile=lib/JavaTXcompiler-0.1-jar-with-dependencies.jar -DgroupId=de.dhbwstuttgart -DartifactId=JavaTXcompiler -Dversion=0.1 -Dpackaging=jar```
4. run ```maven clean```, ```validate``` and ```install``` to load the new Dependency 4. run ```maven clean```, ```validate``` and ```install``` to load the new Dependency
5. you can now package the Language Server or change the code accordingly. 5. you can now package the Language Server or change the code accordingly.