use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.
the class QuteCompletions method doComplete.
/**
* Returns completion list for the given position
*
* @param template the Qute template
* @param position the position where completion was triggered
* @param completionSettings the completion settings.
* @param formattingSettings the formatting settings.
* @param cancelChecker the cancel checker
* @return completion list for the given position
*/
public CompletableFuture<CompletionList> doComplete(Template template, Position position, QuteCompletionSettings completionSettings, QuteFormattingSettings formattingSettings, CancelChecker cancelChecker) {
CompletionRequest completionRequest = null;
try {
completionRequest = new CompletionRequest(template, position, completionSettings, formattingSettings);
} catch (BadLocationException e) {
LOGGER.log(Level.SEVERE, "Creation of CompletionRequest failed", e);
return EMPTY_FUTURE_COMPLETION;
}
Node node = completionRequest.getNode();
if (node == null) {
return EMPTY_FUTURE_COMPLETION;
}
String text = template.getText();
int offset = completionRequest.getOffset();
if (node.getKind() == NodeKind.Expression || node.getKind() == NodeKind.ExpressionParts || node.getKind() == NodeKind.ExpressionPart) {
Expression expression = null;
Node nodeExpression = null;
if (node.getKind() == NodeKind.Expression) {
expression = (Expression) node;
} else if (node.getKind() == NodeKind.ExpressionParts) {
nodeExpression = node;
expression = ((Parts) node).getParent();
} else if (node.getKind() == NodeKind.ExpressionPart) {
nodeExpression = node;
expression = ((Part) node).getParent().getParent();
}
return completionForExpression.doCompleteExpression(completionRequest, expression, nodeExpression, template, offset, completionSettings, formattingSettings, cancelChecker);
} else if (node.getKind() == NodeKind.Text) {
// The completion is triggered in text node (before node)
Section parent = node.getParentSection();
if (parent != null && (parent.isInEndTagName(offset))) {
// The completion is triggered inside end tag
return EMPTY_FUTURE_COMPLETION;
}
// The completion is triggered in text node
// Check if completion is triggered after a start bracket character and if it's
// a valid expression
int nbBrackets = 0;
int bracketOffset = offset - 1;
char previousChar = text.charAt(bracketOffset);
if (previousChar == '#') {
// {#
bracketOffset--;
}
while (bracketOffset >= 0 && text.charAt(bracketOffset) == '{') {
bracketOffset--;
nbBrackets++;
}
if (nbBrackets > 0) {
if (nbBrackets % 2 != 0) {
// The completion is triggered in text node after bracket '{' character
return completionForExpression.doCompleteExpression(completionRequest, null, node, template, offset, completionSettings, formattingSettings, cancelChecker);
}
return EMPTY_FUTURE_COMPLETION;
}
} else if (node.getKind() == NodeKind.ParameterDeclaration) {
return completionsForParameterDeclaration.doCollectJavaClassesSuggestions((ParameterDeclaration) node, template, offset, completionSettings);
} else if (node.getKind() == NodeKind.Section) {
// {#|}
return completionForTagSection.doCompleteTagSection(completionRequest, completionSettings, formattingSettings, cancelChecker);
}
return collectSnippetSuggestions(completionRequest);
}
use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.
the class QuteDiagnostics method validateMethodPart.
/**
* Validate the given method part.
*
* @param part the method part to validate.
* @param ownerSection the owner section and null otherwise.
* @param template the template.
* @param projectUri the project Uri.
* @param resolutionContext the resolution context.
* @param baseType the base object type.
* @param iterableOfType the iterable of type.
* @param diagnostics the diagnostic list to fill.
* @param resolvingJavaTypeContext the resolving Java type context.
*
* @return the Java type returned by the member part and null otherwise.
*/
private ResolvedJavaTypeInfo validateMethodPart(MethodPart methodPart, Section ownerSection, Template template, String projectUri, QuteValidationSettings validationSettings, ResolutionContext resolutionContext, ResolvedJavaTypeInfo resolvedJavaType, ResolvedJavaTypeInfo iter, List<Diagnostic> diagnostics, ResolvingJavaTypeContext resolvingJavaTypeContext) {
// Validate parameters of the method part
boolean undefinedType = false;
List<ResolvedJavaTypeInfo> parameterTypes = new ArrayList<>();
for (Parameter parameter : methodPart.getParameters()) {
ResolvedJavaTypeInfo result = null;
Expression expression = parameter.getJavaTypeExpression();
if (expression != null) {
result = validateExpression(expression, ownerSection, template, validationSettings, resolutionContext, resolvingJavaTypeContext, diagnostics);
}
if (result == null) {
undefinedType = true;
}
parameterTypes.add(result);
}
if (undefinedType) {
// One of parameter cannot be resolved as type, teh validation is stopped
return null;
}
// All parameters are resolved, validate the existing of method name according
// to the computed parameter types
String methodName = methodPart.getPartName();
String namespace = methodPart.getNamespace();
JavaMemberResult result = javaCache.findMethod(resolvedJavaType, namespace, methodName, parameterTypes, projectUri);
JavaMethodInfo method = (JavaMethodInfo) result.getMember();
if (method == null) {
QuteErrorCode errorCode = QuteErrorCode.UnknownMethod;
String arg = null;
if (namespace != null) {
// ex :{config.getXXXX()}
errorCode = QuteErrorCode.UnknownNamespaceResolverMethod;
arg = namespace;
} else {
// ex : {@org.acme.Item item}
// {item.getXXXX()}
arg = resolvedJavaType.getSignature();
InvalidMethodReason reason = javaCache.getInvalidMethodReason(methodName, resolvedJavaType, projectUri);
if (reason != null) {
switch(reason) {
case VoidReturn:
errorCode = QuteErrorCode.InvalidMethodVoid;
break;
case Static:
errorCode = QuteErrorCode.InvalidMethodStatic;
break;
case FromObject:
errorCode = QuteErrorCode.InvalidMethodFromObject;
break;
default:
}
}
}
Range range = QutePositionUtility.createRange(methodPart);
Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, errorCode, methodName, arg);
diagnostics.add(diagnostic);
return null;
}
boolean matchVirtualMethod = result.isMatchVirtualMethod();
if (!matchVirtualMethod) {
Range range = QutePositionUtility.createRange(methodPart);
Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, //
QuteErrorCode.InvalidVirtualMethod, //
method.getName(), //
method.getSimpleSourceType(), resolvedJavaType.getJavaElementSimpleType());
diagnostics.add(diagnostic);
return null;
}
boolean matchParameters = result.isMatchParameters();
if (!matchParameters) {
// The method codePointAt(int) in the type String is not applicable for the
// arguments ()
StringBuilder expectedSignature = new StringBuilder("(");
boolean ignoreParameter = method.isVirtual();
for (JavaParameterInfo parameter : method.getParameters()) {
if (!ignoreParameter) {
if (expectedSignature.length() > 1) {
expectedSignature.append(", ");
}
expectedSignature.append(parameter.getJavaElementSimpleType());
}
ignoreParameter = false;
}
expectedSignature.append(")");
expectedSignature.insert(0, method.getName());
StringBuilder actualSignature = new StringBuilder("(");
for (ResolvedJavaTypeInfo parameterType : parameterTypes) {
if (actualSignature.length() > 1) {
actualSignature.append(", ");
}
actualSignature.append(parameterType != null ? parameterType.getJavaElementSimpleType() : parameterType);
}
actualSignature.append(")");
Range range = QutePositionUtility.createRange(methodPart);
Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, //
QuteErrorCode.InvalidMethodParameter, //
expectedSignature.toString(), //
method.getSimpleSourceType(), /* String */
actualSignature.toString());
diagnostics.add(diagnostic);
return null;
}
String memberType = method.resolveJavaElementType(iter);
return validateJavaTypePart(methodPart, ownerSection, projectUri, diagnostics, resolvingJavaTypeContext, memberType);
}
use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.
the class QuteDiagnostics method validateDataModel.
private void validateDataModel(Node parent, Template template, QuteValidationSettings validationSettings, ResolvingJavaTypeContext resolvingJavaTypeContext, ResolutionContext currentContext, List<Diagnostic> diagnostics) {
ResolutionContext previousContext = currentContext;
List<Node> children = parent.getChildren();
for (Node node : children) {
switch(node.getKind()) {
case ParameterDeclaration:
{
ParameterDeclaration parameter = (ParameterDeclaration) node;
String javaTypeToResolve = parameter.getJavaType();
if (!StringUtils.isEmpty(javaTypeToResolve)) {
String projectUri = template.getProjectUri();
if (projectUri != null) {
List<JavaTypeRangeOffset> classNameRanges = parameter.getJavaTypeNameRanges();
for (RangeOffset classNameRange : classNameRanges) {
String className = template.getText(classNameRange);
ResolvedJavaTypeInfo resolvedJavaType = resolveJavaType(className, projectUri, resolvingJavaTypeContext);
if (resolvedJavaType == null) {
// Java type doesn't exist
Range range = QutePositionUtility.createRange(classNameRange, template);
Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, QuteErrorCode.UnknownType, className);
diagnostics.add(diagnostic);
} else if (!isResolvingJavaType(resolvedJavaType)) {
currentContext.put(javaTypeToResolve, resolvedJavaType);
}
}
}
}
break;
}
case Section:
{
Section section = (Section) node;
if (canChangeContext(section)) {
currentContext = new ResolutionContext(currentContext);
}
List<Parameter> parameters = section.getParameters();
// validate expression parameters
for (Parameter parameter : parameters) {
Expression expression = parameter.getJavaTypeExpression();
if (expression != null) {
ResolvedJavaTypeInfo result = validateExpression(expression, section, template, validationSettings, previousContext, resolvingJavaTypeContext, diagnostics);
switch(section.getSectionKind()) {
case FOR:
case EACH:
String alias = ((LoopSection) section).getAlias();
currentContext.put(alias, result);
break;
case WITH:
currentContext.setWithObject(result);
break;
case LET:
case SET:
currentContext.put(parameter.getName(), result);
break;
default:
}
}
}
switch(section.getSectionKind()) {
case INCLUDE:
validateIncludeSection((IncludeSection) section, diagnostics);
break;
default:
validateSectionTag(section, template, resolvingJavaTypeContext, diagnostics);
}
break;
}
case Expression:
{
validateExpression((Expression) node, null, template, validationSettings, previousContext, resolvingJavaTypeContext, diagnostics);
break;
}
default:
}
validateDataModel(node, template, validationSettings, resolvingJavaTypeContext, currentContext, diagnostics);
}
}
use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.
the class QuteDiagnostics method validateObjectPart.
private ResolvedJavaTypeInfo validateObjectPart(String namespace, ObjectPart objectPart, Section ownerSection, Template template, String projectUri, QuteValidationSettings validationSettings, ResolutionContext resolutionContext, List<Diagnostic> diagnostics, ResolvingJavaTypeContext resolvingJavaTypeContext) {
JavaMemberInfo javaMember = resolutionContext.findMemberWithObject(objectPart.getPartName(), projectUri);
if (javaMember != null) {
ResolvedJavaTypeInfo resolvedJavaType = resolveJavaType(javaMember.getJavaElementType(), projectUri, resolvingJavaTypeContext);
if (isResolvingJavaType(resolvedJavaType)) {
return null;
}
return resolvedJavaType;
}
JavaTypeInfoProvider javaTypeInfo = objectPart.resolveJavaType();
if (javaTypeInfo == null) {
if (!resolvingJavaTypeContext.isDataModelTemplateResolved()) {
// The data model is not loaded, ignore the error of undefined object
return null;
}
if (UserTagUtils.isUserTag(template)) {
// Ignore undefined object diagnostic for user tag
return null;
}
// ex : {item} --> undefined object
DiagnosticSeverity severity = validationSettings.getUndefinedObject().getDiagnosticSeverity();
if (severity == null) {
return null;
}
Range range = QutePositionUtility.createRange(objectPart);
Diagnostic diagnostic = createDiagnostic(range, severity, QuteErrorCode.UndefinedObject, objectPart.getPartName());
// Create data information helpful for code action
diagnostic.setData(DiagnosticDataFactory.createUndefinedObjectData(objectPart.getPartName(), ownerSection != null && ownerSection.isIterable()));
diagnostics.add(diagnostic);
return null;
}
String javaTypeToResolve = javaTypeInfo.getJavaType();
if (javaTypeToResolve == null) {
// case of (#for item as data.items) where data.items expression must be
// evaluated
Expression expression = javaTypeInfo.getJavaTypeExpression();
if (expression != null) {
String literalJavaType = expression.getLiteralJavaType();
if (literalJavaType != null) {
javaTypeToResolve = literalJavaType;
} else {
Part lastPart = expression.getLastPart();
if (lastPart != null) {
ResolvedJavaTypeInfo alias = javaCache.resolveJavaType(lastPart, projectUri).getNow(RESOLVING_JAVA_TYPE);
if (isResolvingJavaType(alias)) {
return null;
}
if (alias == null) {
if (!resolvingJavaTypeContext.isDataModelTemplateResolved()) {
// The data model is not loaded, don't validate the item of items.
return null;
}
} else {
javaTypeToResolve = alias.getSignature();
}
}
}
}
}
return validateJavaTypePart(objectPart, ownerSection, projectUri, diagnostics, resolvingJavaTypeContext, javaTypeToResolve);
}
use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.
the class QuteHover method doHoverForObjectPart.
private CompletableFuture<Hover> doHoverForObjectPart(Part part, String projectUri, HoverRequest hoverRequest) {
if (UserTagUtils.isUserTag(hoverRequest.getTemplate())) {
// It's an user tag
SectionMetadata specialKey = UserTagUtils.getSpecialKey(part.getPartName());
if (specialKey != null) {
// its a special key for user tag ({it} or {nested-content), display the special
// key documentation.
boolean hasMarkdown = hoverRequest.canSupportMarkupKind(MarkupKind.MARKDOWN);
MarkupContent content = DocumentationUtils.getDocumentation(specialKey, hasMarkdown);
Range range = QutePositionUtility.createRange(part);
Hover hover = new Hover(content, range);
return CompletableFuture.completedFuture(hover);
}
}
// Check if part is a literal (ex: true, null, 123, 'abc', etc)
Expression expression = part.getParent().getParent();
String literalJavaType = expression.getLiteralJavaType();
if (literalJavaType != null) {
return doHoverForJavaType(part, literalJavaType, projectUri, hoverRequest);
}
return //
javaCache.resolveJavaType(part, projectUri).thenApply(resolvedJavaType -> {
if (resolvedJavaType != null) {
SectionMetadata metadata = getMetadata(part);
boolean hasMarkdown = hoverRequest.canSupportMarkupKind(MarkupKind.MARKDOWN);
MarkupContent content = DocumentationUtils.getDocumentation(resolvedJavaType, metadata != null ? metadata.getDescription() : null, hasMarkdown);
Range range = QutePositionUtility.createRange(part);
return new Hover(content, range);
}
return null;
});
}
Aggregations