@Override public synchronized int registerTextEditorHighlightingPass( @NotNull TextEditorHighlightingPassFactory factory, @Nullable int[] runAfterCompletionOf, @Nullable int[] runAfterOfStartingOf, boolean runIntentionsPassAfter, int forcedPassId) { assert !checkedForCycles; PassConfig info = new PassConfig( factory, runAfterCompletionOf == null || runAfterCompletionOf.length == 0 ? ArrayUtil.EMPTY_INT_ARRAY : runAfterCompletionOf, runAfterOfStartingOf == null || runAfterOfStartingOf.length == 0 ? ArrayUtil.EMPTY_INT_ARRAY : runAfterOfStartingOf); int passId = forcedPassId == -1 ? nextAvailableId++ : forcedPassId; PassConfig registered = myRegisteredPassFactories.get(passId); assert registered == null : "Pass id " + passId + " has already been registered in: " + registered.passFactory; myRegisteredPassFactories.put(passId, info); if (factory instanceof DirtyScopeTrackingHighlightingPassFactory) { myDirtyScopeTrackingFactories.add((DirtyScopeTrackingHighlightingPassFactory) factory); } return passId; }
private void checkForCycles() { final TIntObjectHashMap<TIntHashSet> transitivePredecessors = new TIntObjectHashMap<TIntHashSet>(); myRegisteredPassFactories.forEachEntry( new TIntObjectProcedure<PassConfig>() { @Override public boolean execute(int passId, PassConfig config) { TIntHashSet allPredecessors = new TIntHashSet(config.completionPredecessorIds); allPredecessors.addAll(config.startingPredecessorIds); transitivePredecessors.put(passId, allPredecessors); allPredecessors.forEach( new TIntProcedure() { @Override public boolean execute(int predecessorId) { PassConfig predecessor = myRegisteredPassFactories.get(predecessorId); if (predecessor == null) return true; TIntHashSet transitives = transitivePredecessors.get(predecessorId); if (transitives == null) { transitives = new TIntHashSet(); transitivePredecessors.put(predecessorId, transitives); } transitives.addAll(predecessor.completionPredecessorIds); transitives.addAll(predecessor.startingPredecessorIds); return true; } }); return true; } }); transitivePredecessors.forEachKey( new TIntProcedure() { @Override public boolean execute(int passId) { if (transitivePredecessors.get(passId).contains(passId)) { throw new IllegalArgumentException( "There is a cycle introduced involving pass " + myRegisteredPassFactories.get(passId).passFactory); } return true; } }); }
@NotNull @Override public List<TextEditorHighlightingPass> instantiateMainPasses( @NotNull final PsiFile psiFile, @NotNull final Document document) { final THashSet<TextEditorHighlightingPass> ids = new THashSet<TextEditorHighlightingPass>(); myRegisteredPassFactories.forEachKey( new TIntProcedure() { @Override public boolean execute(int passId) { PassConfig passConfig = myRegisteredPassFactories.get(passId); TextEditorHighlightingPassFactory factory = passConfig.passFactory; if (factory instanceof MainHighlightingPassFactory) { final TextEditorHighlightingPass pass = ((MainHighlightingPassFactory) factory) .createMainHighlightingPass(psiFile, document); if (pass != null) { ids.add(pass); } } return true; } }); return new ArrayList<TextEditorHighlightingPass>(ids); }
@Override @NotNull public List<TextEditorHighlightingPass> instantiatePasses( @NotNull final PsiFile psiFile, @NotNull final Editor editor, @NotNull final int[] passesToIgnore) { synchronized (this) { if (!checkedForCycles) { checkedForCycles = true; checkForCycles(); } } PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); final Document document = editor.getDocument(); PsiFile fileFromDoc = documentManager.getPsiFile(document); if (!(fileFromDoc instanceof PsiCompiledElement)) { assert fileFromDoc == psiFile : "Files are different: " + psiFile + ";" + fileFromDoc; Document documentFromFile = documentManager.getDocument(psiFile); assert documentFromFile == document : "Documents are different. Doc: " + document + "; Doc from file: " + documentFromFile + "; File: " + psiFile + "; Virtual file: " + PsiUtilCore.getVirtualFile(psiFile); } final TIntObjectHashMap<TextEditorHighlightingPass> id2Pass = new TIntObjectHashMap<TextEditorHighlightingPass>(); final TIntArrayList passesRefusedToCreate = new TIntArrayList(); myRegisteredPassFactories.forEachKey( new TIntProcedure() { @Override public boolean execute(int passId) { if (ArrayUtil.find(passesToIgnore, passId) != -1) { return true; } PassConfig passConfig = myRegisteredPassFactories.get(passId); TextEditorHighlightingPassFactory factory = passConfig.passFactory; final TextEditorHighlightingPass pass = factory.createHighlightingPass(psiFile, editor); if (pass == null) { passesRefusedToCreate.add(passId); } else { // init with editor's colors scheme pass.setColorsScheme(editor.getColorsScheme()); TIntArrayList ids = new TIntArrayList(passConfig.completionPredecessorIds.length); for (int id : passConfig.completionPredecessorIds) { if (myRegisteredPassFactories.containsKey(id)) ids.add(id); } pass.setCompletionPredecessorIds( ids.isEmpty() ? ArrayUtil.EMPTY_INT_ARRAY : ids.toNativeArray()); ids = new TIntArrayList(passConfig.startingPredecessorIds.length); for (int id : passConfig.startingPredecessorIds) { if (myRegisteredPassFactories.containsKey(id)) ids.add(id); } pass.setStartingPredecessorIds( ids.isEmpty() ? ArrayUtil.EMPTY_INT_ARRAY : ids.toNativeArray()); pass.setId(passId); id2Pass.put(passId, pass); } return true; } }); DaemonCodeAnalyzerEx daemonCodeAnalyzer = DaemonCodeAnalyzerEx.getInstanceEx(myProject); final FileStatusMap statusMap = daemonCodeAnalyzer.getFileStatusMap(); passesRefusedToCreate.forEach( new TIntProcedure() { @Override public boolean execute(int passId) { statusMap.markFileUpToDate(document, passId); return true; } }); return (List) Arrays.asList(id2Pass.getValues()); }