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