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