don't search for custom engine if junit 5 is not on classpath
[idea/community.git] / plugins / devkit / src / util / ExtensionLocator.java
1 /*
2  * Copyright 2000-2017 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.idea.devkit.util;
17
18 import com.intellij.openapi.project.Project;
19 import com.intellij.openapi.util.text.StringUtil;
20 import com.intellij.psi.PsiClass;
21 import com.intellij.psi.PsiElement;
22 import com.intellij.psi.PsiFile;
23 import com.intellij.psi.SmartPointerManager;
24 import com.intellij.psi.search.GlobalSearchScope;
25 import com.intellij.psi.search.PsiNonJavaFileReferenceProcessor;
26 import com.intellij.psi.search.PsiSearchHelper;
27 import com.intellij.psi.util.PsiTreeUtil;
28 import com.intellij.psi.xml.XmlTag;
29 import com.intellij.psi.xml.XmlToken;
30 import com.intellij.util.CommonProcessors;
31 import com.intellij.util.Processor;
32 import com.intellij.util.SmartList;
33 import com.intellij.util.xml.DomElement;
34 import com.intellij.util.xml.DomUtil;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.idea.devkit.dom.Extension;
37
38 import java.util.Collections;
39 import java.util.List;
40
41 public class ExtensionLocator {
42   private final PsiClass myPsiClass;
43
44   public ExtensionLocator(PsiClass aClass) {
45     myPsiClass = aClass;
46   }
47
48   @NotNull
49   public List<ExtensionCandidate> findCandidates() {
50     String name = myPsiClass.getQualifiedName();
51     if (name == null) {
52       return Collections.emptyList();
53     }
54
55     List<ExtensionCandidate> result = new SmartList<>();
56     processExtensionDeclarations(myPsiClass, new ReferenceProcessor(name, tag -> {
57       result.add(new ExtensionCandidate(SmartPointerManager.getInstance(tag.getProject()).createSmartPsiElementPointer(tag)));
58       return true; // continue processing
59     }));
60     return result;
61   }
62
63   @SuppressWarnings("unchecked") // it's fine with Processor.FALSE
64   public static boolean isRegisteredExtension(@NotNull PsiClass psiClass) {
65     String name = psiClass.getQualifiedName();
66     if (name == null) {
67       return false;
68     }
69
70     CommonProcessors.FindFirstProcessor<XmlTag> processor = new CommonProcessors.FindFirstProcessor<>();
71     processExtensionDeclarations(psiClass, new ReferenceProcessor(name, processor));
72     return processor.isFound();
73   }
74
75   private static void processExtensionDeclarations(PsiClass psiClass, PsiNonJavaFileReferenceProcessor referenceProcessor) {
76     String name = psiClass.getQualifiedName();
77     if (name == null) return;
78
79     Project project = psiClass.getProject();
80     GlobalSearchScope scope = PluginRelatedLocatorsUtils.getCandidatesScope(project);
81
82     PsiSearchHelper.SERVICE.getInstance(project).processUsagesInNonJavaFiles(name, referenceProcessor, scope);
83   }
84
85   private static class ReferenceProcessor implements PsiNonJavaFileReferenceProcessor {
86     private final String myExtensionClassName;
87     private final Processor<XmlTag> myExtensionTagHandler;
88
89     private ReferenceProcessor(String name, Processor<XmlTag> extensionTagHandler) {
90       myExtensionClassName = name;
91       myExtensionTagHandler = extensionTagHandler;
92     }
93
94     @Override
95     public boolean process(PsiFile file, int startOffset, int endOffset) {
96       PsiElement element = file.findElementAt(startOffset);
97       String tokenText = element instanceof XmlToken ? element.getText() : null;
98       if (!StringUtil.equals(myExtensionClassName, tokenText)) return true;
99
100       XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
101       if (tag == null) return true;
102
103       DomElement dom = DomUtil.getDomElement(tag);
104       if (dom instanceof Extension && ((Extension)dom).getExtensionPoint() != null) {
105         return myExtensionTagHandler.process(tag);
106       }
107       return true;
108     }
109   }
110 }