diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/ReplaceConstructorWithFactoryAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/ReplaceConstructorWithFactoryAction.java
index 40a204e6c92f..22a804507088 100644
--- a/java/java-impl/src/com/intellij/codeInsight/intention/ReplaceConstructorWithFactoryAction.java
+++ b/java/java-impl/src/com/intellij/codeInsight/intention/ReplaceConstructorWithFactoryAction.java
@@ -238,18 +238,14 @@ public class ReplaceConstructorWithFactoryAction implements ModCommandAction {
PsiClass containingClass = ClassUtils.getContainingClass(element);
if (!isSuitableClass(containingClass)) return null;
PsiElement lBrace = containingClass.getLBrace();
- if (lBrace != null && element.getTextRange().getStartOffset() >= lBrace.getTextRange().getStartOffset()) return null;
+ if (lBrace == null || element.getTextRange().getStartOffset() >= lBrace.getTextRange().getStartOffset()) return null;
if (containingClass.getConstructors().length > 0) return null;
return containingClass;
}
private static boolean isSuitableClass(PsiClass containingClass) {
- return containingClass != null &&
- PsiTreeUtil.getParentOfType(containingClass, PsiImplicitClass.class, false) == null &&
- !containingClass.isInterface() &&
- !containingClass.isEnum() &&
- !containingClass.isRecord() &&
- !containingClass.hasModifierProperty(PsiModifier.ABSTRACT) &&
+ return containingClass != null && !containingClass.isInterface() && !containingClass.isEnum() && !containingClass.isRecord() &&
+ !(containingClass instanceof PsiImplicitClass) && !containingClass.hasModifierProperty(PsiModifier.ABSTRACT) &&
containingClass.getQualifiedName() != null;
}
}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingStringTemplates/StringTemplatesJava22.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingStringTemplates/StringTemplatesJava22.java
new file mode 100644
index 000000000000..682b1ff1dd2e
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingStringTemplates/StringTemplatesJava22.java
@@ -0,0 +1,123 @@
+class X {
+
+ void processorMissing() {
+ System.out.println("""
+ \{1}
+ """);
+ "\{}";
+ System.out.println(NOPE."\{false}");
+ System.out.println(RAW."\{false}");
+ }
+
+ void correct(int i) {
+ System.out.println(STR."the value is \{i}");
+ String s = STR."";
+ StringTemplate st = StringTemplate.RAW."""
+ """;
+ }
+
+ void wrongType(String foo) {
+ String s = StringTemplate.RAW."""
+ this: \{foo}
+ """;
+
+ var x = (java.io.Serializable & StringTemplate.Processor)null;
+ java.util.ArrayList v = x."asdf";
+ String t = x."reticulation";
+ }
+
+ String unresolvedValues() {
+ return STR."\{logic} \{proportion}";
+ }
+
+ interface MyProcessor extends StringTemplate.Processor {}
+
+ String raw(StringTemplate.Processor processor, MyProcessor myProcessor) {
+ System.out.println(myProcessor."");
+ return processor."\{}\{}\{}\{}\{}\{}";
+ var z = (java.io.Serializable & StringTemplate.Processor)myProcessor;
+ System.out.println(z."");
+ }
+
+ void nested() {
+ System.out.println(STR."\{STR."\{STR."\{STR."\{STR."\{STR."\{STR.""}"}"}"}"}"}");
+ }
+
+ String badEscape() {
+ System.out.println(STR."b\ad \{} esc\ape 1");
+ System.out.println(STR. """
+ b\ad \{} esc\ape 2
+ """);
+ System.out.println(STR."\{}unclosed);
+ return STR."\{} \uX";
+ }
+
+ static class Covariant implements StringTemplate.Processor