diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml
index 8413b924237f..099b9b23dfb4 100644
--- a/plugins/devkit/resources/META-INF/plugin.xml
+++ b/plugins/devkit/resources/META-INF/plugin.xml
@@ -78,6 +78,13 @@
enabledByDefault="true"
level="WARNING"
implementationClass="org.jetbrains.idea.devkit.inspections.InspectionMappingConsistencyInspection"/>
+
diff --git a/plugins/devkit/resources/inspectionDescriptions/ExtensionPointBeanClass.html b/plugins/devkit/resources/inspectionDescriptions/ExtensionPointBeanClass.html
new file mode 100644
index 000000000000..ec105a2ee396
--- /dev/null
+++ b/plugins/devkit/resources/inspectionDescriptions/ExtensionPointBeanClass.html
@@ -0,0 +1,6 @@
+
+
+Ensures that an <extensionPoint> tag has <with> subtags specifying types for all class fields.
+
+
+
\ No newline at end of file
diff --git a/plugins/devkit/src/dom/ExtensionPoint.java b/plugins/devkit/src/dom/ExtensionPoint.java
index c05fbf8b8c27..1c25bd2e5ebd 100644
--- a/plugins/devkit/src/dom/ExtensionPoint.java
+++ b/plugins/devkit/src/dom/ExtensionPoint.java
@@ -56,4 +56,6 @@ public interface ExtensionPoint extends DomElement {
@NotNull
@SubTagList("with")
List getWithElements();
+
+ With addWith();
}
diff --git a/plugins/devkit/src/dom/impl/PluginFieldNameConverter.java b/plugins/devkit/src/dom/impl/PluginFieldNameConverter.java
index 5515db6d1bd4..37ce15267102 100644
--- a/plugins/devkit/src/dom/impl/PluginFieldNameConverter.java
+++ b/plugins/devkit/src/dom/impl/PluginFieldNameConverter.java
@@ -68,21 +68,25 @@ public class PluginFieldNameConverter extends ResolvingConverter {
}
private static PsiField findFieldByAttributeValue(PsiClass psiClass, @NotNull String attrNameToFind) {
- final PsiConstantEvaluationHelper evalHelper = JavaPsiFacade.getInstance(psiClass.getProject()).getConstantEvaluationHelper();
for (PsiField psiField : psiClass.getAllFields()) {
- final PsiMethod getter = PropertyUtils.findGetterForField(psiField);
- final PsiMethod setter = PropertyUtils.findSetterForField(psiField);
- final PsiAnnotation attrAnno = ExtensionDomExtender.findAnnotation(Attribute.class, psiField, getter, setter);
- if (attrAnno != null) {
- final String attrName = ExtensionDomExtender.getStringAttribute(attrAnno, "value", evalHelper);
- if (attrNameToFind.equals(attrName)) {
- return psiField;
- }
+ if (attrNameToFind.equals(getAttributeAnnotationValue(psiField))) {
+ return psiField;
}
}
return null;
}
+ public static String getAttributeAnnotationValue(PsiField psiField) {
+ final PsiConstantEvaluationHelper evalHelper = JavaPsiFacade.getInstance(psiField.getProject()).getConstantEvaluationHelper();
+ final PsiMethod getter = PropertyUtils.findGetterForField(psiField);
+ final PsiMethod setter = PropertyUtils.findSetterForField(psiField);
+ final PsiAnnotation attrAnno = ExtensionDomExtender.findAnnotation(Attribute.class, psiField, getter, setter);
+ if (attrAnno != null) {
+ return ExtensionDomExtender.getStringAttribute(attrAnno, "value", evalHelper);
+ }
+ return null;
+ }
+
@Nullable
@Override
public String toString(@Nullable PsiField field, ConvertContext context) {
diff --git a/plugins/devkit/src/inspections/ExtensionPointBeanClassInspection.java b/plugins/devkit/src/inspections/ExtensionPointBeanClassInspection.java
new file mode 100644
index 000000000000..c232170d6a5a
--- /dev/null
+++ b/plugins/devkit/src/inspections/ExtensionPointBeanClassInspection.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2013 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;
+
+import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.XmlElementVisitor;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.util.xml.DomElement;
+import com.intellij.util.xml.DomUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.idea.devkit.dom.ExtensionPoint;
+import org.jetbrains.idea.devkit.dom.impl.ExtensionDomExtender;
+import org.jetbrains.idea.devkit.inspections.quickfix.AddWithTagFix;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author yole
+ */
+public class ExtensionPointBeanClassInspection extends DevKitInspectionBase {
+ @NotNull
+ @Override
+ public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
+ return new XmlElementVisitor() {
+ @Override
+ public void visitXmlTag(XmlTag tag) {
+ DomElement element = DomUtil.getDomElement(tag);
+ if (element instanceof ExtensionPoint) {
+ ExtensionPoint extensionPoint = (ExtensionPoint)element;
+ if (extensionPoint.getWithElements().isEmpty() && !collectMissingWithTags(extensionPoint).isEmpty()) {
+ holder.registerProblem(tag,
+ " does not have tags to specify the types of class fields",
+ new AddWithTagFix());
+ }
+ }
+ }
+ };
+ }
+
+ public static List collectMissingWithTags(ExtensionPoint element) {
+ final List result = new ArrayList();
+ PsiClass beanClass = element.getBeanClass().getValue();
+ if (beanClass != null) {
+ for (PsiField field : beanClass.getAllFields()) {
+ if (ExtensionDomExtender.isClassField(field.getName()) &&
+ ExtensionDomExtender.findWithElement(element.getWithElements(), field) == null) {
+ result.add(field);
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/devkit/src/inspections/quickfix/AddWithTagFix.java b/plugins/devkit/src/inspections/quickfix/AddWithTagFix.java
new file mode 100644
index 000000000000..138c2a4ce19e
--- /dev/null
+++ b/plugins/devkit/src/inspections/quickfix/AddWithTagFix.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2000-2013 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.quickfix;
+
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiField;
+import com.intellij.util.PsiNavigateUtil;
+import com.intellij.util.xml.DomElement;
+import com.intellij.util.xml.DomUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.idea.devkit.dom.ExtensionPoint;
+import org.jetbrains.idea.devkit.dom.With;
+import org.jetbrains.idea.devkit.dom.impl.PluginFieldNameConverter;
+import org.jetbrains.idea.devkit.inspections.ExtensionPointBeanClassInspection;
+
+import java.util.List;
+
+/**
+ * @author yole
+ */
+public class AddWithTagFix implements LocalQuickFix {
+ @NotNull
+ @Override
+ public String getName() {
+ return "Add tag";
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
+ DomElement element = DomUtil.getDomElement(descriptor.getPsiElement());
+ if (!(element instanceof ExtensionPoint)) {
+ return;
+ }
+ ExtensionPoint extensionPoint = (ExtensionPoint)element;
+ List fields = ExtensionPointBeanClassInspection.collectMissingWithTags(extensionPoint);
+ PsiElement navTarget = null;
+ for (PsiField field : fields) {
+ String attributeName = PluginFieldNameConverter.getAttributeAnnotationValue(field);
+ if (attributeName == null) {
+ attributeName = field.getName();
+ }
+ With with = extensionPoint.addWith();
+ with.getAttribute().setStringValue(attributeName);
+ with.getImplements().setStringValue("");
+ if (navTarget == null) {
+ navTarget = with.getImplements().getXmlAttributeValue();
+ }
+ }
+ if (navTarget != null) {
+ PsiNavigateUtil.navigate(navTarget);
+ }
+ }
+}