From 64dc2d0d142a40233f8d0565a2562e02786c0e08 Mon Sep 17 00:00:00 2001 From: aboyko Date: Thu, 6 Jun 2024 02:35:52 -0400 Subject: [PATCH] Attempt to fix Java LS semantic tokens coming from Boot LS --- .../boot/java/JdtSemanticTokensHandler.java | 26 +++----------- .../boot/java/JdtSemanticTokensProvider.java | 3 +- .../JdtDataQuerySemanticTokensProvider.java | 3 +- .../JavaSemanticTokensProvider.java | 5 +-- .../semantictokens/SemanticTokensVisitor.java | 36 +++++++++---------- ...dtDataQuerySemanticTokensProviderTest.java | 2 +- 6 files changed, 29 insertions(+), 46 deletions(-) diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/JdtSemanticTokensHandler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/JdtSemanticTokensHandler.java index c2e688a20..1bc0020d5 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/JdtSemanticTokensHandler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/JdtSemanticTokensHandler.java @@ -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 tokenProviders; private final SemanticTokensLegend legend; - private JavaSemanticTokensProvider jdtLsProvider; - public JdtSemanticTokensHandler(CompilationUnitCache cuCache, JavaProjectFinder projectFinder, Collection tokenProviders) { this.cuCache = cuCache; this.projectFinder = projectFinder; - ArrayList 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 semanticTokensFull(TextDocument doc, CancelChecker cancelChecker) { return semanticTokens(doc, cancelChecker, null); @@ -91,19 +77,19 @@ public class JdtSemanticTokensHandler implements SemanticTokensHandler { IJavaProject jp = optProject.get(); List 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 computeTokens(List applicableTokenProviders, IJavaProject jp, CompilationUnit cu, Range r) { + private List computeTokens(List applicableTokenProviders, IJavaProject jp, CompilationUnit cu, Range r, TextDocument doc) { if (cu == null) { return null; } Collector 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(); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/JdtSemanticTokensProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/JdtSemanticTokensProvider.java index 51068f657..ed8cabcd2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/JdtSemanticTokensProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/JdtSemanticTokensProvider.java @@ -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 getTokenTypes(); default List getTokenModifiers() { return Collections.emptyList(); } boolean isApplicable(IJavaProject project); - ASTVisitor getTokensComputer(IJavaProject project, CompilationUnit cu, Collector collector); + ASTVisitor getTokensComputer(IJavaProject project, TextDocument doc, CompilationUnit cu, Collector collector); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/JdtDataQuerySemanticTokensProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/JdtDataQuerySemanticTokensProvider.java index 4e7f3b4c9..654fe4424 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/JdtDataQuerySemanticTokensProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/JdtDataQuerySemanticTokensProvider.java @@ -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 tokensData) { + public ASTVisitor getTokensComputer(IJavaProject jp, TextDocument doc, CompilationUnit cu, Collector tokensData) { SemanticTokensDataProvider provider = SpringProjectUtil.hasDependencyStartingWith(jp, "hibernate-core", null) ? hqlProvider : jpqlProvider; return new ASTVisitor() { @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/semantictokens/JavaSemanticTokensProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/semantictokens/JavaSemanticTokensProvider.java index a8caf5786..b25f1bdd0 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/semantictokens/JavaSemanticTokensProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/semantictokens/JavaSemanticTokensProvider.java @@ -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 collector) { - return new SemanticTokensVisitor(cu, collector); + return new SemanticTokensVisitor(project, doc, cu, collector); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/semantictokens/SemanticTokensVisitor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/semantictokens/SemanticTokensVisitor.java index 6de09c7c5..8d53f581d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/semantictokens/SemanticTokensVisitor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/semantictokens/SemanticTokensVisitor.java @@ -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 collector; - public SemanticTokensVisitor(CompilationUnit cu, Collector collector) { + public SemanticTokensVisitor(IJavaProject project, TextDocument doc, CompilationUnit cu, Collector 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()); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/JdtDataQuerySemanticTokensProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/JdtDataQuerySemanticTokensProviderTest.java index 4c1af30f7..69f8de098 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/JdtDataQuerySemanticTokensProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/JdtDataQuerySemanticTokensProviderTest.java @@ -50,7 +50,7 @@ public class JdtDataQuerySemanticTokensProviderTest { private List computeTokens(CompilationUnit cu) { Collector 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(); }