13 Commits

15 changed files with 395 additions and 154 deletions

View File

@@ -9,3 +9,7 @@ vsc-extension-quickstart.md
**/*.map **/*.map
**/*.ts **/*.ts
**/.vscode-test.* **/.vscode-test.*
!JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar
!JavaTXLanguageServer-1.0-SNAPSHOT-jar-with-dependencies.jar

View File

@@ -1,71 +1,3 @@
# lspclient README # lspclient README
This is the README for your extension "lspclient". After writing up a brief description, we recommend including the following sections. This is the README for the Java-TX LSP Client.
## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
## Extension Settings
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
For example:
This extension contributes the following settings:
* `myExtension.enable`: Enable/disable this extension.
* `myExtension.thing`: Set to `blah` to do something.
## Known Issues
Calling out known issues can help limit users opening duplicate issues against your extension.
## Release Notes
Users appreciate release notes as you update your extension.
### 1.0.0
Initial release of ...
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
---
## Following extension guidelines
Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension.
* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)
## Working with Markdown
You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux).
* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux).
* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets.
## For more information
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
**Enjoy!**

View File

@@ -1,12 +1,12 @@
{ {
"name": "lspclient", "name": "lspclient",
"version": "0.0.1", "version": "0.0.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "lspclient", "name": "lspclient",
"version": "0.0.1", "version": "0.0.2",
"dependencies": { "dependencies": {
"vscode-languageclient": "^9.0.1" "vscode-languageclient": "^9.0.1"
}, },

View File

@@ -42,10 +42,11 @@ export function activate(context: vscode.ExtensionContext) {
revealOutputChannelOn: 4 revealOutputChannelOn: 4
}; };
// Language Client erstellen und starten // Language Client erstellen und starten
const client = new LanguageClient( const client = new LanguageClient(
'javaLanguageServer', // ID des Clients 'javaTxLanguageServer', // ID des Clients
'Java Language Server', // Name des Clients 'Java-TX Language Server', // Name des Clients
serverOptions, serverOptions,
clientOptions clientOptions
); );

View File

@@ -5,6 +5,7 @@ import de.dhbw.helper.CodeSnippetOptions;
import de.dhbw.helper.TextHelper; import de.dhbw.helper.TextHelper;
import de.dhbw.helper.TypeResolver; import de.dhbw.helper.TypeResolver;
import de.dhbw.model.LSPVariable; import de.dhbw.model.LSPVariable;
import de.dhbw.model.LineCharPosition;
import de.dhbw.model.SnippetWithName; import de.dhbw.model.SnippetWithName;
import de.dhbw.model.Type; import de.dhbw.model.Type;
import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface; import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface;
@@ -14,6 +15,7 @@ import org.apache.log4j.LogManager;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
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.jsonrpc.messages.Message;
import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.lsp4j.services.LanguageClient;
import org.eclipse.lsp4j.services.TextDocumentService; import org.eclipse.lsp4j.services.TextDocumentService;
@@ -26,6 +28,7 @@ import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
@@ -42,8 +45,11 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
HashMap<String, String> textDocuments = new HashMap<>(); HashMap<String, String> textDocuments = new HashMap<>();
CodeSnippetOptions codeSnippetOptions = new CodeSnippetOptions(); CodeSnippetOptions codeSnippetOptions = new CodeSnippetOptions();
TextHelper textHelper = new TextHelper(); TextHelper textHelper = new TextHelper();
Boolean dontShowHints = false;
TypeResolver typeResolver = new TypeResolver(); TypeResolver typeResolver = new TypeResolver();
Path fileRoot = null; Path fileRoot = null;
Boolean singleFileOpened = false;
List<LSPVariable> variables = new ArrayList<>();
public void setClient(LanguageClient client) { public void setClient(LanguageClient client) {
this.client = client; this.client = client;
@@ -51,6 +57,9 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
public void setFileRoot(List<WorkspaceFolder> root) { public void setFileRoot(List<WorkspaceFolder> root) {
if (root == null) {
singleFileOpened = true;
}
//TODO: Nicht nur das erste Element nehmen sondern alle beachten //TODO: Nicht nur das erste Element nehmen sondern alle beachten
fileRoot = Path.of(URI.create(root.get(0).getUri())); fileRoot = Path.of(URI.create(root.get(0).getUri()));
} }
@@ -91,6 +100,68 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
textDocuments.put(params.getTextDocument().getUri(), params.getTextDocument().getText()); textDocuments.put(params.getTextDocument().getUri(), params.getTextDocument().getText());
} }
public ArrayList<String> difference(String first, String second) {
ArrayList<String> result = new ArrayList<>();
int i = 0, j = 0;
int startDiff = -1;
while (j < second.length()) {
if (i < first.length() && first.charAt(i) == second.charAt(j)) {
if (startDiff != -1) {
result.add(second.substring(startDiff, j));
startDiff = -1;
}
i++;
j++;
} else {
if (startDiff == -1) {
startDiff = j;
}
j++;
}
}
if (startDiff != -1) {
result.add(second.substring(startDiff));
}
return result;
}
public Map<LineCharPosition, String> differenceLinePos(String first, String second, int line) {
Map<LineCharPosition, String> result = new HashMap<>();
int i = 0, j = 0;
int startDiff = -1;
while (j < second.length()) {
if (i < first.length() && first.charAt(i) == second.charAt(j)) {
if (startDiff != -1) {
String diff = second.substring(startDiff, j);
result.put(new LineCharPosition(line, startDiff), diff);
startDiff = -1;
}
i++;
j++;
} else {
if (startDiff == -1) {
startDiff = j;
}
j++;
}
}
if (startDiff != -1) {
String diff = second.substring(startDiff);
result.put(new LineCharPosition(line, startDiff), diff);
}
return result;
}
/** /**
* Handles didChange-Event. * Handles didChange-Event.
* updates textDocument-State on Server and run Syntax-Check. If an Error is found it will get displayed as a Diagnostic. * updates textDocument-State on Server and run Syntax-Check. If an Error is found it will get displayed as a Diagnostic.
@@ -101,6 +172,35 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
public void didChange(DidChangeTextDocumentParams params) { public void didChange(DidChangeTextDocumentParams params) {
log("[didChange] Client triggered didChange Event.", MessageType.Info); log("[didChange] Client triggered didChange Event.", MessageType.Info);
//TODO: Regenerate if Line-Count does not match -> Return new AST and see where the Positions are instead of calculating them from changes in Text-Document. Even possible?
String currentText = textDocuments.get(params.getTextDocument().getUri());
ArrayList<String> currentTextLines = new ArrayList<>(Arrays.stream(currentText.split("\n")).toList());
HashMap<LineCharPosition, String> preciseChanges = new HashMap<>();
String newText = params.getContentChanges().getFirst().getText();
ArrayList<String> newTextLines = new ArrayList<>(Arrays.stream(newText.split("\n")).toList());
ArrayList<Integer> offsetPerLine = new ArrayList<>();
HashMap<Integer, List<String>> textChanges = new HashMap<>();
int index = 0;
for (String newTextLine : newTextLines) {
if (!(currentTextLines.size() > index)) {
offsetPerLine.add(0);
} else {
Map<LineCharPosition, String> lineDiffs = differenceLinePos(currentTextLines.get(index), newTextLine, index);
preciseChanges.putAll(lineDiffs);
textChanges.put(index, difference(currentTextLines.get(index), newTextLine).stream().map(el -> el.replaceAll(" ", "")).toList());
offsetPerLine.add(newTextLine.length() - currentTextLines.get(index).length());
}
index++;
}
AtomicReference<String> summedUp = new AtomicReference<>(""); AtomicReference<String> summedUp = new AtomicReference<>("");
params.getContentChanges().forEach(el -> summedUp.set(summedUp.get() + el.getText())); params.getContentChanges().forEach(el -> summedUp.set(summedUp.get() + el.getText()));
textDocuments.put(params.getTextDocument().getUri(), summedUp.get()); textDocuments.put(params.getTextDocument().getUri(), summedUp.get());
@@ -111,7 +211,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
List<ParserError> parserErrors = parserInterface.getParseErrors(input); List<ParserError> parserErrors = parserInterface.getParseErrors(input);
List<Diagnostic> diagnostics = parserErrors.stream().map(el -> { List<Diagnostic> diagnosticsList = 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
new Position(el.getLine() - 1, el.getEndCharPosition()) // Endposition new Position(el.getLine() - 1, el.getEndCharPosition()) // Endposition
@@ -125,9 +225,89 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
}).toList(); }).toList();
PublishDiagnosticsParams diagnosticsParams = new PublishDiagnosticsParams(params.getTextDocument().getUri(), diagnostics); // PublishDiagnosticsParams diagnosticsParams = new PublishDiagnosticsParams(params.getTextDocument().getUri(), diagnostics);
client.publishDiagnostics(diagnosticsParams); // client.publishDiagnostics(diagnosticsParams);
List<String> combinedList = new ArrayList<>();
for (List<String> list : textChanges.values()) {
combinedList.addAll(list);
}
typeResolver.reduceCurrent(preciseChanges, variables, client);
//Reduce and display Typehints and Diagnostics
if (!currentlyCalculating) {
currentlyCalculating = true;
ArrayList<Diagnostic> diagnostics = new ArrayList<>();
var sWatch = Stopwatch.createUnstarted();
sWatch.start();
try {
if (textDocuments.get(params.getTextDocument().getUri()) == null) {
log("[didSave] Input of Text Document is null in TextDocument-Hashmap.", MessageType.Error);
}
ArrayList<LSPVariable> typesOfMethodAndParameters = typeResolver.infereInput(textDocuments.get(params.getTextDocument().getUri()), params.getTextDocument().getUri());
List<InlayHint> typeHint = new ArrayList<>();
for (var variable : typesOfMethodAndParameters) {
InlayHint inlayHint = getInlayHint(variable);
typeHint.add(inlayHint);
//Diagnostics of Types
for (var type : variable.getPossibleTypes()) {
Diagnostic diagnostic = getDiagnostic(variable, params.getTextDocument().getUri(), type);
diagnostics.add(diagnostic);
}
}
updateGlobalMaps(diagnostics, typeHint, params.getTextDocument().getUri());
} catch (Exception e) {
log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + e.getMessage(), MessageType.Error);
client.showMessage(new MessageParams(MessageType.Error, e.getMessage()));
updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), params.getTextDocument().getUri());
} finally {
currentlyCalculating = false;
sWatch.stop();
log("[didSave] Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]", MessageType.Info);
}
}
for (var inlayHint : globalInlayHintMap.get(params.getTextDocument().getUri())) {
inlayHint.getPosition().setCharacter(inlayHint.getPosition().getCharacter() + offsetPerLine.get(inlayHint.getPosition().getLine()));
}
for (var inlayHint : globalDiagnosticsMap.get(params.getTextDocument().getUri())) {
inlayHint.getRange().getStart().setCharacter(inlayHint.getRange().getStart().getCharacter() + offsetPerLine.get(inlayHint.getRange().getStart().getLine()));
inlayHint.getRange().getEnd().setCharacter(inlayHint.getRange().getEnd().getCharacter() + offsetPerLine.get(inlayHint.getRange().getEnd().getLine()));
}
for (var textChangeLine : textChanges.entrySet()) {
log(textChangeLine.getKey() + " - " + String.join(",", textChangeLine.getValue()), MessageType.Info);
}
globalInlayHintMap.put(params.getTextDocument().getUri(), globalInlayHintMap.get(params.getTextDocument().getUri()).stream().filter(el -> {
//TODO: Hier das Label aufspalten an | weil die Typehints immer mit und getrennt sind und so jeder Typhint für sich durchlaufen werden kann.
log(el.getLabel().getLeft().replaceAll(" ", "") + "<>" + String.join(",", textChanges.get(el.getPosition().getLine())) + ": " + (!textChanges.get(el.getPosition().getLine()).contains(el.getLabel().getLeft().replaceAll(" ", "")) ? "true" : "false"), MessageType.Info);
return !textChanges.get(el.getPosition().getLine()).contains(el.getLabel().getLeft().replaceAll(" ", ""));
}).toList());
globalDiagnosticsMap.put(params.getTextDocument().getUri(), globalDiagnosticsMap.get(params.getTextDocument().getUri()).stream().filter(el -> {
log(el.getMessage().replaceAll(" ", "") + "<>" + String.join(",", textChanges.get(el.getRange().getStart().getLine())) + ": " + (!textChanges.get(el.getRange().getStart().getLine()).contains(el.getMessage().replaceAll(" ", "")) ? "true" : "false"), MessageType.Info);
return !textChanges.get(el.getRange().getStart().getLine()).contains(el.getMessage().replaceAll(" ", ""));
}).toList());
updateClient(client);
client.publishDiagnostics(new PublishDiagnosticsParams(params.getTextDocument().getUri(), globalDiagnosticsMap.get(params.getTextDocument().getUri())));
} }
/** /**
@@ -244,8 +424,6 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
startLoading("compile-task", "Inferring types...", client); startLoading("compile-task", "Inferring types...", client);
LanguageServerInterface languageServerInterface = new LanguageServerInterface();
if (!currentlyCalculating) { if (!currentlyCalculating) {
currentlyCalculating = true; currentlyCalculating = true;
@@ -254,12 +432,13 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
sWatch.start(); sWatch.start();
try { try {
typeResolver.getCompilerInput(didSaveTextDocumentParams.getTextDocument().getUri(), textDocuments.get(didSaveTextDocumentParams.getTextDocument().getUri()));
if (textDocuments.get(didSaveTextDocumentParams.getTextDocument().getUri()) == null) { if (textDocuments.get(didSaveTextDocumentParams.getTextDocument().getUri()) == null) {
log("[didSave] Input of Text Document is null in TextDocument-Hashmap.", MessageType.Error); log("[didSave] Input of Text Document is null in TextDocument-Hashmap.", MessageType.Error);
} }
ArrayList<LSPVariable> typesOfMethodAndParameters = typeResolver.infereInput(textDocuments.get(didSaveTextDocumentParams.getTextDocument().getUri()), didSaveTextDocumentParams.getTextDocument().getUri()); ArrayList<LSPVariable> typesOfMethodAndParameters = typeResolver.infereInput(textDocuments.get(didSaveTextDocumentParams.getTextDocument().getUri()), didSaveTextDocumentParams.getTextDocument().getUri());
variables = typesOfMethodAndParameters;
List<InlayHint> typeHint = new ArrayList<>(); List<InlayHint> typeHint = new ArrayList<>();
for (var variable : typesOfMethodAndParameters) { for (var variable : typesOfMethodAndParameters) {
@@ -283,6 +462,8 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
} catch (Exception e) { } catch (Exception e) {
log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + e.getMessage(), MessageType.Error); log("[didSave] Error trying to get Inlay-Hints and Diagnostics for Client: " + e.getMessage(), MessageType.Error);
client.showMessage(new MessageParams(MessageType.Error, e.getMessage()));
updateGlobalMaps(new ArrayList<>(), new ArrayList<>(), didSaveTextDocumentParams.getTextDocument().getUri());
} finally { } finally {
currentlyCalculating = false; currentlyCalculating = false;
@@ -295,21 +476,24 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
stopLoading("compile-task", "Types successfully inferred", client); stopLoading("compile-task", "Types successfully inferred", client);
dontShowHints = false;
updateClient(client); updateClient(client);
ArrayList<File> files = new ArrayList<>(); ArrayList<File> files = new ArrayList<>();
if (fileRoot != null) {
try (Stream<Path> stream = Files.walk(Paths.get(fileRoot.toUri()))) { try (Stream<Path> stream = Files.walk(Paths.get(fileRoot.toUri()))) {
stream.filter(Files::isRegularFile) stream.filter(Files::isRegularFile)
.forEach(el -> files.add(el.toFile())); .forEach(el -> files.add(el.toFile()));
} catch (IOException e) { } catch (IOException e) {
} }
} }
}
@Override @Override
public CompletableFuture<List<InlayHint>> inlayHint(InlayHintParams params) { public CompletableFuture<List<InlayHint>> inlayHint(InlayHintParams params) {
log("[inlayHint] The Client requested Inlay-Hints.", MessageType.Info); log("[inlayHint] The Client requested Inlay-Hints.", MessageType.Info);
return CompletableFuture.supplyAsync(() -> globalInlayHintMap.get(params.getTextDocument().getUri()) == null ? Collections.emptyList() : globalInlayHintMap.get(params.getTextDocument().getUri())); return CompletableFuture.supplyAsync(() -> dontShowHints ? Collections.emptyList() : globalInlayHintMap.get(params.getTextDocument().getUri()) == null ? Collections.emptyList() : globalInlayHintMap.get(params.getTextDocument().getUri()));
} }
@Override @Override
@@ -441,7 +625,11 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
@Override @Override
public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActionParams params) { public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActionParams params) {
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); 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);
log("Code-Action Context was: " + params.getContext().getTriggerKind().name(), MessageType.Info);
List<Either<Command, CodeAction>> actions = new ArrayList<>(); List<Either<Command, CodeAction>> actions = new ArrayList<>();
@@ -453,6 +641,8 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
.filter(diagnostic -> rangesOverlap(diagnostic.getRange(), requestedRange)).toList(); .filter(diagnostic -> rangesOverlap(diagnostic.getRange(), requestedRange)).toList();
Range rangeOfInsert = params.getRange(); Range rangeOfInsert = params.getRange();
String documentUri = params.getTextDocument().getUri(); String documentUri = params.getTextDocument().getUri();
@@ -515,7 +705,9 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
} }
} }
return CompletableFuture.completedFuture(actions); return CompletableFuture.supplyAsync(() -> {
return actions;
});
} }

View File

@@ -12,11 +12,15 @@ import de.dhbwstuttgart.target.generate.GenericsResult;
import de.dhbwstuttgart.typeinference.result.ResultSet; 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 org.eclipse.lsp4j.MessageParams;
import org.eclipse.lsp4j.MessageType;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
import org.eclipse.lsp4j.services.LanguageClient;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -29,6 +33,17 @@ public class TypeResolver {
private static final Logger logger = LogManager.getLogger(TypeResolver.class); private static final Logger logger = LogManager.getLogger(TypeResolver.class);
private final boolean ENABLE_GENERICS = false;
private LanguageServerTransferObject current;
public LanguageServerTransferObject getCurrent() {
return current;
}
public void reduceCurrent() {
current.getResultSets().removeFirst();
}
private List<ResultSet> currentResults = new ArrayList<>(); private List<ResultSet> currentResults = new ArrayList<>();
@@ -186,18 +201,35 @@ public class TypeResolver {
return genericTypes; return genericTypes;
} }
public void getCompilerInput(String path, String input) throws IOException, URISyntaxException, ClassNotFoundException {
LanguageServerInterface languageServer = new LanguageServerInterface();
var transferObj = languageServer.getResultSetAndAbstractSyntax(path, input);
current = transferObj;
}
/** /**
* Zum Erhalt für sowohl Parameter als auch Methoden. * Zum Erhalt für sowohl Parameter als auch Methoden.
*/ */
public ArrayList<LSPVariable> infereInput(String input, String path) throws IOException, ClassNotFoundException, URISyntaxException { public ArrayList<LSPVariable> infereInput(String input, String path) throws IOException, ClassNotFoundException, URISyntaxException {
logger.info("Infering Types for Input."); logger.info("Infering Types for Input.");
LanguageServerTransferObject transferObj;
if (current == null) {
LanguageServerInterface languageServer = new LanguageServerInterface(); LanguageServerInterface languageServer = new LanguageServerInterface();
var transferObj = languageServer.getResultSetAndAbstractSyntax(path, input); transferObj = languageServer.getResultSetAndAbstractSyntax(path, input);
current = transferObj;
} else {
transferObj = current;
}
ArrayList<LSPVariable> methodsWithParametersLSPVariableList = new ArrayList<>(); ArrayList<LSPVariable> methodsWithParametersLSPVariableList = new ArrayList<>();
if (!transferObj.getResultSets().isEmpty()) {
//TODO: Hier noch irgendwie die Klasse rausfinden oder durchgehen. //TODO: Hier noch irgendwie die Klasse rausfinden oder durchgehen.
if (ENABLE_GENERICS) {
//GENERICS OF CLASS //GENERICS OF CLASS
for (var method : transferObj.getAst().getAllMethods()) { for (var method : transferObj.getAst().getAllMethods()) {
@@ -206,25 +238,30 @@ public class TypeResolver {
ArrayList<Type> genericTypes = getClassGenerics(transferObj.getGeneratedGenerics(), method, clazz); ArrayList<Type> genericTypes = getClassGenerics(transferObj.getGeneratedGenerics(), method, clazz);
TextHelper helper = new TextHelper(); TextHelper helper = new TextHelper();
if (!genericTypes.isEmpty()) { if (!genericTypes.isEmpty()) {
methodsWithParametersLSPVariableList.add(new LSPClass("test", genericTypes, clazz.getOffset().getLine(), helper.getClassPositionForGeneric(clazz.getOffset().getLine() - 1, input, clazz.getOffset().getStopIndex()), clazz.getOffset().getStopIndex())); methodsWithParametersLSPVariableList.add(new LSPClass("test", genericTypes, clazz.getOffset().getLine(), helper.getClassPositionForGeneric(clazz.getOffset().getLine() - 1, input, clazz.getOffset().getStopIndex()), clazz.getOffset().getStopIndex(), clazz.getReturnType()));
} }
} }
} }
}
for (var method : transferObj.getAst().getAllMethods()) { for (var method : transferObj.getAst().getAllMethods()) {
var types = getAvailableTypes(transferObj.getResultSets(), method); var types = getAvailableTypes(transferObj.getResultSets(), method);
var generics = getAvailableGenericTypes(transferObj.getGeneratedGenerics().values().stream().flatMap(List::stream).collect(Collectors.toList()), method); var generics = getAvailableGenericTypes(transferObj.getGeneratedGenerics().values().stream().flatMap(List::stream).collect(Collectors.toList()), method);
if (!filterOutDuplicates(types).isEmpty()) { if (!filterOutDuplicates(types).isEmpty()) {
methodsWithParametersLSPVariableList.add(new LSPMethod(method.name, filterOutDuplicates(types), method.getOffset().getLine(), method.getOffset().getCharPositionInLine(), method.getOffset().getStopIndex())); methodsWithParametersLSPVariableList.add(new LSPMethod(method.name, filterOutDuplicates(types), method.getOffset().getLine(), method.getOffset().getCharPositionInLine(), method.getOffset().getStopIndex(), method.getReturnType()));
} }
if (ENABLE_GENERICS) {
if (!generics.isEmpty()) { if (!generics.isEmpty()) {
ArrayList<Type> typesThatAreGeneric = filterOutDuplicates(generics, types); ArrayList<Type> typesThatAreGeneric = filterOutDuplicates(generics, types);
typesThatAreGeneric.forEach(el -> el.setType("<" + el.getType() + "> " + el.getType())); typesThatAreGeneric.forEach(el -> el.setType("<" + el.getType() + "> " + el.getType()));
//TODO: Muss Global und wird mehrmals so gemacht. Das if hier ist eigentlich falsch wegen unnötiger Berechnungszeit //TODO: Muss Global und wird mehrmals so gemacht. Das if hier ist eigentlich falsch wegen unnötiger Berechnungszeit
if (!filterOutDuplicates(typesThatAreGeneric).isEmpty()) { if (!filterOutDuplicates(typesThatAreGeneric).isEmpty()) {
methodsWithParametersLSPVariableList.add(new LSPMethod(method.name, filterOutDuplicates(typesThatAreGeneric), method.getOffset().getLine(), method.getOffset().getCharPositionInLine(), method.getOffset().getStopIndex())); methodsWithParametersLSPVariableList.add(new LSPMethod(method.name, filterOutDuplicates(typesThatAreGeneric), method.getOffset().getLine(), method.getOffset().getCharPositionInLine(), method.getOffset().getStopIndex(), method.getReturnType()));
}
} }
} }
@@ -233,16 +270,19 @@ public class TypeResolver {
ArrayList<Type> genericParam = getAvailableGenericTypes(transferObj.getGeneratedGenerics().values().stream().flatMap(List::stream).collect(Collectors.toList()), param.getType()); ArrayList<Type> genericParam = getAvailableGenericTypes(transferObj.getGeneratedGenerics().values().stream().flatMap(List::stream).collect(Collectors.toList()), param.getType());
if (!typeParam.isEmpty()) { if (!typeParam.isEmpty()) {
methodsWithParametersLSPVariableList.add(new LSPParameter(method.name, filterOutDuplicates(typeParam), param.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex())); methodsWithParametersLSPVariableList.add(new LSPParameter(method.name, filterOutDuplicates(typeParam), param.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex(), param.getType()));
} }
if (ENABLE_GENERICS) {
if (!genericParam.isEmpty()) { if (!genericParam.isEmpty()) {
ArrayList<Type> typesThatAreGeneric = filterOutDuplicates(genericParam, typeParam); ArrayList<Type> typesThatAreGeneric = filterOutDuplicates(genericParam, typeParam);
if (!filterOutDuplicates(typesThatAreGeneric).isEmpty()) { if (!filterOutDuplicates(typesThatAreGeneric).isEmpty()) {
methodsWithParametersLSPVariableList.add(new LSPParameter(method.name, filterOutDuplicates(typesThatAreGeneric), method.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex())); methodsWithParametersLSPVariableList.add(new LSPParameter(method.name, filterOutDuplicates(typesThatAreGeneric), method.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex(), param.getType()));
methodsWithParametersLSPVariableList.add(new LSPParameter(method.name, new ArrayList<>(filterOutDuplicates(typesThatAreGeneric).stream().map(el -> new Type("<" + el.getType() + ">", true)).toList()), method.getOffset().getLine(), method.getOffset().getCharPositionInLine(), method.getOffset().getStopIndex())); methodsWithParametersLSPVariableList.add(new LSPParameter(method.name, new ArrayList<>(filterOutDuplicates(typesThatAreGeneric).stream().map(el -> new Type("<" + el.getType() + ">", true)).toList()), method.getOffset().getLine(), method.getOffset().getCharPositionInLine(), method.getOffset().getStopIndex(), method.getReturnType()));
}
}
} }
} }
} }
@@ -252,4 +292,22 @@ public class TypeResolver {
} }
public void reduceCurrent(HashMap<LineCharPosition, String> combinedList, List<LSPVariable> variables, LanguageClient client) {
client.logMessage(new MessageParams(MessageType.Info, "Lenght is: " + combinedList.size()));
for (var lines : combinedList.entrySet()) {
var contentChange = lines.getValue();
for (LSPVariable variable : variables) {
for (Type typeOfVariable : variable.getPossibleTypes()) {
client.logMessage(new MessageParams(MessageType.Info, "\"" + typeOfVariable.getType() + " : " + variable.getLine() + "\"< > \"" + contentChange + " : " + lines.getKey() + "\""));
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(" ", "")));
client.logMessage(new MessageParams(MessageType.Info, "Removing Resultset"));
return;
}
}
}
}
}
}
} }

View File

@@ -1,9 +1,11 @@
package de.dhbw.model; package de.dhbw.model;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import java.util.ArrayList; import java.util.ArrayList;
public class LSPClass extends LSPVariable{ public class LSPClass extends LSPVariable{
public LSPClass(String name, ArrayList<Type> possibleTypes, int line, int charPosition, int endPosition) { public LSPClass(String name, ArrayList<Type> possibleTypes, int line, int charPosition, int endPosition, RefTypeOrTPHOrWildcardOrGeneric originalTphName) {
super(name, possibleTypes, line, charPosition, endPosition); super(name, possibleTypes, line, charPosition, endPosition, originalTphName);
} }
} }

View File

@@ -1,9 +1,11 @@
package de.dhbw.model; package de.dhbw.model;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import java.util.ArrayList; import java.util.ArrayList;
public class LSPMethod extends LSPVariable { public class LSPMethod extends LSPVariable {
public LSPMethod(String name, ArrayList<Type> type, int line, int charPosition, int endPosition) { public LSPMethod(String name, ArrayList<Type> type, int line, int charPosition, int endPosition, RefTypeOrTPHOrWildcardOrGeneric originalTphName) {
super(name, type, line, charPosition, endPosition); super(name, type, line, charPosition, endPosition, originalTphName);
} }
} }

View File

@@ -1,10 +1,12 @@
package de.dhbw.model; package de.dhbw.model;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import java.util.ArrayList; import java.util.ArrayList;
public class LSPParameter extends LSPMethod { public class LSPParameter extends LSPVariable {
public LSPParameter(String name, ArrayList<Type> type, int line, int charPosition, int endPosition) { public LSPParameter(String name, ArrayList<Type> type, int line, int charPosition, int endPosition, RefTypeOrTPHOrWildcardOrGeneric originalTphName) {
super(name, type, line, charPosition, endPosition); super(name, type, line, charPosition, endPosition, originalTphName);
} }
} }

View File

@@ -1,20 +1,33 @@
package de.dhbw.model; package de.dhbw.model;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import java.util.ArrayList; import java.util.ArrayList;
public class LSPVariable { String name; public class LSPVariable {
String name;
ArrayList<Type> possibleTypes; ArrayList<Type> possibleTypes;
int line; int line;
int charPosition; int charPosition;
int endPosition; int endPosition;
boolean needsInference; boolean needsInference;
RefTypeOrTPHOrWildcardOrGeneric originalTphName;
public LSPVariable(String name, ArrayList<Type> possibleTypes, int line, int charPosition, int endPosition) { public LSPVariable(String name, ArrayList<Type> possibleTypes, int line, int charPosition, int endPosition, RefTypeOrTPHOrWildcardOrGeneric originalTphName) {
this.name = name; this.name = name;
this.possibleTypes = possibleTypes; this.possibleTypes = possibleTypes;
this.line = line; this.line = line;
this.charPosition = charPosition; this.charPosition = charPosition;
this.endPosition = endPosition; this.endPosition = endPosition;
this.originalTphName = originalTphName;
}
public RefTypeOrTPHOrWildcardOrGeneric getOriginalTphName() {
return originalTphName;
}
public void setOriginalTphName(RefTypeOrTPHOrWildcardOrGeneric originalTphName) {
this.originalTphName = originalTphName;
} }
public int getEndPosition() { public int getEndPosition() {

View File

@@ -0,0 +1,25 @@
package de.dhbw.model;
public class LineCharPosition {
public final int line;
public final int charPosition;
public LineCharPosition(int line, int charPosition) {
this.line = line;
this.charPosition = charPosition;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof LineCharPosition)) return false;
LineCharPosition that = (LineCharPosition) o;
return line == that.line && charPosition == that.charPosition;
}
@Override
public String toString() {
return "Line " + line + ", Char " + charPosition;
}
}

View File

@@ -1,30 +1,39 @@
import de.dhbw.helper.TextHelper; import de.dhbw.helper.TextHelper;
import de.dhbw.helper.TypeResolver; import de.dhbw.helper.TypeResolver;
import de.dhbwstuttgart.languageServerInterface.LanguageServerInterface;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.net.URISyntaxException;
public class CompilerInterfaceTest { public class CompilerInterfaceTest {
@Test @Test
public void testAbstractSyntaxAsString() throws IOException, ClassNotFoundException { public void testAbstractSyntaxAsString() throws IOException, ClassNotFoundException, URISyntaxException {
// LanguageServerInterface languageServer = new LanguageServerInterface(); TypeResolver typeResolver = new TypeResolver();
// var res = languageServer.getResultSetAndAbstractSyntax("import java.lang.Integer;\n import java.lang.String;\n" + var res = typeResolver.infereInput("import java.lang.Integer;\n import java.lang.String;\n" +
// "public class test{\n" + "public class test{\n" +
// "public main(test){" + "public main(test){" +
// "if(0>1){" + "if(0>1){" +
// "return \"w\";" + "return \"w\";" +
// "}" + "}" +
// "Integer i = 0;" + "Integer i = 0;" +
// "return i;" + "return i;" +
// "}" + "}" +
// "}", "TEST"); "}", "c%3A/Users/ruben/Neuer%20Ordner%20%282%29/LSP-Vortrag/images/test.jav");
//
// System.out.println("TEST OUTPUT:"); var res2 = typeResolver.infereInput("import java.lang.Integer;\n import java.lang.String;\n" +
"public class test{\n" +
"public main(test){" +
"if(0>1){" +
"return \"w\";" +
"}" +
"Integer i = 0;" +
"return i;" +
"}" +
"}", "c%3A/Users/ruben/Neuer%20Ordner%20%282%29/LSP-Vortrag/images/test.jav");
System.out.println("TEST OUTPUT:");
// //
// ArrayList<String> allTypes = new ArrayList<>(); // ArrayList<String> allTypes = new ArrayList<>();
// //

View File

@@ -11,6 +11,7 @@ public class JavaTXLanguageDocumentServiceTest {
@Test @Test
@Ignore @Ignore
public void testWordExtraction() { public void testWordExtraction() {
JavaTXTextDocumentService service = new JavaTXTextDocumentService(); // JavaTXTextDocumentService service = new JavaTXTextDocumentService();
// service.didSave(new DidSaveTextDocumentParams(new TextDocumentIdentifier("file:///c%3A/Users/ruben/Neuer%20Ordner%20%282%29/LSP-Vortrag/images/test.jav")));
} }
} }