9 Commits

Author SHA1 Message Date
RubenKraft
fc628f7547 Update README.md 2025-09-18 16:05:45 +00:00
Ruben
33d5fbb01d feat: update jar and Version 2025-09-18 17:55:45 +02:00
Ruben
6332daf2ad feat: update Compiler Jar 2025-09-18 17:54:17 +02:00
Ruben
01616ee985 feat: update vscode client 2025-09-17 19:11:55 +02:00
Ruben
29f0e6a05a Merge remote-tracking branch 'origin/main'
# Conflicts:
#	Clients/VisualStudioCode/JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar
#	Clients/VisualStudioCode/package.json
2025-09-17 19:08:53 +02:00
Ruben
ed26f869c3 feat #40: only insert Type as normal name without package reference as it is implicitly imported 2025-09-17 14:29:46 +02:00
Ruben
ee0b51868c feat: move compilation into compiler 2025-09-17 11:32:46 +02:00
Ruben
98b32fd418 feat #40: remove Diagnostic if it has been selected 2025-09-17 11:08:07 +02:00
Ruben
7bc07d9ac1 feat: update vscode client 2025-09-15 18:51:24 +02:00
15 changed files with 49 additions and 280 deletions

View File

@@ -1,3 +1,3 @@
# lspclient README
# Java-TX Language Server
This is the README for the Java-TX LSP Client.
This is the official Plugin for Java-TX.

View File

@@ -3,7 +3,7 @@
"name": "java-tx-language-extension",
"displayName": "Java-TX Language Extension",
"description": "The Language Extension for Java-TX with Typehints and Syntax Checks",
"version": "0.0.5",
"version": "0.0.9",
"engines": {
"vscode": "^1.94.0"
},

View File

@@ -13,12 +13,12 @@ function createClient(context: vscode.ExtensionContext): LanguageClient {
const serverOptions: ServerOptions = {
run: {
command: 'java',
args: ['-Xss2m', '-jar', workspaceFolder + "/JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar"],
args: ['-Xss10m', '-jar', workspaceFolder + "/JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar"],
},
debug: {
command: 'java',
args: [
'-Xss2m',
'-Xss10m',
'-jar',
workspaceFolder + '/JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar',
],
@@ -26,7 +26,7 @@ function createClient(context: vscode.ExtensionContext): LanguageClient {
};
const clientOptions: LanguageClientOptions = {
documentSelector: [{ scheme: 'file', language: 'java' }],
documentSelector: [{ scheme: 'file', pattern: '**/*.jav' }],
synchronize: {
fileEvents: vscode.workspace.createFileSystemWatcher('**/*.jav')
},

View File

@@ -55,7 +55,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
this.logService = new LogService(clientService);
this.formattingHandler = new FormattingHandler(textDocumentService);
this.parserService = new ParserService(conversionHelper, clientService, cacheService);
this.codeActionHandler = new CodeActionHandler(textHelper, textDocumentService, cacheService, typeResolver, logService);
this.codeActionHandler = new CodeActionHandler(textHelper, textDocumentService, cacheService, typeResolver, logService, conversionHelper);
this.saveHandler = new SaveHandler(typeResolver, textDocumentService, logService, cacheService, conversionHelper, clientService, parserService);
this.changeHandler = new ChangeHandler(textDocumentService, parserService, conversionHelper, clientService, typeResolver, cacheService, logService);
}
@@ -155,7 +155,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
public void didSave(DidSaveTextDocumentParams didSaveTextDocumentParams) {
logService.log("[didSave] Client triggered didSave-Event.");
clientService.startLoading("compile-task", "Inferring types...", client);
saveHandler.asyncHandle(didSaveTextDocumentParams);
saveHandler.handleSave(didSaveTextDocumentParams);
clientService.stopLoading("compile-task", "Types successfully inferred", client);
clientService.updateClient(client);
}

View File

@@ -1,5 +1,6 @@
package de.dhbw.handler;
import de.dhbw.helper.ConversionHelper;
import de.dhbw.helper.TextHelper;
import de.dhbw.helper.TypeResolver;
import de.dhbw.service.CacheService;
@@ -22,13 +23,15 @@ public class CodeActionHandler {
private final CacheService cacheService;
private final TypeResolver typeResolver;
private final LogService logService;
private final ConversionHelper conversionHelper;
public CodeActionHandler(TextHelper textHelper, TextDocumentService textDocumentService, CacheService cacheService, TypeResolver typeResolver, LogService logService) {
public CodeActionHandler(TextHelper textHelper, TextDocumentService textDocumentService, CacheService cacheService, TypeResolver typeResolver, LogService logService, ConversionHelper conversionHelper) {
this.textHelper = textHelper;
this.textDocumentService = textDocumentService;
this.cacheService = cacheService;
this.typeResolver = typeResolver;
this.logService = logService;
this.conversionHelper = conversionHelper;
}
public static Range wholeDocumentRange(String text) {
@@ -113,6 +116,8 @@ public class CodeActionHandler {
for (var typeInsertList : typeInsertsOverlapping.values()) {
for (var typeInsert : typeInsertList) {
try {
logService.log("NEW TEXT OF FILE BEFORE INSERT IS:");
logService.log(textDocumentService.getFileOfUri(documentUri));
String typeWithReplacedVariable = typeInsert.insert(textDocumentService.getFileOfUri(documentUri));
ArrayList<TextEdit> listOfChanges = new ArrayList<>();
@@ -127,7 +132,7 @@ public class CodeActionHandler {
WorkspaceEdit edit = new WorkspaceEdit();
edit.setChanges(changes);
CodeAction action = new CodeAction("Insert " + typeInsert.getInsertString());
CodeAction action = new CodeAction("Insert " + conversionHelper.cleanType(typeInsert.getInsertString()));
action.setKind(CodeActionKind.QuickFix);
action.setEdit(edit);
actions.add(Either.forRight(action));

View File

@@ -1,27 +1,16 @@
package de.dhbw.handler;
import com.google.common.base.Stopwatch;
import de.dhbw.helper.ResultListener;
import de.dhbw.model.DiagnosticsAndTypehints;
import de.dhbw.service.*;
import de.dhbw.helper.ConversionHelper;
import de.dhbw.helper.TypeResolver;
import de.dhbw.model.LSPVariable;
import de.dhbwstuttgart.core.JavaTXCompiler;
import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface;
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 java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -104,28 +93,4 @@ public class SaveHandler {
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());
}
}
}

View File

@@ -20,12 +20,16 @@ public class ConversionHelper {
this.textDocumentService = textDocumentService;
}
public String cleanType(String type){
return type.replaceAll("java.lang.", "").replaceAll("java.util.", "");
}
public InlayHint getInlayHint(LSPVariable variable) {
InlayHint inlayHint = new InlayHint();
String typeDisplay = "";
for (Type type : variable.getPossibleTypes()) {
typeDisplay += " | " + type.getType().replaceAll("GTV ", "");
typeDisplay += " | " + cleanType(type.getType().replaceAll("GTV ", ""));
}
@@ -45,7 +49,7 @@ public class ConversionHelper {
Diagnostic diagnostic = new Diagnostic(
errorRange,
//TODO: REMOVE! Temporary Fix because GTV, like TPH can be thrown away in the TypeResolver
type.getType().replaceAll("GTV ", ""),
cleanType(type.getType().replaceAll("GTV ", "")),
DiagnosticSeverity.Hint,
"JavaTX Language Server"
);
@@ -62,7 +66,7 @@ public class ConversionHelper {
Diagnostic diagnostic = new Diagnostic(
errorRange,
//TODO: REMOVE! Temporary Fix because GTV, like TPH can be thrown away in the TypeResolver
type.getType().replaceAll("GTV ", ""),
cleanType(type.getType().replaceAll("GTV ", "")),
DiagnosticSeverity.Hint,
"JavaTX Language Server"
);
@@ -103,6 +107,7 @@ public class ConversionHelper {
return new DiagnosticsAndTypehints(diagnostics, typeHint);
}
public DiagnosticsAndTypehints variablesToDiagnosticsAndTypehintsWithInput(ArrayList<LSPVariable> typesOfMethodAndParameters, String input) {
List<InlayHint> typeHint = new ArrayList<>();
ArrayList<Diagnostic> diagnostics = new ArrayList<>();

View File

@@ -19,6 +19,7 @@ public class PlaceholderPlacer extends AbstractASTWalker {
this.genericsResult = genericsResult;
pkgName = forSourceFile.getPkgName();
forSourceFile.accept(this);
inserts.forEach(el -> el.reducePackage());
return inserts;
}

View File

@@ -1,6 +0,0 @@
package de.dhbw.helper;
public class Recalculator {
}

View File

@@ -1,123 +0,0 @@
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);
}
}
}

View File

@@ -143,102 +143,20 @@ public class TypeResolver {
public ArrayList<LSPVariable> infereInput(String pathString, String input, boolean a) throws IOException, ClassNotFoundException, URISyntaxException {
System.setOut(new PrintStream(OutputStream.nullOutputStream()));
var uri = new URI(pathString);
var path = Path.of(uri);
LanguageServerInterface languageServerInterface = new LanguageServerInterface();
LanguageServerTransferObject lsTransfer = languageServerInterface.getResultSetAndAbstractSyntax(pathString);
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);
var parsedSource = lsTransfer.getAst();
var tiResults = lsTransfer.getResultSets();
Set<PlaceholderVariable> tips = new HashSet<>();
// for (var sf : compiler.sourceFiles.values()) {
// Map<JavaClassName, byte[]> bytecode = compiler.generateBytecode(sf, 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);
//
// }
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));
generatedGenerics = lsTransfer.getGeneratedGenerics().get(lsTransfer.getAst());
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)));
tips.addAll(ASTTransformationHelper.createTypeInsertPoints(parsedSource, tiResult, lsTransfer.getGeneratedGenerics().get(lsTransfer.getAst()).get(i)));
}
System.setOut(System.out);
this.current = new LanguageServerTransferObject(tiResults, parsedSource, "", compiler.getGeneratedGenerics());
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 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);
this.current = lsTransfer;
HashMap<String, List<PlaceholderVariable>> insertsOnLines = new HashMap<>();
@@ -321,8 +239,4 @@ public class TypeResolver {
logger.info(ASTPrinter.print(current.getAst()));
}
public void updateCurrent(List<ResultSet> resultSets){
current.getResultSets().addAll(resultSets);
}
}

View File

@@ -12,6 +12,10 @@ public class PlaceholderPoint {
private int extraOffset = 0;
private PlaceholderType kind;
public void setInsertString(String insertString){
this.insertString = insertString;
}
public PlaceholderPoint(Token point, String toInsert, PlaceholderType kind){
this.point = point;
this.kind = kind;
@@ -38,11 +42,6 @@ public class PlaceholderPoint {
return point.getStartIndex() + extraOffset;
}
/* PL 2018-06-19
* Zwei TypeInsertPoint's sind gleich, wenn ihre point's gleich sind
* eingefuegt damit man TypeReplaceMarker vergleichen kann
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
return this == obj;
/*

View File

@@ -12,6 +12,8 @@ public class PlaceholderVariable {
Set<PlaceholderPoint> inserts;
ResultPair<?, ?> resultPair;
public PlaceholderVariable(PlaceholderPoint point, Set<PlaceholderPoint> additionalPoints, ResultPair<?, ?> resultPair) {
this.point = point;
inserts = additionalPoints;
@@ -38,6 +40,9 @@ public class PlaceholderVariable {
return point.getInsertString();
}
public void reducePackage(){point.setInsertString(point.getInsertString().replaceAll("java\\.lang\\.", "").replaceAll("java\\.util\\.", ""));
}
public ResultPair<?, ?> getResultPair() {
return this.resultPair;
}

View File

@@ -55,6 +55,10 @@ The Language Server in itself can be used for any Client. The Clients task is to
![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
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: