OldJetBrainsAnnotationInspection: Converts Java 5 nullability annotations on arrays to Java 8 style

GitOrigin-RevId: 8787ffe250d977f469e8342d1e4c5b59e76c004f
This commit is contained in:
Tagir Valeev
2020-01-01 09:41:29 +00:00
committed by intellij-monorepo-bot
parent 8718df4f50
commit 2268c19ea7
3 changed files with 110 additions and 0 deletions
@@ -123,6 +123,11 @@
enabledByDefault="true"
level="WARNING"
implementationClass="org.jetbrains.idea.devkit.inspections.PostfixTemplateDescriptionNotFoundInspection"/>
<localInspection language="JAVA" displayName="Java 5 nullability annotation on array"
groupPath="Plugin DevKit" groupKey="inspections.group.description.file"
enabledByDefault="false"
level="WARNING" isInternal="true"
implementationClass="org.jetbrains.idea.devkit.inspections.OldJetBrainsAnnotationInspection"/>
<!--suppress PluginXmlCapitalization -->
<localInspection shortName="ComponentRegistrationProblems"
key="inspections.registration.problems.name"
@@ -0,0 +1,8 @@
<html>
<body>
Converts Java 5 nullability annotations on arrays to Java 8 style
(e.g. <code>@NotNull String[] arr</code> &rarr; <code>String @NotNull [] arr</code>). Note that
after applying the fix the code will be non-compilable. To make it compilable you should replace
<code>org.jetbrains:annotations-java5</code> to <code>org.jetbrains:annotations</code> in module dependencies.
</body>
</html>
@@ -0,0 +1,97 @@
// Copyright 2000-2020 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 org.jetbrains.idea.devkit.inspections;
import com.intellij.codeInsight.AnnotationTargetUtil;
import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
public class OldJetBrainsAnnotationInspection extends AbstractBaseJavaLocalInspectionTool {
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override
public void visitAnnotation(PsiAnnotation annotation) {
PsiJavaCodeReferenceElement nameElement = annotation.getNameReferenceElement();
if (nameElement == null) return;
String name = nameElement.getText();
if (!name.equals("Nullable") && !name.equals("NotNull")) return;
PsiClass annotationClass = ObjectUtils.tryCast(nameElement.resolve(), PsiClass.class);
if (annotationClass == null) return;
String qualifiedName = annotationClass.getQualifiedName();
if (qualifiedName == null || !"org.jetbrains.annotations".equals(StringUtil.getPackageName(qualifiedName))) return;
Set<PsiAnnotation.TargetType> targets = AnnotationTargetUtil.getAnnotationTargets(annotationClass);
if (targets == null || targets.contains(PsiAnnotation.TargetType.TYPE_USE)) return;
PsiAnnotationOwner owner = annotation.getOwner();
PsiTypeElement typeElement = findTypeElement(owner);
if (typeElement == null) return;
PsiType type = typeElement.getType();
if (!(type instanceof PsiArrayType)) return;
PsiAnnotation.TargetType target =
AnnotationTargetUtil.findAnnotationTarget(annotation, AnnotationTargetUtil.getTargetsForLocation(owner));
if (target == PsiAnnotation.TargetType.TYPE_USE) return;
holder.registerProblem(annotation, "Old-style array annotation", new OldJetBrainsAnnotationFix());
}
};
}
@Contract("null -> null")
@Nullable
private static PsiTypeElement findTypeElement(PsiAnnotationOwner owner) {
if (!(owner instanceof PsiModifierList)) return null;
PsiElement parent = ((PsiModifierList)owner).getParent();
PsiTypeElement typeElement;
if (parent instanceof PsiVariable) {
typeElement = ((PsiVariable)parent).getTypeElement();
}
else if (parent instanceof PsiMethod) {
typeElement = ((PsiMethod)parent).getReturnTypeElement();
}
else {
return null;
}
if (typeElement == null) return null;
return typeElement;
}
private static class OldJetBrainsAnnotationFix implements LocalQuickFix {
@Nls(capitalization = Nls.Capitalization.Sentence)
@NotNull
@Override
public String getFamilyName() {
return "Convert to new-style annotation";
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiAnnotation annotation = ObjectUtils.tryCast(descriptor.getStartElement(), PsiAnnotation.class);
if (annotation == null) return;
PsiAnnotationOwner owner = annotation.getOwner();
PsiTypeElement typeElement = findTypeElement(owner);
if (typeElement == null) return;
PsiAnnotation copy = (PsiAnnotation)annotation.copy();
PsiType newType = typeElement.getType().annotate(new TypeAnnotationProvider() {
@NotNull
@Override
public PsiAnnotation[] getAnnotations() {
return new PsiAnnotation[]{copy};
}
});
PsiTypeElement newTypeElement = JavaPsiFacade.getElementFactory(project).createTypeElementFromText(newType.getCanonicalText(true), typeElement);
typeElement.replace(newTypeElement);
annotation.delete();
}
}
}