Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qute - fix validation of primitives #15161

Merged
merged 1 commit into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -642,26 +642,28 @@ static Match validateNestedExpressions(TemplateAnalysis templateAnalysis, ClassI
}
}
}
if (member == null) {
// Then try to find an etension method
member = findTemplateExtensionMethod(info, match.type(), templateExtensionMethods, expression,
index,
templateIdToPathFun, results);
}
if (member == null) {
// Test whether the validation should be skipped
TypeCheck check = new TypeCheck(
info.isProperty() ? info.asProperty().name : info.asVirtualMethod().name,
match.clazz(),
info.part.isVirtualMethod() ? info.part.asVirtualMethod().getParameters().size() : -1);
if (isExcluded(check, excludes)) {
LOGGER.debugf(
"Expression part [%s] excluded from validation of [%s] against type [%s]",
info.value,
expression.toOriginalString(), match.type());
match.clearValues();
break;
}
}

if (member == null) {
// Then try to find an etension method
member = findTemplateExtensionMethod(info, match.type(), templateExtensionMethods, expression,
index,
templateIdToPathFun, results);
}

if (member == null) {
// Test whether the validation should be skipped
TypeCheck check = new TypeCheck(
info.isProperty() ? info.asProperty().name : info.asVirtualMethod().name,
match.clazz(),
info.part.isVirtualMethod() ? info.part.asVirtualMethod().getParameters().size() : -1);
if (isExcluded(check, excludes)) {
LOGGER.debugf(
"Expression part [%s] excluded from validation of [%s] against type [%s]",
info.value,
expression.toOriginalString(), match.type());
match.clearValues();
break;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ public class Movie {

public final Boolean alwaysTrue;

public final boolean alwaysFalsePrimitive = false;

public final List<String> mainCharacters;

public Movie(String... mainCharacters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ static Long toLong(Movie movie, long... values) {
return ret;
}

static boolean negate(boolean val) {
return !val;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public class ValidationSuccessTest {
// Built-in value resolvers
+ "{movie.name ?: 'Mono'} "
+ "{movie.alwaysTrue ? 'Mono' : 'Stereo'} "
+ "{movie.alwaysFalsePrimitive ? 'Mono' : 'Stereo'} "
+ "{movie.alwaysFalsePrimitive.negate} "
+ "{movie.mainCharacters.size} "
// Name and number of params ok and param type ignored
+ "{movie.findService('foo')} "
Expand All @@ -53,7 +55,7 @@ public class ValidationSuccessTest {
@Test
public void testResult() {
// Validation succeeded! Yay!
assertEquals("Jason Jason Mono 1 10 11 ok 43 3 ohn bar",
assertEquals("Jason Jason Mono Stereo true 1 10 11 ok 43 3 ohn bar",
movie.data("movie", new Movie("John"), "name", "Vasik", "surname", "Hu", "age", 10l, "map",
Collections.singletonMap("foo", "bar")).render());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.quarkus.qute.generator;

import java.util.concurrent.CompletionStage;
import org.jboss.jandex.DotName;

final class DotNames {

static final DotName BOOLEAN = DotName.createSimple(Boolean.class.getName());
static final DotName BYTE = DotName.createSimple(Byte.class.getName());
static final DotName CHARACTER = DotName.createSimple(Character.class.getName());
static final DotName DOUBLE = DotName.createSimple(Double.class.getName());
static final DotName FLOAT = DotName.createSimple(Float.class.getName());
static final DotName INTEGER = DotName.createSimple(Integer.class.getName());
static final DotName LONG = DotName.createSimple(Long.class.getName());
static final DotName SHORT = DotName.createSimple(Short.class.getName());
static final DotName STRING = DotName.createSimple(String.class.getName());
static final DotName COMPLETION_STAGE = DotName.createSimple(CompletionStage.class.getName());
static final DotName OBJECT = DotName.createSimple(Object.class.getName());

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.jboss.jandex.DotName;
import org.jboss.jandex.IndexView;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.PrimitiveType.Primitive;
import org.jboss.jandex.Type;
import org.jboss.jandex.Type.Kind;

Expand All @@ -55,8 +56,6 @@
public class ExtensionMethodGenerator {

public static final DotName TEMPLATE_EXTENSION = DotName.createSimple(TemplateExtension.class.getName());
static final DotName STRING = DotName.createSimple(String.class.getName());

public static final String SUFFIX = "_Extension" + ValueResolverGenerator.SUFFIX;
public static final String NAMESPACE_SUFFIX = "_Namespace" + SUFFIX;

Expand Down Expand Up @@ -132,7 +131,7 @@ public void generate(MethodInfo method, String matchName, String matchRegex, Int

if (matchRegex != null || matchName.equals(TemplateExtension.ANY)) {
// The second parameter must be a string
if (parameters.size() < 2 || !parameters.get(1).name().equals(STRING)) {
if (parameters.size() < 2 || !parameters.get(1).name().equals(io.quarkus.qute.generator.DotNames.STRING)) {
throw new TemplateException(
"A template extension method matching multiple names or a regular expression must declare at least two parameters and the second parameter must be string: "
+ method);
Expand Down Expand Up @@ -352,7 +351,8 @@ private void implementAppliesTo(ClassCreator valueResolver, MethodInfo method, S

// Test base object class
ResultHandle baseClass = appliesTo.invokeVirtualMethod(Descriptors.GET_CLASS, base);
ResultHandle testClass = appliesTo.loadClass(parameters.get(0).name().toString());
// Perform autoboxing for primitives
ResultHandle testClass = appliesTo.loadClass(box(parameters.get(0)).name().toString());
ResultHandle baseClassTest = appliesTo.invokeVirtualMethod(Descriptors.IS_ASSIGNABLE_FROM, testClass,
baseClass);
BytecodeCreator baseNotAssignable = appliesTo.ifTrue(baseClassTest).falseBranch();
Expand Down Expand Up @@ -633,4 +633,34 @@ static String sha1(String value) {
}
}

static Type box(Type type) {
if (type.kind() == Kind.PRIMITIVE) {
return box(type.asPrimitiveType().primitive());
}
return type;
}

static Type box(Primitive primitive) {
switch (primitive) {
case BOOLEAN:
return Type.create(DotNames.BOOLEAN, Kind.CLASS);
case DOUBLE:
return Type.create(DotNames.DOUBLE, Kind.CLASS);
case FLOAT:
return Type.create(DotNames.FLOAT, Kind.CLASS);
case LONG:
return Type.create(DotNames.LONG, Kind.CLASS);
case INT:
return Type.create(DotNames.INTEGER, Kind.CLASS);
case BYTE:
return Type.create(DotNames.BYTE, Kind.CLASS);
case CHAR:
return Type.create(DotNames.CHARACTER, Kind.CLASS);
case SHORT:
return Type.create(DotNames.SHORT, Kind.CLASS);
default:
throw new IllegalArgumentException("Unsupported primitive: " + primitive);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,6 @@ public static Builder builder() {
public static final DotName TEMPLATE_DATA = DotName.createSimple(TemplateData.class.getName());
public static final DotName TEMPLATE_DATA_CONTAINER = DotName.createSimple(TemplateData.Container.class.getName());

private static final DotName COMPLETION_STAGE = DotName.createSimple(CompletionStage.class.getName());
private static final DotName OBJECT = DotName.createSimple(Object.class.getName());
private static final DotName BOOLEAN = DotName.createSimple(Boolean.class.getName());

public static final String SUFFIX = "_ValueResolver";
public static final String NESTED_SEPARATOR = "$_";

Expand Down Expand Up @@ -115,7 +111,7 @@ public void generate() {
Map<DotName, Set<DotName>> superToSub = new HashMap<>();
for (Entry<DotName, ClassInfo> entry : nameToClass.entrySet()) {
DotName superName = entry.getValue().superName();
if (superName != null && !OBJECT.equals(superName)) {
if (superName != null && !DotNames.OBJECT.equals(superName)) {
superToSub.computeIfAbsent(superName, name -> new HashSet<>()).add(entry.getKey());
}
}
Expand All @@ -135,7 +131,7 @@ public void generate() {
generate(entry.getKey(), priority);
// Queue a class removal
DotName superName = entry.getValue().superName();
if (superName != null && !OBJECT.equals(superName)) {
if (superName != null && !DotNames.OBJECT.equals(superName)) {
superToSubRemovals.computeIfAbsent(superName, name -> new HashSet<>()).add(entry.getKey());
}
// Remove the processed binding
Expand Down Expand Up @@ -229,7 +225,7 @@ private void implementResolve(ClassCreator valueResolver, String clazzName, Clas
.collect(Collectors.toList());
if (!ignoreSuperclasses) {
DotName superName = clazz.superName();
while (superName != null && !superName.equals(OBJECT)) {
while (superName != null && !superName.equals(DotNames.OBJECT)) {
ClassInfo superClass = index.getClassByName(superName);
if (superClass != null) {
methods.addAll(
Expand All @@ -250,7 +246,7 @@ private void implementResolve(ClassCreator valueResolver, String clazzName, Clas
if ((field.type().kind() == org.jboss.jandex.Type.Kind.PRIMITIVE
&& field.type().asPrimitiveType().equals(PrimitiveType.BOOLEAN))
|| (field.type().kind() == org.jboss.jandex.Type.Kind.CLASS
&& field.type().name().equals(BOOLEAN))) {
&& field.type().name().equals(DotNames.BOOLEAN))) {
getterName = IS_PREFIX + capitalize(field.name());
} else {
getterName = GET_PREFIX + capitalize(field.name());
Expand Down Expand Up @@ -837,7 +833,7 @@ static boolean isGetterName(String name, Type returnType) {
return true;
}
if (returnType == null
|| (returnType.name().equals(PrimitiveType.BOOLEAN.name()) || returnType.name().equals(BOOLEAN))) {
|| (returnType.name().equals(PrimitiveType.BOOLEAN.name()) || returnType.name().equals(DotNames.BOOLEAN))) {
return name.startsWith(IS_PREFIX) || name.startsWith(HAS_PREFIX);
}
return false;
Expand Down Expand Up @@ -939,7 +935,7 @@ static String generatedNameFromTarget(String targetPackage, String baseName, Str

public static boolean hasCompletionStageInTypeClosure(ClassInfo classInfo,
IndexView index) {
return hasClassInTypeClosure(classInfo, COMPLETION_STAGE, index);
return hasClassInTypeClosure(classInfo, DotNames.COMPLETION_STAGE, index);
}

public static boolean hasClassInTypeClosure(ClassInfo classInfo, DotName className,
Expand Down