From a7ae6762877d6c11451578eb3613308d75a2721d Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Thu, 24 Jun 2021 00:30:53 +0300 Subject: [PATCH 1/3] Fixed plugin generation for complex non primitive types --- .../PhpClassReferenceExtractor.java | 73 ------ .../PhpClassReferenceResolver.java | 164 ------------ .../PluginGenerateMethodHandlerBase.java | 2 +- .../generator/PluginClassGenerator.java | 10 +- .../PhpClassReferenceExtractor.java | 159 ++++++++++++ .../references/PhpClassReferenceResolver.java | 240 ++++++++++++++++++ .../PhpClassReferenceStorage.java | 35 ++- .../util/FillTextBufferWithPluginMethods.java | 2 +- 8 files changed, 435 insertions(+), 250 deletions(-) delete mode 100644 src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceExtractor.java delete mode 100644 src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceResolver.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceExtractor.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceResolver.java rename src/com/magento/idea/magento2plugin/actions/generation/{ImportReferences => references}/PhpClassReferenceStorage.java (50%) diff --git a/src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceExtractor.java b/src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceExtractor.java deleted file mode 100644 index a8d31faa8..000000000 --- a/src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceExtractor.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -package com.magento.idea.magento2plugin.actions.generation.ImportReferences; - -import com.intellij.psi.PsiElement; -import com.jetbrains.php.lang.psi.elements.*; -import com.jetbrains.php.lang.psi.resolve.types.PhpType; -import com.jetbrains.php.lang.psi.visitors.PhpElementVisitor; -import java.util.Collection; -import org.jetbrains.annotations.NotNull; - -public abstract class PhpClassReferenceExtractor { - private final PhpElementVisitor myCollectorVisitor = new PhpElementVisitor() { - public void visitPhpClass(PhpClass phpClass) { - PhpClassReferenceExtractor.this.processClassReference(phpClass); - } - - public void visitPhpParameter(Parameter parameter) { - PhpClassReferenceExtractor.this.processParameterReference(parameter); - } - - public void visitPhpReturnType(PhpReturnType returnType) { - PhpClassReferenceExtractor.this.processReturnTypeReference(returnType); - } - }; - - public PhpClassReferenceExtractor() { - } - - private void processClassReference(@NotNull PhpClass resolvedClass) { - String name = resolvedClass.getName(); - this.processReference(name, resolvedClass.getFQN(), resolvedClass); - } - - private void processParameterReference(@NotNull Parameter parameter) { - PhpType parameterType = parameter.getDeclaredType(); - if (parameterType.isEmpty() && !PhpType.isPrimitiveType(parameterType.toString())) { - return; - } - String fqn = parameterType.toString(); - String name = getNameFromFqn(parameterType); - this.processReference(name, fqn, parameter); - } - - public void processReturnTypeReference(PhpReturnType returnType) { - PhpType parameterType = returnType.getDeclaredType(); - if (parameterType.isEmpty() && !PhpType.isPrimitiveType(parameterType.toString())) { - return; - } - String fqn = parameterType.toString(); - String name = getNameFromFqn(parameterType); - this.processReference(name, fqn, returnType); - } - - private String getNameFromFqn(PhpType parameterType) { - String[] fqnArray = parameterType.toString().split("\\\\"); - return fqnArray[fqnArray.length - 1]; - } - - protected abstract void processReference(@NotNull String name, @NotNull String fqn, @NotNull PsiElement identifier); - - public void processElement(@NotNull PsiElement element) { - element.accept(this.myCollectorVisitor); - } - - public void processElements(@NotNull Collection originalElements) { - for (PsiElement element : originalElements) { - this.processElement(element); - } - } -} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceResolver.java b/src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceResolver.java deleted file mode 100644 index 14fec51c7..000000000 --- a/src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceResolver.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -package com.magento.idea.magento2plugin.actions.generation.ImportReferences; - -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.jetbrains.php.codeInsight.PhpCodeInsightUtil; -import com.jetbrains.php.lang.PhpLangUtil; -import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment; -import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocType; -import com.jetbrains.php.lang.lexer.PhpTokenTypes; -import com.jetbrains.php.lang.psi.PhpPsiElementFactory; -import com.jetbrains.php.lang.psi.PhpPsiUtil; -import com.jetbrains.php.lang.psi.elements.ClassReference; -import com.jetbrains.php.lang.psi.elements.PhpNamespace; -import com.jetbrains.php.lang.psi.elements.PhpPsiElement; -import com.jetbrains.php.lang.psi.elements.Statement; -import com.jetbrains.php.lang.psi.resolve.types.PhpType; -import com.jetbrains.php.refactoring.PhpAliasImporter; -import gnu.trove.THashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class PhpClassReferenceResolver extends PhpClassReferenceExtractor { - private final PhpClassReferenceStorage myCandidatesToImportStorage = new PhpClassReferenceStorage(); - - public PhpClassReferenceResolver() { - } - - public void processElement(@NotNull PsiElement element) { - super.processElement(element); - } - - protected void processReference(@NotNull String name, @NotNull String fqn, @NotNull PsiElement identifier) { - if (!PhpType.isPrimitiveType(name)) { - this.myCandidatesToImportStorage.processReference(name, fqn, identifier); - } - } - - @Nullable - private static String alreadyImported(@NotNull PhpPsiElement scopeHolder, @NotNull Map aliases, @NotNull String fqn, @NotNull String name) { - boolean isSameNamespace = PhpCodeInsightUtil.isSameNamespace(scopeHolder, fqn); - if (isSameNamespace && PhpLangUtil.equalsClassNames(PhpLangUtil.toShortName(fqn), name)) { - return name; - } - boolean isNonCompound = isNonCompoundUseName(scopeHolder, fqn, name); - if (isNonCompound) { - return name; - } - Iterator entryIterator = aliases.entrySet().iterator(); - - Entry alias; - do { - if (!entryIterator.hasNext()) { - return null; - } - - alias = (Entry) entryIterator.next(); - } while (!PhpLangUtil.equalsClassNames((CharSequence) alias.getValue(), fqn)); - - return (String) alias.getKey(); - } - - public static boolean isNonCompoundUseName(@NotNull PhpPsiElement scopeHolder, @NotNull String fqn, @NotNull String name) { - String currentNamespaceName = scopeHolder instanceof PhpNamespace ? ((PhpNamespace)scopeHolder).getFQN() : ""; - return "\\".equals(currentNamespaceName) && PhpLangUtil.equalsClassNames(fqn, PhpLangUtil.toFQN(name)); - } - - public void importReferences(@NotNull PhpPsiElement scopeHolder, @NotNull List movedElements) { - Map referencesToReplace = this.importWithConflictResolve(scopeHolder); - if (referencesToReplace.isEmpty()) { - return; - } - PhpClassReferenceResolver.PhpClassReferenceRenamer renamer = new PhpClassReferenceResolver.PhpClassReferenceRenamer(scopeHolder.getProject(), referencesToReplace); - renamer.processElements(movedElements); - } - - private Map importWithConflictResolve(PhpPsiElement scopeHolder) { - Map aliases = PhpCodeInsightUtil.getAliasesInScope(scopeHolder); - Map referencesToReplace = new THashMap(); - boolean autoImport = PhpCodeInsightUtil.isAutoImportEnabled(scopeHolder); - - for (String name : this.myCandidatesToImportStorage.getNames()) { - String originalFqn = this.myCandidatesToImportStorage.getFqnByName(name); - assert originalFqn != null; - - String alias = alreadyImported(scopeHolder, aliases, originalFqn, name); - if (alias != null) { - if (!PhpLangUtil.equalsClassNames(name, alias)) { - referencesToReplace.put(name, alias); - } - } else if (!autoImport) { - referencesToReplace.put(name, originalFqn); - } else { - String importedFqn = aliases.get(name); - if (!PhpLangUtil.equalsClassNames(importedFqn, originalFqn)) { - if (importedFqn != null) { - String originalName = PhpLangUtil.toShortName(originalFqn); - String fqnForOriginalName = aliases.get(originalName); - if (fqnForOriginalName != null && !PhpLangUtil.equalsClassNames(fqnForOriginalName, originalFqn)) { - referencesToReplace.put(name, originalFqn); - } else { - referencesToReplace.put(name, originalName); - if (fqnForOriginalName == null) { - insertUseStatement(scopeHolder, originalName, originalFqn); - } - } - } else { - insertUseStatement(scopeHolder, name, originalFqn); - } - } - } - } - - return referencesToReplace; - } - - private static void insertUseStatement(PhpPsiElement scopeHolder, String name, String originalFqn) { - String originalName = PhpLangUtil.toShortName(originalFqn); - if (PhpLangUtil.equalsClassNames(originalName, name)) { - PhpAliasImporter.insertUseStatement(originalFqn, scopeHolder); - return; - } - PhpAliasImporter.insertUseStatement(originalFqn, name, scopeHolder); - } - - private static class PhpClassReferenceRenamer extends PhpClassReferenceExtractor { - private final Project myProject; - private final Map myRefToRename; - - private PhpClassReferenceRenamer(Project project, @NotNull Map replaceWithFqn) { - super(); - this.myProject = project; - this.myRefToRename = replaceWithFqn; - } - - protected void processReference(@NotNull String name, @NotNull String reference, @NotNull PsiElement identifier) { - if (this.myRefToRename.containsKey(name)) { - String fqn = this.myRefToRename.get(name); - Object newReference; - PsiElement oldReference; - if (!PhpPsiUtil.isOfType(identifier, PhpTokenTypes.IDENTIFIER) && !(identifier instanceof ClassReference)) { - newReference = PhpPsiElementFactory.createPhpDocType(this.myProject, fqn); - oldReference = PhpPsiUtil.getParentByCondition(identifier, false, PhpDocType.INSTANCEOF, PhpDocComment.INSTANCEOF); - } else { - newReference = PhpPsiElementFactory.createClassReference(this.myProject, fqn); - oldReference = PhpPsiUtil.getParentByCondition(identifier, false, ClassReference.INSTANCEOF, Statement.INSTANCEOF); - } - - assert oldReference != null; - - PsiElement added = oldReference.addRange(((PsiElement)newReference).getFirstChild(), ((PsiElement)newReference).getLastChild()); - oldReference.deleteChildRange(oldReference.getFirstChild(), added.getPrevSibling()); - } - } - } -} - diff --git a/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java index c2fdb8ce8..a6c66433b 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java @@ -29,7 +29,7 @@ import com.jetbrains.php.lang.psi.elements.Method; import com.jetbrains.php.lang.psi.elements.PhpClass; import com.jetbrains.php.lang.psi.elements.PhpPsiElement; -import com.magento.idea.magento2plugin.actions.generation.ImportReferences.PhpClassReferenceResolver; +import com.magento.idea.magento2plugin.actions.generation.references.PhpClassReferenceResolver; import com.magento.idea.magento2plugin.actions.generation.data.code.PluginMethodData; import com.magento.idea.magento2plugin.actions.generation.generator.code.PluginMethodsGenerator; import com.magento.idea.magento2plugin.actions.generation.util.CodeStyleSettings; diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/PluginClassGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/PluginClassGenerator.java index cb80c4fdd..a01a088c2 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/PluginClassGenerator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/PluginClassGenerator.java @@ -21,12 +21,12 @@ import com.jetbrains.php.lang.psi.elements.Method; import com.jetbrains.php.lang.psi.elements.PhpClass; import com.jetbrains.php.lang.psi.elements.PhpPsiElement; -import com.magento.idea.magento2plugin.actions.generation.ImportReferences.PhpClassReferenceResolver; import com.magento.idea.magento2plugin.actions.generation.data.PluginFileData; import com.magento.idea.magento2plugin.actions.generation.data.code.PluginMethodData; import com.magento.idea.magento2plugin.actions.generation.generator.code.PluginMethodsGenerator; import com.magento.idea.magento2plugin.actions.generation.generator.util.DirectoryGenerator; import com.magento.idea.magento2plugin.actions.generation.generator.util.FileFromTemplateGenerator; +import com.magento.idea.magento2plugin.actions.generation.references.PhpClassReferenceResolver; import com.magento.idea.magento2plugin.actions.generation.util.CodeStyleSettings; import com.magento.idea.magento2plugin.actions.generation.util.CollectInsertedMethods; import com.magento.idea.magento2plugin.actions.generation.util.FillTextBufferWithPluginMethods; @@ -46,10 +46,9 @@ import javax.swing.JOptionPane; import org.jetbrains.annotations.NotNull; -@SuppressWarnings({ - "PMD.ExcessiveImports" -}) +@SuppressWarnings({"PMD.ExcessiveImports"}) public class PluginClassGenerator extends FileGenerator { + private final PluginFileData pluginFileData; private final Project project; private final ValidatorBundle validatorBundle; @@ -86,8 +85,10 @@ public PluginClassGenerator( * Generate plugin. * * @param actionName String + * * @return PsiFile */ + @Override public PsiFile generate(final String actionName) { final PsiFile[] pluginFile = {null}; WriteCommandAction.runWriteCommandAction(project, () -> { @@ -227,6 +228,7 @@ private PhpClass createPluginClass(final String actionName) { return getFirstClassOfFile.execute((PhpFile) pluginFile); } + @Override protected void fillAttributes(final Properties attributes) { attributes.setProperty("NAME", pluginFileData.getPluginClassName()); attributes.setProperty("NAMESPACE", pluginFileData.getNamespace()); diff --git a/src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceExtractor.java b/src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceExtractor.java new file mode 100644 index 000000000..6766b38cb --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceExtractor.java @@ -0,0 +1,159 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.references; + +import com.intellij.psi.PsiElement; +import com.jetbrains.php.lang.psi.elements.Parameter; +import com.jetbrains.php.lang.psi.elements.PhpClass; +import com.jetbrains.php.lang.psi.elements.PhpReturnType; +import com.jetbrains.php.lang.psi.resolve.types.PhpType; +import com.jetbrains.php.lang.psi.visitors.PhpElementVisitor; +import java.util.Collection; +import org.jetbrains.annotations.NotNull; + +public abstract class PhpClassReferenceExtractor { + + /** + * Visitor that collects references from the class elements. + */ + private final PhpElementVisitor myCollectorVisitor = new PhpElementVisitor() { + + /** + * Visit class processor. + * + * @param phpClass PhpClass + */ + @Override + public void visitPhpClass(final PhpClass phpClass) { + PhpClassReferenceExtractor.this.processClassReference(phpClass); + } + + /** + * Visit parameter processor. + * + * @param parameter Parameter + */ + @Override + public void visitPhpParameter(final Parameter parameter) { + PhpClassReferenceExtractor.this.processParameterReference(parameter); + } + + /** + * Visit return type processor. + * + * @param returnType PhpReturnType + */ + @Override + public void visitPhpReturnType(final PhpReturnType returnType) { + PhpClassReferenceExtractor.this.processReturnTypeReference(returnType); + } + }; + + /** + * Process class reference. + * + * @param resolvedClass PhpClass + */ + public void processClassReference(final @NotNull PhpClass resolvedClass) { + final String name = resolvedClass.getName(); + this.processReference(name, resolvedClass.getFQN(), resolvedClass); + } + + /** + * Process reference for non primitive parameter type. + * + * @param parameter Parameter + */ + public void processParameterReference(final @NotNull Parameter parameter) { + final PhpType parameterType = parameter.getDeclaredType(); + final String complexType = extractComplexType(parameterType); + + if (parameterType.isEmpty() || complexType == null) { + return; + } + this.processReference(getNameFromFqn(complexType), complexType, parameter); + } + + /** + * Process reference for non primitive return type. + * + * @param returnType PhpReturnType + */ + public void processReturnTypeReference(final @NotNull PhpReturnType returnType) { + final PhpType returnPhpType = returnType.getDeclaredType(); + final String complexType = extractComplexType(returnPhpType); + + if (returnPhpType.isEmpty() || complexType == null) { + return; + } + this.processReference(getNameFromFqn(complexType), complexType, returnType); + } + + /** + * Extract complex type. + * + * @param type PhpType + * + * @return String + */ + private String extractComplexType(final @NotNull PhpType type) { + String complexType = type.toString(); + + for (final String complexTypeCandidate : type.getTypes()) { + if (!PhpType.isPrimitiveType(complexTypeCandidate)) { + complexType = complexTypeCandidate; + } + } + + return PhpType.isPrimitiveType(complexType) ? null : complexType; + } + + /** + * Get name from FQN string. + * + * @param fqn String + * + * @return String + */ + private String getNameFromFqn(final String fqn) { + final String[] fqnArray = fqn.split("\\\\"); + + return fqnArray[fqnArray.length - 1]; + } + + /** + * Process type reference. + * + * @param name String + * @param fqn String + * @param identifier PsiElement + */ + protected abstract void processReference( + @NotNull String name, + @NotNull String fqn, + @NotNull PsiElement identifier + ); + + /** + * Run visitor on an element. + * + * @param element PsiElement + */ + public void processElement(final @NotNull PsiElement element) { + element.accept(this.myCollectorVisitor); + } + + /** + * Visit elements to collect complex types references. + * + * @param originalElements Collection + */ + public void processElements(final @NotNull Collection originalElements) { + for (final PsiElement element : originalElements) { + this.processElement(element); + } + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceResolver.java b/src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceResolver.java new file mode 100644 index 000000000..ed952c129 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceResolver.java @@ -0,0 +1,240 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.references; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.jetbrains.php.codeInsight.PhpCodeInsightUtil; +import com.jetbrains.php.lang.PhpLangUtil; +import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment; +import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocType; +import com.jetbrains.php.lang.lexer.PhpTokenTypes; +import com.jetbrains.php.lang.psi.PhpPsiElementFactory; +import com.jetbrains.php.lang.psi.PhpPsiUtil; +import com.jetbrains.php.lang.psi.elements.ClassReference; +import com.jetbrains.php.lang.psi.elements.PhpNamespace; +import com.jetbrains.php.lang.psi.elements.PhpPsiElement; +import com.jetbrains.php.lang.psi.elements.Statement; +import com.jetbrains.php.lang.psi.resolve.types.PhpType; +import com.jetbrains.php.refactoring.PhpAliasImporter; +import gnu.trove.THashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PhpClassReferenceResolver extends PhpClassReferenceExtractor { + + private final PhpClassReferenceStorage myCandidatesToImportStorage = + new PhpClassReferenceStorage(); + + /** + * Check if provided FQN is not compound. + * + * @param scopeHolder PhpPsiElement + * @param fqn String + * @param name String + * + * @return boolean + */ + public static boolean isNonCompoundUseName( + final @NotNull PhpPsiElement scopeHolder, + final @NotNull String fqn, + final @NotNull String name + ) { + final String currentNamespaceName = scopeHolder instanceof PhpNamespace + ? ((PhpNamespace)scopeHolder).getFQN() + : ""; + + return "\\".equals(currentNamespaceName) + && PhpLangUtil.equalsClassNames(fqn, PhpLangUtil.toFQN(name)); + } + + /** + * Collect references. + * + * @param scopeHolder PhpPsiElement + * @param movedElements movedElements + */ + public void importReferences( + final @NotNull PhpPsiElement scopeHolder, + final @NotNull List movedElements + ) { + final Map referencesToReplace = this.importWithConflictResolve(scopeHolder); + + if (referencesToReplace.isEmpty()) { + return; + } + final PhpClassReferenceResolver.PhpClassReferenceRenamer renamer = + new PhpClassReferenceResolver.PhpClassReferenceRenamer( + scopeHolder.getProject(), + referencesToReplace + ); + renamer.processElements(movedElements); + } + + @Override + protected void processReference( + final @NotNull String name, + final @NotNull String fqn, + final @NotNull PsiElement identifier + ) { + if (!PhpType.isPrimitiveType(name)) { + this.myCandidatesToImportStorage.processReference(name, fqn, identifier); + } + } + + private static @Nullable String alreadyImported( + final @NotNull PhpPsiElement scopeHolder, + final @NotNull Map aliases, + final @NotNull String fqn, + final @NotNull String name + ) { + final boolean isSameNamespace = PhpCodeInsightUtil.isSameNamespace(scopeHolder, fqn); + + if (isSameNamespace && PhpLangUtil.equalsClassNames(PhpLangUtil.toShortName(fqn), name)) { + return name; + } + final boolean isNonCompound = isNonCompoundUseName(scopeHolder, fqn, name); + + if (isNonCompound) { + return name; + } + final Iterator> entryIterator = aliases.entrySet().iterator(); + + Entry alias; + + do { + if (!entryIterator.hasNext()) { + return null; + } + + alias = entryIterator.next(); + } while (!PhpLangUtil.equalsClassNames(alias.getValue(), fqn)); + + return alias.getKey(); + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ConfusingTernary"}) + private Map importWithConflictResolve( + final @NotNull PhpPsiElement scopeHolder + ) { + final Map aliases = PhpCodeInsightUtil.getAliasesInScope(scopeHolder); + final Map referencesToReplace = new THashMap<>(); + final boolean autoImport = PhpCodeInsightUtil.isAutoImportEnabled(scopeHolder); + + for (final String name : this.myCandidatesToImportStorage.getNames()) { + final String originalFqn = this.myCandidatesToImportStorage.getFqnByName(name); + assert originalFqn != null; + + final String alias = alreadyImported(scopeHolder, aliases, originalFqn, name); + + if (alias != null) { + if (!PhpLangUtil.equalsClassNames(name, alias)) { + referencesToReplace.put(name, alias); + } + } else if (!autoImport) { + referencesToReplace.put(name, originalFqn); + } else { + final String importedFqn = aliases.get(name); + if (!PhpLangUtil.equalsClassNames(importedFqn, originalFqn)) { + if (importedFqn != null) { + final String originalName = PhpLangUtil.toShortName(originalFqn); + final String fqnForOriginalName = aliases.get(originalName); + if (fqnForOriginalName != null + && !PhpLangUtil.equalsClassNames(fqnForOriginalName, originalFqn)) { + referencesToReplace.put(name, originalFqn); + } else { + referencesToReplace.put(name, originalName); + if (fqnForOriginalName == null) { + insertUseStatement(scopeHolder, originalName, originalFqn); + } + } + } else { + insertUseStatement(scopeHolder, name, originalFqn); + } + } + } + } + + return referencesToReplace; + } + + private static void insertUseStatement( + final PhpPsiElement scopeHolder, + final String name, + final String originalFqn + ) { + final String originalName = PhpLangUtil.toShortName(originalFqn); + + if (PhpLangUtil.equalsClassNames(originalName, name)) { + PhpAliasImporter.insertUseStatement(originalFqn, scopeHolder); + return; + } + PhpAliasImporter.insertUseStatement(originalFqn, name, scopeHolder); + } + + private static class PhpClassReferenceRenamer extends PhpClassReferenceExtractor { + + private final Project myProject; + private final Map myRefToRename; + + private PhpClassReferenceRenamer( + final @NotNull Project project, + final @NotNull Map replaceWithFqn + ) { + super(); + this.myProject = project; + this.myRefToRename = replaceWithFqn; + } + + @SuppressWarnings("PMD.ConfusingTernary") + @Override + protected void processReference( + final @NotNull String name, + final @NotNull String reference, + final @NotNull PsiElement identifier + ) { + if (this.myRefToRename.containsKey(name)) { + final String fqn = this.myRefToRename.get(name); + PsiElement newReference; + PsiElement oldReference; + + if (!PhpPsiUtil.isOfType(identifier, PhpTokenTypes.IDENTIFIER) + && !(identifier instanceof ClassReference)) { + + newReference = PhpPsiElementFactory.createPhpDocType(this.myProject, fqn); + oldReference = PhpPsiUtil.getParentByCondition( + identifier, + false, + PhpDocType.INSTANCEOF, + PhpDocComment.INSTANCEOF + ); + } else { + newReference = PhpPsiElementFactory.createClassReference(this.myProject, fqn); + oldReference = PhpPsiUtil.getParentByCondition( + identifier, + false, + ClassReference.INSTANCEOF, + Statement.INSTANCEOF + ); + } + assert oldReference != null; + + final PsiElement added = oldReference.addRange( + newReference.getFirstChild(), + newReference.getLastChild() + ); + oldReference.deleteChildRange( + oldReference.getFirstChild(), + added.getPrevSibling() + ); + } + } + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceStorage.java b/src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceStorage.java similarity index 50% rename from src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceStorage.java rename to src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceStorage.java index 37bda181f..726988cc6 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/ImportReferences/PhpClassReferenceStorage.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/references/PhpClassReferenceStorage.java @@ -2,7 +2,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -package com.magento.idea.magento2plugin.actions.generation.ImportReferences; + +package com.magento.idea.magento2plugin.actions.generation.references; import com.intellij.psi.PsiElement; import com.jetbrains.php.refactoring.importReferences.PhpClassReferenceExtractor; @@ -13,20 +14,40 @@ import org.jetbrains.annotations.Nullable; public class PhpClassReferenceStorage extends PhpClassReferenceExtractor { - private final Map myReferences = new THashMap(); - public PhpClassReferenceStorage() { - } + private final Map myReferences = new THashMap<>(); - protected void processReference(@NotNull String name, @NotNull String fqn, @NotNull PsiElement identifier) { + /** + * Process reference. + * + * @param name String + * @param fqn String + * @param identifier PsiElement + */ + protected void processReference( + final @NotNull String name, + final @NotNull String fqn, + final @NotNull PsiElement identifier + ) { this.myReferences.put(name, fqn); } - @Nullable - public String getFqnByName(@NotNull String name) { + /** + * Get from resolved references type FQN by name. + * + * @param name String + * + * @return String + */ + public @Nullable String getFqnByName(final @NotNull String name) { return this.myReferences.get(name); } + /** + * Get all names for resolved complex PHP types. + * + * @return Set[String] + */ public Set getNames() { return this.myReferences.keySet(); } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java b/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java index 12d1d9bcb..06a05a79d 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java @@ -10,7 +10,7 @@ import com.jetbrains.php.lang.psi.elements.Method; import com.jetbrains.php.lang.psi.elements.Parameter; import com.jetbrains.php.lang.psi.elements.PhpReturnType; -import com.magento.idea.magento2plugin.actions.generation.ImportReferences.PhpClassReferenceResolver; +import com.magento.idea.magento2plugin.actions.generation.references.PhpClassReferenceResolver; import com.magento.idea.magento2plugin.actions.generation.data.code.PluginMethodData; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; From 6de9a0e1c9c17f516ca44abc3b11eb496aa2472b Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Thu, 24 Jun 2021 00:43:57 +0300 Subject: [PATCH 2/3] Fixed static checks issues --- .../PluginGenerateMethodHandlerBase.java | 2 +- .../util/FillTextBufferWithPluginMethods.java | 30 ++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java index a6c66433b..9566cdf34 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java @@ -29,9 +29,9 @@ import com.jetbrains.php.lang.psi.elements.Method; import com.jetbrains.php.lang.psi.elements.PhpClass; import com.jetbrains.php.lang.psi.elements.PhpPsiElement; -import com.magento.idea.magento2plugin.actions.generation.references.PhpClassReferenceResolver; import com.magento.idea.magento2plugin.actions.generation.data.code.PluginMethodData; import com.magento.idea.magento2plugin.actions.generation.generator.code.PluginMethodsGenerator; +import com.magento.idea.magento2plugin.actions.generation.references.PhpClassReferenceResolver; import com.magento.idea.magento2plugin.actions.generation.util.CodeStyleSettings; import com.magento.idea.magento2plugin.actions.generation.util.CollectInsertedMethods; import com.magento.idea.magento2plugin.actions.generation.util.FillTextBufferWithPluginMethods; diff --git a/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java b/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java index 06a05a79d..82e2b4847 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java @@ -2,6 +2,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + package com.magento.idea.magento2plugin.actions.generation.util; import com.intellij.openapi.util.Key; @@ -10,17 +11,22 @@ import com.jetbrains.php.lang.psi.elements.Method; import com.jetbrains.php.lang.psi.elements.Parameter; import com.jetbrains.php.lang.psi.elements.PhpReturnType; -import com.magento.idea.magento2plugin.actions.generation.references.PhpClassReferenceResolver; import com.magento.idea.magento2plugin.actions.generation.data.code.PluginMethodData; -import org.jetbrains.annotations.NotNull; +import com.magento.idea.magento2plugin.actions.generation.references.PhpClassReferenceResolver; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Set; +import org.jetbrains.annotations.NotNull; public class FillTextBufferWithPluginMethods { private static FillTextBufferWithPluginMethods INSTANCE = null; + /** + * Get util instance. + * + * @return FillTextBufferWithPluginMethods + */ public static FillTextBufferWithPluginMethods getInstance() { if (null == INSTANCE) { INSTANCE = new FillTextBufferWithPluginMethods(); @@ -28,7 +34,22 @@ public static FillTextBufferWithPluginMethods getInstance() { return INSTANCE; } - public void execute(@NotNull Key targetClassKey, Set insertedMethodsNames, @NotNull PhpClassReferenceResolver resolver, @NotNull StringBuffer textBuf, @NotNull PluginMethodData[] pluginMethods) { + /** + * Fill text buffer with plugin methods. + * + * @param targetClassKey Key[Object] + * @param insertedMethodsNames Set[CharSequence] + * @param resolver PhpClassReferenceResolver + * @param textBuf StringBuffer + * @param pluginMethods PluginMethodData + */ + public void execute( + final @NotNull Key targetClassKey, + final Set insertedMethodsNames, + final @NotNull PhpClassReferenceResolver resolver, + final @NotNull StringBuffer textBuf, + final @NotNull PluginMethodData[] pluginMethods + ) { for (PluginMethodData pluginMethod : pluginMethods) { insertedMethodsNames.add(pluginMethod.getMethod().getName()); PhpDocComment comment = pluginMethod.getDocComment(); @@ -39,7 +60,8 @@ public void execute(@NotNull Key targetClassKey, Set inser Parameter[] parameters = targetMethod.getParameters(); Collection processElements = new ArrayList<>(Arrays.asList(parameters)); resolver.processElements(processElements); - PsiElement targetClass = (PsiElement) pluginMethod.getTargetMethod().getUserData(targetClassKey); + PsiElement targetClass = (PsiElement) pluginMethod.getTargetMethod() + .getUserData(targetClassKey); resolver.processElement(targetClass); PhpReturnType returnType = targetMethod.getReturnType(); if (returnType != null) { From 58abe4fa9c6ff3025186b69f90ca50292b9635bb Mon Sep 17 00:00:00 2001 From: bohdan-harniuk Date: Thu, 24 Jun 2021 00:53:01 +0300 Subject: [PATCH 3/3] Fixed static checks issues --- .../PluginGenerateMethodHandlerBase.java | 2 +- .../generator/PluginClassGenerator.java | 2 +- .../util/FillTextBufferWithPluginMethods.java | 32 +++++++------------ 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java index 9566cdf34..5fd1810fa 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/PluginGenerateMethodHandlerBase.java @@ -72,7 +72,7 @@ public abstract class PluginGenerateMethodHandlerBase implements LanguageCodeIns */ public PluginGenerateMethodHandlerBase(final Plugin.PluginType type) { this.type = type.toString(); - this.fillTextBuffer = FillTextBufferWithPluginMethods.getInstance(); + this.fillTextBuffer = new FillTextBufferWithPluginMethods(); this.collectInsertedMethods = CollectInsertedMethods.getInstance(); this.validatorBundle = new ValidatorBundle(); this.commonBundle = new CommonBundle(); diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/PluginClassGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/PluginClassGenerator.java index a01a088c2..3e029c84c 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/generator/PluginClassGenerator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/PluginClassGenerator.java @@ -73,7 +73,7 @@ public PluginClassGenerator( this.directoryGenerator = DirectoryGenerator.getInstance(); this.fileFromTemplateGenerator = new FileFromTemplateGenerator(project); this.getFirstClassOfFile = GetFirstClassOfFile.getInstance(); - this.fillTextBuffer = FillTextBufferWithPluginMethods.getInstance(); + this.fillTextBuffer = new FillTextBufferWithPluginMethods(); this.collectInsertedMethods = CollectInsertedMethods.getInstance(); this.pluginFileData = pluginFileData; this.project = project; diff --git a/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java b/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java index 82e2b4847..286d0a3eb 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/util/FillTextBufferWithPluginMethods.java @@ -20,19 +20,6 @@ import org.jetbrains.annotations.NotNull; public class FillTextBufferWithPluginMethods { - private static FillTextBufferWithPluginMethods INSTANCE = null; - - /** - * Get util instance. - * - * @return FillTextBufferWithPluginMethods - */ - public static FillTextBufferWithPluginMethods getInstance() { - if (null == INSTANCE) { - INSTANCE = new FillTextBufferWithPluginMethods(); - } - return INSTANCE; - } /** * Fill text buffer with plugin methods. @@ -43,27 +30,30 @@ public static FillTextBufferWithPluginMethods getInstance() { * @param textBuf StringBuffer * @param pluginMethods PluginMethodData */ + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public void execute( final @NotNull Key targetClassKey, final Set insertedMethodsNames, final @NotNull PhpClassReferenceResolver resolver, final @NotNull StringBuffer textBuf, - final @NotNull PluginMethodData[] pluginMethods + final @NotNull PluginMethodData... pluginMethods ) { - for (PluginMethodData pluginMethod : pluginMethods) { + for (final PluginMethodData pluginMethod : pluginMethods) { insertedMethodsNames.add(pluginMethod.getMethod().getName()); - PhpDocComment comment = pluginMethod.getDocComment(); + final PhpDocComment comment = pluginMethod.getDocComment(); + if (comment != null) { textBuf.append(comment.getText()); } - Method targetMethod = pluginMethod.getTargetMethod(); - Parameter[] parameters = targetMethod.getParameters(); - Collection processElements = new ArrayList<>(Arrays.asList(parameters)); + final Method targetMethod = pluginMethod.getTargetMethod(); + final Parameter[] parameters = targetMethod.getParameters(); + final Collection processElements = + new ArrayList<>(Arrays.asList(parameters)); resolver.processElements(processElements); - PsiElement targetClass = (PsiElement) pluginMethod.getTargetMethod() + final PsiElement targetClass = (PsiElement) pluginMethod.getTargetMethod() .getUserData(targetClassKey); resolver.processElement(targetClass); - PhpReturnType returnType = targetMethod.getReturnType(); + final PhpReturnType returnType = targetMethod.getReturnType(); if (returnType != null) { resolver.processElement(returnType); }