use of org.eclipse.lsp4j.jsonrpc.messages.Tuple.Two in project OberonEmulator by schierlm.
the class Server method getErrors.
protected List<Diagnostic> getErrors(OberonFile of) throws InterruptedException, ExecutionException {
// be careful here and watch out for deadlocks locking two different
// OberonFile instances
Two<List<Diagnostic>, Range> pair = of.waitWhenDirty(backgroundExecutor, ar -> {
Range range = new Range(new Position(0, 0), new Position(0, 0));
Identifier moduleDef = ar.getIdDefinitions().get(1);
if (moduleDef != null && moduleDef.getKind() == SymbolKind.Module) {
range = new Range(of.getPos(moduleDef.getStartPos()), of.getPos(moduleDef.getEndPos()));
}
return new Two<>(ar.getErrors(), range);
}).get();
List<Diagnostic> result = pair.getFirst();
if (of.getCachedModuleName() != null) {
if (allFiles(of.getCachedModuleName(), false).stream().anyMatch(of2 -> of.getCachedModuleName().equals(of2.getCachedModuleName()) && !of.getNormalizedUri().equals(of2.getNormalizedUri()))) {
result = new ArrayList<>(result);
result.add(new Diagnostic(pair.getSecond(), "Same module name used by multiple files"));
}
}
return result;
}
use of org.eclipse.lsp4j.jsonrpc.messages.Tuple.Two in project OberonEmulator by schierlm.
the class Server method getTextDocumentService.
@Override
public TextDocumentService getTextDocumentService() {
return new TextDocumentService() {
@Override
public void didSave(DidSaveTextDocumentParams params) {
}
@Override
public void didOpen(DidOpenTextDocumentParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
if (of == null) {
of = new OberonFile(params.getTextDocument().getUri(), params.getTextDocument().getText());
} else {
of.setContent(params.getTextDocument().getText());
}
openFiles.put(params.getTextDocument().getUri(), of);
fileChanged(of);
}
@Override
public void didClose(DidCloseTextDocumentParams params) {
fileClosed(openFiles.remove(params.getTextDocument().getUri()));
}
@Override
public void didChange(DidChangeTextDocumentParams params) {
OberonFile of = openFiles.get(params.getTextDocument().getUri());
if (params.getContentChanges().size() != 1)
throw new IllegalArgumentException("Incremental changes not supported)");
of.setContent(params.getContentChanges().get(0).getText());
fileChanged(of);
}
@Override
public CompletableFuture<List<Either<SymbolInformation, DocumentSymbol>>> documentSymbol(DocumentSymbolParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
if (of == null)
return CompletableFuture.completedFuture(new ArrayList<>());
return of.waitWhenDirty(backgroundExecutor, f -> new ArrayList<>(f.getOutline()));
}
@Override
public CompletableFuture<SemanticTokens> semanticTokensFull(SemanticTokensParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
return of.waitWhenDirty(backgroundExecutor, f -> new SemanticTokens(IntStream.of(f.getSemanticTokens()).mapToObj(i -> i).collect(Collectors.toList())));
}
@Override
public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completion(CompletionParams position) {
OberonFile of = fileForURI(position.getTextDocument().getUri());
int pos = of.getRawPos(position.getPosition());
if (pos == -1)
return CompletableFuture.completedFuture(Either.forLeft(new ArrayList<>()));
String prefix = of.getContent().substring(0, pos);
CompletableFuture<Either<List<CompletionItem>, CompletionList>> result = new CompletableFuture<>();
backgroundExecutor.submit(() -> {
try {
List<CompletionItem> completions = bridge.complete(prefix);
result.complete(Either.forLeft(completions));
} catch (Throwable ex) {
ex.printStackTrace();
result.completeExceptionally(ex);
}
});
return result;
}
@Override
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition(DefinitionParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
return of.waitWhenDirty(backgroundExecutor, ar -> {
if (debug && params.getPosition().getLine() == 0 && params.getPosition().getCharacter() == 0) {
// validate all references in this file!
int[] errors = { 0 };
for (Identifier id : ar.getIdDefinitions().values()) {
if (id.getKind() == SymbolKind.Module) {
continue;
}
try {
findRangeToDelete(id, ar, new HashSet<Integer>(Arrays.asList(id.getEndPos())));
} catch (RuntimeException ex) {
System.err.println("Unable to find delete range for pos " + id.getEndPos());
errors[0]++;
}
}
for (Identifier id : ar.getIdReferences().values()) {
String desc_ = id.getDefinition().toString();
IdentifierReference definition = lookupSymbolRef(id.getDefinition());
if (definition == null) {
System.err.println(desc_ + ": symbol reference lookup failed");
continue;
} else if (!definition.equals(id.getDefinition())) {
desc_ += "->" + definition;
}
desc_ += " '" + of.getContent().substring(id.getStartPos(), id.getEndPos()) + "'";
String desc = desc_;
final boolean[] found = { false };
for (OberonFile dof : allFiles(definition.getModule(), false)) {
try {
dof.waitWhenDirty(backgroundExecutor, dar -> {
if (dar.getModuleName().equals(definition.getModule())) {
found[0] = true;
if (!dar.getIdDefinitions().containsKey(definition.getEndPos())) {
System.err.println(desc + ": identifier not found");
errors[0]++;
}
}
return null;
}).get();
} catch (InterruptedException | ExecutionException ex) {
}
}
if (!found[0]) {
System.err.println(desc + ": module not loaded");
errors[0]++;
}
}
System.err.println("Reference validation finished, " + errors[0] + " errors detected.");
}
int pos = of.getRawPos(params.getPosition());
Identifier id = findAt(ar.getIdReferences(), pos);
return id != null ? id.getDefinition() : null;
}).thenApply((IdentifierReference sref) -> {
List<Location> result = new ArrayList<>();
if (sref != null) {
IdentifierReference definition = lookupSymbolRef(sref);
if (definition != null) {
Location loc = buildLocation(of, of.getCachedModuleName(), definition);
if (loc != null) {
result.add(loc);
}
}
}
return Either.forLeft(result);
});
}
private CallHierarchyItem buildCallHierarchyItem(OberonFile of, AnalysisResult ar, Identifier id) {
CallHierarchyItem chi = new CallHierarchyItem();
chi.setName(of.getContent().substring(id.getStartPos(), id.getEndPos()));
chi.setKind(id.getKind());
chi.setData(new Two<>(ar.getModuleName(), id.getEndPos()));
Range r = new Range(of.getPos(id.getStartPos()), of.getPos(id.getEndPos()));
chi.setSelectionRange(r);
if (id.getKind() == SymbolKind.Function) {
int[] func = findFunction(ar.getFunctionRanges(), id.getEndPos());
if (func != null && func[1] == id.getEndPos()) {
r = new Range(of.getPos(func[0]), of.getPos(func[1]));
}
}
chi.setRange(r);
return chi;
}
private Location buildLocation(OberonFile baseFile, String baseModule, IdentifierReference definition) {
String uri = null;
for (OberonFile of : allFiles(definition.getModule(), false)) {
try {
Either<Location, String> loc = of.<Either<Location, String>>waitWhenDirty(backgroundExecutor, ar -> {
if (ar.getModuleName().equals(definition.getModule())) {
Identifier id = ar.getIdDefinitions().get(definition.getEndPos());
if (id != null) {
return Either.forLeft(new Location(of.getUri(), new Range(of.getPos(id.getStartPos()), of.getPos(id.getEndPos()))));
}
return Either.forRight(of.getUri());
}
return null;
}).get();
if (loc != null && loc.isLeft())
return loc.getLeft();
else if (loc != null && loc.isRight())
uri = loc.getRight();
} catch (InterruptedException | ExecutionException ex) {
}
}
if (uri == null) {
String baseUri = baseFile.getUri();
int pos = baseUri.lastIndexOf("/" + baseModule + ".");
if (pos != -1) {
uri = baseUri.substring(0, pos + 1) + definition.getModule() + baseUri.substring(pos + baseModule.length() + 1);
}
}
Location location = uri == null ? null : new Location(uri, new Range(new Position(0, 0), new Position(0, 0)));
return location;
}
@Override
public CompletableFuture<List<? extends Location>> references(ReferenceParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
return of.waitWhenDirty(backgroundExecutor, ar -> {
int pos = of.getRawPos(params.getPosition());
Identifier def = findAt(ar.getIdDefinitions(), pos);
if (def != null) {
return new IdentifierReference(def.isExported() ? ar.getModuleName() : "<local>", def.getEndPos());
}
Identifier ref = findAt(ar.getIdReferences(), pos);
if (ref != null) {
if (ref.getDefinition().getModule().equals(ar.getModuleName())) {
if (!ar.getIdDefinitions().get(ref.getDefinition().getEndPos()).isExported() && ref.getDefinition().getEndPos() >= 0) {
return new IdentifierReference("<local>", ref.getDefinition().getEndPos());
}
}
return ref.getDefinition();
}
return (IdentifierReference) null;
}).thenApply(ref -> {
List<Location> result = new ArrayList<>();
if (ref == null)
return result;
IdentifierReference pendingRef = lookupSymbolRef(ref);
if (pendingRef == null)
return result;
List<IdentifierReference> pendingRefs = new ArrayList<>();
pendingRefs.add(ref);
while (!pendingRefs.isEmpty()) {
IdentifierReference reference = pendingRefs.remove(0);
if (reference == null)
continue;
Collection<OberonFile> files;
String defModuleLocal = reference.getModule();
if (defModuleLocal.equals("<local>")) {
defModuleLocal = of.getCachedModuleName();
files = Arrays.asList(of);
} else {
files = allFiles(defModuleLocal, true);
}
final String defModule = defModuleLocal;
for (OberonFile of2 : files) {
of2.waitToAddWhenDirty(result, backgroundExecutor, ar2 -> {
List<Location> locations = new ArrayList<>();
if (ar2.getModuleName().equals(defModule)) {
Identifier rid = findAt(ar2.getIdDefinitions(), reference.getEndPos());
if (rid != null) {
locations.add(new Location(of2.getUri(), new Range(of2.getPos(rid.getStartPos()), of2.getPos(rid.getEndPos()))));
}
}
Map<Integer, List<Integer>> modRefs = ar2.getModuleDeps().get(defModule);
if (modRefs != null) {
List<Integer> refs = modRefs.get(reference.getEndPos());
if (refs != null) {
for (Integer rend : refs) {
if (rend < 0) {
pendingRefs.add(new IdentifierReference(ar2.getModuleName(), rend));
} else {
Identifier rid = ar2.getIdReferences().get(rend);
if (rid != null) {
locations.add(new Location(of2.getUri(), new Range(of2.getPos(rid.getStartPos()), of2.getPos(rid.getEndPos()))));
}
}
}
}
}
return locations;
});
}
}
return result;
});
}
@Override
public CompletableFuture<List<? extends DocumentHighlight>> documentHighlight(DocumentHighlightParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
if (of == null)
return CompletableFuture.completedFuture(new ArrayList<>());
return of.waitWhenDirty(backgroundExecutor, ar -> {
int pos = of.getRawPos(params.getPosition());
IdentifierReference defReference;
Identifier def = findAt(ar.getIdDefinitions(), pos);
if (def != null) {
defReference = new IdentifierReference(ar.getModuleName(), def.getEndPos());
} else {
Identifier ref = findAt(ar.getIdReferences(), pos);
if (ref != null) {
defReference = ref.getDefinition();
} else {
defReference = null;
}
}
List<DocumentHighlight> result = new ArrayList<>();
if (defReference == null)
return result;
if (ar.getModuleName().equals(defReference.getModule())) {
Identifier rid = findAt(ar.getIdDefinitions(), defReference.getEndPos());
if (rid != null) {
result.add(new DocumentHighlight(new Range(of.getPos(rid.getStartPos()), of.getPos(rid.getEndPos())), DocumentHighlightKind.Read));
}
}
Map<Integer, List<Integer>> modRefs = ar.getModuleDeps().get(defReference.getModule());
if (modRefs != null) {
List<Integer> refs = modRefs.get(defReference.getEndPos());
if (refs != null) {
for (Integer rend : refs) {
if (rend < 0) {
continue;
}
Identifier rid = ar.getIdReferences().get(rend);
if (rid != null)
result.add(new DocumentHighlight(new Range(of.getPos(rid.getStartPos()), of.getPos(rid.getEndPos())), rid.isWrittenTo() ? DocumentHighlightKind.Write : DocumentHighlightKind.Read));
}
}
}
return result;
});
}
private CompletableFuture<List<Range>> editingRanges(String uri, Position position) {
OberonFile of = fileForURI(uri);
return of.waitWhenDirty(backgroundExecutor, ar -> {
final List<Range> ranges = new ArrayList<>();
int pos = of.getRawPos(position);
IdentifierReference defReference = null;
Identifier definition = findAt(ar.getIdDefinitions(), pos);
if (definition != null) {
defReference = new IdentifierReference(ar.getModuleName(), definition.getEndPos());
} else {
Identifier ref = findAt(ar.getIdReferences(), pos);
if (ref != null) {
defReference = ref.getDefinition();
}
}
if (defReference != null && defReference.getModule().equals(ar.getModuleName())) {
if (ar.getIdReferences().containsKey(defReference.getEndPos())) {
// do not allow to rename unaliased IMPORTs!
return ranges;
}
Identifier id = ar.getIdDefinitions().get(defReference.getEndPos());
if (id.isExported()) {
// do not allow to rename exported definitions
return ranges;
}
ranges.add(new Range(of.getPos(id.getStartPos()), of.getPos(id.getEndPos())));
Map<Integer, List<Integer>> modRefs = ar.getModuleDeps().get(defReference.getModule());
if (modRefs != null) {
List<Integer> refs = modRefs.get(defReference.getEndPos());
if (refs != null) {
for (Integer rend : refs) {
if (rend < 0)
continue;
Identifier ref = ar.getIdReferences().get(rend);
ranges.add(new Range(of.getPos(ref.getStartPos()), of.getPos(ref.getEndPos())));
}
}
}
}
return ranges;
});
}
@Override
public CompletableFuture<LinkedEditingRanges> linkedEditingRange(LinkedEditingRangeParams params) {
return editingRanges(params.getTextDocument().getUri(), params.getPosition()).thenApply(LinkedEditingRanges::new);
}
private boolean positionBefore(Position p1, Position p2) {
return p1.getLine() < p2.getLine() || (p1.getLine() == p2.getLine() && p1.getCharacter() <= p2.getCharacter());
}
@Override
public CompletableFuture<Either<Range, PrepareRenameResult>> prepareRename(PrepareRenameParams params) {
return editingRanges(params.getTextDocument().getUri(), params.getPosition()).thenApply(rs -> {
for (Range r : rs) {
if (positionBefore(r.getStart(), params.getPosition()) && positionBefore(params.getPosition(), r.getEnd()))
return Either.forLeft(r);
}
return null;
});
}
@Override
public CompletableFuture<WorkspaceEdit> rename(RenameParams params) {
return editingRanges(params.getTextDocument().getUri(), params.getPosition()).thenApply(rs -> {
List<TextEdit> edits = new ArrayList<>();
for (Range r : rs) {
edits.add(new TextEdit(r, params.getNewName()));
}
Map<String, List<TextEdit>> changes = new HashMap<>();
changes.put(params.getTextDocument().getUri(), edits);
return new WorkspaceEdit(changes);
});
}
@Override
public CompletableFuture<SignatureHelp> signatureHelp(SignatureHelpParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
CompletableFuture<SignatureHelp> result = new CompletableFuture<>();
backgroundExecutor.submit(new Callable<Void>() {
public Void call() throws Exception {
Thread.sleep(200);
of.waitWhenDirty(backgroundExecutor, ar -> {
int paramIndex = 0, startPos = -1;
{
SortedMap<Integer, ParamTag> tagsBefore = ar.getParamTags().headMap(of.getRawPos(params.getPosition()) + 1);
int depth = 0;
loop: while (!tagsBefore.isEmpty()) {
int p = tagsBefore.lastKey();
ParamTag t = tagsBefore.get(p);
tagsBefore = tagsBefore.headMap(p);
switch(t) {
case CALL_START:
if (depth == 0) {
startPos = p - 1;
break loop;
}
depth--;
break;
case END:
depth++;
break;
case NEXT:
if (depth == 0)
paramIndex++;
break;
case END_LAST:
case PROC_START:
default:
break loop;
}
}
}
if (startPos == -1)
return new Two<Integer, IdentifierReference>(paramIndex, null);
while (startPos > 0 && of.getContent().charAt(startPos - 1) <= ' ') startPos--;
Identifier refid = ar.getIdReferences().get(startPos);
return new Two<>(paramIndex, refid.getDefinition());
}).thenApply(pair -> {
final int paramIndex_ = pair.getFirst();
IdentifierReference ref = lookupSymbolRef(pair.getSecond());
if (ref == null)
return null;
for (OberonFile of2 : allFiles(ref.getModule(), false)) {
try {
SignatureHelp sh = of2.waitWhenDirty(backgroundExecutor, ar2 -> {
if (ar2.getModuleName().equals(ref.getModule())) {
Identifier id = ar2.getIdDefinitions().get(ref.getEndPos());
if (id != null) {
int ssPos = id.getStartPos();
SortedMap<Integer, ParamTag> tagsAfter = ar2.getParamTags().tailMap(ssPos);
int p = tagsAfter.firstKey();
ParamTag t = tagsAfter.get(p);
if (t != ParamTag.PROC_START)
return null;
int psPos = p;
tagsAfter = tagsAfter.tailMap(p + 1);
List<ParameterInformation> pis = new ArrayList<>();
while (!tagsAfter.isEmpty()) {
p = tagsAfter.firstKey();
t = tagsAfter.get(p);
tagsAfter = tagsAfter.tailMap(p + 1);
if (t != ParamTag.NEXT && t != ParamTag.END && t != ParamTag.END_LAST)
return null;
ParameterInformation pi = new ParameterInformation();
pi.setLabel(new Two<Integer, Integer>(psPos - ssPos, p - 1 - ssPos));
pis.add(pi);
psPos = p;
if (t != ParamTag.NEXT)
break;
}
SignatureInformation si = new SignatureInformation(of2.getContent().substring(ssPos, psPos));
si.setParameters(pis);
return new SignatureHelp(Arrays.asList(si), 0, paramIndex_);
}
}
return null;
}).get();
if (sh != null)
return sh;
} catch (InterruptedException | ExecutionException ex) {
}
}
return null;
}).thenApply(r -> result.complete(r));
return null;
}
});
return result;
}
@Override
public CompletableFuture<List<FoldingRange>> foldingRange(FoldingRangeRequestParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
if (of == null)
return CompletableFuture.completedFuture(new ArrayList<>());
return of.waitWhenDirty(backgroundExecutor, ar -> {
List<FoldingRange> result = new ArrayList<>();
Map<Integer, Integer> lastLineForOuterFunc = new HashMap<>();
for (Map.Entry<Integer, int[]> func : ar.getFunctionRanges().entrySet()) {
int outerFunc = func.getValue().length > 2 ? func.getValue()[2] : -1;
int lastLine = lastLineForOuterFunc.getOrDefault(outerFunc, -1);
int startLine = of.getPos(func.getKey()).getLine();
int endLine = of.getPos(func.getValue()[1]).getLine();
if (startLine > lastLine) {
result.add(new FoldingRange(startLine, endLine));
lastLineForOuterFunc.put(outerFunc, endLine);
}
}
return result;
});
}
@Override
public CompletableFuture<Hover> hover(HoverParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
if (of == null)
return CompletableFuture.completedFuture(null);
return of.waitWhenDirty(backgroundExecutor, ar -> {
int pos = of.getRawPos(params.getPosition());
Identifier def = findAt(ar.getIdDefinitions(), pos);
if (def != null) {
return new Two<>(def, new IdentifierReference(ar.getModuleName(), def.getEndPos()));
}
Identifier ref = findAt(ar.getIdReferences(), pos);
if (ref != null) {
return new Two<>(ref, ref.getDefinition());
}
return new Two<>((Identifier) null, (IdentifierReference) null);
}).thenApply(pair -> {
Identifier id = pair.getFirst();
IdentifierReference def = lookupSymbolRef(pair.getSecond());
List<Hover> hovers = new ArrayList<>();
if (def != null) {
for (OberonFile of2 : allFiles(def.getModule(), false)) {
of2.waitToAddWhenDirty(hovers, backgroundExecutor, ar2 -> {
if (ar2.getModuleName() != null && ar2.getModuleName().equals(def.getModule())) {
Identifier rid = findAt(ar2.getIdDefinitions(), def.getEndPos());
if (rid != null) {
String content = of2.getContent();
int startPos = rid.getStartPos();
while (startPos > 0 && content.charAt(startPos - 1) != '\n') startPos--;
int endPos = rid.getEndPos();
while (endPos < content.length() && content.charAt(endPos) != '\n') endPos++;
return Arrays.asList(new Hover(new MarkupContent(MarkupKind.PLAINTEXT, of2.getContent().substring(startPos, endPos)), new Range(of.getPos(id.getStartPos()), of.getPos(id.getEndPos()))));
}
}
return Collections.emptyList();
});
}
}
if (!hovers.isEmpty()) {
Hover hover = hovers.get(0);
hover.setRange(new Range(of.getPos(id.getStartPos()), of.getPos(id.getEndPos())));
return hover;
}
return null;
});
}
@Override
public CompletableFuture<List<? extends TextEdit>> formatting(DocumentFormattingParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
if (of == null)
return CompletableFuture.completedFuture(new ArrayList<>());
String content = of.getContent();
Range fullRange = new Range(of.getPos(0), of.getPos(of.getContent().length()));
CompletableFuture<List<? extends TextEdit>> result = new CompletableFuture<>();
backgroundExecutor.submit(() -> {
String newText;
try {
List<FormatTokenInfo> tokens = bridge.format(content);
OberonFormatter ofo = new OberonFormatter();
int pos = 0;
for (FormatTokenInfo token : tokens) {
if (pos < token.getStartPos()) {
ofo.appendWhitespace(content.substring(pos, token.getStartPos()));
}
ofo.appendToken(content.substring(token.getStartPos(), token.getEndPos()), token);
pos = token.getEndPos();
}
if (pos < content.length())
ofo.appendWhitespace(content.substring(pos));
newText = ofo.getResult();
} catch (Exception ex) {
ex.printStackTrace();
result.complete(new ArrayList<>());
return;
}
result.complete(Arrays.asList(new TextEdit(fullRange, newText)));
});
return result;
}
@Override
public CompletableFuture<List<CallHierarchyItem>> prepareCallHierarchy(CallHierarchyPrepareParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
return of.waitWhenDirty(backgroundExecutor, (Function<AnalysisResult, Either<List<CallHierarchyItem>, IdentifierReference>>) ar -> {
int pos = of.getRawPos(params.getPosition());
Identifier id = findAt(ar.getIdDefinitions(), pos);
IdentifierReference def;
if (id != null) {
def = new IdentifierReference(ar.getModuleName(), id.getEndPos());
} else {
id = findAt(ar.getIdReferences(), pos);
if (id != null) {
def = id.getDefinition();
} else {
int[] func = findFunction(ar.getFunctionRanges(), pos);
if (func != null) {
id = ar.getIdDefinitions().get(func[1]);
if (id != null) {
def = new IdentifierReference(ar.getModuleName(), func[1]);
} else {
return Either.forLeft(Collections.emptyList());
}
} else {
return Either.forLeft(Collections.emptyList());
}
}
}
if (def == null || !def.getModule().equals(ar.getModuleName())) {
return Either.forRight(def);
}
CallHierarchyItem chi = buildCallHierarchyItem(of, ar, id);
return Either.forLeft(Arrays.asList(chi));
}).thenApply((Either<List<CallHierarchyItem>, IdentifierReference> either) -> {
if (either.isLeft())
return either.getLeft();
IdentifierReference ref = lookupSymbolRef(either.getRight());
List<CallHierarchyItem> result = new ArrayList<>();
if (ref == null)
return result;
for (OberonFile of2 : allFiles(ref.getModule(), false)) {
of2.waitToAddWhenDirty(result, backgroundExecutor, ar2 -> {
CallHierarchyItem chi = null;
if (ar2.getModuleName().equals(ref.getModule())) {
Identifier id = ar2.getIdDefinitions().get(ref.getEndPos());
if (id != null)
chi = buildCallHierarchyItem(of2, ar2, id);
}
return chi == null ? Collections.emptyList() : Arrays.asList(chi);
});
}
return result;
});
}
@Override
public CompletableFuture<List<CallHierarchyIncomingCall>> callHierarchyIncomingCalls(CallHierarchyIncomingCallsParams params) {
@SuppressWarnings("unchecked") Two<String, Integer> details = (Two<String, Integer>) params.getItem().getData();
String defModule = details.getFirst();
int defEndPos = details.getSecond();
CompletableFuture<List<CallHierarchyIncomingCall>> ret = new CompletableFuture<>();
backgroundExecutor.submit(() -> {
List<CallHierarchyIncomingCall> result = new ArrayList<>();
for (OberonFile of : allFiles(defModule, true)) {
of.waitToAddWhenDirty(result, backgroundExecutor, ar -> {
Map<Integer, List<Range>> functionCallRanges = new TreeMap<>();
Map<Integer, List<Integer>> modRefs = ar.getModuleDeps().get(defModule);
if (modRefs != null) {
List<Integer> rends = modRefs.get(defEndPos);
if (rends != null) {
for (Integer rend : rends) {
if (rend < 0)
continue;
Identifier rid = ar.getIdReferences().get(rend);
if (rid == null)
continue;
int[] func = findFunction(ar.getFunctionRanges(), rend);
if (func != null) {
functionCallRanges.computeIfAbsent(func[1], x -> new ArrayList<>()).add(new Range(of.getPos(rid.getStartPos()), of.getPos(rid.getEndPos())));
}
}
}
}
List<CallHierarchyIncomingCall> calls = new ArrayList<>();
for (int funcPos : functionCallRanges.keySet()) {
Identifier id = ar.getIdDefinitions().get(funcPos);
calls.add(new CallHierarchyIncomingCall(buildCallHierarchyItem(of, ar, id), functionCallRanges.get(funcPos)));
}
return calls;
});
}
ret.complete(result);
});
return ret;
}
@Override
public CompletableFuture<List<CallHierarchyOutgoingCall>> callHierarchyOutgoingCalls(CallHierarchyOutgoingCallsParams params) {
@SuppressWarnings("unchecked") Two<String, Integer> details = (Two<String, Integer>) params.getItem().getData();
String defModule = details.getFirst();
int defEndPos = details.getSecond();
CompletableFuture<List<CallHierarchyOutgoingCall>> ret = new CompletableFuture<>();
backgroundExecutor.submit(() -> {
List<Map.Entry<String, Map<Integer, List<Range>>>> tempResult = new ArrayList<>();
for (OberonFile of : allFiles(defModule, false)) {
of.waitToAddWhenDirty(tempResult, backgroundExecutor, ar -> {
Map<String, Map<Integer, List<Range>>> functionRefRanges = new TreeMap<>();
if (ar.getModuleName().equals(defModule)) {
Identifier rid = findAt(ar.getIdDefinitions(), defEndPos);
if (rid != null && rid.getKind() == SymbolKind.Function) {
int[] func = findFunction(ar.getFunctionRanges(), defEndPos);
if (func != null && func[1] == defEndPos) {
for (Identifier ref : ar.getIdReferences().subMap(defEndPos, func[2]).values()) {
if (ref.getKind() == SymbolKind.Function) {
IdentifierReference def = lookupSymbolRef(ref.getDefinition());
if (def != null) {
functionRefRanges.computeIfAbsent(def.getModule(), x -> new HashMap<>()).computeIfAbsent(def.getEndPos(), x -> new ArrayList<>()).add(new Range(of.getPos(ref.getStartPos()), of.getPos(ref.getEndPos())));
}
}
}
}
}
}
return new ArrayList<>(functionRefRanges.entrySet());
});
}
List<CallHierarchyOutgoingCall> result = new ArrayList<>();
for (Map.Entry<String, Map<Integer, List<Range>>> entry : tempResult) {
for (OberonFile of : allFiles(entry.getKey(), false)) {
of.waitToAddWhenDirty(result, backgroundExecutor, ar -> {
List<CallHierarchyOutgoingCall> calls = new ArrayList<>();
if (ar.getModuleName().equals(entry.getKey())) {
for (Map.Entry<Integer, List<Range>> positions : entry.getValue().entrySet()) {
Identifier id = ar.getIdDefinitions().get(positions.getKey());
calls.add(new CallHierarchyOutgoingCall(buildCallHierarchyItem(of, ar, id), positions.getValue()));
}
}
return calls;
});
}
}
ret.complete(result);
});
return ret;
}
@Override
public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActionParams params) {
OberonFile of = fileForURI(params.getTextDocument().getUri());
return of.waitWhenDirty(backgroundExecutor, ar -> {
return fillCodeActions(params, of, ar);
});
}
@Override
public CompletableFuture<CodeAction> resolveCodeAction(CodeAction unresolved) {
return fillResolvedCodeAction(unresolved);
}
};
}
use of org.eclipse.lsp4j.jsonrpc.messages.Tuple.Two in project lsp4jakarta by eclipse.
the class AnnotationDiagnosticsCollector method collectDiagnostics.
public void collectDiagnostics(ICompilationUnit unit, List<Diagnostic> diagnostics) {
if (unit != null) {
try {
ArrayList<Tuple.Two<IAnnotation, IAnnotatable>> annotatables = new ArrayList<Two<IAnnotation, IAnnotatable>>();
for (IPackageDeclaration p : unit.getPackageDeclarations()) {
for (IAnnotation annotation : p.getAnnotations()) {
annotatables.add(new Tuple.Two<>(annotation, p));
}
}
for (IType type : unit.getAllTypes()) {
for (IAnnotation annotation : type.getAnnotations()) {
annotatables.add(new Tuple.Two<>(annotation, type));
}
for (IMethod method : type.getMethods()) {
for (IAnnotation annotation : method.getAnnotations()) {
annotatables.add(new Tuple.Two<>(annotation, method));
}
}
for (IField field : type.getFields()) {
for (IAnnotation annotation : field.getAnnotations()) {
annotatables.add(new Tuple.Two<>(annotation, field));
}
}
}
for (Tuple.Two<IAnnotation, IAnnotatable> annotatable : annotatables) {
IAnnotation annotation = annotatable.getFirst();
IAnnotatable element = annotatable.getSecond();
if (annotation.getElementName().equals(AnnotationConstants.GENERATED)) {
for (IMemberValuePair pair : annotation.getMemberValuePairs()) {
// If date element exists and is non-empty, it must follow ISO 8601 format.
if (pair.getMemberName().equals("date")) {
if (pair.getValue() instanceof String) {
String date = (String) pair.getValue();
if (!date.equals("")) {
if (!Pattern.matches(AnnotationConstants.ISO_8601_REGEX, date)) {
ISourceRange annotationNameRange = JDTUtils.getNameRange(annotation);
Range annotationRange = JDTUtils.toRange(unit, annotationNameRange.getOffset(), annotationNameRange.getLength());
String diagnosticMessage = generateDiagnosticAnnotation("Generated", "define the attribute 'date' following the ISO 8601 standard.");
Diagnostic diagnostic = new Diagnostic(annotationRange, diagnosticMessage);
diagnostic.setCode(AnnotationConstants.DIAGNOSTIC_CODE_DATE_FORMAT);
completeDiagnostic(diagnostic);
diagnostics.add(diagnostic);
}
}
}
}
}
} else if (annotation.getElementName().equals(AnnotationConstants.RESOURCE)) {
if (element instanceof IType) {
IType type = (IType) element;
if (type.getElementType() == IJavaElement.TYPE && ((IType) type).isClass()) {
Boolean nameEmpty = true;
Boolean typeEmpty = true;
for (IMemberValuePair pair : annotation.getMemberValuePairs()) {
if (pair.getMemberName().equals("name")) {
nameEmpty = false;
}
if (pair.getMemberName().equals("type")) {
typeEmpty = false;
}
}
ISourceRange annotationNameRange = JDTUtils.getNameRange(annotation);
Range annotationRange = JDTUtils.toRange(unit, annotationNameRange.getOffset(), annotationNameRange.getLength());
String diagnosticMessage = generateDiagnosticAnnotation("Resource", "define the attribute");
if (nameEmpty) {
diagnosticMessage = diagnosticMessage + " 'name'.";
Diagnostic diagnostic = new Diagnostic(annotationRange, diagnosticMessage);
diagnostic.setCode(AnnotationConstants.DIAGNOSTIC_CODE_MISSING_RESOURCE_NAME_ATTRIBUTE);
completeDiagnostic(diagnostic);
diagnostics.add(diagnostic);
}
if (typeEmpty) {
diagnosticMessage = diagnosticMessage + " 'type'.";
Diagnostic diagnostic = new Diagnostic(annotationRange, diagnosticMessage);
diagnostic.setCode(AnnotationConstants.DIAGNOSTIC_CODE_MISSING_RESOURCE_TYPE_ATTRIBUTE);
completeDiagnostic(diagnostic);
diagnostics.add(diagnostic);
}
}
}
}
if (annotation.getElementName().equals(AnnotationConstants.POST_CONSTRUCT)) {
if (element instanceof IMethod) {
IMethod method = (IMethod) element;
ISourceRange methodNameRange = JDTUtils.getNameRange(method);
Range methodRange = JDTUtils.toRange(unit, methodNameRange.getOffset(), methodNameRange.getLength());
if (method.getNumberOfParameters() != 0) {
String diagnosticMessage = generateDiagnosticMethod("PostConstruct", "not have any parameters.");
Diagnostic diagnostic = new Diagnostic(methodRange, diagnosticMessage);
diagnostic.setCode(AnnotationConstants.DIAGNOSTIC_CODE_POSTCONSTRUCT_PARAMS);
completeDiagnostic(diagnostic);
diagnostics.add(diagnostic);
}
if (!method.getReturnType().equals("V")) {
String diagnosticMessage = generateDiagnosticMethod("PostConstruct", "be void.");
Diagnostic diagnostic = new Diagnostic(methodRange, diagnosticMessage);
diagnostic.setCode(AnnotationConstants.DIAGNOSTIC_CODE_POSTCONSTRUCT_RETURN_TYPE);
completeDiagnostic(diagnostic);
diagnostics.add(diagnostic);
}
if (method.getExceptionTypes().length != 0) {
String diagnosticMessage = generateDiagnosticMethod("PostConstruct", "not throw checked exceptions.");
Diagnostic diagnostic = new Diagnostic(methodRange, diagnosticMessage);
diagnostic.setCode(AnnotationConstants.DIAGNOSTIC_CODE_POSTCONSTRUCT_EXCEPTION);
completeDiagnostic(diagnostic);
diagnostic.setSeverity(AnnotationConstants.WARNING);
diagnostics.add(diagnostic);
}
}
} else if (annotation.getElementName().equals(AnnotationConstants.PRE_DESTROY)) {
if (element instanceof IMethod) {
IMethod method = (IMethod) element;
ISourceRange methodNameRange = JDTUtils.getNameRange(method);
Range methodRange = JDTUtils.toRange(unit, methodNameRange.getOffset(), methodNameRange.getLength());
if (method.getNumberOfParameters() != 0) {
String diagnosticMessage = generateDiagnosticMethod("PreDestroy", "not have any parameters.");
Diagnostic diagnostic = new Diagnostic(methodRange, diagnosticMessage);
diagnostic.setCode(AnnotationConstants.DIAGNOSTIC_CODE_PREDESTROY_PARAMS);
completeDiagnostic(diagnostic);
diagnostics.add(diagnostic);
}
if (Flags.isStatic(method.getFlags())) {
String diagnosticMessage = generateDiagnosticMethod("PreDestroy", "not be static.");
Diagnostic diagnostic = new Diagnostic(methodRange, diagnosticMessage);
diagnostic.setCode(AnnotationConstants.DIAGNOSTIC_CODE_PREDESTROY_STATIC);
completeDiagnostic(diagnostic);
diagnostic.setData(method.getElementType());
diagnostics.add(diagnostic);
}
if (method.getExceptionTypes().length != 0) {
String diagnosticMessage = generateDiagnosticMethod("PreDestroy", "not throw checked exceptions.");
Diagnostic diagnostic = new Diagnostic(methodRange, diagnosticMessage);
diagnostic.setCode(AnnotationConstants.DIAGNOSTIC_CODE_PREDESTROY_EXCEPTION);
completeDiagnostic(diagnostic);
diagnostic.setSeverity(AnnotationConstants.WARNING);
diagnostics.add(diagnostic);
}
}
}
}
} catch (JavaModelException e) {
JakartaCorePlugin.logException("Cannot calculate diagnostics", e);
}
}
}
Aggregations