mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-05-06 05:10:22 +07:00
Improved type annotation support
PsiTypeElementImpl#addAnnotation implemented AddAnnotationPsiFix, NullableNotNullManager adjusted Fixes IDEA-232258 "Annotate overridden method parameters @NotNull" erroneously adds notNull to the param, not its type Fixes IDEA-232565 Intention "Annotate overriding methods as NotNull" doesn't respect "type use" Also, AddAnnotationPsiFix can be applied in batch now when annotations are not external. GitOrigin-RevId: 0b652d3b032ed0d1c701beeda102c5e3c841762c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ba85ab49e2
commit
2c486b2d0a
@@ -1,10 +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.codeInsight.intention;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.ExternalAnnotationsManager;
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.codeInsight.*;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationsHighlightUtil;
|
||||
import com.intellij.codeInsight.intention.impl.BaseIntentionAction;
|
||||
import com.intellij.codeInspection.LocalQuickFixOnPsiElement;
|
||||
@@ -34,6 +31,7 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement {
|
||||
private final String[] myAnnotationsToRemove;
|
||||
private final PsiNameValuePair[] myPairs; // not used when registering local quick fix
|
||||
protected final String myText;
|
||||
private final ExternalAnnotationsManager.AnnotationPlace myAnnotationPlace;
|
||||
|
||||
public AddAnnotationPsiFix(@NotNull String fqn,
|
||||
@NotNull PsiModifierListOwner modifierListOwner,
|
||||
@@ -46,6 +44,7 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement {
|
||||
ObjectUtils.assertAllElementsNotNull(annotationsToRemove);
|
||||
myAnnotationsToRemove = annotationsToRemove;
|
||||
myText = calcText(modifierListOwner, myAnnotation);
|
||||
myAnnotationPlace = choosePlace(modifierListOwner);
|
||||
}
|
||||
|
||||
public static String calcText(PsiModifierListOwner modifierListOwner, @Nullable String annotation) {
|
||||
@@ -131,7 +130,7 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement {
|
||||
|
||||
@Override
|
||||
public boolean startInWriteAction() {
|
||||
return false;
|
||||
return myAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.IN_CODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,48 +140,80 @@ public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement {
|
||||
@NotNull PsiElement endElement) {
|
||||
final PsiModifierListOwner myModifierListOwner = (PsiModifierListOwner)startElement;
|
||||
|
||||
PsiAnnotationOwner target = getTarget(project, myModifierListOwner);
|
||||
if (target == null || target.hasAnnotation(myAnnotation)) return;
|
||||
final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project);
|
||||
final PsiModifierList modifierList = myModifierListOwner.getModifierList();
|
||||
if (modifierList == null || modifierList.hasAnnotation(myAnnotation)) return;
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(myAnnotation, myModifierListOwner.getResolveScope());
|
||||
final ExternalAnnotationsManager.AnnotationPlace annotationAnnotationPlace;
|
||||
if (aClass != null && BaseIntentionAction.canModify(myModifierListOwner) &&
|
||||
(AnnotationsHighlightUtil.getRetentionPolicy(aClass) == RetentionPolicy.RUNTIME ||
|
||||
!CommonClassNames.DEFAULT_PACKAGE.equals(StringUtil.getPackageName(myAnnotation)) &&
|
||||
JavaPsiFacade.getInstance(project).getResolveHelper()//if class is already imported in current file
|
||||
.resolveReferencedClass(StringUtil.getShortName(myAnnotation), myModifierListOwner) != null)) {
|
||||
annotationAnnotationPlace = ExternalAnnotationsManager.AnnotationPlace.IN_CODE;
|
||||
}
|
||||
else {
|
||||
annotationAnnotationPlace = annotationsManager.chooseAnnotationsPlace(myModifierListOwner);
|
||||
}
|
||||
if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.NOWHERE) return;
|
||||
if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.EXTERNAL) {
|
||||
for (String fqn : myAnnotationsToRemove) {
|
||||
annotationsManager.deannotate(myModifierListOwner, fqn);
|
||||
}
|
||||
try {
|
||||
annotationsManager.annotateExternally(myModifierListOwner, myAnnotation, file, myPairs);
|
||||
}
|
||||
catch (ExternalAnnotationsManager.CanceledConfigurationException ignored) {}
|
||||
}
|
||||
else {
|
||||
final PsiFile containingFile = myModifierListOwner.getContainingFile();
|
||||
WriteCommandAction.runWriteCommandAction(project, null, null, () -> {
|
||||
removePhysicalAnnotations(myModifierListOwner, myAnnotationsToRemove);
|
||||
ExternalAnnotationsManager.AnnotationPlace place = myAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.NEED_ASK_USER ?
|
||||
annotationsManager.chooseAnnotationsPlace(myModifierListOwner) : myAnnotationPlace;
|
||||
switch (place) {
|
||||
case NOWHERE:
|
||||
return;
|
||||
case EXTERNAL:
|
||||
for (String fqn : myAnnotationsToRemove) {
|
||||
annotationsManager.deannotate(myModifierListOwner, fqn);
|
||||
}
|
||||
try {
|
||||
annotationsManager.annotateExternally(myModifierListOwner, myAnnotation, file, myPairs);
|
||||
}
|
||||
catch (ExternalAnnotationsManager.CanceledConfigurationException ignored) {
|
||||
}
|
||||
break;
|
||||
case IN_CODE:
|
||||
final PsiFile containingFile = myModifierListOwner.getContainingFile();
|
||||
WriteCommandAction.runWriteCommandAction(project, null, null, () -> {
|
||||
removePhysicalAnnotations(myModifierListOwner, myAnnotationsToRemove);
|
||||
|
||||
PsiAnnotation inserted = addPhysicalAnnotation(myAnnotation, myPairs, modifierList);
|
||||
JavaCodeStyleManager.getInstance(project).shortenClassReferences(inserted);
|
||||
}, containingFile);
|
||||
PsiAnnotation inserted = addPhysicalAnnotation(myAnnotation, myPairs, target);
|
||||
JavaCodeStyleManager.getInstance(project).shortenClassReferences(inserted);
|
||||
}, containingFile);
|
||||
|
||||
if (containingFile != file) {
|
||||
UndoUtil.markPsiFileForUndo(file);
|
||||
}
|
||||
if (containingFile != file) {
|
||||
UndoUtil.markPsiFileForUndo(file);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ExternalAnnotationsManager.AnnotationPlace choosePlace(@NotNull PsiModifierListOwner modifierListOwner) {
|
||||
Project project = modifierListOwner.getProject();
|
||||
final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project);
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(myAnnotation, modifierListOwner.getResolveScope());
|
||||
if (aClass != null && BaseIntentionAction.canModify(modifierListOwner) &&
|
||||
(AnnotationsHighlightUtil.getRetentionPolicy(aClass) == RetentionPolicy.RUNTIME ||
|
||||
!CommonClassNames.DEFAULT_PACKAGE.equals(StringUtil.getPackageName(myAnnotation)) &&
|
||||
JavaPsiFacade.getInstance(project).getResolveHelper()//if class is already imported in current file
|
||||
.resolveReferencedClass(StringUtil.getShortName(myAnnotation), modifierListOwner) != null)) {
|
||||
return ExternalAnnotationsManager.AnnotationPlace.IN_CODE;
|
||||
}
|
||||
return annotationsManager.chooseAnnotationsPlaceNoUi(modifierListOwner);
|
||||
}
|
||||
|
||||
private @Nullable PsiAnnotationOwner getTarget(@NotNull Project project, @NotNull PsiModifierListOwner modifierListOwner) {
|
||||
PsiModifierList list = modifierListOwner.getModifierList();
|
||||
if (list == null) return null;
|
||||
PsiClass annotationClass = JavaPsiFacade.getInstance(project).findClass(myAnnotation, modifierListOwner.getResolveScope());
|
||||
if (annotationClass != null &&
|
||||
AnnotationTargetUtil.findAnnotationTarget(annotationClass, PsiAnnotation.TargetType.TYPE_USE) != null) {
|
||||
PsiElement parent = list.getParent();
|
||||
PsiTypeElement type = null;
|
||||
if (parent instanceof PsiMethod) {
|
||||
type = ((PsiMethod)parent).getReturnTypeElement();
|
||||
}
|
||||
else if (parent instanceof PsiVariable) {
|
||||
type = ((PsiVariable)parent).getTypeElement();
|
||||
}
|
||||
if (type != null && !type.getType().equals(PsiType.VOID)) return type;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static PsiAnnotation addPhysicalAnnotation(String fqn, PsiNameValuePair[] pairs, PsiModifierList modifierList) {
|
||||
PsiAnnotation inserted = modifierList.addAnnotation(fqn);
|
||||
return addPhysicalAnnotation(fqn, pairs, (PsiAnnotationOwner)modifierList);
|
||||
}
|
||||
|
||||
public static PsiAnnotation addPhysicalAnnotation(String fqn, PsiNameValuePair[] pairs, PsiAnnotationOwner owner) {
|
||||
PsiAnnotation inserted = owner.addAnnotation(fqn);
|
||||
for (PsiNameValuePair pair : pairs) {
|
||||
inserted.setDeclaredAttributeValue(pair.getName(), pair.getValue());
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -673,11 +674,25 @@ public final class ExternalAnnotationsManagerImpl extends ReadableExternalAnnota
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public AnnotationPlace chooseAnnotationsPlaceNoUi(@NotNull final PsiElement element) {
|
||||
return chooseAnnotationsPlace(element, () -> AnnotationPlace.NEED_ASK_USER);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public AnnotationPlace chooseAnnotationsPlace(@NotNull final PsiElement element) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
if (!element.isPhysical() && !(element.getOriginalElement() instanceof PsiCompiledElement)) return AnnotationPlace.IN_CODE; //element just created
|
||||
return chooseAnnotationsPlace(element, () -> confirmNewExternalAnnotationRoot(element));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AnnotationPlace chooseAnnotationsPlace(@NotNull final PsiElement element,
|
||||
@NotNull Supplier<AnnotationPlace> confirmNewExternalAnnotationRoot) {
|
||||
if (!element.isPhysical() && !(element.getOriginalElement() instanceof PsiCompiledElement)) {
|
||||
return AnnotationPlace.IN_CODE; //element just created
|
||||
}
|
||||
if (!element.getManager().isInProject(element)) return AnnotationPlace.EXTERNAL;
|
||||
final Project project = myPsiManager.getProject();
|
||||
|
||||
@@ -699,48 +714,56 @@ public final class ExternalAnnotationsManagerImpl extends ReadableExternalAnnota
|
||||
}
|
||||
}
|
||||
|
||||
final MyExternalPromptDialog dialog = ApplicationManager.getApplication().isUnitTestMode() ||
|
||||
ApplicationManager.getApplication().isHeadlessEnvironment() ? null : new MyExternalPromptDialog(project);
|
||||
if (dialog != null && dialog.isToBeShown()) {
|
||||
final PsiElement highlightElement = element instanceof PsiNameIdentifierOwner
|
||||
? ((PsiNameIdentifierOwner)element).getNameIdentifier()
|
||||
: element.getNavigationElement();
|
||||
LOG.assertTrue(highlightElement != null);
|
||||
final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
|
||||
final List<RangeHighlighter> highlighters = new ArrayList<>();
|
||||
final boolean highlight =
|
||||
editor != null && editor.getDocument() == PsiDocumentManager.getInstance(project).getDocument(containingFile);
|
||||
try {
|
||||
if (highlight) { //do not highlight for batch inspections
|
||||
final EditorColorsManager colorsManager = EditorColorsManager.getInstance();
|
||||
final TextAttributes attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
|
||||
final TextRange textRange = highlightElement.getTextRange();
|
||||
HighlightManager.getInstance(project).addRangeHighlight(editor,
|
||||
textRange.getStartOffset(), textRange.getEndOffset(),
|
||||
attributes, true, highlighters);
|
||||
final LogicalPosition logicalPosition = editor.offsetToLogicalPosition(textRange.getStartOffset());
|
||||
editor.getScrollingModel().scrollTo(logicalPosition, ScrollType.CENTER);
|
||||
}
|
||||
|
||||
dialog.show();
|
||||
if (dialog.getExitCode() == 2) {
|
||||
return AnnotationPlace.EXTERNAL;
|
||||
}
|
||||
else if (dialog.getExitCode() == 1) {
|
||||
return AnnotationPlace.NOWHERE;
|
||||
}
|
||||
return confirmNewExternalAnnotationRoot.get();
|
||||
}
|
||||
return AnnotationPlace.IN_CODE;
|
||||
}
|
||||
|
||||
private static @NotNull AnnotationPlace confirmNewExternalAnnotationRoot(@NotNull PsiElement element) {
|
||||
PsiFile containingFile = element.getContainingFile();
|
||||
Project project = containingFile.getProject();
|
||||
final MyExternalPromptDialog dialog = ApplicationManager.getApplication().isUnitTestMode() ||
|
||||
ApplicationManager.getApplication().isHeadlessEnvironment()
|
||||
? null
|
||||
: new MyExternalPromptDialog(project);
|
||||
if (dialog != null && dialog.isToBeShown()) {
|
||||
final PsiElement highlightElement = element instanceof PsiNameIdentifierOwner
|
||||
? ((PsiNameIdentifierOwner)element).getNameIdentifier()
|
||||
: element.getNavigationElement();
|
||||
LOG.assertTrue(highlightElement != null);
|
||||
final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
|
||||
final List<RangeHighlighter> highlighters = new ArrayList<>();
|
||||
final boolean highlight =
|
||||
editor != null && editor.getDocument() == PsiDocumentManager.getInstance(project).getDocument(containingFile);
|
||||
try {
|
||||
if (highlight) { //do not highlight for batch inspections
|
||||
final EditorColorsManager colorsManager = EditorColorsManager.getInstance();
|
||||
final TextAttributes attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
|
||||
final TextRange textRange = highlightElement.getTextRange();
|
||||
HighlightManager.getInstance(project).addRangeHighlight(editor,
|
||||
textRange.getStartOffset(), textRange.getEndOffset(),
|
||||
attributes, true, highlighters);
|
||||
final LogicalPosition logicalPosition = editor.offsetToLogicalPosition(textRange.getStartOffset());
|
||||
editor.getScrollingModel().scrollTo(logicalPosition, ScrollType.CENTER);
|
||||
}
|
||||
finally {
|
||||
if (highlight) {
|
||||
HighlightManager.getInstance(project).removeSegmentHighlighter(editor, highlighters.get(0));
|
||||
}
|
||||
|
||||
dialog.show();
|
||||
if (dialog.getExitCode() == 2) {
|
||||
return AnnotationPlace.EXTERNAL;
|
||||
}
|
||||
else if (dialog.getExitCode() == 1) {
|
||||
return AnnotationPlace.NOWHERE;
|
||||
}
|
||||
}
|
||||
else if (dialog != null) {
|
||||
dialog.close(DialogWrapper.OK_EXIT_CODE);
|
||||
finally {
|
||||
if (highlight) {
|
||||
HighlightManager.getInstance(project).removeSegmentHighlighter(editor, highlighters.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dialog != null) {
|
||||
dialog.close(DialogWrapper.OK_EXIT_CODE);
|
||||
}
|
||||
return AnnotationPlace.IN_CODE;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,28 @@ public abstract class ExternalAnnotationsManager {
|
||||
|
||||
public static final Topic<ExternalAnnotationsListener> TOPIC = Topic.create("external annotations", ExternalAnnotationsListener.class);
|
||||
|
||||
/**
|
||||
* Describes where to place the new annotation
|
||||
*/
|
||||
public enum AnnotationPlace {
|
||||
/**
|
||||
* Annotation must be placed right in the code
|
||||
*/
|
||||
IN_CODE,
|
||||
/**
|
||||
* Annotation must be placed externally
|
||||
*/
|
||||
EXTERNAL,
|
||||
/**
|
||||
* User should be asked to decide whether they want to create new annotation root for external annotation.
|
||||
* {@link ExternalAnnotationsManager#chooseAnnotationsPlace(PsiElement)} asks user automatically, so this result is never returned,
|
||||
* but it requires EDT thread. On the other hand, {@link ExternalAnnotationsManager#chooseAnnotationsPlaceNoUi(PsiElement)}
|
||||
* never display UI but may return this result.
|
||||
*/
|
||||
NEED_ASK_USER,
|
||||
/**
|
||||
* User actively cancelled the annotation addition, so it should not be added at all.
|
||||
*/
|
||||
NOWHERE
|
||||
}
|
||||
|
||||
@@ -106,6 +125,18 @@ public abstract class ExternalAnnotationsManager {
|
||||
@NotNull String annotationFQN,
|
||||
PsiNameValuePair @Nullable [] value);
|
||||
|
||||
/**
|
||||
* @param element element to add new annotation for
|
||||
* @return place where the annotation must be added. No UI is displayed, so can be called inside any read-action.
|
||||
* May return {@link AnnotationPlace#NEED_ASK_USER} if the user confirmation is necessary.
|
||||
*/
|
||||
@NotNull
|
||||
public abstract AnnotationPlace chooseAnnotationsPlaceNoUi(@NotNull PsiElement element);
|
||||
|
||||
/**
|
||||
* @param element element to add new annotation for
|
||||
* @return place where the annotation must be added. Must be called in EDT.
|
||||
*/
|
||||
@NotNull
|
||||
public abstract AnnotationPlace chooseAnnotationsPlace(@NotNull PsiElement element);
|
||||
|
||||
|
||||
@@ -315,6 +315,10 @@ public abstract class NullableNotNullManager {
|
||||
? findAnnotationInHierarchy(owner, qualifiedNames)
|
||||
: findAnnotation(owner, qualifiedNames);
|
||||
PsiType type = getOwnerType(owner);
|
||||
if (memberAnno != null && type instanceof PsiArrayType && AnnotationTargetUtil.isTypeAnnotation(memberAnno)) {
|
||||
// Ambiguous TYPE_USE annotation on array type: we consider that it annotates an array component instead.
|
||||
memberAnno = null;
|
||||
}
|
||||
if (memberAnno != null) {
|
||||
PsiAnnotation annotation = preferTypeAnnotation(memberAnno, type);
|
||||
if (annotation != memberAnno && !qualifiedNames.contains(annotation.getQualifiedName())) return null;
|
||||
|
||||
@@ -399,6 +399,12 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnnotationPlace chooseAnnotationsPlaceNoUi(@NotNull PsiElement element) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnnotationPlace chooseAnnotationsPlace(@NotNull PsiElement element) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.psi.impl.PsiJavaParserFacadeImpl;
|
||||
import com.intellij.psi.impl.source.tree.*;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.SmartList;
|
||||
@@ -321,7 +322,30 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
|
||||
@Override
|
||||
@NotNull
|
||||
public PsiAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
|
||||
throw new UnsupportedOperationException();//todo
|
||||
PsiAnnotation annotation = JavaPsiFacade.getElementFactory(getProject()).createAnnotationFromText('@' + qualifiedName, this);
|
||||
PsiElement firstChild = getFirstChild();
|
||||
for (PsiElement child = getLastChild(); child != firstChild; child = child.getPrevSibling()) {
|
||||
if (PsiUtil.isJavaToken(child, JavaTokenType.LBRACKET) || PsiUtil.isJavaToken(child, JavaTokenType.ELLIPSIS)) {
|
||||
return (PsiAnnotation)addBefore(annotation, child);
|
||||
}
|
||||
}
|
||||
if (firstChild instanceof PsiJavaCodeReferenceElement) {
|
||||
PsiIdentifier identifier = PsiTreeUtil.getChildOfType(firstChild, PsiIdentifier.class);
|
||||
if (identifier != null) {
|
||||
return (PsiAnnotation)firstChild.addBefore(annotation, identifier);
|
||||
}
|
||||
}
|
||||
PsiElement parent = getParent();
|
||||
if (parent instanceof PsiModifierListOwner) {
|
||||
PsiModifierList modifierList = ((PsiModifierListOwner)parent).getModifierList();
|
||||
if (modifierList != null) {
|
||||
PsiTypeParameterList list = parent instanceof PsiTypeParameterListOwner ? ((PsiTypeParameterListOwner)parent).getTypeParameterList() : null;
|
||||
if (list == null || list.textMatches("")) {
|
||||
return (PsiAnnotation)modifierList.add(annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (PsiAnnotation)addBefore(annotation, firstChild);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// "Fix all '@NotNull/@Nullable problems' problems in file" "true"
|
||||
package typeUse;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.PARAMETER}) public @interface NotNull { }
|
||||
@Target({ElementType.TYPE_USE, ElementType.PARAMETER}) public @interface Nullable { }
|
||||
|
||||
interface Foo {
|
||||
void processString(@NotNull String s);
|
||||
void processArray(String @NotNull [] arr);
|
||||
void processArray2(String @NotNull [] arr);
|
||||
void processString2(java.lang.@NotNull String qualified);
|
||||
void processList(@NotNull List<@NotNull String> list);
|
||||
void processList2(@NotNull List<String> finalList);
|
||||
}
|
||||
|
||||
static class Bar implements Foo {
|
||||
@Override
|
||||
public void processString(@NotNull String s) { }
|
||||
|
||||
@Override
|
||||
public void processArray(String @NotNull [] arr) { }
|
||||
|
||||
@Override
|
||||
public void processArray2(@NotNull String @NotNull [] arr) { }
|
||||
|
||||
@Override
|
||||
public void processString2(java.lang.@NotNull String qualified) { }
|
||||
|
||||
@Override
|
||||
public void processList(@NotNull List<@NotNull String> list) { }
|
||||
|
||||
@Override
|
||||
public void processList2(final @NotNull List<String> finalList) { }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// "Fix all '@NotNull/@Nullable problems' problems in file" "true"
|
||||
package typeUse;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.TYPE_USE) public @interface NotNull { }
|
||||
@Target(ElementType.TYPE_USE) public @interface Nullable { }
|
||||
|
||||
interface Foo {
|
||||
@NotNull String getString();
|
||||
String @NotNull [] getArray();
|
||||
java.lang.@NotNull String getString2();
|
||||
@NotNull List<@NotNull String> getList();
|
||||
<T> @NotNull List<String> getList2();
|
||||
}
|
||||
|
||||
class Bar implements Foo {
|
||||
@Override
|
||||
public @NotNull String getString() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String @NotNull [] getArray() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.lang.@NotNull String getString2() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<String> getList() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @NotNull List<String> getList2() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// "Fix all '@NotNull/@Nullable problems' problems in file" "true"
|
||||
package typeUse;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.TYPE_USE) public @interface NotNull { }
|
||||
@Target(ElementType.TYPE_USE) public @interface Nullable { }
|
||||
|
||||
interface Foo {
|
||||
void processString(@NotNull String s);
|
||||
void processArray(String @NotNull [] arr);
|
||||
void processArray2(String @NotNull [] arr);
|
||||
void processArray3(String @NotNull ... arr);
|
||||
void processString2(java.lang.@NotNull String qualified);
|
||||
void processList(@NotNull List<@NotNull String> list);
|
||||
void processList2(@NotNull List<String> finalList);
|
||||
}
|
||||
|
||||
static class Bar implements Foo {
|
||||
@Override
|
||||
public void processString(@NotNull String s) { }
|
||||
|
||||
@Override
|
||||
public void processArray(String @NotNull [] arr) { }
|
||||
|
||||
@Override
|
||||
public void processArray2(@NotNull String @NotNull [] arr) { }
|
||||
|
||||
@Override
|
||||
public void processArray3(String @NotNull ... arr) { }
|
||||
|
||||
@Override
|
||||
public void processString2(java.lang.@NotNull String qualified) { }
|
||||
|
||||
@Override
|
||||
public void processList(@NotNull List<@NotNull String> list) { }
|
||||
|
||||
@Override
|
||||
public void processList2(final @NotNull List<String> finalList) { }
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// "Fix all '@NotNull/@Nullable problems' problems in file" "true"
|
||||
package typeUse;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({ElementType.TYPE_USE, ElementType.PARAMETER}) public @interface NotNull { }
|
||||
@Target({ElementType.TYPE_USE, ElementType.PARAMETER}) public @interface Nullable { }
|
||||
|
||||
interface Foo {
|
||||
void processString(@NotNull String s);
|
||||
void processArray(String @NotNull [] arr);
|
||||
void processArray2(String @NotNull [] arr);
|
||||
void processString2(java.lang.@NotNull String qualified);
|
||||
void processList(@NotNull List<@NotNull String> list);
|
||||
void processList2(@NotNull List<String> finalList);
|
||||
}
|
||||
|
||||
static class Bar implements Foo {
|
||||
@Override
|
||||
public void processString(String <caret>s) { }
|
||||
|
||||
@Override
|
||||
public void processArray(String[] arr) { }
|
||||
|
||||
@Override
|
||||
public void processArray2(@NotNull String[] arr) { }
|
||||
|
||||
@Override
|
||||
public void processString2(java.lang.String qualified) { }
|
||||
|
||||
@Override
|
||||
public void processList(List<@NotNull String> list) { }
|
||||
|
||||
@Override
|
||||
public void processList2(final List<String> finalList) { }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// "Fix all '@NotNull/@Nullable problems' problems in file" "true"
|
||||
package typeUse;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.TYPE_USE) public @interface NotNull { }
|
||||
@Target(ElementType.TYPE_USE) public @interface Nullable { }
|
||||
|
||||
interface Foo {
|
||||
@NotNull String getString();
|
||||
String @NotNull [] getArray();
|
||||
java.lang.@NotNull String getString2();
|
||||
@NotNull List<@NotNull String> getList();
|
||||
<T> @NotNull List<String> getList2();
|
||||
}
|
||||
|
||||
class Bar implements Foo {
|
||||
@Override
|
||||
public String g<caret>etString() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getArray() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.lang.String getString2() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getList() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<String> getList2() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// "Fix all '@NotNull/@Nullable problems' problems in file" "true"
|
||||
package typeUse;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.TYPE_USE) public @interface NotNull { }
|
||||
@Target(ElementType.TYPE_USE) public @interface Nullable { }
|
||||
|
||||
interface Foo {
|
||||
void processString(@NotNull String s);
|
||||
void processArray(String @NotNull [] arr);
|
||||
void processArray2(String @NotNull [] arr);
|
||||
void processArray3(String @NotNull ... arr);
|
||||
void processString2(java.lang.@NotNull String qualified);
|
||||
void processList(@NotNull List<@NotNull String> list);
|
||||
void processList2(@NotNull List<String> finalList);
|
||||
}
|
||||
|
||||
static class Bar implements Foo {
|
||||
@Override
|
||||
public void processString(String <caret>s) { }
|
||||
|
||||
@Override
|
||||
public void processArray(String[] arr) { }
|
||||
|
||||
@Override
|
||||
public void processArray2(@NotNull String[] arr) { }
|
||||
|
||||
@Override
|
||||
public void processArray3(String... arr) { }
|
||||
|
||||
@Override
|
||||
public void processString2(java.lang.String qualified) { }
|
||||
|
||||
@Override
|
||||
public void processList(List<@NotNull String> list) { }
|
||||
|
||||
@Override
|
||||
public void processList2(final List<String> finalList) { }
|
||||
}
|
||||
@@ -15,9 +15,11 @@
|
||||
*/
|
||||
package com.intellij.java.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.nullable.NullableStuffInspection;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -27,6 +29,26 @@ public class AnnotateMethodTest extends LightQuickFixParameterizedTestCase {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/annotateMethod";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
if (getTestName(false).contains("TypeUse")) {
|
||||
NullableNotNullManager nnnManager = NullableNotNullManager.getInstance(getProject());
|
||||
String prevNullable = nnnManager.getDefaultNullable();
|
||||
String prevNotNull = nnnManager.getDefaultNotNull();
|
||||
nnnManager.setNotNulls("typeUse.NotNull");
|
||||
nnnManager.setNullables("typeUse.Nullable");
|
||||
nnnManager.setDefaultNotNull("typeUse.NotNull");
|
||||
nnnManager.setDefaultNullable("typeUse.Nullable");
|
||||
Disposer.register(getTestRootDisposable(), () -> {
|
||||
nnnManager.setNotNulls();
|
||||
nnnManager.setNullables();
|
||||
nnnManager.setDefaultNotNull(prevNotNull);
|
||||
nnnManager.setDefaultNullable(prevNullable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new NullableStuffInspection()};
|
||||
@@ -34,6 +56,6 @@ public class AnnotateMethodTest extends LightQuickFixParameterizedTestCase {
|
||||
|
||||
@Override
|
||||
protected LanguageLevel getLanguageLevel() {
|
||||
return LanguageLevel.JDK_1_5;
|
||||
return LanguageLevel.JDK_1_8;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user