Skip to content

Commit e5bfb5a

Browse files
committed
Release 3.9.7
1 parent a8461dd commit e5bfb5a

File tree

5 files changed

+106
-62
lines changed

5 files changed

+106
-62
lines changed

build.gradle.kts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import org.jetbrains.changelog.markdownToHTML
33
plugins {
44
id("java")
55
id("org.jetbrains.kotlin.jvm") version "2.0.21"
6-
id("org.jetbrains.intellij.platform") version "2.1.0"
6+
id("org.jetbrains.intellij.platform") version "2.5.0"
77
id("org.jetbrains.changelog") version "2.2.1"
88
}
99

1010
group = "dev.rollczi"
11-
version = "3.9.0"
11+
version = "3.9.7"
1212

1313
repositories {
1414
mavenCentral()
@@ -23,7 +23,7 @@ repositories {
2323
dependencies {
2424
implementation("dev.rollczi:litecommands-framework:${version}")
2525
intellijPlatform {
26-
intellijIdeaCommunity("2024.2.3")
26+
intellijIdeaCommunity("2025.1")
2727
bundledPlugins("com.intellij.java", "org.jetbrains.kotlin")
2828
instrumentationTools()
2929
pluginVerifier()
@@ -42,7 +42,7 @@ intellijPlatform {
4242

4343
ideaVersion {
4444
sinceBuild = "242"
45-
untilBuild = "243.*"
45+
untilBuild = "251.*"
4646
}
4747
}
4848

src/main/java/dev/rollczi/litecommands/intellijplugin/annotation/AnnotationFactory.java

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,24 @@
2020
import java.lang.reflect.Proxy;
2121
import java.lang.reflect.UndeclaredThrowableException;
2222
import java.util.ArrayList;
23-
import java.util.Arrays;
2423
import java.util.List;
2524
import java.util.Optional;
26-
import java.util.stream.Collectors;
2725

2826
@SuppressWarnings("UnstableApiUsage")
2927
public class AnnotationFactory {
3028

31-
public static <A extends Annotation> List<A> fromAnnotatedPsi(Class<A> annotationClass, PsiModifierListOwner element) {
32-
return Arrays.stream(element.getAnnotations())
33-
.filter(psiAnnotation -> psiAnnotation.hasQualifiedName(annotationClass.getName()))
34-
.flatMap(psiAnnotation -> fromPsiAnnotation(annotationClass, psiAnnotation).stream())
35-
.map(holder -> holder.asAnnotation())
36-
.collect(Collectors.toList());
37-
}
38-
39-
public static <A extends Annotation> List<AnnotationHolder<A>> from(Class<A> annotationClass, PsiModifierListOwner element) {
40-
return Arrays.stream(element.getAnnotations())
41-
.filter(psiAnnotation -> psiAnnotation.hasQualifiedName(annotationClass.getName()))
42-
.flatMap(psiAnnotation -> fromPsiAnnotation(annotationClass, psiAnnotation).stream())
43-
.collect(Collectors.toList());
29+
public static <A extends Annotation> Optional<A> fromAsAnnotation(Class<A> annotationClass, PsiModifierListOwner element) {
30+
return Optional.ofNullable(element.getAnnotation(annotationClass.getName()))
31+
.flatMap(annotation -> from(annotationClass, annotation))
32+
.map(holder -> holder.asAnnotation());
4433
}
4534

4635
@SuppressWarnings("unchecked")
47-
public static <A extends Annotation> Optional<AnnotationHolder<A>> fromPsiAnnotation(Class<A> annotationClass, PsiAnnotation psiAnnotation) {
36+
public static <A extends Annotation> Optional<AnnotationHolder<A>> from(Class<A> annotationClass, PsiAnnotation psiAnnotation) {
37+
if (!annotationClass.getName().equals(psiAnnotation.getQualifiedName())) {
38+
return Optional.empty();
39+
}
40+
4841
try {
4942
A annotation = (A) Proxy.newProxyInstance(
5043
AnnotationFactory.class.getClassLoader(),
@@ -193,7 +186,7 @@ private Object getRealValue(JvmAnnotationAttributeValue attributeValue, Class<?>
193186
}
194187

195188
Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) Class.forName(nestedAnnotation.getQualifiedName());
196-
Object value = fromPsiAnnotation(annotationClass, (PsiAnnotation) nestedAnnotation)
189+
Object value = from(annotationClass, (PsiAnnotation) nestedAnnotation)
197190
.orElseThrow(() -> new RuntimeException("Cannot create annotation for " + nestedAnnotation.getClass().getName()));
198191

199192

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package dev.rollczi.litecommands.intellijplugin.api.psijava;
22

3+
import com.intellij.lang.jvm.annotation.JvmAnnotationConstantValue;
4+
import com.intellij.psi.PsiAnnotation;
5+
import com.intellij.psi.PsiClass;
36
import com.intellij.psi.PsiMethod;
47
import com.intellij.psi.PsiParameter;
58
import dev.rollczi.litecommands.annotations.argument.Arg;
@@ -9,6 +12,7 @@
912
import dev.rollczi.litecommands.annotations.literal.Literal;
1013
import dev.rollczi.litecommands.annotations.optional.OptionalArg;
1114
import dev.rollczi.litecommands.annotations.quoted.Quoted;
15+
import dev.rollczi.litecommands.annotations.requirement.RequirementDefinition;
1216
import dev.rollczi.litecommands.intellijplugin.api.Argument;
1317
import dev.rollczi.litecommands.intellijplugin.api.CommandNode;
1418
import dev.rollczi.litecommands.intellijplugin.api.ExecutorNode;
@@ -17,81 +21,119 @@
1721
import dev.rollczi.litecommands.intellijplugin.util.LiteTypeChecks;
1822
import java.util.ArrayList;
1923
import java.util.List;
24+
import java.util.Objects;
2025
import java.util.Optional;
2126
import static java.util.Optional.*;
27+
import java.util.stream.Stream;
2228

2329
public class PsiJavaExecutorNode extends PsiJavaAbstractNode implements ExecutorNode {
2430

25-
26-
2731
private final static List<ArgumentMapper> ARGUMENTS_MAPPERS = List.of(
2832
// Array or Collection
29-
(node, parameter) -> {
33+
(node, parameter, annotation) -> {
3034
if (LiteTypeChecks.isArrayWrapper(parameter.getType(), parameter.getProject())) {
31-
Optional<Argument> psiJavaArgument = AnnotationFactory.from(Arg.class, parameter).stream()
32-
.findFirst()
35+
Optional<Argument> psiJavaArgument = AnnotationFactory.from(Arg.class, annotation)
3336
.map(holder -> new PsiJavaArgument(node, parameter, holder.asAnnotation().value(), PsiJavaArgument.ARRAY));
3437

3538
if (psiJavaArgument.isPresent()) {
3639
return psiJavaArgument;
3740
}
3841

39-
return AnnotationFactory.from(OptionalArg.class, parameter).stream()
40-
.findFirst()
42+
return AnnotationFactory.from(OptionalArg.class, annotation)
4143
.map(holder -> new PsiJavaArgument(node, parameter, holder.asAnnotation().value(), PsiJavaArgument.ARRAY));
4244
}
4345

4446
return empty();
4547
},
4648

4749
// Optional wrapper
48-
(node, parameter) -> {
50+
(node, parameter, annotation) -> {
4951
if (LiteTypeChecks.isOptionalWrapper(parameter.getType())) {
50-
return AnnotationFactory.from(Arg.class, parameter).stream()
51-
.findFirst()
52+
return AnnotationFactory.from(Arg.class, annotation)
5253
.map(holder -> new PsiJavaArgument(node, parameter, holder.asAnnotation().value(), PsiJavaArgument.OPTIONAL));
5354
}
5455

5556
return empty();
5657
},
5758
// Optional (nullable)
58-
(node, parameter) -> AnnotationFactory.from(OptionalArg.class, parameter).stream()
59-
.findFirst()
59+
(node, parameter, annotation) -> AnnotationFactory.from(OptionalArg.class, annotation)
6060
.map(holder -> new PsiJavaArgument(node, parameter, holder.asAnnotation().value(), PsiJavaArgument.OPTIONAL)),
6161

6262
// Quoted
63-
(node, parameter) -> {
63+
(node, parameter, annotation) -> {
6464
if (parameter.getAnnotation(Quoted.class.getName()) == null) {
6565
return empty();
6666
}
6767

68-
return AnnotationFactory.from(Arg.class, parameter).stream()
69-
.findFirst()
68+
return AnnotationFactory.from(Arg.class, annotation)
7069
.map(holder -> new PsiJavaArgument(node, parameter, holder.asAnnotation().value(), PsiJavaArgument.JOIN));
7170
},
7271
// Joined
73-
(node, parameter) -> AnnotationFactory.from(Join.class, parameter).stream()
74-
.findFirst()
72+
(node, parameter, annotation) -> AnnotationFactory.from(Join.class, annotation)
7573
.map(holder -> new PsiJavaArgument(node, parameter, holder.asAnnotation().value(), PsiJavaArgument.JOIN)),
7674

7775
// Arg
78-
(node, parameter) -> AnnotationFactory.from(Arg.class, parameter).stream()
79-
.findFirst()
76+
(node, parameter, annotation) -> AnnotationFactory.from(Arg.class, annotation)
8077
.map(holder -> new PsiJavaArgument(node, parameter, holder.asAnnotation().value(), PsiJavaArgument.ARG)),
8178

8279
// Flag
83-
(node, parameter) -> AnnotationFactory.from(Flag.class, parameter).stream()
84-
.findFirst()
80+
(node, parameter, annotation) -> AnnotationFactory.from(Flag.class, annotation)
8581
.map(holder -> new PsiJavaArgument(node, parameter, holder.asAnnotation().value(), PsiJavaArgument.STATIC_VALUE)),
8682

87-
(node, parameter) -> AnnotationFactory.from(Literal.class, parameter).stream()
88-
.findFirst()
83+
// Literal
84+
(node, parameter, annotation) -> AnnotationFactory.from(Literal.class, annotation)
8985
.map(holder -> {
9086
String[] values = holder.asAnnotation().value();
9187
return new PsiJavaArgument(node, parameter, values.length == 0 ? "" : values[0], PsiJavaArgument.STATIC_VALUE);
92-
})
88+
}),
89+
90+
// Any
91+
(node, parameter, annotation) -> {
92+
boolean isArray = LiteTypeChecks.isArrayWrapper(parameter.getType(), parameter.getProject());
93+
Optional<RequirementDefinition> definition = extractArgumentDefinition(annotation);
94+
if (definition.isPresent()) {
95+
RequirementDefinition requirementDefinition = definition.get();
96+
Optional<String> string = extractName(requirementDefinition, annotation);
97+
98+
return of(new PsiJavaArgument(node, parameter, string.orElse(""), isArray ? PsiJavaArgument.ARRAY : PsiJavaArgument.ARG));
99+
}
100+
101+
return empty();
102+
}
93103
);
94104

105+
private static Optional<String> extractName(RequirementDefinition definition, PsiAnnotation annotation) {
106+
return Stream.of(definition.nameProviders())
107+
.map(nameProvider -> annotation.findAttribute(nameProvider))
108+
.filter(Objects::nonNull)
109+
.map(jvmAnnotationAttribute -> jvmAnnotationAttribute.getAttributeValue())
110+
.filter(Objects::nonNull)
111+
.filter(jvmAnnotationAttributeValue -> jvmAnnotationAttributeValue instanceof JvmAnnotationConstantValue)
112+
.map(jvmAnnotationAttributeValue -> ((JvmAnnotationConstantValue) jvmAnnotationAttributeValue).getConstantValue())
113+
.filter(Objects::nonNull)
114+
.filter(value -> value instanceof String text && !text.isBlank())
115+
.map(value -> (String) value)
116+
.findFirst();
117+
}
118+
119+
private static Optional<RequirementDefinition> extractArgumentDefinition(PsiAnnotation annotation) {
120+
PsiClass type = annotation.resolveAnnotationType();
121+
if (type == null) {
122+
return Optional.empty();
123+
}
124+
125+
Optional<RequirementDefinition> definition = AnnotationFactory.fromAsAnnotation(RequirementDefinition.class, type);
126+
if (definition.isEmpty()) {
127+
return Optional.empty();
128+
}
129+
130+
if (definition.get().type() == RequirementDefinition.Type.ARGUMENT) {
131+
return definition;
132+
}
133+
134+
return Optional.empty();
135+
}
136+
95137
private final PsiJavaCommandNode parent;
96138
private final PsiMethod psiMethod;
97139

@@ -111,12 +153,13 @@ public List<Argument> arguments() {
111153
List<Argument> arguments = new ArrayList<>();
112154

113155
for (PsiParameter parameter : psiMethod.getParameterList().getParameters()) {
114-
for (ArgumentMapper mapper : ARGUMENTS_MAPPERS) {
115-
Optional<Argument> optional = mapper.map(this, parameter);
116-
117-
if (optional.isPresent()) {
118-
arguments.add(optional.get());
119-
break;
156+
for (PsiAnnotation annotation : parameter.getAnnotations()) {
157+
for (ArgumentMapper mapper : ARGUMENTS_MAPPERS) {
158+
Optional<Argument> optional = mapper.map(this, parameter, annotation);
159+
if (optional.isPresent()) {
160+
arguments.add(optional.get());
161+
break;
162+
}
120163
}
121164
}
122165
}
@@ -130,7 +173,7 @@ public NavigatableReference navigatable() {
130173
}
131174

132175
interface ArgumentMapper {
133-
Optional<Argument> map(PsiJavaExecutorNode node, PsiParameter parameter);
176+
Optional<Argument> map(PsiJavaExecutorNode node, PsiParameter parameter, PsiAnnotation annotation);
134177
}
135178

136179
}

src/main/java/dev/rollczi/litecommands/intellijplugin/inspection/annotation/LiteNullabilityAnnotationPackage.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import com.intellij.codeInsight.Nullability;
44
import com.intellij.codeInsight.NullabilityAnnotationInfo;
55
import com.intellij.codeInsight.annoPackages.AnnotationPackageSupport;
6+
import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute;
7+
import com.intellij.lang.jvm.annotation.JvmAnnotationAttributeValue;
8+
import com.intellij.lang.jvm.annotation.JvmAnnotationConstantValue;
69
import com.intellij.psi.PsiAnnotation;
710
import com.intellij.psi.PsiElement;
811
import dev.rollczi.litecommands.annotations.argument.Arg;
@@ -38,19 +41,25 @@ public class LiteNullabilityAnnotationPackage implements AnnotationPackageSuppor
3841

3942
@Override
4043
public @Nullable NullabilityAnnotationInfo getNullabilityByContainerAnnotation(@NotNull PsiAnnotation anno, @NotNull PsiElement context, PsiAnnotation.TargetType @NotNull [] types, boolean superPackage) {
41-
Optional<AnnotationHolder<Arg>> optionalArg = AnnotationFactory.fromPsiAnnotation(Arg.class, anno);
44+
if (!Arg.class.getName().equals(anno.getQualifiedName())) {
45+
return null;
46+
}
4247

43-
if (optionalArg.isPresent()) {
44-
Arg arg = optionalArg.get().asAnnotation();
48+
@Nullable JvmAnnotationAttribute attribute = anno.findAttribute("nullable");
49+
if (attribute == null) {
50+
return null;
51+
}
4552

46-
return new NullabilityAnnotationInfo(
47-
anno,
48-
arg.nullable() ? Nullability.NULLABLE : Nullability.NOT_NULL,
49-
false
50-
);
53+
@Nullable JvmAnnotationAttributeValue value = attribute.getAttributeValue();
54+
if (!(value instanceof JvmAnnotationConstantValue constantValue)) {
55+
return null;
56+
}
57+
58+
if (!(constantValue.getConstantValue() instanceof Boolean nullable)) {
59+
return null;
5160
}
5261

53-
return null;
62+
return new NullabilityAnnotationInfo(anno, nullable ? Nullability.NULLABLE : Nullability.NOT_NULL, false);
5463
}
5564

5665
}

src/main/java/dev/rollczi/litecommands/intellijplugin/inspection/parameter/ParameterMixedAnnotationsInspection.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ public class ParameterMixedAnnotationsInspection extends LiteInspection {
4040
OptionalArg.class.getName(),
4141
Flag.class.getName(),
4242
Join.class.getName(),
43-
Literal.class.getName(),
4443
Varargs.class.getName()
4544
);
4645

0 commit comments

Comments
 (0)