Skip to content

Commit

Permalink
Merge pull request #588 from Iamwade/develop-plugin-declaration-inspe…
Browse files Browse the repository at this point in the history
…ctions

Develop plugin declaration inspections
  • Loading branch information
Vitaliy authored May 17, 2021
2 parents 33defc4 + b6383d9 commit d4c03c7
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 0 deletions.
7 changes: 7 additions & 0 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,13 @@
enabledByDefault="true" level="WARNING"
implementationClass="com.magento.idea.magento2plugin.inspections.xml.PreferenceDeclarationInspection"/>

<localInspection language="XML" groupPath="XML"
shortName="PluginAttrTypeInspection"
bundle="magento2.inspection" key="inspection.displayName.PluginAttrTypeInspection"
groupBundle="magento2.inspection" groupKey="inspection.group.name"
enabledByDefault="true" level="WARNING"
implementationClass="com.magento.idea.magento2plugin.inspections.xml.PluginAttributeTypeInspection"/>

<internalFileTemplate name="Magento Composer JSON"/>
<internalFileTemplate name="Magento Registration PHP"/>
<internalFileTemplate name="Magento Module XML"/>
Expand Down
19 changes: 19 additions & 0 deletions resources/inspectionDescriptions/PluginAttrTypeInspection.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!--
/*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<html>
<body>
<p>
Validates if attribute `type` in the &lt;plugin/&gt; tag of di.xml files contains valid classes or interfaces
and that it cannot be empty.
</p>
<p>This inspection inspects:
<ul>
<li>The existence of the class on the specified path</li>
<li>Tag `type` is not empty</li>
</ul>
</body>
</html>
1 change: 1 addition & 0 deletions resources/magento2/inspection.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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
);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<config>
<type name="Magento\CatalogSearch\Helper\Data">
<plugin name="unique_plugin_name" type=""/>
</type>
</config>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<config>
<type name="Magento\CatalogSearch\Helper\Data">
<plugin name="unique_plugin_name" type="Magento\Catalog\Plugin\PluginClass"/>
</type>
</config>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<config>
<type name="Magento\CatalogSearch\Helper\Data">
<plugin name="unique_plugin_name" type="Not\Existent\Class"/>
</type>
</config>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<config>
<type name="Magento\CatalogSearch\Helper\Data">
<plugin name="unique_plugin_name" type="Magento\Catalog\Plugin\PluginClass"/>
</type>
</config>
Original file line number Diff line number Diff line change
@@ -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.
* <plugin name="unique_plugin_name" type=""/>
*/
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.
* <plugin name="unique_plugin_name" type="Magento\Catalog\Plugin\PluginClass" />
*/
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));
}
}

0 comments on commit d4c03c7

Please sign in to comment.