Merge branch 'ypankratyev/duplicate_extension_in_register_quickfix'
authorYaroslav Pankratyev <yaroslav.pankratyev@jetbrains.com>
Fri, 11 Aug 2017 09:18:11 +0000 (16:18 +0700)
committerYaroslav Pankratyev <yaroslav.pankratyev@jetbrains.com>
Fri, 11 Aug 2017 09:18:11 +0000 (16:18 +0700)
platform/core-api/src/com/intellij/psi/search/GlobalSearchScope.java
plugins/devkit/src/inspections/quickfix/RegisterExtensionFix.java
plugins/devkit/src/inspections/quickfix/RegisterExtensionFixProvider.java
plugins/devkit/src/util/ExtensionLocator.java
plugins/devkit/src/util/ExtensionPointCandidate.java
plugins/devkit/src/util/ExtensionPointLocator.java
plugins/devkit/src/util/PluginRelatedLocatorsUtils.java

index f94d07f258fb72fa3485a6eef41076257f614ed9..7c4dcbaa3c86c1c6cff21c4d22f6f67393c228de 100644 (file)
@@ -345,13 +345,22 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw
   @NotNull
   public static GlobalSearchScope filesWithoutLibrariesScope(@NotNull Project project, @NotNull Collection<VirtualFile> files) {
     if (files.isEmpty()) return EMPTY_SCOPE;
-    return new FilesScope(project, files, false);
+    return new FilesScope(project, files, false, false);
   }
 
   @NotNull
   public static GlobalSearchScope filesWithLibrariesScope(@NotNull Project project, @NotNull Collection<VirtualFile> files) {
+    return filesWithLibrariesScope(project, files, false);
+  }
+
+  /**
+   * @since 2017.3
+   */
+  @NotNull
+  public static GlobalSearchScope filesWithLibrariesScope(@NotNull Project project, @NotNull Collection<VirtualFile> files,
+                                                          boolean searchOutsideRootModel) {
     if (files.isEmpty()) return EMPTY_SCOPE;
-    return new FilesScope(project, files, true);
+    return new FilesScope(project, files, true, searchOutsideRootModel);
   }
 
   /**
@@ -759,19 +768,22 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw
 
   public static class FilesScope extends GlobalSearchScope implements Iterable<VirtualFile> {
     private final Collection<VirtualFile> myFiles;
+    private final boolean mySearchOutsideRootModel;
     private volatile Boolean myHasFilesOutOfProjectRoots;
 
     /**
      * @deprecated use {@link GlobalSearchScope#filesScope(Project, Collection)}
      */
     public FilesScope(@Nullable Project project, @NotNull Collection<VirtualFile> files) {
-      this(project, files, null);
+      this(project, files, null, false);
     }
 
     // Optimization
-    private FilesScope(@Nullable  Project project, @NotNull Collection<VirtualFile> files, @Nullable Boolean hasFilesOutOfProjectRoots) {
+    private FilesScope(@Nullable  Project project, @NotNull Collection<VirtualFile> files, @Nullable Boolean hasFilesOutOfProjectRoots,
+                       boolean searchOutsideRootModel) {
       super(project);
       myFiles = files;
+      mySearchOutsideRootModel = searchOutsideRootModel;
       myHasFilesOutOfProjectRoots = hasFilesOutOfProjectRoots;
     }
 
@@ -827,5 +839,10 @@ public abstract class GlobalSearchScope extends SearchScope implements ProjectAw
     public Iterator<VirtualFile> iterator() {
       return myFiles.iterator();
     }
+
+    @Override
+    public boolean isSearchOutsideRootModel() {
+      return mySearchOutsideRootModel;
+    }
   }
 }
index 67bc2114b4d8b51ea17479418845de9038f17150..9563590507817d54761d7c95bc917976082e3b6a 100644 (file)
@@ -33,7 +33,6 @@ import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiFile;
 import com.intellij.psi.xml.XmlAttribute;
 import com.intellij.psi.xml.XmlTag;
-import com.intellij.util.Consumer;
 import com.intellij.util.IncorrectOperationException;
 import com.intellij.util.KeyedLazyInstanceEP;
 import com.intellij.util.PsiNavigateUtil;
@@ -45,17 +44,15 @@ import org.jetbrains.idea.devkit.dom.Extensions;
 import org.jetbrains.idea.devkit.dom.IdeaPlugin;
 import org.jetbrains.idea.devkit.util.ExtensionPointCandidate;
 
-import java.util.List;
+import java.util.ArrayList;
 import java.util.Map;
+import java.util.Set;
 
-/**
- * @author yole
- */
 public class RegisterExtensionFix implements IntentionAction {
   private final PsiClass myExtensionClass;
-  private final List<ExtensionPointCandidate> myEPCandidates;
+  private final Set<ExtensionPointCandidate> myEPCandidates;
 
-  public RegisterExtensionFix(PsiClass extensionClass, List<ExtensionPointCandidate> epCandidates) {
+  public RegisterExtensionFix(PsiClass extensionClass, Set<ExtensionPointCandidate> epCandidates) {
     myExtensionClass = extensionClass;
     myEPCandidates = epCandidates;
   }
@@ -84,11 +81,11 @@ public class RegisterExtensionFix implements IntentionAction {
 
   private void doFix(Editor editor, final DomFileElement<IdeaPlugin> element) {
     if (myEPCandidates.size() == 1) {
-      registerExtension(element, myEPCandidates.get(0));
+      registerExtension(element, myEPCandidates.iterator().next());
     }
     else {
       final BaseListPopupStep<ExtensionPointCandidate> popupStep =
-        new BaseListPopupStep<ExtensionPointCandidate>("Choose Extension Point", myEPCandidates) {
+        new BaseListPopupStep<ExtensionPointCandidate>("Choose Extension Point", new ArrayList<>(myEPCandidates)) {
           @Override
           public PopupStep onChosen(ExtensionPointCandidate selectedValue, boolean finalChoice) {
             registerExtension(element, selectedValue);
index 815d597442c56a8df262f529339f6affd40da9ea..fc375d7cd1456e4e297d92280c44a3811a1be737 100644 (file)
@@ -29,12 +29,8 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.idea.devkit.util.ExtensionPointCandidate;
 import org.jetbrains.idea.devkit.util.ExtensionPointLocator;
 
-import java.util.List;
+import java.util.Set;
 
-/**
- * @author Dmitry Avdeev
- *         Date: 1/19/12
- */
 public class RegisterExtensionFixProvider implements UnusedDeclarationFixProvider {
 
   @NotNull
@@ -53,7 +49,7 @@ public class RegisterExtensionFixProvider implements UnusedDeclarationFixProvide
     }
 
     ExtensionPointLocator extensionPointLocator = new ExtensionPointLocator(psiClass);
-    List<ExtensionPointCandidate> candidateList = extensionPointLocator.findSuperCandidates();
+    Set<ExtensionPointCandidate> candidateList = extensionPointLocator.findSuperCandidates();
     if (!candidateList.isEmpty()) {
       return new IntentionAction[]{new RegisterExtensionFix(psiClass, candidateList)};
     }
index e56046198932d96d4f3a47497d016306888fd91f..358f08865d36b2f974146397ef5b133487261a70 100644 (file)
@@ -60,7 +60,6 @@ public class ExtensionLocator {
     return result;
   }
 
-  @SuppressWarnings("unchecked") // it's fine with Processor.FALSE
   public static boolean isRegisteredExtension(@NotNull PsiClass psiClass) {
     String name = psiClass.getQualifiedName();
     if (name == null) {
index 87fee08af0adf9c313df211b665f42a1d4755335..13db4271bb7cbd889a49776b018c7946a2505b17 100644 (file)
@@ -18,9 +18,6 @@ package org.jetbrains.idea.devkit.util;
 import com.intellij.psi.SmartPsiElementPointer;
 import com.intellij.psi.xml.XmlTag;
 
-/**
- * @author yole
- */
 public class ExtensionPointCandidate extends PointableCandidate {
   public final String epName;
   public final String attributeName;
@@ -52,4 +49,28 @@ public class ExtensionPointCandidate extends PointableCandidate {
   public String toString() {
     return epName;
   }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ExtensionPointCandidate candidate = (ExtensionPointCandidate)o;
+
+    if (epName != null ? !epName.equals(candidate.epName) : candidate.epName != null) return false;
+    if (attributeName != null ? !attributeName.equals(candidate.attributeName) : candidate.attributeName != null) return false;
+    if (tagName != null ? !tagName.equals(candidate.tagName) : candidate.tagName != null) return false;
+    if (beanClassName != null ? !beanClassName.equals(candidate.beanClassName) : candidate.beanClassName != null) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = epName != null ? epName.hashCode() : 0;
+    result = 31 * result + (attributeName != null ? attributeName.hashCode() : 0);
+    result = 31 * result + (tagName != null ? tagName.hashCode() : 0);
+    result = 31 * result + (beanClassName != null ? beanClassName.hashCode() : 0);
+    return result;
+  }
 }
index 0ce5c5f8f1ea0adea19727aaac5fb580505380ba..6122931b0eb9a9ae418005385debfe94968440d6 100644 (file)
@@ -24,49 +24,48 @@ import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.search.PsiSearchHelper;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.psi.xml.XmlTag;
-import com.intellij.util.SmartList;
+import com.intellij.util.containers.SmartHashSet;
 import com.intellij.util.xml.DomElement;
 import com.intellij.util.xml.DomUtil;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.idea.devkit.dom.ExtensionPoint;
 
 import java.util.HashSet;
-import java.util.List;
+import java.util.Set;
 
 public class ExtensionPointLocator {
-
   private final PsiClass myPsiClass;
 
   public ExtensionPointLocator(PsiClass psiClass) {
     myPsiClass = psiClass;
   }
 
-  public List<ExtensionPointCandidate> findDirectCandidates() {
-    final List<ExtensionPointCandidate> candidates = new SmartList<>();
+
+  public Set<ExtensionPointCandidate> findDirectCandidates() {
+    Set<ExtensionPointCandidate> candidates = new SmartHashSet<>();
     findExtensionPointCandidates(myPsiClass, candidates);
     return candidates;
   }
 
-  public List<ExtensionPointCandidate> findSuperCandidates() {
-    final List<ExtensionPointCandidate> candidates = new SmartList<>();
+  public Set<ExtensionPointCandidate> findSuperCandidates() {
+    Set<ExtensionPointCandidate> candidates = new SmartHashSet<>();
     findExtensionPointCandidatesInHierarchy(myPsiClass, candidates, new HashSet<>());
     return candidates;
   }
 
   private static void findExtensionPointCandidatesInHierarchy(PsiClass psiClass,
-                                                              List<ExtensionPointCandidate> list,
+                                                              Set<ExtensionPointCandidate> candidates,
                                                               HashSet<PsiClass> processed) {
     for (PsiClass superClass : psiClass.getSupers()) {
-      if (!processed.add(superClass) ||
-          CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) {
+      if (!processed.add(superClass) || CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName())) {
         continue;
       }
-      findExtensionPointCandidates(superClass, list);
-      findExtensionPointCandidatesInHierarchy(superClass, list, processed);
+      findExtensionPointCandidates(superClass, candidates);
+      findExtensionPointCandidatesInHierarchy(superClass, candidates, processed);
     }
   }
 
-  private static void findExtensionPointCandidates(PsiClass psiClass, final List<ExtensionPointCandidate> list) {
+  private static void findExtensionPointCandidates(PsiClass psiClass, Set<ExtensionPointCandidate> candidates) {
     String name = psiClass.getQualifiedName();
     if (name == null) return;
 
@@ -74,18 +73,18 @@ public class ExtensionPointLocator {
     GlobalSearchScope scope = PluginRelatedLocatorsUtils.getCandidatesScope(project);
     PsiSearchHelper.SERVICE.getInstance(project).processUsagesInNonJavaFiles(name, (file, startOffset, endOffset) -> {
       PsiElement element = file.findElementAt(startOffset);
-      processExtensionPointCandidate(element, list);
+      processExtensionPointCandidate(element, candidates);
       return true;
     }, scope);
   }
 
-  private static void processExtensionPointCandidate(PsiElement element, List<ExtensionPointCandidate> list) {
+  private static void processExtensionPointCandidate(PsiElement element, Set<ExtensionPointCandidate> candidates) {
     XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
     if (tag == null) return;
     if ("extensionPoint".equals(tag.getName())) {
       String epName = getEPName(tag);
       if (epName != null) {
-        list.add(new ExtensionPointCandidate(SmartPointerManager.getInstance(tag.getProject()).createSmartPsiElementPointer(tag), epName));
+        candidates.add(new ExtensionPointCandidate(SmartPointerManager.getInstance(tag.getProject()).createSmartPsiElementPointer(tag), epName));
       }
     }
     else if ("with".equals(tag.getName())) {
@@ -97,7 +96,7 @@ public class ExtensionPointLocator {
       String epName = getEPName(extensionPointTag);
       String beanClassName = extensionPointTag.getAttributeValue("beanClass");
       if ((attrName == null && tagName == null) || epName == null) return;
-      list.add(new ExtensionPointCandidate(SmartPointerManager.getInstance(extensionPointTag.getProject())
+      candidates.add(new ExtensionPointCandidate(SmartPointerManager.getInstance(extensionPointTag.getProject())
                                              .createSmartPsiElementPointer(extensionPointTag), epName, attrName, tagName, beanClassName));
     }
   }
index 9c1366d6cde0a1d5da9f5c8ab83e0efc462a942d..8b4a4695043c65f6a793f8aecfbae5ec6d09b315 100644 (file)
 package org.jetbrains.idea.devkit.util;
 
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.impl.LibraryScopeCache;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.GlobalSearchScopesCore;
 import com.intellij.util.xml.DomService;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.idea.devkit.dom.IdeaPlugin;
@@ -30,8 +32,11 @@ class PluginRelatedLocatorsUtils {
 
   @NotNull
   static GlobalSearchScope getCandidatesScope(@NotNull Project project) {
+    GlobalSearchScope scope = GlobalSearchScopesCore.projectProductionScope(project)
+      .uniteWith(LibraryScopeCache.getInstance(project).getLibrariesOnlyScope());
+
     Collection<VirtualFile> candidates = DomService.getInstance()
-      .getDomFileCandidates(IdeaPlugin.class, project, GlobalSearchScope.allScope(project));
-    return GlobalSearchScope.filesScope(project, candidates);
+      .getDomFileCandidates(IdeaPlugin.class, project, scope);
+    return GlobalSearchScope.filesWithLibrariesScope(project, candidates, true);
   }
 }