mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-01 17:03:12 +07:00
PY-18525 Suggest Python compatibility inspection for compatible-looking code
This commit is contained in:
committed by
Andrey Vlasovskikh
parent
6c1d3b4de5
commit
0db5ac3c11
@@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
@@ -52,7 +53,7 @@ public enum LanguageLevel {
|
||||
.build();
|
||||
|
||||
private static final LanguageLevel DEFAULT2 = PYTHON27;
|
||||
private static final LanguageLevel DEFAULT3 = PYTHON34;
|
||||
private static final LanguageLevel DEFAULT3 = PYTHON35;
|
||||
|
||||
public static LanguageLevel FORCE_LANGUAGE_LEVEL = null;
|
||||
|
||||
@@ -158,6 +159,12 @@ public enum LanguageLevel {
|
||||
return getDefault();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static LanguageLevel getLatest() {
|
||||
//noinspection ConstantConditions
|
||||
return ArrayUtil.getLastElement(values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myVersion / 10 + "." + myVersion % 10;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
<highlightRangeExtension implementation="com.jetbrains.python.validation.DumbAwareHighlightingAnnotator"/>
|
||||
<annotator language="Python" implementationClass="com.jetbrains.python.validation.PyAnnotatingVisitor"/>
|
||||
<annotator language="Python" implementationClass="com.jetbrains.python.validation.PyDumbAwareAnnotator"/>
|
||||
<annotator language="Python" implementationClass="com.jetbrains.python.inspections.PyCompatibilityInspectionAdvertiser"/>
|
||||
<quoteHandler fileType="Python" className="com.jetbrains.python.editor.PythonQuoteHandler"/>
|
||||
<enterHandlerDelegate implementation="com.jetbrains.python.editor.PythonEnterHandler"/>
|
||||
<enterHandlerDelegate implementation="com.jetbrains.python.editor.PyEnterAtIndentHandler" order="first"/>
|
||||
@@ -93,6 +94,8 @@
|
||||
serviceImplementation="com.jetbrains.python.psi.types.TypeEvalContextCacheImpl"
|
||||
/>
|
||||
|
||||
<projectService serviceImplementation="com.jetbrains.python.inspections.PyCompatibilityInspectionAdvertiserSettings"/>
|
||||
|
||||
<applicationService serviceInterface="com.jetbrains.python.packaging.PyPackageService"
|
||||
serviceImplementation="com.jetbrains.python.packaging.PyPackageService"/>
|
||||
<applicationService serviceInterface="com.jetbrains.python.packaging.PyCondaPackageService"
|
||||
|
||||
@@ -15,23 +15,26 @@
|
||||
*/
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.intellij.codeInspection.InspectionProfile;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.ide.util.ElementsChooser;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.JDOMExternalizableStringList;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
@@ -47,8 +50,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
@@ -59,15 +60,24 @@ import java.util.List;
|
||||
* Inspection to detect code incompatibility with python versions
|
||||
*/
|
||||
public class PyCompatibilityInspection extends PyInspection {
|
||||
public static final int LATEST_INSPECTION_VERSION = 1;
|
||||
public static final List<LanguageLevel> DEFAULT_PYTHON_VERSIONS = ImmutableList.of(LanguageLevel.PYTHON27, LanguageLevel.getLatest());
|
||||
|
||||
public JDOMExternalizableStringList ourVersions = new JDOMExternalizableStringList();
|
||||
// Legacy DefaultJDOMExternalizer requires public fields for proper serialization
|
||||
public JDOMExternalizableStringList ourVersions = new JDOMExternalizableStringList(ContainerUtil.map(DEFAULT_PYTHON_VERSIONS, LanguageLevel::toString));
|
||||
|
||||
public PyCompatibilityInspection () {
|
||||
super();
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
ourVersions.addAll(UnsupportedFeaturesUtil.ALL_LANGUAGE_LEVELS);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PyCompatibilityInspection getInstance(@NotNull PsiElement element) {
|
||||
final InspectionProfile inspectionProfile = InspectionProjectProfileManager.getInstance(element.getProject()).getInspectionProfile();
|
||||
final String toolName = PyCompatibilityInspection.class.getSimpleName();
|
||||
return (PyCompatibilityInspection)inspectionProfile.getUnwrappedTool(toolName, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledByDefault() {
|
||||
@@ -93,42 +103,21 @@ public class PyCompatibilityInspection extends PyInspection {
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
final JPanel versionPanel = new JPanel(new BorderLayout());
|
||||
final JBList list = new JBList(UnsupportedFeaturesUtil.ALL_LANGUAGE_LEVELS);
|
||||
|
||||
JLabel label = new JLabel("Check for compatibility with python versions:");
|
||||
label.setLabelFor(list);
|
||||
versionPanel.add(label, BorderLayout.PAGE_START);
|
||||
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
JBScrollPane scrollPane = new JBScrollPane(list, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
|
||||
versionPanel.add(scrollPane);
|
||||
|
||||
int[] indices = new int[ourVersions.size()];
|
||||
for (int i = 0; i != ourVersions.size(); ++i) {
|
||||
String s = ourVersions.get(i);
|
||||
indices[i] = UnsupportedFeaturesUtil.ALL_LANGUAGE_LEVELS.indexOf(s);
|
||||
}
|
||||
|
||||
list.setSelectedIndices(indices);
|
||||
list.setCellRenderer(new DefaultListCellRenderer() {
|
||||
final ElementsChooser<String> chooser = new ElementsChooser<String>(true);
|
||||
chooser.setElements(UnsupportedFeaturesUtil.ALL_LANGUAGE_LEVELS, false);
|
||||
chooser.markElements(ourVersions);
|
||||
chooser.addElementsMarkListener(new ElementsChooser.ElementsMarkListener<String>() {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object o, int i, boolean b, boolean b2) {
|
||||
return super
|
||||
.getListCellRendererComponent(list, "Python " + o, i, b, b2);
|
||||
}
|
||||
});
|
||||
list.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent event) {
|
||||
public void elementMarkChanged(String element, boolean isMarked) {
|
||||
ourVersions.clear();
|
||||
for (Object value : list.getSelectedValues()) {
|
||||
ourVersions.add((String)value);
|
||||
}
|
||||
ourVersions.addAll(chooser.getMarkedElements());
|
||||
}
|
||||
});
|
||||
|
||||
final JPanel versionPanel = new JPanel(new BorderLayout());
|
||||
JLabel label = new JLabel("Check for compatibility with python versions:");
|
||||
label.setLabelFor(chooser);
|
||||
versionPanel.add(label, BorderLayout.PAGE_START);
|
||||
versionPanel.add(chooser);
|
||||
return versionPanel;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
|
||||
import com.intellij.codeInspection.InspectionProfile;
|
||||
import com.intellij.codeInspection.ex.EditInspectionToolsSettingsAction;
|
||||
import com.intellij.codeInspection.ex.InspectionProfileImpl;
|
||||
import com.intellij.codeInspection.ex.InspectionToolWrapper;
|
||||
import com.intellij.codeInspection.ex.ScopeToolState;
|
||||
import com.intellij.lang.annotation.AnnotationHolder;
|
||||
import com.intellij.lang.annotation.Annotator;
|
||||
import com.intellij.notification.NotificationDisplayType;
|
||||
import com.intellij.notification.NotificationGroup;
|
||||
import com.intellij.notification.NotificationListener;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.JDOMExternalizableStringList;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import com.jetbrains.python.psi.PyFile;
|
||||
import com.jetbrains.python.psi.PyFromImportStatement;
|
||||
import com.jetbrains.python.psi.PyImportElement;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.jetbrains.python.psi.PyUtil.as;
|
||||
|
||||
/**
|
||||
* @author Mikhail Golubev
|
||||
*/
|
||||
public class PyCompatibilityInspectionAdvertiser implements Annotator {
|
||||
|
||||
private static final String NOTIFICATIONS_TITLE = "Python Versions Compatibility";
|
||||
private static final NotificationGroup BALLOON_NOTIFICATIONS = new NotificationGroup("Python Compatibility Inspection Advertiser",
|
||||
NotificationDisplayType.STICKY_BALLOON, false);
|
||||
private static final Key<Boolean> DONT_SHOW_BALLOON = Key.create("showingPyCompatibilityAdvertiserBalloon");
|
||||
|
||||
// Allow to show declined suggestion multiple times to ease debugging
|
||||
private static final boolean SHOW_ONCE_FOR_VERSION = true;
|
||||
|
||||
@Language("HTML")
|
||||
private static final String YES_NO_REFS = "<a href=\"#yes\">Yes</a> <a href=\"#no\">No</a>";
|
||||
private static final String USING_FUTURE_IMPORTS = "Your source code contains __future__ imports";
|
||||
private static final String USING_SIX = "Your source code imports the 'six' package";
|
||||
|
||||
@Override
|
||||
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
|
||||
if (element instanceof PyFile) {
|
||||
|
||||
final PyFile pyFile = (PyFile)element;
|
||||
final Project project = element.getProject();
|
||||
|
||||
final Boolean showingFlag = project.getUserData(DONT_SHOW_BALLOON);
|
||||
if (showingFlag != null && showingFlag.booleanValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int inspectionVersion = getSettings(project).version;
|
||||
if (inspectionVersion < PyCompatibilityInspection.LATEST_INSPECTION_VERSION) {
|
||||
if (isCompatibilityInspectionEnabled(element)) {
|
||||
final LanguageLevel pyVersion = getLatestConfiguredCompatiblePython3Version(element);
|
||||
if (pyVersion != null && pyVersion.isOlderThan(LanguageLevel.getLatest())) {
|
||||
showStalePython3VersionWarning(pyFile, project, pyVersion);
|
||||
}
|
||||
}
|
||||
else if (containsFutureImports(pyFile)) {
|
||||
showInspectionAdvertisement(project, USING_FUTURE_IMPORTS);
|
||||
}
|
||||
else if (containsSixImport(pyFile)) {
|
||||
showInspectionAdvertisement(project, USING_SIX);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LanguageLevel getLatestConfiguredCompatiblePython3Version(@NotNull PsiElement element) {
|
||||
final LanguageLevel latestVersion = getLatestConfiguredCompatiblePythonVersion(element);
|
||||
return latestVersion != null && latestVersion.isAtLeast(LanguageLevel.PYTHON30) ? latestVersion : null;
|
||||
}
|
||||
|
||||
private static void showStalePython3VersionWarning(@NotNull PyFile file,
|
||||
@NotNull Project project,
|
||||
@NotNull LanguageLevel latestConfiguredVersion) {
|
||||
final List<LanguageLevel> versionsToEnable = getVersionsNewerThan(latestConfiguredVersion);
|
||||
final String versionsList = StringUtil.join(versionsToEnable, ", ");
|
||||
final String message =
|
||||
String.format("Code compatibility inspection is configured for Python versions up to %s.<br/>" +
|
||||
"Would you like to enable it for Python %s?<br/>" + YES_NO_REFS, latestConfiguredVersion, versionsList);
|
||||
showSingletonNotification(project, NOTIFICATIONS_TITLE, message, NotificationType.INFORMATION, (notification, event) -> {
|
||||
final boolean enabled = "#yes".equals(event.getDescription());
|
||||
if (enabled) {
|
||||
enableVersions(project, file, versionsToEnable);
|
||||
}
|
||||
if (enabled || SHOW_ONCE_FOR_VERSION) {
|
||||
getSettings(project).version = PyCompatibilityInspection.LATEST_INSPECTION_VERSION;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<LanguageLevel> getVersionsNewerThan(@NotNull LanguageLevel version) {
|
||||
final List<LanguageLevel> result = new ArrayList<>();
|
||||
final LanguageLevel latest = LanguageLevel.getLatest();
|
||||
for (LanguageLevel level : LanguageLevel.values()) {
|
||||
if (version.isOlderThan(level) && latest.isAtLeast(level)) {
|
||||
result.add(level);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void enableVersions(@NotNull Project project, @NotNull PsiElement file, @NotNull List<LanguageLevel> versions) {
|
||||
final InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
|
||||
final String shortName = getCompatibilityInspectionShortName();
|
||||
final InspectionToolWrapper tool = profile.getInspectionTool(shortName, project);
|
||||
if (tool != null) {
|
||||
profile.modifyProfile(model -> {
|
||||
final PyCompatibilityInspection inspection = (PyCompatibilityInspection)model.getUnwrappedTool(shortName, file);
|
||||
inspection.ourVersions.addAll(ContainerUtil.map(versions, LanguageLevel::toString));
|
||||
});
|
||||
EditInspectionToolsSettingsAction.editToolSettings(project, profile, true, shortName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void showInspectionAdvertisement(@NotNull Project project, @NotNull String message) {
|
||||
final String msg = message + ".<br/>Would you like to enable Code compatibility inspection?<br/>" + YES_NO_REFS;
|
||||
showSingletonNotification(project, NOTIFICATIONS_TITLE, msg, NotificationType.INFORMATION, (notification, event) -> {
|
||||
final boolean enabled = "#yes".equals(event.getDescription());
|
||||
if (enabled) {
|
||||
enableCompatibilityInspection(project);
|
||||
}
|
||||
if (enabled || SHOW_ONCE_FOR_VERSION) {
|
||||
getSettings(project).version = PyCompatibilityInspection.LATEST_INSPECTION_VERSION;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void showSingletonNotification(@NotNull Project project,
|
||||
@NotNull String title,
|
||||
@NotNull String htmlContent,
|
||||
@NotNull NotificationType type,
|
||||
@NotNull NotificationListener listener) {
|
||||
project.putUserData(DONT_SHOW_BALLOON, true);
|
||||
BALLOON_NOTIFICATIONS.createNotification(title, htmlContent, type, (notification, event) -> {
|
||||
try {
|
||||
listener.hyperlinkUpdate(notification, event);
|
||||
}
|
||||
finally {
|
||||
notification.expire();
|
||||
}
|
||||
}).notify(project);
|
||||
}
|
||||
|
||||
private static boolean containsSixImport(@NotNull PyFile file) {
|
||||
for (PyFromImportStatement importStatement : file.getFromImports()) {
|
||||
final QualifiedName name = importStatement.getImportSourceQName();
|
||||
if (name != null && "six".equals(name.toString())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (PyImportElement importElement : file.getImportTargets()) {
|
||||
final QualifiedName name = importElement.getImportedQName();
|
||||
if (name != null && "six".equals(name.getFirstComponent())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean containsFutureImports(@NotNull PyFile file) {
|
||||
for (PyFromImportStatement importStatement : file.getFromImports()) {
|
||||
if (importStatement.isFromFuture()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isCompatibilityInspectionEnabled(@NotNull PsiElement anchor) {
|
||||
final InspectionProfile profile = InspectionProjectProfileManager.getInstance(anchor.getProject()).getInspectionProfile();
|
||||
final InspectionToolWrapper tool = profile.getInspectionTool(getCompatibilityInspectionShortName(), anchor.getProject());
|
||||
return tool != null && profile.isToolEnabled(HighlightDisplayKey.findById(tool.getID()), anchor);
|
||||
}
|
||||
|
||||
private static void enableCompatibilityInspection(@NotNull Project project) {
|
||||
final InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
|
||||
final InspectionToolWrapper tool = profile.getInspectionTool(getCompatibilityInspectionShortName(), project);
|
||||
if (tool != null) {
|
||||
// Partially copied from JSLinterInspection
|
||||
final InspectionProfileImpl inspectionProfileImpl = as(profile, InspectionProfileImpl.class);
|
||||
if (inspectionProfileImpl != null) {
|
||||
final ScopeToolState state = inspectionProfileImpl.getToolDefaultState(tool.getShortName(), project);
|
||||
state.setEnabled(true);
|
||||
}
|
||||
profile.modifyProfile(model -> model.enableTool(tool.getShortName(), null, project));
|
||||
EditInspectionToolsSettingsAction.editToolSettings(project, profile, true, getCompatibilityInspectionShortName());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LanguageLevel getLatestConfiguredCompatiblePythonVersion(@NotNull PsiElement anchor) {
|
||||
final InspectionProfile profile = InspectionProjectProfileManager.getInstance(anchor.getProject()).getInspectionProfile();
|
||||
final PyCompatibilityInspection inspection = (PyCompatibilityInspection)profile.getUnwrappedTool(getCompatibilityInspectionShortName(), anchor);
|
||||
final JDOMExternalizableStringList versions = inspection.ourVersions;
|
||||
if (versions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final String maxVersion = Collections.max(versions);
|
||||
return LanguageLevel.fromPythonVersion(maxVersion);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getCompatibilityInspectionShortName() {
|
||||
return PyCompatibilityInspection.class.getSimpleName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PyCompatibilityInspectionAdvertiserSettings getSettings(@NotNull Project project) {
|
||||
return ServiceManager.getService(project, PyCompatibilityInspectionAdvertiserSettings.class);
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Mikhail Golubev
|
||||
*/
|
||||
@State(name = "PythonCompatibilityInspectionAdvertiser")
|
||||
public class PyCompatibilityInspectionAdvertiserSettings implements PersistentStateComponent<PyCompatibilityInspectionAdvertiserSettings> {
|
||||
public int version = 0;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PyCompatibilityInspectionAdvertiserSettings getState() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(PyCompatibilityInspectionAdvertiserSettings state) {
|
||||
XmlSerializerUtil.copyBean(state, this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user