Attempt to fix Java LS semantic tokens coming from Boot LS

This commit is contained in:
aboyko
2024-06-06 02:35:52 -04:00
parent 72c285eef8
commit 64dc2d0d14
6 changed files with 29 additions and 46 deletions

View File

@@ -11,7 +11,6 @@
package org.springframework.ide.vscode.boot.java;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
@@ -24,7 +23,6 @@ import org.eclipse.lsp4j.SemanticTokensLegend;
import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.springframework.ide.vscode.boot.java.reconcilers.CompositeASTVisitor;
import org.springframework.ide.vscode.boot.java.semantictokens.JavaSemanticTokensProvider;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
@@ -41,20 +39,10 @@ public class JdtSemanticTokensHandler implements SemanticTokensHandler {
private final Collection<JdtSemanticTokensProvider> tokenProviders;
private final SemanticTokensLegend legend;
private JavaSemanticTokensProvider jdtLsProvider;
public JdtSemanticTokensHandler(CompilationUnitCache cuCache, JavaProjectFinder projectFinder, Collection<JdtSemanticTokensProvider> tokenProviders) {
this.cuCache = cuCache;
this.projectFinder = projectFinder;
ArrayList<JdtSemanticTokensProvider> tokenProvidersList = new ArrayList<>(tokenProviders.size());
for (JdtSemanticTokensProvider tp : tokenProviders) {
if (tp instanceof JavaSemanticTokensProvider jdtLsProvider) {
this.jdtLsProvider = jdtLsProvider;
} else {
tokenProvidersList.add(tp);
}
}
this.tokenProviders = tokenProvidersList;
this.tokenProviders = tokenProviders;
this.legend = new SemanticTokensLegend(
tokenProviders.stream().flatMap(tp -> tp.getTokenTypes().stream()).distinct().collect(Collectors.toList()),
tokenProviders.stream().flatMap(tp -> tp.getTokenModifiers().stream()).distinct().collect(Collectors.toList())
@@ -73,8 +61,6 @@ public class JdtSemanticTokensHandler implements SemanticTokensHandler {
return capabilities;
}
@Override
public List<SemanticTokenData> semanticTokensFull(TextDocument doc, CancelChecker cancelChecker) {
return semanticTokens(doc, cancelChecker, null);
@@ -91,19 +77,19 @@ public class JdtSemanticTokensHandler implements SemanticTokensHandler {
IJavaProject jp = optProject.get();
List<JdtSemanticTokensProvider> applicableTokenProviders = tokenProviders.stream().filter(tp -> tp.isApplicable(jp)).collect(Collectors.toList());
if (!applicableTokenProviders.isEmpty()) {
return cuCache.withCompilationUnit(jp, URI.create(doc.getUri()), cu -> computeTokens(applicableTokenProviders, jp, cu, r));
return cuCache.withCompilationUnit(jp, URI.create(doc.getUri()), cu -> computeTokens(applicableTokenProviders, jp, cu, r, doc));
}
}
return null;
}
private List<SemanticTokenData> computeTokens(List<JdtSemanticTokensProvider> applicableTokenProviders, IJavaProject jp, CompilationUnit cu, Range r) {
private List<SemanticTokenData> computeTokens(List<JdtSemanticTokensProvider> applicableTokenProviders, IJavaProject jp, CompilationUnit cu, Range r, TextDocument doc) {
if (cu == null) {
return null;
}
Collector<SemanticTokenData> collector = new Collector<>();
CompositeASTVisitor visitor = new CompositeASTVisitor();
applicableTokenProviders.forEach(tp -> visitor.add(tp.getTokensComputer(jp, cu, collector)));
applicableTokenProviders.forEach(tp -> visitor.add(tp.getTokensComputer(jp, doc, cu, collector)));
if (r != null) {
if (r.getStart() != null) {
visitor.setStartOffset(cu.getPosition(r.getStart().getLine(), r.getStart().getCharacter()));
@@ -113,10 +99,6 @@ public class JdtSemanticTokensHandler implements SemanticTokensHandler {
}
}
cu.accept(visitor);
if (!collector.isEmpty() && jdtLsProvider != null) {
// If there are tokens computed then also run JDT LS tokens provider not to lose JDT LS semantic highlights
cu.accept(jdtLsProvider.getTokensComputer(jp, cu, collector));
}
return collector.isEmpty() ? null : collector.get();
}

View File

@@ -18,12 +18,13 @@ import org.eclipse.jdt.core.dom.CompilationUnit;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
import org.springframework.ide.vscode.commons.util.Collector;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
public interface JdtSemanticTokensProvider {
List<String> getTokenTypes();
default List<String> getTokenModifiers() { return Collections.emptyList(); }
boolean isApplicable(IJavaProject project);
ASTVisitor getTokensComputer(IJavaProject project, CompilationUnit cu, Collector<SemanticTokenData> collector);
ASTVisitor getTokensComputer(IJavaProject project, TextDocument doc, CompilationUnit cu, Collector<SemanticTokenData> collector);
}

View File

@@ -32,6 +32,7 @@ import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokensDataProvider;
import org.springframework.ide.vscode.commons.util.Collector;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProvider {
@@ -61,7 +62,7 @@ public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProv
}
@Override
public ASTVisitor getTokensComputer(IJavaProject jp, CompilationUnit cu, Collector<SemanticTokenData> tokensData) {
public ASTVisitor getTokensComputer(IJavaProject jp, TextDocument doc, CompilationUnit cu, Collector<SemanticTokenData> tokensData) {
SemanticTokensDataProvider provider = SpringProjectUtil.hasDependencyStartingWith(jp, "hibernate-core", null) ? hqlProvider : jpqlProvider;
return new ASTVisitor() {
@Override

View File

@@ -20,6 +20,7 @@ import org.springframework.ide.vscode.boot.java.JdtSemanticTokensProvider;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
import org.springframework.ide.vscode.commons.util.Collector;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
public class JavaSemanticTokensProvider implements JdtSemanticTokensProvider {
@@ -39,9 +40,9 @@ public class JavaSemanticTokensProvider implements JdtSemanticTokensProvider {
}
@Override
public ASTVisitor getTokensComputer(IJavaProject project, CompilationUnit cu,
public ASTVisitor getTokensComputer(IJavaProject project, TextDocument doc, CompilationUnit cu,
Collector<SemanticTokenData> collector) {
return new SemanticTokensVisitor(cu, collector);
return new SemanticTokensVisitor(project, doc, cu, collector);
}
}

View File

@@ -17,10 +17,7 @@ package org.springframework.ide.vscode.boot.java.semantictokens;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.ITerminalSymbols;
@@ -57,18 +54,20 @@ import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.TypeLiteral;
import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
import org.springframework.ide.vscode.commons.util.Collector;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
public class SemanticTokensVisitor extends ASTVisitor {
private CompilationUnit cu;
private final IScanner scanner;
private Collector<SemanticTokenData> collector;
public SemanticTokensVisitor(CompilationUnit cu, Collector<SemanticTokenData> collector) {
public SemanticTokensVisitor(IJavaProject project, TextDocument doc, CompilationUnit cu, Collector<SemanticTokenData> collector) {
super(true);
this.cu = cu;
this.scanner = createScanner(cu);
this.scanner = createScanner(project, doc, cu);
this.collector = collector;
}
@@ -421,7 +420,11 @@ public class SemanticTokensVisitor extends ASTVisitor {
break; // "class" or "interface" keyword tokens
case ITerminalSymbols.TokenNameextends:
addToken(tokenOffset, tokenLength, TokenType.MODIFIER, 0);
acceptNode(node.getSuperclassType());
if (node.isInterface()) {
acceptNodeList(node.superInterfaceTypes());
} else {
acceptNode(node.getSuperclassType());
}
break; // "extends" keyword token
case ITerminalSymbols.TokenNameimplements:
addToken(tokenOffset, tokenLength, TokenType.MODIFIER, 0);
@@ -443,32 +446,27 @@ public class SemanticTokensVisitor extends ASTVisitor {
/**
* Tries to create an {@link IScanner} for the source of the given compilation unit.
* @param doc
* @param javaProject
*
* @param cu the compilation unit
* @return the scanner, or {@code null} if not available
*/
private IScanner createScanner(CompilationUnit cu) {
final ITypeRoot typeRoot = cu.getTypeRoot();
if (typeRoot == null) {
private IScanner createScanner(IJavaProject javaProject, TextDocument doc, CompilationUnit cu) {
if (doc == null) {
return null;
}
final IJavaProject javaProject = typeRoot.getJavaProject();
if (javaProject == null) {
return null;
}
final String source;
try {
source = typeRoot.getSource();
} catch (JavaModelException e) {
return null;
}
final String source = doc.get();
if (source == null) {
return null;
}
final String sourceLevel = javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
final String complianceLevel = javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
final boolean enablePreview = JavaCore.ENABLED.equals(javaProject.getOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, true));
final String sourceLevel = JavaCore.VERSION_21;/*javaProject.getOption(JavaCore.COMPILER_SOURCE, true);*/
final String complianceLevel = JavaCore.VERSION_21; /*javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);*/
final boolean enablePreview = false; /*JavaCore.ENABLED.equals(javaProject.getOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, true));*/
final IScanner scanner = ToolFactory.createScanner(false, false, false, sourceLevel, complianceLevel, enablePreview);
scanner.setSource(source.toCharArray());

View File

@@ -50,7 +50,7 @@ public class JdtDataQuerySemanticTokensProviderTest {
private List<SemanticTokenData> computeTokens(CompilationUnit cu) {
Collector<SemanticTokenData> collector = new Collector<>();
CompositeASTVisitor visitor = new CompositeASTVisitor();
visitor.add(provider.getTokensComputer(jp, cu, collector));
visitor.add(provider.getTokensComputer(jp, null, cu, collector));
cu.accept(visitor);
return collector.get();
}