12 Commits

11 changed files with 314 additions and 283 deletions

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>

View File

@@ -1,21 +1,14 @@
package de.dhbw; package de.dhbw;
import com.google.common.base.Stopwatch;
import de.dhbw.compiler.languageServerInterface.ParserInterface; import de.dhbw.compiler.languageServerInterface.ParserInterface;
import de.dhbw.compiler.languageServerInterface.model.ParserError; import de.dhbw.compiler.languageServerInterface.model.ParserError;
import de.dhbw.helper.CodeSnippetOptions; 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.ParseError.DiagnoseErrorListener;
import de.dhbw.model.SnippetWithName; import de.dhbw.model.SnippetWithName;
import de.dhbw.compiler.parser.antlr.Java17Lexer; import de.dhbw.model.Type;
import de.dhbw.compiler.parser.antlr.Java17Parser;
import de.dhbw.compiler.parser.antlr.Java17ParserBaseListener;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.apache.log4j.LogManager; import org.apache.log4j.LogManager;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.eclipse.lsp4j.*; import org.eclipse.lsp4j.*;
@@ -35,6 +28,8 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
private static final Logger logger = LogManager.getLogger(JavaTXTextDocumentService.class); private static final Logger logger = LogManager.getLogger(JavaTXTextDocumentService.class);
LanguageClient client; LanguageClient client;
HashMap<String, List<InlayHint>> globalInlayHintMap = new HashMap<>();
Boolean calculate = false;
HashMap<String, List<Diagnostic>> globalDiagnosticsMap = new HashMap<>(); HashMap<String, List<Diagnostic>> globalDiagnosticsMap = new HashMap<>();
HashMap<String, String> textDocuments = new HashMap<>(); HashMap<String, String> textDocuments = new HashMap<>();
CodeSnippetOptions codeSnippetOptions = new CodeSnippetOptions(); CodeSnippetOptions codeSnippetOptions = new CodeSnippetOptions();
@@ -90,7 +85,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
*/ */
@Override @Override
public void didChange(DidChangeTextDocumentParams params) { public void didChange(DidChangeTextDocumentParams params) {
logger.debug("DIDCHANGE-EVENT"); logger.info("DIDCHANGE-EVENT");
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()));
@@ -103,7 +98,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
List<ParserError> parserErrors = parserInterface.getParseErrors(input); List<ParserError> parserErrors = parserInterface.getParseErrors(input);
logger.debug("Found " + parserErrors.size() + " Errors."); logger.info("Found " + parserErrors.size() + " Errors.");
List<Diagnostic> diagnostics = parserErrors.stream().map(el -> { List<Diagnostic> diagnostics = parserErrors.stream().map(el -> {
Range errorRange = new Range( Range errorRange = new Range(
@@ -131,7 +126,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
*/ */
@Override @Override
public CompletableFuture<List<? extends TextEdit>> formatting(DocumentFormattingParams params) { public CompletableFuture<List<? extends TextEdit>> formatting(DocumentFormattingParams params) {
logger.debug("FORMAT-EVENT"); logger.info("FORMAT-EVENT");
List<TextEdit> edits = new ArrayList<>(); List<TextEdit> edits = new ArrayList<>();
@@ -157,30 +152,37 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
@Override @Override
public void didSave(DidSaveTextDocumentParams didSaveTextDocumentParams) { public void didSave(DidSaveTextDocumentParams didSaveTextDocumentParams) {
calculate = true;
} }
@Override @Override
public CompletableFuture<List<InlayHint>> inlayHint(InlayHintParams params) { public CompletableFuture<List<InlayHint>> inlayHint(InlayHintParams params) {
logger.debug("INLAYHINT-EVENT"); logger.info("The Client requested Inlay-Hints.");
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
ArrayList<Diagnostic> diagnostics = new ArrayList<>(); ArrayList<Diagnostic> diagnostics = new ArrayList<>();
var sWatch = Stopwatch.createUnstarted();
sWatch.start();
try { try {
ArrayList<LSPVariable> typesOfMethodAndParameters = typeResolver.infereMethodsWithParameters(textDocuments.get(params.getTextDocument().getUri())); ArrayList<LSPVariable> typesOfMethodAndParameters = typeResolver.infereInput(textDocuments.get(params.getTextDocument().getUri()));
List<InlayHint> typeHint = new ArrayList<>(); List<InlayHint> typeHint = new ArrayList<>();
for (var variable : typesOfMethodAndParameters) { for (var variable : typesOfMethodAndParameters) {
InlayHint inlayHint = new InlayHint(); InlayHint inlayHint = new InlayHint();
AtomicReference<String> typeDisplay = new AtomicReference<>(""); String typeDisplay = "";
variable.getPossibleTypes().forEach(el -> typeDisplay.getAndSet("| " + el.getType())); for(Type type : variable.getPossibleTypes()){
typeDisplay += " | " + type.getType().replaceAll("GTV ", "");
}
inlayHint.setLabel(typeDisplay.get().length() > 2 ? typeDisplay.get().substring(2) : typeDisplay.get()); inlayHint.setLabel(typeDisplay.length() > 2 ? typeDisplay.substring(2) : typeDisplay);
inlayHint.setPosition(new Position(variable.getLine() - 1, variable.getCharPosition())); inlayHint.setPosition(new Position(variable.getLine() - 1, variable.getCharPosition()));
inlayHint.setKind(InlayHintKind.Parameter); inlayHint.setKind(InlayHintKind.Parameter);
inlayHint.setPaddingRight(true);
inlayHint.setPaddingRight(true);
typeHint.add(inlayHint); typeHint.add(inlayHint);
@@ -192,7 +194,8 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
); );
Diagnostic diagnostic = new Diagnostic( Diagnostic diagnostic = new Diagnostic(
errorRange, errorRange,
typ.getType(), //TODO: REMOVE! Temporary Fix because GTV, like TPH can be thrown away in the TypeResolver
typ.getType().replaceAll("GTV ", ""),
DiagnosticSeverity.Hint, DiagnosticSeverity.Hint,
"JavaTX Language Server" "JavaTX Language Server"
); );
@@ -201,23 +204,29 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
diagnostics.add(diagnostic); diagnostics.add(diagnostic);
} }
} }
logger.debug("Returning " + typeHint.size() + " Typehints."); logger.info("Returning [" + typeHint.size() + "] Inlay-Hints.");
globalDiagnosticsMap.put(params.getTextDocument().getUri(), diagnostics); globalDiagnosticsMap.put(params.getTextDocument().getUri(), diagnostics);
globalInlayHintMap.put(params.getTextDocument().getUri(), typeHint);
PublishDiagnosticsParams diagnosticsParams = new PublishDiagnosticsParams(params.getTextDocument().getUri(), diagnostics); PublishDiagnosticsParams diagnosticsParams = new PublishDiagnosticsParams(params.getTextDocument().getUri(), diagnostics);
client.publishDiagnostics(diagnosticsParams); client.publishDiagnostics(diagnosticsParams);
sWatch.stop();
logger.info("Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]");
return typeHint; return typeHint;
} catch (Exception e) { } catch (Exception e) {
sWatch.stop();
logger.info("Calculating returned an Error after [" + sWatch.elapsed().toSeconds() + "s]");
String stacktrace = ""; String stacktrace = "";
for (var i : e.getStackTrace()) { for (var i : e.getStackTrace()) {
stacktrace += i.toString() + "\n"; stacktrace += i.toString() + "\n";
} }
logger.error("Fehler in der Anzeige der Typen: " + e.getMessage() + "\n" + stacktrace); logger.error("Error trying to get Inlay-Hints and Diagnostics for Client:\n" + e.getMessage() + "\n" + stacktrace);
return Collections.emptyList(); return Collections.emptyList();
} }
}); });
@@ -353,22 +362,18 @@ 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) {
logger.debug("INSERT-EVENT"); logger.info("Client requested Insert at Line [" + params.getRange().getStart().getLine() + "] and from Char [" + params.getRange().getStart().getCharacter() + "] to [" + params.getRange().getEnd().getCharacter() + "].");
List<Either<Command, CodeAction>> actions = new ArrayList<>(); List<Either<Command, CodeAction>> actions = new ArrayList<>();
List<Diagnostic> diagnosticInCurrentDocument = params.getContext().getDiagnostics(); List<Diagnostic> diagnosticInCurrentDocument = params.getContext().getDiagnostics();
logger.debug("Document has " + diagnosticInCurrentDocument.size() + " Diagnostics."); logger.info("Document has currently [" + diagnosticInCurrentDocument.size() + "] Diagnostics.");
Range requestedRange = params.getRange(); Range requestedRange = params.getRange();
//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
List<Diagnostic> diagnosticsOverlappingHover = diagnosticInCurrentDocument.stream() List<Diagnostic> diagnosticsOverlappingHover = diagnosticInCurrentDocument.stream()
.filter(diagnostic -> rangesOverlap(diagnostic.getRange(), requestedRange)).toList(); .filter(diagnostic -> rangesOverlap(diagnostic.getRange(), requestedRange)).toList();
for (var dia : diagnosticInCurrentDocument) {
logger.debug(dia.getMessage());
}
Range rangeOfInsert = params.getRange(); Range rangeOfInsert = params.getRange();
String documentUri = params.getTextDocument().getUri(); String documentUri = params.getTextDocument().getUri();
@@ -405,11 +410,11 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
listOfChanges.add(new TextEdit(rangeOfInsert, typeWithReplacedVariable)); listOfChanges.add(new TextEdit(rangeOfInsert, typeWithReplacedVariable));
} }
var isTypeImported = false;
if (!typeDiagnostic.getCode().getLeft().equalsIgnoreCase("generic")) {
isTypeImported = typeResolver.isTypeImported(textDocuments.get(params.getTextDocument().getUri()), typeDiagnostic.getMessage());
var isTypeImported = typeResolver.isTypeImported(textDocuments.get(params.getTextDocument().getUri()), typeDiagnostic.getMessage()); }
if (!isTypeImported && !typeDiagnostic.getMessage().equals("void") && !typeDiagnostic.getCode().getLeft().equals("GENERIC")) { if (!isTypeImported && !typeDiagnostic.getMessage().equals("void") && !typeDiagnostic.getCode().getLeft().equals("GENERIC")) {
Range importRange = new Range(new Position(0, 0), new Position(0, 0)); Range importRange = new Range(new Position(0, 0), new Position(0, 0));
@@ -417,7 +422,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
listOfChanges.add(new TextEdit(importRange, "import " + typeWithoutGenerics + ";\n")); listOfChanges.add(new TextEdit(importRange, "import " + typeWithoutGenerics + ";\n"));
} }
logger.debug("Returning " + listOfChanges.size() + " Changes for the Document."); logger.info("Returning [" + listOfChanges.size() + "] Changes for the Document.");
Map<String, List<TextEdit>> changes = new HashMap<>(); Map<String, List<TextEdit>> changes = new HashMap<>();
changes.put(documentUri, listOfChanges); changes.put(documentUri, listOfChanges);
@@ -430,7 +435,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
action.setEdit(edit); action.setEdit(edit);
actions.add(Either.forRight(action)); actions.add(Either.forRight(action));
} catch (Exception e) { } catch (Exception e) {
logger.error("Error creating Actions, returning empty List. The Error was: " + e.getMessage()); logger.error("Error creating Actions, returning empty List. The Error was:\n" + e.getMessage());
} }
} }

View File

@@ -2,20 +2,26 @@ package de.dhbw.compiler.languageServerInterface;
import de.dhbw.compiler.languageServerInterface.model.LanguageServerTransferObject; import de.dhbw.compiler.languageServerInterface.model.LanguageServerTransferObject;
import de.dhbw.compiler.core.JavaTXCompiler; import de.dhbw.compiler.core.JavaTXCompiler;
import org.apache.log4j.Logger;
import java.io.*; import java.io.*;
/** /**
* Implementation of an Interface for the Language-Server to get the Resultset and abstract Syntax. * Implementation of an Interface for the Language-Server to get the Resultset and abstract Syntax.
* */ */
public class LanguageServerInterface { public class LanguageServerInterface {
private static final Logger log = Logger.getLogger(LanguageServerInterface.class);
/** /**
* get final Result Set * get final Result Set
* */ */
public LanguageServerTransferObject getResultSetAndAbstractSyntax(String input) throws IOException, ClassNotFoundException { public LanguageServerTransferObject getResultSetAndAbstractSyntax(String input) throws IOException, ClassNotFoundException {
System.setOut(new PrintStream(OutputStream.nullOutputStream())); System.setOut(new PrintStream(OutputStream.nullOutputStream()));
int RETRYCOUNT = 50;
for (int i = 0; i < RETRYCOUNT; i++) {
try {
File tempSourcefile = File.createTempFile("temp", ".java"); File tempSourcefile = File.createTempFile("temp", ".java");
tempSourcefile.deleteOnExit(); tempSourcefile.deleteOnExit();
@@ -25,7 +31,14 @@ public class LanguageServerInterface {
JavaTXCompiler tx = new JavaTXCompiler(tempSourcefile); JavaTXCompiler tx = new JavaTXCompiler(tempSourcefile);
var test = tx.getResultSetAndAbstractSyntax(tempSourcefile); var test = tx.getResultSetAndAbstractSyntax(tempSourcefile);
log.debug("JAVA-TX LANGUAGE SERVER INTERFACE RESULTED IN THE FOLLOWING: \n" + test.getResultSets().toString());
System.setOut(System.out); System.setOut(System.out);
return test; return test;
} catch (Exception e) {
log.error("ERROR FETCHING COMPILER RESULTS: \n" + e.getMessage());
log.warn("NEW RETRY. RETRYCOUNT IS: " + i);
}
}
throw new RuntimeException("ERROR FETCHING COMPILER RESULTS");
} }
} }

View File

@@ -0,0 +1,19 @@
package de.dhbw.compiler.languageServerInterface.model;
import de.dhbw.compiler.typeinference.unify.UnifyResultEvent;
import de.dhbw.compiler.typeinference.unify.UnifyResultListener;
import de.dhbw.helper.TypeResolver;
public class ResultSetListener implements UnifyResultListener {
TypeResolver typeResolver;
public ResultSetListener(TypeResolver typeResolver){
this.typeResolver = typeResolver;
}
@Override
public void onNewTypeResultFound(UnifyResultEvent evt) {
}
}

View File

@@ -1,32 +1,82 @@
package de.dhbw.helper; package de.dhbw.helper;
import org.apache.log4j.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
public class TextHelper { public class TextHelper {
private static final Logger log = Logger.getLogger(TextHelper.class);
public Integer getEndingCharOfStartingChar(Integer line, Integer startChar, String input){ public Integer getClassPositionForGeneric(Integer line, String input, Integer startChar){
log.info("Calculating Position of Class-Generic Variable at Line [" + line + "] and Char [" + startChar + "].");
List<String> endingChars = List.of("(", ")", " ", "{", "}", ";", ",");
String[] lines = input.split("\n"); String[] lines = input.split("\n");
if(lines.length < line){ if(lines.length < line){
log.warn("Returning hardcoded Value because the requested Line [" + line + "] does not exist in Text Document.");
return startChar+3; return startChar+3;
} }
String[] linesInChar = lines[line].split(""); String[] linesInChar = lines[line].split("");
var index = startChar;
var found = false;
for (int i = startChar; i < linesInChar.length; i++) { for (int i = startChar; i < linesInChar.length; i++) {
if(linesInChar[i].contains("{")){
index = i;
found = true;
break;
}
}
if(!found){
index = linesInChar.length-1;
}
for(int j = index; j <= linesInChar.length; j--){
if(!linesInChar[j].isEmpty() && !linesInChar[j].equals(" ")){
return j;
}
}
return index;
}
public Integer getEndingCharOfStartingChar(Integer line, Integer startChar, String input){
log.info("Calculating ending-Position for Variable at Line [" + line + "] and Char [" + startChar + "].");
List<String> endingChars = List.of("(", ")", " ", "{", "}", ";", ",");
String[] lines = input.split("\n");
if(lines.length < line){
log.warn("Returning hardcoded Value because the requested Line [" + line + "] does not exist in Text Document.");
return startChar+3;
}
String[] linesInChar = lines[line].split("");
var index = startChar;
for (int i = startChar; i < linesInChar.length; i++) {
index++;
if(endingChars.contains(linesInChar[i])){ if(endingChars.contains(linesInChar[i])){
return i; return i;
} }
} }
return startChar+3; return index-1;
} }
public String getTextOfChars(String textDocument, Integer line, Integer charStart, Integer charEnd){ public String getTextOfChars(String textDocument, Integer line, Integer charStart, Integer charEnd){

View File

@@ -2,14 +2,20 @@ package de.dhbw.helper;
import de.dhbw.compiler.languageServerInterface.LanguageServerInterface; import de.dhbw.compiler.languageServerInterface.LanguageServerInterface;
import de.dhbw.compiler.languageServerInterface.model.LanguageServerTransferObject; import de.dhbw.compiler.languageServerInterface.model.LanguageServerTransferObject;
import de.dhbw.compiler.syntaxtree.ClassOrInterface;
import de.dhbw.compiler.syntaxtree.Method; import de.dhbw.compiler.syntaxtree.Method;
import de.dhbw.compiler.syntaxtree.SourceFile;
import de.dhbw.compiler.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbw.compiler.target.generate.GenericsResult;
import de.dhbw.compiler.typeinference.result.ResultSet;
import de.dhbw.model.*; import de.dhbw.model.*;
import org.apache.log4j.LogManager; import org.apache.log4j.LogManager;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.checkerframework.checker.units.qual.A;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/** /**
@@ -21,16 +27,33 @@ public class TypeResolver {
LanguageServerInterface languageServer; LanguageServerInterface languageServer;
private static final Logger logger = LogManager.getLogger(TypeResolver.class); private static final Logger logger = LogManager.getLogger(TypeResolver.class);
private List<ResultSet> currentResults = new ArrayList<>();
public List<ResultSet> getCurrentResults() {
return currentResults;
}
public void setCurrentResults(List<ResultSet> currentResults) {
this.currentResults = currentResults;
}
public void addToCurrentResults(List<ResultSet> additionalResults) {
this.currentResults.addAll(additionalResults);
}
public TypeResolver() { public TypeResolver() {
languageServer = new LanguageServerInterface(); languageServer = new LanguageServerInterface();
} }
private LanguageServerTransferObject getCacheOrCalculate(String input) throws IOException, ClassNotFoundException { private LanguageServerTransferObject getCacheOrCalculate(String input) throws IOException, ClassNotFoundException {
logger.info("Trying to find cached Compiler-Answer for input with key [" + input.hashCode() + "].");
if (dataCache.containsKey(input.hashCode())) { if (dataCache.containsKey(input.hashCode())) {
logger.debug("Returning Cache instead of calculating Types."); logger.info("Found Cache for the Input with key [" + input.hashCode() + "].");
return dataCache.get(input.hashCode()); return dataCache.get(input.hashCode());
} else { } else {
logger.info("Could not find Cache for Input with key [" + input.hashCode() + "]. Using Compiler Interface and Saving the Answer in Cache.");
var transferObject = languageServer.getResultSetAndAbstractSyntax(input); var transferObject = languageServer.getResultSetAndAbstractSyntax(input);
dataCache.put(input.hashCode(), transferObject); dataCache.put(input.hashCode(), transferObject);
return transferObject; return transferObject;
@@ -44,214 +67,170 @@ public class TypeResolver {
var isAlreadyImported = false; var isAlreadyImported = false;
for (var importStatement : abstractSyntax.getImports()) { for (var importStatement : abstractSyntax.getImports()) {
logger.debug(importStatement.toString() + "<>" + type);
isAlreadyImported = !isAlreadyImported && importStatement.toString().equals(type); isAlreadyImported = !isAlreadyImported && importStatement.toString().equals(type);
} }
return isAlreadyImported; return isAlreadyImported;
} catch (Exception e) { } catch (Exception e) {
logger.error("Error creating Transferobject: " + Arrays.toString(e.getStackTrace()));
return true; return true;
} }
} }
public ArrayList<Type> getAvailableTypes(List<ResultSet> resultSets, Method method) {
logger.info("Searching for resulting Types of Placeholder [" + method.getReturnType().toString() + "].");
ArrayList<String> normalType = new ArrayList<>();
/** resultSets.forEach(conSet -> {
* find the concrete Type of all TPHs and return the outcome as Hashmap. if (method.getReturnType().toString().toLowerCase().contains("tph ")) {
*/ normalType.add(conSet.resolveType(method.getReturnType()).resolvedType.toString());
public HashMap<String, ArrayList<String>> findAvailableTypes(LanguageServerTransferObject resultSet) throws IOException, ClassNotFoundException { }
});
HashMap<String, ArrayList<String>> typePlaceholderTypes = new HashMap<>();
resultSet.getResultSets().forEach(conSet -> { return new ArrayList<>(normalType.stream().filter(el -> !el.contains("TPH ")).map(el -> new Type(el, false)).toList());
for (var constraint : conSet.results) {
var typeNameString = constraint.getLeft().toString();
ArrayList<String> finalTypes = new ArrayList<>();
Queue<String> queue = new LinkedList<>();
if (typeNameString.contains("TPH ")) {
queue.add(typeNameString);
} else {
finalTypes.add(typeNameString);
} }
while (!queue.isEmpty()) { public ArrayList<Type> getAvailableGenericTypes(List<GenericsResult> genericsResult, Method method) {
var nextType = queue.remove(); logger.info("Searching for resulting Types of Placeholder [" + method.getReturnType().toString() + "].");
resultSet.getResultSets().forEach(el -> el.results.forEach(el2 -> { ArrayList<String> genericTypes = new ArrayList<>();
if (el2.getLeft().toString().equals(nextType)) { genericsResult.forEach(conSet -> {
if (el2.getRight().toString().toLowerCase().contains("tph")) { if (method.getReturnType().toString().toLowerCase().contains("tph ")) {
queue.add(el2.getRight().toString()); genericTypes.add(conSet.resolveTarget(method.getReturnType()).name().replaceAll("GTV ", ""));
} else {
if (!finalTypes.contains(el2.getRight().toString())) {
finalTypes.add(el2.getRight().toString());
} }
});
return new ArrayList<>(genericTypes.stream().filter(el -> !el.contains("TPH ")).map(el -> new Type(el, true)).toList());
} }
public ArrayList<Type> getAvailableGenericTypes(List<GenericsResult> genericsResult, RefTypeOrTPHOrWildcardOrGeneric parameter) {
logger.info("Searching for resulting Types of Placeholder [" + parameter.toString() + "].");
ArrayList<String> paramTypes = new ArrayList<>();
genericsResult.forEach(conSet -> {
if (parameter.toString().toLowerCase().contains("tph ")) {
paramTypes.add(conSet.resolveTarget(parameter).name());
} }
})); });
return new ArrayList<>(paramTypes.stream().filter(el -> !el.contains("TPH ")).map(el -> new Type(el, true)).toList());
} }
typePlaceholderTypes.put(typeNameString, finalTypes);
public ArrayList<Type> getAvailableTypes(List<ResultSet> resultSets, RefTypeOrTPHOrWildcardOrGeneric parameter) {
logger.info("Searching for resulting Types of Placeholder [" + parameter.toString() + "].");
ArrayList<String> paramTypes = new ArrayList<>();
resultSets.forEach(conSet -> {
if (parameter.toString().toLowerCase().contains("tph ")) {
paramTypes.add(conSet.resolveType(parameter).resolvedType.toString());
}
});
return new ArrayList<>(paramTypes.stream().filter(el -> !el.contains("TPH ")).map(el -> new Type(el, false)).toList());
}
public ArrayList<Type> filterOutDuplicates(List<Type> typeListOne, List<Type> typeListTwo) {
ArrayList<Type> filteredArrayList = new ArrayList<>();
typeListOne.forEach(el -> {
boolean found = false;
for(Type typeInListTwo : typeListTwo) {
found = found || typeInListTwo.getType().equals(el.getType());
}
if(!found) {
filteredArrayList.add(el);
}
});
return filteredArrayList;
}
public ArrayList<Type> filterOutDuplicates(List<Type> typeListOne) {
HashMap<String, Type> hashMap = new HashMap<>();
typeListOne.forEach(el -> {
hashMap.put(el.getType(), el);
});
return new ArrayList<>(hashMap.values());
}
public ArrayList<Type> getClassGenerics(Map<SourceFile, List<GenericsResult>> genericsResult, Method method, ClassOrInterface clazz) {
ArrayList<Type> genericTypes = new ArrayList<>();
genericsResult.forEach(((key, value) -> value.forEach(genericResultSet -> {
var result = genericResultSet.resolveTarget(method.getReturnType());
var genericResult = genericResultSet.getBounds(method.getReturnType(), clazz, method);
if (result != null && genericResult != null) {
genericResult.forEach(res -> {
if (res != null && !res.isOnMethod()) {
genericTypes.add(new Type("<" + result.name() + (res.bound().toString().equals("java.lang.Object") ? ">" : " extends " + res.bound().toString() + ">"), true));
} }
} }
); );
return typePlaceholderTypes;
} }
public ArrayList<String> findTypeOfMethod(LanguageServerTransferObject transferObj, Method method) throws IOException, ClassNotFoundException { })));
var typeHashMap = findAvailableTypes(transferObj); return genericTypes;
if (method.getReturnType().toString().contains("TPH ")) {
return typeHashMap.get(method.getReturnType().toString()) == null ? new ArrayList<>() : typeHashMap.get(method.getReturnType().toString());
}
return new ArrayList<>();
}
public ArrayList<ArrayList<String>> findTypesOfAllParameters(LanguageServerTransferObject transferObj, Method method) throws IOException, ClassNotFoundException {
ArrayList<ArrayList<String>> paramTypes = new ArrayList<>();
var typeHashMap = findAvailableTypes(transferObj);
for (var param : method.getParameterList()) {
if (param.getType().toString().contains("TPH ")) {
if (!typeHashMap.containsKey(param.getType().toString()) || typeHashMap.get(param.getType().toString()) == null) {
logger.debug("Type is null in Types");
paramTypes.add(new ArrayList<>(List.of("java.lang.Object")));
} else {
paramTypes.add(typeHashMap.get(param.getType().toString()));
}
} else {
paramTypes.add(new ArrayList<>());
}
}
return paramTypes;
} }
/** /**
* Zum Erhalt für sowohl Parameter als auch Methoden. * Zum Erhalt für sowohl Parameter als auch Methoden.
*/ */
public ArrayList<LSPVariable> infereMethodsWithParameters(String input) throws IOException, ClassNotFoundException { public ArrayList<LSPVariable> infereInput(String input) throws IOException, ClassNotFoundException {
var transferObj = getCacheOrCalculate(input); logger.info("Infering Types for Input.");
ArrayList<Type> genericClassTypes = new ArrayList<>();
var transferObj = languageServer.getResultSetAndAbstractSyntax(input);
ArrayList<LSPVariable> methodsWithParametersLSPVariableList = new ArrayList<>(); ArrayList<LSPVariable> methodsWithParametersLSPVariableList = new ArrayList<>();
//TODO: Hier noch irgendwie die Klasse rausfinden oder durchgehen. //TODO: Hier noch irgendwie die Klasse rausfinden oder durchgehen.
//GENERICS OF CLASS
for (var method : transferObj.getAst().getAllMethods()) { for (var method : transferObj.getAst().getAllMethods()) {
ArrayList<Type> genericTypes = new ArrayList<>();
for (var clazz : transferObj.getAst().getClasses()) { for (var clazz : transferObj.getAst().getClasses()) {
transferObj.getGeneratedGenerics().forEach(((key, value) -> value.forEach(genericResultSet -> { ArrayList<Type> genericTypes = getClassGenerics(transferObj.getGeneratedGenerics(), method, clazz);
TextHelper helper = new TextHelper();
var result = genericResultSet.resolveTarget(method.getReturnType()); methodsWithParametersLSPVariableList.add(new LSPClass("test", genericTypes, clazz.getOffset().getLine(), helper.getClassPositionForGeneric(clazz.getOffset().getLine() - 1, input, clazz.getOffset().getStopIndex()), clazz.getOffset().getStopIndex()));
var result2 = genericResultSet.getBounds(method.getReturnType(), clazz, method);
if (result != null && result2 != null) {
result2.forEach(res -> {
boolean alreadyInList2 = false;
for (Type type : genericTypes) {
alreadyInList2 = type.getType().equals("<" + result.name() + " extends " + res.bound().toString() + ">") || alreadyInList2;
} }
if (res == null) {
logger.debug("TEST RES IST NULL");
} }
if (!alreadyInList2) {
assert res != null;
genericTypes.add(new Type("<" + result.name() + " extends " + res.bound().toString() + ">", true));
genericClassTypes.add(new Type(result.name(), true));
}
}
);
}
})));
methodsWithParametersLSPVariableList.add(new LSPClass("test", genericTypes, clazz.getOffset().getLine(), clazz.getOffset().getCharPositionInLine() + 10, clazz.getOffset().getStopIndex()));
}
}
for (var method : transferObj.getAst().getAllMethods()) { for (var method : transferObj.getAst().getAllMethods()) {
if (method.getReturnType().toString().toLowerCase().contains("tph")) { var types = getAvailableTypes(transferObj.getResultSets(), method);
var normalType = findTypeOfMethod(transferObj, method); var generics = getAvailableGenericTypes(transferObj.getGeneratedGenerics().values().stream().flatMap(List::stream).collect(Collectors.toList()), method);
ArrayList<Type> types = new ArrayList<>(normalType.stream().map(el -> new Type(el, false)).toList());
ArrayList<Type> genericTypes = new ArrayList<>();
transferObj.getGeneratedGenerics().forEach(((key, value) -> value.forEach(genericResultSet -> {
var result = genericResultSet.resolveTarget(method.getReturnType());
if (result != null) {
boolean alreadyInList = false;
for (Type type : genericTypes) {
alreadyInList = type.getType().equals(result.name()) || alreadyInList;
}
for (Type type : types) {
alreadyInList = type.getType().equals(result.name()) || alreadyInList;
}
if (!alreadyInList) {
genericTypes.add(new Type(result.name(), true));
}
}
})));
types.addAll(genericTypes);
if (!types.isEmpty()) { if (!types.isEmpty()) {
methodsWithParametersLSPVariableList.add(new LSPMethod(method.name, 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()));
} }
if (!generics.isEmpty()) {
ArrayList<Type> typesThatAreGeneric = filterOutDuplicates(generics, types);
typesThatAreGeneric.forEach(el -> el.setType("<" + el.getType() + "> " + el.getType()));
methodsWithParametersLSPVariableList.add(new LSPMethod(method.name, filterOutDuplicates(typesThatAreGeneric), method.getOffset().getLine(), method.getOffset().getCharPositionInLine(), method.getOffset().getStopIndex()));
} }
var paramType = findTypesOfAllParameters(transferObj, method);
logger.debug("Returned " + paramType.size() + " Parameters");
int index = 0;
for (var param : method.getParameterList()) { for (var param : method.getParameterList()) {
ArrayList<Type> typeParam = getAvailableTypes(transferObj.getResultSets(), param.getType());
ArrayList<Type> genericParam = getAvailableGenericTypes(transferObj.getGeneratedGenerics().values().stream().flatMap(List::stream).collect(Collectors.toList()), param.getType());
ArrayList<Type> typeParamArray = new ArrayList<>(); if (!typeParam.isEmpty()) {
transferObj.getGeneratedGenerics().forEach(((key, value) -> value.forEach(genericResultSet -> { methodsWithParametersLSPVariableList.add(new LSPParameter(method.name, filterOutDuplicates(typeParam), param.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex()));
var result = genericResultSet.resolveTarget(param.getType());
boolean isClassVariable = false;
for (Type typeClass : genericClassTypes) {
isClassVariable = typeClass.getType().equals(result.name()) || isClassVariable;
} }
if (!genericParam.isEmpty()) {
boolean alreadyInList = false; ArrayList<Type> typesThatAreGeneric = filterOutDuplicates(genericParam, typeParam);
for (Type type : typeParamArray) { methodsWithParametersLSPVariableList.add(new LSPMethod(method.name, filterOutDuplicates(typesThatAreGeneric), method.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex()));
alreadyInList = type.getType().equals(result.name()) || alreadyInList;
} }
if (!alreadyInList && isClassVariable) {
typeParamArray.add(new Type(result.name(), true));
}
})));
if (paramType.get(index) != null && !paramType.get(index).isEmpty()) {
typeParamArray.addAll(new ArrayList<>(paramType.get(index).stream().map(el -> new Type(el, false)).toList()));
}
methodsWithParametersLSPVariableList.add(new LSPParameter(method.name, typeParamArray, param.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex()));
index++;
} }
} }
@@ -259,44 +238,4 @@ public class TypeResolver {
} }
@Deprecated
public ArrayList<LSPMethod> infereMethodType(String input) throws IOException, ClassNotFoundException {
var transferObj = getCacheOrCalculate(input);
ArrayList<LSPMethod> methodNameWithTypeList = new ArrayList<>();
for (var method : transferObj.getAst().getAllMethods()) {
var type = findTypeOfMethod(transferObj, method);
methodNameWithTypeList.add(new LSPMethod(method.name, new ArrayList<>(type.stream().map(el -> new Type(el, false)).toList()), method.getOffset().getLine(), method.getOffset().getStartIndex(), method.getOffset().getStopIndex()));
}
return methodNameWithTypeList;
}
@Deprecated
public ArrayList<LSPParameter> infereParameterType(String input, String methodName) throws IOException, ClassNotFoundException {
var transferObj = getCacheOrCalculate(input);
System.out.println(transferObj.getResultSets().toString());
System.out.println(transferObj.getPrintedAst());
ArrayList<LSPParameter> LSPParameter = new ArrayList<>();
for (var method : transferObj.getAst().getAllMethods()) {
if (method.name.equals(methodName)) {
int index = 0;
for (var param : method.getParameterList()) {
var type = findTypesOfAllParameters(transferObj, method);
LSPParameter.add(new LSPParameter(method.name, new ArrayList<>(type.get(index).stream().map(el -> new Type(el, false)).toList()), param.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex()));
index++;
}
}
}
return LSPParameter;
}
} }

View File

@@ -3,7 +3,7 @@ log4j.rootLogger=DEBUG, FILE
# File Appender # File Appender
log4j.appender.FILE=org.apache.log4j.FileAppender log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=/home/ruben/logs/application.log log4j.appender.FILE.File=C:/Users/ruben/Desktop/log.txt
log4j.appender.FILE.Append=true log4j.appender.FILE.Append=true
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c{1}] %m%n log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c{1}] %m%n

View File

@@ -1,33 +1,36 @@
import de.dhbw.compiler.languageServerInterface.LanguageServerInterface; import de.dhbw.compiler.languageServerInterface.LanguageServerInterface;
import de.dhbw.compiler.target.generate.GenericsResult;
import de.dhbw.helper.TextHelper; import de.dhbw.helper.TextHelper;
import de.dhbw.helper.TypeResolver; import de.dhbw.helper.TypeResolver;
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.List; import java.util.ArrayList;
public class CompilerInterfaceTest { public class CompilerInterfaceTest {
@Test @Test
public void testAbstractSyntaxAsString() throws IOException, ClassNotFoundException { public void testAbstractSyntaxAsString() throws IOException, ClassNotFoundException {
LanguageServerInterface languageServer = new LanguageServerInterface(); LanguageServerInterface languageServer = new LanguageServerInterface();
var res = languageServer.getResultSetAndAbstractSyntax("import java.lang.Integer; public class test{\n" + var res = languageServer.getResultSetAndAbstractSyntax("import java.lang.Integer;\n import java.lang.String;\n" +
" \n" + "public class test{\n" +
" public main(testa){\n" + "public main(test){" +
" return testa;\n" + "if(0>1){" +
" }\n" + "return \"w\";" +
"}" +
"Integer i = 0;" +
"return i;" +
"}" +
"}"); "}");
System.out.println("TEST OUTPUT:"); System.out.println("TEST OUTPUT:");
var results = res.getGeneratedGenerics().entrySet().iterator().next(); ArrayList<String> allTypes = new ArrayList<>();
var genericResult = results.getValue().get(0);
res.getResultSets().forEach(el -> allTypes.add(el.resolveType(res.getAst().getAllMethods().get(0).getReturnType()).resolvedType.toString()));
var results = res.getGeneratedGenerics().entrySet().iterator().next();
var something = genericResult.get(res.getAst().getAllMethods().get(0));
var somethingTwo = genericResult.get(res.getAst().getClasses().get(0));
var somethingThree = genericResult.resolve(res.getAst().getAllMethods().get(0).getParameterList().getFormalparalist().get(0).getType());
System.out.println(res.getResultSets().toString()); System.out.println(res.getResultSets().toString());
@@ -41,7 +44,7 @@ public class CompilerInterfaceTest {
TypeResolver typeResolver = new TypeResolver(); TypeResolver typeResolver = new TypeResolver();
var res = typeResolver.infereMethodsWithParameters("import java.lang.Integer; public class test{\n" + var res = typeResolver.infereInput("import java.lang.Integer; public class test{\n" +
" \n" + " \n" +
" public main(testa){\n" + " public main(testa){\n" +
" return testa;\n" + " return testa;\n" +
@@ -53,7 +56,7 @@ public class CompilerInterfaceTest {
@Test @Test
public void testTypeFinder() throws IOException, ClassNotFoundException { public void testTypeFinder() throws IOException, ClassNotFoundException {
TypeResolver typeResolver = new TypeResolver(); TypeResolver typeResolver = new TypeResolver();
var inferedMethods = typeResolver.infereMethodsWithParameters("import java.lang.Integer;\n import java.lang.String;\n" + var inferedMethods = 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){" +
@@ -72,7 +75,7 @@ public class CompilerInterfaceTest {
@Test @Test
public void testGenericTypes() throws IOException, ClassNotFoundException { public void testGenericTypes() throws IOException, ClassNotFoundException {
TypeResolver typeResolver = new TypeResolver(); TypeResolver typeResolver = new TypeResolver();
var inferedMethods = typeResolver.infereMethodsWithParameters("import java.lang.Integer; public class test{\n" + var inferedMethods = typeResolver.infereInput("import java.lang.Integer; public class test{\n" +
" \n" + " \n" +
" public main(testa){\n" + " public main(testa){\n" +
" return testa;\n" + " return testa;\n" +
@@ -87,7 +90,7 @@ public class CompilerInterfaceTest {
@Test @Test
public void testTypeFinderParameter() throws IOException, ClassNotFoundException { public void testTypeFinderParameter() throws IOException, ClassNotFoundException {
TypeResolver typeResolver = new TypeResolver(); TypeResolver typeResolver = new TypeResolver();
var inferedMethods = typeResolver.infereMethodsWithParameters("import java.lang.Integer;\n" + var inferedMethods = typeResolver.infereInput("import java.lang.Integer;\n" +
"import java.lang.String; \n" + "import java.lang.String; \n" +
"public class test{\n" + "public class test{\n" +
" public main(test, test2){\n" + " public main(test, test2){\n" +

View File

@@ -44,12 +44,13 @@ To use this Language Server you have to follow this steps:
4. run ```npm run compile``` 4. run ```npm run compile```
5. Go to Debug and Run the Extension. 5. Go to Debug and Run the Extension.
6. Press F1 and execute the Hello World Command. 6. Press F1 and execute the Hello World Command.
7. You can create .java Files which will be analysed by the Language Server. 7. You can create .jav Files which will be analysed by the Language Server.
## Known Problems and what to do ## Known Problems and what to do
1. If the TypeInference does not display any Typehints or Typeselection, restart the IDE including the Extension thus deleting the Cache. 1. If the TypeInference does not display any Typehints or Typeselection, restart the IDE including the Extension thus deleting the Cache.
2. Selecting a Generic will Result in a Class-Generic extending Object, wich is not legal in Java. Delete the extends Statement.
3. Selecting a Generic after another Generic is selected results in illegal Syntax. Delete the newly greated Generic and add the Generic Name and if needet its extension into the other Declaration.
## Logic ## Logic
The Language Server in itself can be used for any Client. The Clients task is to start the Langauge Server and handle the Communication with it. The Language Server in itself can be used for any Client. The Clients task is to start the Langauge Server and handle the Communication with it.