diff --git a/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form b/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form
index fdaf15cc6910..edb06a0b70f0 100644
--- a/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form
+++ b/java/compiler/impl/src/com/intellij/compiler/options/CompilerOptionsPanel.form
@@ -157,7 +157,7 @@
-
+
diff --git a/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java b/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java
index e4a93f342e7f..00651634c509 100644
--- a/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java
+++ b/java/compiler/impl/src/com/intellij/compiler/options/CompilerUIConfigurable.java
@@ -16,6 +16,7 @@
package com.intellij.compiler.options;
import com.intellij.codeInsight.NullableNotNullDialog;
+import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.compiler.CompilerWorkspaceConfiguration;
@@ -83,6 +84,7 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
private JLabel myParallelCompilationLegendLabel;
private JButton myConfigureAnnotations;
private JLabel myWarningLabel;
+ private JPanel myAssertNotNullPanel;
public CompilerUIConfigurable(@NotNull final Project project) {
myProject = project;
@@ -108,7 +110,10 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
s -> StringUtil.startsWithIgnoreCase(s, "-Xmx")) == null);
}
});
- myConfigureAnnotations.addActionListener(NullableNotNullDialog.createActionListener(myPanel));
+ myConfigureAnnotations.addActionListener(e -> {
+ NullableNotNullDialog.showDialogWithInstrumentationOptions(myPanel);
+ myCbAssertNotNull.setSelected(!NullableNotNullManager.getInstance(myProject).getInstrumentedNotNulls().isEmpty());
+ });
}
private void tweakControls(@NotNull Project project) {
@@ -140,7 +145,7 @@ public class CompilerUIConfigurable implements SearchableConfigurable, Configura
Map> controls = ContainerUtilRt.newHashMap();
controls.put(Setting.RESOURCE_PATTERNS, ContainerUtilRt.newArrayList(myResourcePatternsLabel, myResourcePatternsField, myPatternLegendLabel));
controls.put(Setting.CLEAR_OUTPUT_DIR_ON_REBUILD, Collections.singleton(myCbClearOutputDirectory));
- controls.put(Setting.ADD_NOT_NULL_ASSERTIONS, Collections.singleton(myCbAssertNotNull));
+ controls.put(Setting.ADD_NOT_NULL_ASSERTIONS, Collections.singleton(myAssertNotNullPanel));
controls.put(Setting.AUTO_SHOW_FIRST_ERROR_IN_EDITOR, Collections.singleton(myCbAutoShowFirstError));
controls.put(Setting.DISPLAY_NOTIFICATION_POPUP, Collections.singleton(myCbDisplayNotificationPopup));
controls.put(Setting.AUTO_MAKE, ContainerUtilRt.newArrayList(myCbEnableAutomake, myEnableAutomakeLegendLabel));
diff --git a/java/java-impl/src/com/intellij/codeInsight/NullableNotNullManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/NullableNotNullManagerImpl.java
index fbdbed46d538..44008727e688 100644
--- a/java/java-impl/src/com/intellij/codeInsight/NullableNotNullManagerImpl.java
+++ b/java/java-impl/src/com/intellij/codeInsight/NullableNotNullManagerImpl.java
@@ -6,9 +6,7 @@ import com.intellij.codeInspection.dataFlow.Nullness;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.DefaultJDOMExternalizer;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.util.JDOMExternalizableStringList;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
@@ -17,27 +15,97 @@ import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.xmlb.annotations.Tag;
+import com.intellij.util.xmlb.annotations.XCollection;
import one.util.streamex.StreamEx;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jps.model.serialization.java.compiler.JpsJavaCompilerNotNullableSerializer;
import java.util.*;
-@State(name = "NullableNotNullManager")
-public class NullableNotNullManagerImpl extends NullableNotNullManager implements PersistentStateComponent {
+import static com.intellij.codeInsight.AnnotationUtil.NOT_NULL;
+import static com.intellij.codeInsight.AnnotationUtil.NULLABLE;
+@State(name = "NullableNotNullManager")
+public class NullableNotNullManagerImpl extends NullableNotNullManager implements PersistentStateComponent {
public static final String TYPE_QUALIFIER_NICKNAME = "javax.annotation.meta.TypeQualifierNickname";
+ private List myNullables = ContainerUtil.newArrayList(DEFAULT_NULLABLES);
+ private List myNotNulls = ContainerUtil.newArrayList(DEFAULT_NOT_NULLS);
+
+ public static class StateBean {
+ @Tag("option") public Element myNullables = null;
+ @Tag("option") public Element myNotNulls = null;
+ @XCollection(style = XCollection.Style.v2) public List instrumentedNotNulls = ContainerUtil.newArrayList(NOT_NULL);
+ public String myDefaultNullable = NULLABLE;
+ public String myDefaultNotNull = NOT_NULL;
+ }
+
+ private StateBean myState = new StateBean();
public NullableNotNullManagerImpl(Project project) {
super(project);
- myNotNulls.addAll(getPredefinedNotNulls());
}
@Override
- public List getPredefinedNotNulls() {
- return JpsJavaCompilerNotNullableSerializer.DEFAULT_NOT_NULLS;
+ public void setNotNulls(@NotNull String... annotations) {
+ LinkedHashSet set = ContainerUtil.newLinkedHashSet(annotations);
+ Collections.addAll(set, DEFAULT_NOT_NULLS);
+ myNotNulls = new ArrayList<>(set);
+ }
+
+ @Override
+ public void setNullables(@NotNull String... annotations) {
+ LinkedHashSet set = ContainerUtil.newLinkedHashSet(annotations);
+ Collections.addAll(set, DEFAULT_NULLABLES);
+ myNullables = new ArrayList<>(set);
+ }
+
+ @Override
+ @NotNull
+ public String getDefaultNullable() {
+ return myState.myDefaultNullable;
+ }
+
+ @Override
+ public void setDefaultNullable(@NotNull String defaultNullable) {
+ LOG.assertTrue(getNullables().contains(defaultNullable));
+ myState.myDefaultNullable = defaultNullable;
+ }
+
+ @Override
+ @NotNull
+ public String getDefaultNotNull() {
+ return myState.myDefaultNotNull;
+ }
+
+ @Override
+ public void setDefaultNotNull(@NotNull String defaultNotNull) {
+ LOG.assertTrue(getNotNulls().contains(defaultNotNull));
+ myState.myDefaultNotNull = defaultNotNull;
+ }
+
+ @Override
+ @NotNull
+ public List getNullables() {
+ return Collections.unmodifiableList(myNullables);
+ }
+
+ @Override
+ @NotNull
+ public List getNotNulls() {
+ return Collections.unmodifiableList(myNotNulls);
+ }
+
+ @NotNull
+ @Override
+ public List getInstrumentedNotNulls() {
+ return Collections.unmodifiableList(myState.instrumentedNotNulls);
+ }
+
+ @Override
+ public void setInstrumentedNotNulls(@NotNull List names) {
+ myState.instrumentedNotNulls = ContainerUtil.sorted(names);
}
@Override
@@ -48,36 +116,35 @@ public class NullableNotNullManagerImpl extends NullableNotNullManager implement
@SuppressWarnings("deprecation")
@Override
- public Element getState() {
- final Element component = new Element("component");
+ public StateBean getState() {
+ StateBean state = myState;
- if (hasDefaultValues()) {
- return component;
- }
+ state.myNullables = new Element("option").setAttribute("name", "myNullables").addContent(new Element("value"));
+ new JDOMExternalizableStringList(myNullables).writeExternal(state.myNullables.getChild("value"));
- try {
- DefaultJDOMExternalizer.writeExternal(this, component);
- }
- catch (WriteExternalException e) {
- LOG.error(e);
- }
- return component;
+ state.myNotNulls = new Element("option").setAttribute("name", "myNotNulls").addContent(new Element("value"));
+ new JDOMExternalizableStringList(myNotNulls).writeExternal(state.myNotNulls.getChild("value"));
+
+ return state;
}
- @SuppressWarnings("deprecation")
@Override
- public void loadState(@NotNull Element state) {
- try {
- DefaultJDOMExternalizer.readExternal(this, state);
- if (myNullables.isEmpty()) {
- Collections.addAll(myNullables, DEFAULT_NULLABLES);
- }
- if (myNotNulls.isEmpty()) {
- myNotNulls.addAll(getPredefinedNotNulls());
- }
+ public void loadState(@NotNull StateBean state) {
+ myState = state;
+
+ readJdomList(state.myNullables, myNullables, DEFAULT_NULLABLES);
+ readJdomList(state.myNotNulls, myNotNulls, DEFAULT_NOT_NULLS);
+ }
+
+ private static void readJdomList(@Nullable Element src, @NotNull List to, @NotNull String[] defaults) {
+ to.clear();
+ Element value = src != null ? src.getChild("value") : null;
+ if (value != null) {
+ //noinspection deprecation
+ JDOMExternalizableStringList.readList(to, value);
}
- catch (InvalidDataException e) {
- LOG.error(e);
+ if (to.isEmpty()) {
+ Collections.addAll(to, defaults);
}
}
diff --git a/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java b/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java
index 44f713bd9589..6e53cd55045e 100644
--- a/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java
+++ b/java/java-psi-api/src/com/intellij/codeInsight/NullableNotNullManager.java
@@ -4,7 +4,6 @@ package com.intellij.codeInsight;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.JDOMExternalizableStringList;
import com.intellij.openapi.util.RecursionManager;
import com.intellij.psi.*;
import com.intellij.psi.util.TypeConversionUtil;
@@ -12,7 +11,9 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.*;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
import static com.intellij.codeInsight.AnnotationUtil.*;
@@ -24,11 +25,6 @@ public abstract class NullableNotNullManager {
protected static final Logger LOG = Logger.getInstance(NullableNotNullManager.class);
protected final Project myProject;
- public String myDefaultNullable = NULLABLE;
- public String myDefaultNotNull = NOT_NULL;
- @SuppressWarnings("deprecation") public final JDOMExternalizableStringList myNullables = new JDOMExternalizableStringList();
- @SuppressWarnings("deprecation") public final JDOMExternalizableStringList myNotNulls = new JDOMExternalizableStringList();
-
protected static final String JAVAX_ANNOTATION_NULLABLE = "javax.annotation.Nullable";
protected static final String JAVAX_ANNOTATION_NONNULL = "javax.annotation.Nonnull";
@@ -43,10 +39,20 @@ public abstract class NullableNotNullManager {
"org.checkerframework.checker.nullness.compatqual.NullableDecl",
"org.checkerframework.checker.nullness.compatqual.NullableType"
};
+ static final String[] DEFAULT_NOT_NULLS = {
+ NotNull.class.getName(),
+ "javax.annotation.Nonnull",
+ "javax.validation.constraints.NotNull",
+ "edu.umd.cs.findbugs.annotations.NonNull",
+ "android.support.annotation.NonNull",
+ "androidx.annotation.NonNull",
+ "org.checkerframework.checker.nullness.qual.NonNull",
+ "org.checkerframework.checker.nullness.compatqual.NonNullDecl",
+ "org.checkerframework.checker.nullness.compatqual.NonNullType"
+ };
- public NullableNotNullManager(Project project) {
+ protected NullableNotNullManager(Project project) {
myProject = project;
- Collections.addAll(myNullables, DEFAULT_NULLABLES);
}
public static NullableNotNullManager getInstance(Project project) {
@@ -60,36 +66,12 @@ public abstract class NullableNotNullManager {
return isNullable(owner, false) || isNotNull(owner, false);
}
- private static void addAllIfNotPresent(@NotNull Collection super String> collection, @NotNull String... annotations) {
- for (String annotation : annotations) {
- LOG.assertTrue(annotation != null);
- if (!collection.contains(annotation)) {
- collection.add(annotation);
- }
- }
- }
+ public abstract void setNotNulls(@NotNull String... annotations);
- public void setNotNulls(@NotNull String... annotations) {
- myNotNulls.clear();
- for (String annotation : getPredefinedNotNulls()) {
- LOG.assertTrue(annotation != null);
- if (!myNotNulls.contains(annotation)) {
- myNotNulls.add(annotation);
- }
- }
- addAllIfNotPresent(myNotNulls, annotations);
- }
-
- public void setNullables(@NotNull String... annotations) {
- myNullables.clear();
- addAllIfNotPresent(myNullables, DEFAULT_NULLABLES);
- addAllIfNotPresent(myNullables, annotations);
- }
+ public abstract void setNullables(@NotNull String... annotations);
@NotNull
- public String getDefaultNullable() {
- return myDefaultNullable;
- }
+ public abstract String getDefaultNullable();
@Nullable
public String getNullable(@NotNull PsiModifierListOwner owner) {
@@ -117,15 +99,10 @@ public abstract class NullableNotNullManager {
return checkNullityDefault(anno, acceptAnyTarget, false) != null;
}
- public void setDefaultNullable(@NotNull String defaultNullable) {
- LOG.assertTrue(getNullables().contains(defaultNullable));
- myDefaultNullable = defaultNullable;
- }
+ public abstract void setDefaultNullable(@NotNull String defaultNullable);
@NotNull
- public String getDefaultNotNull() {
- return myDefaultNotNull;
- }
+ public abstract String getDefaultNotNull();
@Nullable
public PsiAnnotation getNotNullAnnotation(@NotNull PsiModifierListOwner owner, boolean checkBases) {
@@ -186,10 +163,7 @@ public abstract class NullableNotNullManager {
return annotation == null ? null : annotation.getQualifiedName();
}
- public void setDefaultNotNull(@NotNull String defaultNotNull) {
- LOG.assertTrue(getNotNulls().contains(defaultNotNull));
- myDefaultNotNull = defaultNotNull;
- }
+ public abstract void setDefaultNotNull(@NotNull String defaultNotNull);
@Nullable
private PsiAnnotation findNullityAnnotationWithDefault(@NotNull PsiModifierListOwner owner, boolean checkBases, boolean nullable) {
@@ -208,7 +182,7 @@ public abstract class NullableNotNullManager {
if (type == null || TypeConversionUtil.isPrimitiveAndNotNull(type)) return null;
// even if javax.annotation.Nullable is not configured, it should still take precedence over ByDefault annotations
- List annotations = nullable ? getPredefinedNotNulls() : Arrays.asList(DEFAULT_NULLABLES);
+ List annotations = Arrays.asList(nullable ? DEFAULT_NOT_NULLS : DEFAULT_NULLABLES);
int flags = (checkBases ? CHECK_HIERARCHY : 0) | CHECK_EXTERNAL | CHECK_INFERRED | CHECK_TYPE;
if (isAnnotated(owner, annotations, flags)) {
return null;
@@ -359,36 +333,10 @@ public abstract class NullableNotNullManager {
protected abstract NullityDefault isJsr305Default(@NotNull PsiAnnotation annotation, @NotNull PsiAnnotation.TargetType[] placeTargetTypes);
@NotNull
- public List getNullables() {
- return myNullables;
- }
+ public abstract List getNullables();
@NotNull
- public List getNotNulls() {
- return myNotNulls;
- }
-
- boolean hasDefaultValues() {
- List predefinedNotNulls = getPredefinedNotNulls();
- if (DEFAULT_NULLABLES.length != getNullables().size() || predefinedNotNulls.size() != getNotNulls().size()) {
- return false;
- }
- if (!myDefaultNotNull.equals(NOT_NULL) || !myDefaultNullable.equals(NULLABLE)) {
- return false;
- }
- for (int i = 0; i < DEFAULT_NULLABLES.length; i++) {
- if (!getNullables().get(i).equals(DEFAULT_NULLABLES[i])) {
- return false;
- }
- }
- for (int i = 0; i < predefinedNotNulls.size(); i++) {
- if (!getNotNulls().get(i).equals(predefinedNotNulls.get(i))) {
- return false;
- }
- }
-
- return true;
- }
+ public abstract List getNotNulls();
public static boolean isNullable(@NotNull PsiModifierListOwner owner) {
return getInstance(owner.getProject()).isNullable(owner, true);
@@ -398,7 +346,10 @@ public abstract class NullableNotNullManager {
return getInstance(owner.getProject()).isNotNull(owner, true);
}
- public abstract List getPredefinedNotNulls();
+ @NotNull
+ public abstract List getInstrumentedNotNulls();
+
+ public abstract void setInstrumentedNotNulls(@NotNull List names);
public static boolean isNullableAnnotation(@NotNull PsiAnnotation annotation) {
return getInstance(annotation.getProject()).getNullablesWithNickNames().contains(annotation.getQualifiedName());
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/MakeInferredAnnotationExplicitTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/MakeInferredAnnotationExplicitTest.groovy
index 63931b5d38e4..ef4f0b1f91f4 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInsight/MakeInferredAnnotationExplicitTest.groovy
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/MakeInferredAnnotationExplicitTest.groovy
@@ -18,6 +18,7 @@ package com.intellij.java.codeInsight
import com.intellij.codeInsight.AnnotationUtil
import com.intellij.codeInsight.NullableNotNullManager
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
+import com.intellij.util.ArrayUtil
/**
* @author peter
@@ -95,7 +96,7 @@ class Foo {
@Override
protected void tearDown() throws Exception {
- NullableNotNullManager.getInstance(project).notNulls = NullableNotNullManager.getInstance(project).predefinedNotNulls as String[]
+ NullableNotNullManager.getInstance(project).notNulls = ArrayUtil.EMPTY_STRING_ARRAY
NullableNotNullManager.getInstance(project).defaultNotNull = AnnotationUtil.NOT_NULL
super.tearDown()
diff --git a/java/openapi/src/com/intellij/codeInsight/NullableNotNullDialog.java b/java/openapi/src/com/intellij/codeInsight/NullableNotNullDialog.java
index 88b97ee6ead4..ebb88eb6fe19 100644
--- a/java/openapi/src/com/intellij/codeInsight/NullableNotNullDialog.java
+++ b/java/openapi/src/com/intellij/codeInsight/NullableNotNullDialog.java
@@ -28,29 +28,49 @@ import com.intellij.openapi.ui.Splitter;
import com.intellij.psi.PsiClass;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.*;
-import com.intellij.ui.components.JBList;
-import com.intellij.util.ArrayUtil;
+import com.intellij.ui.table.JBTable;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.EmptyIcon;
+import com.intellij.util.ui.JBDimension;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
+import sun.swing.table.DefaultTableCellHeaderRenderer;
import javax.swing.*;
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
+import java.util.List;
public class NullableNotNullDialog extends DialogWrapper {
private final Project myProject;
- private AnnotationsPanel myNullablePanel;
- private AnnotationsPanel myNotNullPanel;
+ private final AnnotationsPanel myNullablePanel;
+ private final AnnotationsPanel myNotNullPanel;
+ private final boolean myShowInstrumentationOptions;
public NullableNotNullDialog(@NotNull Project project) {
+ this(project, false);
+ }
+
+ private NullableNotNullDialog(@NotNull Project project, boolean showInstrumentationOptions) {
super(project, true);
myProject = project;
+ myShowInstrumentationOptions = showInstrumentationOptions;
+
+ NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject);
+ myNullablePanel = new AnnotationsPanel("Nullable",
+ manager.getDefaultNullable(),
+ manager.getNullables(), NullableNotNullManager.DEFAULT_NULLABLES,
+ Collections.emptySet(), false);
+ myNotNullPanel = new AnnotationsPanel("NotNull",
+ manager.getDefaultNotNull(),
+ manager.getNotNulls(), NullableNotNullManager.DEFAULT_NOT_NULLS,
+ ContainerUtil.newHashSet(manager.getInstrumentedNotNulls()), showInstrumentationOptions);
+
init();
setTitle("Nullable/NotNull Configuration");
}
@@ -70,22 +90,26 @@ public class NullableNotNullDialog extends DialogWrapper {
return new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(context));
- if (project == null) project = ProjectManager.getInstance().getDefaultProject();
- new NullableNotNullDialog(project).show();
+ showDialog(context, false);
}
};
}
+ public static void showDialogWithInstrumentationOptions(@NotNull Component context) {
+ showDialog(context, true);
+ }
+
+ private static void showDialog(Component context, boolean showInstrumentationOptions) {
+ Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(context));
+ if (project == null) project = ProjectManager.getInstance().getDefaultProject();
+ NullableNotNullDialog dialog = new NullableNotNullDialog(project, showInstrumentationOptions);
+ dialog.show();
+ }
+
@Override
protected JComponent createCenterPanel() {
- final NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject);
final Splitter splitter = new Splitter(true);
- myNullablePanel =
- new AnnotationsPanel("Nullable", manager.getDefaultNullable(), manager.getNullables(), NullableNotNullManager.DEFAULT_NULLABLES);
splitter.setFirstComponent(myNullablePanel.getComponent());
- myNotNullPanel =
- new AnnotationsPanel("NotNull", manager.getDefaultNotNull(), manager.getNotNulls(), ArrayUtil.toStringArray(manager.getPredefinedNotNulls()));
splitter.setSecondComponent(myNotNullPanel.getComponent());
splitter.setHonorComponentsMinimumSize(true);
splitter.setPreferredSize(JBUI.size(300, 400));
@@ -102,78 +126,137 @@ public class NullableNotNullDialog extends DialogWrapper {
manager.setNullables(myNullablePanel.getAnnotations());
manager.setDefaultNullable(myNullablePanel.getDefaultAnnotation());
+ if (myShowInstrumentationOptions) {
+ manager.setInstrumentedNotNulls(myNotNullPanel.getCheckedAnnotations());
+ }
+
super.doOKAction();
}
private class AnnotationsPanel {
private String myDefaultAnnotation;
private final Set myDefaultAnnotations;
- private final JBList myList;
+ private final JBTable myTable;
private final JPanel myComponent;
+ private final DefaultTableModel myTableModel;
- private AnnotationsPanel(final String name, final String defaultAnnotation,
- final Collection annotations, final String[] defaultAnnotations) {
+ private AnnotationsPanel(String name, String defaultAnnotation, List annotations, String[] defaultAnnotations, Set checkedAnnotations, boolean showInstrumentationOptions) {
myDefaultAnnotation = defaultAnnotation;
myDefaultAnnotations = new HashSet<>(Arrays.asList(defaultAnnotations));
- myList = new JBList<>(annotations);
- myList.setCellRenderer(new ColoredListCellRenderer() {
+ myTableModel = new DefaultTableModel() {
@Override
- protected void customizeCellRenderer(@NotNull JList list, String value, int index, boolean selected, boolean hasFocus) {
- append(value, SimpleTextAttributes.REGULAR_ATTRIBUTES);
+ public boolean isCellEditable(int row, int column) {
+ return column == 1;
+ }
+ };
+ myTableModel.setColumnCount(showInstrumentationOptions ? 2 : 1);
+ for (String annotation : annotations) {
+ addRow(annotation, checkedAnnotations.contains(annotation));
+ }
+
+ DefaultTableColumnModel columnModel = new DefaultTableColumnModel();
+ columnModel.addColumn(new TableColumn(0, 100, new ColoredTableCellRenderer() {
+ @Override
+ public void acquireState(JTable table, boolean isSelected, boolean hasFocus, int row, int column) {
+ super.acquireState(table, isSelected, false, row, column);
+ }
+
+ @Override
+ protected void customizeCellRenderer(JTable table,
+ Object value,
+ boolean selected,
+ boolean hasFocus,
+ int row,
+ int column) {
+ append((String)value, SimpleTextAttributes.REGULAR_ATTRIBUTES);
if (value.equals(myDefaultAnnotation)) {
setIcon(AllIcons.Diff.CurrentLine);
} else {
setIcon(EmptyIcon.ICON_16);
}
- //if (myDefaultAnnotations.contains(value)) {
- // append(" (built in)", SimpleTextAttributes.GRAY_ATTRIBUTES);
- //}
}
- });
+ }, null));
+ if (showInstrumentationOptions) {
+ columnModel.getColumn(0).setHeaderValue("Annotation");
+
+ TableColumn checkColumn = new TableColumn(1, 100, new BooleanTableCellRenderer(), new BooleanTableCellEditor());
+ columnModel.addColumn(checkColumn);
+ checkColumn.setHeaderValue(" Instrument ");
+
+ DefaultTableCellHeaderRenderer renderer = new DefaultTableCellHeaderRenderer();
+ renderer.setToolTipText("Add runtime assertions for notnull-annotated methods and parameters");
+ checkColumn.setHeaderRenderer(renderer);
+ checkColumn.sizeWidthToFit();
+ }
+
+ myTable = new JBTable(myTableModel, columnModel);
final AnActionButton selectButton =
new AnActionButton("Select annotation used for code generation", AllIcons.Actions.Checked) {
@Override
public void actionPerformed(AnActionEvent e) {
- final String selectedValue = myList.getSelectedValue();
+ String selectedValue = getSelectedAnnotation();
if (selectedValue == null) return;
myDefaultAnnotation = selectedValue;
- DefaultListModel model = (DefaultListModel)myList.getModel();
// to show the new default value in the ui
- model.setElementAt(myList.getSelectedValue(), myList.getSelectedIndex());
+ myTableModel.fireTableRowsUpdated(myTable.getSelectedRow(), myTable.getSelectedRow());
}
@Override
public void updateButton(AnActionEvent e) {
- String selectedValue = myList.getSelectedValue();
+ String selectedValue = getSelectedAnnotation();
e.getPresentation().setEnabled(selectedValue != null && !selectedValue.equals(myDefaultAnnotation));
}
};
- final ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myList).disableUpDownActions()
- .setAddAction(b -> chooseAnnotation(name, myList))
- .setRemoveAction(new AnActionButtonRunnable() {
+ final ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myTable).disableUpDownActions()
+ .setAddAction(b -> chooseAnnotation(name))
+ .setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton anActionButton) {
- final String selectedValue = myList.getSelectedValue();
+ String selectedValue = getSelectedAnnotation();
if (selectedValue == null) return;
- if (myDefaultAnnotation.equals(selectedValue)) myDefaultAnnotation = myList.getModel().getElementAt(0);
+ if (myDefaultAnnotation.equals(selectedValue)) myDefaultAnnotation = (String)myTable.getValueAt(0, 0);
- ((DefaultListModel)myList.getModel()).removeElement(selectedValue);
+ myTableModel.removeRow(myTable.getSelectedRow());
}
})
- .setRemoveActionUpdater(e -> !myDefaultAnnotations.contains(myList.getSelectedValue()))
- .addExtraAction(selectButton);
+ .setRemoveActionUpdater(e -> !myDefaultAnnotations.contains(getSelectedAnnotation()))
+ .addExtraAction(selectButton);
final JPanel panel = toolbarDecorator.createPanel();
myComponent = new JPanel(new BorderLayout());
myComponent.setBorder(IdeBorderFactory.createTitledBorder(name + " annotations", false, JBUI.insetsTop(10)));
myComponent.add(panel);
- myList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- myList.setSelectedValue(myDefaultAnnotation, true);
+ myComponent.setPreferredSize(new JBDimension(myComponent.getPreferredSize().width, 200));
+
+ myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ myTable.setRowSelectionAllowed(true);
+ myTable.setShowGrid(false);
+
+ selectAnnotation(myDefaultAnnotation);
}
- private void chooseAnnotation(String title, JBList list) {
+ private void addRow(String annotation, boolean checked) {
+ myTableModel.addRow(new Object[]{annotation, checked});
+ }
+
+ private Integer selectAnnotation(String annotation) {
+ for (int i = 0; i < myTable.getRowCount(); i++) {
+ if (annotation.equals(myTable.getValueAt(i, 0))) {
+ myTable.setRowSelectionInterval(i, i);
+ return i;
+ }
+ }
+ return null;
+ }
+
+ private String getSelectedAnnotation() {
+ int selectedRow = myTable.getSelectedRow();
+ return selectedRow <0 ? null : (String)myTable.getValueAt(selectedRow, 0);
+ }
+
+ private void chooseAnnotation(String title) {
final TreeClassChooser chooser = TreeClassChooserFactory.getInstance(myProject)
.createNoInnerClassesScopeChooser("Choose " + title + " annotation", GlobalSearchScope.allScope(myProject), new ClassFilter() {
@Override
@@ -187,30 +270,34 @@ public class NullableNotNullDialog extends DialogWrapper {
return;
}
final String qualifiedName = selected.getQualifiedName();
- //noinspection unchecked
- final DefaultListModel model = (DefaultListModel)list.getModel();
- final int index = model.indexOf(qualifiedName);
- if (index < 0) {
- model.addElement(qualifiedName);
- } else {
- myList.setSelectedIndex(index);
+ if (selectAnnotation(qualifiedName) == null) {
+ addRow(qualifiedName, false);
}
}
- public JComponent getComponent() {
+ JComponent getComponent() {
return myComponent;
}
- public String getDefaultAnnotation() {
+ String getDefaultAnnotation() {
return myDefaultAnnotation;
}
- public String[] getAnnotations() {
- final ListModel model = myList.getModel();
- final int size = model.getSize();
- final String[] result = new String[size];
+ String[] getAnnotations() {
+ int size = myTable.getRowCount();
+ String[] result = new String[size];
for (int i = 0; i < size; i++) {
- result[i] = (String)model.getElementAt(i);
+ result[i] = (String)myTable.getValueAt(i, 0);
+ }
+ return result;
+ }
+
+ List getCheckedAnnotations() {
+ List result = new ArrayList<>();
+ for (int i = 0; i < myTable.getRowCount(); i++) {
+ if (Boolean.TRUE.equals(myTable.getValueAt(i, 1))) {
+ result.add((String)myTable.getValueAt(i, 0));
+ }
}
return result;
}
diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/JpsJavaCompilerNotNullableSerializer.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/JpsJavaCompilerNotNullableSerializer.java
index f488f32af719..12c15ecc8262 100644
--- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/JpsJavaCompilerNotNullableSerializer.java
+++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/compiler/JpsJavaCompilerNotNullableSerializer.java
@@ -23,24 +23,13 @@ import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
import org.jetbrains.jps.model.serialization.JpsProjectExtensionSerializer;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
/**
* @author vladimir.dolzhenko
*/
public class JpsJavaCompilerNotNullableSerializer extends JpsProjectExtensionSerializer {
- public static final List DEFAULT_NOT_NULLS = Arrays.asList(
- NotNull.class.getName(),
- "javax.annotation.Nonnull",
- "javax.validation.constraints.NotNull",
- "edu.umd.cs.findbugs.annotations.NonNull",
- "android.support.annotation.NonNull",
- "androidx.annotation.NonNull",
- "org.checkerframework.checker.nullness.qual.NonNull",
- "org.checkerframework.checker.nullness.compatqual.NonNullDecl",
- "org.checkerframework.checker.nullness.compatqual.NonNullType"
- );
public JpsJavaCompilerNotNullableSerializer() {
super("misc.xml", "NullableNotNullManager");
@@ -50,26 +39,21 @@ public class JpsJavaCompilerNotNullableSerializer extends JpsProjectExtensionSer
public void loadExtension(@NotNull JpsProject project, @NotNull Element componentTag) {
JpsJavaCompilerConfiguration configuration = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project);
List annoNames = ContainerUtil.newArrayList();
- for (Element option : componentTag.getChildren("option")) {
- if ("myNotNulls".equals(option.getAttributeValue("name"))){
- for (Element value : option.getChildren("value")) {
- for (Element list : value.getChildren("list")) {
- for (Element item : list.getChildren("item")) {
- ContainerUtil.addIfNotNull(annoNames, item.getAttributeValue("itemvalue"));
- }
- }
- }
+ for (Element option : componentTag.getChildren("instrumentedNotNulls")) {
+ for (Element item : option.getChildren("option")) {
+ ContainerUtil.addIfNotNull(annoNames, item.getAttributeValue("value"));
}
}
if (annoNames.isEmpty()) {
- annoNames.addAll(DEFAULT_NOT_NULLS);
+ annoNames.add(NotNull.class.getName());
}
configuration.setNotNullAnnotations(annoNames);
}
@Override
public void loadExtensionWithDefaultSettings(@NotNull JpsProject project) {
- JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project).setNotNullAnnotations(DEFAULT_NOT_NULLS);
+ JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project).setNotNullAnnotations(
+ Collections.singletonList(NotNull.class.getName()));
}
@Override
diff --git a/resources-en/src/messages/CompilerBundle.properties b/resources-en/src/messages/CompilerBundle.properties
index f5796a778436..d70a36e6f34b 100644
--- a/resources-en/src/messages/CompilerBundle.properties
+++ b/resources-en/src/messages/CompilerBundle.properties
@@ -103,7 +103,7 @@ statistics.warnings.count={0} {0,choice, 0#warnings|1#warning|2#warnings}
compiler.running.dialog.title=Compiler Running
warning.compiler.running.on.project.close=The compiler is running. Proceed with project closing?
warning.compiler.running.on.toolwindow.close=The compiler is running. Terminate it?
-add.notnull.assertions=Add runtime &assertions for not-null-annotated methods and parameters
+add.notnull.assertions=Add runtime &assertions for notnull-annotated methods and parameters
compiler.eclipse.name=Eclipse
eclipse.options.group.title=Eclipse Options