@NotNull private Set<PsiFile> getInjectedPsiFiles( @NotNull final List<PsiElement> elements1, @NotNull final List<PsiElement> elements2, @NotNull final ProgressIndicator progress) { ApplicationManager.getApplication().assertReadAccessAllowed(); final Set<PsiFile> outInjected = new THashSet<PsiFile>(); List<DocumentWindow> injected = InjectedLanguageUtil.getCachedInjectedDocuments(myFile); final Collection<PsiElement> hosts = new THashSet<PsiElement>(elements1.size() + elements2.size() + injected.size()); // rehighlight all injected PSI regardless the range, // since change in one place can lead to invalidation of injected PSI in (completely) other // place. for (DocumentWindow documentRange : injected) { progress.checkCanceled(); if (!documentRange.isValid()) continue; PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(documentRange); if (file == null) continue; PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file); if (context != null && context.isValid() && !file.getProject().isDisposed() && (myUpdateAll || myRestrictRange.intersects(context.getTextRange()))) { hosts.add(context); } } InjectedLanguageManagerImpl injectedLanguageManager = InjectedLanguageManagerImpl.getInstanceImpl(myProject); Processor<PsiElement> collectInjectableProcessor = new CommonProcessors.CollectProcessor<PsiElement>(hosts); injectedLanguageManager.processInjectableElements(elements1, collectInjectableProcessor); injectedLanguageManager.processInjectableElements(elements2, collectInjectableProcessor); final PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { @Override public void visit( @NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) { synchronized (outInjected) { outInjected.add(injectedPsi); } } }; if (!JobLauncher.getInstance() .invokeConcurrentlyUnderProgress( new ArrayList<PsiElement>(hosts), progress, true, new Processor<PsiElement>() { @Override public boolean process(PsiElement element) { ApplicationManager.getApplication().assertReadAccessAllowed(); progress.checkCanceled(); InjectedLanguageUtil.enumerate(element, myFile, false, visitor); return true; } })) { throw new ProcessCanceledException(); } synchronized (outInjected) { return outInjected; } }
private static MultiHostRegistrarImpl probeElementsUp( @NotNull PsiElement element, @NotNull PsiFile hostPsiFile, boolean probeUp) { PsiManager psiManager = hostPsiFile.getManager(); final Project project = psiManager.getProject(); InjectedLanguageManagerImpl injectedManager = InjectedLanguageManagerImpl.getInstanceImpl(project); if (injectedManager == null) { return null; // for tests } MultiHostRegistrarImpl registrar = null; PsiElement current = element; nextParent: while (current != null && current != hostPsiFile) { ProgressManager.checkCanceled(); if ("EL".equals(current.getLanguage().getID())) break; ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement> data = current.getUserData(INJECTED_PSI); if (data == null) { registrar = InjectedPsiCachedValueProvider.doCompute( current, injectedManager, project, hostPsiFile); } else { registrar = data.getValue(current); } current = current.getParent(); // cache no injection for current if (registrar != null) { List<Pair<Place, PsiFile>> places = registrar.getResult(); // check that injections found intersect with queried element TextRange elementRange = element.getTextRange(); for (Pair<Place, PsiFile> pair : places) { Place place = pair.first; for (PsiLanguageInjectionHost.Shred shred : place) { if (shred.getHost().getTextRange().intersects(elementRange)) { if (place.isValid()) break nextParent; } } } } if (!probeUp) { break; } } if (probeUp) { // cache only if we walked all parents for (PsiElement e = element; e != current && e != null && e != hostPsiFile; e = e.getParent()) { ProgressManager.checkCanceled(); if (registrar == null) { e.putUserData(INJECTED_PSI, null); } else { ParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement> cachedValue = CachedValuesManager.getManager(project) .createParameterizedCachedValue(INJECTED_PSI_PROVIDER, false); CachedValueProvider.Result<MultiHostRegistrarImpl> result = CachedValueProvider.Result.create( registrar, PsiModificationTracker.MODIFICATION_COUNT, registrar); ((PsiParameterizedCachedValue<MultiHostRegistrarImpl, PsiElement>) cachedValue) .setValue(result); e.putUserData(INJECTED_PSI, cachedValue); } } } return registrar; }