12 Commits

11 changed files with 314 additions and 283 deletions

View File

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

View File

@@ -1,21 +1,14 @@
package de.dhbw;
import com.google.common.base.Stopwatch;
import de.dhbw.compiler.languageServerInterface.ParserInterface;
import de.dhbw.compiler.languageServerInterface.model.ParserError;
import de.dhbw.helper.CodeSnippetOptions;
import de.dhbw.helper.TextHelper;
import de.dhbw.helper.TypeResolver;
import de.dhbw.model.LSPVariable;
import de.dhbw.model.ParseError.DiagnoseErrorListener;
import de.dhbw.model.SnippetWithName;
import de.dhbw.compiler.parser.antlr.Java17Lexer;
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 de.dhbw.model.Type;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
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);
LanguageClient client;
HashMap<String, List<InlayHint>> globalInlayHintMap = new HashMap<>();
Boolean calculate = false;
HashMap<String, List<Diagnostic>> globalDiagnosticsMap = new HashMap<>();
HashMap<String, String> textDocuments = new HashMap<>();
CodeSnippetOptions codeSnippetOptions = new CodeSnippetOptions();
@@ -90,7 +85,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
*/
@Override
public void didChange(DidChangeTextDocumentParams params) {
logger.debug("DIDCHANGE-EVENT");
logger.info("DIDCHANGE-EVENT");
AtomicReference<String> summedUp = new AtomicReference<>("");
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);
logger.debug("Found " + parserErrors.size() + " Errors.");
logger.info("Found " + parserErrors.size() + " Errors.");
List<Diagnostic> diagnostics = parserErrors.stream().map(el -> {
Range errorRange = new Range(
@@ -131,7 +126,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
*/
@Override
public CompletableFuture<List<? extends TextEdit>> formatting(DocumentFormattingParams params) {
logger.debug("FORMAT-EVENT");
logger.info("FORMAT-EVENT");
List<TextEdit> edits = new ArrayList<>();
@@ -157,30 +152,37 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
@Override
public void didSave(DidSaveTextDocumentParams didSaveTextDocumentParams) {
calculate = true;
}
@Override
public CompletableFuture<List<InlayHint>> inlayHint(InlayHintParams params) {
logger.debug("INLAYHINT-EVENT");
logger.info("The Client requested Inlay-Hints.");
return CompletableFuture.supplyAsync(() -> {
ArrayList<Diagnostic> diagnostics = new ArrayList<>();
var sWatch = Stopwatch.createUnstarted();
sWatch.start();
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<>();
for (var variable : typesOfMethodAndParameters) {
InlayHint inlayHint = new InlayHint();
AtomicReference<String> typeDisplay = new AtomicReference<>("");
variable.getPossibleTypes().forEach(el -> typeDisplay.getAndSet("| " + el.getType()));
String typeDisplay = "";
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.setKind(InlayHintKind.Parameter);
inlayHint.setPaddingRight(true);
inlayHint.setPaddingRight(true);
typeHint.add(inlayHint);
@@ -192,7 +194,8 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
);
Diagnostic diagnostic = new Diagnostic(
errorRange,
typ.getType(),
//TODO: REMOVE! Temporary Fix because GTV, like TPH can be thrown away in the TypeResolver
typ.getType().replaceAll("GTV ", ""),
DiagnosticSeverity.Hint,
"JavaTX Language Server"
);
@@ -201,23 +204,29 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
diagnostics.add(diagnostic);
}
}
logger.debug("Returning " + typeHint.size() + " Typehints.");
logger.info("Returning [" + typeHint.size() + "] Inlay-Hints.");
globalDiagnosticsMap.put(params.getTextDocument().getUri(), diagnostics);
globalInlayHintMap.put(params.getTextDocument().getUri(), typeHint);
PublishDiagnosticsParams diagnosticsParams = new PublishDiagnosticsParams(params.getTextDocument().getUri(), diagnostics);
client.publishDiagnostics(diagnosticsParams);
sWatch.stop();
logger.info("Finished Calculating in [" + sWatch.elapsed().toSeconds() + "s]");
return typeHint;
} catch (Exception e) {
sWatch.stop();
logger.info("Calculating returned an Error after [" + sWatch.elapsed().toSeconds() + "s]");
String stacktrace = "";
for (var i : e.getStackTrace()) {
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();
}
});
@@ -353,22 +362,18 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
@Override
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<Diagnostic> diagnosticInCurrentDocument = params.getContext().getDiagnostics();
logger.debug("Document has " + diagnosticInCurrentDocument.size() + " Diagnostics.");
logger.info("Document has currently [" + diagnosticInCurrentDocument.size() + "] Diagnostics.");
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
List<Diagnostic> diagnosticsOverlappingHover = diagnosticInCurrentDocument.stream()
.filter(diagnostic -> rangesOverlap(diagnostic.getRange(), requestedRange)).toList();
for (var dia : diagnosticInCurrentDocument) {
logger.debug(dia.getMessage());
}
Range rangeOfInsert = params.getRange();
String documentUri = params.getTextDocument().getUri();
@@ -401,15 +406,15 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
listOfChanges.add(new TextEdit(diagnostic.getRange(), genericType));
}
}
}else{
} else {
listOfChanges.add(new TextEdit(rangeOfInsert, typeWithReplacedVariable));
}
var isTypeImported = false;
var isTypeImported = typeResolver.isTypeImported(textDocuments.get(params.getTextDocument().getUri()), typeDiagnostic.getMessage());
if (!typeDiagnostic.getCode().getLeft().equalsIgnoreCase("generic")) {
isTypeImported = typeResolver.isTypeImported(textDocuments.get(params.getTextDocument().getUri()), typeDiagnostic.getMessage());
}
if (!isTypeImported && !typeDiagnostic.getMessage().equals("void") && !typeDiagnostic.getCode().getLeft().equals("GENERIC")) {
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"));
}
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<>();
changes.put(documentUri, listOfChanges);
@@ -430,7 +435,7 @@ public class JavaTXTextDocumentService implements org.eclipse.lsp4j.services.Tex
action.setEdit(edit);
actions.add(Either.forRight(action));
} 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,30 +2,43 @@ package de.dhbw.compiler.languageServerInterface;
import de.dhbw.compiler.languageServerInterface.model.LanguageServerTransferObject;
import de.dhbw.compiler.core.JavaTXCompiler;
import org.apache.log4j.Logger;
import java.io.*;
/**
* Implementation of an Interface for the Language-Server to get the Resultset and abstract Syntax.
* */
*/
public class LanguageServerInterface {
private static final Logger log = Logger.getLogger(LanguageServerInterface.class);
/**
* get final Result Set
* */
*/
public LanguageServerTransferObject getResultSetAndAbstractSyntax(String input) throws IOException, ClassNotFoundException {
System.setOut(new PrintStream(OutputStream.nullOutputStream()));
File tempSourcefile = File.createTempFile("temp", ".java");
tempSourcefile.deleteOnExit();
int RETRYCOUNT = 50;
for (int i = 0; i < RETRYCOUNT; i++) {
try {
File tempSourcefile = File.createTempFile("temp", ".java");
tempSourcefile.deleteOnExit();
BufferedWriter out = new BufferedWriter(new FileWriter(tempSourcefile));
out.write(input);
out.close();
BufferedWriter out = new BufferedWriter(new FileWriter(tempSourcefile));
out.write(input);
out.close();
JavaTXCompiler tx = new JavaTXCompiler(tempSourcefile);
var test = tx.getResultSetAndAbstractSyntax(tempSourcefile);
System.setOut(System.out);
return test;
JavaTXCompiler tx = new JavaTXCompiler(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);
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

@@ -13,7 +13,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TypeInsertPlacer extends AbstractASTWalker {
public class TypeInsertPlacer extends AbstractASTWalker {
Set<TypeInsert> inserts = new HashSet<>();
private ResultSet withResults;
String pkgName;

View File

@@ -1,32 +1,82 @@
package de.dhbw.helper;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TextHelper {
private static final Logger log = Logger.getLogger(TextHelper.class);
public Integer getEndingCharOfStartingChar(Integer line, Integer startChar, String input){
List<String> endingChars = List.of("(", ")", " ", "{", "}", ";", ",");
public Integer getClassPositionForGeneric(Integer line, String input, Integer startChar){
log.info("Calculating Position of Class-Generic Variable at Line [" + line + "] and Char [" + startChar + "].");
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;
var found = false;
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])){
return i;
}
}
return startChar+3;
return index-1;
}
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.model.LanguageServerTransferObject;
import de.dhbw.compiler.syntaxtree.ClassOrInterface;
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 org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.checkerframework.checker.units.qual.A;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
@@ -21,16 +27,33 @@ public class TypeResolver {
LanguageServerInterface languageServer;
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() {
languageServer = new LanguageServerInterface();
}
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())) {
logger.debug("Returning Cache instead of calculating Types.");
logger.info("Found Cache for the Input with key [" + input.hashCode() + "].");
return dataCache.get(input.hashCode());
} 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);
dataCache.put(input.hashCode(), transferObject);
return transferObject;
@@ -44,214 +67,170 @@ public class TypeResolver {
var isAlreadyImported = false;
for (var importStatement : abstractSyntax.getImports()) {
logger.debug(importStatement.toString() + "<>" + type);
isAlreadyImported = !isAlreadyImported && importStatement.toString().equals(type);
}
return isAlreadyImported;
} catch (Exception e) {
logger.error("Error creating Transferobject: " + Arrays.toString(e.getStackTrace()));
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<>();
/**
* find the concrete Type of all TPHs and return the outcome as Hashmap.
*/
public HashMap<String, ArrayList<String>> findAvailableTypes(LanguageServerTransferObject resultSet) throws IOException, ClassNotFoundException {
HashMap<String, ArrayList<String>> typePlaceholderTypes = new HashMap<>();
resultSet.getResultSets().forEach(conSet -> {
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()) {
var nextType = queue.remove();
resultSet.getResultSets().forEach(el -> el.results.forEach(el2 -> {
if (el2.getLeft().toString().equals(nextType)) {
if (el2.getRight().toString().toLowerCase().contains("tph")) {
queue.add(el2.getRight().toString());
} else {
if (!finalTypes.contains(el2.getRight().toString())) {
finalTypes.add(el2.getRight().toString());
}
}
}
}));
}
typePlaceholderTypes.put(typeNameString, finalTypes);
}
}
);
return typePlaceholderTypes;
}
public ArrayList<String> findTypeOfMethod(LanguageServerTransferObject transferObj, Method method) throws IOException, ClassNotFoundException {
var typeHashMap = findAvailableTypes(transferObj);
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<>());
resultSets.forEach(conSet -> {
if (method.getReturnType().toString().toLowerCase().contains("tph ")) {
normalType.add(conSet.resolveType(method.getReturnType()).resolvedType.toString());
}
}
});
return paramTypes;
return new ArrayList<>(normalType.stream().filter(el -> !el.contains("TPH ")).map(el -> new Type(el, false)).toList());
}
public ArrayList<Type> getAvailableGenericTypes(List<GenericsResult> genericsResult, Method method) {
logger.info("Searching for resulting Types of Placeholder [" + method.getReturnType().toString() + "].");
ArrayList<String> genericTypes = new ArrayList<>();
genericsResult.forEach(conSet -> {
if (method.getReturnType().toString().toLowerCase().contains("tph ")) {
genericTypes.add(conSet.resolveTarget(method.getReturnType()).name().replaceAll("GTV ", ""));
}
});
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());
}
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 genericTypes;
}
/**
* Zum Erhalt für sowohl Parameter als auch Methoden.
*/
public ArrayList<LSPVariable> infereMethodsWithParameters(String input) throws IOException, ClassNotFoundException {
var transferObj = getCacheOrCalculate(input);
ArrayList<Type> genericClassTypes = new ArrayList<>();
public ArrayList<LSPVariable> infereInput(String input) throws IOException, ClassNotFoundException {
logger.info("Infering Types for Input.");
var transferObj = languageServer.getResultSetAndAbstractSyntax(input);
ArrayList<LSPVariable> methodsWithParametersLSPVariableList = new ArrayList<>();
//TODO: Hier noch irgendwie die Klasse rausfinden oder durchgehen.
//GENERICS OF CLASS
for (var method : transferObj.getAst().getAllMethods()) {
ArrayList<Type> genericTypes = new ArrayList<>();
for (var clazz : transferObj.getAst().getClasses()) {
transferObj.getGeneratedGenerics().forEach(((key, value) -> value.forEach(genericResultSet -> {
var result = genericResultSet.resolveTarget(method.getReturnType());
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()));
ArrayList<Type> genericTypes = getClassGenerics(transferObj.getGeneratedGenerics(), method, clazz);
TextHelper helper = new TextHelper();
methodsWithParametersLSPVariableList.add(new LSPClass("test", genericTypes, clazz.getOffset().getLine(), helper.getClassPositionForGeneric(clazz.getOffset().getLine() - 1, input, clazz.getOffset().getStopIndex()), clazz.getOffset().getStopIndex()));
}
}
for (var method : transferObj.getAst().getAllMethods()) {
if (method.getReturnType().toString().toLowerCase().contains("tph")) {
var normalType = findTypeOfMethod(transferObj, method);
var types = getAvailableTypes(transferObj.getResultSets(), 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()) {
methodsWithParametersLSPVariableList.add(new LSPMethod(method.name, types, method.getOffset().getLine(), method.getOffset().getCharPositionInLine(), method.getOffset().getStopIndex()));
}
if (!types.isEmpty()) {
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()) {
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<>();
transferObj.getGeneratedGenerics().forEach(((key, value) -> value.forEach(genericResultSet -> {
var result = genericResultSet.resolveTarget(param.getType());
boolean isClassVariable = false;
for (Type typeClass : genericClassTypes) {
isClassVariable = typeClass.getType().equals(result.name()) || isClassVariable;
}
boolean alreadyInList = false;
for (Type type : typeParamArray) {
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()));
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, typeParamArray, param.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex()));
index++;
if (!genericParam.isEmpty()) {
ArrayList<Type> typesThatAreGeneric = filterOutDuplicates(genericParam, typeParam);
methodsWithParametersLSPVariableList.add(new LSPMethod(method.name, filterOutDuplicates(typesThatAreGeneric), method.getOffset().getLine(), param.getOffset().getCharPositionInLine(), param.getOffset().getStopIndex()));
}
}
}
@@ -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
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.layout=org.apache.log4j.PatternLayout
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.target.generate.GenericsResult;
import de.dhbw.helper.TextHelper;
import de.dhbw.helper.TypeResolver;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
public class CompilerInterfaceTest {
@Test
public void testAbstractSyntaxAsString() throws IOException, ClassNotFoundException {
LanguageServerInterface languageServer = new LanguageServerInterface();
var res = languageServer.getResultSetAndAbstractSyntax("import java.lang.Integer; public class test{\n" +
" \n" +
" public main(testa){\n" +
" return testa;\n" +
" }\n" +
var res = languageServer.getResultSetAndAbstractSyntax("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;" +
"}" +
"}");
System.out.println("TEST OUTPUT:");
var results = res.getGeneratedGenerics().entrySet().iterator().next();
var genericResult = results.getValue().get(0);
ArrayList<String> allTypes = new ArrayList<>();
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());
@@ -41,7 +44,7 @@ public class CompilerInterfaceTest {
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" +
" public main(testa){\n" +
" return testa;\n" +
@@ -53,7 +56,7 @@ public class CompilerInterfaceTest {
@Test
public void testTypeFinder() throws IOException, ClassNotFoundException {
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 main(test){" +
"if(0>1){" +
@@ -72,7 +75,7 @@ public class CompilerInterfaceTest {
@Test
public void testGenericTypes() throws IOException, ClassNotFoundException {
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" +
" public main(testa){\n" +
" return testa;\n" +
@@ -87,7 +90,7 @@ public class CompilerInterfaceTest {
@Test
public void testTypeFinderParameter() throws IOException, ClassNotFoundException {
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" +
"public class test{\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```
5. Go to Debug and Run the Extension.
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
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
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.