SSR: remove debug output
[idea/community.git] / platform / structuralsearch / source / com / intellij / structuralsearch / impl / matcher / MatcherImpl.java
1 package com.intellij.structuralsearch.impl.matcher;
2
3 import com.intellij.dupLocator.iterators.ArrayBackedNodeIterator;
4 import com.intellij.dupLocator.iterators.NodeIterator;
5 import com.intellij.lang.Language;
6 import com.intellij.lang.StdLanguages;
7 import com.intellij.openapi.application.ApplicationManager;
8 import com.intellij.openapi.application.ModalityState;
9 import com.intellij.openapi.diagnostic.Logger;
10 import com.intellij.openapi.editor.Document;
11 import com.intellij.openapi.fileTypes.FileType;
12 import com.intellij.openapi.fileTypes.FileTypes;
13 import com.intellij.openapi.fileTypes.LanguageFileType;
14 import com.intellij.openapi.progress.ProcessCanceledException;
15 import com.intellij.openapi.progress.ProgressIndicator;
16 import com.intellij.openapi.project.Project;
17 import com.intellij.openapi.roots.ContentIterator;
18 import com.intellij.openapi.util.Computable;
19 import com.intellij.openapi.util.Pair;
20 import com.intellij.openapi.vfs.VirtualFile;
21 import com.intellij.psi.*;
22 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
23 import com.intellij.psi.search.GlobalSearchScope;
24 import com.intellij.psi.search.LocalSearchScope;
25 import com.intellij.psi.search.SearchScope;
26 import com.intellij.structuralsearch.*;
27 import com.intellij.structuralsearch.impl.matcher.compiler.PatternCompiler;
28 import com.intellij.structuralsearch.impl.matcher.handlers.MatchingHandler;
29 import com.intellij.structuralsearch.impl.matcher.handlers.TopLevelMatchingHandler;
30 import com.intellij.structuralsearch.impl.matcher.iterators.SsrFilteringNodeIterator;
31 import com.intellij.structuralsearch.impl.matcher.strategies.MatchingStrategy;
32 import com.intellij.structuralsearch.plugin.ui.Configuration;
33 import com.intellij.structuralsearch.plugin.util.CollectingMatchResultSink;
34 import com.intellij.structuralsearch.plugin.util.DuplicateFilteringResultSink;
35 import com.intellij.util.IncorrectOperationException;
36 import com.intellij.util.PairProcessor;
37 import com.intellij.util.SmartList;
38 import com.intellij.util.indexing.FileBasedIndex;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
41
42 import java.lang.ref.SoftReference;
43 import java.util.ArrayList;
44 import java.util.Collections;
45 import java.util.LinkedList;
46 import java.util.List;
47
48 /**
49  * This class makes program structure tree matching:
50  */
51 public class MatcherImpl {
52   private static final Logger LOG = Logger.getInstance("#com.intellij.structuralsearch.impl.matcher.MatcherImpl");
53   // project being worked on
54   private final Project project;
55
56   // context of matching
57   private final MatchContext matchContext;
58   private boolean isTesting;
59
60   // visitor to delegate the real work
61   private final GlobalMatchingVisitor visitor = new GlobalMatchingVisitor();
62   private ProgressIndicator progress;
63   private final TaskScheduler scheduler = new TaskScheduler();
64
65   private int totalFilesToScan;
66   private int scannedFilesCount;
67
68   public MatcherImpl(final Project project, final MatchOptions matchOptions) {
69     this.project = project;
70     matchContext = new MatchContext();
71     matchContext.setMatcher(visitor);
72
73     if (matchOptions != null) {
74       matchContext.setOptions(matchOptions);
75       cacheCompiledPattern(matchOptions, PatternCompiler.compilePattern(project,matchOptions));
76     }
77   }
78
79   static class LastMatchData {
80     CompiledPattern lastPattern;
81     MatchOptions lastOptions;
82   }
83
84   private static SoftReference<LastMatchData> lastMatchData;
85
86   protected MatcherImpl(Project project) {
87     this(project, null);
88   }
89
90   public static void validate(Project project, MatchOptions options) {
91     synchronized(MatcherImpl.class) {
92       final LastMatchData data = new LastMatchData();
93       data.lastPattern =  PatternCompiler.compilePattern(project, options);
94       data.lastOptions = options;
95       lastMatchData = new SoftReference<LastMatchData>(data);
96     }
97
98     final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByFileType(options.getFileType());
99     profile.checkSearchPattern(project, options);
100   }
101
102   public static class CompiledOptions {
103     public final List<Pair<MatchContext, Configuration>> matchContexts;
104
105     public CompiledOptions(final List<Pair<MatchContext, Configuration>> matchContexts) {
106       this.matchContexts = matchContexts;
107     }
108
109     public List<Pair<MatchContext, Configuration>> getMatchContexts() {
110       return matchContexts;
111     }
112   }
113
114   public static boolean checkIfShouldAttemptToMatch(MatchContext context, NodeIterator matchedNodes) {
115     final CompiledPattern pattern = context.getPattern();
116     final NodeIterator patternNodes = pattern.getNodes();
117     try {
118       while (true) {
119         final PsiElement patternNode = patternNodes.current();
120         if (patternNode == null) {
121           return true;
122         }
123         final PsiElement matchedNode = matchedNodes.current();
124         if (matchedNode == null) {
125           return false;
126         }
127         final MatchingHandler matchingHandler = pattern.getHandler(patternNode);
128         if (matchingHandler == null || !matchingHandler.canMatch(patternNode, matchedNode)) {
129           return false;
130         }
131         matchedNodes.advance();
132         patternNodes.advance();
133       }
134     } finally {
135       patternNodes.reset();
136       matchedNodes.reset();
137     }
138   }
139
140   public void processMatchesInElement(MatchContext context, Configuration configuration,
141                                       NodeIterator matchedNodes,
142                                       PairProcessor<MatchResult, Configuration> processor) {
143     try {
144       configureOptions(context, configuration, matchedNodes.current(), processor);
145       context.setShouldRecursivelyMatch(false);
146       visitor.matchContext(matchedNodes);
147     } finally {
148       matchedNodes.reset();
149       context.getOptions().setScope(null);
150     }
151   }
152
153   public void clearContext() {
154     matchContext.clear();
155   }
156
157   private void configureOptions(MatchContext context,
158                                 final Configuration configuration,
159                                 PsiElement psiFile,
160                                 final PairProcessor<MatchResult, Configuration> processor) {
161     if (psiFile == null) return;
162     LocalSearchScope scope = new LocalSearchScope(psiFile);
163
164     matchContext.clear();
165     matchContext.setMatcher(visitor);
166
167     MatchOptions options = context.getOptions();
168     matchContext.setOptions(options);
169     matchContext.setPattern(context.getPattern());
170     matchContext.setShouldRecursivelyMatch(context.shouldRecursivelyMatch());
171     visitor.setMatchContext(matchContext);
172
173     matchContext.setSink(
174       new DuplicateFilteringResultSink(
175         new MatchResultSink() {
176           public void newMatch(MatchResult result) {
177             processor.process(result, configuration);
178           }
179
180           public void processFile(PsiFile element) {
181           }
182
183           public void setMatchingProcess(MatchingProcess matchingProcess) {
184           }
185
186           public void matchingFinished() {
187           }
188
189           public ProgressIndicator getProgressIndicator() {
190             return null;
191           }
192         }
193       )
194     );
195     options.setScope(scope);
196   }
197
198   public CompiledOptions precompileOptions(List<Configuration> configurations) {
199     final List<Pair<MatchContext, Configuration>> contexts = new ArrayList<Pair<MatchContext, Configuration>>();
200
201     for (final Configuration configuration : configurations) {
202       final MatchContext matchContext = new MatchContext();
203       matchContext.setMatcher(visitor);
204       final MatchOptions matchOptions = configuration.getMatchOptions();
205       matchContext.setOptions(matchOptions);
206
207       ApplicationManager.getApplication().runReadAction(new Runnable() {
208         @Override
209         public void run() {
210           try {
211             CompiledPattern compiledPattern = PatternCompiler.compilePattern(project, matchOptions);
212             matchContext.setPattern(compiledPattern);
213             contexts.add(Pair.create(matchContext, configuration));
214           }
215           catch (UnsupportedPatternException ignored) {}
216           catch (MalformedPatternException ignored) {}
217         }
218       });
219     }
220     return new CompiledOptions(contexts);
221   }
222
223   Project getProject() {
224     return project;
225   }
226
227   /**
228    * Finds the matches of given pattern starting from given tree element.
229    * @throws MalformedPatternException
230    * @throws UnsupportedPatternException
231    */
232   protected void findMatches(MatchResultSink sink, final MatchOptions options) throws MalformedPatternException, UnsupportedPatternException
233   {
234     CompiledPattern compiledPattern = prepareMatching(sink, options);
235     if (compiledPattern== null) {
236       return;
237     }
238
239     matchContext.getSink().setMatchingProcess( scheduler );
240     scheduler.init();
241     progress = matchContext.getSink().getProgressIndicator();
242
243     if (/*TokenBasedSearcher.canProcess(compiledPattern)*/ false) {
244       //TokenBasedSearcher searcher = new TokenBasedSearcher(this);
245       //searcher.search(compiledPattern);
246       if (isTesting) {
247         matchContext.getSink().matchingFinished();
248         return;
249       }
250     }
251     else {
252       if (isTesting) {
253         // testing mode;
254         final PsiElement[] elements = ((LocalSearchScope)options.getScope()).getScope();
255
256         PsiElement parent = elements[0].getParent();
257         if (elements.length > 0 && matchContext.getPattern().getStrategy().continueMatching(parent != null ? parent : elements[0])) {
258           visitor.matchContext(new SsrFilteringNodeIterator(new ArrayBackedNodeIterator(elements)));
259         }
260         else {
261           for (PsiElement element : elements) {
262             match(element);
263           }
264         }
265
266         matchContext.getSink().matchingFinished();
267         return;
268       }
269       if (!findMatches(options, compiledPattern)) {
270         return;
271       }
272     }
273
274     if (scheduler.getTaskQueueEndAction()==null) {
275       scheduler.setTaskQueueEndAction(
276         new Runnable() {
277           public void run() {
278             matchContext.getSink().matchingFinished();
279           }
280         }
281       );
282     }
283
284     scheduler.executeNext();
285   }
286
287   private boolean findMatches(MatchOptions options, CompiledPattern compiledPattern) {
288     LanguageFileType languageFileType = (LanguageFileType)options.getFileType();
289     final Language patternLanguage = languageFileType.getLanguage();
290     final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByLanguage(patternLanguage);
291     assert profile != null;
292     final Language patternLanguage2 = patternLanguage == StdLanguages.XML ? StdLanguages.XHTML:null;
293     SearchScope searchScope = compiledPattern.getScope();
294     boolean ourOptimizedScope = searchScope != null;
295     if (!ourOptimizedScope) searchScope = options.getScope();
296
297     if (searchScope instanceof GlobalSearchScope) {
298       final GlobalSearchScope scope = (GlobalSearchScope)searchScope;
299
300       final ContentIterator ci = new ContentIterator() {
301         public boolean processFile(final VirtualFile fileOrDir) {
302           if (!fileOrDir.isDirectory() && scope.contains(fileOrDir) && fileOrDir.getFileType() != FileTypes.UNKNOWN) {
303             ++totalFilesToScan;
304             scheduler.addOneTask(new MatchOneVirtualFile(fileOrDir, profile, patternLanguage, patternLanguage2));
305           }
306           return true;
307         }
308       };
309
310       ApplicationManager.getApplication().runReadAction(new Runnable() {
311         @Override
312         public void run() {
313           FileBasedIndex.getInstance().iterateIndexableFiles(ci, project, progress);
314         }
315       });
316       progress.setText2("");
317     }
318     else {
319       final PsiElement[] elementsToScan = ((LocalSearchScope)searchScope).getScope();
320       totalFilesToScan = elementsToScan.length;
321
322       for (int i = 0; i < elementsToScan.length; ++i) {
323         final PsiElement psiElement = elementsToScan[i];
324
325         if (psiElement == null) continue;
326         final Language language = psiElement.getLanguage();
327
328         PsiFile file = psiElement instanceof PsiFile ? (PsiFile)psiElement : psiElement.getContainingFile();
329
330         if (profile.isMyFile(file, language, patternLanguage, patternLanguage2)) {
331           scheduler.addOneTask(new MatchOnePsiFile(psiElement));
332         }
333         if (ourOptimizedScope) elementsToScan[i] = null; // to prevent long PsiElement reference
334       }
335     }
336     return true;
337   }
338
339   private CompiledPattern prepareMatching(final MatchResultSink sink, final MatchOptions options) {
340     CompiledPattern savedPattern = null;
341
342     if (matchContext.getOptions() == options && matchContext.getPattern() != null &&
343         matchContext.getOptions().hashCode() == matchContext.getPattern().getOptionsHashStamp()) {
344       savedPattern = matchContext.getPattern();
345     }
346
347     matchContext.clear();
348     matchContext.setSink(new DuplicateFilteringResultSink(sink));
349     matchContext.setOptions(options);
350     matchContext.setMatcher(visitor);
351     visitor.setMatchContext(matchContext);
352
353     CompiledPattern compiledPattern = savedPattern;
354
355     if (compiledPattern == null) {
356
357       synchronized(getClass()) {
358         final LastMatchData data = com.intellij.reference.SoftReference.dereference(lastMatchData);
359         if (data != null && options == data.lastOptions) {
360           compiledPattern = data.lastPattern;
361         }
362         lastMatchData = null;
363       }
364
365       if (compiledPattern==null) {
366         compiledPattern = ApplicationManager.getApplication().runReadAction(new Computable<CompiledPattern>() {
367           @Override
368           public CompiledPattern compute() {
369             return PatternCompiler.compilePattern(project,options);
370           }
371         });
372       }
373     }
374
375     cacheCompiledPattern(options, compiledPattern);
376     return compiledPattern;
377   }
378
379   private void cacheCompiledPattern(final MatchOptions options, final CompiledPattern compiledPattern) {
380     matchContext.setPattern(compiledPattern);
381     compiledPattern.setOptionsHashStamp(options.hashCode());
382   }
383
384   /**
385    * Finds the matches of given pattern starting from given tree element.
386    * @param sink match result destination
387    * @throws MalformedPatternException
388    * @throws UnsupportedPatternException
389    */
390   protected void testFindMatches(MatchResultSink sink, MatchOptions options)
391     throws MalformedPatternException, UnsupportedPatternException {
392     isTesting = true;
393     try {
394       findMatches(sink,options);
395     } finally {
396       isTesting = false;
397     }
398   }
399
400   /**
401    * Finds the matches of given pattern starting from given tree element.
402    * @param source string for search
403    * @param pattern to be searched
404    * @return list of matches found
405    * @throws MalformedPatternException
406    * @throws UnsupportedPatternException
407    */
408   protected List<MatchResult> testFindMatches(String source,
409                                               String pattern,
410                                               MatchOptions options,
411                                               boolean filePattern,
412                                               FileType sourceFileType,
413                                               String sourceExtension,
414                                               boolean physicalSourceFile)
415     throws MalformedPatternException, UnsupportedPatternException {
416
417     CollectingMatchResultSink sink = new CollectingMatchResultSink();
418
419     try {
420       PsiElement[] elements = MatcherImplUtil.createSourceTreeFromText(source,
421                                                                        filePattern ? PatternTreeContext.File : PatternTreeContext.Block,
422                                                                        sourceFileType,
423                                                                        sourceExtension,
424                                                                        project, physicalSourceFile);
425
426       options.setSearchPattern(pattern);
427       options.setScope(new LocalSearchScope(elements));
428       testFindMatches(sink, options);
429     }
430     catch (IncorrectOperationException e) {
431       MalformedPatternException exception = new MalformedPatternException();
432       exception.initCause(e);
433       throw exception;
434     } finally {
435       options.setScope(null);
436     }
437
438     return sink.getMatches();
439   }
440
441   protected List<MatchResult> testFindMatches(String source, String pattern, MatchOptions options, boolean filePattern) {
442     return testFindMatches(source, pattern, options, filePattern, options.getFileType(), null, false);
443   }
444
445   class TaskScheduler implements MatchingProcess {
446     private LinkedList<Runnable> tasks = new LinkedList<Runnable>();
447     private boolean ended;
448     private Runnable taskQueueEndAction;
449
450     private boolean suspended;
451
452     public void stop() {
453       ended = true;
454     }
455
456     public void pause() {
457       suspended = true;
458     }
459
460     public void resume() {
461       if (!suspended) return;
462       suspended = false;
463       executeNext();
464     }
465
466     public boolean isSuspended() {
467       return suspended;
468     }
469
470     public boolean isEnded() {
471       return ended;
472     }
473
474     void setTaskQueueEndAction(Runnable taskQueueEndAction) {
475       this.taskQueueEndAction = taskQueueEndAction;
476     }
477     Runnable getTaskQueueEndAction () {
478       return taskQueueEndAction;
479     }
480
481     void addOneTask(Runnable runnable) {
482       tasks.add(runnable);
483     }
484
485     private void executeNext() {
486       while(!suspended && !ended) {
487         if (tasks.isEmpty()) {
488           ended = true;
489           break;
490         }
491
492         final Runnable task = tasks.removeFirst();
493         try {
494           task.run();
495         }
496         catch (ProcessCanceledException e) {
497           ended = true;
498           clearSchedule();
499           throw e;
500         }
501         catch (StructuralSearchException e) {
502           ended = true;
503           clearSchedule();
504           throw e;
505         }
506         catch (Throwable th) {
507           LOG.error(th);
508         }
509       }
510
511       if (ended) clearSchedule();
512     }
513
514     private void init() {
515       ended = false;
516       suspended = false;
517       PsiManager.getInstance(project).startBatchFilesProcessingMode();
518     }
519
520     private void clearSchedule() {
521       if (tasks != null) {
522         taskQueueEndAction.run();
523         if (!project.isDisposed()) {
524           PsiManager.getInstance(project).finishBatchFilesProcessingMode();
525         }
526         tasks = null;
527       }
528     }
529
530   }
531
532   private class MatchOnePsiFile extends MatchOneFile {
533     private PsiElement file;
534
535     MatchOnePsiFile(PsiElement file) {
536       this.file = file;
537     }
538
539     @Nullable
540     @Override
541     protected List<PsiElement> getPsiElementsToProcess() {
542       PsiElement file = this.file;
543       this.file = null;
544       return new SmartList<PsiElement>(file);
545     }
546   }
547
548   private abstract class MatchOneFile implements Runnable {
549     public void run() {
550       List<PsiElement> files = getPsiElementsToProcess();
551
552       if (progress!=null) {
553         progress.setFraction((double)scannedFilesCount/totalFilesToScan);
554       }
555
556       ++scannedFilesCount;
557
558       if (files == null || files.size() == 0) return;
559       final PsiFile psiFile = files.get(0).getContainingFile();
560
561       if (psiFile!=null) {
562         final Runnable action = new Runnable() {
563           public void run() {
564             ApplicationManager.getApplication().runWriteAction(new Runnable() {
565               public void run() {
566                 if (project.isDisposed()) return;
567                 final PsiDocumentManager manager = PsiDocumentManager.getInstance(project);
568                 Document document = manager.getDocument(psiFile);
569                 if (document != null) manager.commitDocument(document);
570               }
571             });
572           }
573         };
574
575         if (ApplicationManager.getApplication().isDispatchThread()) {
576           action.run();
577         } else {
578           ApplicationManager.getApplication().invokeAndWait(
579             action,
580             ModalityState.defaultModalityState()
581           );
582         }
583       }
584
585       if (project.isDisposed()) return;
586
587       for(PsiElement file:files) {
588         if (file instanceof PsiFile) {
589           matchContext.getSink().processFile((PsiFile)file);
590         }
591
592         final PsiElement finalFile = file;
593         ApplicationManager.getApplication().runReadAction(
594           new Runnable() {
595             public void run() {
596               PsiElement file = finalFile;
597               if (!file.isValid()) return;
598               file = StructuralSearchUtil.getProfileByLanguage(file.getLanguage()).extendMatchOnePsiFile(file);
599               match(file);
600             }
601           }
602         );
603       }
604     }
605
606     protected abstract @Nullable List<PsiElement> getPsiElementsToProcess();
607   }
608
609   // Initiates the matching process for given element
610   // @param element the current search tree element
611   public void match(PsiElement element) {
612     MatchingStrategy strategy = matchContext.getPattern().getStrategy();
613
614     if (strategy.continueMatching(element)) {
615       visitor.matchContext(new ArrayBackedNodeIterator(new PsiElement[] {element}));
616       return;
617     }
618     for(PsiElement el=element.getFirstChild();el!=null;el=el.getNextSibling()) {
619       match(el);
620     }
621     if (element instanceof PsiLanguageInjectionHost) {
622       InjectedLanguageUtil.enumerate(element, new PsiLanguageInjectionHost.InjectedPsiVisitor() {
623         @Override
624         public void visit(@NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) {
625           match(injectedPsi);
626         }
627       });
628     }
629   }
630
631   @NotNull
632   protected List<MatchResult> matchByDownUp(PsiElement element, final MatchOptions options) {
633     final CollectingMatchResultSink sink = new CollectingMatchResultSink();
634     final CompiledPattern compiledPattern = prepareMatching(sink, options);
635     matchContext.setShouldRecursivelyMatch(false);
636
637     PsiElement targetNode = compiledPattern.getTargetNode();
638     PsiElement elementToStartMatching = null;
639
640     if (targetNode == null) {
641       targetNode = compiledPattern.getNodes().current();
642       if (targetNode != null) {
643         compiledPattern.getNodes().advance();
644         assert !compiledPattern.getNodes().hasNext();
645         compiledPattern.getNodes().rewind();
646
647         element = element.getParent();
648         if (element == null) {
649           return Collections.emptyList();
650         }
651         while (element.getClass() != targetNode.getClass()) {
652           element = element.getParent();
653           if (element == null)  return Collections.emptyList();
654         }
655
656         elementToStartMatching = element;
657       }
658     } else {
659       final StructuralSearchProfile profile = StructuralSearchUtil.getProfileByPsiElement(element);
660       if (profile == null) return Collections.emptyList();
661       targetNode = profile.extendMatchedByDownUp(targetNode);
662
663       MatchingHandler handler = null;
664
665       while (element.getClass() == targetNode.getClass() ||
666              compiledPattern.isTypedVar(targetNode) && compiledPattern.getHandler(targetNode).canMatch(targetNode, element)) {
667         handler = compiledPattern.getHandler(targetNode);
668         handler.setPinnedElement(element);
669         elementToStartMatching = element;
670         if (handler instanceof TopLevelMatchingHandler) break;
671         element = element.getParent();
672         targetNode = targetNode.getParent();
673
674         if (options.isLooseMatching()) {
675           element = profile.updateCurrentNode(element);
676           targetNode = profile.updateCurrentNode(targetNode);
677         }
678       }
679
680       if (!(handler instanceof TopLevelMatchingHandler)) return Collections.emptyList();
681     }
682
683     assert targetNode != null : "Could not match down up when no target node";
684
685     match(elementToStartMatching);
686     matchContext.getSink().matchingFinished();
687     return sink.getMatches();
688   }
689
690   private class MatchOneVirtualFile extends MatchOneFile {
691     private final VirtualFile myFileOrDir;
692     private final StructuralSearchProfile myProfile;
693     private final Language myOurPatternLanguage;
694     private final Language myOurPatternLanguage2;
695
696     public MatchOneVirtualFile(VirtualFile fileOrDir,
697                                StructuralSearchProfile profile,
698                                Language ourPatternLanguage,
699                                Language ourPatternLanguage2) {
700       myFileOrDir = fileOrDir;
701       myProfile = profile;
702       myOurPatternLanguage = ourPatternLanguage;
703       myOurPatternLanguage2 = ourPatternLanguage2;
704     }
705
706     @Nullable
707     @Override
708     protected List<PsiElement> getPsiElementsToProcess() {
709       return ApplicationManager.getApplication().runReadAction(new Computable<List<PsiElement>>() {
710         @Override
711         public List<PsiElement> compute() {
712           PsiFile file = PsiManager.getInstance(project).findFile(myFileOrDir);
713           if (file == null) {
714             return null;
715           }
716
717           final FileViewProvider viewProvider = file.getViewProvider();
718           List<PsiElement> elementsToProcess = new SmartList<PsiElement>();
719
720           for(Language lang: viewProvider.getLanguages()) {
721             if (myProfile.isMyFile(file, lang, myOurPatternLanguage, myOurPatternLanguage2)) {
722               elementsToProcess.add(viewProvider.getPsi(lang));
723             }
724           }
725
726           return elementsToProcess;
727         }
728       });
729     }
730   }
731 }