summaryrefslogtreecommitdiff
path: root/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java')
-rw-r--r--plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java161
1 files changed, 85 insertions, 76 deletions
diff --git a/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java b/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java
index e23254da8d1a..3fcf1c337b86 100644
--- a/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java
+++ b/plugins/groovy/src/org/intellij/plugins/intelliLang/inject/groovy/PatternEditorContextMembersProvider.java
@@ -19,7 +19,7 @@ import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
-import com.intellij.openapi.util.ModificationTracker;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.compiler.PatternClassBean;
import com.intellij.patterns.compiler.PatternCompilerFactory;
import com.intellij.psi.*;
@@ -30,14 +30,13 @@ import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.TextOccurenceProcessor;
import com.intellij.psi.search.UsageSearchContext;
-import com.intellij.psi.util.CachedValue;
-import com.intellij.psi.util.CachedValueProvider;
-import com.intellij.psi.util.CachedValuesManager;
-import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.*;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlText;
+import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.SoftFactoryMap;
import com.intellij.util.text.StringSearcher;
import org.intellij.plugins.intelliLang.inject.InjectorUtils;
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
@@ -46,86 +45,74 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
-import java.util.Collections;
import java.util.List;
+import java.util.Set;
/**
* @author Gregory.Shrago
*/
public class PatternEditorContextMembersProvider extends NonCodeMembersContributor {
- public static final Key<CachedValue<List<PsiElement>>> INJECTION_PARSED_CONTEXT = Key.create("INJECTION_PARSED_CONTEXT");
+ private static final Key<SoftFactoryMap<Class[], PsiFile>> PATTERN_INJECTION_CONTEXT = Key.create("PATTERN_INJECTION_CONTEXT");
+ private static final Key<CachedValue<Set<String>>> PATTERN_CLASSES = Key.create("PATTERN_CLASSES");
@Override
public void processDynamicElements(@NotNull PsiType qualifierType,
- @NotNull PsiScopeProcessor processor,
- @NotNull PsiElement place,
- @NotNull ResolveState state) {
+ @NotNull final PsiScopeProcessor scopeProcessor,
+ @NotNull final PsiElement place,
+ @NotNull final ResolveState state) {
final PsiFile file = place.getContainingFile().getOriginalFile();
- CachedValue<List<PsiElement>> value = file.getUserData(INJECTION_PARSED_CONTEXT);
- if (value == null) {
- final BaseInjection injection = file.getUserData(BaseInjection.INJECTION_KEY);
- final CachedValueProvider<List<PsiElement>> provider;
- if (injection == null) {
- provider = createDevProvider(file);
- }
- else {
- provider = createPatternProvider(injection, file);
+ final BaseInjection injection = file.getUserData(BaseInjection.INJECTION_KEY);
+ Processor<PsiElement> processor = new Processor<PsiElement>() {
+ @Override
+ public boolean process(PsiElement element) {
+ return element.processDeclarations(scopeProcessor, state, null, place);
}
- if (provider == null) return;
- file.putUserData(INJECTION_PARSED_CONTEXT,
- value = CachedValuesManager.getManager(file.getProject()).createCachedValue(provider, false));
+ };
+ if (injection == null) {
+ processDevContext(file, processor);
}
- final List<PsiElement> roots = value.getValue();
- for (PsiElement root : roots) {
- if (!root.processDeclarations(processor, state, null, place)) return;
+ else {
+ processPatternContext(injection, file, processor);
}
}
- private static CachedValueProvider<List<PsiElement>> createPatternProvider(final BaseInjection injection, final PsiFile file) {
- return new CachedValueProvider<List<PsiElement>>() {
- @Override
- public Result<List<PsiElement>> compute() {
- return new Result<List<PsiElement>>(Collections.<PsiElement>singletonList(
- getRootByClasses(InjectorUtils.getPatternClasses(injection.getSupportId()), file.getProject())),
- ModificationTracker.NEVER_CHANGED);
- }
- };
+ private static boolean processPatternContext(@NotNull BaseInjection injection,
+ @NotNull PsiFile file,
+ @NotNull Processor<PsiElement> processor) {
+ return processor.process(getRootByClasses(file, InjectorUtils.getPatternClasses(injection.getSupportId())));
}
- private static PsiFile getRootByClasses(Class[] classes, Project project) {
- final String text = PatternCompilerFactory.getFactory().getPatternCompiler(classes).dumpContextDeclarations();
- return PsiFileFactory.getInstance(project).createFileFromText("context.groovy", GroovyFileType.GROOVY_FILE_TYPE, text);
+ @NotNull
+ private static PsiFile getRootByClasses(@NotNull PsiFile file, @NotNull Class[] classes) {
+ final Project project = file.getProject();
+ SoftFactoryMap<Class[], PsiFile> map = project.getUserData(PATTERN_INJECTION_CONTEXT);
+ if (map == null) {
+ map = new SoftFactoryMap<Class[], PsiFile>() {
+
+ @Override
+ protected PsiFile create(Class[] key) {
+ String text = PatternCompilerFactory.getFactory().getPatternCompiler(key).dumpContextDeclarations();
+ return PsiFileFactory.getInstance(project).createFileFromText("context.groovy", GroovyFileType.GROOVY_FILE_TYPE, text);
+ }
+ };
+ project.putUserData(PATTERN_INJECTION_CONTEXT, map);
+ }
+ return map.get(classes);
}
- @Nullable
- private static CachedValueProvider<List<PsiElement>> createDevProvider(final PsiFile file) {
+ private static boolean processDevContext(final PsiFile file, Processor<PsiElement> processor) {
final XmlTag tag = getTagByInjectedFile(file);
final XmlTag parentTag = tag == null ? null : tag.getParentTag();
final String parentTagName = parentTag == null ? null : parentTag.getName();
final String name = tag == null ? null : tag.getName();
- if ("place".equals(name) && "injection".equals(parentTagName) && parentTag != null) {
- return new CachedValueProvider<List<PsiElement>>() {
- @Override
- public Result<List<PsiElement>> compute() {
- final XmlTag tag = getTagByInjectedFile(file);
- final XmlTag parentTag = tag == null ? null : tag.getParentTag();
- if (parentTag == null) return Result.create(Collections.<PsiElement>emptyList(), file);
- return new Result<List<PsiElement>>(getRootsByClassNames(file, parentTag.getAttributeValue("injector-id")), parentTag.getContainingFile());
- }
- };
+ if ("place".equals(name) && "injection".equals(parentTagName)) {
+ return processRootsByClassNames(file, parentTag.getAttributeValue("injector-id"), processor);
}
else if ("pattern".equals(name) && parentTag != null) {
- return new CachedValueProvider<List<PsiElement>>() {
- @Override
- public Result<List<PsiElement>> compute() {
- final XmlTag tag = getTagByInjectedFile(file);
- if (tag == null) return Result.create(Collections.<PsiElement>emptyList(), file);
- return new Result<List<PsiElement>>(getRootsByClassNames(file, tag.getAttributeValue("type")), tag.getContainingFile());
- }
- };
+ return processRootsByClassNames(file, tag.getAttributeValue("type"), processor);
}
- else return null;
+ return true;
}
@Nullable
@@ -135,22 +122,48 @@ public class PatternEditorContextMembersProvider extends NonCodeMembersContribut
return element instanceof XmlText ? ((XmlText)element).getParentTag() : null;
}
- private static List<PsiElement> getRootsByClassNames(PsiFile file, String type) {
- final List<PsiElement> roots = ContainerUtil.createLockFreeCopyOnWriteList();
+ private static boolean processRootsByClassNames(@NotNull PsiFile file, @Nullable String type, @NotNull Processor<PsiElement> processor) {
+ Project project = file.getProject();
+ Set<String> classNames = collectDevPatternClassNames(project);
+ if (!classNames.isEmpty()) {
+ JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
+ for (String className : classNames) {
+ PsiClass patternClass = psiFacade.findClass(className, GlobalSearchScope.allScope(project));
+ if (patternClass != null && !processor.process(patternClass)) return false;
+ }
+ }
+ Class[] classes = StringUtil.isEmpty(type) ? ArrayUtil.EMPTY_CLASS_ARRAY : PatternCompilerFactory.getFactory().getPatternClasses(type);
+ return classes.length == 0 || processor.process(getRootByClasses(file, classes));
+ }
+
+ private static Set<String> collectDevPatternClassNames(@NotNull final Project project) {
+ CachedValue<Set<String>> cachedValue = project.getUserData(PATTERN_CLASSES);
+ if (cachedValue == null) {
+ cachedValue = CachedValuesManager.getManager(project).createCachedValue(new CachedValueProvider<Set<String>>() {
+ @Nullable
+ @Override
+ public Result<Set<String>> compute() {
+ return Result.create(calcDevPatternClassNames(project), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
+ }
+ }, false);
+ project.putUserData(PATTERN_CLASSES, cachedValue);
+ }
+ return cachedValue.getValue();
+ }
- final Project project = file.getProject();
- final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
- final PsiClass beanClass = psiFacade.findClass(PatternClassBean.class.getName(), GlobalSearchScope.allScope(project));
+ private static Set<String> calcDevPatternClassNames(@NotNull final Project project) {
+ final List<String> roots = ContainerUtil.createLockFreeCopyOnWriteList();
+ JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
+ PsiClass beanClass = psiFacade.findClass(PatternClassBean.class.getName(), GlobalSearchScope.allScope(project));
if (beanClass != null) {
- final GlobalSearchScope scope =
- GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.allScope(project), StdFileTypes.XML);
+ GlobalSearchScope scope = GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.allScope(project), StdFileTypes.XML);
final TextOccurenceProcessor occurenceProcessor = new TextOccurenceProcessor() {
@Override
public boolean execute(@NotNull PsiElement element, int offsetInElement) {
- final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
- final String className = tag == null ? null : tag.getAttributeValue("className");
- if (className != null && tag.getLocalName().endsWith("patternClass")) {
- ContainerUtil.addIfNotNull(psiFacade.findClass(className, GlobalSearchScope.allScope(project)), roots);
+ XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
+ String className = tag == null ? null : tag.getAttributeValue("className");
+ if (StringUtil.isNotEmpty(className) && tag.getLocalName().endsWith("patternClass")) {
+ roots.add(className);
}
return true;
}
@@ -159,17 +172,13 @@ public class PatternEditorContextMembersProvider extends NonCodeMembersContribut
CacheManager.SERVICE.getInstance(beanClass.getProject()).processFilesWithWord(new Processor<PsiFile>() {
@Override
public boolean process(PsiFile psiFile) {
- LowLevelSearchUtil
- .processElementsContainingWordInElement(occurenceProcessor, psiFile, searcher, true, new EmptyProgressIndicator());
+ LowLevelSearchUtil.processElementsContainingWordInElement(occurenceProcessor, psiFile, searcher, true,
+ new EmptyProgressIndicator());
return true;
}
}, searcher.getPattern(), UsageSearchContext.IN_FOREIGN_LANGUAGES, scope, searcher.isCaseSensitive());
}
- final Class[] classes = PatternCompilerFactory.getFactory().getPatternClasses(type);
- if (classes.length != 0) {
- roots.add(getRootByClasses(classes, project));
- }
- return roots;
+ return ContainerUtil.newHashSet(roots);
}
}