Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f5c0f8c
add initial support for simplify hover information
aosen-xiong Sep 4, 2023
d3e8fc4
apply spotless
aosen-xiong Sep 4, 2023
b24905d
Merge branch 'master' into filterout-hover-info
aosen-xiong Oct 10, 2023
590f5de
add support for generics
aosen-xiong Oct 13, 2023
4c09a40
refactor code
aosen-xiong Oct 13, 2023
497c522
Merge branch 'master' into filterout-hover-info
aosen-xiong Oct 20, 2023
80e227e
temp for migrate to new laptop
aosen-xiong Nov 22, 2023
fcb8692
Merge branch 'master' into filterout-hover-info
wmdietl Nov 27, 2023
3c756c1
Fix formatting error
wmdietl Nov 27, 2023
6a618c3
Merge branch 'master' into filterout-hover-info
aosen-xiong Dec 5, 2023
81ba914
apply spotless
aosen-xiong Dec 5, 2023
45f7d64
Merge branch 'master' into filterout-hover-info
wmdietl Jan 4, 2024
f29a717
Merge branch 'master' into filterout-hover-info
aosen-xiong Feb 28, 2024
b184575
Undo unintentional change to build gradle
aosen-xiong Feb 28, 2024
451231e
Undo code action and leave to new PR
aosen-xiong Feb 28, 2024
5c9eeb3
Address naming comment
aosen-xiong Feb 28, 2024
d851dd7
Add javadoc
aosen-xiong Feb 28, 2024
c84507e
Refactor code and add comment
aosen-xiong Feb 28, 2024
6d52076
Applied suggestions from IDE
aosen-xiong Feb 28, 2024
7c33d4b
Remove no longer used method
aosen-xiong Feb 28, 2024
bfaa7de
Add space after :
aosen-xiong Mar 1, 2024
c4f0143
Merge branch 'master' into filterout-hover-info
wmdietl Mar 14, 2024
1a543dc
Merge branch 'master' into filterout-hover-info
wmdietl Jun 26, 2024
1dba908
Merge branch 'master' into filterout-hover-info
wmdietl Jan 2, 2025
ade6b64
Merge branch 'master' into filterout-hover-info
wmdietl May 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -202,20 +202,154 @@ public void didSave(DidSaveTextDocumentParams params) {
public void publish(Map<String, List<javax.tools.Diagnostic<?>>> result) {
for (Map.Entry<String, List<javax.tools.Diagnostic<?>>> entry : result.entrySet()) {
List<Diagnostic> diagnostics = new ArrayList<>();
Map<String, List<CheckerTypeKind>> uniqueTypeInfo =
processDiagnosticString(entry, diagnostics);
publishTypeMessageWithFilter(entry, uniqueTypeInfo);
server.publishDiagnostics(new PublishDiagnosticsParams(entry.getKey(), diagnostics));
}
}

/**
* Process Diagnostic strings to separate type message and error message.
*
* @param entry The Diagnostic entry for getting diagnostic message
* @param diagnostics A list for storing checkerframework issued errors
* @return TypeMessage processed for non-verbose output
*/
private Map<String, List<CheckerTypeKind>> processDiagnosticString(
Map.Entry<String, List<javax.tools.Diagnostic<?>>> entry,
List<Diagnostic> diagnostics) {
Map<String, List<CheckerTypeKind>> TypeMessage = new HashMap<>();
for (javax.tools.Diagnostic<?> diagnostic : entry.getValue()) {
String message = diagnostic.getMessage(Locale.getDefault());
if (message != null && message.contains("lsp.type.information")) {
String checker = getChecker(message);
String kind = getKind(message);
String type = getType(message);
String positionInfo = getPosition(message);
// If the position is not in the map, add a new entry.
List<CheckerTypeKind> checkerTypeKinds =
TypeMessage.computeIfAbsent(positionInfo, k -> new ArrayList<>());
// If the checker is not in the list, add a new entry.
CheckerTypeKind checkerTypeKind =
checkerTypeKinds.stream()
.filter(c -> c.getCheckername().equals(checker))
.findFirst()
.orElseGet(
() -> {
CheckerTypeKind newCheckerTypeKind =
new CheckerTypeKind(checker, new HashMap<>());
checkerTypeKinds.add(newCheckerTypeKind);
return newCheckerTypeKind;
});
// If the type is not in the map, add a new entry.
checkerTypeKind.getTypeToKindMap().putIfAbsent(type, kind);
} else {
// If is not type message, add to diagnostics.
diagnostics.add(convertToLSPDiagnostic(diagnostic));
}
}
return TypeMessage;
}

for (javax.tools.Diagnostic<?> diagnostic : entry.getValue()) {
String message = diagnostic.getMessage(Locale.getDefault());
if (message != null && message.contains("lsp.type.information")) {
// this message is for lsp support
File file = new File(URI.create(entry.getKey()));
publishTypeMessage(file, message);
} else {
diagnostics.add(convertToLSPDiagnostic(diagnostic));
/**
* Publish the given type message for the given file in non-verbose mode.
*
* @param entry The Diagnostic entry for getting file name string
* @param diagnosticString processed for simplicity output
*/
private void publishTypeMessageWithFilter(
Map.Entry<String, List<javax.tools.Diagnostic<?>>> entry,
Map<String, List<CheckerTypeKind>> diagnosticString) {
for (Map.Entry<String, List<CheckerTypeKind>> typeMessage : diagnosticString.entrySet()) {
String location = typeMessage.getKey();
for (CheckerTypeKind checkerTypeKind : typeMessage.getValue()) {
Map<String, String> typeKinds = checkerTypeKind.getTypeToKindMap();
for (Map.Entry<String, String> typeKind : typeKinds.entrySet()) {
StringBuilder typeMessageBuilder =
new StringBuilder(checkerTypeKind.getCheckername());
// If there are more than one type message from a checker, add the kind of type
// e.g. use/declared. If not, collapse the message.
if (typeKinds.size() > 1) {
typeMessageBuilder.append(" ").append(typeKind.getValue());
}
typeMessageBuilder.append(": ").append(typeKind.getKey()).append(location);
publishTypeMessage(
new File(URI.create(entry.getKey())), typeMessageBuilder.toString());
}
}
}
}

server.publishDiagnostics(new PublishDiagnosticsParams(entry.getKey(), diagnostics));
/**
* Get checker name from type message in checkerframework.
*
* @param typeMessage Type message string from checkerframework
* @return Checker name from checkerframework e.g. Nullness
*/
private static String getChecker(String typeMessage) {
String checkerPrefix = "checker=";
int checkerStart = typeMessage.indexOf(checkerPrefix);
if (checkerStart != -1) {
int checkerEnd = typeMessage.indexOf(";", checkerStart);
if (checkerEnd != -1) {
String checker =
typeMessage
.substring(checkerStart + checkerPrefix.length(), checkerEnd)
.trim();
checker = checker.replace("Subchecker", "").replace("Checker", "").trim();
return checker;
}
}
return null;
}

/**
* Get message kind from type message in checkerframework.
*
* @param typeMessage Type message string from checkerframework
* @return Lower case message kind from checkerframework e.g. use/declared
*/
private static String getKind(String typeMessage) {
String kindPrefix = "kind=";
int kindStart = typeMessage.indexOf(kindPrefix);
if (kindStart != -1) {
int kindEnd = typeMessage.indexOf(";", kindStart);
if (kindEnd != -1) {
String kind =
typeMessage.substring(kindStart + kindPrefix.length(), kindEnd).trim();
kind = kind.toLowerCase(Locale.ROOT).replace("_type", "");
return kind;
}
}
return null;
}

/**
* Get type information from type message in checkerframework.
*
* @param typeMessage Type Message String from checkerframework
* @return Type information from checkerframework e.g. @Nullable Object
*/
private static String getType(String typeMessage) {
String typePrefix = "type=";
int typeStart = typeMessage.indexOf(typePrefix);
if (typeStart != -1) {
int typeEnd = typeMessage.indexOf(";", typeStart);
return typeMessage.substring(typeStart + typePrefix.length(), typeEnd).trim() + "; ";
}
return null;
}

/**
* Get position range from type message in checkerframework.
*
* @param typeMessage Type Message String from checkerframework
* @return Position range from checkerframework e.g. range=(11, 8, 11, 9)
*/
private static String getPosition(String typeMessage) {
int lastDelimiter = typeMessage.lastIndexOf(';');
return typeMessage.substring(lastDelimiter + 1).trim();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.checkerframework.languageserver;

import java.util.Map;

/** This class is for storing the type information from Checker Framework. */
public class CheckerTypeKind {
/** The string stores checker name e.g. Nullness, KeyFor. */
private final String checkerName;

/**
* The map stores type information in the key of the map and type kind information e.g.
* used/declared in the value of the map.
*/
private final Map<String, String> typeToKindMap;

/**
* Constructor for creating the CheckerTypeKind class
*
* @param checkerName checker's name
* @param typeToKindMap type and kind pair
*/
CheckerTypeKind(String checkerName, Map<String, String> typeToKindMap) {
this.checkerName = checkerName;
this.typeToKindMap = typeToKindMap;
}

/**
* Return the name of the checker
*
* @return name of the checker
*/
/*package-private*/ String getCheckername() {
return this.checkerName;
}

/**
* Return the type and kind map
*
* @return type and kind map
*/
Map<String, String> getTypeToKindMap() {
return this.typeToKindMap;
}
}