Skip to content

Commit fee85eb

Browse files
author
Alexander Chen
committed
Added diagnostic and CodeAction to use let to replace with
Signed-off-by: Alexander Chen <alchen@redhat.com>
1 parent 3ff7394 commit fee85eb

File tree

7 files changed

+152
-25
lines changed

7 files changed

+152
-25
lines changed

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/commons/CodeActionFactory.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@ public static CodeAction replace(String title, Range range, String replaceText,
106106
return replace(title, Collections.singletonList(replace), document, diagnostic);
107107
}
108108

109+
@SuppressWarnings("null")
110+
public static CodeAction replace(String title, List<Range> ranges, String replaceText, TextDocumentItem document,
111+
Diagnostic diagnostic) {
112+
List<TextEdit> edits = null;
113+
for (Range range : ranges) {
114+
edits.add(new TextEdit(range, replaceText));
115+
}
116+
return replace(title, edits, document, diagnostic);
117+
}
118+
109119
public static CodeAction replace(String title, List<TextEdit> replace, TextDocumentItem document,
110120
Diagnostic diagnostic) {
111121

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteCodeActions.java

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_ITERABLE;
1616
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_NAME;
1717
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_TAG;
18+
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.EXPRESSION_DATA;
1819

1920
import java.text.MessageFormat;
2021
import java.util.ArrayList;
@@ -50,7 +51,7 @@
5051

5152
/**
5253
* Qute code actions support.
53-
*
54+
*
5455
* @author Angelo ZERR
5556
*
5657
*/
@@ -72,6 +73,8 @@ class QuteCodeActions {
7273

7374
private static final String EXCLUDED_VALIDATION_TITLE = "Exclude this file from validation.";
7475

76+
private static final String QUTE_DEPRICATED_WITH_SECTION = "Replace `with` with `let`.";
77+
7578
public CompletableFuture<List<CodeAction>> doCodeActions(Template template, CodeActionContext context, Range range,
7679
SharedSettings sharedSettings) {
7780
List<CodeAction> codeActions = new ArrayList<>();
@@ -109,6 +112,15 @@ public CompletableFuture<List<CodeAction>> doCodeActions(Template template, Code
109112
// Create `undefinedTag`"
110113
doCodeActionsForUndefinedSectionTag(template, diagnostic, codeActions);
111114
break;
115+
case NotRecommendedWithSection:
116+
// The following Qute template:
117+
// {#with }
118+
//
119+
// will provide a quickfix like:
120+
//
121+
// Replace `with` with `let`.
122+
doCodeActionsForNotRecommendedWithSection(template, diagnostic, codeActions);
123+
break;
112124
default:
113125
break;
114126
}
@@ -186,15 +198,53 @@ private static void doCodeActionToDisableValidation(Template template, List<Diag
186198
codeActions.add(disableValidationForTemplateQuickFix);
187199
}
188200

201+
/**
202+
* Create CodeAction for deprecated `with` Qute syntax.
203+
*
204+
* @param template the Qute template.
205+
* @param diagnostic the diagnostic list that this CodeAction will fix.
206+
* @param codeActions the list of CodeActions to perform.
207+
* @throws BadLocationException
208+
*
209+
*/
210+
private void doCodeActionsForNotRecommendedWithSection(Template template, Diagnostic diagnostic,
211+
List<CodeAction> codeActions) {
212+
Range withSectionRange = diagnostic.getRange();
213+
try {
214+
JsonObject data = (JsonObject) diagnostic.getData();
215+
if (data != null) {
216+
String javaResourceClassName = data.get(DIAGNOSTIC_DATA_TAG).getAsString();
217+
String[] javaResourceAttributes = data.get(EXPRESSION_DATA).getAsString().split(",");
218+
List<String> letExpressionParameterList = new ArrayList<String>();
219+
for (String resourceAttribute : javaResourceAttributes) {
220+
letExpressionParameterList
221+
.add(MessageFormat.format("{1}={0}.{1}", javaResourceClassName, resourceAttribute));
222+
}
223+
String letExpressionParameters = String.join(" ", letExpressionParameterList);
224+
int withSectionStart = template.offsetAt(withSectionRange.getStart());
225+
int withSectionEnd = template.offsetAt(withSectionRange.getEnd());
226+
String withSectionText = template.getText(withSectionStart, withSectionEnd);
227+
int withClosingSectionIndex = withSectionText.lastIndexOf("/with");
228+
String replacement = withSectionText.replaceFirst("#with", "#let").substring(0, withClosingSectionIndex)
229+
.replaceFirst(javaResourceClassName, letExpressionParameters) + "/let";
230+
CodeAction replaceWithSection = CodeActionFactory.replace(QUTE_DEPRICATED_WITH_SECTION,
231+
diagnostic.getRange(), replacement, template.getTextDocument(), diagnostic);
232+
codeActions.add(replaceWithSection);
233+
}
234+
} catch (BadLocationException e) {
235+
return;
236+
}
237+
}
238+
189239
/**
190240
* Create the configuration update (done on client side) quick fix.
191-
*
241+
*
192242
* @param title the displayed name of the QuickFix.
193243
* @param sectionName the section name of the settings to update.
194244
* @param item the section value of the settings to update.
195245
* @param editType the configuration edit type.
196246
* @param diagnostic the diagnostic list that this CodeAction will fix.
197-
*
247+
*
198248
* @return the configuration update (done on client side) quick fix.
199249
*/
200250
private static CodeAction createConfigurationUpdateCodeAction(String title, String scopeUri, String sectionName,

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.concurrent.CompletableFuture;
2424
import java.util.logging.Level;
2525
import java.util.logging.Logger;
26+
import java.util.stream.Collectors;
2627

2728
import org.eclipse.lsp4j.Diagnostic;
2829
import org.eclipse.lsp4j.DiagnosticSeverity;
@@ -54,6 +55,7 @@
5455
import com.redhat.qute.parser.template.Template;
5556
import com.redhat.qute.parser.template.sections.IncludeSection;
5657
import com.redhat.qute.parser.template.sections.LoopSection;
58+
import com.redhat.qute.parser.template.sections.WithSection;
5759
import com.redhat.qute.project.JavaMemberResult;
5860
import com.redhat.qute.project.QuteProject;
5961
import com.redhat.qute.project.datamodel.JavaDataModelCache;
@@ -246,6 +248,9 @@ private void validateDataModel(Node parent, Template template, ResolvingJavaType
246248
case INCLUDE:
247249
validateIncludeSection((IncludeSection) section, diagnostics);
248250
break;
251+
case WITH:
252+
validateWithSection((WithSection) section, diagnostics);
253+
break;
249254
default:
250255
validateSectionTag(section, template, resolvingJavaTypeContext, diagnostics);
251256
}
@@ -345,6 +350,32 @@ private static void validateIncludeSection(IncludeSection includeSection, List<D
345350
}
346351
}
347352

353+
/**
354+
* Report that `#with` section is deprecated.
355+
*
356+
* @param withSection the with section
357+
* @param diagnostics the diagnostics to fill
358+
*/
359+
private static void validateWithSection(WithSection withSection, List<Diagnostic> diagnostics) {
360+
// List<DiagnosticTag> tags = Collections.singletonList(DiagnosticTag.Deprecated);
361+
Range range = QutePositionUtility.createRange(withSection);
362+
// Diagnostic diagnostic = createDiagnosticWithTags(range, DiagnosticSeverity.Warning,
363+
// QuteErrorCode.DeprecatedWithSection, tags);
364+
Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Warning,
365+
QuteErrorCode.NotRecommendedWithSection);
366+
String javaResourceClassName = withSection.getObjectParameter().getName();
367+
List<Node> withExpressions = withSection.getChildren().stream().filter(s -> s instanceof Expression)
368+
.collect(Collectors.toList());
369+
List<String> withExpressionContents = new ArrayList<String>();
370+
for (Node expression : withExpressions) {
371+
withExpressionContents.add(((Expression) expression).getContent());
372+
}
373+
String withExpressionContentsString = String.join(",", withExpressionContents);
374+
diagnostic.setData(DiagnosticDataFactory.createNotRecommendedWithSectionData(javaResourceClassName,
375+
withExpressionContentsString));
376+
diagnostics.add(diagnostic);
377+
}
378+
348379
private ResolvedJavaTypeInfo validateExpression(Expression expression, Section ownerSection, Template template,
349380
ResolutionContext resolutionContext, ResolvingJavaTypeContext resolvingJavaTypeContext,
350381
List<Diagnostic> diagnostics) {
@@ -391,7 +422,7 @@ private ResolvedJavaTypeInfo validateExpressionParts(Parts parts, Section ownerS
391422
ResolvedJavaTypeInfo resolvedJavaType = null;
392423
String namespace = null;
393424
for (int i = 0; i < parts.getChildCount(); i++) {
394-
Part current = ((Part) parts.getChild(i));
425+
Part current = (parts.getChild(i));
395426

396427
if (current.isLast()) {
397428
// It's the last part, check if it is not ended with '.'
@@ -586,7 +617,7 @@ private ResolvedJavaTypeInfo validateObjectPart(ObjectPart objectPart, Section o
586617

587618
/**
588619
* Validate the given property, method part.
589-
*
620+
*
590621
* @param part the property, method part to validate.
591622
* @param ownerSection the owner section and null otherwise.
592623
* @param template the template.
@@ -596,7 +627,7 @@ private ResolvedJavaTypeInfo validateObjectPart(ObjectPart objectPart, Section o
596627
* @param iterableOfType the iterable of type.
597628
* @param diagnostics the diagnostic list to fill.
598629
* @param resolvingJavaTypeContext the resolving Java type context.
599-
*
630+
*
600631
* @return the Java type returned by the member part and null otherwise.
601632
*/
602633
private ResolvedJavaTypeInfo validateMemberPart(Part part, Section ownerSection, Template template,
@@ -617,7 +648,7 @@ private ResolvedJavaTypeInfo validateMemberPart(Part part, Section ownerSection,
617648

618649
/**
619650
* Validate the given property part.
620-
*
651+
*
621652
* @param part the property part to validate.
622653
* @param ownerSection the owner section and null otherwise.
623654
* @param template the template.
@@ -627,7 +658,7 @@ private ResolvedJavaTypeInfo validateMemberPart(Part part, Section ownerSection,
627658
* @param iterableOfType the iterable of type.
628659
* @param diagnostics the diagnostic list to fill.
629660
* @param resolvingJavaTypeContext the resolving Java type context.
630-
*
661+
*
631662
* @return the Java type returned by the member part and null otherwise.
632663
*/
633664
private ResolvedJavaTypeInfo validatePropertyPart(PropertyPart part, Section ownerSection, Template template,
@@ -650,7 +681,7 @@ private ResolvedJavaTypeInfo validatePropertyPart(PropertyPart part, Section own
650681

651682
/**
652683
* Validate the given method part.
653-
*
684+
*
654685
* @param part the method part to validate.
655686
* @param ownerSection the owner section and null otherwise.
656687
* @param template the template.
@@ -660,7 +691,7 @@ private ResolvedJavaTypeInfo validatePropertyPart(PropertyPart part, Section own
660691
* @param iterableOfType the iterable of type.
661692
* @param diagnostics the diagnostic list to fill.
662693
* @param resolvingJavaTypeContext the resolving Java type context.
663-
*
694+
*
664695
* @return the Java type returned by the member part and null otherwise.
665696
*/
666697
private ResolvedJavaTypeInfo validateMethodPart(MethodPart methodPart, Section ownerSection, Template template,

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/diagnostics/DiagnosticDataFactory.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,21 @@
1414
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_ITERABLE;
1515
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_NAME;
1616
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_TAG;
17+
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.EXPRESSION_DATA;
1718
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.QUTE_SOURCE;
1819

20+
import java.util.List;
21+
1922
import org.eclipse.lsp4j.Diagnostic;
2023
import org.eclipse.lsp4j.DiagnosticSeverity;
24+
import org.eclipse.lsp4j.DiagnosticTag;
2125
import org.eclipse.lsp4j.Range;
2226

2327
import com.google.gson.JsonObject;
2428

2529
/**
2630
* Diagnostic factory.
27-
*
31+
*
2832
* @author Angelo ZERR
2933
*
3034
*/
@@ -43,6 +47,13 @@ public static JsonObject createUndefinedSectionTagData(String tagName) {
4347
return data;
4448
}
4549

50+
public static JsonObject createNotRecommendedWithSectionData(String partName, String expressions) {
51+
JsonObject data = new JsonObject();
52+
data.addProperty(DIAGNOSTIC_DATA_NAME, partName);
53+
data.addProperty(EXPRESSION_DATA, expressions);
54+
return data;
55+
}
56+
4657
public static Diagnostic createDiagnostic(Range range, DiagnosticSeverity severity, IQuteErrorCode errorCode,
4758
Object... arguments) {
4859
String message = errorCode.getMessage(arguments);
@@ -55,4 +66,13 @@ public static Diagnostic createDiagnostic(Range range, String message, Diagnosti
5566
errorCode != null ? errorCode.getCode() : null);
5667
return diagnostic;
5768
}
69+
70+
public static Diagnostic createDiagnosticWithTags(Range range, DiagnosticSeverity severity,
71+
IQuteErrorCode errorCode, List<DiagnosticTag> tags, Object... arguments) {
72+
String message = errorCode.getMessage(arguments);
73+
Diagnostic diagnostic = new Diagnostic(range, message, severity, QUTE_SOURCE,
74+
errorCode != null ? errorCode.getCode() : null);
75+
diagnostic.setTags(tags);
76+
return diagnostic;
77+
}
5878
}

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/diagnostics/QuteDiagnosticContants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ private QuteDiagnosticContants() {
2424
public static final String DIAGNOSTIC_DATA_ITERABLE = "iterable";
2525

2626
public static final String DIAGNOSTIC_DATA_TAG = "tag";
27+
28+
public static final String EXPRESSION_DATA = "expressions";
2729
}

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/diagnostics/QuteErrorCode.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ public enum QuteErrorCode implements IQuteErrorCode {
4545

4646
UndefinedSectionTag("No section helper found for `{0}`."), //
4747

48-
SyntaxError("Syntax error: `{0}`.");
48+
SyntaxError("Syntax error: `{0}`."),
49+
50+
// Error code for deprecated #with section
51+
NotRecommendedWithSection("`with` is not recommended. Use `let` instead.");
4952

5053
private final String rawMessage;
5154

qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionWithWithSectionTest.java

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
/**
2525
* Test with #with section
26-
*
26+
*
2727
* @author Angelo ZERR
2828
*
2929
*/
@@ -34,23 +34,28 @@ public void undefinedObject() throws Exception {
3434
String template = "{#with item}\r\n" + //
3535
"{/with}";
3636

37-
Diagnostic d = d(0, 7, 0, 11, QuteErrorCode.UndefinedVariable, "`item` cannot be resolved to a variable.",
37+
Diagnostic d1 = d(0, 7, 0, 11, QuteErrorCode.UndefinedVariable, "`item` cannot be resolved to a variable.",
3838
DiagnosticSeverity.Warning);
39-
d.setData(DiagnosticDataFactory.createUndefinedVariableData("item", false));
39+
d1.setData(DiagnosticDataFactory.createUndefinedVariableData("item", false));
4040

41-
testDiagnosticsFor(template, d);
42-
testCodeActionsFor(template, d, //
43-
ca(d, te(0, 0, 0, 0, "{@java.lang.String item}\r\n")));
41+
Diagnostic d2 = d(0, 0, 1, 7, QuteErrorCode.NotRecommendedWithSection,
42+
"`with` is not recommended. Use `let` instead.", DiagnosticSeverity.Warning);
43+
44+
testDiagnosticsFor(template, d1, d2);
45+
testCodeActionsFor(template, d1, //
46+
ca(d1, te(0, 0, 0, 0, "{@java.lang.String item}\r\n")));
4447
}
4548

4649
@Test
47-
public void noError() throws Exception {
50+
public void singleSection() throws Exception {
4851
String template = "{@org.acme.Item item}\r\n" + //
4952
"{#with item}\r\n" + //
5053
" <h1>{name}</h1> \r\n" + //
5154
" <p>{price}</p> \r\n" + //
5255
"{/with}";
53-
testDiagnosticsFor(template);
56+
Diagnostic d = d(1, 0, 4, 7, QuteErrorCode.NotRecommendedWithSection,
57+
"`with` is not recommended. Use `let` instead.", DiagnosticSeverity.Warning);
58+
testDiagnosticsFor(template, d);
5459
}
5560

5661
@Test
@@ -68,13 +73,19 @@ public void nested() throws Exception {
6873
" {/with}\r\n" + //
6974
"{/with}";
7075

71-
Diagnostic d = d(6, 5, 6, 12, QuteErrorCode.UndefinedVariable, "`average` cannot be resolved to a variable.",
76+
Diagnostic d1 = d(1, 0, 11, 7, QuteErrorCode.NotRecommendedWithSection,
77+
"`with` is not recommended. Use `let` instead.", DiagnosticSeverity.Warning);
78+
79+
Diagnostic d2 = d(4, 2, 10, 9, QuteErrorCode.NotRecommendedWithSection,
80+
"`with` is not recommended. Use `let` instead.", DiagnosticSeverity.Warning);
81+
82+
Diagnostic d3 = d(6, 5, 6, 12, QuteErrorCode.UndefinedVariable, "`average` cannot be resolved to a variable.",
7283
DiagnosticSeverity.Warning);
73-
d.setData(DiagnosticDataFactory.createUndefinedVariableData("average", false));
84+
d3.setData(DiagnosticDataFactory.createUndefinedVariableData("average", false));
7485

75-
testDiagnosticsFor(template, d);
76-
testCodeActionsFor(template, d, //
77-
ca(d, te(0, 0, 0, 0, "{@java.lang.String average}\r\n")));
86+
testDiagnosticsFor(template, d1, d2, d3);
87+
testCodeActionsFor(template, d3, //
88+
ca(d3, te(0, 0, 0, 0, "{@java.lang.String average}\r\n")));
7889

7990
}
8091
}

0 commit comments

Comments
 (0)