Skip to content

Commit 20d8e73

Browse files
author
Vitaliy
authored
Merge branch '1.0.0-develop' into description-for-graphql-resolver-templates
2 parents 19cf5f7 + dc0d014 commit 20d8e73

File tree

8 files changed

+359
-3
lines changed

8 files changed

+359
-3
lines changed

resources/META-INF/plugin.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@
131131
level="WARNING"
132132
implementationClass="com.magento.idea.magento2plugin.inspections.xml.ObserverDeclarationInspection"/>
133133

134+
<localInspection language="XML" groupPath="XML"
135+
shortName="PluginDeclarationInspection"
136+
displayName="Duplicated Plugin Usage in di XML"
137+
groupName="Magento 2"
138+
enabledByDefault="true"
139+
level="WARNING"
140+
implementationClass="com.magento.idea.magento2plugin.inspections.xml.PluginDeclarationInspection"/>
141+
134142
<localInspection language="XML" groupPath="XML"
135143
shortName="CacheableFalseInDefaultLayoutInspection"
136144
displayName="Inspection for disabled cache site-wide"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
inspection.plugin.duplicateInSameFile=The plugin name already used in this file. For more details see Inspection Description.
2+
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.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.bundles;
7+
8+
public class InspectionBundle extends AbstractBundle {
9+
protected final String BUNDLE_NAME = "magento2.inspection";
10+
11+
public String getBundleName() {
12+
return BUNDLE_NAME;
13+
}
14+
}

src/com/magento/idea/magento2plugin/indexes/IndexManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.intellij.util.indexing.FileBasedIndexImpl;
88
import com.intellij.util.indexing.ID;
99
import com.magento.idea.magento2plugin.stubs.indexes.*;
10+
import com.magento.idea.magento2plugin.stubs.indexes.PluginIndex;
1011
import com.magento.idea.magento2plugin.stubs.indexes.js.MagentoLibJsIndex;
1112
import com.magento.idea.magento2plugin.stubs.indexes.js.RequireJsIndex;
1213
import com.magento.idea.magento2plugin.stubs.indexes.graphql.GraphQlResolverIndex;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
package com.magento.idea.magento2plugin.indexes;
6+
7+
import com.intellij.openapi.project.Project;
8+
import com.intellij.openapi.vfs.VirtualFile;
9+
import com.intellij.psi.PsiElement;
10+
import com.intellij.psi.PsiManager;
11+
import com.intellij.psi.search.GlobalSearchScope;
12+
import com.intellij.psi.xml.XmlAttributeValue;
13+
import com.intellij.psi.xml.XmlFile;
14+
import com.intellij.util.indexing.FileBasedIndex;
15+
import com.magento.idea.magento2plugin.magento.files.ModuleDiXml;
16+
import com.magento.idea.magento2plugin.xml.XmlPsiTreeUtil;
17+
18+
import java.util.ArrayList;
19+
import java.util.Collection;
20+
21+
public class PluginIndex {
22+
23+
private static PluginIndex INSTANCE;
24+
25+
private Project project;
26+
27+
private PluginIndex() {
28+
}
29+
30+
public static PluginIndex getInstance(final Project project) {
31+
if (null == INSTANCE) {
32+
INSTANCE = new PluginIndex();
33+
}
34+
INSTANCE.project = project;
35+
36+
return INSTANCE;
37+
}
38+
39+
public Collection<PsiElement> getPluginElements(final String name, final GlobalSearchScope scope) {
40+
Collection<PsiElement> result = new ArrayList<>();
41+
42+
Collection<VirtualFile> virtualFiles =
43+
FileBasedIndex.getInstance().getContainingFiles(
44+
com.magento.idea.magento2plugin.stubs.indexes.PluginIndex.KEY,
45+
name,
46+
scope
47+
);
48+
49+
for (VirtualFile virtualFile : virtualFiles) {
50+
XmlFile xmlFile = (XmlFile) PsiManager.getInstance(project).findFile(virtualFile);
51+
Collection<XmlAttributeValue> valueElements = XmlPsiTreeUtil
52+
.findAttributeValueElements(xmlFile, ModuleDiXml.PLUGIN_TYPE_ATTRIBUTE, ModuleDiXml.PLUGIN_TYPE_ATTR_NAME, name);
53+
result.addAll(valueElements);
54+
}
55+
return result;
56+
}
57+
}
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
/*
2+
* Copyright © Magento, Inc. All rights reserved.
3+
* See COPYING.txt for license details.
4+
*/
5+
6+
package com.magento.idea.magento2plugin.inspections.xml;
7+
8+
import com.intellij.codeInspection.ProblemHighlightType;
9+
import com.intellij.codeInspection.ProblemsHolder;
10+
import com.intellij.ide.highlighter.XmlFileType;
11+
import com.intellij.openapi.vfs.VfsUtil;
12+
import com.intellij.openapi.vfs.VirtualFile;
13+
import com.intellij.psi.*;
14+
import com.intellij.psi.search.GlobalSearchScope;
15+
import com.intellij.psi.util.PsiTreeUtil;
16+
import com.intellij.psi.xml.XmlAttribute;
17+
import com.intellij.psi.xml.XmlAttributeValue;
18+
import com.intellij.psi.xml.XmlDocument;
19+
import com.intellij.psi.xml.XmlTag;
20+
import com.jetbrains.php.lang.inspections.PhpInspection;
21+
import com.magento.idea.magento2plugin.bundles.InspectionBundle;
22+
import com.magento.idea.magento2plugin.indexes.PluginIndex;
23+
import com.magento.idea.magento2plugin.magento.files.ModuleDiXml;
24+
import com.magento.idea.magento2plugin.magento.files.ModuleXml;
25+
import com.magento.idea.magento2plugin.magento.packages.Package;
26+
import org.jetbrains.annotations.NotNull;
27+
import org.jetbrains.annotations.Nullable;
28+
import java.io.File;
29+
import java.net.MalformedURLException;
30+
import java.net.URL;
31+
import java.util.*;
32+
33+
public class PluginDeclarationInspection extends PhpInspection {
34+
35+
@NotNull
36+
@Override
37+
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder problemsHolder, boolean b) {
38+
return new XmlElementVisitor() {
39+
private final String moduleXmlFileName = ModuleXml.getInstance().getFileName();
40+
private InspectionBundle inspectionBundle = new InspectionBundle();
41+
private HashMap<String, VirtualFile> loadedFileHash = new HashMap<>();
42+
private final ProblemHighlightType errorSeverity = ProblemHighlightType.WARNING;
43+
44+
@Override
45+
public void visitFile(PsiFile file) {
46+
if (!file.getName().equals(ModuleDiXml.FILE_NAME)) {
47+
return;
48+
}
49+
50+
XmlTag[] xmlTags = getFileXmlTags(file);
51+
PluginIndex pluginIndex = PluginIndex.getInstance(file.getProject());
52+
53+
if (xmlTags == null) {
54+
return;
55+
}
56+
57+
HashMap<String, XmlTag> targetPluginHash = new HashMap<>();
58+
59+
for (XmlTag pluginXmlTag: xmlTags) {
60+
HashMap<String, XmlTag> pluginProblems = new HashMap<>();
61+
if (!pluginXmlTag.getName().equals(ModuleDiXml.PLUGIN_TYPE_TAG)) {
62+
continue;
63+
}
64+
65+
XmlAttribute pluginNameAttribute = pluginXmlTag.getAttribute(ModuleDiXml.PLUGIN_TYPE_ATTR_NAME);
66+
67+
String pluginNameAttributeValue = pluginNameAttribute.getValue();
68+
if (pluginNameAttributeValue == null) {
69+
continue;
70+
}
71+
72+
List<XmlTag> targetPlugin = fetchPluginTagsFromPluginTag(pluginXmlTag);
73+
74+
for (XmlTag pluginTypeXmlTag: targetPlugin) {
75+
XmlAttribute pluginTypeNameAttribute = pluginTypeXmlTag.getAttribute(ModuleDiXml.PLUGIN_TYPE_ATTR_NAME);
76+
XmlAttribute pluginTypeDisabledAttribute = pluginTypeXmlTag.getAttribute(ModuleDiXml.DISABLED_ATTR_NAME);
77+
78+
if (pluginTypeNameAttribute == null ||
79+
(
80+
pluginTypeDisabledAttribute != null &&
81+
pluginTypeDisabledAttribute.getValue() != null &&
82+
pluginTypeDisabledAttribute.getValue().equals("true")
83+
)
84+
) {
85+
continue;
86+
}
87+
88+
String pluginTypeName = pluginTypeNameAttribute.getValue();
89+
String pluginTypeKey = pluginNameAttributeValue.concat("_").concat(pluginTypeName);
90+
if (targetPluginHash.containsKey(pluginTypeKey)) {
91+
problemsHolder.registerProblem(
92+
pluginTypeNameAttribute.getValueElement(),
93+
inspectionBundle.message("inspection.plugin.duplicateInSameFile"),
94+
errorSeverity
95+
);
96+
}
97+
targetPluginHash.put(pluginTypeKey, pluginTypeXmlTag);
98+
99+
List<HashMap<String, String>> modulesWithSamePluginName = fetchModuleNamesWhereSamePluginNameUsed(pluginNameAttributeValue, pluginTypeName, pluginIndex, file);
100+
for (HashMap<String, String> moduleEntry: modulesWithSamePluginName) {
101+
Map.Entry<String, String> module = moduleEntry.entrySet().iterator().next();
102+
String moduleName = module.getKey();
103+
String scope = module.getValue();
104+
String problemKey = pluginTypeKey.concat("_").concat(moduleName).concat("_").concat(scope);
105+
if (!pluginProblems.containsKey(problemKey)){
106+
problemsHolder.registerProblem(
107+
pluginTypeNameAttribute.getValueElement(),
108+
inspectionBundle.message(
109+
"inspection.plugin.duplicateInOtherPlaces",
110+
pluginTypeName,
111+
pluginNameAttributeValue,
112+
moduleName,
113+
scope
114+
),
115+
errorSeverity
116+
);
117+
pluginProblems.put(problemKey, pluginTypeXmlTag);
118+
}
119+
}
120+
}
121+
}
122+
}
123+
124+
private List<HashMap<String, String>> fetchModuleNamesWhereSamePluginNameUsed(String pluginNameAttributeValue, String pluginTypeName, PluginIndex pluginIndex, PsiFile file) {
125+
List<HashMap<String, String>> modulesName = new ArrayList<>();
126+
String currentFileDirectory = file.getContainingDirectory().toString();
127+
String currentFileFullPath = currentFileDirectory.concat(File.separator).concat(file.getName());
128+
129+
Collection<PsiElement> indexedPlugins = pluginIndex.getPluginElements(pluginNameAttributeValue, GlobalSearchScope.getScopeRestrictedByFileTypes(
130+
GlobalSearchScope.allScope(file.getProject()),
131+
XmlFileType.INSTANCE
132+
));
133+
134+
for (PsiElement indexedPlugin: indexedPlugins) {
135+
PsiFile indexedAttributeParent = PsiTreeUtil.getTopmostParentOfType(indexedPlugin, PsiFile.class);
136+
if (indexedAttributeParent == null) {
137+
continue;
138+
}
139+
140+
String indexedPluginAttributeValue = ((XmlAttributeValue) indexedPlugin).getValue();
141+
if (!indexedPluginAttributeValue.equals(pluginNameAttributeValue)) {
142+
continue;
143+
}
144+
145+
String indexedFileDirectory = indexedAttributeParent.getContainingDirectory().toString();
146+
String indexedFileFullPath = indexedFileDirectory.concat(File.separator).concat(indexedAttributeParent.getName());
147+
if (indexedFileFullPath.equals(currentFileFullPath)) {
148+
continue;
149+
}
150+
151+
String scope = getAreaFromFileDirectory(indexedAttributeParent);
152+
153+
List<XmlTag> indexPluginTags = fetchPluginTagsFromPluginTag((XmlTag) indexedPlugin.getParent().getParent());
154+
for (XmlTag indexPluginTag: indexPluginTags) {
155+
XmlAttribute indexedPluginNameAttribute = indexPluginTag.getAttribute(ModuleDiXml.PLUGIN_TYPE_ATTR_NAME);
156+
if (indexedPluginNameAttribute == null) {
157+
continue;
158+
}
159+
if (!pluginTypeName.equals(indexedPluginNameAttribute.getValue())){
160+
continue;
161+
}
162+
addModuleNameWhereSamePluginUsed(modulesName, indexedAttributeParent, scope);
163+
}
164+
}
165+
166+
return modulesName;
167+
}
168+
169+
private List<XmlTag> fetchPluginTagsFromPluginTag(XmlTag pluginXmlTag) {
170+
List<XmlTag> result = new ArrayList<>();
171+
XmlTag[] pluginTypeXmlTags = PsiTreeUtil.getChildrenOfType(pluginXmlTag, XmlTag.class);
172+
if (pluginTypeXmlTags == null) {
173+
return result;
174+
}
175+
176+
for (XmlTag pluginTypeXmlTag: pluginTypeXmlTags) {
177+
if (!pluginTypeXmlTag.getName().equals(ModuleDiXml.PLUGIN_TAG_NAME)) {
178+
continue;
179+
}
180+
181+
result.add(pluginTypeXmlTag);
182+
}
183+
184+
return result;
185+
}
186+
187+
private void addModuleNameWhereSamePluginUsed(List<HashMap<String, String>> modulesName, PsiFile indexedFile, String scope) {
188+
XmlTag moduleDeclarationTag = getModuleDeclarationTagByConfigFile(indexedFile);
189+
if (moduleDeclarationTag == null) return;
190+
191+
if (!moduleDeclarationTag.getName().equals("module")) {
192+
return;
193+
}
194+
XmlAttribute moduleNameAttribute = moduleDeclarationTag.getAttribute(ModuleXml.MODULE_ATTR_NAME);
195+
if (moduleNameAttribute == null) {
196+
return;
197+
}
198+
199+
HashMap<String, String> moduleEntry = new HashMap<>();
200+
201+
moduleEntry.put(moduleNameAttribute.getValue(), scope);
202+
modulesName.add(moduleEntry);
203+
}
204+
205+
@Nullable
206+
private XmlTag getModuleDeclarationTagByConfigFile(PsiFile file) {
207+
String fileDirectory = file.getContainingDirectory().toString();
208+
String fileArea = file.getContainingDirectory().getName();
209+
String moduleXmlFilePath = getModuleXmlFilePathByConfigFileDirectory(fileDirectory, fileArea);
210+
211+
VirtualFile virtualFile = getFileByPath(moduleXmlFilePath);
212+
if (virtualFile == null) return null;
213+
214+
PsiFile moduleDeclarationFile = PsiManager.getInstance(file.getProject()).findFile(virtualFile);
215+
XmlTag[] moduleDeclarationTags = getFileXmlTags(moduleDeclarationFile);
216+
if (moduleDeclarationTags == null) {
217+
return null;
218+
}
219+
return moduleDeclarationTags[0];
220+
}
221+
222+
@Nullable
223+
private VirtualFile getFileByPath(String moduleXmlFilePath) {
224+
if (loadedFileHash.containsKey(moduleXmlFilePath)) {
225+
return loadedFileHash.get(moduleXmlFilePath);
226+
}
227+
VirtualFile virtualFile;
228+
try {
229+
virtualFile = VfsUtil.findFileByURL(new URL(moduleXmlFilePath));
230+
} catch (MalformedURLException e) {
231+
return null;
232+
}
233+
if (virtualFile == null) {
234+
return null;
235+
}
236+
loadedFileHash.put(moduleXmlFilePath, virtualFile);
237+
return virtualFile;
238+
}
239+
240+
private String getModuleXmlFilePathByConfigFileDirectory(String fileDirectory, String fileArea) {
241+
String moduleXmlFile = fileDirectory.replace(fileArea, "").concat(moduleXmlFileName);
242+
if (fileDirectory.endsWith(Package.MODULE_BASE_AREA_DIR)) {
243+
moduleXmlFile = fileDirectory.concat(File.separator).concat(moduleXmlFileName);
244+
}
245+
return moduleXmlFile.replace("PsiDirectory:", "file:");
246+
}
247+
248+
@Nullable
249+
private XmlTag[] getFileXmlTags(PsiFile file) {
250+
XmlDocument xmlDocument = PsiTreeUtil.getChildOfType(file, XmlDocument.class);
251+
XmlTag xmlRootTag = PsiTreeUtil.getChildOfType(xmlDocument, XmlTag.class);
252+
return PsiTreeUtil.getChildrenOfType(xmlRootTag, XmlTag.class);
253+
}
254+
255+
private String getAreaFromFileDirectory(@NotNull PsiFile file) {
256+
if (file.getParent() == null) {
257+
return "";
258+
}
259+
260+
String areaFromFileDirectory = file.getParent().getName();
261+
262+
if (areaFromFileDirectory.equals(Package.MODULE_BASE_AREA_DIR)) {
263+
return Package.Areas.base.toString();
264+
}
265+
266+
for (Package.Areas area: Package.Areas.values()) {
267+
if (area.toString().equals(areaFromFileDirectory)) {
268+
return area.toString();
269+
}
270+
}
271+
272+
return "";
273+
}
274+
};
275+
}
276+
}

src/com/magento/idea/magento2plugin/magento/files/ModuleDiXml.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class ModuleDiXml implements ModuleFileInterface {
2222
public static String PLUGIN_TYPE_ATTR_NAME = "name";
2323
public static String PREFERENCE_TAG_NAME = "preference";
2424
public static String PREFERENCE_ATTR_FOR = "for";
25+
public static String DISABLED_ATTR_NAME = "disabled";
2526

2627
private static ModuleDiXml INSTANCE = null;
2728

src/com/magento/idea/magento2plugin/stubs/indexes/PluginIndex.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@
2424
import java.util.Map;
2525
import java.util.Set;
2626

27-
/**
28-
* Created by dkvashnin on 11/10/15.
29-
*/
3027
public class PluginIndex extends FileBasedIndexExtension<String, Set<String>> {
3128
public static final ID<String, Set<String>> KEY
3229
= ID.create("com.magento.idea.magento2plugin.stubs.indexes.plugin_to_type");

0 commit comments

Comments
 (0)