Skip to content
Merged
Show file tree
Hide file tree
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0).

- Require restart on plugin update due to using native libraries

### Fixed

- Class completion doesn't display interfaces

## 3.1.2

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

package com.magento.idea.magento2plugin.completion.provider;

import com.intellij.codeInsight.completion.CompletionParameters;
Expand All @@ -18,87 +19,106 @@
import com.jetbrains.php.lang.psi.elements.PhpNamespace;
import com.magento.idea.magento2plugin.util.RegExUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;

public class PhpClassCompletionProvider extends CompletionProvider<CompletionParameters> {

final private static String PHP_CLASS_COMPLETION_REGEX
private static final String PHP_CLASS_COMPLETION_REGEX
= "\\\\?" + RegExUtil.PhpRegex.FQN + "\\\\?";

@SuppressWarnings({
"PMD.CyclomaticComplexity",
"PMD.NPathComplexity"
})
@Override
protected void addCompletions(@NotNull CompletionParameters parameters,
ProcessingContext context,
@NotNull CompletionResultSet result) {
PsiElement position = parameters.getPosition().getOriginalElement();
protected void addCompletions(
final @NotNull CompletionParameters parameters,
final ProcessingContext context,
final @NotNull CompletionResultSet result
) {
final PsiElement position = parameters.getPosition().getOriginalElement();
if (position == null) {
return;
}
String prefix = result.getPrefixMatcher().getPrefix();
Matcher matcher = Pattern.compile(PHP_CLASS_COMPLETION_REGEX).matcher(prefix);
final String prefix = result.getPrefixMatcher().getPrefix();
final Matcher matcher = Pattern.compile(PHP_CLASS_COMPLETION_REGEX)
.matcher(prefix);
if (!matcher.matches()) {
return;
}

String className = prefix.lastIndexOf(92) < 0 ? prefix : prefix.substring(prefix.lastIndexOf(92) + 1);
String namespace = prefix.lastIndexOf(92) < 0 ? "" : prefix.substring(0, prefix.lastIndexOf(92));
final String className = prefix.lastIndexOf(92) < 0 ? prefix : prefix
.substring(prefix.lastIndexOf(92) + 1);
final String namespace = prefix.lastIndexOf(92) < 0 ? "" : prefix
.substring(0, prefix.lastIndexOf(92));

PhpIndex phpIndex = PhpIndex.getInstance(parameters.getPosition().getProject());
final PhpIndex phpIndex = PhpIndex.getInstance(
parameters.getPosition().getProject()
);

final Collection<PhpClass> phpClasses = new THashSet<>();
Collection<String> namespaceNames = new ArrayList<>();

if (!className.isEmpty()) {
// case for input: "SomeClassOrNamespace"

// add classes
Collection<String> classNames = phpIndex.getAllClassNames(new CamelHumpMatcher(className));
for (String cName: classNames) {
phpClasses.addAll(phpIndex.getClassesByName(cName));
if (className.isEmpty()) {
// add namespaces
final Collection<PhpNamespace> namespaces
= phpIndex.getNamespacesByName(("\\" + namespace)
.toLowerCase(Locale.ROOT));
for (final PhpNamespace nsp: namespaces) {
phpClasses.addAll(PsiTreeUtil.getChildrenOfTypeAsList(
nsp.getStatements(),
PhpClass.class
)
);
}

// add namespaces and classes (string representation)
namespaceNames
= phpIndex.getChildNamespacesByParentName("\\".concat(namespace)
.concat("\\").toLowerCase(Locale.ROOT));
namespaceNames
= namespaceNames.stream().map(n -> namespace.concat("\\")
.concat(n)).collect(Collectors.toList());
} else {
// add interfaces
Collection<String> interfaceNames = phpIndex.getAllInterfaceNames();
interfaceNames.removeIf(i -> !i.contains(className));
for (String iName: interfaceNames) {
final Collection<String> interfaceNames = phpIndex.getAllInterfaceNames();
interfaceNames.removeIf(i -> !i.contains(className.toLowerCase(Locale.ROOT)));
Copy link
Contributor Author

@VitaliyBoyko VitaliyBoyko Mar 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line makes the difference, others are static fixes

for (final String iName: interfaceNames) {
phpClasses.addAll(phpIndex.getInterfacesByName(iName));
}
if (!namespace.isEmpty()) {
phpClasses.removeIf(c -> !c.getPresentableFQN().startsWith(namespace));
} else {
// add classes
final Collection<String> classNames = phpIndex.getAllClassNames(
new CamelHumpMatcher(className)
);
for (final String cName: classNames) {
phpClasses.addAll(phpIndex.getClassesByName(cName));
}
if (namespace.isEmpty()) {
namespaceNames = phpIndex.getChildNamespacesByParentName("\\");
namespaceNames.removeIf(n -> !n.contains(prefix));
} else {
phpClasses.removeIf(c -> !c.getPresentableFQN().startsWith(namespace));
}
} else {
// case for input: "Some\Namespace\ + ^+<Space>"

// add namespaces
Collection<PhpNamespace> namespaces = phpIndex.getNamespacesByName(("\\" + namespace).toLowerCase());
for (PhpNamespace nsp: namespaces) {
phpClasses.addAll(PsiTreeUtil.getChildrenOfTypeAsList(nsp.getStatements(), PhpClass.class));
}

// add namespaces and classes (string representation)
namespaceNames
= phpIndex.getChildNamespacesByParentName("\\".concat(namespace).concat("\\").toLowerCase());
namespaceNames
= namespaceNames.stream().map(n -> namespace.concat("\\").concat(n)).collect(Collectors.toList());
}

// add all above founded items to lookup builder
// order is important (items with the same name override each other), add classes first
for (PhpClass phpClass : phpClasses) {
// order is important (items with the same name override each other),
// add classes first
for (final PhpClass phpClass : phpClasses) {
result.addElement(
LookupElementBuilder
.create(phpClass.getPresentableFQN())
.withIcon(phpClass.getIcon())
);
}

for (String nsName : namespaceNames) {
for (final String nsName : namespaceNames) {
result.addElement(
LookupElementBuilder
.create(nsName)
Expand Down