diff options
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.java | 161 |
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); } } |