mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Move externalizable check to inspection
(IDEABKL-3776 "Externalizable class should have public no-args constructor" warning false negative)
This commit is contained in:
+1
-31
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 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.
|
||||
@@ -756,36 +756,6 @@ public class HighlightClassUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static HighlightInfo checkExternalizableHasPublicNoArgsConstructor(PsiClass aClass, PsiElement context) {
|
||||
if (!isExternalizable(aClass) || aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
return null;
|
||||
}
|
||||
PsiMethod[] constructors = aClass.getConstructors();
|
||||
boolean hasPublicNoArgsConstructor = constructors.length == 0;
|
||||
for (PsiMethod constructor : constructors) {
|
||||
if (constructor.getParameterList().getParametersCount() == 0 && constructor.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
hasPublicNoArgsConstructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasPublicNoArgsConstructor) {
|
||||
HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.WARNING,
|
||||
context,
|
||||
JavaErrorMessages.message("externalizable.class.should.have.public.constructor"));
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createAddDefaultConstructorFix(aClass));
|
||||
return highlightInfo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isExternalizable(PsiClass aClass) {
|
||||
PsiManager manager = aClass.getManager();
|
||||
PsiClass externalizableClass =
|
||||
JavaPsiFacade.getInstance(manager.getProject()).findClass("java.io.Externalizable", aClass.getResolveScope());
|
||||
return externalizableClass != null && aClass.isInheritor(externalizableClass, true);
|
||||
}
|
||||
|
||||
public static boolean hasEnclosingInstanceInScope(PsiClass aClass, PsiElement scope, final boolean isSuperClassAccepted) {
|
||||
PsiManager manager = aClass.getManager();
|
||||
PsiElement place = scope;
|
||||
|
||||
-1
@@ -407,7 +407,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
|
||||
myHolder.add(HighlightClassUtil.checkClassAlreadyImported(aClass, identifier));
|
||||
myHolder.add(HighlightClassUtil.checkExternalizableHasPublicNoArgsConstructor(aClass, identifier));
|
||||
if (!(parent instanceof PsiAnonymousClass) && aClass.getNameIdentifier() == identifier) {
|
||||
myHolder.add(HighlightNamesUtil.highlightClassName(aClass, identifier, colorsScheme));
|
||||
}
|
||||
|
||||
@@ -107,7 +107,6 @@ qualified.new.of.static.class=Qualified new of static class
|
||||
invalid.qualified.new=Invalid qualified new
|
||||
class.name.expected=Class name expected
|
||||
no.enclosing.instance.in.scope=No enclosing instance of type ''{0}'' is in scope
|
||||
externalizable.class.should.have.public.constructor=Externalizable class should have public no-args constructor
|
||||
is.not.an.enclosing.class=''{0}'' is not an enclosing class
|
||||
cannot.be.referenced.from.static.context=''{0}'' cannot be referenced from a static context
|
||||
no.default.constructor.available=There is no default constructor available in ''{0}''
|
||||
|
||||
-27
@@ -48,33 +48,6 @@ class b {
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
abstract class e implements Externalizable {
|
||||
}
|
||||
class eImpl extends e {
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
}
|
||||
}
|
||||
class <warning descr="Externalizable class should have public no-args constructor">eImpl1</warning> extends e {
|
||||
private eImpl1() {}
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
}
|
||||
}
|
||||
class <warning descr="Externalizable class should have public no-args constructor">eImpl2</warning> extends e {
|
||||
public eImpl2(int i) {
|
||||
System.out.print(i);
|
||||
}
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class abstractNoSerializable {
|
||||
protected Object readResolve() throws ObjectStreamException {
|
||||
|
||||
@@ -2025,6 +2025,10 @@
|
||||
key="comparator.not.serializable.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.serialization.issues" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.serialization.ComparatorNotSerializableInspection"/>
|
||||
<localInspection language="JAVA" shortName="ExternalizableWithoutPublicNoArgConstructor" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="externalizable.without.public.no.arg.constructor.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.serialization.issues" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.serialization.ExternalizableWithoutPublicNoArgConstructorInspection"/>
|
||||
<localInspection language="JAVA" suppressId="ExternalizableClassWithSerializationMethods" shortName="ExternalizableWithSerializationMethods"
|
||||
bundle="com.siyeh.InspectionGadgetsBundle" key="externalizable.with.serialization.methods.display.name"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.serialization.issues" enabledByDefault="false"
|
||||
@@ -2187,7 +2191,7 @@
|
||||
<localInspection language="JAVA" shortName="SimplifiableEqualsExpression" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="simplifiable.equals.expression.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.code.style.issues" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.style.SimplifiableEqualsExpressionInspection"/>
|
||||
implementationClass="com.siyeh.ig.controlflow.SimplifiableEqualsExpressionInspection"/>
|
||||
<localInspection language="JAVA" shortName="StringBufferReplaceableByString" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="string.buffer.replaceable.by.string.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.performance.issues" enabledByDefault="true" level="WARNING"
|
||||
|
||||
@@ -1114,7 +1114,7 @@ public.constructor.in.non.public.class.problem.descriptor=Constructor is declare
|
||||
static.inheritance.replace.quickfix=Replace inheritance with qualified references in {0}
|
||||
utility.class.with.public.constructor.make.quickfix=Make {0, choice, 1#constructor|2#constructors} private
|
||||
utility.class.without.private.constructor.create.quickfix=Generate empty private constructor
|
||||
utility.class.without.private.constructor.make.quickfix=Make constructor private
|
||||
utility.class.without.private.constructor.make.quickfix=Make constructor 'private'
|
||||
annotation.naming.convention.problem.descriptor.short=Annotation name <code>#ref</code> is too short #loc
|
||||
annotation.naming.convention.problem.descriptor.long=Annotation name <code>#ref</code> is too long #loc
|
||||
annotation.naming.convention.problem.descriptor.regex.mismatch=Annotation name <code>#ref</code> doesn''t match regex ''{0}'' #loc
|
||||
@@ -1208,7 +1208,7 @@ unsecure.random.number.generation.problem.descriptor3=For security purposes, use
|
||||
serializable.has.serialization.methods.problem.descriptor=Serializable class <code>#ref</code> does not define 'readObject()' or 'writeObject()' #loc
|
||||
serializable.has.serialization.methods.problem.descriptor1=Serializable class <code>#ref</code> does not define 'writeObject()' #loc
|
||||
serializable.has.serialization.methods.problem.descriptor2=Serializable class <code>#ref</code> does not define 'readObject()' #loc
|
||||
serializable.with.unconstructable.ancestor.problem.descriptor=<code>#ref</code> has an non-serializable ancestor ''{0}'' without a no-arg constructor #loc
|
||||
serializable.with.unconstructable.ancestor.problem.descriptor=<code>#ref</code> has a non-serializable ancestor ''{0}'' without no-arg constructor #loc
|
||||
transient.field.in.non.serializable.class.problem.descriptor=Field ''{0}'' is marked <code>#ref</code>, in non-Serializable class #loc
|
||||
transient.field.in.non.serializable.class.remove.quickfix=Remove 'transient'
|
||||
condition.signal.replace.quickfix=Replace with 'signalAll()'
|
||||
@@ -1957,4 +1957,7 @@ string.builder.replaceable.by.string.quickfix=Replace 'StringBuilder' with 'Stri
|
||||
string.buffer.replaceable.by.string.quickfix=Replace 'StringBuffer' with 'String'
|
||||
add.0.to.ignore.if.annotated.by.list.quickfix=Add ''{0}'' to ''Ignore if annotated by'' list
|
||||
non.final.field.in.enum.display.name=Non-'final' field in enum
|
||||
non.final.field.in.enum.problem.descriptor=non-''final'' field <code>#ref</code> in enum ''{0}''
|
||||
non.final.field.in.enum.problem.descriptor=non-''final'' field <code>#ref</code> in enum ''{0}''
|
||||
externalizable.without.public.no.arg.constructor.display.name=Externalizable class without public no-arg constructor
|
||||
externalizable.without.public.no.arg.constructor.problem.descriptor=Externalizable class <code>#ref</code> has no public no-arg constructor
|
||||
make.constructor.public=Make constructor 'public'
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.siyeh.ig.serialization;
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.AddDefaultConstructorFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.DelegatingFix;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class ExternalizableWithoutPublicNoArgConstructorInspection extends BaseInspection {
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("externalizable.without.public.no.arg.constructor.display.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("externalizable.without.public.no.arg.constructor.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
final PsiMethod constructor = (PsiMethod)infos[1];
|
||||
if (constructor == null) {
|
||||
final PsiClass aClass = (PsiClass)infos[0];
|
||||
return new DelegatingFix(new AddDefaultConstructorFix(aClass, PsiModifier.PUBLIC));
|
||||
}
|
||||
else {
|
||||
return new MakeConstructorPublicFix();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod getNoArgConstructor(PsiClass aClass) {
|
||||
final PsiMethod[] constructors = aClass.getConstructors();
|
||||
for (PsiMethod constructor : constructors) {
|
||||
final PsiParameterList parameterList = constructor.getParameterList();
|
||||
if (parameterList.getParametersCount() == 0) {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class MakeConstructorPublicFix extends InspectionGadgetsFix {
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message("make.constructor.public");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFix(Project project, ProblemDescriptor descriptor)
|
||||
throws IncorrectOperationException {
|
||||
final PsiElement classNameIdentifier = descriptor.getPsiElement();
|
||||
final PsiClass aClass = (PsiClass)classNameIdentifier.getParent();
|
||||
if (aClass == null) {
|
||||
return;
|
||||
}
|
||||
final PsiMethod constructor = getNoArgConstructor(aClass);
|
||||
if (constructor == null) {
|
||||
return;
|
||||
}
|
||||
constructor.getModifierList().setModifierProperty(PsiModifier.PUBLIC, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new ExternalizableWithoutPublicNoArgConstructorVisitor();
|
||||
}
|
||||
|
||||
private static class ExternalizableWithoutPublicNoArgConstructorVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType() || aClass instanceof PsiTypeParameter) {
|
||||
return;
|
||||
}
|
||||
if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
return;
|
||||
}
|
||||
if (!isExternalizable(aClass)) {
|
||||
return;
|
||||
}
|
||||
final PsiMethod constructor = getNoArgConstructor(aClass);
|
||||
if (constructor == null) {
|
||||
if (aClass.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (constructor.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registerClassError(aClass, aClass, constructor);
|
||||
}
|
||||
|
||||
private static boolean isExternalizable(PsiClass aClass) {
|
||||
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(aClass.getProject());
|
||||
final PsiClass externalizableClass = psiFacade.findClass("java.io.Externalizable", aClass.getResolveScope());
|
||||
return externalizableClass != null && aClass.isInheritor(externalizableClass, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports a <b>Externalizable</b> classes without a public no-argument constructor.
|
||||
When an Externalizable object is reconstructed, an instance is created using the public no-arg constructor before the readExternal
|
||||
method called. If a public no-arg constructor is not present a <b>java.io.InvalidClassException</b> will be thrown at runtime.
|
||||
<p>
|
||||
<small>New in 12, Powered by InspectionGadgets</small>
|
||||
</body>
|
||||
</html>
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.siyeh.igtest.serialization.externalizable_without_public_no_arg_constructor;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
abstract class e implements Externalizable {
|
||||
|
||||
protected e() {}
|
||||
}
|
||||
class eImpl extends e {
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
}
|
||||
}
|
||||
class eImpl1 extends e {
|
||||
private eImpl1() {}
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
}
|
||||
}
|
||||
class eImpl2 extends e {
|
||||
public eImpl2(int i) {
|
||||
System.out.print(i);
|
||||
}
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>ExternalizableWithoutPublicNoArgConstructor.java</file>
|
||||
<line>9</line>
|
||||
<module>test_5975879954938100914</module>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Externalizable class without public no-arg constructor</problem_class>
|
||||
<description>Externalizable class <code>eImpl</code> has no public no-arg constructor</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ExternalizableWithoutPublicNoArgConstructor.java</file>
|
||||
<line>16</line>
|
||||
<entry_point TYPE="class" FQNAME="com.siyeh.igtest.serialization.externalizable_without_public_no_arg_constructor.eImpl1" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Externalizable class without public no-arg constructor</problem_class>
|
||||
<description>Externalizable class <code>eImpl1</code> has no public no-arg constructor</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ExternalizableWithoutPublicNoArgConstructor.java</file>
|
||||
<line>24</line>
|
||||
<entry_point TYPE="class" FQNAME="com.siyeh.igtest.serialization.externalizable_without_public_no_arg_constructor.eImpl2" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Externalizable class without public no-arg constructor</problem_class>
|
||||
<description>Externalizable class <code>eImpl2</code> has no public no-arg constructor</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.siyeh.ig.serialization;
|
||||
|
||||
import com.siyeh.ig.IGInspectionTestCase;
|
||||
|
||||
public class ExternalizableWithoutPublicNoArgConstructorInspectionTest extends IGInspectionTestCase {
|
||||
|
||||
public void test() throws Exception {
|
||||
doTest("com/siyeh/igtest/serialization/externalizable_without_public_no_arg_constructor",
|
||||
new ExternalizableWithoutPublicNoArgConstructorInspection());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user