[java] avoid copying nullability type annotations (IDEA-132058)

This commit is contained in:
Roman Shevchenko
2015-11-17 12:58:08 +01:00
parent d36fa738a4
commit 37ef1d7bca
11 changed files with 110 additions and 117 deletions

View File

@@ -342,7 +342,7 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction {
if (parameter == null) {
continue;
}
notNull(field, parameter);
NullableNotNullManager.getInstance(field.getProject()).copyNotNullAnnotation(field, parameter);
cleanupElements.add(parameter);
final PsiElement assignmentStatement = AssignFieldFromParameterAction.addFieldAssignmentStatement(project, field, parameter, editor);
if (assignmentStatement != null) {
@@ -356,14 +356,6 @@ public class CreateConstructorParameterFromFieldFix implements IntentionAction {
}
}
private static void notNull(PsiField field, PsiParameter parameter) {
final PsiAnnotation notNull = NullableNotNullManager.getInstance(field.getProject()).copyNotNullAnnotation(field);
if (notNull != null) {
//noinspection ConstantConditions
parameter.getModifierList().addBefore(notNull, null);
}
}
@Nullable
private static PsiParameter findParamByName(String newName,
PsiType type,

View File

@@ -275,13 +275,7 @@ public class GenerateConstructorHandler extends GenerateMembersHandlerBase {
parmName = javaStyle.suggestUniqueVariableName(parmName, dummyConstructor, true);
PsiParameter parm = factory.createParameter(parmName, field.getType(), aClass);
PsiAnnotation notNull = NullableNotNullManager.getInstance(project).copyNotNullAnnotation(field);
if (notNull != null) {
PsiModifierList modifierList = parm.getModifierList();
if (modifierList != null) {
modifierList.addAfter(notNull, null);
}
}
NullableNotNullManager.getInstance(project).copyNotNullAnnotation(field, parm);
if (constructor.isVarArgs()) {
final PsiParameterList parameterList = constructor.getParameterList();

View File

@@ -17,6 +17,7 @@ package com.intellij.codeInsight.generation;
import com.intellij.codeInsight.AnnotationTargetUtil;
import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
@@ -685,19 +686,9 @@ public class GenerateMembersUtil {
}
result = (PsiMethod)CodeStyleManager.getInstance(project).reformat(result);
PsiModifierListOwner listOwner = null;
if (isGetter) {
listOwner = result;
}
else {
final PsiParameter[] parameters = result.getParameterList().getParameters();
if (parameters.length == 1) {
listOwner = parameters[0];
}
}
if (listOwner != null) {
PropertyUtil.annotateWithNullableStuff(field, listOwner);
}
PsiModifierListOwner annotationTarget = isGetter ? result : result.getParameterList().getParameters()[0];
NullableNotNullManager.getInstance(project).copyNullableOrNotNullAnnotation(field, annotationTarget);
return generatePrototype(field, result);
}

View File

@@ -195,17 +195,7 @@ public final class FieldFromParameterUtils {
modifierList.setModifierProperty(PsiModifier.STATIC, isStatic);
modifierList.setModifierProperty(PsiModifier.FINAL, isFinal);
final NullableNotNullManager manager = NullableNotNullManager.getInstance(project);
final PsiAnnotation nullable = manager.copyNullableAnnotation(parameter);
if (nullable != null) {
modifierList.addAfter(nullable, null);
}
else if (isFinal) {
final PsiAnnotation notNull = manager.copyNotNullAnnotation(parameter);
if (notNull != null) {
modifierList.addAfter(notNull, null);
}
}
NullableNotNullManager.getInstance(project).copyNullableOrNotNullAnnotation(parameter, field);
PsiCodeBlock methodBody = method.getBody();
if (methodBody == null) return;

View File

@@ -18,7 +18,7 @@ package com.intellij.refactoring.inheritanceToDelegation;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
import com.intellij.codeInsight.generation.GenerateMembersUtil;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.codeInsight.generation.OverrideImplementExploreUtil;
import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.diagnostic.Logger;
@@ -53,7 +53,6 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -465,7 +464,7 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
final PsiExpression newExpr;
final PsiReferenceExpression ref;
@NonNls final String delegateQualifier;
final String delegateQualifier;
if (!(expression instanceof PsiThisExpression || expression instanceof PsiSuperExpression)) {
delegateQualifier = "a.";
} else {
@@ -498,7 +497,7 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
if (!myAbstractDelegatedMethods.contains(method)) {
PsiMethod methodToAdd = delegateMethod(myFieldName, method, getSuperSubstitutor(method.getContainingClass()));
String visibility = myDelegatedMethodsVisibility.get(method);
@PsiModifier.ModifierConstant String visibility = myDelegatedMethodsVisibility.get(method);
if (visibility != null) {
PsiUtil.setModifierProperty(methodToAdd, visibility, true);
}
@@ -508,25 +507,15 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
}
}
private PsiMethod delegateMethod(@NonNls String delegationTarget,
private PsiMethod delegateMethod(String delegationTarget,
PsiMethod method,
PsiSubstitutor substitutor) throws IncorrectOperationException {
substitutor = OverrideImplementUtil.correctSubstitutor(method, substitutor);
substitutor = OverrideImplementExploreUtil.correctSubstitutor(method, substitutor);
PsiMethod methodToAdd = GenerateMembersUtil.substituteGenericMethod(method, substitutor);
final PsiModifierList modifierList = methodToAdd.getModifierList();
final NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject);
modifierList.setModifierProperty(PsiModifier.ABSTRACT, false);
final PsiAnnotation nullable = manager.copyNullableAnnotation(method);
if (nullable != null) {
modifierList.addAfter(nullable, null);
}
else {
final PsiAnnotation notNull = manager.copyNotNullAnnotation(method);
if (notNull != null) {
modifierList.addAfter(notNull, null);
}
}
methodToAdd.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, false);
NullableNotNullManager.getInstance(myProject).copyNullableOrNotNullAnnotation(method, methodToAdd);
final String delegationBody = getDelegationBody(methodToAdd, delegationTarget);
PsiCodeBlock newBody = myFactory.createCodeBlockFromText(delegationBody, method);
@@ -546,7 +535,7 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
}
private static String getDelegationBody(PsiMethod methodToAdd, String delegationTarget) {
@NonNls final StringBuffer buffer = new StringBuffer();
StringBuilder buffer = new StringBuilder();
buffer.append("{\n");
if (!PsiType.VOID.equals(methodToAdd.getReturnType())) {
@@ -618,7 +607,7 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
if (myGenerateGetter) {
final String getterVisibility = PsiModifier.PUBLIC;
@NonNls StringBuffer getterBuffer = new StringBuffer();
StringBuffer getterBuffer = new StringBuffer();
getterBuffer.append(getterVisibility);
getterBuffer.append(" Object ");
getterBuffer.append(myGetterName);
@@ -647,12 +636,12 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
return PsiModifier.PRIVATE;
}
private @NonNls String defaultClassFieldType() {
private String defaultClassFieldType() {
return (myIsInnerClassNeeded ? myInnerClassName : "Object");
}
private PsiField createField(final String fieldVisibility, final boolean fieldInitializerNeeded, String defaultTypeName) throws IncorrectOperationException {
@NonNls StringBuffer buffer = new StringBuffer();
StringBuffer buffer = new StringBuffer();
buffer.append(fieldVisibility);
buffer.append(" final " + defaultTypeName + " ");
buffer.append(myFieldName);
@@ -671,7 +660,7 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
for (PsiMethod constructor : constructors) {
PsiCodeBlock body = constructor.getBody();
final PsiStatement[] statements = body.getStatements();
@NonNls String fieldQualifier = "";
String fieldQualifier = "";
PsiParameter[] constructorParams = constructor.getParameterList().getParameters();
for (PsiParameter constructorParam : constructorParams) {
if (myFieldName.equals(constructorParam.getName())) {
@@ -679,7 +668,7 @@ public class InheritanceToDelegationProcessor extends BaseRefactoringProcessor {
break;
}
}
final @NonNls String assignmentText = fieldQualifier + myFieldName + "= new " + defaultClassFieldType() + "()";
final String assignmentText = fieldQualifier + myFieldName + "= new " + defaultClassFieldType() + "()";
if (statements.length < 1 || !JavaHighlightUtil.isSuperOrThisCall(statements[0], true, true) || myBaseClass.isInterface()) {
PsiExpressionStatement assignmentStatement =
(PsiExpressionStatement)myFactory.createStatementFromText(

View File

@@ -137,10 +137,42 @@ public abstract class NullableNotNullManager implements PersistentStateComponent
return findNullabilityAnnotationWithDefault(owner, checkBases, false);
}
@Nullable
public PsiAnnotation copyNotNullAnnotation(@NotNull PsiModifierListOwner original, @NotNull PsiModifierListOwner generated) {
return copyAnnotation(getNotNullAnnotation(original, false), generated);
}
@Nullable
public PsiAnnotation copyNullableOrNotNullAnnotation(@NotNull PsiModifierListOwner original, @NotNull PsiModifierListOwner generated) {
PsiAnnotation annotation = getNullableAnnotation(original, false);
if (annotation == null) annotation = getNotNullAnnotation(original, false);
return copyAnnotation(annotation, generated);
}
@Nullable
private PsiAnnotation copyAnnotation(PsiAnnotation annotation, PsiModifierListOwner target) {
// type annotations are part of target's type and should not to be copied explicitly to avoid duplication
if (annotation != null && !AnnotationTargetUtil.isTypeAnnotation(annotation)) {
String qualifiedName = checkContainer(annotation, false);
if (qualifiedName != null) {
PsiModifierList modifierList = target.getModifierList();
if (modifierList != null && modifierList.findAnnotation(qualifiedName) == null) {
return modifierList.addAnnotation(qualifiedName);
}
}
}
return null;
}
/** @deprecated use {@link #copyNotNullAnnotation(PsiModifierListOwner, PsiModifierListOwner)} (to be removed in IDEA 17) */
@SuppressWarnings("unused")
public PsiAnnotation copyNotNullAnnotation(PsiModifierListOwner owner) {
return copyAnnotation(owner, getNotNullAnnotation(owner, false));
}
/** @deprecated use {@link #copyNullableOrNotNullAnnotation(PsiModifierListOwner, PsiModifierListOwner)} (to be removed in IDEA 17) */
@SuppressWarnings("unused")
public PsiAnnotation copyNullableAnnotation(PsiModifierListOwner owner) {
return copyAnnotation(owner, getNullableAnnotation(owner, false));
}

View File

@@ -401,7 +401,7 @@ public class PropertyUtil {
PsiUtil.setModifierProperty(getMethod, PsiModifier.STATIC, true);
}
annotateWithNullableStuff(field, getMethod);
NullableNotNullManager.getInstance(project).copyNullableOrNotNullAnnotation(field, getMethod);
PsiCodeBlock body = factory.createCodeBlockFromText("{\nreturn " + name + ";\n}", null);
getMethod.getBody().replace(body);
@@ -457,7 +457,7 @@ public class PropertyUtil {
String parameterName = codeStyleManager.propertyNameToVariableName(propertyName, VariableKind.PARAMETER);
PsiParameter param = factory.createParameter(parameterName, field.getType());
annotateWithNullableStuff(field, param);
NullableNotNullManager.getInstance(project).copyNullableOrNotNullAnnotation(field, param);
setMethod.getParameterList().add(param);
PsiUtil.setModifierProperty(setMethod, PsiModifier.PUBLIC, true);
@@ -496,27 +496,11 @@ public class PropertyUtil {
}
}
/** @deprecated use {@link NullableNotNullManager#copyNullableOrNotNullAnnotation(PsiModifierListOwner, PsiModifierListOwner)} (to be removed in IDEA 17) */
@SuppressWarnings("unused")
public static void annotateWithNullableStuff(@NotNull PsiModifierListOwner field,
@NotNull PsiModifierListOwner listOwner)
throws IncorrectOperationException {
final NullableNotNullManager manager = NullableNotNullManager.getInstance(field.getProject());
final PsiAnnotation notNull = manager.copyNotNullAnnotation(field);
if (notNull != null) {
annotate(listOwner, notNull);
}
else {
final PsiAnnotation nullable = manager.copyNullableAnnotation(field);
if (nullable != null) {
annotate(listOwner, nullable);
}
}
}
private static void annotate(@NotNull PsiModifierListOwner listOwner, @NotNull PsiAnnotation annotation)
throws IncorrectOperationException {
final PsiModifierList modifierList = listOwner.getModifierList();
LOG.assertTrue(modifierList != null);
modifierList.addAfter(annotation, null);
@NotNull PsiModifierListOwner listOwner) throws IncorrectOperationException {
NullableNotNullManager.getInstance(field.getProject()).copyNullableOrNotNullAnnotation(field, listOwner);
}
public static String suggestPropertyName(@NotNull PsiField field) {

View File

@@ -0,0 +1,9 @@
import foo.TestNotNull;
class C {
private @TestNotNull String s;
public C(@TestNotNull String s) {
this.s = s;
}
}

View File

@@ -0,0 +1,7 @@
import foo.TestNotNull;
class C {
private @TestNotNull String s;
<caret>
}

View File

@@ -15,21 +15,36 @@
*/
package com.intellij.codeInsight;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.generation.ClassMember;
import com.intellij.codeInsight.generation.GenerateConstructorHandler;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.testFramework.LightCodeInsightTestCase;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author ven
*/
public class GenerateConstructorTest extends LightCodeInsightTestCase {
public class GenerateConstructorTest extends LightCodeInsightFixtureTestCase {
@NotNull
@Override
protected LightProjectDescriptor getProjectDescriptor() {
return JAVA_8;
}
@Override
protected String getBasePath() {
return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/generateConstructor";
}
public void testAbstractClass() { doTest(); }
public void testPackageLocalClass() { doTest(); }
public void testPrivateClass() { doTest(); }
@@ -61,13 +76,21 @@ public class GenerateConstructorTest extends LightCodeInsightTestCase {
doTest();
}
public void testTypeAnnotatedField() {
myFixture.addClass("package foo;\n\nimport java.lang.annotation.*;\n\n@Target(ElementType.TYPE_USE) public @interface TestNotNull { }");
NullableNotNullManager manager = NullableNotNullManager.getInstance(getProject());
manager.setNotNulls("foo.TestNotNull");
Disposer.register(myTestRootDisposable, manager::setNotNulls);
doTest();
}
private void doTest() {
doTest(false);
}
private void doTest(boolean preSelect) {
String name = getTestName(false);
configureByFile("/codeInsight/generateConstructor/before" + name + ".java");
myFixture.configureByFile("before" + name + ".java");
new GenerateConstructorHandler() {
@Override
protected ClassMember[] chooseMembers(ClassMember[] members, boolean allowEmpty, boolean copyJavadoc, Project project, Editor editor) {
@@ -80,6 +103,6 @@ public class GenerateConstructorTest extends LightCodeInsightTestCase {
}
}
}.invoke(getProject(), getEditor(), getFile());
checkResultByFile("/codeInsight/generateConstructor/after" + name + ".java");
myFixture.checkResultByFile("after" + name + ".java");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -554,35 +554,17 @@ public class GroovyPropertyUtils {
}
}
private static void annotateWithNullableStuff(final PsiModifierListOwner field, final PsiModifierListOwner listOwner)
throws IncorrectOperationException {
final NullableNotNullManager manager = NullableNotNullManager.getInstance(field.getProject());
final PsiAnnotation notNull = manager.copyNotNullAnnotation(field);
if (notNull != null) {
annotate(listOwner, notNull);
}
else {
final PsiAnnotation nullable = manager.copyNullableAnnotation(field);
if (nullable != null) {
annotate(listOwner, nullable);
}
}
@SuppressWarnings("MagicConstant")
private static void annotateWithNullableStuff(PsiModifierListOwner original,
PsiModifierListOwner generated) throws IncorrectOperationException {
NullableNotNullManager.getInstance(original.getProject()).copyNullableOrNotNullAnnotation(original, generated);
final PsiModifierList modifierList = listOwner.getModifierList();
if (modifierList.hasExplicitModifier(GrModifier.DEF)) {
PsiModifierList modifierList = generated.getModifierList();
if (modifierList != null && modifierList.hasExplicitModifier(GrModifier.DEF)) {
LOG.assertTrue(modifierList instanceof GrModifierList);
if (modifierList.getAnnotations().length > 0 || ((GrModifierList)modifierList).getModifiers().length > 1) {
((GrModifierList)modifierList).setModifierProperty(GrModifier.DEF, false);
modifierList.setModifierProperty(GrModifier.DEF, false);
}
}
}
private static void annotate(final PsiModifierListOwner listOwner, final PsiAnnotation annotation)
throws IncorrectOperationException {
final PsiModifierList modifierList = listOwner.getModifierList();
LOG.assertTrue(modifierList != null);
modifierList.addAnnotation(annotation.getQualifiedName());
}
}