Embedded code accounts for concatenated strings and escape chars

This commit is contained in:
aboyko
2024-11-01 18:49:15 -04:00
parent 3957aac98e
commit ea033714b4
55 changed files with 2272 additions and 1595 deletions

View File

@@ -13,19 +13,25 @@ package org.springframework.ide.vscode.commons.languageserver.semantic.tokens;
import java.util.Arrays;
import java.util.Objects;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
public record SemanticTokenData(
int start,
int end,
IRegion range,
String type,
String[] modifiers
) implements Comparable<SemanticTokenData> {
public SemanticTokenData(int start, int end, String type, String[] modifiers) {
this(new Region(start, end -start), type, modifiers);
}
@Override
public int compareTo(SemanticTokenData o) {
if (start == o.start) {
return end - o.end;
if (range.getOffset() == o.range().getOffset()) {
return range.getLength() - o.range().getLength();
}
return start - o.start;
return range.getOffset() - o.range().getOffset();
}
@Override
@@ -33,7 +39,7 @@ public record SemanticTokenData(
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(modifiers);
result = prime * result + Objects.hash(end, start, type);
result = prime * result + Objects.hash(range, type);
return result;
}
@@ -46,8 +52,16 @@ public record SemanticTokenData(
if (getClass() != obj.getClass())
return false;
SemanticTokenData other = (SemanticTokenData) obj;
return end == other.end && Arrays.equals(modifiers, other.modifiers) && start == other.start
return range.getLength() == other.range.getLength() && Arrays.equals(modifiers, other.modifiers) && range.getOffset() == other.range().getOffset()
&& Objects.equals(type, other.type);
}
public int getStart() {
return range.getStart();
}
public int getEnd() {
return range.getEnd();
}
}

View File

@@ -17,6 +17,6 @@ public interface SemanticTokensDataProvider {
List<String> getTokenTypes();
default List<String> getTypeModifiers() { return Collections.emptyList(); }
List<SemanticTokenData> computeTokens(String text, int initialOffset);
List<SemanticTokenData> computeTokens(String text);
}

View File

@@ -52,11 +52,11 @@ public class SemanticTokensUtils {
int previousLine = 0;
int previousColumn = 0;
for (SemanticTokenData tokenData : tokensData) {
int currentLine = getLineNumber.apply(tokenData.start());
int currentColumn = getColumnNumber.apply(tokenData.start());
int currentLine = getLineNumber.apply(tokenData.getStart());
int currentColumn = getColumnNumber.apply(tokenData.getStart());
data.add(currentLine - previousLine);
data.add(currentLine == previousLine ? currentColumn - previousColumn : currentColumn);
data.add(tokenData.end() - tokenData.start());
data.add(tokenData.getEnd() - tokenData.getStart());
data.add(SemanticTokensUtils.getSemanticTokenTypeIndex(legend, tokenData.type()));
data.add(SemanticTokensUtils.getSemanticTokenModifiersFlags(legend, tokenData.modifiers()));
previousLine = currentLine;
@@ -79,11 +79,11 @@ public class SemanticTokensUtils {
int previousColumn = 0;
for (SemanticTokenData tokenData : tokensData) {
try {
int currentLine = doc.getLineOfOffset(tokenData.start());
int currentColumn = tokenData.start() - doc.getLineOffset(currentLine);
int currentLine = doc.getLineOfOffset(tokenData.getStart());
int currentColumn = tokenData.getStart() - doc.getLineOffset(currentLine);
data.add(currentLine - previousLine);
data.add(currentLine == previousLine ? currentColumn - previousColumn : currentColumn);
data.add(tokenData.end() - tokenData.start());
data.add(tokenData.getEnd() - tokenData.getStart());
data.add(SemanticTokensUtils.getSemanticTokenTypeIndex(legend, tokenData.type()));
data.add(SemanticTokensUtils.getSemanticTokenModifiersFlags(legend, tokenData.modifiers()));
previousLine = currentLine;

View File

@@ -18,5 +18,11 @@ public interface IRegion {
int getOffset();
int getLength();
default int getEnd() {
return getOffset() + getLength();
}
default int getStart() {
return getOffset();
}
}

View File

@@ -1489,7 +1489,7 @@ InvalidUnterminatedUnicodeQuotedIdentifier: 'U' '&' InvalidUnterminatedQuotedIde
StringConstant: UnterminatedStringConstant '\'';
UnterminatedStringConstant: '\'' ('\'\'' | ~ '\'' | '\\\\\'' | '\\\'')*;
UnterminatedStringConstant: '\'' ('\'\'' | ~ '\'' | '\\\'')*;
// String Constants with C-style Escapes (4.1.2.2)
BeginEscapeStringConstant: 'E' '\'' -> more, pushMode (EscapeStringConstantMode);
@@ -1625,7 +1625,6 @@ fragment EscapeStringText options {
}:
(
'\\\''
| '\'\'\''
| '\\' (
// two-digit hex escapes are still valid when treated as single-digit escapes
'x' [0-9a-fA-F]

View File

@@ -14,11 +14,11 @@ import java.util.Optional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.AntlrReconcilerWithSpel;
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.boot.java.data.jpa.queries.QueryProblemType;
import org.springframework.ide.vscode.boot.java.embadded.lang.AntlrReconcilerWithSpel;
import org.springframework.ide.vscode.boot.java.spel.SpelReconciler;
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;

View File

@@ -14,6 +14,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.BitSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import org.antlr.v4.runtime.ANTLRErrorListener;
import org.antlr.v4.runtime.CharStreams;
@@ -35,6 +36,8 @@ 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.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
import org.springframework.ide.vscode.commons.util.text.linetracker.DefaultLineTracker;
import org.springframework.ide.vscode.parser.cron.CronLexer;
import org.springframework.ide.vscode.parser.cron.CronParser;
@@ -62,7 +65,7 @@ public class CronReconciler implements Reconciler {
}
@Override
public void reconcile(String text, int startPosition, IProblemCollector problemCollector) {
public void reconcile(String text, Function<IRegion, IRegion> mapping, IProblemCollector problemCollector) {
CronLexer lexer = new CronLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
CronParser parser = new CronParser(antlrTokens);
@@ -117,7 +120,8 @@ public class CronReconciler implements Reconciler {
if (message.startsWith("For input string:")) {
markProblemsForNumberFormatException(ctx, message);
} else {
problemCollector.accept(new ReconcileProblemImpl(CronProblemType.FIELD, "CRON: %s".formatted(message), startPosition + ctx.getStart().getStartIndex(), ctx.getText().length()));
IRegion r = mapping.apply(new Region(ctx.getStart().getStartIndex(), ctx.getText().length()));
problemCollector.accept(new ReconcileProblemImpl(CronProblemType.FIELD, "CRON: %s".formatted(message), r.getOffset(), r.getLength()));
}
}
}
@@ -132,12 +136,14 @@ public class CronReconciler implements Reconciler {
String problemText = message.substring(start + 1, end);
int offset = text.indexOf(problemText);
if (offset >= 0) {
problemCollector.accept(new ReconcileProblemImpl(CronProblemType.FIELD, "CRON: Number expected", startPosition + ctx.getStart().getStartIndex() + offset, problemText.length()));
IRegion r = mapping.apply(new Region(ctx.getStart().getStartIndex() + offset, problemText.length()));
problemCollector.accept(new ReconcileProblemImpl(CronProblemType.FIELD, "CRON: Number expected", r.getOffset(), r.getLength()));
return;
}
}
}
problemCollector.accept(new ReconcileProblemImpl(CronProblemType.FIELD, "CRON: %s".formatted(message), startPosition + ctx.getStart().getStartIndex(), ctx.getText().length()));
IRegion r = mapping.apply(new Region(ctx.getStart().getStartIndex(), ctx.getText().length()));
problemCollector.accept(new ReconcileProblemImpl(CronProblemType.FIELD, "CRON: %s".formatted(message), r.getOffset(), r.getLength()));
}
@@ -169,7 +175,8 @@ public class CronReconciler implements Reconciler {
log.error("", e1);
}
}
problemCollector.accept(new ReconcileProblemImpl(CronProblemType.SYNTAX, "CRON: " + msg, startPosition + offset, length));
IRegion r = mapping.apply(new Region(offset, length));
problemCollector.accept(new ReconcileProblemImpl(CronProblemType.SYNTAX, "CRON: " + msg, r.getOffset(), r.getLength()));
}
@Override

View File

@@ -58,7 +58,7 @@ public class CronSemanticTokens implements SemanticTokensDataProvider {
}
@Override
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
public List<SemanticTokenData> computeTokens(String text) {
CronLexer lexer = new CronLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
CronParser parser = new CronParser(antlrTokens);
@@ -157,8 +157,8 @@ public class CronSemanticTokens implements SemanticTokensDataProvider {
parser.cronExpression();
tokens.addAll(semantics.entrySet().stream()
.map(e -> new SemanticTokenData(e.getKey().getStartIndex() + initialOffset,
e.getKey().getStartIndex() + e.getKey().getText().length() + initialOffset, e.getValue(),
.map(e -> new SemanticTokenData(e.getKey().getStartIndex(),
e.getKey().getStartIndex() + e.getKey().getText().length(), e.getValue(),
new String[0]))
.collect(Collectors.toList()));

View File

@@ -15,7 +15,7 @@ import java.net.URI;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedExpression;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLanguageSnippet;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
@@ -46,9 +46,9 @@ public class JdtCronReconciler implements JdtAstReconciler {
return new ASTVisitor() {
@Override
public boolean visit(NormalAnnotation node) {
EmbeddedExpression e = JdtCronVisitorUtils.extractCron(node);
EmbeddedLanguageSnippet e = JdtCronVisitorUtils.extractCron(node);
if (e != null) {
cronReconciler.reconcile(e.text(), e.offset(), problemCollector);
cronReconciler.reconcile(e.getText(), e::toSingleJavaRange, problemCollector);
}
return super.visit(node);
}

View File

@@ -16,7 +16,7 @@ import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.springframework.ide.vscode.boot.java.JdtSemanticTokensProvider;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedExpression;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLanguageSnippet;
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;
@@ -56,9 +56,12 @@ public class JdtCronSemanticTokensProvider implements JdtSemanticTokensProvider
@Override
public boolean visit(NormalAnnotation node) {
EmbeddedExpression e = JdtCronVisitorUtils.extractCron(node);
EmbeddedLanguageSnippet e = JdtCronVisitorUtils.extractCron(node);
if (e != null) {
tokensProvider.computeTokens(e.text(), e.offset()).forEach(collector::accept);
tokensProvider.computeTokens(e.getText()).stream()
.flatMap(td -> e.toJavaRanges(td.range()).stream().map(r -> new SemanticTokenData(r,
td.type(), td.modifiers())))
.forEach(collector::accept);
}
return super.visit(node);
}

View File

@@ -10,8 +10,6 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.cron;
import static org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.extractEmbeddedExpression;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MemberValuePair;
@@ -19,13 +17,14 @@ import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.TextBlock;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedExpression;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLangAstUtils;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLanguageSnippet;
public class JdtCronVisitorUtils {
static final String SCHEDULED_SIMPLE_NAME = "Scheduled";
public static EmbeddedExpression extractCron(NormalAnnotation node) {
public static EmbeddedLanguageSnippet extractCron(NormalAnnotation node) {
if (node.getTypeName() != null) {
String fqn = node.getTypeName().getFullyQualifiedName();
if (SCHEDULED_SIMPLE_NAME.equals(fqn) || Annotations.SCHEDULED.equals(fqn)) {
@@ -36,7 +35,7 @@ public class JdtCronVisitorUtils {
MemberValuePair pair = (MemberValuePair) value;
String name = pair.getName().getFullyQualifiedName();
if (name != null && "cron".equals(name) && isCronExpression(pair.getValue())) {
return extractEmbeddedExpression(pair.getValue());
return EmbeddedLangAstUtils.extractEmbeddedExpression(pair.getValue());
}
}
}

View File

@@ -57,14 +57,14 @@ public class DataQueryParameterDefinitionProvider implements IJavaDefinitionProv
Collector<SemanticTokenData> collector = new Collector<>();
a.accept(semanticTokensProvider.getTokensComputer(project, doc, cu, collector));
for (SemanticTokenData t : collector.get()) {
if ("parameter".equals(t.type()) && t.start() <= offset && offset <= t.end()) {
if ("parameter".equals(t.type()) && t.range().getOffset() <= offset && offset <= t.range().getEnd()) {
try {
String parameterDescriptor = doc.get(t.start(), t.end() - t.start());
String parameterDescriptor = doc.get(t.range().getOffset(), t.range().getLength());
SimpleName paramName = JdtQueryDocHighlightsProvider.findParameter(m, parameterDescriptor);
if (paramName != null) {
LocationLink link = new LocationLink();
link.setTargetUri(docId.getUri());
link.setOriginSelectionRange(doc.toRange(t.start(), t.end() - t.start()));
link.setOriginSelectionRange(doc.toRange(t.range().getOffset(), t.range().getLength()));
link.setTargetSelectionRange(doc.toRange(paramName.getStartPosition(), paramName.getLength()));
link.setTargetRange(link.getTargetSelectionRange());
return List.of(link);

View File

@@ -32,6 +32,7 @@ import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.springframework.ide.vscode.boot.java.embadded.lang.AntlrUtils;
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokensDataProvider;
@@ -75,7 +76,7 @@ public class HqlSemanticTokens implements SemanticTokensDataProvider {
}
@Override
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
public List<SemanticTokenData> computeTokens(String text) {
HqlLexer lexer = new HqlLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
HqlParser parser = new HqlParser(antlrTokens);
@@ -109,7 +110,7 @@ public class HqlSemanticTokens implements SemanticTokensDataProvider {
case HqlParser.WS:
break;
case HqlParser.SPEL:
tokens.addAll(JpqlSemanticTokens.computeTokensFromSpelNode(node, initialOffset, optSpelTokens));
tokens.addAll(JpqlSemanticTokens.computeTokensFromSpelNode(node, 0, optSpelTokens));
break;
default:
if (HqlParser.WS < type && type <= HqlParser.YEAR) {
@@ -132,7 +133,7 @@ public class HqlSemanticTokens implements SemanticTokensDataProvider {
@Override
public void exitInstantiationTarget(InstantiationTargetContext ctx) {
int offset = initialOffset + ctx.getStart().getStartIndex();
int offset = ctx.getStart().getStartIndex();
int length = ctx.getText().length();
tokens.add(new SemanticTokenData(offset, offset + length , "method", new String[0]));
AntlrUtils.getAllLeafs(ctx).forEach(semantics::remove);
@@ -189,8 +190,8 @@ public class HqlSemanticTokens implements SemanticTokensDataProvider {
parser.ql_statement();
semantics.entrySet().stream()
.map(e -> new SemanticTokenData(e.getKey().getStartIndex() + initialOffset,
e.getKey().getStartIndex() + e.getKey().getText().length() + initialOffset, e.getValue(),
.map(e -> new SemanticTokenData(e.getKey().getStartIndex(),
e.getKey().getStartIndex() + e.getKey().getText().length(), e.getValue(),
new String[0]))
.forEach(tokens::add);

View File

@@ -75,12 +75,12 @@ public class JdtDataQueriesInlayHintsProvider implements JdtInlayHintsProvider {
}
private void processQuery(IJavaProject project, TextDocument doc, Collector<InlayHint> collector, MethodDeclaration m, EmbeddedQueryExpression q) {
List<SemanticTokenData> semanticTokens = semanticTokensProvider.computeSemanticTokens(project, q.query().text(), q.query().offset(), q.isNative());
List<SemanticTokenData> semanticTokens = semanticTokensProvider.computeSemanticTokens(project, q.query(), q.isNative());
SemanticTokenData previousToken = null;
for (SemanticTokenData t : semanticTokens) {
if (isValidParameterOrdinalInputParameterToken(doc, t, previousToken)) {
try {
int number = Integer.parseInt(doc.get(t.start(), t.end() - t.start()));
int number = Integer.parseInt(doc.get(t.range().getOffset(), t.range().getLength()));
if (number > 0 && number <= m.parameters().size()) {
Object param = m.parameters().get(number - 1);
if (param instanceof SingleVariableDeclaration svd) {
@@ -90,7 +90,7 @@ public class JdtDataQueriesInlayHintsProvider implements JdtInlayHintsProvider {
hint.setLabel(Either.forLeft(paramName));
hint.setPaddingLeft(true);
hint.setPaddingRight(true);
hint.setPosition(doc.toPosition(firstNonSkippedChar(doc, t.end(), c -> '%' != c)));
hint.setPosition(doc.toPosition(firstNonSkippedChar(doc, t.range().getEnd(), c -> '%' != c)));
collector.accept(hint);
}
@@ -111,7 +111,7 @@ public class JdtDataQueriesInlayHintsProvider implements JdtInlayHintsProvider {
private static boolean isValidParameterOrdinalInputParameterToken(TextDocument doc, SemanticTokenData token, SemanticTokenData previous) {
if ("parameter".equals(token.type()) && previous != null && "operator".equals(previous.type())) {
try {
return "?".equals(doc.get(previous.start(), previous.end() - previous.start()));
return "?".equals(doc.get(previous.range().getOffset(), previous.range().getLength()));
} catch (BadLocationException e) {
// ignore
}

View File

@@ -25,6 +25,7 @@ import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.springframework.ide.vscode.boot.java.JdtSemanticTokensProvider;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedQueryExpression;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLanguageSnippet;
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
@@ -68,7 +69,7 @@ public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProv
public boolean visit(NormalAnnotation a) {
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(a);
if (q != null) {
computeSemanticTokens(jp, q.query().text(), q.query().offset(), q.isNative()).forEach(tokensData::accept);
computeSemanticTokens(jp, q.query(), q.isNative()).forEach(tokensData::accept);
}
return super.visit(a);
}
@@ -77,7 +78,7 @@ public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProv
public boolean visit(SingleMemberAnnotation a) {
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(a);
if (q != null) {
computeSemanticTokens(jp, q.query().text(), q.query().offset(), q.isNative()).forEach(tokensData::accept);
computeSemanticTokens(jp, q.query(), q.isNative()).forEach(tokensData::accept);
}
return super.visit(a);
}
@@ -86,17 +87,22 @@ public class JdtDataQuerySemanticTokensProvider implements JdtSemanticTokensProv
public boolean visit(MethodInvocation node) {
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
if (q != null) {
computeSemanticTokens(jp, q.query().text(), q.query().offset(), q.isNative()).forEach(tokensData::accept);
computeSemanticTokens(jp, q.query(), q.isNative()).forEach(tokensData::accept);
}
return super.visit(node);
}
};
}
public List<SemanticTokenData> computeSemanticTokens(IJavaProject jp, String query, int offset, boolean isNative) {
SemanticTokensDataProvider provider = isNative ? getSqlSemanticTokensProvider(jp) : (SpringProjectUtil.hasDependencyStartingWith(jp, "hibernate-core", null) ? hqlProvider : jpqlProvider);
public List<SemanticTokenData> computeSemanticTokens(IJavaProject jp, EmbeddedLanguageSnippet s, boolean isNative) {
SemanticTokensDataProvider provider = isNative ? getSqlSemanticTokensProvider(jp)
: (SpringProjectUtil.hasDependencyStartingWith(jp, "hibernate-core", null) ? hqlProvider
: jpqlProvider);
if (provider != null) {
return provider.computeTokens(query, offset);
return provider.computeTokens(s.getText()).stream()
.flatMap(td -> s.toJavaRanges(td.range()).stream().map(r -> new SemanticTokenData(r,
td.type(), td.modifiers())))
.toList();
}
return Collections.emptyList();
}

View File

@@ -54,9 +54,9 @@ public class JdtQueryDocHighlightsProvider implements JdtAstDocHighlightsProvide
Collector<SemanticTokenData> collector = new Collector<>();
a.accept(semanticTokensProvider.getTokensComputer(project, doc, cu, collector));
for (SemanticTokenData t : collector.get()) {
if ("parameter".equals(t.type()) && t.start() <= offset && offset <= t.end()) {
if ("parameter".equals(t.type()) && t.range().getStart() <= offset && offset <= t.range().getEnd()) {
try {
String parameterDescriptor = doc.get(t.start(), t.end() - t.start());
String parameterDescriptor = doc.get(t.range().getOffset(), t.range().getLength());
SimpleName paramName = findParameter(m, parameterDescriptor);
if (paramName != null) {
DocumentHighlight highlight = new DocumentHighlight();

View File

@@ -18,24 +18,21 @@ import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.TextBlock;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLangAstUtils;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLanguageSnippet;
public class JdtQueryVisitorUtils {
private static final String QUERY = "Query";
private static final String NAMED_QUERY = "NamedQuery";
public record EmbeddedExpression(Expression expression, String text, int offset) {};
public record EmbeddedQueryExpression(EmbeddedExpression query, boolean isNative) {};
public record EmbeddedQueryExpression(EmbeddedLanguageSnippet query, boolean isNative) {};
public static EmbeddedQueryExpression extractQueryExpression(SingleMemberAnnotation a) {
if (isQueryAnnotation(a)) {
EmbeddedExpression expression = extractEmbeddedExpression(a.getValue());
EmbeddedLanguageSnippet expression = EmbeddedLangAstUtils.extractEmbeddedExpression(a.getValue());
return expression == null ? null : new EmbeddedQueryExpression(expression, false);
}
return null;
@@ -83,7 +80,7 @@ public class JdtQueryVisitorUtils {
}
}
if (queryExpression != null) {
EmbeddedExpression e = extractEmbeddedExpression(queryExpression);
EmbeddedLanguageSnippet e = EmbeddedLangAstUtils.extractEmbeddedExpression(queryExpression);
if (e != null) {
return new EmbeddedQueryExpression(e, isNative);
}
@@ -96,7 +93,7 @@ public class JdtQueryVisitorUtils {
IMethodBinding methodBinding = m.resolveMethodBinding();
if ("jakarta.persistence.EntityManager".equals(methodBinding.getDeclaringClass().getQualifiedName())) {
if (methodBinding.getParameterTypes().length <= 2 && "java.lang.String".equals(methodBinding.getParameterTypes()[0].getQualifiedName())) {
EmbeddedExpression expression = extractEmbeddedExpression(queryExpr);
EmbeddedLanguageSnippet expression = EmbeddedLangAstUtils.extractEmbeddedExpression(queryExpr);
return expression == null ? null : new EmbeddedQueryExpression(expression, false);
}
}
@@ -104,22 +101,6 @@ public class JdtQueryVisitorUtils {
return null;
}
public static EmbeddedExpression extractEmbeddedExpression(Expression valueExp) {
String text = null;
int offset = 0;
if (valueExp instanceof StringLiteral sl) {
text = sl.getEscapedValue();
text = text.substring(1, text.length() - 1);
offset = sl.getStartPosition() + 1; // +1 to skip over opening "
} else if (valueExp instanceof TextBlock tb) {
text = tb.getEscapedValue();
text = text.substring(3, text.length() - 3);
offset = tb.getStartPosition() + 3; // +3 to skip over opening """
}
return text == null ? null : new EmbeddedExpression(valueExp, text, offset);
}
static boolean isQueryAnnotation(Annotation a) {
if (Annotations.DATA_QUERY.equals(a.getTypeName().getFullyQualifiedName()) || QUERY.equals(a.getTypeName().getFullyQualifiedName())) {
ITypeBinding type = a.resolveTypeBinding();

View File

@@ -35,6 +35,7 @@ import org.antlr.v4.runtime.tree.TerminalNode;
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
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.text.Region;
import org.springframework.ide.vscode.parser.jpql.JpqlBaseListener;
import org.springframework.ide.vscode.parser.jpql.JpqlLexer;
import org.springframework.ide.vscode.parser.jpql.JpqlParser;
@@ -77,7 +78,7 @@ public class JpqlSemanticTokens implements SemanticTokensDataProvider {
}
@Override
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
public List<SemanticTokenData> computeTokens(String text) {
JpqlLexer lexer = new JpqlLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
JpqlParser parser = new JpqlParser(antlrTokens);
@@ -114,7 +115,7 @@ public class JpqlSemanticTokens implements SemanticTokensDataProvider {
case JpqlParser.WS:
break;
case JpqlParser.SPEL:
tokens.addAll(computeTokensFromSpelNode(node, initialOffset, optSpelTokens));
tokens.addAll(computeTokensFromSpelNode(node, 0, optSpelTokens));
break;
default:
if (JpqlParser.WS < type && type <= JpqlParser.WHERE) {
@@ -201,8 +202,8 @@ public class JpqlSemanticTokens implements SemanticTokensDataProvider {
parser.ql_statement();
semantics.entrySet().stream()
.map(e -> new SemanticTokenData(e.getKey().getStartIndex() + initialOffset,
e.getKey().getStartIndex() + e.getKey().getText().length() + initialOffset, e.getValue(),
.map(e -> new SemanticTokenData(e.getKey().getStartIndex(),
e.getKey().getStartIndex() + e.getKey().getText().length(), e.getValue(),
new String[0]))
.forEach(tokens::add);
@@ -222,10 +223,14 @@ public class JpqlSemanticTokens implements SemanticTokensDataProvider {
spelTokens.add(new SemanticTokenData(startPosition, spelStartPosition, "operator", new String[0]));
// SPEL contents
optSpelTokens.ifPresentOrElse(
spelTokenProvider -> spelTokens
.addAll(spelTokenProvider.computeTokens(node.getText().substring(2, node.getText().length() - 1), spelStartPosition)),
() -> spelTokens.add(new SemanticTokenData(spelStartPosition, spelEndPosition, "string", new String[0])));
spelTokenProvider -> spelTokens.addAll(spelTokenProvider
.computeTokens(node.getText().substring(2, node.getText().length() - 1)).stream()
.map(td -> new SemanticTokenData(new Region(td.range().getOffset() + spelStartPosition, td.range().getLength()),
td.type(), td.modifiers()))
.toList()),
() -> spelTokens
.add(new SemanticTokenData(spelStartPosition, spelEndPosition, "string", new String[0])));
// '}' operator
spelTokens.add(new SemanticTokenData(spelEndPosition, endPosition, "operator", new String[0]));
return spelTokens;

View File

@@ -33,6 +33,7 @@ import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.springframework.ide.vscode.boot.java.embadded.lang.AntlrUtils;
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokensDataProvider;
@@ -72,7 +73,7 @@ public class MySqlSemanticTokens implements SemanticTokensDataProvider {
}
@Override
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
public List<SemanticTokenData> computeTokens(String text) {
MySqlLexer lexer = new MySqlLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(antlrTokens);
@@ -90,7 +91,7 @@ public class MySqlSemanticTokens implements SemanticTokensDataProvider {
int type = node.getSymbol().getType();
switch (type) {
case MySqlParser.SPEL:
tokens.addAll(JpqlSemanticTokens.computeTokensFromSpelNode(node, initialOffset, optSpelTokens));
tokens.addAll(JpqlSemanticTokens.computeTokensFromSpelNode(node, 0, optSpelTokens));
break;
case MySqlParser.ID:
semantics.put(node.getSymbol(), "variable");
@@ -255,17 +256,17 @@ public class MySqlSemanticTokens implements SemanticTokensDataProvider {
if (e.getKey().getType() == MySqlLexer.DOT_ID) {
return Stream.of(
// the prefix '.' is an operator
new SemanticTokenData(startIndex + initialOffset,
startIndex + 1 + initialOffset, "operator",
new SemanticTokenData(startIndex,
startIndex + 1, "operator",
new String[0]),
// the rest whatever it was meant to be initially
new SemanticTokenData(startIndex + 1 + initialOffset,
startIndex + e.getKey().getText().length() + initialOffset, e.getValue(),
new SemanticTokenData(startIndex + 1,
startIndex + e.getKey().getText().length(), e.getValue(),
new String[0])
);
} else {
return Stream.of(new SemanticTokenData(startIndex + initialOffset,
startIndex + e.getKey().getText().length() + initialOffset, e.getValue(),
return Stream.of(new SemanticTokenData(startIndex,
startIndex + e.getKey().getText().length(), e.getValue(),
new String[0]));
}
})

View File

@@ -17,6 +17,7 @@ import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFin
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.util.text.Region;
import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser;
import org.springframework.ide.vscode.java.properties.parser.ParseResults;
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.KeyValuePair;
@@ -45,7 +46,7 @@ public class NamedQueryPropertiesReconcileEngine implements IReconcileEngine {
ParseResults parseResults = parser.parse(doc.get());
for (KeyValuePair pair : parseResults.ast.getPropertyValuePairs()) {
Value value = pair.getValue();
reconciler.reconcile(value.decode(), value.getOffset(), problemCollector);
reconciler.reconcile(value.decode(), r -> new Region(r.getOffset() + value.getOffset(), r.getLength()), problemCollector);
}
} finally {
problemCollector.endCollecting();

View File

@@ -32,6 +32,7 @@ import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.springframework.ide.vscode.boot.java.embadded.lang.AntlrUtils;
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokensDataProvider;
@@ -73,7 +74,7 @@ public class PostgreSqlSemanticTokens implements SemanticTokensDataProvider {
}
@Override
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
public List<SemanticTokenData> computeTokens(String text) {
PostgreSqlLexer lexer = new PostgreSqlLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
PostgreSqlParser parser = new PostgreSqlParser(antlrTokens);
@@ -109,7 +110,7 @@ public class PostgreSqlSemanticTokens implements SemanticTokensDataProvider {
} else if (type >= PostgreSqlLexer.LineComment && type <= PostgreSqlLexer.UnterminatedBlockComment) {
semantics.put(token, "comment");
} else if (type == PostgreSqlLexer.SPEL) {
tokens.addAll(JpqlSemanticTokens.computeTokensFromSpelNode(node, initialOffset, optSpelTokens));
tokens.addAll(JpqlSemanticTokens.computeTokensFromSpelNode(node, 0, optSpelTokens));
}
}
@@ -181,8 +182,8 @@ public class PostgreSqlSemanticTokens implements SemanticTokensDataProvider {
parser.root();
semantics.entrySet().stream()
.map(e -> new SemanticTokenData(e.getKey().getStartIndex() + initialOffset,
e.getKey().getStartIndex() + e.getKey().getText().length() + initialOffset, e.getValue(),
.map(e -> new SemanticTokenData(e.getKey().getStartIndex(),
e.getKey().getStartIndex() + e.getKey().getText().length(), e.getValue(),
new String[0]))
.forEach(tokens::add);

View File

@@ -17,13 +17,11 @@ import java.util.Optional;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.TextBlock;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.JdtQueryVisitorUtils.EmbeddedQueryExpression;
import org.springframework.ide.vscode.boot.java.embadded.lang.AntlrReconcilerWithSpel;
import org.springframework.ide.vscode.boot.java.handlers.Reconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.RequiredCompleteAstException;
@@ -63,7 +61,7 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
if (q != null) {
Optional<Reconciler> reconcilerOpt = q.isNative() ? getSqlReconciler(project) : Optional.of(getQueryReconciler(project));
reconcilerOpt.ifPresent(r -> r.reconcile(q.query().text(), q.query().offset(), problemCollector));
reconcilerOpt.ifPresent(r -> r.reconcile(q.query().getText(), q.query()::toSingleJavaRange, problemCollector));
}
return super.visit(node);
}
@@ -72,7 +70,7 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
public boolean visit(SingleMemberAnnotation node) {
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
if (q != null) {
getQueryReconciler(project).reconcile(q.query().text(), q.query().offset(), problemCollector);
getQueryReconciler(project).reconcile(q.query().getText(), q.query()::toSingleJavaRange, problemCollector);
}
return super.visit(node);
}
@@ -81,7 +79,7 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
public boolean visit(MethodInvocation node) {
EmbeddedQueryExpression q = JdtQueryVisitorUtils.extractQueryExpression(node);
if (q != null) {
getQueryReconciler(project).reconcile(q.query().text(), q.query().offset(), problemCollector);
getQueryReconciler(project).reconcile(q.query().getText(), q.query()::toSingleJavaRange, problemCollector);
}
return super.visit(node);
}
@@ -96,23 +94,23 @@ public class QueryJdtAstReconciler implements JdtAstReconciler {
return SpringProjectUtil.hasDependencyStartingWith(project, "hibernate-core", null) ? hqlReconciler : jpqlReconciler;
}
public static void reconcileExpression(Reconciler reconciler, Expression valueExp, IProblemCollector problemCollector) {
String query = null;
int offset = 0;
if (valueExp instanceof StringLiteral sl) {
query = sl.getEscapedValue();
query = query.substring(1, query.length() - 1);
offset = sl.getStartPosition() + 1; // +1 to skip over opening "
} else if (valueExp instanceof TextBlock tb) {
query = tb.getEscapedValue();
query = query.substring(3, query.length() - 3);
offset = tb.getStartPosition() + 3; // +3 to skip over opening """
}
if (query != null) {
reconciler.reconcile(query, offset, problemCollector);
}
}
// public static void reconcileExpression(Reconciler reconciler, Expression valueExp, IProblemCollector problemCollector) {
// String query = null;
// int offset = 0;
// if (valueExp instanceof StringLiteral sl) {
// query = sl.getEscapedValue();
// query = query.substring(1, query.length() - 1);
// offset = sl.getStartPosition() + 1; // +1 to skip over opening "
// } else if (valueExp instanceof TextBlock tb) {
// query = tb.getEscapedValue();
// query = query.substring(3, query.length() - 3);
// offset = tb.getStartPosition() + 3; // +3 to skip over opening """
// }
//
// if (query != null) {
// reconciler.reconcile(query, offset, problemCollector);
// }
// }
@Override
public boolean isApplicable(IJavaProject project) {

View File

@@ -27,6 +27,7 @@ import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.Sem
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.util.text.LanguageId;
import org.springframework.ide.vscode.commons.util.text.Region;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser;
import org.springframework.ide.vscode.java.properties.parser.ParseResults;
@@ -76,7 +77,9 @@ public class QueryPropertiesSemanticTokensHandler implements SemanticTokensHandl
for (PropertiesAst.KeyValuePair node : result.ast.getPropertyValuePairs()) {
Value value = node.getValue();
if (value != null) {
data.addAll(tokensProvider.computeTokens(value.decode(), value.getOffset()));
tokensProvider.computeTokens(value.decode()).stream()
.map(td -> new SemanticTokenData(new Region(td.range().getOffset() + value.getOffset(), td.range().getLength()), td.type(), td.modifiers()))
.forEach(data::add);
}
}
return data;

View File

@@ -8,10 +8,11 @@
* Contributors:
* Broadcom, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
package org.springframework.ide.vscode.boot.java.embadded.lang;
import java.util.BitSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import org.antlr.v4.runtime.ANTLRErrorListener;
import org.antlr.v4.runtime.CharStream;
@@ -33,6 +34,8 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemC
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
import org.springframework.ide.vscode.commons.util.text.linetracker.DefaultLineTracker;
public class AntlrReconciler implements Reconciler {
@@ -57,7 +60,7 @@ public class AntlrReconciler implements Reconciler {
this.problemType = problemType;
}
protected Parser createParser(String text, int startPosition, IProblemCollector problemCollector) throws Exception {
protected Parser createParser(String text, Function<IRegion, IRegion> mapping, IProblemCollector problemCollector) throws Exception {
Lexer lexer = lexerClass.getDeclaredConstructor(CharStream.class).newInstance(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
Parser parser = parserClass.getDeclaredConstructor(TokenStream.class).newInstance(antlrTokens);
@@ -93,7 +96,8 @@ public class AntlrReconciler implements Reconciler {
log.error("", e1);
}
}
problemCollector.accept(new ReconcileProblemImpl(problemType, String.format("%s: %s", prefix, msg), startPosition + offset, length));
IRegion problemRegion = mapping.apply(new Region(offset, length));
problemCollector.accept(new ReconcileProblemImpl(problemType, String.format("%s: %s", prefix, msg), problemRegion.getOffset(), problemRegion.getLength()));
}
@Override
@@ -121,9 +125,9 @@ public class AntlrReconciler implements Reconciler {
}
@Override
public void reconcile(String text, int startPosition, IProblemCollector problemCollector) {
public void reconcile(String text, Function<IRegion, IRegion> mapping, IProblemCollector problemCollector) {
try {
Parser parser = createParser(text, startPosition, problemCollector);
Parser parser = createParser(text, mapping, problemCollector);
parserClass.getDeclaredMethod(parseMethod).invoke(parser);
} catch (Throwable t) {
log.error("", t);

View File

@@ -8,9 +8,10 @@
* Contributors:
* Broadcom, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
package org.springframework.ide.vscode.boot.java.embadded.lang;
import java.util.Optional;
import java.util.function.Function;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.Parser;
@@ -21,6 +22,8 @@ import org.antlr.v4.runtime.tree.TerminalNode;
import org.springframework.ide.vscode.boot.java.spel.SpelReconciler;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
public class AntlrReconcilerWithSpel extends AntlrReconciler {
@@ -35,15 +38,15 @@ public class AntlrReconcilerWithSpel extends AntlrReconciler {
}
@Override
protected Parser createParser(String text, int startPosition, IProblemCollector problemCollector) throws Exception {
Parser parser = super.createParser(text, startPosition, problemCollector);
protected Parser createParser(String text, Function<IRegion, IRegion> mapping, IProblemCollector problemCollector) throws Exception {
Parser parser = super.createParser(text, mapping, problemCollector);
// Reconcile embedded SPEL
spelReconciler.ifPresent(r -> parser.addParseListener(new ParseTreeListener() {
private void processTerminal(TerminalNode node) {
if (node.getSymbol().getType() == spelTokenType) {
AntlrReconcilerWithSpel.reconcileEmbeddedSpelNode(node, startPosition, r, problemCollector);
AntlrReconcilerWithSpel.reconcileEmbeddedSpelNode(node, mapping, r, problemCollector);
}
}
@@ -70,10 +73,9 @@ public class AntlrReconcilerWithSpel extends AntlrReconciler {
return parser;
}
private static void reconcileEmbeddedSpelNode(TerminalNode node, int initialOffset, SpelReconciler spelReconciler, IProblemCollector problemCollector) {
int startPosition = initialOffset + node.getSymbol().getStartIndex();
private static void reconcileEmbeddedSpelNode(TerminalNode node, Function<IRegion, IRegion> mapping, SpelReconciler spelReconciler, IProblemCollector problemCollector) {
String spelContent = node.getSymbol().getText().substring(2, node.getSymbol().getText().length() - 1);
spelReconciler.reconcile(spelContent, startPosition, problemCollector);
spelReconciler.reconcile(spelContent, r -> new Region(r.getOffset() + node.getSymbol().getStartIndex(), r.getLength())/*i -> mapping.apply(i + node.getSymbol().getStartIndex())*/, problemCollector);
}
}

View File

@@ -8,7 +8,7 @@
* Contributors:
* Broadcom, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data.jpa.queries;
package org.springframework.ide.vscode.boot.java.embadded.lang;
import java.util.stream.Stream;

View File

@@ -0,0 +1,92 @@
/*******************************************************************************
* 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.embadded.lang;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
public class CompositeEmbeddedLanguageSnippet implements EmbeddedLanguageSnippet {
private TreeMap<Region, EmbeddedLanguageSnippet> snippetParts;
private String text;
public CompositeEmbeddedLanguageSnippet(Collection<EmbeddedLanguageSnippet> snippets) {
snippetParts = new TreeMap<>(new Comparator<IRegion>() {
@Override
public int compare(IRegion o1, IRegion o2) {
return o1.getOffset() - o2.getOffset();
}
});
StringBuilder sb = new StringBuilder();
int offset = 0;
for (EmbeddedLanguageSnippet s : snippets) {
String t = s.getText();
sb.append(t);
snippetParts.putIfAbsent(new Region(offset, t.length()), s);
offset += t.length();
}
this.text = sb.toString();
}
@Override
public List<IRegion> toJavaRanges(IRegion range) {
List<IRegion> javaRegions = new ArrayList<>();
Entry<Region, EmbeddedLanguageSnippet> startEntry = snippetParts.floorEntry(new Region(range.getStart(), 0));
Entry<Region, EmbeddedLanguageSnippet> endEntry = snippetParts.floorEntry(new Region(range.getEnd(), 0));
if (startEntry.getKey().equals(endEntry.getKey())) {
// The Range is within the same snippet piece
javaRegions.addAll(startEntry.getValue().toJavaRanges(new Region(range.getOffset() - startEntry.getKey().getOffset(), range.getLength())));
} else {
// The range spans a number of snippets
// starting snippet - part of it should be included
int offset = range.getOffset() - startEntry.getKey().getOffset();
int length = startEntry.getKey().getLength() - offset;
if (length > 0) {
javaRegions.addAll(startEntry.getValue().toJavaRanges(new Region(offset, length)));
}
// snippet parts entirely in the request range - entire snippet range is included
for (Entry<Region, EmbeddedLanguageSnippet> e : snippetParts.subMap(startEntry.getKey(), false, endEntry.getKey(), false).entrySet()) {
javaRegions.addAll(e.getValue().toJavaRanges(new Region(0, e.getKey().getLength())));
}
// ending snippet - part of it should be included
offset = 0;
length = range.getEnd() - endEntry.getKey().getOffset();
if (length > 0) {
javaRegions.addAll(endEntry.getValue().toJavaRanges(new Region(offset, length)));
}
}
return javaRegions;
}
@Override
public int toJavaOffset(int offset) {
Entry<Region, EmbeddedLanguageSnippet> entry = snippetParts.floorEntry(new Region(offset, 0));
return entry.getValue().toJavaOffset(offset - entry.getKey().getOffset());
}
@Override
public String getText() {
return text;
}
}

View File

@@ -0,0 +1,57 @@
/*******************************************************************************
* 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.embadded.lang;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.TextBlock;
public class EmbeddedLangAstUtils {
public static EmbeddedLanguageSnippet extractEmbeddedExpression(Expression valueExp) {
if (valueExp instanceof StringLiteral sl) {
return new StringLiteralLanguageSnippet(sl);
} else if (valueExp instanceof TextBlock tb) {
return new TextBlockLanguageSnippet(tb);
} else if (valueExp instanceof InfixExpression ie && ie.getOperator() == InfixExpression.Operator.PLUS) {
EmbeddedLanguageSnippet leftSnippet = extractEmbeddedExpression(ie.getLeftOperand());
List<EmbeddedLanguageSnippet> snippets = new ArrayList<>(2 + ie.extendedOperands().size());
if (leftSnippet == null) {
return null;
} else {
snippets.add(leftSnippet);
}
EmbeddedLanguageSnippet rightSnippet = extractEmbeddedExpression(ie.getRightOperand());
if (rightSnippet == null) {
return null;
} else {
snippets.add(rightSnippet);
}
for (Object o : ie.extendedOperands()) {
if (o instanceof Expression exp) {
EmbeddedLanguageSnippet s = extractEmbeddedExpression(exp);
if (s == null) {
return null;
} else {
snippets.add(s);
}
}
}
return new CompositeEmbeddedLanguageSnippet(snippets);
}
return null;
}
}

View File

@@ -0,0 +1,37 @@
/*******************************************************************************
* 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.embadded.lang;
import java.util.List;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
public interface EmbeddedLanguageSnippet {
List<IRegion> toJavaRanges(IRegion range);
default IRegion toSingleJavaRange(IRegion range) {
List<IRegion> ranges = toJavaRanges(range);
int start = ranges.get(0).getOffset();
int end = ranges.get(ranges.size() - 1).getEnd();
return new Region(start, end - start);
}
int toJavaOffset(int offset);
String getText();
default IRegion getTotalRange() {
return toSingleJavaRange(new Region(0, getText().length()));
}
}

View File

@@ -0,0 +1,45 @@
/*******************************************************************************
* 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.embadded.lang;
import java.util.List;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
public class EmbeddedLanguageSnippetWithPrefixAndSuffix implements EmbeddedLanguageSnippet {
private final EmbeddedLanguageSnippet snippet;
private final int start;
private final int end;
public EmbeddedLanguageSnippetWithPrefixAndSuffix(EmbeddedLanguageSnippet snippet, int start, int end) {
this.snippet = snippet;
this.start = start;
this.end = end;
}
@Override
public String getText() {
return snippet.getText().substring(start, end);
}
@Override
public List<IRegion> toJavaRanges(IRegion range) {
return snippet.toJavaRanges(new Region(range.getOffset() + start, range.getLength()));
}
@Override
public int toJavaOffset(int offset) {
return snippet.toJavaOffset(offset + start);
}
}

View File

@@ -0,0 +1,100 @@
/*******************************************************************************
* 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.embadded.lang;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
public class StringLiteralLanguageSnippet implements EmbeddedLanguageSnippet {
final private int literalOffset;
final private String escapedValue;
final private String literalValue;
private transient int startOffset;
/*
* Each region represents a tuple where:
* - offset is the position in the snippet text.
* - length is the number of chars symbol at that location takes in the escaped snippet text
*/
private transient List<Region> specialRegions;
public StringLiteralLanguageSnippet(StringLiteral literal) {
this(literal.getEscapedValue(), literal.getLiteralValue(), literal.getStartPosition());
}
public StringLiteralLanguageSnippet(String escapedValue, String literalValue, int literalOffset) {
this.escapedValue = escapedValue;
this.literalValue = literalValue;
this.literalOffset = literalOffset;
}
@Override
public int toJavaOffset(int offset) {
if (specialRegions == null) {
specialRegions = createMappings();
}
int mappedOffset = literalOffset + startOffset + offset;
for (Region r : specialRegions) {
if (offset > r.getStart()) {
// length - 1 because 1 is added implicitly from '+ offset' above. Length of char escaped or not is >= 1
mappedOffset += (r.getLength() - 1);
} else {
break;
}
}
return mappedOffset;
}
@Override
public List<IRegion> toJavaRanges(IRegion range) {
int start = toJavaOffset(range.getStart());
int end = toJavaOffset(range.getEnd());
return List.of(new Region(start, end - start));
}
@Override
public String getText() {
return literalValue;
}
private List<Region> createMappings() {
List<Region> regions = new ArrayList<>();
if (literalValue.length() > 0) {
int current = 1; // skip over opening "
startOffset = current;
boolean escaping = false;
// <= to include the next char after the end of the literal actual value
for (int i = 0; i <= literalValue.length();) {
if (escaping) {
regions.add(new Region(i, 2));
i++;
current++;
escaping = false;
} else {
if (escapedValue.charAt(current) == '\\') {
escaping = escapedValue.charAt(current) == '\\';
current++;
} else {
i++;
current++;
}
}
}
}
return regions;
}
}

View File

@@ -0,0 +1,96 @@
/*******************************************************************************
* 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.embadded.lang;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.core.dom.TextBlock;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
public class TextBlockLanguageSnippet implements EmbeddedLanguageSnippet {
final private int literalOffset;
final private String escapedValue;
final private String literalValue;
private transient int startOffset;
private transient List<Region> specialRegions;
public TextBlockLanguageSnippet(TextBlock block) {
this(block.getEscapedValue(), block.getLiteralValue(), block.getStartPosition());
}
public TextBlockLanguageSnippet(String escapedValue, String literalValue, int literalOffset) {
this.escapedValue = escapedValue;
this.literalValue = literalValue;
this.literalOffset = literalOffset;
}
@Override
public List<IRegion> toJavaRanges(IRegion range) {
int start = toJavaOffset(range.getStart());
int end = toJavaOffset(range.getEnd());
return List.of(new Region(start, end - start));
}
@Override
public int toJavaOffset(int offset) {
if (specialRegions == null) {
specialRegions = createMappings();
}
int mappedOffset = literalOffset + startOffset + offset;
for (Region r : specialRegions) {
if (offset > r.getStart()) {
// length - 1 because 1 is added implicitly from '+ offset' above. Length of char escaped or not is >= 1
mappedOffset += (r.getLength() - 1);
}
}
return mappedOffset;
}
@Override
public String getText() {
return literalValue;
}
private List<Region> createMappings() {
List<Region> regions = new ArrayList<>();
if (literalValue.length() > 0) {
int current = 3; // skip over opening """
for (; current < escapedValue.length() && escapedValue.charAt(current) != '\\' && escapedValue.charAt(current) != literalValue.charAt(0); current++) {
}
startOffset = current;
boolean escaping = escapedValue.charAt(current) == '\\';
// <= to include the next char after the end of the literal actual value
for (int i = 0; i <= literalValue.length();) {
if (escaping) {
regions.add(new Region(i, 2));
i++;
current++;
escaping = false;
} else {
if (escapedValue.charAt(current) == '\\') {
escaping = escapedValue.charAt(current) == '\\';
current++;
} else {
i++;
current++;
}
}
}
}
return regions;
}
}

View File

@@ -38,8 +38,8 @@ import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLanguageSnippet;
import org.springframework.ide.vscode.boot.java.spel.AnnotationParamSpelExtractor;
import org.springframework.ide.vscode.boot.java.spel.AnnotationParamSpelExtractor.Snippet;
import org.springframework.ide.vscode.boot.java.spel.SpelSemanticTokens;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
@@ -47,6 +47,7 @@ import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFin
import org.springframework.ide.vscode.commons.languageserver.semantic.tokens.SemanticTokenData;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.collect.ImmutableList;
@@ -99,7 +100,7 @@ public class CopilotCodeLensProvider implements CodeLensProvider {
public boolean visit(SingleMemberAnnotation node) {
Arrays.stream(spelExtractors).map(e -> e.getSpelRegion(node)).filter(o -> o.isPresent())
.map(o -> o.get()).forEach(snippet -> {
String additionalContext = parseSpelAndFetchContext(cu, snippet.text());
String additionalContext = parseSpelAndFetchContext(cu, snippet.getText());
provideCodeLensForSpelExpression(cancelToken, node, document, snippet, additionalContext, resultAccumulator);
});
@@ -119,7 +120,7 @@ public class CopilotCodeLensProvider implements CodeLensProvider {
Arrays.stream(spelExtractors).map(e -> e.getSpelRegion(node)).filter(o -> o.isPresent())
.map(o -> o.get()).forEach(snippet -> {
String additionalContext = parseSpelAndFetchContext(cu, snippet.text());
String additionalContext = parseSpelAndFetchContext(cu, snippet.getText());
provideCodeLensForSpelExpression(cancelToken, node, document, snippet, additionalContext, resultAccumulator);
});
@@ -154,7 +155,7 @@ public class CopilotCodeLensProvider implements CodeLensProvider {
}
protected void provideCodeLensForSpelExpression(CancelChecker cancelToken, Annotation node, TextDocument document,
Snippet snippet, String additionalContext, List<CodeLens> resultAccumulator) {
EmbeddedLanguageSnippet snippet, String additionalContext, List<CodeLens> resultAccumulator) {
cancelToken.checkCanceled();
if (snippet != null) {
@@ -167,12 +168,13 @@ public class CopilotCodeLensProvider implements CodeLensProvider {
""",additionalContext) : "";
CodeLens codeLens = new CodeLens();
codeLens.setRange(document.toRange(snippet.offset(), snippet.text().length()));
IRegion totalRange = snippet.getTotalRange();
codeLens.setRange(document.toRange(totalRange.getStart(), totalRange.getLength()));
Command cmd = new Command();
cmd.setTitle(QueryType.SPEL.getTitle());
cmd.setCommand(CMD);
cmd.setArguments(ImmutableList.of(QueryType.SPEL.getPrompt() + snippet.text() + "\n\n" + context));
cmd.setArguments(ImmutableList.of(QueryType.SPEL.getPrompt() + snippet.getText() + "\n\n" + context));
codeLens.setCommand(cmd);
resultAccumulator.add(codeLens);
@@ -235,7 +237,7 @@ public class CopilotCodeLensProvider implements CodeLensProvider {
private List<SemanticTokenData> parseSpelExpression(String spelText) {
try {
return spelSemanticTokens.computeTokens(spelText, 0);
return spelSemanticTokens.computeTokens(spelText);
} catch (Exception e) {
logger.error("Error computing tokens: " + e.getMessage());
return Collections.emptyList();
@@ -244,7 +246,7 @@ public class CopilotCodeLensProvider implements CodeLensProvider {
private static Set<String> extractMethodNames(List<SemanticTokenData> tokens, String spelText) {
return tokens.stream().filter(token -> "method".equals(token.type()))
.map(token -> spelText.substring(token.start(), token.end())).collect(Collectors.toSet());
.map(token -> spelText.substring(token.range().getStart(), token.range().getEnd())).collect(Collectors.toSet());
}
private List<String> collectMethodContexts(Set<String> methodNames, CompilationUnit cu) {

View File

@@ -10,13 +10,16 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.handlers;
import java.util.function.Function;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.util.text.IRegion;
/**
* @author Martin Lippert
*/
public interface Reconciler {
void reconcile(String value, int startPosition, IProblemCollector problemCollector);
void reconcile(String value, Function<IRegion, IRegion> offsetMapper, IProblemCollector problemCollector);
}

View File

@@ -10,12 +10,16 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.handlers;
import java.util.function.Function;
import org.springframework.expression.ParseException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.ide.vscode.boot.java.SpelProblemType;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
import org.springframework.util.SystemPropertyUtils;
/**
@@ -34,7 +38,7 @@ public class SpelExpressionReconciler implements Reconciler {
}
@Override
public void reconcile(String spelExpression, int startPosition, IProblemCollector problemCollector) {
public void reconcile(String spelExpression, Function<IRegion, IRegion> mapper, IProblemCollector problemCollector) {
if (!this.spelExpressionValidationEnabled) {
return;
}
@@ -47,17 +51,11 @@ public class SpelExpressionReconciler implements Reconciler {
catch (ParseException e) {
String message = e.getSimpleMessage();
int position = e.getPosition();
createProblem(spelExpression, message, startPosition, position, problemCollector);
IRegion r = mapper.apply(new Region(0, position));
ReconcileProblem problem = new ReconcileProblemImpl(SpelProblemType.JAVA_SPEL_EXPRESSION_SYNTAX, message, r.getOffset(), r.getLength());
problemCollector.accept(problem);
}
}
}
private void createProblem(String spelExpression, String message, int startPosition, int position, IProblemCollector problemCollector) {
int start = startPosition + position;
int length = spelExpression.length() - position;
ReconcileProblem problem = new ReconcileProblemImpl(SpelProblemType.JAVA_SPEL_EXPRESSION_SYNTAX, message, start, length);
problemCollector.accept(problem);
}
}

View File

@@ -17,9 +17,11 @@ import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLangAstUtils;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLanguageSnippet;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLanguageSnippetWithPrefixAndSuffix;
public final class AnnotationParamSpelExtractor {
@@ -87,7 +89,7 @@ public final class AnnotationParamSpelExtractor {
this.prefixSuffixes = List.of(new PrefixSuffix(paramValuePrefix, paramValueSuffx), new PrefixSuffix("", ""));
}
public Optional<Snippet> getSpelRegion(NormalAnnotation a) {
public Optional<EmbeddedLanguageSnippet> getSpelRegion(NormalAnnotation a) {
if (paramName == null) {
return Optional.empty();
}
@@ -104,8 +106,9 @@ public final class AnnotationParamSpelExtractor {
String name = pair.getName().getFullyQualifiedName();
if (name != null && name.equals(paramName)) {
Expression expression = pair.getValue();
if (expression instanceof StringLiteral) {
return fromStringLiteral((StringLiteral) expression);
EmbeddedLanguageSnippet embeddedSnippet = EmbeddedLangAstUtils.extractEmbeddedExpression(expression);
if (embeddedSnippet != null) {
return fromEmbeddedSnippet(embeddedSnippet);
}
}
}
@@ -114,7 +117,7 @@ public final class AnnotationParamSpelExtractor {
return Optional.empty();
}
public Optional<Snippet> getSpelRegion(SingleMemberAnnotation a) {
public Optional<EmbeddedLanguageSnippet> getSpelRegion(SingleMemberAnnotation a) {
if (this.paramName != null) {
return Optional.empty();
}
@@ -124,26 +127,24 @@ public final class AnnotationParamSpelExtractor {
}
Expression valueExp = a.getValue();
if (valueExp instanceof StringLiteral) {
return fromStringLiteral((StringLiteral) valueExp);
}
EmbeddedLanguageSnippet embeddedSnippet = EmbeddedLangAstUtils.extractEmbeddedExpression(valueExp);
if (embeddedSnippet != null) {
return fromEmbeddedSnippet(embeddedSnippet);
}
return Optional.empty();
}
private Optional<Snippet> fromStringLiteral(StringLiteral valueExp) {
String value = valueExp.getEscapedValue();
value = value.substring(1, value.length() - 1);
if (value != null) {
private Optional<EmbeddedLanguageSnippet> fromEmbeddedSnippet(EmbeddedLanguageSnippet embeddedSnippet) {
String value = embeddedSnippet.getText();
if (value != null && !value.isBlank()) {
for (PrefixSuffix ps : prefixSuffixes) {
int startIdx = value.indexOf(ps.prefix);
if (startIdx >= 0) {
int endIdx = value.lastIndexOf(ps.suffix);
if (endIdx >= 0) {
String spelText = value.substring(startIdx + ps.prefix.length(), endIdx);
int offset = valueExp.getStartPosition() + startIdx + ps.prefix.length() + 1;
return Optional.of(new Snippet(spelText, offset));
return Optional.of(new EmbeddedLanguageSnippetWithPrefixAndSuffix(embeddedSnippet, startIdx + ps.prefix.length(), endIdx));
}
}
}

View File

@@ -53,7 +53,7 @@ public class JdtSpelReconciler implements JdtAstReconciler {
.map(e -> e.getSpelRegion(node))
.filter(o -> o.isPresent())
.map(o -> o.get())
.forEach(snippet -> spelReconciler.reconcile(snippet.text(), snippet.offset(), problemCollector));
.forEach(snippet -> spelReconciler.reconcile(snippet.getText(), snippet::toSingleJavaRange, problemCollector));
return super.visit(node);
}
@@ -63,7 +63,7 @@ public class JdtSpelReconciler implements JdtAstReconciler {
.map(e -> e.getSpelRegion(node))
.filter(o -> o.isPresent())
.map(o -> o.get())
.forEach(snippet -> spelReconciler.reconcile(snippet.text(), snippet.offset(), problemCollector));
.forEach(snippet -> spelReconciler.reconcile(snippet.getText(), snippet::toSingleJavaRange, problemCollector));
return super.visit(node);
}

View File

@@ -60,7 +60,10 @@ public class JdtSpelSemanticTokensProvider implements JdtSemanticTokensProvider
.map(e -> e.getSpelRegion(node))
.filter(o -> o.isPresent())
.map(o -> o.get())
.forEach(snippet -> tokensProvider.computeTokens(snippet.text(), snippet.offset()).forEach(collector::accept));
.forEach(snippet -> tokensProvider.computeTokens(snippet.getText()).stream()
.flatMap(td -> snippet.toJavaRanges(td.range()).stream().map(r -> new SemanticTokenData(r,
td.type(), td.modifiers())))
.forEach(collector::accept));
return super.visit(node);
}
@@ -70,7 +73,10 @@ public class JdtSpelSemanticTokensProvider implements JdtSemanticTokensProvider
.map(e -> e.getSpelRegion(node))
.filter(o -> o.isPresent())
.map(o -> o.get())
.forEach(snippet -> tokensProvider.computeTokens(snippet.text(), snippet.offset()).forEach(collector::accept));
.forEach(snippet -> tokensProvider.computeTokens(snippet.getText()).stream()
.flatMap(td -> snippet.toJavaRanges(td.range()).stream().map(r -> new SemanticTokenData(r,
td.type(), td.modifiers())))
.forEach(collector::accept));
return super.visit(node);
}

View File

@@ -32,7 +32,7 @@ import org.antlr.v4.runtime.atn.ATNConfigSet;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.AntlrUtils;
import org.springframework.ide.vscode.boot.java.embadded.lang.AntlrUtils;
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.placeholder.PropertyPlaceHolderBaseListener;
@@ -56,7 +56,7 @@ public class PropertyPlaceHolderSemanticTokens implements SemanticTokensDataProv
}
@Override
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
public List<SemanticTokenData> computeTokens(String text) {
PropertyPlaceHolderLexer lexer = new PropertyPlaceHolderLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
PropertyPlaceHolderParser parser = new PropertyPlaceHolderParser(antlrTokens);
@@ -74,7 +74,7 @@ public class PropertyPlaceHolderSemanticTokens implements SemanticTokensDataProv
public void exitKey(KeyContext ctx) {
// Remove all children nodes semantics as they will be replaced by a single token spanning multiple AST nodes
AntlrUtils.getAllLeafs(ctx).forEach(semantics::remove);
int start = ctx.getStart().getStartIndex() + initialOffset;
int start = ctx.getStart().getStartIndex();
int end = start + ctx.getText().length();
tokens.add(new SemanticTokenData(start, end, "property", new String[0]));
}
@@ -87,7 +87,7 @@ public class PropertyPlaceHolderSemanticTokens implements SemanticTokensDataProv
}
if (ctx.value() != null) {
ValueContext valueCtx = ctx.value();
int start = valueCtx.getStart().getStartIndex() + initialOffset;
int start = valueCtx.getStart().getStartIndex();
int end = start + valueCtx.getText().length();
tokens.add(new SemanticTokenData(start, end, "string", new String[0]));
}
@@ -148,8 +148,8 @@ public class PropertyPlaceHolderSemanticTokens implements SemanticTokensDataProv
parser.start();
tokens.addAll(semantics.entrySet().stream()
.map(e -> new SemanticTokenData(e.getKey().getStartIndex() + initialOffset,
e.getKey().getStartIndex() + e.getKey().getText().length() + initialOffset, e.getValue(),
.map(e -> new SemanticTokenData(e.getKey().getStartIndex(),
e.getKey().getStartIndex() + e.getKey().getText().length(), e.getValue(),
new String[0]))
.collect(Collectors.toList()));

View File

@@ -52,15 +52,17 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.IJavaDefinitionProvider;
import org.springframework.ide.vscode.boot.java.embadded.lang.EmbeddedLanguageSnippet;
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
import org.springframework.ide.vscode.boot.java.spel.AnnotationParamSpelExtractor.Snippet;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.util.text.Region;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import org.springframework.ide.vscode.parser.spel.SpelLexer;
import org.springframework.ide.vscode.parser.spel.SpelParser;
@@ -116,11 +118,11 @@ public class SpelDefinitionProvider implements IJavaDefinitionProvider {
return e.getSpelRegion((SingleMemberAnnotation) a);
else if (a instanceof NormalAnnotation)
return e.getSpelRegion((NormalAnnotation) a);
return Optional.<Snippet>empty();
return Optional.<EmbeddedLanguageSnippet>empty();
}).filter(o -> o.isPresent()).map(o -> o.get())
.filter(snippet -> {
int tokenEndIndex = snippet.offset() + snippet.text().length();
return snippet.offset() <= (offset) && (offset) <= tokenEndIndex;
IRegion snippetRegion = snippet.getTotalRange();
return snippetRegion.getStart() <= (offset) && (offset) <= snippetRegion.getEnd();
}).forEach(snippet -> {
List<TokenData> beanReferenceTokens = computeTokens(snippet, offset);
if (beanReferenceTokens != null && beanReferenceTokens.size() > 0) {
@@ -213,8 +215,8 @@ public class SpelDefinitionProvider implements IJavaDefinitionProvider {
}).collect(Collectors.toList());
}
private List<TokenData> computeTokens(Snippet snippet, int offset) {
SpelLexer lexer = new SpelLexer(CharStreams.fromString(snippet.text()));
private List<TokenData> computeTokens(EmbeddedLanguageSnippet snippet, int offset) {
SpelLexer lexer = new SpelLexer(CharStreams.fromString(snippet.getText()));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
SpelParser parser = new SpelParser(antlrTokens);
@@ -236,8 +238,9 @@ public class SpelDefinitionProvider implements IJavaDefinitionProvider {
}
private void addTokenData(Token sym, int offset) {
int start = sym.getStartIndex() + snippet.offset();
int end = sym.getStartIndex() + sym.getText().length() + snippet.offset();
List<IRegion> symbolRegions = snippet.toJavaRanges(new Region(sym.getStartIndex(), sym.getText().length()));
int start = symbolRegions.get(0).getStart();
int end = symbolRegions.get(symbolRegions.size() - 1).getEnd();
if (isOffsetWithinToken(start, end, offset)) {
beanReferenceTokens.add(new TokenData(sym.getText(), start, end));
}
@@ -254,10 +257,10 @@ public class SpelDefinitionProvider implements IJavaDefinitionProvider {
return beanReferenceTokens;
}
private Optional<Tuple2<String, String>> parseAndExtractMethodClassPairFromSpel(Snippet snippet, int offset) {
private Optional<Tuple2<String, String>> parseAndExtractMethodClassPairFromSpel(EmbeddedLanguageSnippet snippet, int offset) {
SpelExpressionParser parser = new SpelExpressionParser();
try {
org.springframework.expression.Expression expression = parser.parseExpression(snippet.text());
org.springframework.expression.Expression expression = parser.parseExpression(snippet.getText());
SpelExpression spelExpressionAST = (SpelExpression) expression;
SpelNode rootNode = spelExpressionAST.getAST();
@@ -269,8 +272,8 @@ public class SpelDefinitionProvider implements IJavaDefinitionProvider {
}
private Optional<Tuple2<String, String>> extractMethodClassPairFromSpelNodes(SpelNode node, SpelNode parent,
Snippet snippet, int offset) {
if (node instanceof MethodReference && checkOffsetInMethodName(node, snippet.offset(), offset)) {
EmbeddedLanguageSnippet snippet, int offset) {
if (node instanceof MethodReference && checkOffsetInMethodName(node, snippet.toJavaOffset(0), offset)) {
MethodReference methodRef = (MethodReference) node;
String methodName = methodRef.getName();
String className = extractClassNameFromParent(parent);

View File

@@ -10,14 +10,18 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.spel;
import java.util.function.Function;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.springframework.ide.vscode.boot.java.SpelProblemType;
import org.springframework.ide.vscode.boot.java.data.jpa.queries.AntlrReconciler;
import org.springframework.ide.vscode.boot.java.embadded.lang.AntlrReconciler;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.util.text.IRegion;
import org.springframework.ide.vscode.commons.util.text.Region;
import org.springframework.ide.vscode.parser.placeholder.PropertyPlaceHolderLexer;
import org.springframework.ide.vscode.parser.placeholder.PropertyPlaceHolderParser;
import org.springframework.ide.vscode.parser.spel.SpelLexer;
@@ -40,25 +44,27 @@ public class SpelReconciler extends AntlrReconciler {
}
@Override
public void reconcile(String text, int startPosition, IProblemCollector problemCollector) {
public void reconcile(String text, Function<IRegion, IRegion> mapper, IProblemCollector problemCollector) {
if (!enabled) {
return;
}
super.reconcile(text, startPosition, problemCollector);
super.reconcile(text, mapper, problemCollector);
}
@Override
protected Parser createParser(String text, int startPosition, IProblemCollector problemCollector) throws Exception {
Parser parser = super.createParser(text, startPosition, problemCollector);
protected Parser createParser(String text, Function<IRegion, IRegion> mapper, IProblemCollector problemCollector) throws Exception {
Parser parser = super.createParser(text, mapper, problemCollector);
// Reconcile embedded SPEL
parser.addParseListener(new ParseTreeListener() {
private void processTerminal(TerminalNode node) {
if (node.getSymbol().getType() == SpelLexer.PROPERTY_PLACE_HOLDER) {
int placeHolderStartPosition = startPosition + node.getSymbol().getStartIndex() + 2;
String content = node.getSymbol().getText().substring(2, node.getSymbol().getText().length() - 1);
propertyHolderReconciler.reconcile(content, placeHolderStartPosition, problemCollector);
propertyHolderReconciler.reconcile(content, r -> {
IRegion n = mapper.apply(r);
return new Region(n.getOffset() + node.getSymbol().getStartIndex() + 2, n.getLength());
}, problemCollector);
}
}

View File

@@ -10,7 +10,66 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.spel;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.*;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.AND;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.ASSIGN;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.BACKTICK;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.BEAN_REF;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.COLON;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.COMMA;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.DEC;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.DIV;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.DOT;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.DOUBLE_QUOTED_STRING;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.ELVIS;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.EQ;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.EQ_KEYWORD;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.FACTORY_BEAN_REF;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.FALSE;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.GE;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.GE_KEYWORD;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.GT;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.GT_KEYWORD;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.HASH;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.IDENTIFIER;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.INC;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.INTEGER_LITERAL;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.LCURLY;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.LE;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.LE_KEYWORD;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.LPAREN;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.LSQUARE;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.LT;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.LT_KEYWORD;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.MATCHES;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.MINUS;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.MOD;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.NE;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.NEW;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.NE_KEYWORD;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.NOT;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.NULL;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.OR;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.PLUS;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.POWER;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.PROJECT;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.PROPERTY_PLACE_HOLDER;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.QMARK;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.RCURLY;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.REAL_LITERAL;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.RPAREN;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.RSQUARE;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.SAFE_NAVI;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.SELECT;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.SELECT_FIRST;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.SELECT_LAST;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.SEMICOLON;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.SINGLE_QUOTED_STRING;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.STAR;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.STRING_LITERAL;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.SYMBOLIC_AND;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.SYMBOLIC_OR;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.T;
import static org.springframework.ide.vscode.parser.spel.SpelLexer.TRUE;
import java.util.ArrayList;
import java.util.BitSet;
@@ -38,6 +97,7 @@ 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.commons.util.text.Region;
import org.springframework.ide.vscode.parser.spel.SpelLexer;
import org.springframework.ide.vscode.parser.spel.SpelParser;
import org.springframework.ide.vscode.parser.spel.SpelParser.BeanReferenceContext;
@@ -71,7 +131,7 @@ public class SpelSemanticTokens implements SemanticTokensDataProvider {
}
@Override
public List<SemanticTokenData> computeTokens(String text, int initialOffset) {
public List<SemanticTokenData> computeTokens(String text) {
SpelLexer lexer = new SpelLexer(CharStreams.fromString(text));
CommonTokenStream antlrTokens = new CommonTokenStream(lexer);
SpelParser parser = new SpelParser(antlrTokens);
@@ -158,7 +218,7 @@ public class SpelSemanticTokens implements SemanticTokensDataProvider {
semantics.put(node.getSymbol(), "string");
break;
case PROPERTY_PLACE_HOLDER:
tokens.addAll(computeTokensFromPropertyPlaceHolderNode(node, initialOffset));
tokens.addAll(computeTokensFromPropertyPlaceHolderNode(node));
break;
}
}
@@ -215,7 +275,7 @@ public class SpelSemanticTokens implements SemanticTokensDataProvider {
semantics.remove(ctx.INTEGER_LITERAL().getSymbol());
semantics.remove(ctx.RSQUARE().getSymbol());
int start = ctx.getStart().getStartIndex() + initialOffset;
int start = ctx.getStart().getStartIndex();
int end = start + ctx.getText().length();
tokens.add(new SemanticTokenData(start, end, "parameter", new String[0]));
}
@@ -260,8 +320,8 @@ public class SpelSemanticTokens implements SemanticTokensDataProvider {
parser.spelExpr();
tokens.addAll(semantics.entrySet().stream()
.map(e -> new SemanticTokenData(e.getKey().getStartIndex() + initialOffset,
e.getKey().getStartIndex() + e.getKey().getText().length() + initialOffset, e.getValue(),
.map(e -> new SemanticTokenData(e.getKey().getStartIndex(),
e.getKey().getStartIndex() + e.getKey().getText().length(), e.getValue(),
new String[0]))
.collect(Collectors.toList()));
@@ -270,18 +330,19 @@ public class SpelSemanticTokens implements SemanticTokensDataProvider {
return tokens;
}
private Collection<? extends SemanticTokenData> computeTokensFromPropertyPlaceHolderNode(TerminalNode node,
int initialOffset) {
private Collection<? extends SemanticTokenData> computeTokensFromPropertyPlaceHolderNode(TerminalNode node) {
List<SemanticTokenData> placeHolderTokens = new ArrayList<>();
int startPosition = initialOffset + node.getSymbol().getStartIndex();
int startPosition = node.getSymbol().getStartIndex();
int placeHolderStartPosition = startPosition + 2;
int endPosition = startPosition + node.getText().length();
int placeHolderEndPosition = endPosition - 1;
// '${' operator
placeHolderTokens.add(new SemanticTokenData(startPosition, placeHolderStartPosition, "operator", new String[0]));
// Property Place Holder contents
placeHolderTokens.addAll(propertyPlaceHolderSemanticTokens.computeTokens(node.getText().substring(2, node.getText().length() - 1), placeHolderStartPosition));
propertyPlaceHolderSemanticTokens.computeTokens(node.getText().substring(2, node.getText().length() - 1))
.stream().map(td -> new SemanticTokenData(new Region(td.range().getOffset() + placeHolderStartPosition, td.range().getLength()), td.type(), td.modifiers()))
.forEach(placeHolderTokens::add);
// '}' operator
placeHolderTokens.add(new SemanticTokenData(placeHolderEndPosition, endPosition, "operator", new String[0]));
return placeHolderTokens;

View File

@@ -17,6 +17,7 @@ import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lemminx.dom.DOMRange;
import org.springframework.ide.vscode.boot.java.handlers.Reconciler;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.util.text.Region;
/**
* @author mlippert
@@ -68,7 +69,7 @@ public class XMLElementReconciler {
if (value != null && value.startsWith(prefix) && value.endsWith(postfix)) {
String valueToReconcile = value.substring(prefix.length(), value.length() - postfix.length());
reconciler.reconcile(valueToReconcile, start + prefix.length() + 1, problemCollector);
reconciler.reconcile(valueToReconcile, r -> new Region(r.getOffset() + start + prefix.length() + 1, r.getLength()), problemCollector);
}
}

View File

@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -26,27 +27,27 @@ public class CronReconcilerTest {
@Test
void noProblems_1() {
reconciler.reconcile("0 0 0 L-3 * *", 0, collector);
reconciler.reconcile("0 0 0 L-3 * *", Function.identity(), collector);
assertEquals(0, problems.size());
}
@Test
void DayOfTheWeekProblems_1() {
reconciler.reconcile("0 0 0 8 * MAR-JUL", 0, collector);
reconciler.reconcile("0 0 0 8 * MAR-JUL", Function.identity(), collector);
assertEquals(1, problems.size());
assertReconcileProblem(problems.get(0), CronProblemType.FIELD, 10, 6);
}
@Test
void noProblems_3() {
reconciler.reconcile("MAR-JUL 0 0 8 * *", 0, collector);
reconciler.reconcile("MAR-JUL 0 0 8 * *", Function.identity(), collector);
assertEquals(1, problems.size());
assertReconcileProblem(problems.get(0), CronProblemType.FIELD, 0, 7);
}
@Test
void syntax_and_field_problems_1() {
reconciler.reconcile("0 0 0 8LW * MARCH-JUL", 0, collector);
reconciler.reconcile("0 0 0 8LW * MARCH-JUL", Function.identity(), collector);
assertEquals(3, problems.size());
assertReconcileProblem(problems.get(0), CronProblemType.SYNTAX, 7, 2);
assertReconcileProblem(problems.get(1), CronProblemType.SYNTAX, 12, 5);
@@ -55,14 +56,14 @@ public class CronReconcilerTest {
@Test
void syntax_problems_2() {
reconciler.reconcile("qq#3 0 Blah 1-88LW * JUL-MARCH", 0, collector);
reconciler.reconcile("qq#3 0 Blah 1-88LW * JUL-MARCH", Function.identity(), collector);
assertEquals(1, problems.size());
assertReconcileProblem(problems.get(0), CronProblemType.SYNTAX, 0, 2);
}
@Test
void syntax_problems_3() {
reconciler.reconcile("10/2. * * ? * MON-5", 0, collector);
reconciler.reconcile("10/2. * * ? * MON-5", Function.identity(), collector);
assertEquals(1, problems.size());
assertReconcileProblem(problems.get(0), CronProblemType.SYNTAX, 4, 0);
}

View File

@@ -31,7 +31,7 @@ public class CronSemanticTokensTest {
@Test
void topHoueEveryDayEveryWeek() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 * * * *", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 * * * *");
assertThat(tokens.size()).isEqualTo(6);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0]));
@@ -43,7 +43,7 @@ public class CronSemanticTokensTest {
@Test
void everyTenSeconds() {
List<SemanticTokenData> tokens = provider.computeTokens("*/10 * * * * *", 0);
List<SemanticTokenData> tokens = provider.computeTokens("*/10 * * * * *");
assertThat(tokens.size()).isEqualTo(8);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "operator", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(1, 2, "operator", new String[0]));
@@ -57,7 +57,7 @@ public class CronSemanticTokensTest {
@Test
void betweenEightAndTenEveryDay() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 8-10 * * *", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 8-10 * * *");
assertThat(tokens.size()).isEqualTo(8);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -71,7 +71,7 @@ public class CronSemanticTokensTest {
@Test
void everyDayBetweenSixAndSeven() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 6,19 * * *", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 6,19 * * *");
assertThat(tokens.size()).isEqualTo(8);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -85,7 +85,7 @@ public class CronSemanticTokensTest {
@Test
void everyHalfHourBetweenEightAndEleven() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0/30 8-10 * * *", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0/30 8-10 * * *");
assertThat(tokens.size()).isEqualTo(10);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -101,7 +101,7 @@ public class CronSemanticTokensTest {
@Test
void nineToFiveOnWeekdays() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 9-17 * * MON-FRI", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 9-17 * * MON-FRI");
assertThat(tokens.size()).isEqualTo(10);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -117,7 +117,7 @@ public class CronSemanticTokensTest {
@Test
void christmas() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 25 12 ?", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 25 12 ?");
assertThat(tokens.size()).isEqualTo(6);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -129,7 +129,7 @@ public class CronSemanticTokensTest {
@Test
void lastDayOfMonthAtMidnight() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 L * *", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 L * *");
assertThat(tokens.size()).isEqualTo(6);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -141,7 +141,7 @@ public class CronSemanticTokensTest {
@Test
void thirdToLasttDayOfMonthAtMidnight() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 L-3 * *", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 L-3 * *");
assertThat(tokens.size()).isEqualTo(8);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -155,7 +155,7 @@ public class CronSemanticTokensTest {
@Test
void firstWeekDayOfMonthAtMidnight() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 1W * *", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 1W * *");
assertThat(tokens.size()).isEqualTo(7);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -168,7 +168,7 @@ public class CronSemanticTokensTest {
@Test
void lastWeekDayOfMonthAtMidnight() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 LW * *", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 LW * *");
assertThat(tokens.size()).isEqualTo(6);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -180,7 +180,7 @@ public class CronSemanticTokensTest {
@Test
void lastFridayOfMonthAtMidnight() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 * * 5L", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 * * 5L");
assertThat(tokens.size()).isEqualTo(7);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -193,7 +193,7 @@ public class CronSemanticTokensTest {
@Test
void lastThursdayOfMonthAtMidnight() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 * * THUL", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 * * THUL");
assertThat(tokens.size()).isEqualTo(7);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -206,7 +206,7 @@ public class CronSemanticTokensTest {
@Test
void secondFridayOfMonthAtMidnight() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 ? * 5#2", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 ? * 5#2");
assertThat(tokens.size()).isEqualTo(8);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -220,7 +220,7 @@ public class CronSemanticTokensTest {
@Test
void firstMondayOfMonthAtMidnight() {
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 ? * MON#1", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 ? * MON#1");
assertThat(tokens.size()).isEqualTo(8);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -234,7 +234,7 @@ public class CronSemanticTokensTest {
@Test
void macro() {
List<SemanticTokenData> tokens = provider.computeTokens("@yearly", 0);
List<SemanticTokenData> tokens = provider.computeTokens("@yearly");
assertThat(tokens.size()).isEqualTo(1);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 7, "macro", new String[0])); // @yearly
}
@@ -242,7 +242,7 @@ public class CronSemanticTokensTest {
@Test
void errors_1() {
provider = new CronSemanticTokens();
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 8LW * Foo#bar", 0);
List<SemanticTokenData> tokens = provider.computeTokens("0 0 0 8LW * Foo#bar");
assertThat(tokens.size()).isEqualTo(9);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0])); // 0
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "number", new String[0])); // 0
@@ -258,7 +258,7 @@ public class CronSemanticTokensTest {
@Test
void errors_2() {
provider = new CronSemanticTokens();
List<SemanticTokenData> tokens = provider.computeTokens("qq#3 0 Blah 1-88LW * JUL-MARCH", 0);
List<SemanticTokenData> tokens = provider.computeTokens("qq#3 0 Blah 1-88LW * JUL-MARCH");
assertThat(tokens.size()).isEqualTo(13);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 2, "enum", new String[0])); // qq
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "operator", new String[0])); // #

View File

@@ -83,35 +83,35 @@ public class JdtCronSemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(117, 118, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(119, 120, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(121, 122, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(123, 124, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("?");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("?");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(125, 126, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("*");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("*");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(127, 128, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("5");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("5");
token = tokens.get(6);
assertThat(token).isEqualTo(new SemanticTokenData(128, 129, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("#");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("#");
token = tokens.get(7);
assertThat(token).isEqualTo(new SemanticTokenData(129, 130, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("2");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("2");
}
@@ -142,31 +142,31 @@ public class JdtCronSemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(117, 118, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(119, 120, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(121, 122, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(123, 124, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("*");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("*");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(125, 126, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("*");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("*");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(127, 130, "enum", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("THU");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("THU");
token = tokens.get(6);
assertThat(token).isEqualTo(new SemanticTokenData(130, 131, "method", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("L");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("L");
}
@@ -197,35 +197,35 @@ public class JdtCronSemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(117, 118, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(119, 120, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(121, 122, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(123, 124, "method", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("L");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("L");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(124, 125, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("-");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("-");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(125, 126, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("3");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("3");
token = tokens.get(6);
assertThat(token).isEqualTo(new SemanticTokenData(127, 128, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("*");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("*");
token = tokens.get(7);
assertThat(token).isEqualTo(new SemanticTokenData(129, 130, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("*");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("*");
}
@Test
@@ -255,39 +255,39 @@ public class JdtCronSemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(117, 118, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(119, 120, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(121, 122, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(123, 124, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("8");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("8");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(124, 126, "method", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("LW");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("LW");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(127, 128, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("*");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("*");
token = tokens.get(6);
assertThat(token).isEqualTo(new SemanticTokenData(129, 132, "enum", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("Foo");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("Foo");
token = tokens.get(7);
assertThat(token).isEqualTo(new SemanticTokenData(132, 133, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("#");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("#");
token = tokens.get(8);
assertThat(token).isEqualTo(new SemanticTokenData(133, 136, "enum", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("bar");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("bar");
}
@Test
@@ -317,55 +317,55 @@ public class JdtCronSemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(117, 119, "enum", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("qq");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("qq");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(119, 120, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("#");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("#");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(120, 121, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("3");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("3");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(122, 123, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("0");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("0");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(124, 128, "enum", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("Blah");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("Blah");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(129, 130, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("1");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("1");
token = tokens.get(6);
assertThat(token).isEqualTo(new SemanticTokenData(130, 131, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("-");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("-");
token = tokens.get(7);
assertThat(token).isEqualTo(new SemanticTokenData(131, 133, "number", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("88");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("88");
token = tokens.get(8);
assertThat(token).isEqualTo(new SemanticTokenData(133, 135, "method", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("LW");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("LW");
token = tokens.get(9);
assertThat(token).isEqualTo(new SemanticTokenData(136, 137, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("*");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("*");
token = tokens.get(10);
assertThat(token).isEqualTo(new SemanticTokenData(138, 141, "enum", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("JUL");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("JUL");
token = tokens.get(11);
assertThat(token).isEqualTo(new SemanticTokenData(141, 142, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("-");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("-");
token = tokens.get(12);
assertThat(token).isEqualTo(new SemanticTokenData(142, 147, "enum", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("MARCH");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("MARCH");
}
@Test

View File

@@ -32,7 +32,7 @@ public class HqlSemanticTokensTest {
@Test
void simpleQuery_1() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner");
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 12, "variable", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(13, 17, "keyword", new String[0]));
@@ -42,21 +42,9 @@ public class HqlSemanticTokensTest {
assertThat(tokens.size()).isEqualTo(5);
}
@Test
void initialOffset() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner", 3);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(3, 9, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(10, 15, "variable", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(16, 20, "keyword", new String[0]));
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(21, 26, "class", new String[0]));
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(27, 32, "variable", new String[0]));
assertThat(tokens.size()).isEqualTo(5);
}
@Test
void query_with_conflicting_groupby() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT g FROM Group g GROUP BY g.name", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT g FROM Group g GROUP BY g.name");
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]));
@@ -73,7 +61,7 @@ public class HqlSemanticTokensTest {
@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 DISTINCT owner FROM Owner owner left join owner.pets WHERE owner.lastName LIKE :lastName%");
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
@@ -99,7 +87,7 @@ public class HqlSemanticTokensTest {
@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);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:#{id}");
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
@@ -127,7 +115,7 @@ public class HqlSemanticTokensTest {
@Test
void query_with_SPEL_Tokens() {
provider = new HqlSemanticTokens(Optional.of(new SpelSemanticTokens()));
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:#{id}", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:#{id}");
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
@@ -155,7 +143,7 @@ public class HqlSemanticTokensTest {
@Test
void query_with_complex_SPEL_Tokens() {
provider = new HqlSemanticTokens(Optional.of(new SpelSemanticTokens()));
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:#{someBean.someProperty != null ? someBean.someProperty : 'default'}", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:#{someBean.someProperty != null ? someBean.someProperty : 'default'}");
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
@@ -193,7 +181,7 @@ public class HqlSemanticTokensTest {
@Test
void instatiotation_1() {
provider = new HqlSemanticTokens(Optional.of(new SpelSemanticTokens()));
List<SemanticTokenData> tokens = provider.computeTokens("SELECT new com.example.ls.issue.SampleTableSizePojo(t.schemaName, sum(t.tableSize) ) FROM MTables t GROUP BY t.schemaName ORDER BY sum(t.tableSize) DESC", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT new com.example.ls.issue.SampleTableSizePojo(t.schemaName, sum(t.tableSize) ) FROM MTables t GROUP BY t.schemaName ORDER BY sum(t.tableSize) DESC");
assertThat(tokens.size()).isEqualTo(32);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0])); // SELECT

View File

@@ -78,27 +78,27 @@ public class JdtDataQuerySemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(120, 126, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("SELECT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("SELECT");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(127, 135, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("DISTINCT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("DISTINCT");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(136, 141, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(142, 146, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("FROM");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("FROM");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(147, 152, "class", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("Owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("Owner");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(153, 158, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
}
@Test
@@ -126,27 +126,27 @@ public class JdtDataQuerySemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(125, 131, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("SELECT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("SELECT");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(132, 140, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("DISTINCT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("DISTINCT");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(141, 146, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(147, 151, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("FROM");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("FROM");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(152, 157, "class", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("Owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("Owner");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(158, 163, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
}
@Test
@@ -172,27 +172,27 @@ public class JdtDataQuerySemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(128, 134, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("SELECT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("SELECT");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(135, 143, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("DISTINCT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("DISTINCT");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(144, 149, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(150, 154, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("FROM");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("FROM");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(155, 160, "class", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("Owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("Owner");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(161, 166, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
}
@Test
@@ -219,27 +219,27 @@ public class JdtDataQuerySemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(176, 182, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("SELECT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("SELECT");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(183, 191, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("DISTINCT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("DISTINCT");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(192, 197, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(198, 202, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("FROM");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("FROM");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(203, 208, "class", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("Owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("Owner");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(209, 214, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
}
@Test
@@ -268,27 +268,27 @@ public class JdtDataQuerySemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(181, 187, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("SELECT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("SELECT");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(188, 196, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("DISTINCT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("DISTINCT");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(197, 202, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(203, 207, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("FROM");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("FROM");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(208, 213, "class", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("Owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("Owner");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(214, 219, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
}
@Test
@@ -313,47 +313,47 @@ public class JdtDataQuerySemanticTokensProviderTest {
List<SemanticTokenData> tokens = computeTokens(cu);
SemanticTokenData token = tokens.get(0);
assertThat(source.substring(token.start(), token.end())).isEqualTo("SELECT");
assertThat(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(".");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo(".");
assertThat(token).isEqualTo(new SemanticTokenData(157, 158, "operator", new String[0]));
token = tokens.get(8);
assertThat(source.substring(token.start(), token.end())).isEqualTo("status");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("status");
assertThat(token).isEqualTo(new SemanticTokenData(158, 164, "property", new String[0]));
token = tokens.get(9);
assertThat(source.substring(token.start(), token.end())).isEqualTo("=");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("=");
assertThat(token).isEqualTo(new SemanticTokenData(165, 166, "operator", new String[0]));
token = tokens.get(10);
assertThat(source.substring(token.start(), token.end())).isEqualTo("1");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("1");
assertThat(token).isEqualTo(new SemanticTokenData(167, 168, "number", new String[0]));
}
@@ -380,59 +380,59 @@ public class JdtDataQuerySemanticTokensProviderTest {
List<SemanticTokenData> tokens = computeTokens(cu);
SemanticTokenData token = tokens.get(0);
assertThat(source.substring(token.start(), token.end())).isEqualTo("SELECT");
assertThat(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(source.substring(token.getStart(), token.getEnd())).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(".");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo(".");
assertThat(token).isEqualTo(new SemanticTokenData(157, 158, "operator", new String[0]));
token = tokens.get(8);
assertThat(source.substring(token.start(), token.end())).isEqualTo("status");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("status");
assertThat(token).isEqualTo(new SemanticTokenData(158, 164, "property", new String[0]));
token = tokens.get(9);
assertThat(source.substring(token.start(), token.end())).isEqualTo("=");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("=");
assertThat(token).isEqualTo(new SemanticTokenData(165, 166, "operator", new String[0]));
token = tokens.get(10);
assertThat(source.substring(token.start(), token.end())).isEqualTo("?");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("?");
assertThat(token).isEqualTo(new SemanticTokenData(167, 168, "operator", new String[0]));
token = tokens.get(11);
assertThat(source.substring(token.start(), token.end())).isEqualTo("#{");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("#{");
assertThat(token).isEqualTo(new SemanticTokenData(168, 170, "operator", new String[0]));
token = tokens.get(12);
assertThat(source.substring(token.start(), token.end())).isEqualTo("status");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("status");
assertThat(token).isEqualTo(new SemanticTokenData(170, 176, "variable", new String[0]));
token = tokens.get(13);
assertThat(source.substring(token.start(), token.end())).isEqualTo("}");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("}");
assertThat(token).isEqualTo(new SemanticTokenData(176, 177, "operator", new String[0]));
}
@@ -457,27 +457,84 @@ public class JdtDataQuerySemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(101, 107, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("SELECT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("SELECT");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(108, 116, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("DISTINCT");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("DISTINCT");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(117, 122, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(123, 127, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("FROM");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("FROM");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(128, 133, "class", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("Owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("Owner");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(134, 139, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("owner");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("owner");
}
@Test
void nativeConcatenatedStringQuery() throws Exception {
String source = """
package my.package
import org.springframework.data.jpa.repository.Query;
public interface OwnerRepository {
@Query(value = "SELECT" +
" DIS" +
"TINCT" +
" test FROM Te" +
"st", nativeQuery = true)
void findByLastName();
}
""";
String uri = Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/OwnerRepository.java").toUri()
.toASCIIString();
CompilationUnit cu = CompilationUnitCache.parse2(source.toCharArray(), uri, "OwnerRepository.java", jp);
assertThat(cu).isNotNull();
List<SemanticTokenData> tokens = computeTokens(cu);
SemanticTokenData token = tokens.get(0);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("SELECT");
assertThat(token).isEqualTo(new SemanticTokenData(128, 134, "keyword", new String[0]));
token = tokens.get(1);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("DIS");
assertThat(token).isEqualTo(new SemanticTokenData(142, 145, "keyword", new String[0]));
token = tokens.get(2);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("TINCT");
assertThat(token).isEqualTo(new SemanticTokenData(152, 157, "keyword", new String[0]));
token = tokens.get(3);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("test");
assertThat(token).isEqualTo(new SemanticTokenData(165, 169, "variable", new String[0]));
token = tokens.get(4);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("FROM");
assertThat(token).isEqualTo(new SemanticTokenData(170, 174, "keyword", new String[0]));
token = tokens.get(5);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("Te");
assertThat(token).isEqualTo(new SemanticTokenData(175, 177, "variable", new String[0]));
token = tokens.get(6);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("st");
assertThat(token).isEqualTo(new SemanticTokenData(184, 186, "variable", new String[0]));
}
}

View File

@@ -32,7 +32,7 @@ public class JpqlSemanticTokensTest {
@Test
void simpleQuery_1() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner");
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 12, "variable", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(13, 17, "keyword", new String[0]));
@@ -42,21 +42,9 @@ public class JpqlSemanticTokensTest {
assertThat(tokens.size()).isEqualTo(5);
}
@Test
void initialOffset() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner", 3);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(3, 9, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(10, 15, "variable", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(16, 20, "keyword", new String[0]));
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(21, 26, "class", new String[0]));
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(27, 32, "variable", new String[0]));
assertThat(tokens.size()).isEqualTo(5);
}
@Test
void query_with_conflicting_groupby() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT g FROM G g GROUP BY g.name", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT g FROM G g GROUP BY g.name");
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
@@ -73,7 +61,7 @@ public class JpqlSemanticTokensTest {
@Test
void query_with_parameter() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT f from Student f LEFT JOIN f.classTbls s WHERE s.ClassName = :className", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT f from Student f LEFT JOIN f.classTbls s WHERE s.ClassName = :className");
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])); // f
@@ -99,7 +87,7 @@ public class JpqlSemanticTokensTest {
@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);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:#{id}");
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
@@ -127,7 +115,7 @@ public class JpqlSemanticTokensTest {
@Test
void query_with_SPEL_Tokens() {
provider = new JpqlSemanticTokens(Optional.of(new SpelSemanticTokens()));
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:#{id}", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:#{id}");
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

View File

@@ -32,7 +32,7 @@ public class MySqlSemanticTokensTest {
@Test
void simple() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * from Document document WHERE document.id=fn_module_candidates()", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * from Document document WHERE document.id=fn_module_candidates()");
assertThat(tokens.size()).isEqualTo(13);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 8, "operator", new String[0]));
@@ -52,7 +52,7 @@ public class MySqlSemanticTokensTest {
@Test
void parametersInQuery() {
List<SemanticTokenData> tokens = provider.computeTokens("DELETE FROM component_document WHERE item_document_id = :itemDocumentId", 0);
List<SemanticTokenData> tokens = provider.computeTokens("DELETE FROM component_document WHERE item_document_id = :itemDocumentId");
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 11, "keyword", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(12, 30, "variable", new String[0]));
@@ -67,7 +67,7 @@ public class MySqlSemanticTokensTest {
@Test
void spelInQuery() {
List<SemanticTokenData> tokens = provider.computeTokens("DELETE FROM component_document WHERE item_document_id = :#{someBean}", 0);
List<SemanticTokenData> tokens = provider.computeTokens("DELETE FROM component_document WHERE item_document_id = :#{someBean}");
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 11, "keyword", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(12, 30, "variable", new String[0]));
@@ -84,7 +84,7 @@ public class MySqlSemanticTokensTest {
@Test
void complexSpelInQuery() {
List<SemanticTokenData> tokens = provider.computeTokens("DELETE FROM component_document WHERE item_document_id = :#{someBean.someProperty != null ? someBean.someProperty : 'default'}", 0);
List<SemanticTokenData> tokens = provider.computeTokens("DELETE FROM component_document WHERE item_document_id = :#{someBean.someProperty != null ? someBean.someProperty : 'default'}");
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 11, "keyword", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(12, 30, "variable", new String[0]));

View File

@@ -32,7 +32,7 @@ public class PostgreSqlSemanticTokensTest {
@Test
void simple() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * from fn_module_candidates", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * from fn_module_candidates");
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 8, "operator", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(9, 13, "keyword", new String[0]));
@@ -51,7 +51,7 @@ public class PostgreSqlSemanticTokensTest {
WHERE document.project_id=?1
AND json_path_exists(document.content::jsonb, ('strict $.content.**.id ? (@ == "\\' || representation.targetobjectid || \\'")')::jsonpath)
)
""", 0);
""");
assertThat(tokens.size()).isEqualTo(43);
assertThat(tokens.get(10)).isEqualTo(new SemanticTokenData(74, 75, "parameter", new String[0])); // 1 from ?1
@@ -66,7 +66,7 @@ public class PostgreSqlSemanticTokensTest {
@Test
void spelInQuery() {
List<SemanticTokenData> tokens = provider.computeTokens("DELETE FROM component_document WHERE item_document_id = :#{someBean}", 0);
List<SemanticTokenData> tokens = provider.computeTokens("DELETE FROM component_document WHERE item_document_id = :#{someBean}");
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 11, "keyword", new String[0]));
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(12, 30, "variable", new String[0]));
@@ -83,7 +83,7 @@ public class PostgreSqlSemanticTokensTest {
@Test
void semiColonAtEnd() {
List<SemanticTokenData> tokens = provider.computeTokens(" select count(*) from anecdote where anecdote_id=:anecdote ; ", 0);
List<SemanticTokenData> tokens = provider.computeTokens(" select count(*) from anecdote where anecdote_id=:anecdote ; ");
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(1, 7, "keyword", new String[0])); // select
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(8, 13, "method", new String[0])); // count
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(13, 14, "operator", new String[0])); // (
@@ -103,7 +103,7 @@ public class PostgreSqlSemanticTokensTest {
@Test
void parameterInLimitClause_1() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * FROM cards ORDER BY random() LIMIT ?2", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * FROM cards ORDER BY random() LIMIT ?2");
assertThat(tokens.size()).isEqualTo(12);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
@@ -122,7 +122,7 @@ public class PostgreSqlSemanticTokensTest {
@Test
void parameterInLimitClause_2() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * FROM cards ORDER BY random() LIMIT ?2", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * FROM cards ORDER BY random() LIMIT ?2");
assertThat(tokens.size()).isEqualTo(12);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
@@ -141,7 +141,7 @@ public class PostgreSqlSemanticTokensTest {
@Test
void parameterInLimitClause_3() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * FROM cards ORDER BY random() LIMIT :#{qq}", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * FROM cards ORDER BY random() LIMIT :#{qq}");
assertThat(tokens.size()).isEqualTo(14);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
@@ -162,7 +162,7 @@ public class PostgreSqlSemanticTokensTest {
@Test
void parameterInLimitClause_4() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * FROM cards ORDER BY random() LIMIT :limit", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT * FROM cards ORDER BY random() LIMIT :limit");
assertThat(tokens.size()).isEqualTo(12);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
@@ -181,19 +181,19 @@ public class PostgreSqlSemanticTokensTest {
@Test
void notInInsideWhereClausePredicate() {
List<SemanticTokenData> tokens = provider.computeTokens("delete from SAMPLE_TABLE where id not in (select top 1 id from SAMPLE_TABLE order by TABLE_NAME desc)", 0);
List<SemanticTokenData> tokens = provider.computeTokens("delete from SAMPLE_TABLE where id not in (select top 1 id from SAMPLE_TABLE order by TABLE_NAME desc)");
assertThat(tokens.size()).isEqualTo(19);
}
@Test
void keywordAsIdentifier() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT SCHEMA_NAME, TABLE_NAME, VERSION from SAMPLE_TABLE", 0);
List<SemanticTokenData> tokens = provider.computeTokens("SELECT SCHEMA_NAME, TABLE_NAME, VERSION from SAMPLE_TABLE");
assertThat(tokens.size()).isEqualTo(8);
}
@Test
void topInSelectClause() {
List<SemanticTokenData> tokens = provider.computeTokens("select top 1 * from SAMPLE_TABLE where SCHEMA_NAME = ?1", 0);
List<SemanticTokenData> tokens = provider.computeTokens("select top 1 * from SAMPLE_TABLE where SCHEMA_NAME = ?1");
assertThat(tokens.size()).isEqualTo(11);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "keyword", new String[0]));
@@ -212,7 +212,7 @@ public class PostgreSqlSemanticTokensTest {
@Test
void over_clause_1() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;\n"
+ "", 0);
+ "");
assertThat(tokens.size()).isEqualTo(20);
}
@@ -222,21 +222,21 @@ public class PostgreSqlSemanticTokensTest {
SELECT depname, empno, salary,
rank() OVER (PARTITION BY depname ORDER BY salary DESC)
FROM empsalary;
""", 0);
""");
assertThat(tokens.size()).isEqualTo(23);
}
@Test
void over_clause_3() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT salary, sum(salary) OVER () FROM empsalary;"
+ "", 0);
+ "");
assertThat(tokens.size()).isEqualTo(13);
}
@Test
void over_clause_4() {
List<SemanticTokenData> tokens = provider.computeTokens("SELECT salary, sum(salary) OVER (ORDER BY salary) FROM empsalary;"
+ "", 0);
+ "");
assertThat(tokens.size()).isEqualTo(16);
}
@@ -250,7 +250,7 @@ public class PostgreSqlSemanticTokensTest {
FROM empsalary
) AS ss
WHERE pos < 3;
""", 0);
""");
assertThat(tokens.size()).isEqualTo(46);
}
@@ -260,7 +260,7 @@ public class PostgreSqlSemanticTokensTest {
SELECT sum(salary) OVER w, avg(salary) OVER w
FROM empsalary
WINDOW w AS (PARTITION BY depname ORDER BY salary DESC);
""", 0);
""");
assertThat(tokens.size()).isEqualTo(29);
}
@@ -282,7 +282,7 @@ public class PostgreSqlSemanticTokensTest {
(rn = 1 OR status = 10)
AND (scenario = 11 OR scenario = 8)
ORDER BY status DESC
""", 0);
""");
assertThat(tokens.size()).isEqualTo(74);
}
@@ -290,7 +290,7 @@ public class PostgreSqlSemanticTokensTest {
void collate_1() {
List<SemanticTokenData> tokens = provider.computeTokens("""
SELECT DISTINCT test COLLATE "numeric" FROM Test
""", 0);
""");
assertThat(tokens.size()).isEqualTo(7);
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])); // DISTICT
@@ -303,9 +303,24 @@ public class PostgreSqlSemanticTokensTest {
@Test
void collate_2() {
List<SemanticTokenData> tokens = provider.computeTokens("""
SELECT DISTINCT test COLLATE \"numeric\" FROM Test
""");
assertThat(tokens.size()).isEqualTo(7);
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])); // DISTICT
assertThat(tokens.get(2)).isEqualTo(new SemanticTokenData(16, 20, "variable", new String[0])); // test
assertThat(tokens.get(3)).isEqualTo(new SemanticTokenData(21, 28, "keyword", new String[0])); // COLLATE
assertThat(tokens.get(4)).isEqualTo(new SemanticTokenData(29, 38, "variable", new String[0])); // \"numeric\"
assertThat(tokens.get(5)).isEqualTo(new SemanticTokenData(39, 43, "keyword", new String[0])); // FROM
assertThat(tokens.get(6)).isEqualTo(new SemanticTokenData(44, 48, "variable", new String[0])); // Test
}
@Test
void collate_3() {
List<SemanticTokenData> tokens = provider.computeTokens("""
SELECT a COLLATE "de_DE" < b FROM test1
""", 0);
""");
assertThat(tokens.size()).isEqualTo(8);
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])); // a

View File

@@ -81,39 +81,39 @@ public class JdtSpelSemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(119, 122, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("new");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("new");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(123, 129, "method", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("String");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("String");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(129, 130, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("(");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("(");
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(130, 143, "string", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("'hello world'");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("'hello world'");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(143, 144, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo(")");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo(")");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(144, 145, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo(".");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo(".");
token = tokens.get(6);
assertThat(token).isEqualTo(new SemanticTokenData(145, 156, "method", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("toUpperCase");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("toUpperCase");
token = tokens.get(7);
assertThat(token).isEqualTo(new SemanticTokenData(156, 157, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("(");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("(");
token = tokens.get(8);
assertThat(token).isEqualTo(new SemanticTokenData(157, 158, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo(")");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo(")");
}
@@ -142,16 +142,16 @@ public class JdtSpelSemanticTokensProviderTest {
assertThat(tokens.size()).isEqualTo(3);
SemanticTokenData token = tokens.get(0);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("'invalid alphabetic string #$1'");
assertThat(token).isEqualTo(new SemanticTokenData(113, 144, "string", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("'invalid alphabetic string #$1'");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(145, 152, "keyword", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("matches");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("matches");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(153, 166, "string", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("'[a-zA-Z\\s]+'");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("'[a-zA-Z\\s]+'");
}
@@ -182,15 +182,108 @@ public class JdtSpelSemanticTokensProviderTest {
SemanticTokenData token = tokens.get(0);
assertThat(token).isEqualTo(new SemanticTokenData(121, 125, "variable", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("demo");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("demo");
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(125, 126, "operator", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo(".");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo(".");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(126, 130, "property", new String[0]));
assertThat(source.substring(token.start(), token.end())).isEqualTo("cron");
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("cron");
}
@Test
void concatenatedString() throws Exception {
String source = """
package my.package
import org.springframework.beans.factory.annotation.Value;
public class Owner {
@Value("#{'inval" + "id alphabetic s" + "tring #$1' mat" + "ches '[a-z" + "A-Z\\s]+' }")
String s;
}
""";
String uri = Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/OwnerRepository.java").toUri().toASCIIString();
CompilationUnit cu = CompilationUnitCache.parse2(source.toCharArray(), uri, "OwnerRepository.java", jp);
assertThat(cu).isNotNull();
List<SemanticTokenData> tokens = computeTokens(cu);
assertThat(tokens.size()).isEqualTo(7);
//id alphabetic string #$1'
SemanticTokenData token = tokens.get(0);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("'inval");
assertThat(token).isEqualTo(new SemanticTokenData(113, 119, "string", new String[0]));
token = tokens.get(1);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("id alphabetic s");
assertThat(token).isEqualTo(new SemanticTokenData(124, 139, "string", new String[0]));
token = tokens.get(2);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("tring #$1'");
assertThat(token).isEqualTo(new SemanticTokenData(144, 154, "string", new String[0]));
token = tokens.get(3);
assertThat(token).isEqualTo(new SemanticTokenData(155, 158, "keyword", new String[0]));
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("mat");
token = tokens.get(4);
assertThat(token).isEqualTo(new SemanticTokenData(163, 167, "keyword", new String[0]));
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("ches");
token = tokens.get(5);
assertThat(token).isEqualTo(new SemanticTokenData(168, 173, "string", new String[0]));
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("'[a-z");
token = tokens.get(6);
assertThat(token).isEqualTo(new SemanticTokenData(178, 186, "string", new String[0]));
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("A-Z\\s]+'");
}
@Test
void textBlock() throws Exception {
String source = """
package my.package
import org.springframework.beans.factory.annotation.Value;
public class Owner {
@Value(\"""
#{'invalid alphabetic string #$1' matches '[a-zA-Z\\s]+' }
\""")
String s;
}
""";
String uri = Paths.get(jp.getLocationUri()).resolve("src/main/resource/my/package/OwnerRepository.java").toUri().toASCIIString();
CompilationUnit cu = CompilationUnitCache.parse2(source.toCharArray(), uri, "OwnerRepository.java", jp);
assertThat(cu).isNotNull();
List<SemanticTokenData> tokens = computeTokens(cu);
assertThat(tokens.size()).isEqualTo(3);
SemanticTokenData token = tokens.get(0);
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("'invalid alphabetic string #$1'");
assertThat(token).isEqualTo(new SemanticTokenData(118, 149, "string", new String[0]));
token = tokens.get(1);
assertThat(token).isEqualTo(new SemanticTokenData(150, 157, "keyword", new String[0]));
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("matches");
token = tokens.get(2);
assertThat(token).isEqualTo(new SemanticTokenData(158, 171, "string", new String[0]));
assertThat(source.substring(token.getStart(), token.getEnd())).isEqualTo("'[a-zA-Z\\s]+'");
}
}

View File

@@ -15,7 +15,7 @@ public class PropertyPlaceHolderSemanticTokensTest {
@Test
void propertyWithDefault() {
List<SemanticTokenData> tokens = provider.computeTokens("server.port:5673", 0);
List<SemanticTokenData> tokens = provider.computeTokens("server.port:5673");
assertThat(tokens.size()).isEqualTo(3);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 11, "property", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(11, 12, "operator", new String[0]));
@@ -24,14 +24,14 @@ public class PropertyPlaceHolderSemanticTokensTest {
@Test
void propertyOnly() {
List<SemanticTokenData> tokens = provider.computeTokens("server.port", 0);
List<SemanticTokenData> tokens = provider.computeTokens("server.port");
assertThat(tokens.size()).isEqualTo(1);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 11, "property", new String[0]));
}
@Test
void propertyWithEmptyDefaulValue() {
List<SemanticTokenData> tokens = provider.computeTokens("server.port:", 0);
List<SemanticTokenData> tokens = provider.computeTokens("server.port:");
assertThat(tokens.size()).isEqualTo(3);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 11, "property", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(11, 12, "operator", new String[0]));
@@ -41,7 +41,7 @@ public class PropertyPlaceHolderSemanticTokensTest {
@Test
void error_1() {
provider = new PropertyPlaceHolderSemanticTokens(Optional.empty());
List<SemanticTokenData> tokens = provider.computeTokens("server.:", 0);
List<SemanticTokenData> tokens = provider.computeTokens("server.:");
assertThat(tokens.size()).isEqualTo(3);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "property", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(6, 7, "property", new String[0]));
@@ -51,7 +51,7 @@ public class PropertyPlaceHolderSemanticTokensTest {
@Test
void error_2() {
provider = new PropertyPlaceHolderSemanticTokens(Optional.empty());
List<SemanticTokenData> tokens = provider.computeTokens("server.", 0);
List<SemanticTokenData> tokens = provider.computeTokens("server.");
assertThat(tokens.size()).isEqualTo(2);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 6, "property", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(6, 7, "property", new String[0]));

View File

@@ -25,7 +25,7 @@ public class SpelSemanticTokensTest {
@Test
void simpleCompare() {
List<SemanticTokenData> tokens = provider.computeTokens("1 >= 1", 0);
List<SemanticTokenData> tokens = provider.computeTokens("1 >= 1");
assertThat(tokens.size()).isEqualTo(3);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 4, "operator", new String[0]));
@@ -34,7 +34,7 @@ public class SpelSemanticTokensTest {
@Test
void simpleCompareWithOp() {
List<SemanticTokenData> tokens = provider.computeTokens("1 ge 1", 0);
List<SemanticTokenData> tokens = provider.computeTokens("1 ge 1");
assertThat(tokens.size()).isEqualTo(3);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 4, "keyword", new String[0]));
@@ -43,7 +43,7 @@ public class SpelSemanticTokensTest {
@Test
void logicalOperators() {
List<SemanticTokenData> tokens = provider.computeTokens("4 > 3 or 15 < 10", 0);
List<SemanticTokenData> tokens = provider.computeTokens("4 > 3 or 15 < 10");
assertThat(tokens.size()).isEqualTo(7);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "number", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 3, "operator", new String[0]));
@@ -56,7 +56,7 @@ public class SpelSemanticTokensTest {
@Test
void conditionalOperators() {
List<SemanticTokenData> tokens = provider.computeTokens("someBean.someProperty != null ? someBean.someProperty : 'default'", 0);
List<SemanticTokenData> tokens = provider.computeTokens("someBean.someProperty != null ? someBean.someProperty : 'default'");
assertThat(tokens.size()).isEqualTo(11);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 8, "variable", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(8, 9, "operator", new String[0]));
@@ -73,7 +73,7 @@ public class SpelSemanticTokensTest {
@Test
void regex() {
List<SemanticTokenData> tokens = provider.computeTokens("'invalid alphabetic string #$1' matches '[a-zA-Z\\s]+' ", 0);
List<SemanticTokenData> tokens = provider.computeTokens("'invalid alphabetic string #$1' matches '[a-zA-Z\\s]+' ");
assertThat(tokens.size()).isEqualTo(3);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 31, "string", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(32, 39, "keyword", new String[0]));
@@ -82,7 +82,7 @@ public class SpelSemanticTokensTest {
@Test
void accessMapObj() {
List<SemanticTokenData> tokens = provider.computeTokens("carPark.carsByDriver['Driver1']", 0);
List<SemanticTokenData> tokens = provider.computeTokens("carPark.carsByDriver['Driver1']");
assertThat(tokens.size()).isEqualTo(6);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 7, "variable", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 8, "operator", new String[0]));
@@ -94,7 +94,7 @@ public class SpelSemanticTokensTest {
@Test
void accessListItems() {
List<SemanticTokenData> tokens = provider.computeTokens("carPark.cars[0]", 0);
List<SemanticTokenData> tokens = provider.computeTokens("carPark.cars[0]");
assertThat(tokens.size()).isEqualTo(6);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 7, "variable", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(7, 8, "operator", new String[0]));
@@ -106,7 +106,7 @@ public class SpelSemanticTokensTest {
@Test
void beanReference() {
List<SemanticTokenData> tokens = provider.computeTokens("@vetRepo", 0);
List<SemanticTokenData> tokens = provider.computeTokens("@vetRepo");
assertThat(tokens.size()).isEqualTo(2);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 1, "operator", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(1, 8, "type", new String[0]));
@@ -114,7 +114,7 @@ public class SpelSemanticTokensTest {
@Test
void contructorAndMethod() {
List<SemanticTokenData> tokens = provider.computeTokens("new String('hello world').toUpperCase()", 0);
List<SemanticTokenData> tokens = provider.computeTokens("new String('hello world').toUpperCase()");
assertThat(tokens.size()).isEqualTo(9);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 3, "keyword", new String[0]));
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(4, 10, "method", new String[0]));
@@ -130,7 +130,7 @@ public class SpelSemanticTokensTest {
//https://github.com/spring-projects/sts4/issues/1320
@Test
void inputParameter() {
List<SemanticTokenData> tokens = provider.computeTokens("[1].size().longValue()", 0);
List<SemanticTokenData> tokens = provider.computeTokens("[1].size().longValue()");
assertThat(tokens.size()).isEqualTo(9);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 3, "parameter", new String[0])); // [1]
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(3, 4, "operator", new String[0])); // .
@@ -145,7 +145,7 @@ public class SpelSemanticTokensTest {
@Test
void withPropertyPlaceHolder() {
List<SemanticTokenData> tokens = provider.computeTokens("${server.port:8080} == 8080", 0);
List<SemanticTokenData> tokens = provider.computeTokens("${server.port:8080} == 8080");
assertThat(tokens.size()).isEqualTo(7);
assertThat(tokens.get(0)).isEqualTo(new SemanticTokenData(0, 2, "operator", new String[0])); // ${
assertThat(tokens.get(1)).isEqualTo(new SemanticTokenData(2, 13, "property", new String[0])); // server.port