diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml
index c46e50242..8901b735b 100644
--- a/resources/META-INF/plugin.xml
+++ b/resources/META-INF/plugin.xml
@@ -229,6 +229,13 @@
enabledByDefault="true" level="WARNING"
implementationClass="com.magento.idea.magento2plugin.inspections.xml.PreferenceDeclarationInspection"/>
+
+
diff --git a/resources/inspectionDescriptions/PluginAttrTypeInspection.html b/resources/inspectionDescriptions/PluginAttrTypeInspection.html
new file mode 100644
index 000000000..a81d6880d
--- /dev/null
+++ b/resources/inspectionDescriptions/PluginAttrTypeInspection.html
@@ -0,0 +1,19 @@
+
+
+
+
+ Validates if attribute `type` in the <plugin/> tag of di.xml files contains valid classes or interfaces
+ and that it cannot be empty.
+
+This inspection inspects:
+
+ - The existence of the class on the specified path
+ - Tag `type` is not empty
+
+
+
diff --git a/resources/magento2/inspection.properties b/resources/magento2/inspection.properties
index 15900c813..b41be33d5 100644
--- a/resources/magento2/inspection.properties
+++ b/resources/magento2/inspection.properties
@@ -8,6 +8,7 @@ inspection.displayName.ModuleDeclarationInModuleXmlInspection=Inspection for the
inspection.displayName.AclResourceXmlInspection=Inspection for the Title XML required attribute in the `etc/acl.xml` file
inspection.displayName.WebApiServiceInspection=Inspection for the Web API XML service declaration
inspection.displayName.InvalidDiTypeInspection=Invalid type configuration in the `etc/di.xml` file
+inspection.displayName.PluginAttrTypeInspection=Inspection for the attribute `type` in the `plugin` tag
inspection.displayName.PreferenceXmlInspections=Inspection for the Preference declaration
inspection.plugin.duplicateInSameFile=The plugin name already used in this file. For more details see Inspection Description.
inspection.plugin.duplicateInOtherPlaces=The plugin name "{0}" for targeted "{1}" class is already used in the module "{2}" ({3} scope). For more details see Inspection Description.
diff --git a/src/com/magento/idea/magento2plugin/inspections/xml/PluginAttributeTypeInspection.java b/src/com/magento/idea/magento2plugin/inspections/xml/PluginAttributeTypeInspection.java
new file mode 100644
index 000000000..54649a79d
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/inspections/xml/PluginAttributeTypeInspection.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.inspections.xml;
+
+import com.intellij.codeInspection.ProblemHighlightType;
+import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.codeInspection.XmlSuppressableInspectionTool;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.XmlElementVisitor;
+import com.intellij.psi.xml.XmlAttribute;
+import com.intellij.psi.xml.XmlTag;
+import com.magento.idea.magento2plugin.bundles.InspectionBundle;
+import com.magento.idea.magento2plugin.inspections.validator.InspectionValidator;
+import com.magento.idea.magento2plugin.inspections.validator.NotEmptyValidator;
+import com.magento.idea.magento2plugin.inspections.validator.PhpClassExistenceValidator;
+import com.magento.idea.magento2plugin.magento.files.ModuleDiXml;
+import org.jetbrains.annotations.NotNull;
+
+public class PluginAttributeTypeInspection extends XmlSuppressableInspectionTool {
+
+ @Override
+ public @NotNull
+ PsiElementVisitor buildVisitor(
+ final @NotNull ProblemsHolder problemsHolder,
+ final boolean isOnTheFly
+ ) {
+ return new XmlElementVisitor() {
+
+ private final InspectionBundle inspectionBundle = new InspectionBundle();
+ private final InspectionValidator phpClassExistenceValidator =
+ new PhpClassExistenceValidator(problemsHolder.getProject());
+ private final InspectionValidator notEmptyValidator = new NotEmptyValidator();
+
+ @Override
+ public void visitXmlTag(final XmlTag xmlTag) {
+ final PsiFile file = xmlTag.getContainingFile();
+
+ if (!file.getName().equals(ModuleDiXml.FILE_NAME)
+ || !xmlTag.getName().equals(ModuleDiXml.PLUGIN_TAG_NAME)) {
+ return;
+ }
+
+ final XmlAttribute pluginTypeAttribute =
+ xmlTag.getAttribute(ModuleDiXml.TYPE_ATTR);
+
+ if (pluginTypeAttribute == null
+ || pluginTypeAttribute.getValue() == null
+ || pluginTypeAttribute.getValueElement() == null
+ || pluginTypeAttribute.getValueElement().getText().isEmpty()) {
+ return;
+ }
+
+ if (!notEmptyValidator.validate(pluginTypeAttribute.getValue())) {
+ reportCouldNotBeEmpty(
+ pluginTypeAttribute.getValueElement(),
+ pluginTypeAttribute.getName()
+ );
+ }
+
+ if (!phpClassExistenceValidator.validate(pluginTypeAttribute.getValue())) {
+ reportClassDoesNotExists(
+ pluginTypeAttribute.getValueElement(),
+ pluginTypeAttribute.getValue()
+ );
+ }
+ }
+
+ /**
+ * Report Attribute Value could not be empty.
+ *
+ * @param psiElement PsiElement
+ * @param messageParams Object...
+ */
+ private void reportCouldNotBeEmpty(
+ final @NotNull PsiElement psiElement,
+ final Object... messageParams
+ ) {
+ problemsHolder.registerProblem(
+ psiElement,
+ inspectionBundle.message(
+ "inspection.error.idAttributeCanNotBeEmpty",
+ messageParams
+ ),
+ ProblemHighlightType.ERROR
+ );
+ }
+
+ /**
+ * Report class does not exists.
+ *
+ * @param psiElement PsiElement
+ * @param messageParams Object...
+ */
+ private void reportClassDoesNotExists(
+ final @NotNull PsiElement psiElement,
+ final Object... messageParams
+ ) {
+ problemsHolder.registerProblem(
+ psiElement,
+ inspectionBundle.message(
+ "inspection.warning.class.does.not.exist",
+ messageParams
+ ),
+ ProblemHighlightType.WARNING
+ );
+ }
+ };
+ }
+}
diff --git a/testData/inspections/xml/PluginAttributeTypeInspection/attrArgTypeValueIsEmpty/di.xml b/testData/inspections/xml/PluginAttributeTypeInspection/attrArgTypeValueIsEmpty/di.xml
new file mode 100644
index 000000000..d59a47dd8
--- /dev/null
+++ b/testData/inspections/xml/PluginAttributeTypeInspection/attrArgTypeValueIsEmpty/di.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/testData/inspections/xml/PluginAttributeTypeInspection/attrTypeClassExists/di.xml b/testData/inspections/xml/PluginAttributeTypeInspection/attrTypeClassExists/di.xml
new file mode 100644
index 000000000..69ae9c322
--- /dev/null
+++ b/testData/inspections/xml/PluginAttributeTypeInspection/attrTypeClassExists/di.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/testData/inspections/xml/PluginAttributeTypeInspection/classAttrTypeDoesNotExists/di.xml b/testData/inspections/xml/PluginAttributeTypeInspection/classAttrTypeDoesNotExists/di.xml
new file mode 100644
index 000000000..1cd190a2d
--- /dev/null
+++ b/testData/inspections/xml/PluginAttributeTypeInspection/classAttrTypeDoesNotExists/di.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/testData/inspections/xml/PluginAttributeTypeInspection/classAttrTypeIsExist/di.xml b/testData/inspections/xml/PluginAttributeTypeInspection/classAttrTypeIsExist/di.xml
new file mode 100644
index 000000000..69ae9c322
--- /dev/null
+++ b/testData/inspections/xml/PluginAttributeTypeInspection/classAttrTypeIsExist/di.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/tests/com/magento/idea/magento2plugin/inspections/xml/PluginAttributeTypeInspectionTest.java b/tests/com/magento/idea/magento2plugin/inspections/xml/PluginAttributeTypeInspectionTest.java
new file mode 100644
index 000000000..712c69233
--- /dev/null
+++ b/tests/com/magento/idea/magento2plugin/inspections/xml/PluginAttributeTypeInspectionTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.inspections.xml;
+
+import com.magento.idea.magento2plugin.magento.files.ModuleDiXml;
+
+public class PluginAttributeTypeInspectionTest extends InspectionXmlFixtureTestCase {
+
+ private static final String ARGUMENT_VALUE_IS_EMPTY =
+ "inspection.error.idAttributeCanNotBeEmpty";
+ private static final String CLASS_DOES_NOT_EXIST =
+ "inspection.warning.class.does.not.exist";
+ private static final String EXISTENT_CLASS =
+ "Magento\\Catalog\\Plugin\\PluginClass";
+ private static final String NOT_EXISTENT_CLASS =
+ "Not\\Existent\\Class";
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ myFixture.enableInspections(PluginAttributeTypeInspection.class);
+ }
+
+ /**
+ * Test for an error for the "type" attribute because it is empty.
+ *
+ */
+ public void testAttrArgTypeValueIsEmpty() {
+ configureFixture();
+
+ final String forAttrIsEmptyMessage = inspectionBundle.message(
+ ARGUMENT_VALUE_IS_EMPTY,
+ ModuleDiXml.TYPE_ATTR
+ );
+
+ assertHasHighlighting(forAttrIsEmptyMessage);
+ }
+
+ /**
+ * Test for no error for the "type" attribute because this class exists.
+ *
+ */
+ public void testAttrTypeClassExists() {
+ configureFixture();
+
+ final String typeAttrIsEmptyMessage = inspectionBundle.message(
+ ARGUMENT_VALUE_IS_EMPTY,
+ ModuleDiXml.TYPE_ATTR
+ );
+
+ assertHasNoHighlighting(typeAttrIsEmptyMessage);
+ }
+
+ /**
+ * Test for throwing an error for a class that does not exist for the "type" attribute.
+ */
+ public void testClassAttrTypeDoesNotExists() {
+ configureFixture();
+
+ final String forClassDoesNotExists = inspectionBundle.message(
+ CLASS_DOES_NOT_EXIST,
+ NOT_EXISTENT_CLASS
+ );
+
+ assertHasHighlighting(forClassDoesNotExists);
+ }
+
+ /**
+ * Test for the absence of an error in the presence of
+ * classes or interfaces specified for plugins.
+ */
+ public void testClassAttrTypeIsExist() {
+ configureFixture();
+
+ final String classOneExists = inspectionBundle.message(
+ CLASS_DOES_NOT_EXIST,
+ EXISTENT_CLASS
+ );
+
+ assertHasNoHighlighting(classOneExists);
+ }
+
+ private void configureFixture() {
+ myFixture.configureByFile(getFixturePath(ModuleDiXml.FILE_NAME));
+ }
+}