Skip to content

654: fixed class cast exception in web api type index #897

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 96 additions & 55 deletions src/com/magento/idea/magento2plugin/stubs/indexes/WebApiTypeIndex.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
/*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

package com.magento.idea.magento2plugin.stubs.indexes;

import com.intellij.ide.highlighter.XmlFileType;
Expand All @@ -13,88 +14,97 @@
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.indexing.*;
import com.intellij.util.indexing.DataIndexer;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.indexing.FileContent;
import com.intellij.util.indexing.ID;
import com.intellij.util.indexing.ScalarIndexExtension;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import com.jetbrains.php.lang.PhpLangUtil;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.magento.idea.magento2plugin.project.Settings;
import com.magento.idea.magento2plugin.linemarker.xml.LineMarkerXmlTagDecorator;
import com.magento.idea.magento2plugin.project.Settings;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.util.*;

/**
* Indexer for classes/interfaces which have methods exposed via Web API.
*/
public class WebApiTypeIndex extends ScalarIndexExtension<String> {

public static final ID<String, Void> KEY = ID.create("com.magento.idea.magento2plugin.stubs.indexes.webapi_type");

public static final ID<String, Void> KEY = ID.create(
"com.magento.idea.magento2plugin.stubs.indexes.webapi_type"
);
private final KeyDescriptor<String> keyDescriptor = new EnumeratorStringDescriptor();

@NotNull
@Override
public ID<String, Void> getName() {
public @NotNull ID<String, Void> getName() {
return KEY;
}

@NotNull
@SuppressWarnings("PMD.CognitiveComplexity")
@Override
public DataIndexer<String, Void, FileContent> getIndexer() {
public @NotNull DataIndexer<String, Void, FileContent> getIndexer() {
return inputData -> {
Map<String, Void> map = new HashMap<>();
final Map<String, Void> map = new HashMap<>();
final PsiFile psiFile = inputData.getPsiFile();

PsiFile psiFile = inputData.getPsiFile();
if (!Settings.isEnabled(psiFile.getProject())) {
return map;
}

if (!(psiFile instanceof XmlFile)) {
return map;
}
final XmlDocument document = ((XmlFile) psiFile).getDocument();

XmlDocument document = ((XmlFile) psiFile).getDocument();
if (document == null) {
return map;
}
final XmlTag[] xmlTags = PsiTreeUtil.getChildrenOfType(
psiFile.getFirstChild(),
XmlTag.class
);

XmlTag xmlTags[] = PsiTreeUtil.getChildrenOfType(psiFile.getFirstChild(), XmlTag.class);
if (xmlTags == null) {
return map;
}

for (XmlTag xmlTag : xmlTags) {
if (xmlTag.getName().equals("routes")) {
for (XmlTag routeNode : xmlTag.findSubTags("route")) {
for (XmlTag serviceNode : routeNode.findSubTags("service")) {
String typeName = serviceNode.getAttributeValue("class");
for (final XmlTag xmlTag : xmlTags) {
if ("routes".equals(xmlTag.getName())) {
for (final XmlTag routeNode : xmlTag.findSubTags("route")) {
for (final XmlTag serviceNode : routeNode.findSubTags("service")) {
final String typeName = serviceNode.getAttributeValue("class");

if (typeName != null) {
map.put(PhpLangUtil.toPresentableFQN(typeName), null);
}
}
}
}
}

return map;
};
}

@NotNull
@Override
public KeyDescriptor<String> getKeyDescriptor() {
public @NotNull KeyDescriptor<String> getKeyDescriptor() {
return keyDescriptor;
}

@NotNull
@Override
public FileBasedIndex.InputFilter getInputFilter() {
return file -> (
file.getFileType() == XmlFileType.INSTANCE && file.getNameWithoutExtension().equals("webapi")
&& !file.getPath().contains("testsuite") && !file.getPath().contains("_files")
);
public @NotNull FileBasedIndex.InputFilter getInputFilter() {
return file -> file.getFileType() == XmlFileType.INSTANCE
&& "webapi".equals(file.getNameWithoutExtension())
&& !file.getPath().contains("testsuite") && !file.getPath().contains("_files");
}

@Override
Expand All @@ -109,45 +119,77 @@ public int getVersion() {

/**
* Get list of Web API routes associated with the provided method.
*
* Parent classes are not taken into account.
*
* @param method Method
*
* @return List[XmlTag]
*/
public static List<XmlTag> getWebApiRoutes(Method method) {
List<XmlTag> tags = new ArrayList<>();
public static List<XmlTag> getWebApiRoutes(final Method method) {
final List<XmlTag> tags = new ArrayList<>();

if (!method.getAccess().isPublic()) {
return tags;
}
PhpClass phpClass = method.getContainingClass();
String methodFqn = method.getName();
final PhpClass phpClass = method.getContainingClass();

if (phpClass == null) {
return tags;
}
String classFqn = phpClass.getPresentableFQN();
Collection<VirtualFile> containingFiles = FileBasedIndex
.getInstance().getContainingFiles(KEY, classFqn, GlobalSearchScope.allScope(phpClass.getProject()));
final String classFqn = phpClass.getPresentableFQN();
final Collection<VirtualFile> containingFiles = FileBasedIndex
.getInstance()
.getContainingFiles(
KEY,
classFqn,
GlobalSearchScope.allScope(phpClass.getProject())
);

final PsiManager psiManager = PsiManager.getInstance(phpClass.getProject());
final String methodFqn = method.getName();

for (final VirtualFile virtualFile : containingFiles) {
if (virtualFile.getFileType() != XmlFileType.INSTANCE) {
continue;
}
final XmlFile file = (XmlFile) psiManager.findFile(virtualFile);

PsiManager psiManager = PsiManager.getInstance(phpClass.getProject());
for (VirtualFile virtualFile : containingFiles) {
XmlFile file = (XmlFile) psiManager.findFile(virtualFile);
if (file == null) {
continue;
}
XmlTag rootTag = file.getRootTag();
final XmlTag rootTag = file.getRootTag();

if (rootTag == null) {
continue;
}
fillRelatedTags(classFqn, methodFqn, rootTag, tags);
}

return tags;
}

/**
* Find routes related to the specified method within single webapi.xml
* Find routes related to the specified method within single webapi.xml.
*
* @param classFqn String
* @param methodFqn String
* @param parentTag XmlTag
* @param tagsReferences List[XmlTag]
*/
private static void fillRelatedTags(String classFqn, String methodFqn, XmlTag parentTag, List<XmlTag> tagsReferences) {
for (XmlTag routeNode : parentTag.findSubTags("route")) {
for (XmlTag serviceNode : routeNode.findSubTags("service")) {
String typeName = serviceNode.getAttributeValue("class");
String methodName = serviceNode.getAttributeValue("method");
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
private static void fillRelatedTags(
final String classFqn,
final String methodFqn,
final XmlTag parentTag,
final List<XmlTag> tagsReferences
) {
for (final XmlTag routeNode : parentTag.findSubTags("route")) {
for (final XmlTag serviceNode : routeNode.findSubTags("service")) {
final String typeName = serviceNode.getAttributeValue("class");
final String methodName = serviceNode.getAttributeValue("method");

if (typeName != null && typeName.equals(classFqn)
&& methodName != null && methodName.equals(methodFqn)
&& methodName != null && methodName.equals(methodFqn)
) {
tagsReferences.add(new WebApiLineMarkerXmlTagDecorator(routeNode));
}
Expand All @@ -160,25 +202,24 @@ private static void fillRelatedTags(String classFqn, String methodFqn, XmlTag pa
*/
private static class WebApiLineMarkerXmlTagDecorator extends LineMarkerXmlTagDecorator {

WebApiLineMarkerXmlTagDecorator(XmlTag xmlTag) {
public WebApiLineMarkerXmlTagDecorator(final XmlTag xmlTag) {
super(xmlTag);
}

@NotNull
@Override
public String getDescription() {
public @NotNull String getDescription() {
return "";
}

@Override
@NotNull
@NonNls
public String getName() {
String httpMethod = this.xmlTag.getAttributeValue("method");
String route = this.xmlTag.getAttributeValue("url");
public @NonNls @NotNull String getName() {
final String httpMethod = this.xmlTag.getAttributeValue("method");
final String route = this.xmlTag.getAttributeValue("url");

if (httpMethod != null && route != null) {
return String.format(" %-7s %s", httpMethod, route);
}

return xmlTag.getName();
}
}
Expand Down