Embedded SQL syntax highlighting and syntax validation
This commit is contained in:
4
headless-services/commons/jpql/.gitignore
vendored
4
headless-services/commons/jpql/.gitignore
vendored
@@ -7,4 +7,8 @@
|
||||
/src/main/java/org/springframework/ide/vscode/parser/hql/Hql.tokens
|
||||
/src/main/java/org/springframework/ide/vscode/parser/hql/HqlLexer.interp
|
||||
/src/main/java/org/springframework/ide/vscode/parser/hql/HqlLexer.tokens
|
||||
/src/main/java/org/springframework/ide/vscode/parser/sql/MySqlParser.interp
|
||||
/src/main/java/org/springframework/ide/vscode/parser/sql/MySqlParser.tokens
|
||||
/src/main/java/org/springframework/ide/vscode/parser/sql/MySqlLexer.interp
|
||||
/src/main/java/org/springframework/ide/vscode/parser/sql/MySqlLexer.tokens
|
||||
/target
|
||||
|
||||
@@ -7,5 +7,6 @@ fi
|
||||
workdir=$(pwd)
|
||||
cd grammars
|
||||
java -jar ${workdir}/antlr-${ANTLR_VERSION}.jar Jpql.g4 -o ${workdir}/src/main/java/org/springframework/ide/vscode/parser/jpql -package org.springframework.ide.vscode.parser.jpql
|
||||
java -jar ${workdir}/antlr-${ANTLR_VERSION}.jar Hql.g4 -o ${workdir}/src/main/java/org/springframework/ide/vscode//parser/hql -package org.springframework.ide.vscode.parser.hql
|
||||
java -jar ${workdir}/antlr-${ANTLR_VERSION}.jar Hql.g4 -o ${workdir}/src/main/java/org/springframework/ide/vscode/parser/hql -package org.springframework.ide.vscode.parser.hql
|
||||
java -jar ${workdir}/antlr-${ANTLR_VERSION}.jar MySqlLexer.g4 MySqlParser.g4 -o ${workdir}/src/main/java/org/springframework/ide/vscode/parser/sql -package org.springframework.ide.vscode.parser.sql
|
||||
|
||||
|
||||
1354
headless-services/commons/jpql/grammars/MySqlLexer.g4
Normal file
1354
headless-services/commons/jpql/grammars/MySqlLexer.g4
Normal file
File diff suppressed because it is too large
Load Diff
3492
headless-services/commons/jpql/grammars/MySqlParser.g4
Normal file
3492
headless-services/commons/jpql/grammars/MySqlParser.g4
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -25,8 +25,10 @@ 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.HqlReconciler;
|
||||
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.JpqlReconciler;
|
||||
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.boot.java.links.JavaElementLocationProvider;
|
||||
@@ -128,7 +130,7 @@ public class BootLanguageServerInitializer implements InitializingBean {
|
||||
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(HqlSemanticTokens.class), appContext.getBean(JpqlSupportState.class))
|
||||
appContext.getBean(HqlSemanticTokens.class), appContext.getBean(JpqlSupportState.class), appContext.getBean(HqlReconciler.class), appContext.getBean(JpqlReconciler.class))
|
||||
);
|
||||
|
||||
for (LanguageServerComponents c : componentsList) {
|
||||
|
||||
@@ -12,11 +12,15 @@ 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.HqlReconciler;
|
||||
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.JpqlReconciler;
|
||||
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.boot.java.data.jpa.queries.QueryJdtAstReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.SqlReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.SqlSemanticTokens;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.AddConfigurationIfBeansPresentReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.AnnotationNodeReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.reconcilers.AuthorizeHttpRequestsReconciler;
|
||||
@@ -117,12 +121,12 @@ public class JdtConfig {
|
||||
return new JavaSemanticTokensProvider();
|
||||
}
|
||||
|
||||
@Bean JdtDataQuerySemanticTokensProvider jpqlJdtSemanticTokensProvider(JpqlSemanticTokens jpqlProvider, HqlSemanticTokens hqlProvider, JpqlSupportState supportState) {
|
||||
return new JdtDataQuerySemanticTokensProvider(jpqlProvider, hqlProvider, supportState);
|
||||
@Bean JdtDataQuerySemanticTokensProvider jpqlJdtSemanticTokensProvider(JpqlSemanticTokens jpqlProvider, HqlSemanticTokens hqlProvider, SqlSemanticTokens sqlSemanticTokens, JpqlSupportState supportState) {
|
||||
return new JdtDataQuerySemanticTokensProvider(jpqlProvider, hqlProvider, sqlSemanticTokens, supportState);
|
||||
}
|
||||
|
||||
@Bean QueryJdtAstReconciler dataQueryReconciler() {
|
||||
return new QueryJdtAstReconciler();
|
||||
@Bean QueryJdtAstReconciler dataQueryReconciler(HqlReconciler hqlReconciler, JpqlReconciler jpqlReconciler, SqlReconciler sqlReconciler) {
|
||||
return new QueryJdtAstReconciler(hqlReconciler, jpqlReconciler, sqlReconciler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,9 +12,13 @@ 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.HqlReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.HqlSemanticTokens;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JpqlReconciler;
|
||||
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.boot.java.data.jpa.queries.SqlReconciler;
|
||||
import org.springframework.ide.vscode.boot.java.data.jpa.queries.SqlSemanticTokens;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
|
||||
@@ -30,6 +34,26 @@ public class SpringDataConfig {
|
||||
HqlSemanticTokens hqlSemanticTokens() {
|
||||
return new HqlSemanticTokens();
|
||||
}
|
||||
|
||||
@Bean
|
||||
SqlSemanticTokens sqlSemanticTokens() {
|
||||
return new SqlSemanticTokens();
|
||||
}
|
||||
|
||||
@Bean
|
||||
HqlReconciler hqlReconciler() {
|
||||
return new HqlReconciler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
JpqlReconciler jpqlReconciler() {
|
||||
return new JpqlReconciler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
SqlReconciler sqlReconciler() {
|
||||
return new SqlReconciler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
JpqlSupportState jpqlSupportState(SimpleLanguageServer server, ProjectObserver projectObserver, BootJavaConfig config) {
|
||||
|
||||
@@ -50,7 +50,7 @@ public class HqlReconciler implements Reconciler {
|
||||
offset = token.getStartIndex() - token.getCharPositionInLine();
|
||||
length = token.getCharPositionInLine() + 1;
|
||||
}
|
||||
problemCollector.accept(new ReconcileProblemImpl(QueryProblemType.EXPRESSION_SYNTAX, msg, startPosition + offset, length));
|
||||
problemCollector.accept(new ReconcileProblemImpl(QueryProblemType.EXPRESSION_SYNTAX, "HQL: " + msg, startPosition + offset, length));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -40,11 +40,13 @@ public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProv
|
||||
|
||||
private final JpqlSemanticTokens jpqlProvider;
|
||||
private final HqlSemanticTokens hqlProvider;
|
||||
private final SqlSemanticTokens sqlProvider;
|
||||
private final JpqlSupportState supportState;
|
||||
|
||||
public JdtDataQuerySemanticTokensProvider(JpqlSemanticTokens jpqlProvider, HqlSemanticTokens hqlProvider, JpqlSupportState supportState) {
|
||||
public JdtDataQuerySemanticTokensProvider(JpqlSemanticTokens jpqlProvider, HqlSemanticTokens hqlProvider, SqlSemanticTokens sqlSemanticTokens, JpqlSupportState supportState) {
|
||||
this.jpqlProvider = jpqlProvider;
|
||||
this.hqlProvider = hqlProvider;
|
||||
this.sqlProvider = sqlSemanticTokens;
|
||||
this.supportState = supportState;
|
||||
}
|
||||
|
||||
@@ -94,7 +96,7 @@ public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProv
|
||||
|
||||
if (queryExpression != null) {
|
||||
if (isNative) {
|
||||
//TODO: SQL semantic tokens
|
||||
computeTokensForQueryExpression(sqlProvider, queryExpression).forEach(tokensData::accept);
|
||||
} else {
|
||||
computeTokensForQueryExpression(provider, queryExpression).forEach(tokensData::accept);
|
||||
}
|
||||
|
||||
@@ -26,9 +26,10 @@ public class JpaQueryPropertiesLanguageServerComponents implements LanguageServe
|
||||
private final NamedQueryPropertiesReconcileEngine reconcileEngine;
|
||||
|
||||
public JpaQueryPropertiesLanguageServerComponents(SimpleTextDocumentService documents, JavaProjectFinder projectsFinder,
|
||||
JpqlSemanticTokens jpqlSemanticTokensProvider, HqlSemanticTokens hqlSematicTokensProvider, JpqlSupportState supportState) {
|
||||
JpqlSemanticTokens jpqlSemanticTokensProvider, HqlSemanticTokens hqlSematicTokensProvider, JpqlSupportState supportState,
|
||||
HqlReconciler hqlReconciler, JpqlReconciler jpqlReconciler) {
|
||||
this.semanticTokensHandler = new QueryPropertiesSemanticTokensHandler(projectsFinder, jpqlSemanticTokensProvider, hqlSematicTokensProvider, supportState);
|
||||
this.reconcileEngine = new NamedQueryPropertiesReconcileEngine(projectsFinder);
|
||||
this.reconcileEngine = new NamedQueryPropertiesReconcileEngine(projectsFinder, hqlReconciler, jpqlReconciler);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -50,7 +50,7 @@ public class JpqlReconciler implements Reconciler {
|
||||
offset = token.getStartIndex() - token.getCharPositionInLine();
|
||||
length = token.getCharPositionInLine() + 1;
|
||||
}
|
||||
problemCollector.accept(new ReconcileProblemImpl(QueryProblemType.EXPRESSION_SYNTAX, msg, startPosition + offset, length));
|
||||
problemCollector.accept(new ReconcileProblemImpl(QueryProblemType.EXPRESSION_SYNTAX, "JPQL: " + msg, startPosition + offset, length));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,16 +25,20 @@ import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.Value
|
||||
public class NamedQueryPropertiesReconcileEngine implements IReconcileEngine {
|
||||
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private final HqlReconciler hqlReconciler;
|
||||
private final JpqlReconciler jpqlReconciler;
|
||||
|
||||
public NamedQueryPropertiesReconcileEngine(JavaProjectFinder projectFinder) {
|
||||
public NamedQueryPropertiesReconcileEngine(JavaProjectFinder projectFinder, HqlReconciler hqlReconciler, JpqlReconciler jpqlReconciler) {
|
||||
this.projectFinder = projectFinder;
|
||||
this.hqlReconciler = hqlReconciler;
|
||||
this.jpqlReconciler = jpqlReconciler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconcile(IDocument doc, IProblemCollector problemCollector) {
|
||||
try {
|
||||
Reconciler reconciler = projectFinder.find(new TextDocumentIdentifier(doc.getUri()))
|
||||
.map(p -> SpringProjectUtil.hasDependencyStartingWith(p, "spring-data-jpa", null) ? new HqlReconciler() : new JpqlReconciler())
|
||||
.map(p -> SpringProjectUtil.hasDependencyStartingWith(p, "spring-data-jpa", null) ? hqlReconciler : jpqlReconciler)
|
||||
.orElse(new JpqlReconciler());
|
||||
|
||||
AntlrParser parser = new AntlrParser();
|
||||
|
||||
@@ -34,6 +34,18 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemC
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
|
||||
|
||||
public class QueryJdtAstReconciler implements JdtAstReconciler {
|
||||
|
||||
private final HqlReconciler hqlReconciler;
|
||||
private final JpqlReconciler jpqlReconciler;
|
||||
private final SqlReconciler sqlReconciler;
|
||||
|
||||
|
||||
public QueryJdtAstReconciler(HqlReconciler hqlReconciler, JpqlReconciler jpqlReconciler,
|
||||
SqlReconciler sqlReconciler) {
|
||||
this.hqlReconciler = hqlReconciler;
|
||||
this.jpqlReconciler = jpqlReconciler;
|
||||
this.sqlReconciler = sqlReconciler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASTVisitor createVisitor(IJavaProject project, URI docURI, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) throws RequiredCompleteAstException {
|
||||
@@ -75,7 +87,7 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
|
||||
|
||||
if (queryExpression != null) {
|
||||
if (isNative) {
|
||||
//TODO: SQL syntax validation
|
||||
reconcileExpression(sqlReconciler, queryExpression, problemCollector);
|
||||
} else {
|
||||
reconcileExpression(getQueryReconciler(project), queryExpression, problemCollector);
|
||||
}
|
||||
@@ -113,8 +125,8 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
|
||||
/*
|
||||
* Gets either HQL or JPQL reconciler
|
||||
*/
|
||||
private static Reconciler getQueryReconciler(IJavaProject project) {
|
||||
return SpringProjectUtil.hasDependencyStartingWith(project, "hibernate-core", null) ? new HqlReconciler() : new JpqlReconciler();
|
||||
private Reconciler getQueryReconciler(IJavaProject project) {
|
||||
return SpringProjectUtil.hasDependencyStartingWith(project, "hibernate-core", null) ? hqlReconciler : jpqlReconciler;
|
||||
}
|
||||
|
||||
private void reconcileExpression(Reconciler reconciler, Expression valueExp, IProblemCollector problemCollector) {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.antlr.v4.runtime.ANTLRErrorListener;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.antlr.v4.runtime.ConsoleErrorListener;
|
||||
import org.antlr.v4.runtime.Parser;
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Recognizer;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.atn.ATNConfigSet;
|
||||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.Reconciler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
|
||||
import org.springframework.ide.vscode.parser.sql.MySqlLexer;
|
||||
import org.springframework.ide.vscode.parser.sql.MySqlParser;
|
||||
|
||||
public class SqlReconciler implements Reconciler {
|
||||
|
||||
@Override
|
||||
public void reconcile(String text, int startPosition, IProblemCollector problemCollector) {
|
||||
MySqlLexer lexer = new MySqlLexer(CharStreams.fromString(text));
|
||||
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
|
||||
MySqlParser parser = new MySqlParser(antlrTokens);
|
||||
|
||||
parser.removeErrorListener(ConsoleErrorListener.INSTANCE);
|
||||
|
||||
parser.addErrorListener(new ANTLRErrorListener() {
|
||||
|
||||
@Override
|
||||
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine,
|
||||
String msg, RecognitionException e) {
|
||||
Token token = (Token) offendingSymbol;
|
||||
int offset = token.getStartIndex();
|
||||
int length = token.getStopIndex() - token.getStartIndex() + 1;
|
||||
if (token.getStartIndex() >= token.getStopIndex()) {
|
||||
offset = token.getStartIndex() - token.getCharPositionInLine();
|
||||
length = token.getCharPositionInLine() + 1;
|
||||
}
|
||||
problemCollector.accept(new ReconcileProblemImpl(QueryProblemType.EXPRESSION_SYNTAX, "SQL: " + msg, startPosition + offset, length));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportContextSensitivity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, int prediction,
|
||||
ATNConfigSet configs) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportAttemptingFullContext(Parser recognizer, DFA dfa, int startIndex, int stopIndex,
|
||||
BitSet conflictingAlts, ATNConfigSet configs) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, boolean exact,
|
||||
BitSet ambigAlts, ATNConfigSet configs) {
|
||||
}
|
||||
});
|
||||
|
||||
parser.sqlStatements();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2024 Broadcom, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Broadcom, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
|
||||
|
||||
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;
|
||||
import org.antlr.v4.runtime.ConsoleErrorListener;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.ErrorNode;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
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.parser.sql.MySqlLexer;
|
||||
import org.springframework.ide.vscode.parser.sql.MySqlParser;
|
||||
import org.springframework.ide.vscode.parser.sql.MySqlParserBaseListener;
|
||||
|
||||
public class SqlSemanticTokens implements SemanticTokensDataProvider {
|
||||
|
||||
private static List<String> TOKEN_TYPES = List.of("keyword", "type", "string", "number", "operator",
|
||||
"variable", "regexp", "comment");
|
||||
|
||||
@Override
|
||||
public List<String> getTokenTypes() {
|
||||
return TOKEN_TYPES;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
|
||||
MySqlLexer lexer = new MySqlLexer(CharStreams.fromString(text));
|
||||
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
|
||||
MySqlParser parser = new MySqlParser(antlrTokens);
|
||||
|
||||
Map<Token, String> semantics = new HashMap<>();
|
||||
|
||||
parser.removeErrorListener(ConsoleErrorListener.INSTANCE);
|
||||
|
||||
parser.addParseListener(new MySqlParserBaseListener() {
|
||||
|
||||
private void processTerminalNode(TerminalNode node) {
|
||||
int type = node.getSymbol().getType();
|
||||
switch (type) {
|
||||
case MySqlParser.SPEL:
|
||||
semantics.put(node.getSymbol(), "regexp");
|
||||
break;
|
||||
case MySqlParser.ID:
|
||||
semantics.put(node.getSymbol(), "variable");
|
||||
break;
|
||||
case MySqlParser.DOT_ID:
|
||||
semantics.put(node.getSymbol(), "variable");
|
||||
break;
|
||||
case MySqlParser.DOT:
|
||||
semantics.put(node.getSymbol(), "operator");
|
||||
break;
|
||||
case MySqlParser.NULL_LITERAL:
|
||||
semantics.put(node.getSymbol(), "number");
|
||||
break;
|
||||
case MySqlParser.FILESIZE_LITERAL:
|
||||
semantics.put(node.getSymbol(), "number");
|
||||
break;
|
||||
case MySqlParser.ZERO_DECIMAL:
|
||||
case MySqlParser.ONE_DECIMAL:
|
||||
case MySqlParser.TWO_DECIMAL:
|
||||
semantics.put(node.getSymbol(), "number");
|
||||
break;
|
||||
case MySqlParser.START_NATIONAL_STRING_LITERAL:
|
||||
case MySqlParser.STRING_LITERAL:
|
||||
semantics.put(node.getSymbol(), "string");
|
||||
break;
|
||||
case MySqlParser.STRING_CHARSET_NAME:
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
break;
|
||||
case MySqlParser.HOST_IP_ADDRESS:
|
||||
case MySqlParser.LOCAL_ID:
|
||||
case MySqlParser.GLOBAL_ID:
|
||||
semantics.put(node.getSymbol(), "string");
|
||||
break;
|
||||
case MySqlParser.SPEC_MYSQL_COMMENT:
|
||||
case MySqlParser.COMMENT_INPUT:
|
||||
case MySqlParser.LINE_COMMENT:
|
||||
semantics.put(node.getSymbol(), "comment");
|
||||
break;
|
||||
default:
|
||||
if (MySqlParser.VAR_ASSIGN <= type && type <= MySqlParser.COLON_SYMB) {
|
||||
semantics.put(node.getSymbol(), "operator");
|
||||
} else if (MySqlParser.DECIMAL_LITERAL <= type && type <= MySqlParser.BIT_STRING) {
|
||||
semantics.put(node.getSymbol(), "number");
|
||||
} else if (MySqlParser.ABS <= type && type <= MySqlParser.X_FUNCTION) {
|
||||
// Common function names
|
||||
semantics.put(node.getSymbol(), "keyword");
|
||||
} else if (MySqlParser.ADD <= type && type <= MySqlParser.ZEROFILL) {
|
||||
// Keywords
|
||||
// Common Keywords
|
||||
semantics.put(node.getSymbol(), "keyword");
|
||||
} else if (MySqlParser.TINYINT <= type && type <= MySqlParser.SERIAL) {
|
||||
// DATA TYPE Keywords
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
} else if (MySqlParser.YEAR_MONTH <= type && type <= MySqlParser.DAY_MICROSECOND) {
|
||||
// Interval type Keywords
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
} else if (MySqlParser.JSON_ARRAY <= type && type <= MySqlParser.PATH) {
|
||||
// JSON keywords
|
||||
semantics.put(node.getSymbol(), "keyword");
|
||||
} else if (MySqlParser.JSON_ARRAY <= type && type <= MySqlParser.PATH) {
|
||||
// Group function Keywords
|
||||
semantics.put(node.getSymbol(), "keyword");
|
||||
} else if (MySqlParser.CURRENT_DATE <= type && type <= MySqlParser.UTC_TIMESTAMP) {
|
||||
// Common function Keywords
|
||||
semantics.put(node.getSymbol(), "keyword");
|
||||
} else if (MySqlParser.ACCOUNT <= type && type <= MySqlParser.YES) {
|
||||
// Keywords, but can be ID
|
||||
// Common Keywords, but can be ID
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
} else if (MySqlParser.EUR <= type && type <= MySqlParser.INTERNAL) {
|
||||
// Date format Keywords
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
} else if (MySqlParser.QUARTER <= type && type <= MySqlParser.MICROSECOND) {
|
||||
// Date format Keywords
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
} else if (MySqlParser.ADMIN <= type && type <= MySqlParser.XA_RECOVER_ADMIN) {
|
||||
// PRIVILEGES
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
} else if (MySqlParser.ARMSCII8 <= type && type <= MySqlParser.UTF8MB4) {
|
||||
// Charsets
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
} else if (MySqlParser.ARCHIVE <= type && type <= MySqlParser.TOKUDB) {
|
||||
// DB Engines
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
} else if (MySqlParser.REPEATABLE <= type && type <= MySqlParser.SERIALIZABLE) {
|
||||
// Transaction Levels
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
} else if (MySqlParser.GEOMETRYCOLLECTION <= type && type <= MySqlParser.POLYGON) {
|
||||
// Spatial data types
|
||||
semantics.put(node.getSymbol(), "type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTerminal(TerminalNode node) {
|
||||
processTerminalNode(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitErrorNode(ErrorNode node) {
|
||||
processTerminalNode(node);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
parser.sqlStatements();
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -300,7 +300,7 @@ public class JdtDataQuerySemanticTokensProviderTest {
|
||||
|
||||
public interface OwnerRepository {
|
||||
|
||||
@Query(value = "SELECT DISTINCT owner FROM Owner owner", nativeQuery = true)
|
||||
@Query(value = "SELECT * FROM USERS u WHERE u.status = 1", nativeQuery = true)
|
||||
void findByLastName();
|
||||
}
|
||||
""";
|
||||
@@ -312,7 +312,45 @@ public class JdtDataQuerySemanticTokensProviderTest {
|
||||
|
||||
List<SemanticTokenData> tokens = computeTokens(cu);
|
||||
|
||||
assertThat(tokens.size()).isZero();
|
||||
SemanticTokenData token = tokens.get(0);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("SELECT");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(128, 134, "keyword", new String[0]));
|
||||
|
||||
token = tokens.get(1);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("*");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(135, 136, "operator", new String[0]));
|
||||
|
||||
token = tokens.get(2);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("FROM");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(137, 141, "keyword", new String[0]));
|
||||
|
||||
token = tokens.get(3);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("USERS");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(142, 147, "variable", new String[0]));
|
||||
|
||||
token = tokens.get(4);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("u");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(148, 149, "variable", new String[0]));
|
||||
|
||||
token = tokens.get(5);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("WHERE");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(150, 155, "keyword", new String[0]));
|
||||
|
||||
token = tokens.get(6);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("u");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(156, 157, "variable", new String[0]));
|
||||
|
||||
token = tokens.get(7);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo(".status");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(157, 164, "variable", new String[0]));
|
||||
|
||||
token = tokens.get(8);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("=");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(165, 166, "operator", new String[0]));
|
||||
|
||||
token = tokens.get(9);
|
||||
assertThat(source.substring(token.start(), token.end())).isEqualTo("1");
|
||||
assertThat(token).isEqualTo(new SemanticTokenData(167, 168, "number", new String[0]));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public class QueryReconcilerTest {
|
||||
String docUri = directory.toPath().resolve("src/main/resources/jpa-named-queries.properties").toUri()
|
||||
.toString();
|
||||
Editor editor = harness.newEditor(LanguageId.JPA_QUERY_PROPERTIES, source, docUri);
|
||||
editor.assertProblems("SELECTX|mismatched input 'SELECTX'");
|
||||
editor.assertProblems("SELECTX|HQL: mismatched input 'SELECTX'");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -99,7 +99,7 @@ public class QueryReconcilerTest {
|
||||
String docUri = directory.toPath().resolve("src/main/resources/jpa-named-queries.properties").toUri()
|
||||
.toString();
|
||||
Editor editor = harness.newEditor(LanguageId.JPA_QUERY_PROPERTIES, source, docUri);
|
||||
editor.assertProblems("WHERE|no viable alternative");
|
||||
editor.assertProblems("WHERE|JPQL: no viable alternative");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -141,7 +141,7 @@ public class QueryReconcilerTest {
|
||||
String docUri = directory.toPath().resolve("src/main/java/example/demo/OwnerRepository.java").toUri()
|
||||
.toString();
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, docUri);
|
||||
editor.assertProblems("SELECTX|mismatched input 'SELECTX'");
|
||||
editor.assertProblems("SELECTX|HQL: mismatched input 'SELECTX'");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,7 +164,7 @@ public class QueryReconcilerTest {
|
||||
String docUri = directory.toPath().resolve("src/main/java/example/demo/OwnerRepository.java").toUri()
|
||||
.toString();
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, docUri);
|
||||
editor.assertProblems("SELECTX|mismatched input 'SELECTX'");
|
||||
editor.assertProblems("SELECTX|HQL: mismatched input 'SELECTX'");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -185,7 +185,7 @@ public class QueryReconcilerTest {
|
||||
String docUri = directory.toPath().resolve("src/main/java/example/demo/OwnerRepository.java").toUri()
|
||||
.toString();
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, docUri);
|
||||
editor.assertProblems("SELECTX|mismatched input 'SELECTX'");
|
||||
editor.assertProblems("SELECTX|HQL: mismatched input 'SELECTX'");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -206,7 +206,7 @@ public class QueryReconcilerTest {
|
||||
String docUri = directory.toPath().resolve("src/main/java/example/demo/OwnerRepository.java").toUri()
|
||||
.toString();
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, source, docUri);
|
||||
editor.assertProblems();
|
||||
editor.assertProblems("SELECTX|SQL: mismatched input 'SELECTX' expecting {'ALTER',");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user