HQL syntax highlighting in Java and properties files

This commit is contained in:
aboyko
2024-04-16 17:04:42 -04:00
parent 5ab79dc701
commit 8b4abbcfd2
18 changed files with 3796 additions and 3708 deletions

View File

@@ -672,7 +672,9 @@ variable
;
parameter
: prefix=':' identifier ('%')?
: prefix=':' SPEL
| prefix=':' identifier ('%')?
| prefix='?' SPEL
| prefix='?' INTEGER_LITERAL?
;
@@ -1091,4 +1093,5 @@ BINARY_LITERAL : [xX] '\'' HEX_DIGIT+ '\''
| [xX] '"' HEX_DIGIT+ '"'
;
IDENTIFICATION_VARIABLE : ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '$' | '_') ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '0' .. '9' | '$' | '_')* ;
IDENTIFICATION_VARIABLE : ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '$' | '_') ('a' .. 'z' | 'A' .. 'Z' | '\u0080' .. '\ufffe' | '0' .. '9' | '$' | '_')* ;
SPEL : ('#')('{')(.)*?('}') ;

View File

@@ -74,7 +74,6 @@ range_variable_declaration
join
: join_spec join_association_path_expression AS? identification_variable (join_condition)?
| join_spec join_association_path_expression where_clause
;
fetch_join
@@ -601,6 +600,7 @@ identification_variable
: IDENTIFICATION_VARIABLE
| f=(COUNT
| DATE
| FROM
| INNER
| KEY
| LEFT

View File

@@ -25,6 +25,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.boot.factories.SpringFactoriesLanguageServerComponents;
import org.springframework.ide.vscode.boot.index.cache.IndexCache;
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.HqlSemanticTokens;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpaQueryPropertiesLanguageServerComponents;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSemanticTokens;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSupportState;
@@ -126,7 +127,8 @@ public class BootLanguageServerInitializer implements InitializingBean {
new SpringXMLLanguageServerComponents(server, springIndexer, params, config),
new SpringFactoriesLanguageServerComponents(projectFinder, springIndexer, config),
new PomLanguageServerComponents(server, projectFinder, params.projectObserver, appContext.getBean(SpringProjectsProvider.class)),
new JpaQueryPropertiesLanguageServerComponents(server.getTextDocumentService(), projectFinder, appContext.getBean(JpqlSemanticTokens.class), appContext.getBean(JpqlSupportState.class))
new JpaQueryPropertiesLanguageServerComponents(server.getTextDocumentService(), projectFinder, appContext.getBean(JpqlSemanticTokens.class),
appContext.getBean(HqlSemanticTokens.class), appContext.getBean(JpqlSupportState.class))
);
for (LanguageServerComponents c : componentsList) {

View File

@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.app;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.HqlSemanticTokens;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtDataQuerySemanticTokensProvider;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSemanticTokens;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSupportState;
@@ -110,8 +111,8 @@ public class JdtConfig {
return new EntityIdForRepoReconciler();
}
@Bean JdtDataQuerySemanticTokensProvider jpqlJdtSemanticTokensProvider(JpqlSemanticTokens provider, JpqlSupportState supportState) {
return new JdtDataQuerySemanticTokensProvider(provider, supportState);
@Bean JdtDataQuerySemanticTokensProvider jpqlJdtSemanticTokensProvider(JpqlSemanticTokens jpqlProvider, HqlSemanticTokens hqlProvider, JpqlSupportState supportState) {
return new JdtDataQuerySemanticTokensProvider(jpqlProvider, hqlProvider, supportState);
}
}

View File

@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.boot.app;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.HqlSemanticTokens;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSemanticTokens;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlSupportState;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
@@ -25,9 +26,14 @@ public class SpringDataConfig {
return new JpqlSemanticTokens();
}
@Bean
HqlSemanticTokens hqlSemanticTokens() {
return new HqlSemanticTokens();
}
@Bean
JpqlSupportState jpqlSupportState(SimpleLanguageServer server, ProjectObserver projectObserver, BootJavaConfig config) {
return new JpqlSupportState(server, projectObserver, config);
}
}

View File

@@ -66,14 +66,14 @@ 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(params.getTextDocument().getUri()), cu -> computeTokens(applicableTokenProviders, cu));
return cuCache.withCompilationUnit(jp, URI.create(params.getTextDocument().getUri()), cu -> computeTokens(applicableTokenProviders, jp, cu));
}
}
return new SemanticTokens();
}
private SemanticTokens computeTokens(List<JdtSemanticTokensProvider> applicableTokenProviders, CompilationUnit cu) {
List<SemanticTokenData> tokensData = applicableTokenProviders.stream().map(tp -> tp.computeTokens(cu)).flatMap(t -> t.stream()).collect(Collectors.toList());
private SemanticTokens computeTokens(List<JdtSemanticTokensProvider> applicableTokenProviders, IJavaProject jp, CompilationUnit cu) {
List<SemanticTokenData> tokensData = applicableTokenProviders.stream().map(tp -> tp.computeTokens(jp, cu)).flatMap(t -> t.stream()).collect(Collectors.toList());
return new SemanticTokens(SemanticTokensUtils.mapTokensDataToLsp(tokensData, legend, offset -> cu.getLineNumber(offset) - 1, cu::getColumnNumber));
}

View File

@@ -21,7 +21,7 @@ public interface JdtSemanticTokensProvider {
List<String> getTokenTypes();
default List<String> getTokenModifiers() { return Collections.emptyList(); }
List<SemanticTokenData> computeTokens(CompilationUnit cu);
List<SemanticTokenData> computeTokens(IJavaProject project, CompilationUnit cu);
boolean isApplicable(IJavaProject project);
}

View File

@@ -10,10 +10,11 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import java.util.Map;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
@@ -26,12 +27,14 @@ import org.springframework.ide.vscode.parser.hql.HqlBaseListener;
import org.springframework.ide.vscode.parser.hql.HqlLexer;
import org.springframework.ide.vscode.parser.hql.HqlParser;
import org.springframework.ide.vscode.parser.hql.HqlParser.EntityNameContext;
import org.springframework.ide.vscode.parser.hql.HqlParser.IdentifierContext;
import org.springframework.ide.vscode.parser.hql.HqlParser.ParameterContext;
import org.springframework.ide.vscode.parser.hql.HqlParser.SimplePathElementContext;
public class HqlSemanticTokens implements SemanticTokensDataProvider {
private static List<String> TOKEN_TYPES = List.of("keyword", "type", "class", "string", "number", "operator",
"variable", "method", "modifier", "regexp");
"variable", "method", "parameter", "regexp");
@Override
public List<String> getTokenTypes() {
@@ -40,58 +43,43 @@ public class HqlSemanticTokens implements SemanticTokensDataProvider {
@Override
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
List<SemanticTokenData> tokens = new ArrayList<>();
HqlLexer lexer = new HqlLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
HqlParser parser = new HqlParser(antlrTokens);
LinkedHashSet<Token> coloredTokens = new LinkedHashSet<>();
Stack<SimplePathElementContext> pathContexts = new Stack<>();
Map<Token, String> semantics = new HashMap<>();
parser.addParseListener(new HqlBaseListener() {
private void addToken(Token token, String tokenType) {
tokens.add(new SemanticTokenData(token.getStartIndex() + initialOffset,
token.getStartIndex() + token.getText().length() + initialOffset, tokenType, new String[0]));
coloredTokens.add(token);
}
private void processTerminalNode(TerminalNode node) {
if (coloredTokens.contains(node.getSymbol())) {
return;
}
int type = node.getSymbol().getType();
switch (type) {
case HqlParser.STRINGLITERAL:
case HqlParser.CHARACTER:
addToken(node.getSymbol(), "string");
semantics.put(node.getSymbol(), "string");
break;
case HqlParser.HEXLITERAL:
case HqlParser.INTEGER_LITERAL:
case HqlParser.FLOAT_LITERAL:
case HqlParser.BINARY_LITERAL:
addToken(node.getSymbol(), "number");
semantics.put(node.getSymbol(), "number");
break;
case HqlParser.IDENTIFICATION_VARIABLE:
if (pathContexts.isEmpty()) {
addToken(node.getSymbol(), "variable");
} else {
addToken(node.getSymbol(), "method");
}
semantics.put(node.getSymbol(), "variable");
break;
case HqlParser.JAVASTRINGLITERAL:
addToken(node.getSymbol(), "class");
semantics.put(node.getSymbol(), "class");
break;
case HqlParser.WS:
break;
// case JpqlParser.SPEL:
// addToken(node.getSymbol(), "regexp");
// break;
case HqlParser.SPEL:
semantics.put(node.getSymbol(), "regexp");
break;
default:
if (HqlParser.WS < type && type <= HqlParser.YEAR) {
addToken(node.getSymbol(), "keyword");
semantics.put(node.getSymbol(), "keyword");
} else {
addToken(node.getSymbol(), "modifier");
semantics.put(node.getSymbol(), "operator");
}
}
}
@@ -105,28 +93,38 @@ public class HqlSemanticTokens implements SemanticTokensDataProvider {
public void visitErrorNode(ErrorNode node) {
processTerminalNode(node);
}
@Override
public void enterEntityName(EntityNameContext ctx) {
addToken(ctx.getStart(), "class");
}
@Override
public void enterSimplePathElement(SimplePathElementContext ctx) {
pathContexts.push(ctx);
}
@Override
public void exitSimplePathElement(SimplePathElementContext ctx) {
pathContexts.pop();
semantics.put(ctx.identifier().getStart(), "method");
}
@Override
public void exitEntityName(EntityNameContext ctx) {
for (IdentifierContext i : ctx.identifier()) {
semantics.put(i.getStart(), "class");
}
}
@Override
public void exitParameter(ParameterContext ctx) {
if (ctx.identifier() != null && ctx.identifier().getStart() != null) {
semantics.put(ctx.identifier().getStart(), "parameter");
}
}
});
parser.ql_statement();
List<SemanticTokenData> tokens = semantics.entrySet().stream()
.map(e -> new SemanticTokenData(e.getKey().getStartIndex() + initialOffset,
e.getKey().getStartIndex() + e.getKey().getText().length() + initialOffset, e.getValue(),
new String[0]))
.collect(Collectors.toList());
Collections.sort(tokens);
return tokens;
}

View File

@@ -12,6 +12,8 @@ package org.springframework.ide.vscode.boot.java.data.jpa.queries;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Annotation;
@@ -29,28 +31,39 @@ import org.springframework.ide.vscode.boot.java.JdtSemanticTokensProvider;
import org.springframework.ide.vscode.commons.java.IJavaProject;
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;
public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProvider {
private static final String QUERY = "Query";
private static final String FQN_QUERY = "org.springframework.data.jpa.repository." + QUERY;
private final JpqlSemanticTokens provider;
private final JpqlSemanticTokens jpqlProvider;
private final HqlSemanticTokens hqlProvider;
private final JpqlSupportState supportState;
public JdtDataQuerySemanticTokensProvider(JpqlSemanticTokens provider, JpqlSupportState supportState) {
this.provider = provider;
public JdtDataQuerySemanticTokensProvider(JpqlSemanticTokens jpqlProvider, HqlSemanticTokens hqlProvider, JpqlSupportState supportState) {
this.jpqlProvider = jpqlProvider;
this.hqlProvider = hqlProvider;
this.supportState = supportState;
}
@Override
public List<String> getTokenTypes() {
return provider.getTokenTypes();
return Stream.concat(jpqlProvider.getTokenTypes().stream(), hqlProvider.getTokenTypes().stream()).distinct().collect(Collectors.toList());
}
@Override
public List<SemanticTokenData> computeTokens(CompilationUnit cu) {
public List<String> getTokenModifiers() {
return Stream.concat(jpqlProvider.getTypeModifiers().stream(), hqlProvider.getTypeModifiers().stream()).distinct().collect(Collectors.toList());
}
@Override
public List<SemanticTokenData> computeTokens(IJavaProject jp, CompilationUnit cu) {
List<SemanticTokenData> tokensData = new ArrayList<>();
SemanticTokensDataProvider provider = SpringProjectUtil.hasDependencyStartingWith(jp, "hibernate-core", null) ? hqlProvider : jpqlProvider;
cu.accept(new ASTVisitor() {
@Override

View File

@@ -23,8 +23,9 @@ public class JpaQueryPropertiesLanguageServerComponents implements LanguageServe
private final QueryPropertiesSemanticTokensHandler semanticTokensHandler;
public JpaQueryPropertiesLanguageServerComponents(SimpleTextDocumentService documents, JavaProjectFinder projectsFinder, JpqlSemanticTokens jpqlSemanticTokensProvider, JpqlSupportState supportState) {
this.semanticTokensHandler = new QueryPropertiesSemanticTokensHandler(documents, projectsFinder, jpqlSemanticTokensProvider, supportState);
public JpaQueryPropertiesLanguageServerComponents(SimpleTextDocumentService documents, JavaProjectFinder projectsFinder,
JpqlSemanticTokens jpqlSemanticTokensProvider, HqlSemanticTokens hqlSematicTokensProvider, JpqlSupportState supportState) {
this.semanticTokensHandler = new QueryPropertiesSemanticTokensHandler(documents, projectsFinder, jpqlSemanticTokensProvider, hqlSematicTokensProvider, supportState);
}
@Override

View File

@@ -10,9 +10,11 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
@@ -27,13 +29,15 @@ import org.springframework.ide.vscode.parser.jpql.JpqlParser;
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Collection_valued_fieldContext;
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Entity_nameContext;
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Entity_type_literalContext;
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Identification_variableContext;
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Input_parameterContext;
import org.springframework.ide.vscode.parser.jpql.JpqlParser.Single_valued_object_fieldContext;
import org.springframework.ide.vscode.parser.jpql.JpqlParser.State_fieldContext;
public class JpqlSemanticTokens implements SemanticTokensDataProvider {
private static List<String> TOKEN_TYPES = List.of("keyword", "type", "class", "string", "number", "operator",
"variable", "method", "modifier", "regexp");
"variable", "method", "regexp", "parameter");
@Override
public List<String> getTokenTypes() {
@@ -42,90 +46,80 @@ public class JpqlSemanticTokens implements SemanticTokensDataProvider {
@Override
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
List<SemanticTokenData> tokens = new ArrayList<>();
JpqlLexer lexer = new JpqlLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
JpqlParser parser = new JpqlParser(antlrTokens);
HashSet<Token> coloredTokens = new HashSet<>();
Map<Token, String> semantics = new HashMap<>();
parser.addParseListener(new JpqlBaseListener() {
private void addToken(Token token, String tokenType) {
tokens.add(new SemanticTokenData(token.getStartIndex() + initialOffset,
token.getStartIndex() + token.getText().length() + initialOffset, tokenType, new String[0]));
coloredTokens.add(token);
}
private void processTerminalNode(TerminalNode node) {
if (coloredTokens.contains(node.getSymbol())) {
return;
}
int type = node.getSymbol().getType();
switch (type) {
case JpqlParser.STRINGLITERAL:
case JpqlParser.CHARACTER:
addToken(node.getSymbol(), "string");
semantics.put(node.getSymbol(), "string");
break;
case JpqlParser.LONGLITERAL:
case JpqlParser.INTLITERAL:
case JpqlParser.FLOATLITERAL:
addToken(node.getSymbol(), "number");
semantics.put(node.getSymbol(), "number");
break;
case JpqlParser.IDENTIFICATION_VARIABLE:
addToken(node.getSymbol(), "variable");
semantics.put(node.getSymbol(), "variable");
break;
case JpqlParser.JAVASTRINGLITERAL:
addToken(node.getSymbol(), "class");
semantics.put(node.getSymbol(), "class");
break;
case JpqlParser.EQUAL:
case JpqlParser.NOT_EQUAL:
addToken(node.getSymbol(), "operator");
semantics.put(node.getSymbol(), "operator");
break;
case JpqlParser.WS:
break;
case JpqlParser.SPEL:
addToken(node.getSymbol(), "regexp");
semantics.put(node.getSymbol(), "regexp");
break;
default:
if (JpqlParser.WS < type && type <= JpqlParser.WHERE) {
addToken(node.getSymbol(), "keyword");
semantics.put(node.getSymbol(), "keyword");
} else {
addToken(node.getSymbol(), "modifier");
semantics.put(node.getSymbol(), "operator");
}
}
}
@Override
public void enterState_field(State_fieldContext ctx) {
if (!coloredTokens.contains(ctx.getStart())) {
addToken(ctx.getStart(), "method");
public void exitState_field(State_fieldContext ctx) {
semantics.put(ctx.identification_variable().getStart(), "method");
}
@Override
public void exitSingle_valued_object_field(Single_valued_object_fieldContext ctx) {
semantics.put(ctx.identification_variable().getStart(), "method");
}
@Override
public void exitCollection_valued_field(Collection_valued_fieldContext ctx) {
semantics.put(ctx.identification_variable().getStart(), "method");
}
@Override
public void exitEntity_name(Entity_nameContext ctx) {
for (Identification_variableContext iv : ctx.identification_variable()) {
semantics.put(iv.getStart(), "class");
}
}
@Override
public void enterSingle_valued_object_field(Single_valued_object_fieldContext ctx) {
if (!coloredTokens.contains(ctx.getStart())) {
addToken(ctx.getStart(), "method");
}
public void exitEntity_type_literal(Entity_type_literalContext ctx) {
semantics.put(ctx.identification_variable().getStart(), "type");
}
@Override
public void enterCollection_valued_field(Collection_valued_fieldContext ctx) {
if (!coloredTokens.contains(ctx.getStart())) {
addToken(ctx.getStart(), "method");
}
}
@Override
public void enterEntity_name(Entity_nameContext ctx) {
if (!coloredTokens.contains(ctx.getStart())) {
addToken(ctx.getStart(), "class");
}
}
@Override
public void enterEntity_type_literal(Entity_type_literalContext ctx) {
if (!coloredTokens.contains(ctx.getStart())) {
addToken(ctx.getStart(), "type");
public void exitInput_parameter(Input_parameterContext ctx) {
if (ctx.identification_variable() != null && ctx.identification_variable().getStart() != null) {
semantics.put(ctx.identification_variable().getStart(), "parameter");
}
}
@@ -140,7 +134,17 @@ public class JpqlSemanticTokens implements SemanticTokensDataProvider {
}
});
parser.ql_statement();
List<SemanticTokenData> tokens = semantics.entrySet().stream()
.map(e -> new SemanticTokenData(e.getKey().getStartIndex() + initialOffset,
e.getKey().getStartIndex() + e.getKey().getText().length() + initialOffset, e.getValue(),
new String[0]))
.collect(Collectors.toList());
Collections.sort(tokens);
return tokens;
}

View File

@@ -14,6 +14,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.lsp4j.DocumentFilter;
import org.eclipse.lsp4j.SemanticTokens;
@@ -27,6 +29,7 @@ import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
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.languageserver.semantic.tokens.SemanticTokensHandler;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokensUtils;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
@@ -44,13 +47,16 @@ public class QueryPropertiesSemanticTokensHandler implements SemanticTokensHandl
private final JavaProjectFinder projectFinder;
private final SimpleTextDocumentService documents;
private final JpqlSemanticTokens tokensProvider;
private final JpqlSemanticTokens jpqlTokensProvider;
private final HqlSemanticTokens hqlTokensProvider;
private final JpqlSupportState supportState;
public QueryPropertiesSemanticTokensHandler(SimpleTextDocumentService documents, JavaProjectFinder projectFinder, JpqlSemanticTokens jpqlTokensProvider, JpqlSupportState supportState) {
public QueryPropertiesSemanticTokensHandler(SimpleTextDocumentService documents, JavaProjectFinder projectFinder, JpqlSemanticTokens jpqlTokensProvider, HqlSemanticTokens hqlTokensProvider, JpqlSupportState supportState) {
this.documents = documents;
this.projectFinder = projectFinder;
this.tokensProvider = jpqlTokensProvider;
this.jpqlTokensProvider = jpqlTokensProvider;
this.hqlTokensProvider = hqlTokensProvider;
this.supportState = supportState;
}
@@ -61,7 +67,9 @@ public class QueryPropertiesSemanticTokensHandler implements SemanticTokensHandl
documentFilter.setLanguage(LanguageId.JPA_QUERY_PROPERTIES.getId());
capabilities.setDocumentSelector(List.of(documentFilter));
capabilities.setFull(true);
capabilities.setLegend(new SemanticTokensLegend(tokensProvider.getTokenTypes(), tokensProvider.getTypeModifiers()));
capabilities.setLegend(new SemanticTokensLegend(
Stream.concat(jpqlTokensProvider.getTokenTypes().stream(), hqlTokensProvider.getTokenTypes().stream()).distinct().collect(Collectors.toList()),
Stream.concat(jpqlTokensProvider.getTypeModifiers().stream(), hqlTokensProvider.getTypeModifiers().stream()).distinct().collect(Collectors.toList())));
return capabilities;
}
@@ -74,6 +82,7 @@ public class QueryPropertiesSemanticTokensHandler implements SemanticTokensHandl
if (optProject.isPresent() && SpringProjectUtil.hasDependencyStartingWith(optProject.get(), "spring-data-jpa", null)) {
TextDocument doc = documents.getLatestSnapshot(params.getTextDocument().getUri());
if (doc != null) {
SemanticTokensDataProvider tokensProvider = SpringProjectUtil.hasDependencyStartingWith(optProject.get(), "hibernate-core", null) ? hqlTokensProvider : jpqlTokensProvider;
AntlrParser propertiesParser = new AntlrParser();
ParseResults result = propertiesParser.parse(doc.get());
List<SemanticTokenData> data = new ArrayList<>();

View File

@@ -56,7 +56,7 @@ public class HqlSemanticTokensTest {
assertThat(tokens.get(5)).isEqualTo(new SemanticTokenData(22, 27, "keyword", new String[0]));
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(28, 30, "keyword", new String[0]));
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(31, 32, "variable", new String[0]));
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(32, 33, "modifier", new String[0]));
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(32, 33, "operator", new String[0]));
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(33, 37, "method", new String[0]));
assertThat(tokens.size()).isEqualTo(10);
@@ -74,18 +74,43 @@ public class HqlSemanticTokensTest {
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(39, 43, "keyword", new String[0])); // left
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(44, 48, "keyword", new String[0])); // join
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(50, 55, "variable", new String[0])); // owner
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(55, 56, "modifier", new String[0])); // .
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(55, 56, "operator", new String[0])); // .
assertThat(tokens.get(10)).isEqualTo(new SemanticTokenData(56, 60, "method", new String[0])); // pets
assertThat(tokens.get(11)).isEqualTo(new SemanticTokenData(61, 66, "keyword", new String[0])); // WHERE
assertThat(tokens.get(12)).isEqualTo(new SemanticTokenData(67, 72, "variable", new String[0])); // owner
assertThat(tokens.get(13)).isEqualTo(new SemanticTokenData(72, 73, "modifier", new String[0])); // .
assertThat(tokens.get(13)).isEqualTo(new SemanticTokenData(72, 73, "operator", new String[0])); // .
assertThat(tokens.get(14)).isEqualTo(new SemanticTokenData(73, 81, "method", new String[0])); // lastName
assertThat(tokens.get(15)).isEqualTo(new SemanticTokenData(82, 86, "keyword", new String[0])); // LIKE
assertThat(tokens.get(16)).isEqualTo(new SemanticTokenData(87, 88, "modifier", new String[0])); // :
assertThat(tokens.get(17)).isEqualTo(new SemanticTokenData(88, 96, "variable", new String[0])); // lastName
assertThat(tokens.get(18)).isEqualTo(new SemanticTokenData(96, 97, "modifier", new String[0])); // lastName
assertThat(tokens.get(16)).isEqualTo(new SemanticTokenData(87, 88, "operator", new String[0])); // :
assertThat(tokens.get(17)).isEqualTo(new SemanticTokenData(88, 96, "parameter", new String[0])); // lastName
assertThat(tokens.get(18)).isEqualTo(new SemanticTokenData(96, 97, "operator", new String[0])); // lastName
assertThat(tokens.size()).isEqualTo(19);
}
@Test
void query_with_SPEL() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:#{id}", 0);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0])); // SELECT
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 12, "variable", new String[0])); // owner
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(13, 17, "keyword", new String[0])); // FROM
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(18, 23, "class", new String[0])); // Owner
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(24, 29, "variable", new String[0])); // owner
assertThat(tokens.get(5)).isEqualTo(new SemanticTokenData(30, 34, "keyword", new String[0])); // left
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(35, 39, "keyword", new String[0])); // join
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(40, 45, "keyword", new String[0])); // fetch
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(46, 51, "variable", new String[0])); // owner
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(51, 52, "operator", new String[0])); // .
assertThat(tokens.get(10)).isEqualTo(new SemanticTokenData(52, 56, "method", new String[0])); // pets
assertThat(tokens.get(11)).isEqualTo(new SemanticTokenData(57, 62, "keyword", new String[0])); // WHERE
assertThat(tokens.get(12)).isEqualTo(new SemanticTokenData(63, 68, "variable", new String[0])); // owner
assertThat(tokens.get(13)).isEqualTo(new SemanticTokenData(68, 69, "operator", new String[0])); // .
assertThat(tokens.get(14)).isEqualTo(new SemanticTokenData(69, 71, "method", new String[0])); // id
assertThat(tokens.get(15)).isEqualTo(new SemanticTokenData(72, 73, "operator", new String[0])); // =
assertThat(tokens.get(16)).isEqualTo(new SemanticTokenData(73, 74, "operator", new String[0])); // :
assertThat(tokens.get(17)).isEqualTo(new SemanticTokenData(74, 79, "regexp", new String[0])); // #{id}
assertThat(tokens.size()).isEqualTo(18);
}
}

View File

@@ -64,7 +64,7 @@ public class JdtDataQuerySemanticTokensProviderTest {
assertThat(cu).isNotNull();
List<SemanticTokenData> tokens = provider.computeTokens(cu);
List<SemanticTokenData> tokens = provider.computeTokens(jp, cu);
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(120, 126, "keyword", new String[0]));
@@ -110,7 +110,7 @@ public class JdtDataQuerySemanticTokensProviderTest {
assertThat(cu).isNotNull();
List<SemanticTokenData> tokens = provider.computeTokens(cu);
List<SemanticTokenData> tokens = provider.computeTokens(jp, cu);
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(128, 134, "keyword", new String[0]));
@@ -157,7 +157,7 @@ public class JdtDataQuerySemanticTokensProviderTest {
assertThat(cu).isNotNull();
List<SemanticTokenData> tokens = provider.computeTokens(cu);
List<SemanticTokenData> tokens = provider.computeTokens(jp, cu);
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(176, 182, "keyword", new String[0]));
@@ -203,7 +203,7 @@ public class JdtDataQuerySemanticTokensProviderTest {
assertThat(cu).isNotNull();
List<SemanticTokenData> tokens = provider.computeTokens(cu);
List<SemanticTokenData> tokens = provider.computeTokens(jp, cu);
assertThat(tokens.size()).isZero();

View File

@@ -47,43 +47,44 @@ public class JpqlSemanticTokensTest {
@Test
void query_with_conflicting_groupby() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT g FROM Group g GROUP BY g.name", 0);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 8, "variable", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(9, 13, "keyword", new String[0]));
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(14, 19, "class", new String[0]));
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(20, 21, "variable", new String[0]));
assertThat(tokens.get(5)).isEqualTo(new SemanticTokenData(22, 27, "keyword", new String[0]));
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(28, 30, "keyword", new String[0]));
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(31, 32, "variable", new String[0]));
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(32, 33, "modifier", new String[0]));
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(33, 37, "method", new String[0]));
List<SemanticTokenData> tokens = provider.computeTokens("SELECT g FROM G g GROUP BY g.name", 0);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0])); // SELECT
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 8, "variable", new String[0])); // g
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(9, 13, "keyword", new String[0])); // FROM
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(14, 15, "class", new String[0])); //G
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(16, 17, "variable", new String[0])); // g
assertThat(tokens.get(5)).isEqualTo(new SemanticTokenData(18, 23, "keyword", new String[0])); // GROUP
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(24, 26, "keyword", new String[0])); // BY
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(27, 28, "variable", new String[0])); // g
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(28, 29, "operator", new String[0])); // .
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(29, 33, "method", new String[0])); // name
assertThat(tokens.size()).isEqualTo(10);
}
@Test
void query_with_parameter() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :lastName%", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT f from Student f LEFT JOIN f.classTbls s WHERE s.ClassName = :className%", 0);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0])); // SELECT
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 15, "keyword", new String[0])); // DISTINCT
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(16, 21, "variable", new String[0])); // owner
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(22, 26, "keyword", new String[0])); // FROM
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(27, 32, "class", new String[0])); // Owner
assertThat(tokens.get(5)).isEqualTo(new SemanticTokenData(33, 38, "variable", new String[0])); // owner
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(39, 43, "keyword", new String[0])); // left
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(44, 48, "keyword", new String[0])); // join
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(50, 55, "variable", new String[0])); // owner
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(55, 56, "modifier", new String[0])); // .
assertThat(tokens.get(10)).isEqualTo(new SemanticTokenData(56, 60, "method", new String[0])); // pets
assertThat(tokens.get(11)).isEqualTo(new SemanticTokenData(61, 66, "keyword", new String[0])); // WHERE
assertThat(tokens.get(12)).isEqualTo(new SemanticTokenData(67, 72, "variable", new String[0])); // owner
assertThat(tokens.get(13)).isEqualTo(new SemanticTokenData(72, 73, "modifier", new String[0])); // .
assertThat(tokens.get(14)).isEqualTo(new SemanticTokenData(73, 81, "method", new String[0])); // lastName
assertThat(tokens.get(15)).isEqualTo(new SemanticTokenData(82, 86, "keyword", new String[0])); // LIKE
assertThat(tokens.get(16)).isEqualTo(new SemanticTokenData(87, 88, "modifier", new String[0])); // :
assertThat(tokens.get(17)).isEqualTo(new SemanticTokenData(88, 96, "variable", new String[0])); // lastName
assertThat(tokens.get(18)).isEqualTo(new SemanticTokenData(96, 97, "modifier", new String[0])); // lastName
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 8, "variable", new String[0])); // f
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(9, 13, "keyword", new String[0])); // from
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(14, 21, "class", new String[0])); // Student
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(22, 23, "variable", new String[0])); // f
assertThat(tokens.get(5)).isEqualTo(new SemanticTokenData(24, 28, "keyword", new String[0])); // LEFT
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(29, 33, "keyword", new String[0])); // JOIN
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(34, 35, "variable", new String[0])); // f
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(35, 36, "operator", new String[0])); // .
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(36, 45, "method", new String[0])); // classTbls
assertThat(tokens.get(10)).isEqualTo(new SemanticTokenData(46, 47, "variable", new String[0])); // s
assertThat(tokens.get(11)).isEqualTo(new SemanticTokenData(48, 53, "keyword", new String[0])); // WHERE
assertThat(tokens.get(12)).isEqualTo(new SemanticTokenData(54, 55, "variable", new String[0])); // s
assertThat(tokens.get(13)).isEqualTo(new SemanticTokenData(55, 56, "operator", new String[0])); // .
assertThat(tokens.get(14)).isEqualTo(new SemanticTokenData(56, 65, "method", new String[0])); // ClassName
assertThat(tokens.get(15)).isEqualTo(new SemanticTokenData(66, 67, "operator", new String[0])); // =
assertThat(tokens.get(16)).isEqualTo(new SemanticTokenData(68, 69, "operator", new String[0])); // :
assertThat(tokens.get(17)).isEqualTo(new SemanticTokenData(69, 78, "parameter", new String[0])); // className
assertThat(tokens.get(18)).isEqualTo(new SemanticTokenData(78, 79, "operator", new String[0])); // %
assertThat(tokens.size()).isEqualTo(19);
}
@@ -100,15 +101,15 @@ public class JpqlSemanticTokensTest {
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(35, 39, "keyword", new String[0])); // join
assertThat(tokens.get(7)).isEqualTo(new SemanticTokenData(40, 45, "keyword", new String[0])); // fetch
assertThat(tokens.get(8)).isEqualTo(new SemanticTokenData(46, 51, "variable", new String[0])); // owner
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(51, 52, "modifier", new String[0])); // .
assertThat(tokens.get(9)).isEqualTo(new SemanticTokenData(51, 52, "operator", new String[0])); // .
assertThat(tokens.get(10)).isEqualTo(new SemanticTokenData(52, 56, "method", new String[0])); // pets
assertThat(tokens.get(11)).isEqualTo(new SemanticTokenData(57, 62, "keyword", new String[0])); // WHERE
assertThat(tokens.get(12)).isEqualTo(new SemanticTokenData(63, 68, "variable", new String[0])); // owner
assertThat(tokens.get(13)).isEqualTo(new SemanticTokenData(68, 69, "modifier", new String[0])); // .
assertThat(tokens.get(13)).isEqualTo(new SemanticTokenData(68, 69, "operator", new String[0])); // .
assertThat(tokens.get(14)).isEqualTo(new SemanticTokenData(69, 71, "method", new String[0])); // id
assertThat(tokens.get(15)).isEqualTo(new SemanticTokenData(72, 73, "operator", new String[0])); // =
assertThat(tokens.get(16)).isEqualTo(new SemanticTokenData(73, 74, "modifier", new String[0])); // :
assertThat(tokens.get(17)).isEqualTo(new SemanticTokenData(74, 79, "regexp", new String[0])); // ${id}
assertThat(tokens.get(16)).isEqualTo(new SemanticTokenData(73, 74, "operator", new String[0])); // :
assertThat(tokens.get(17)).isEqualTo(new SemanticTokenData(74, 79, "regexp", new String[0])); // #{id}
assertThat(tokens.size()).isEqualTo(18);
}