RecordAugmentProvider: add annotations to fields and methods according to JLS

GitOrigin-RevId: f14e521ab157336873ec88889b6c44ac4af70953
This commit is contained in:
Roman.Ivanov
2019-12-17 11:02:18 +00:00
committed by intellij-monorepo-bot
parent b2e5cfc647
commit 81da6b615b
4 changed files with 83 additions and 13 deletions
@@ -1,6 +1,7 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.psi.impl;
import com.intellij.codeInsight.AnnotationTargetUtil;
import com.intellij.psi.*;
import com.intellij.psi.augment.PsiAugmentProvider;
import com.intellij.psi.impl.light.LightMethod;
@@ -9,9 +10,11 @@ import com.intellij.psi.impl.light.LightRecordMethod;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static com.intellij.util.ObjectUtils.tryCast;
public class RecordAugmentProvider extends PsiAugmentProvider {
@NotNull
@@ -36,9 +39,9 @@ public class RecordAugmentProvider extends PsiAugmentProvider {
PsiElementFactory factory = JavaPsiFacade.getInstance(element.getProject()).getElementFactory();
ArrayList<Psi> methods = new ArrayList<>(components.length);
for (PsiRecordComponent component : components) {
String name = component.getName();
if (name == null) continue;
LightMethod method = new LightRecordMethod(element.getManager(), factory.createMethod(name, component.getType()), aClass, component);
PsiMethod recordMethod = createRecordMethod(component, factory);
if (recordMethod == null) continue;
LightMethod method = new LightRecordMethod(element.getManager(), recordMethod, aClass, component);
//noinspection unchecked
methods.add((Psi)method);
}
@@ -64,9 +67,50 @@ public class RecordAugmentProvider extends PsiAugmentProvider {
private static PsiField createRecordField(@NotNull PsiRecordComponent component, @NotNull PsiElementFactory factory) {
String name = component.getName();
if (name == null) return null;
PsiTypeElement typeElement = component.getTypeElement();
if (typeElement == null) return null;
PsiClass aClass = factory.createClassFromText("private final " + typeElement.getText() + " " + name + ";", null);
String typeText = getTypeText(component, RecordAugmentProvider::hasTargetApplicableForField);
if (typeText == null) return null;
PsiClass aClass = factory.createClassFromText("private final " + typeText + " " + name + ";", null);
return aClass.getFields()[0];
}
@Nullable
private static PsiMethod createRecordMethod(@NotNull PsiRecordComponent component, @NotNull PsiElementFactory factory) {
String name = component.getName();
if (name == null) return null;
String typeText = getTypeText(component, RecordAugmentProvider::hasTargetApplicableForMethod);
if (typeText == null) return null;
PsiClass aClass = factory.createClassFromText("public " + typeText + " " + name + "(){}", null);
return aClass.getMethods()[0];
}
@Nullable
private static String getTypeText(@NotNull PsiRecordComponent component, Predicate<PsiAnnotation> annotationPredicate) {
PsiTypeElement typeElement = component.getTypeElement();
if (typeElement == null) return null;
String annotations = Arrays.stream(component.getAnnotations())
.filter(annotationPredicate)
.map(annotation -> annotation.getText())
.collect(Collectors.joining(" "));
return annotations + " " + typeElement.getText();
}
private static boolean hasTargetApplicableForField(PsiAnnotation annotation) {
Set<PsiAnnotation.TargetType> targets = getTargets(annotation);
if (targets == null) return false;
return targets.contains(PsiAnnotation.TargetType.TYPE) || targets.contains(PsiAnnotation.TargetType.FIELD);
}
private static boolean hasTargetApplicableForMethod(PsiAnnotation annotation) {
Set<PsiAnnotation.TargetType> targets = getTargets(annotation);
if (targets == null) return false;
return targets.contains(PsiAnnotation.TargetType.TYPE) || targets.contains(PsiAnnotation.TargetType.METHOD);
}
private static Set<PsiAnnotation.TargetType> getTargets(PsiAnnotation annotation) {
PsiJavaCodeReferenceElement element = annotation.getNameReferenceElement();
if (element == null) return null;
PsiClass annotationClass = tryCast(element.resolve(), PsiClass.class);
if (annotationClass == null) return null;
return AnnotationTargetUtil.getAnnotationTargets(annotationClass);
}
}
@@ -1,7 +1,17 @@
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
public class Test1 {
record A(int value) {}
record A(@F @M int value) {}
void test(A a){
a.<caret>value();
}
}
@Target(value={FIELD})
@interface F{}
@Target(value={METHOD})
@interface M{}
@@ -1,5 +1,15 @@
record A(int value) {
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
record A(@F @M int value) {
void test(){
<caret>value
}
}
@Target(value={FIELD})
@interface F{}
@Target(value={METHOD})
@interface M{}
@@ -22,7 +22,8 @@ public class ResolveRecordMethodsTest extends LightResolveTestCase {
public void testRecordComponent() {
PsiElement target = resolve();
assertTrue(target instanceof PsiMethod);
assertEquals(PsiType.INT, ((PsiMethod)target).getReturnType());
PsiMethod targetMethod = (PsiMethod)target;
assertEquals(PsiType.INT, targetMethod.getReturnType());
PsiJavaFile file = (PsiJavaFile)getFile();
@@ -31,12 +32,15 @@ public class ResolveRecordMethodsTest extends LightResolveTestCase {
PsiRecordComponent[] components = record.getRecordComponents();
assertSize(1, components);
assertEquals(target.getTextOffset(), components[0].getTextOffset());
assertFalse(targetMethod.hasAnnotation("F"));
assertTrue(targetMethod.hasAnnotation("M"));
}
public void testRecordField() {
PsiElement target = resolve();
assertTrue(target instanceof PsiField);
assertEquals(PsiType.INT, ((PsiField)target).getType());
PsiField targetField = (PsiField)target;
assertEquals(PsiType.INT, targetField.getType());
PsiJavaFile file = (PsiJavaFile)getFile();
@@ -44,5 +48,7 @@ public class ResolveRecordMethodsTest extends LightResolveTestCase {
PsiRecordComponent[] components = record.getRecordComponents();
assertSize(1, components);
assertEquals(target.getTextOffset(), components[0].getTextOffset());
assertTrue(targetField.hasAnnotation("F"));
assertFalse(targetField.hasAnnotation("M"));
}
}