From e5cda859f11f98c123d82f10a8610ceb979bb6f1 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Sun, 7 Dec 2014 22:21:40 +0300 Subject: [PATCH] OC: check usages of public members of @Serializable classes --- plugins/devkit/resources/META-INF/plugin.xml | 5 ++ .../OCSerializableCheck.html | 5 ++ .../idea/devkit/DevKitBundle.properties | 1 + .../OCSerializableCheckInspection.java | 83 +++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 plugins/devkit/resources/inspectionDescriptions/OCSerializableCheck.html create mode 100644 plugins/devkit/src/inspections/internal/OCSerializableCheckInspection.java diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index ef3688448fda..93a838191197 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -132,6 +132,11 @@ groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.internal.UseVirtualFileEqualsInspection"/> + + diff --git a/plugins/devkit/resources/inspectionDescriptions/OCSerializableCheck.html b/plugins/devkit/resources/inspectionDescriptions/OCSerializableCheck.html new file mode 100644 index 000000000000..04f7bf70c24f --- /dev/null +++ b/plugins/devkit/resources/inspectionDescriptions/OCSerializableCheck.html @@ -0,0 +1,5 @@ + + +In OC we use a serialization mechanism which forces us to declare public fields and public constructors. The inspection checks these public members are not used explicitly in code. + + \ No newline at end of file diff --git a/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties b/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties index 2d1f3de4e3d6..d916b40fb9d3 100644 --- a/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties +++ b/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties @@ -161,3 +161,4 @@ group.PluginDeployActions.text=Plugin Deployment Actions error.cannot.resolve.plugin=Cannot resolve plugin {0} create.description.file=Create Description File select.target.location.of.description=Select target location of {0} +serialization.only.member.used.explicitly=Serialization-only member used explicitly diff --git a/plugins/devkit/src/inspections/internal/OCSerializableCheckInspection.java b/plugins/devkit/src/inspections/internal/OCSerializableCheckInspection.java new file mode 100644 index 000000000000..04c5434cf518 --- /dev/null +++ b/plugins/devkit/src/inspections/internal/OCSerializableCheckInspection.java @@ -0,0 +1,83 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.idea.devkit.inspections.internal; + +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.devkit.DevKitBundle; + +/** + * Created by Max Medvedev on 07/12/14 + */ +public class OCSerializableCheckInspection extends InternalInspection { + + public static final String SERIALIZABLE = "com.jetbrains.objc.symbols.Serializable"; + + @Override + public PsiElementVisitor buildInternalVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + return new JavaElementVisitor() { + @Override + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + + PsiMethod constructor = expression.resolveConstructor(); + if (constructor != null && constructor.getParameterList().getParametersCount() == 0) { + checkSerializable(constructor, expression); + } + } + + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + + PsiElement resolved = expression.resolve(); + if (resolved instanceof PsiField) { + PsiElement nameElement = expression.getReferenceNameElement(); + if (nameElement != null) { + checkSerializable((PsiField)resolved, nameElement); + } + } + } + + private void checkSerializable(@NotNull PsiMember member, @NotNull PsiElement place) { + if (member.hasModifierProperty(PsiModifier.PUBLIC) && !isInInitializer(place)) { + PsiClass aClass = member.getContainingClass(); + if (aClass != null && !PsiTreeUtil.isAncestor(aClass, place, true)) { + PsiModifierList modifierList = aClass.getModifierList(); + if (modifierList != null && modifierList.findAnnotation(SERIALIZABLE) != null) { + String message = DevKitBundle.message("serialization.only.member.used.explicitly"); + holder.registerProblem(place, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + } + } + } + } + }; + } + + private static boolean isInInitializer(PsiElement place) { + while (true) { + place = PsiTreeUtil.getParentOfType(place, PsiClass.class); + if (place == null) return false; + String name = ((PsiClass)place).getName(); + if (name != null && name.contains("Serializer")) { + return true; + } + } + } +}