Compare commits

..

2 Commits

Author SHA1 Message Date
Ruben 0d50cf1517 feat: [NOT WORKING] maybe slowly starts working 2025-09-15 17:11:20 +02:00
Ruben 39876f3866 feat: [NOT WORKING] add initial Version of async calculation of compiler 2025-09-15 15:47:14 +02:00
26 changed files with 1223 additions and 3097 deletions
+2 -2
View File
@@ -1,3 +1,3 @@
# Java-TX Language Server # lspclient README
This is the official Plugin for Java-TX. This is the README for the Java-TX LSP Client.
+635 -2574
View File
File diff suppressed because it is too large Load Diff
+1 -14
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.21", "version": "0.0.5",
"engines": { "engines": {
"vscode": "^1.94.0" "vscode": "^1.94.0"
}, },
@@ -20,18 +20,6 @@
"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": {
@@ -54,7 +42,6 @@
"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"
} }
} }
+22 -59
View File
@@ -1,71 +1,32 @@
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 | null { function createClient(context: vscode.ExtensionContext): LanguageClient {
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: cmd, run: {
debug: cmd command: 'java',
args: ['-Xss2m', '-jar', workspaceFolder + "/JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar"],
},
debug: {
command: 'java',
args: [
'-Xss2m',
'-jar',
workspaceFolder + '/JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar',
],
}
}; };
const clientOptions: LanguageClientOptions = { const clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: 'file', pattern: '**/*.jav' }], documentSelector: [{ scheme: 'file', language: 'java' }],
synchronize: { synchronize: {
fileEvents: vscode.workspace.createFileSystemWatcher('**/*.jav') fileEvents: vscode.workspace.createFileSystemWatcher('**/*.jav')
}, },
@@ -81,9 +42,7 @@ function createClient(context: vscode.ExtensionContext): LanguageClient | null {
} }
export async function activate(context: vscode.ExtensionContext) { export async function activate(context: vscode.ExtensionContext) {
const c = createClient(context); client = 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"))
@@ -91,6 +50,12 @@ 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) {
@@ -103,9 +68,7 @@ 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);
} }
const c = createClient(context); // komplett neu erzeugen client = 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
@@ -1,11 +0,0 @@
## 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
@@ -1,84 +0,0 @@
;;; 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))
+45 -29
View File
@@ -14,22 +14,61 @@
<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.13.2</version> <version>4.11.1</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.14.0</version> <version>5.10.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>
@@ -39,7 +78,6 @@
<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>
@@ -72,6 +110,7 @@
<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>
@@ -95,29 +134,6 @@
</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>
@@ -17,7 +17,6 @@ import java.util.concurrent.CompletableFuture;
* */ * */
public class JavaTXLanguageServer implements LanguageServer { public class JavaTXLanguageServer implements LanguageServer {
private static final Logger logger = LogManager.getLogger(JavaTXLanguageServer.class); 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) {
@@ -49,7 +48,6 @@ 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));
} }
@@ -55,7 +55,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
this.logService = new LogService(clientService); 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);
this.saveHandler = new SaveHandler(typeResolver, textDocumentService, logService, cacheService, conversionHelper, clientService, parserService); this.saveHandler = new SaveHandler(typeResolver, textDocumentService, logService, cacheService, conversionHelper, clientService, parserService);
this.changeHandler = new ChangeHandler(textDocumentService, parserService, conversionHelper, clientService, typeResolver, cacheService, logService); this.changeHandler = new ChangeHandler(textDocumentService, parserService, conversionHelper, clientService, typeResolver, cacheService, logService);
} }
@@ -113,7 +113,8 @@ 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);
} }
clientService.updateClient(); client.refreshDiagnostics();
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());
} }
@@ -153,10 +154,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..."); clientService.startLoading("compile-task", "Inferring types...", client);
saveHandler.handleSave(didSaveTextDocumentParams); saveHandler.asyncHandle(didSaveTextDocumentParams);
clientService.stopLoading("compile-task", "Types successfully inferred"); clientService.stopLoading("compile-task", "Types successfully inferred", client);
clientService.updateClient(); clientService.updateClient(client);
} }
@Override @Override
@@ -297,9 +298,7 @@ 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);
var triggerKind = params.getContext().getTriggerKind(); logService.log("Code-Action Context was: " + params.getContext().getTriggerKind().name(), MessageType.Info);
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,7 +3,6 @@ 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;
@@ -14,8 +13,6 @@ import org.eclipse.lsp4j.*;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.net.URI;
import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@@ -81,8 +78,6 @@ 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.");
@@ -98,7 +93,7 @@ public class ChangeHandler {
logService.log("Type is here: " + type); logService.log("Type is here: " + type);
for (LSPVariable variable : cacheService.getVariables()) { for (LSPVariable variable : cacheService.getVariables()) {
for (Type variableType : variable.getPossibleTypes()) { for (Type variableType : variable.getPossibleTypes()) {
logService.log(variableType.getType() + " <> " + type.replaceAll(" ", "") + ": " + type.replaceAll(" ", "").contains(variableType.getType().replaceAll(" ", ""))); logService.log(variableType.getType() + " <> "+ type.replaceAll(" ", "") + ": " + type.replaceAll(" ", "").contains(variableType.getType().replaceAll(" ", "")));
shouldCalculate = shouldCalculate || type.replaceAll(" ", "").contains(variableType.getType().replaceAll(" ", "")); shouldCalculate = shouldCalculate || type.replaceAll(" ", "").contains(variableType.getType().replaceAll(" ", ""));
if (shouldCalculate) { if (shouldCalculate) {
break; break;
@@ -108,69 +103,68 @@ public class ChangeHandler {
logService.log("Should Calculate is: " + shouldCalculate); logService.log("Should Calculate is: " + shouldCalculate);
if (false) {
/*try { try {
File tempDir = new File(System.getProperty("java.io.tmpdir")); File tempDir = new File(System.getProperty("java.io.tmpdir"));
File tempFile = File.createTempFile("newText", ".tmp", tempDir); File tempFile = File.createTempFile("newText", ".tmp", tempDir);
FileWriter fileWriter = new FileWriter(tempFile, true); FileWriter fileWriter = new FileWriter(tempFile, true);
System.out.println(tempFile.getAbsolutePath()); System.out.println(tempFile.getAbsolutePath());
BufferedWriter bw = new BufferedWriter(fileWriter); BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(summedUp.get()); bw.write(summedUp.get());
bw.close(); bw.close();
typeResolver.updateAst(tempFile.toURI().getPath()); typeResolver.updateAst(tempFile.toURI().getPath());
tempFile.delete(); tempFile.delete();
} catch (Exception e) { } catch (Exception e) {
logService.log(e.getMessage()); 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()); var sWatch = Stopwatch.createUnstarted();
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.getTextDocument().getUri()); sWatch.start();
} 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 {
try { try {
File tempDir2 = Path.of(new URI(params.getTextDocument().getUri())).getParent().toFile(); ArrayList<LSPVariable> typesOfMethodAndParameters = typeResolver.infereChangeInput();
File tempFile2 = File.createTempFile("jtx_temp", ".tmp", tempDir2); DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehints(typesOfMethodAndParameters, params.getTextDocument().getUri());
FileWriter fileWriter = new FileWriter(tempFile2, true);
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(input);
bw.close();
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 {
InferenceResult inferenceResult = typeResolver.infereInput(tempFile2.toURI().toString(), input); File tempDir2 = new File(System.getProperty("java.io.tmpdir"));
cacheService.setVariables(inferenceResult.variables()); File tempFile2 = File.createTempFile("newText", ".tmp", tempDir2);
FileWriter fileWriter = new FileWriter(tempFile2, true);
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(input);
bw.close();
DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehintsWithInput(inferenceResult, input); ArrayList<LSPVariable> variables = typeResolver.infereInput(tempFile2.toURI().toString(), input, false);
cacheService.setVariables(variables);
DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehintsWithInput(variables, input);
List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints(); List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints();
List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics(); List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics();
@@ -178,31 +172,32 @@ public class ChangeHandler {
cacheService.updateGlobalMaps(diagnostics, typeHint, params.getTextDocument().getUri()); cacheService.updateGlobalMaps(diagnostics, typeHint, params.getTextDocument().getUri());
List<Diagnostic> allDiagnostics = new ArrayList<>(diagnostics); List<Diagnostic> allDiagnostics = new ArrayList<>(diagnostics);
allDiagnostics.addAll(parserService.getDiagnosticsOfErrors(input, params.getTextDocument().getUri()));
clientService.publishDiagnostics(params.getTextDocument().getUri(), allDiagnostics); clientService.publishDiagnostics(params.getTextDocument().getUri(), allDiagnostics);
} catch (Exception | VerifyError f) {
logService.log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + f.getMessage(), MessageType.Error);
for (StackTraceElement elem : f.getStackTrace()) { 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, f.getMessage() == null ? "null" : f.getMessage()); clientService.showMessage(MessageType.Error, e.getMessage() == null ? "null" : e.getMessage());
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.getTextDocument().getUri()); 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);
clientService.showMessage(MessageType.Error, e.getMessage() == null ? "null" : e.getMessage());
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.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);
}
} catch (Exception e) {
logService.log(e.getMessage());
} }
} catch (Exception e) {
logService.log(e.getMessage());
} }
} }
} }
} }
@@ -1,8 +1,5 @@
package de.dhbw.handler; package de.dhbw.handler;
import de.dhbw.helper.ASTTransformationHelper;
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;
@@ -25,15 +22,13 @@ public class CodeActionHandler {
private final CacheService cacheService; private final CacheService cacheService;
private final TypeResolver typeResolver; private final TypeResolver typeResolver;
private final LogService logService; private final LogService logService;
private final ConversionHelper conversionHelper;
public CodeActionHandler(TextHelper textHelper, TextDocumentService textDocumentService, CacheService cacheService, TypeResolver typeResolver, LogService logService, ConversionHelper conversionHelper) { public CodeActionHandler(TextHelper textHelper, TextDocumentService textDocumentService, CacheService cacheService, TypeResolver typeResolver, LogService logService) {
this.textHelper = textHelper; this.textHelper = textHelper;
this.textDocumentService = textDocumentService; this.textDocumentService = textDocumentService;
this.cacheService = cacheService; this.cacheService = cacheService;
this.typeResolver = typeResolver; this.typeResolver = typeResolver;
this.logService = logService; this.logService = logService;
this.conversionHelper = conversionHelper;
} }
public static Range wholeDocumentRange(String text) { public static Range wholeDocumentRange(String text) {
@@ -70,8 +65,8 @@ public class CodeActionHandler {
} }
public static <V> Map<InsertPoint, V> getOverlapping( public static <V> Map<String, V> getOverlapping(
Map<InsertPoint, V> map, Map<String, V> map,
int line, int line,
int startChar, int startChar,
int endChar int endChar
@@ -85,13 +80,20 @@ 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 -> {
InsertPoint key = entry.getKey(); String key = entry.getKey();
int kLine = key.line(); String[] parts = key.split("\\s+");
int kChar = key.character(); if (parts.length != 2) return false;
return kLine == line && kChar >= s && kChar <= e; try {
}) int kLine = Integer.parseInt(parts[0]);
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); int kChar = Integer.parseInt(parts[1]);
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));
} }
@@ -100,53 +102,41 @@ public class CodeActionHandler {
String documentUri = params.getTextDocument().getUri(); String documentUri = params.getTextDocument().getUri();
Range rangeOfInsert = params.getRange(); Range rangeOfInsert = params.getRange();
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<>();
for (var typeInsertList : typeInsertsOverlapping.values()) { for (var typeInsertList : typeInsertsOverlapping.values()) {
for (var typeInsert : typeInsertList) { for (var typeInsert : typeInsertList) {
try { try {
logService.log("NEW TEXT OF FILE BEFORE INSERT IS:"); String typeWithReplacedVariable = typeInsert.insert(textDocumentService.getFileOfUri(documentUri));
logService.log(textDocumentService.getFileOfUri(documentUri));
String typeWithReplacedVariable = typeInsert.insert(textDocumentService.getFileOfUri(documentUri));
ArrayList<TextEdit> listOfChanges = new ArrayList<>(); ArrayList<TextEdit> listOfChanges = new ArrayList<>();
listOfChanges.add(new TextEdit(wholeDocumentRange(textDocumentService.getFileOfUri(documentUri)), typeWithReplacedVariable)); listOfChanges.add(new TextEdit(wholeDocumentRange(textDocumentService.getFileOfUri(documentUri)), typeWithReplacedVariable));
Map<String, List<TextEdit>> changes = new HashMap<>(); var isTypeImported = false;
changes.put(documentUri, listOfChanges);
WorkspaceEdit edit = new WorkspaceEdit(); Map<String, List<TextEdit>> changes = new HashMap<>();
edit.setChanges(changes); changes.put(documentUri, listOfChanges);
var constraints = typeInsert.getConstraints(); WorkspaceEdit edit = new WorkspaceEdit();
var genericsString = ""; edit.setChanges(changes);
if (constraints != null && !constraints.isEmpty()) {
genericsString = ASTTransformationHelper.createConstraintsString(constraints);
}
CodeAction action = new CodeAction("Insert " + ConversionHelper.cleanType(typeInsert.getInsertString()) + genericsString);
action.setKind(CodeActionKind.QuickFix);
action.setEdit(edit);
if(!actions.stream().map(el -> el.getRight().getTitle()).toList().contains(action.getTitle())){ CodeAction action = new CodeAction("Insert " + typeInsert.getInsertString());
actions.add(Either.forRight(action)); action.setKind(CodeActionKind.QuickFix);
} action.setEdit(edit);
} catch (Exception e) { actions.add(Either.forRight(action));
logService.log("Error creating Actions, returning empty List. The Error was: " + e.getMessage(), MessageType.Error); } catch (Exception e) {
} logService.log("Error creating Actions, returning empty List. The Error was: " + e.getMessage(), MessageType.Error);
} }
} }
return actions;
} }
return actions;
return new ArrayList<>();
} }
public List<Either<Command, CodeAction>> handleCodeAction(CodeActionParams params) { public List<Either<Command, CodeAction>> handleCodeAction(CodeActionParams params) {
@@ -1,18 +1,27 @@
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.helper.ResultListener;
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.core.JavaTXCompiler;
import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface; import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface;
import de.dhbwstuttgart.languageServerInterface.model.ParserError; import de.dhbwstuttgart.languageServerInterface.model.ParserError;
import de.dhbwstuttgart.syntaxtree.SourceFile;
import de.dhbwstuttgart.target.generate.GenerateGenerics;
import de.dhbwstuttgart.target.generate.GenericsResult;
import de.dhbwstuttgart.typeinference.result.ResultSet;
import org.apache.commons.io.output.NullOutputStream;
import org.eclipse.lsp4j.*; import org.eclipse.lsp4j.*;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.net.URI; import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
@@ -53,23 +62,22 @@ 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);
} }
InferenceResult inferenceResult = typeResolver.infereInput(didSaveTextDocumentParams.getTextDocument().getUri(), fileInput); ArrayList<LSPVariable> variables = typeResolver.infereInput(didSaveTextDocumentParams.getTextDocument().getUri(), fileInput, false);
cacheService.setVariables(inferenceResult.variables()); cacheService.setVariables(variables);
DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehints(inferenceResult, didSaveTextDocumentParams.getTextDocument().getUri()); DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehints(variables, didSaveTextDocumentParams.getTextDocument().getUri());
List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints(); List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints();
List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics(); List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics();
@@ -82,15 +90,42 @@ public class SaveHandler {
} }
} catch (Exception | VerifyError e) { } catch (Exception 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);
} }
} }
public void asyncHandle(DidSaveTextDocumentParams didSaveTextDocumentParams) {
var sWatch = Stopwatch.createUnstarted();
sWatch.start();
try {
ResultListener resultListener = new ResultListener(typeResolver, didSaveTextDocumentParams, cacheService, conversionHelper, clientService);
resultListener.init(didSaveTextDocumentParams);
} 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());
}
clientService.showMessage(MessageType.Error, e.getMessage() == null ? "null" : e.getMessage());
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), didSaveTextDocumentParams.getTextDocument().getUri());
}
}
} }
@@ -15,13 +15,12 @@ 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.Optional;
import java.util.Set; import java.util.Set;
public class ASTTransformationHelper { public class ASTTransformationHelper {
public static Set<PlaceholderVariable> createTypeInsertPoints(SourceFile forSourcefile, GenericsResult generics) { public static Set<PlaceholderVariable> createTypeInsertPoints(SourceFile forSourcefile, ResultSet withResults, GenericsResult generics) {
return new PlaceholderPlacer(forSourcefile, generics).getTypeInserts(); return new PlaceholderPlacer().getTypeInserts(forSourcefile, withResults, generics);
} }
public static PlaceholderVariable createInsertPoints(RefTypeOrTPHOrWildcardOrGeneric type, Token offset, ClassOrInterface cl, Method m, public static PlaceholderVariable createInsertPoints(RefTypeOrTPHOrWildcardOrGeneric type, Token offset, ClassOrInterface cl, Method m,
@@ -30,20 +29,27 @@ public class ASTTransformationHelper {
ResolvedType resolvedType = resultSet.resolveType(type); ResolvedType resolvedType = resultSet.resolveType(type);
PlaceholderPoint insertPoint = new PlaceholderPoint(offset, PlaceholderPoint insertPoint = new PlaceholderPoint(offset,
new PlaceholderToInsertString(resolvedType.resolvedType, constraints, classConstraints).insert, PlaceholderType.NORMAL_INSERT); new PlaceholderToInsertString(resolvedType.resolvedType, constraints, classConstraints).insert, PlaceholderType.NORMAL_INSERT);
return new PlaceholderVariable(insertPoint, createGenericInsert(constraints, classConstraints, cl, m, offset), resolvedType.getResultPair(), constraints); return new PlaceholderVariable(insertPoint, createGenericInsert(constraints, classConstraints, cl, m, resultSet, offset), resolvedType.getResultPair());
} }
private static synchronized Set<PlaceholderPoint> createGenericInsert(GenericsResultSet methodConstraints, GenericsResultSet classConstraints, ClassOrInterface cl, Method m, Token mOffset){ private static synchronized Set<PlaceholderPoint> createGenericInsert(GenericsResultSet methodConstraints, GenericsResultSet classConstraints, ClassOrInterface cl, Method m, ResultSet resultSet, Token mOffset){
Set<PlaceholderPoint> result = createGenericClassInserts(classConstraints, cl); Set<PlaceholderPoint> result = createGenericClassInserts(classConstraints, cl);
if (m != null) { if (m != null) {
createMethodConstraints(methodConstraints, m.getOffset() != null ? m.getOffset() : mOffset).ifPresent(result::add); result.addAll(createMethodConstraints(methodConstraints, m.getOffset() != null ? m.getOffset() : mOffset));
} }
return result; return result;
} }
private static Set<PlaceholderPoint> createMethodConstraints(GenericsResultSet constraints, Token mOffset) {
Set<PlaceholderPoint> result = new HashSet<>();
Token offset = mOffset;
public static String createConstraintsString(GenericsResultSet constraints) { if (constraints.size() == 0) {
return result;
}
String insert = " <"; String insert = " <";
for (var genericInsertConstraint : constraints) { for (var genericInsertConstraint : constraints) {
@@ -57,16 +63,9 @@ public class ASTTransformationHelper {
insert = insert.substring(0, insert.length() -2); insert = insert.substring(0, insert.length() -2);
insert += ">"; insert += ">";
return insert; result.add(new PlaceholderPoint(offset, insert, PlaceholderType.GENERERIC_METHOD_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) {
@@ -76,7 +75,23 @@ 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,11 +1,9 @@
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.*;
@@ -22,17 +20,12 @@ public class ConversionHelper {
this.textDocumentService = textDocumentService; this.textDocumentService = textDocumentService;
} }
public static String cleanType(String type) {
// 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) {
InlayHint inlayHint = new InlayHint(); InlayHint inlayHint = new InlayHint();
String typeDisplay = ""; String typeDisplay = "";
for (Type type : variable.getPossibleTypes()) { for (Type type : variable.getPossibleTypes()) {
typeDisplay += "| " + cleanType(type.getType().replaceAll("GTV ", "")); typeDisplay += " | " + type.getType().replaceAll("GTV ", "");
} }
@@ -52,7 +45,7 @@ public class ConversionHelper {
Diagnostic diagnostic = new Diagnostic( Diagnostic diagnostic = new Diagnostic(
errorRange, errorRange,
//TODO: REMOVE! Temporary Fix because GTV, like TPH can be thrown away in the TypeResolver //TODO: REMOVE! Temporary Fix because GTV, like TPH can be thrown away in the TypeResolver
cleanType(type.getType().replaceAll("GTV ", "")), type.getType().replaceAll("GTV ", ""),
DiagnosticSeverity.Hint, DiagnosticSeverity.Hint,
"JavaTX Language Server" "JavaTX Language Server"
); );
@@ -69,7 +62,7 @@ public class ConversionHelper {
Diagnostic diagnostic = new Diagnostic( Diagnostic diagnostic = new Diagnostic(
errorRange, errorRange,
//TODO: REMOVE! Temporary Fix because GTV, like TPH can be thrown away in the TypeResolver //TODO: REMOVE! Temporary Fix because GTV, like TPH can be thrown away in the TypeResolver
cleanType(type.getType().replaceAll("GTV ", "")), type.getType().replaceAll("GTV ", ""),
DiagnosticSeverity.Hint, DiagnosticSeverity.Hint,
"JavaTX Language Server" "JavaTX Language Server"
); );
@@ -78,7 +71,7 @@ public class ConversionHelper {
return diagnostic; return diagnostic;
} }
public List<Diagnostic> parseErrorToDiagnostic(List<ParserError> parserErrors) { public List<Diagnostic> parseErrorToDiagnostic(List<ParserError> parserErrors){
return parserErrors.stream().map(el -> { return parserErrors.stream().map(el -> {
Range errorRange = new Range( Range errorRange = new Range(
new Position(el.getLine() - 1, el.getCharPositionInLine()), // Startposition new Position(el.getLine() - 1, el.getCharPositionInLine()), // Startposition
@@ -93,35 +86,11 @@ public class ConversionHelper {
}).toList(); }).toList();
} }
public DiagnosticsAndTypehints addWarningsToDiagnostics(DiagnosticsAndTypehints diagnosticsAndTypehints, List<CompilerWarning> warnings) { public DiagnosticsAndTypehints variablesToDiagnosticsAndTypehints(ArrayList<LSPVariable> typesOfMethodAndParameters, String uri){
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 : variables) { for (var variable : typesOfMethodAndParameters) {
InlayHint inlayHint = getInlayHint(variable); InlayHint inlayHint = getInlayHint(variable);
typeHint.add(inlayHint); typeHint.add(inlayHint);
@@ -134,12 +103,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 : inferenceResult.variables()) { for (var variable : typesOfMethodAndParameters) {
InlayHint inlayHint = getInlayHint(variable); InlayHint inlayHint = getInlayHint(variable);
typeHint.add(inlayHint); typeHint.add(inlayHint);
@@ -150,6 +118,6 @@ public class ConversionHelper {
} }
} }
return addWarningsToDiagnostics(new DiagnosticsAndTypehints(diagnostics, typeHint), inferenceResult.warnings()); return new DiagnosticsAndTypehints(diagnostics, typeHint);
} }
} }
@@ -1,3 +0,0 @@
package de.dhbw.helper;
public record InsertPoint(int line, int character) {}
@@ -3,32 +3,28 @@ package de.dhbw.helper;
import de.dhbw.model.PlaceholderVariable; import de.dhbw.model.PlaceholderVariable;
import de.dhbwstuttgart.syntaxtree.*; import de.dhbwstuttgart.syntaxtree.*;
import de.dhbwstuttgart.target.generate.GenericsResult; import de.dhbwstuttgart.target.generate.GenericsResult;
import de.dhbwstuttgart.typeinference.result.ResultSet;
import java.util.HashSet; import java.util.HashSet;
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 GenericsResult genericsResult;
private SourceFile forSourceFile;
public PlaceholderPlacer(SourceFile forSourceFile, GenericsResult genericsResult) { public Set<PlaceholderVariable> getTypeInserts(SourceFile forSourceFile, ResultSet withResults, GenericsResult genericsResult){
this.forSourceFile = forSourceFile; this.withResults = withResults;
this.genericsResult = genericsResult; this.genericsResult = genericsResult;
this.pkgName = forSourceFile.getPkgName(); pkgName = forSourceFile.getPkgName();
} forSourceFile.accept(this);
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, genericsResult); de.dhbw.helper.PlaceholderPlacerClass cl = new de.dhbw.helper.PlaceholderPlacerClass(classOrInterface, withResults, genericsResult);
this.inserts.addAll(cl.inserts); this.inserts.addAll(cl.inserts);
} }
} }
@@ -21,10 +21,10 @@ class PlaceholderPlacerClass extends AbstractASTWalker{
GenericsResultSet constraints; GenericsResultSet constraints;
GenericsResultSet classConstraints; GenericsResultSet classConstraints;
PlaceholderPlacerClass(ClassOrInterface forClass, GenericsResult generatedGenerics) { PlaceholderPlacerClass(ClassOrInterface forClass, ResultSet withResults, GenericsResult generatedGenerics){
this.cl = forClass; this.cl = forClass;
this.method = null; this.method = null;
this.results = generatedGenerics.getGenerics().getResultSet(); this.results = withResults;
this.generatedGenerics = generatedGenerics; this.generatedGenerics = generatedGenerics;
forClass.accept(this); forClass.accept(this);
} }
@@ -32,7 +32,7 @@ class PlaceholderPlacerClass extends AbstractASTWalker{
@Override @Override
public void visit(Method method) { public void visit(Method method) {
this.method = method; this.method = method;
constraints = generatedGenerics.get(cl, method); constraints = generatedGenerics.get(method);
classConstraints = generatedGenerics.get(cl); classConstraints = generatedGenerics.get(cl);
if(method.getReturnType() instanceof TypePlaceholder) if(method.getReturnType() instanceof TypePlaceholder)
inserts.add(ASTTransformationHelper.createInsertPoints( inserts.add(ASTTransformationHelper.createInsertPoints(
@@ -1,7 +1,6 @@
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.*;
@@ -61,14 +60,14 @@ public class PlaceholderToInsertString implements ResultSetVisitor{
@Override @Override
public void visit(TypePlaceholder typePlaceholder) { public void visit(TypePlaceholder typePlaceholder) {
GenerateGenerics.Pair resultPair = null; ResultPair<?, ?> 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 += resultPair.left.toString(); insert += ((TypePlaceholder)resultPair.getLeft()).getName();
} }
@Override @Override
@@ -0,0 +1,6 @@
package de.dhbw.helper;
public class Recalculator {
}
@@ -0,0 +1,123 @@
package de.dhbw.helper;
import com.google.common.base.Stopwatch;
import de.dhbw.handler.SaveHandler;
import de.dhbw.model.DiagnosticsAndTypehints;
import de.dhbw.model.LSPVariable;
import de.dhbw.service.CacheService;
import de.dhbw.service.ClientService;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.syntaxtree.SourceFile;
import de.dhbwstuttgart.target.generate.GenericsResult;
import de.dhbwstuttgart.typeinference.unify.UnifyResultEvent;
import de.dhbwstuttgart.typeinference.unify.UnifyResultListener;
import org.apache.commons.io.output.NullOutputStream;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DidSaveTextDocumentParams;
import org.eclipse.lsp4j.InlayHint;
import org.eclipse.lsp4j.MessageType;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
public class ResultListener implements UnifyResultListener {
TypeResolver typeResolver;
SourceFile ast;
DidSaveTextDocumentParams didSaveTextDocumentParams;
CacheService cacheService;
ConversionHelper conversionHelper;
ClientService clientService;
JavaTXCompiler compiler;
SourceFile sourceFile;
public ResultListener(TypeResolver saveHandler, DidSaveTextDocumentParams didSaveTextDocumentParams, CacheService cacheService, ConversionHelper conversionHelper, ClientService clientService){
this.typeResolver = saveHandler;
this.didSaveTextDocumentParams = didSaveTextDocumentParams;
this.cacheService = cacheService;
this.conversionHelper = conversionHelper;
this.clientService = clientService;
}
public void init(DidSaveTextDocumentParams didSaveTextDocumentParams){
var sWatch = Stopwatch.createUnstarted();
sWatch.start();
try {
System.setOut(new PrintStream(OutputStream.nullOutputStream()));
var uri = new URI(didSaveTextDocumentParams.getTextDocument().getUri());
var path = Path.of(uri);
var file = path.toFile();
Files.createDirectories(path.getParent().resolve("out"));
this.compiler = new JavaTXCompiler(file, false);
sourceFile = compiler.sourceFiles.get(file);
compiler.typeInferenceAsync(this, new OutputStreamWriter(new NullOutputStream()));
} catch (Exception e) {
clientService.sendClientLog("KRITISCHE");
clientService.showMessage(MessageType.Error, e.getMessage() == null ? "null" : e.getMessage());
for (StackTraceElement stack : e.getStackTrace()){
clientService.sendClientLog(stack.toString());
}
cacheService.updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), didSaveTextDocumentParams.getTextDocument().getUri());
}
}
@Override
public void onNewTypeResultFound(UnifyResultEvent unifyResultEvent) {
try {
clientService.sendClientLog("YEEEEEEEEEEEP: " + (unifyResultEvent.getNewTypeResult() == null ? "Null" : "Nicht null"));
List<LSPVariable> lspVariables = typeResolver.infereIncremental(unifyResultEvent.getNewTypeResult(), this.compiler.getGeneratedGenerics().get(sourceFile), ast);
if(cacheService.getVariables() == null){
clientService.sendClientLog("Variablen null");
cacheService.setVariables(new ArrayList<>());
}
cacheService.getVariables().addAll(lspVariables);
DiagnosticsAndTypehints diagnosticsAndTypehints = conversionHelper.variablesToDiagnosticsAndTypehints(new ArrayList<>(lspVariables), didSaveTextDocumentParams.getTextDocument().getUri());
clientService.sendClientLog("Diagnostiken erstellt");
List<InlayHint> typeHint = diagnosticsAndTypehints.getInlayHints();
List<Diagnostic> diagnostics = diagnosticsAndTypehints.getDiagnostics();
cacheService.getGlobalInlayHintMap().computeIfAbsent(didSaveTextDocumentParams.getTextDocument().getUri(), k -> new ArrayList<>());
cacheService.getGlobalDiagnosticsMap().computeIfAbsent(didSaveTextDocumentParams.getTextDocument().getUri(), k -> new ArrayList<>());
cacheService.getGlobalInlayHintMap().get(didSaveTextDocumentParams.getTextDocument().getUri()).addAll(typeHint);
cacheService.getGlobalDiagnosticsMap().get(didSaveTextDocumentParams.getTextDocument().getUri()).addAll(diagnostics);
clientService.sendClientLog("paaaaaaaaaaaaast");
clientService.publishDiagnostics(didSaveTextDocumentParams.getTextDocument().getUri(), cacheService.getGlobalDiagnosticsMap().get(didSaveTextDocumentParams.getTextDocument().getUri()));
} catch (IOException e) {
clientService.sendClientLog("KOMISCHER FEHLER!");
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
clientService.sendClientLog("KOMISCHER FEHLER!");
throw new RuntimeException(e);
} catch (URISyntaxException e) {
clientService.sendClientLog("KOMISCHER FEHLER!");
throw new RuntimeException(e);
}
}
}
@@ -3,21 +3,30 @@ package de.dhbw.helper;
import de.dhbw.model.*; import de.dhbw.model.*;
import de.dhbw.model.PlaceholderVariable; 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
*/ */
@@ -28,10 +37,10 @@ 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<InsertPoint, List<PlaceholderVariable>> inserts; private HashMap<String, List<PlaceholderVariable>> inserts;
public HashMap<InsertPoint, List<PlaceholderVariable>> getInserts() { public HashMap<String, List<PlaceholderVariable>> getInserts() {
return inserts; return inserts;
} }
@@ -41,7 +50,9 @@ public class TypeResolver {
private LanguageServerTransferObject current; private LanguageServerTransferObject current;
public void reset() { public void reset() {
this.current = null; HashMap<String, List<TypeInsert>> inserts = null;
List<GenericsResult> generatedGenerics = null;
current = null;
} }
@@ -71,7 +82,7 @@ public class TypeResolver {
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.getResultSetAndAbstractSyntax(path, RESET_TO_LETTER); var transferObj = languageServer.getResultSetAndAbastractSyntax(path, RESET_TO_LETTER);
current = transferObj; current = transferObj;
} }
@@ -88,37 +99,25 @@ public class TypeResolver {
Set<PlaceholderVariable> tips = new HashSet<>(); Set<PlaceholderVariable> tips = new HashSet<>();
for (var results : generatedGenerics) { for (int i = 0; i < current.getResultSets().size(); i++) {
tips.addAll(ASTTransformationHelper.createTypeInsertPoints(current.getAst(), results)); 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) {
var insertPoint = new InsertPoint(insert.point.point.getLine(), insert.point.point.getCharPositionInLine()); if (!insertsOnLines.containsKey(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine())) {
if (!insertsOnLines.containsKey(insertPoint)) { insertsOnLines.put(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine(), new ArrayList<>(List.of(insert)));
insertsOnLines.put(insertPoint, new ArrayList<>(List.of(insert)));
} else { } else {
insertsOnLines.get(insertPoint).add(insert); insertsOnLines.get(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine()).add(insert);
} }
} }
inserts = insertsOnLines; inserts = insertsOnLines;
ArrayList<LSPVariable> variables = new ArrayList<>( 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());
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.getResultPair().getLeft());
}
).toList()
);
for (var variable : variables) { for (var variable : variables) {
@@ -141,32 +140,48 @@ public class TypeResolver {
return variables; return variables;
} }
public record InferenceResult(ArrayList<LSPVariable> variables, List<CompilerWarning> warnings) {} public ArrayList<LSPVariable> infereInput(String pathString, String input, boolean a) throws IOException, ClassNotFoundException, URISyntaxException {
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(); var uri = new URI(pathString);
LanguageServerTransferObject lsTransfer = languageServerInterface.getResultSetAndAbstractSyntax(pathString); var path = Path.of(uri);
var parsedSource = lsTransfer.getAst(); logger.info("Path is for calculation: " + path.toString());
var file = path.toFile();
Files.createDirectories(path.getParent().resolve("out"));
JavaTXCompiler compiler = new JavaTXCompiler(List.of(file), List.of(path.getParent().toFile()), path.getParent().resolve("out").toFile());
var parsedSource = compiler.sourceFiles.get(file);
var tiResults = compiler.typeInference(file);
Set<PlaceholderVariable> tips = new HashSet<>(); Set<PlaceholderVariable> tips = new HashSet<>();
generatedGenerics = lsTransfer.getGeneratedGenerics().get(lsTransfer.getAst()); // for (var sf : compiler.sourceFiles.values()) {
for (var generics : generatedGenerics) { // Map<JavaClassName, byte[]> bytecode = compiler.generateBytecode(sf, tiResults);
tips.addAll(ASTTransformationHelper.createTypeInsertPoints(parsedSource, generics)); // logger.info("Path for Class-File is: " + path.getParent().resolve("out").toFile());
// Files.createDirectories(path.getParent().resolve("out"));
// compiler.writeClassFile(bytecode, path.getParent().resolve("out").toFile(), false);
//
// }
Map<JavaClassName, byte[]> bytecode = compiler.generateBytecode(parsedSource, tiResults);
logger.info("Path for Class-File is: " + path.getParent().resolve("out").toFile());
Files.createDirectories(path.getParent().resolve("out"));
compiler.writeClassFile(bytecode, path.getParent().resolve("out").toFile(), false);
generatedGenerics = compiler.getGeneratedGenerics().get(compiler.sourceFiles.get(file));
for (int i = 0; i < tiResults.size(); i++) {
ResultSet tiResult = tiResults.get(i);
tips.addAll(ASTTransformationHelper.createTypeInsertPoints(parsedSource, tiResult, compiler.getGeneratedGenerics().get(compiler.sourceFiles.get(file)).get(i)));
} }
System.setOut(System.out); System.setOut(System.out);
this.current = lsTransfer; this.current = new LanguageServerTransferObject(tiResults, parsedSource, "", compiler.getGeneratedGenerics());
HashMap<InsertPoint, List<PlaceholderVariable>> insertsOnLines = new HashMap<>(); HashMap<String, List<PlaceholderVariable>> insertsOnLines = new HashMap<>();
for (PlaceholderVariable insert : tips) { for (PlaceholderVariable insert : tips) {
var insertPoint = new InsertPoint(insert.point.point.getLine(), insert.point.point.getCharPositionInLine()); if (!insertsOnLines.containsKey(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine())) {
if (!insertsOnLines.containsKey(insertPoint)) { insertsOnLines.put(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine(), new ArrayList<>(List.of(insert)));
insertsOnLines.put(insertPoint, new ArrayList<>(List.of(insert)));
} else { } else {
insertsOnLines.get(insertPoint).add(insert); insertsOnLines.get(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine()).add(insert);
} }
} }
@@ -183,13 +198,8 @@ 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()));
} }
var variable = entrySet.getValue().getFirst(); 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()));
variables.add(new LSPVariable("test", typesOfVariable,
variable.point.point.getLine(),
variable.point.point.getCharPositionInLine(),
variable.point.point.getStopIndex(),
variable.getResultPair().getLeft()));
} }
@@ -210,7 +220,91 @@ public class TypeResolver {
} }
return new InferenceResult(variables, lsTransfer.getWarnings()); return variables;
}
public ArrayList<LSPVariable> infereIncremental(List<ResultSet> newResultSet, List<GenericsResult> generatedGenerics, SourceFile ast) throws IOException, ClassNotFoundException, URISyntaxException {
System.setOut(new PrintStream(OutputStream.nullOutputStream()));
logger.info("HMMMMMMMMMMMMM");
var parsedSource = ast;
var tiResults = newResultSet;
Set<PlaceholderVariable> tips = new HashSet<>();
for (int i = 0; i < tiResults.size(); i++) {
ResultSet tiResult = tiResults.get(i);
tips.addAll(ASTTransformationHelper.createTypeInsertPoints(parsedSource, tiResult, null));
}
logger.info("OKI DOKI ALLES ERSTELLT");
System.setOut(System.out);
HashMap<String, List<PlaceholderVariable>> insertsOnLines = new HashMap<>();
for (PlaceholderVariable insert : tips) {
if (!insertsOnLines.containsKey(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine())) {
insertsOnLines.put(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine(), new ArrayList<>(List.of(insert)));
} else {
insertsOnLines.get(insert.point.point.getLine() + " " + insert.point.point.getCharPositionInLine()).add(insert);
}
}
inserts = insertsOnLines;
logger.info("TYPES ARE:");
insertsOnLines.forEach((key, value) -> value.forEach(type -> logger.info(type.point.getInsertString())));
ArrayList<LSPVariable> variables = new ArrayList<>();
for(var entrySet : insertsOnLines.entrySet()){
ArrayList<Type> typesOfVariable = new ArrayList<>();
for(PlaceholderVariable typeinsert : entrySet.getValue()){
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()));
}
for (var variable : variables) {
HashMap<String, Type> uniqueType = new HashMap<>();
for (var type : variable.getPossibleTypes()) {
if (!uniqueType.containsKey(type.getType().replaceAll(" ", ""))) {
uniqueType.put(type.getType(), type);
}
}
variable.setPossibleTypes(new ArrayList<>(uniqueType.values()));
logger.info(variable.getLine() + ":" + variable.getCharPosition());
for (Type t : variable.getPossibleTypes()) {
logger.info(t.getType());
}
}
return variables;
}
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 {
@@ -221,10 +315,14 @@ 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(getNewAst(uri), "", current.getGeneratedGenerics(), current.getWarnings()); this.current = new LanguageServerTransferObject(current.getResultSets(), getNewAst(uri), "", current.getGeneratedGenerics());
logger.info("NEW AST:"); logger.info("NEW AST:");
logger.info(ASTPrinter.print(current.getAst())); logger.info(ASTPrinter.print(current.getAst()));
} }
public void updateCurrent(List<ResultSet> resultSets){
current.getResultSets().addAll(resultSets);
}
} }
@@ -12,10 +12,6 @@ public class PlaceholderPoint {
private int extraOffset = 0; private int extraOffset = 0;
private PlaceholderType kind; private PlaceholderType kind;
public void setInsertString(String insertString){
this.insertString = insertString;
}
public PlaceholderPoint(Token point, String toInsert, PlaceholderType kind){ public PlaceholderPoint(Token point, String toInsert, PlaceholderType kind){
this.point = point; this.point = point;
this.kind = kind; this.kind = kind;
@@ -41,12 +37,12 @@ public class PlaceholderPoint {
public int getPositionInCode() { public int getPositionInCode() {
return point.getStartIndex() + extraOffset; return point.getStartIndex() + extraOffset;
} }
/* PL 2018-06-19
public PlaceholderType getKind() { * Zwei TypeInsertPoint's sind gleich, wenn ihre point's gleich sind
return kind; * eingefuegt damit man TypeReplaceMarker vergleichen kann
} * @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) { public boolean equals(Object obj) {
return this == obj; return this == obj;
/* /*
@@ -1,7 +1,5 @@
package de.dhbw.model; package de.dhbw.model;
import de.dhbw.helper.ConversionHelper;
import de.dhbwstuttgart.target.generate.GenericsResultSet;
import de.dhbwstuttgart.typeinference.result.ResultPair; import de.dhbwstuttgart.typeinference.result.ResultPair;
import java.util.*; import java.util.*;
@@ -13,11 +11,9 @@ public class PlaceholderVariable {
public final PlaceholderPoint point; public final PlaceholderPoint point;
Set<PlaceholderPoint> inserts; Set<PlaceholderPoint> inserts;
ResultPair<?, ?> resultPair; ResultPair<?, ?> resultPair;
private final GenericsResultSet constraints;
public PlaceholderVariable(PlaceholderPoint point, Set<PlaceholderPoint> additionalPoints, ResultPair<?, ?> resultPair, 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.resultPair = resultPair;
} }
@@ -28,10 +24,7 @@ public class PlaceholderVariable {
List<PlaceholderPoint> insertsSorted = new ArrayList<>(); List<PlaceholderPoint> insertsSorted = new ArrayList<>();
insertsSorted.add(point); insertsSorted.add(point);
insertsSorted.addAll(inserts);
if (!point.getInsertString().contains("void")) {
insertsSorted.addAll(inserts);
}
Collections.sort(insertsSorted, new PlaceholderPoint.TypeInsertPointPositionComparator().reversed()); Collections.sort(insertsSorted, new PlaceholderPoint.TypeInsertPointPositionComparator().reversed());
for (PlaceholderPoint insertPoint : insertsSorted) { for (PlaceholderPoint insertPoint : insertsSorted) {
@@ -45,10 +38,6 @@ public class PlaceholderVariable {
return point.getInsertString(); return point.getInsertString();
} }
public void reducePackage() {
point.setInsertString(ConversionHelper.cleanType(point.getInsertString()));
}
public ResultPair<?, ?> getResultPair() { public ResultPair<?, ?> getResultPair() {
return this.resultPair; return this.resultPair;
} }
@@ -76,8 +65,4 @@ public class PlaceholderVariable {
public String toString() { public String toString() {
return point.toString(); return point.toString();
} }
public GenericsResultSet getConstraints() {
return constraints;
}
} }
@@ -3,12 +3,8 @@ 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 {
@@ -43,18 +39,21 @@ public class ClientService {
this.client = client; this.client = client;
} }
public void updateClient(LanguageClient client) {
client.refreshInlayHints();
client.refreshDiagnostics();
}
public void updateClient() { public void updateClient() {
if (JavaTXLanguageServer.capabilities.getWorkspace().getInlayHint() != null) client.refreshInlayHints();
client.refreshInlayHints(); client.refreshDiagnostics();
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) { public void startLoading(String taskName, String title, LanguageClient client) {
Either<String, Integer> token = Either.forLeft(taskName); Either<String, Integer> token = Either.forLeft(taskName);
client.createProgress(new WorkDoneProgressCreateParams(token)); client.createProgress(new WorkDoneProgressCreateParams(token));
@@ -68,7 +67,7 @@ public class ClientService {
} }
public void stopLoading(String taskName, String title) { public void stopLoading(String taskName, String title, LanguageClient client) {
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);
+1 -6
View File
@@ -55,16 +55,11 @@ The Language Server in itself can be used for any Client. The Clients task is to
![Diagram](docs/diagram.png) ![Diagram](docs/diagram.png)
## Additional Information
- Uses the [LSP-Interface](https://gitea.hb.dhbw-stuttgart.de/JavaTX/JavaCompilerCore/src/branch/LSP-Interface) Branch of the Java-TX Compiler Repository
## Update JavaTX Compiler Dependency as Maven Package ## Update JavaTX Compiler Dependency as Maven Package
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. create a lib Folder at ./LangaugeServer -> ./LanguageServer/lib 2. take the Jar-File and copy it into the /lib Folder
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.