Skip to content

Commit bea259f

Browse files
authored
Merge pull request #30593 from mkouba/qute-m1-fix
2 parents d004bcf + d576fa2 commit bea259f

File tree

3 files changed

+96
-60
lines changed

3 files changed

+96
-60
lines changed

extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/MessageBundleProcessor.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
import io.quarkus.qute.deployment.QuteProcessor.Match;
8989
import io.quarkus.qute.deployment.TemplatesAnalysisBuildItem.TemplateAnalysis;
9090
import io.quarkus.qute.deployment.Types.AssignableInfo;
91+
import io.quarkus.qute.deployment.Types.HierarchyIndexer;
9192
import io.quarkus.qute.generator.Descriptors;
9293
import io.quarkus.qute.generator.ValueResolverGenerator;
9394
import io.quarkus.qute.i18n.Localized;
@@ -428,6 +429,7 @@ public String apply(String id) {
428429

429430
LookupConfig lookupConfig = new QuteProcessor.FixedLookupConfig(index, QuteProcessor.initDefaultMembersFilter(), false);
430431
Map<DotName, AssignableInfo> assignableCache = new HashMap<>();
432+
HierarchyIndexer hierarchyIndexer = new HierarchyIndexer(index);
431433

432434
// bundle name -> (key -> method)
433435
Map<String, Map<String, MethodInfo>> bundleMethodsMap = new HashMap<>();
@@ -546,8 +548,8 @@ public String apply(String id) {
546548
results, excludes, incorrectExpressions, expression, index,
547549
implicitClassToMembersUsed, templateIdToPathFun, generatedIdsToMatches,
548550
extensionMethodExcludes, checkedTemplate, lookupConfig, namedBeans,
549-
namespaceTemplateData,
550-
regularExtensionMethods, namespaceExtensionMethods, assignableCache);
551+
namespaceTemplateData, regularExtensionMethods, namespaceExtensionMethods,
552+
assignableCache, hierarchyIndexer);
551553
Match match = results.get(param.toOriginalString());
552554
if (match != null && !match.isEmpty() && !Types.isAssignableFrom(match.type(),
553555
methodParams.get(idx), index, assignableCache)) {

extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java

+17-13
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
import io.quarkus.qute.deployment.TypeCheckExcludeBuildItem.TypeCheck;
126126
import io.quarkus.qute.deployment.TypeInfos.Info;
127127
import io.quarkus.qute.deployment.Types.AssignableInfo;
128+
import io.quarkus.qute.deployment.Types.HierarchyIndexer;
128129
import io.quarkus.qute.generator.ExtensionMethodGenerator;
129130
import io.quarkus.qute.generator.ExtensionMethodGenerator.NamespaceResolverCreator;
130131
import io.quarkus.qute.generator.ExtensionMethodGenerator.NamespaceResolverCreator.ResolveCreator;
@@ -856,6 +857,7 @@ public String apply(String id) {
856857

857858
LookupConfig lookupConfig = new FixedLookupConfig(index, initDefaultMembersFilter(), false);
858859
Map<DotName, AssignableInfo> assignableCache = new HashMap<>();
860+
HierarchyIndexer hierarchyIndexer = new HierarchyIndexer(index);
859861
int expressionsValidated = 0;
860862

861863
for (TemplateAnalysis templateAnalysis : templatesAnalysis.getAnalysis()) {
@@ -884,7 +886,7 @@ public String apply(String id) {
884886
incorrectExpressions, expression, index, implicitClassToMembersUsed, templateIdToPathFun,
885887
generatedIdsToMatches, extensionMethodExcludes,
886888
checkedTemplate, lookupConfig, namedBeans, namespaceTemplateData, regularExtensionMethods,
887-
namespaceExtensionMethods, assignableCache);
889+
namespaceExtensionMethods, assignableCache, hierarchyIndexer);
888890
generatedIdsToMatches.put(expression.getGeneratedId(), match);
889891
}
890892

@@ -894,7 +896,7 @@ public String apply(String id) {
894896
if (defaultValue != null) {
895897
Match match;
896898
if (defaultValue.isLiteral()) {
897-
match = new Match(index, assignableCache);
899+
match = new Match(hierarchyIndexer, assignableCache);
898900
setMatchValues(match, defaultValue, generatedIdsToMatches, index);
899901
} else {
900902
match = generatedIdsToMatches.get(defaultValue.getGeneratedId());
@@ -1001,7 +1003,7 @@ static Match validateNestedExpressions(QuteConfig config, TemplateAnalysis templ
10011003
Map<String, TemplateDataBuildItem> namespaceTemplateData,
10021004
List<TemplateExtensionMethodBuildItem> regularExtensionMethods,
10031005
Map<String, List<TemplateExtensionMethodBuildItem>> namespaceExtensionMethods,
1004-
Map<DotName, AssignableInfo> assignableCache) {
1006+
Map<DotName, AssignableInfo> assignableCache, HierarchyIndexer hierarchyIndexer) {
10051007

10061008
LOGGER.debugf("Validate %s from %s", expression, expression.getOrigin());
10071009

@@ -1017,13 +1019,14 @@ static Match validateNestedExpressions(QuteConfig config, TemplateAnalysis templ
10171019
validateNestedExpressions(config, templateAnalysis, null, results, excludes,
10181020
incorrectExpressions, param, index, implicitClassToMembersUsed, templateIdToPathFun,
10191021
generatedIdsToMatches, extensionMethodExcludes, checkedTemplate, lookupConfig, namedBeans,
1020-
namespaceTemplateData, regularExtensionMethods, namespaceExtensionMethods, assignableCache);
1022+
namespaceTemplateData, regularExtensionMethods, namespaceExtensionMethods, assignableCache,
1023+
hierarchyIndexer);
10211024
}
10221025
}
10231026
}
10241027
}
10251028

1026-
Match match = new Match(index, assignableCache);
1029+
Match match = new Match(hierarchyIndexer, assignableCache);
10271030

10281031
String namespace = expression.getNamespace();
10291032
TypeInfos.TypeInfo dataNamespaceExpTypeInfo = null;
@@ -2365,14 +2368,14 @@ static Type extractMatchType(Set<Type> closure, DotName matchName, Function<Type
23652368

23662369
static class Match {
23672370

2368-
private final IndexView index;
2371+
private final HierarchyIndexer indexer;
23692372
private final Map<DotName, AssignableInfo> assignableCache;
23702373

23712374
private ClassInfo clazz;
23722375
private Type type;
23732376

2374-
Match(IndexView index, Map<DotName, AssignableInfo> assignableCache) {
2375-
this.index = index;
2377+
Match(HierarchyIndexer indexer, Map<DotName, AssignableInfo> assignableCache) {
2378+
this.indexer = indexer;
23762379
this.assignableCache = assignableCache;
23772380
}
23782381

@@ -2428,19 +2431,20 @@ boolean isEmpty() {
24282431
void autoExtractType() {
24292432
if (clazz != null) {
24302433
// Make sure that hierarchy of the matching class is indexed
2431-
Types.indexHierarchy(clazz, index);
2432-
boolean hasCompletionStage = Types.isAssignableFrom(Names.COMPLETION_STAGE, clazz.name(), index,
2434+
indexer.indexHierarchy(clazz);
2435+
boolean hasCompletionStage = Types.isAssignableFrom(Names.COMPLETION_STAGE, clazz.name(), indexer.index,
24332436
assignableCache);
24342437
boolean hasUni = hasCompletionStage ? false
2435-
: Types.isAssignableFrom(Names.UNI, clazz.name(), index, assignableCache);
2438+
: Types.isAssignableFrom(Names.UNI, clazz.name(), indexer.index, assignableCache);
24362439
if (hasCompletionStage || hasUni) {
24372440
Set<Type> closure = Types.getTypeClosure(clazz, Types.buildResolvedMap(
2438-
getParameterizedTypeArguments(), getTypeParameters(), new HashMap<>(), index), index);
2441+
getParameterizedTypeArguments(), getTypeParameters(), new HashMap<>(), indexer.index),
2442+
indexer.index);
24392443
// CompletionStage<List<Item>> => List<Item>
24402444
// Uni<List<String>> => List<String>
24412445
this.type = extractMatchType(closure, hasCompletionStage ? Names.COMPLETION_STAGE : Names.UNI,
24422446
FIRST_PARAM_TYPE_EXTRACT_FUN);
2443-
this.clazz = index.getClassByName(type.name());
2447+
this.clazz = indexer.index.getClassByName(type.name());
24442448
}
24452449
}
24462450
}

extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/Types.java

+75-45
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package io.quarkus.qute.deployment;
22

3-
import java.lang.reflect.Modifier;
43
import java.util.Collection;
54
import java.util.Collections;
65
import java.util.HashMap;
76
import java.util.HashSet;
87
import java.util.List;
98
import java.util.Map;
9+
import java.util.Objects;
1010
import java.util.Set;
11+
import java.util.stream.Collectors;
1112

1213
import org.jboss.jandex.ClassInfo;
1314
import org.jboss.jandex.DotName;
@@ -17,13 +18,16 @@
1718
import org.jboss.jandex.Type;
1819
import org.jboss.jandex.Type.Kind;
1920
import org.jboss.jandex.TypeVariable;
21+
import org.jboss.logging.Logger;
2022

2123
import io.quarkus.arc.processor.DotNames;
2224

2325
public final class Types {
2426

2527
static final String JAVA_LANG_PREFIX = "java.lang.";
2628

29+
private static final Logger LOG = Logger.getLogger(Types.class);
30+
2731
static Set<Type> getTypeClosure(ClassInfo classInfo, Map<TypeVariable, Type> resolvedTypeParameters,
2832
IndexView index) {
2933
Set<Type> types = new HashSet<>();
@@ -138,58 +142,99 @@ static boolean isAssignableFrom(Type type1, Type type2, IndexView index, Map<Dot
138142

139143
static class AssignableInfo {
140144

145+
static AssignableInfo from(ClassInfo classInfo, IndexView index) {
146+
if (classInfo.isInterface()) {
147+
return new AssignableInfo(null, toNames(index.getAllKnownImplementors(classInfo.name())),
148+
toNames(index.getAllKnownSubinterfaces(classInfo.name())));
149+
} else {
150+
return new AssignableInfo(toNames(index.getAllKnownSubclasses(classInfo.name())), null, null);
151+
}
152+
}
153+
154+
private static Set<DotName> toNames(Collection<ClassInfo> classes) {
155+
return classes.stream().map(ClassInfo::name).collect(Collectors.toSet());
156+
}
157+
141158
final Set<DotName> subclasses;
142159
final Set<DotName> implementors;
143-
final Set<DotName> extendingInterfaces;
160+
final Set<DotName> subInterfaces;
144161

145-
public AssignableInfo(Collection<ClassInfo> subclasses, Collection<ClassInfo> implementors,
146-
Set<DotName> extendingInterfaces) {
147-
this.subclasses = new HashSet<>();
148-
for (ClassInfo subclass : subclasses) {
149-
this.subclasses.add(subclass.name());
150-
}
151-
this.implementors = new HashSet<>();
152-
for (ClassInfo implementor : implementors) {
153-
this.implementors.add(implementor.name());
154-
}
155-
this.extendingInterfaces = extendingInterfaces;
162+
AssignableInfo(Set<DotName> subclasses, Set<DotName> implementors, Set<DotName> subInterfaces) {
163+
this.subclasses = subclasses;
164+
this.implementors = implementors;
165+
this.subInterfaces = subInterfaces;
156166
}
157167

158168
boolean isAssignableFrom(DotName clazz) {
159-
return subclasses.contains(clazz) || implementors.contains(clazz) || extendingInterfaces.contains(clazz);
169+
if (subclasses != null && subclasses.contains(clazz)) {
170+
return true;
171+
}
172+
if (implementors != null && implementors.contains(clazz)) {
173+
return true;
174+
}
175+
return subInterfaces != null && subInterfaces.contains(clazz);
160176
}
161177

162178
}
163179

164-
static boolean isAssignableFrom(DotName class1, DotName class2, IndexView index,
180+
static boolean isAssignableFrom(DotName className1, DotName className2, IndexView index,
165181
Map<DotName, AssignableInfo> assignableCache) {
166182
// java.lang.Object is assignable from any type
167-
if (class1.equals(DotNames.OBJECT)) {
183+
if (className1.equals(DotNames.OBJECT)) {
168184
return true;
169185
}
170186
// type1 is the same as type2
171-
if (class1.equals(class2)) {
187+
if (className1.equals(className2)) {
172188
return true;
173189
}
174-
AssignableInfo assignableInfo = assignableCache.get(class1);
190+
ClassInfo class1 = index.getClassByName(className1);
191+
AssignableInfo assignableInfo = assignableCache.get(className1);
175192
if (assignableInfo == null) {
176-
assignableInfo = new AssignableInfo(index.getAllKnownSubclasses(class1), index.getAllKnownImplementors(class1),
177-
getAllInterfacesExtending(class1, index));
178-
assignableCache.put(class1, assignableInfo);
193+
// No cached info
194+
assignableInfo = AssignableInfo.from(class1, index);
195+
assignableCache.put(className1, assignableInfo);
196+
return assignableInfo.isAssignableFrom(className2);
197+
} else {
198+
if (assignableInfo.isAssignableFrom(className2)) {
199+
return true;
200+
}
201+
// Cached info does not match - try to update the assignable info (a computing index is used)
202+
assignableInfo = AssignableInfo.from(class1, index);
203+
if (assignableInfo.isAssignableFrom(className2)) {
204+
// Update the cache
205+
assignableCache.put(className1, assignableInfo);
206+
return true;
207+
}
179208
}
180-
return assignableInfo.isAssignableFrom(class2);
209+
return false;
181210
}
182211

183-
static void indexHierarchy(ClassInfo classInfo, IndexView index) {
184-
// Interfaces
185-
for (DotName interfaceName : classInfo.interfaceNames()) {
186-
index.getClassByName(interfaceName);
212+
// This class is not thread-safe
213+
static class HierarchyIndexer {
214+
215+
final IndexView index;
216+
final Set<DotName> processed;
217+
218+
public HierarchyIndexer(IndexView index) {
219+
this.index = Objects.requireNonNull(index);
220+
this.processed = new HashSet<>();
187221
}
188-
// Superclass
189-
DotName superName = classInfo.superName();
190-
if (superName != null && !superName.equals(DotNames.OBJECT)) {
191-
indexHierarchy(index.getClassByName(superName), index);
222+
223+
void indexHierarchy(ClassInfo classInfo) {
224+
if (classInfo != null && processed.add(classInfo.name())) {
225+
LOG.debugf("Index hierarchy of: %s", classInfo);
226+
// Interfaces
227+
for (DotName interfaceName : classInfo.interfaceNames()) {
228+
indexHierarchy(index.getClassByName(interfaceName));
229+
}
230+
// Superclass
231+
DotName superName = classInfo.superName();
232+
if (superName != null && !superName.equals(DotNames.OBJECT)) {
233+
indexHierarchy(index.getClassByName(superName));
234+
}
235+
}
192236
}
237+
193238
}
194239

195240
static Type box(Type type) {
@@ -222,19 +267,4 @@ static Type box(Primitive primitive) {
222267
}
223268
}
224269

225-
private static Set<DotName> getAllInterfacesExtending(DotName target, IndexView index) {
226-
Set<DotName> ret = new HashSet<>();
227-
for (ClassInfo clazz : index.getKnownClasses()) {
228-
if (!Modifier.isInterface(clazz.flags())
229-
|| clazz.isAnnotation()
230-
|| clazz.isEnum()) {
231-
continue;
232-
}
233-
if (clazz.interfaceNames().contains(target)) {
234-
ret.add(clazz.name());
235-
}
236-
}
237-
return ret;
238-
}
239-
240270
}

0 commit comments

Comments
 (0)