void (@NotNull AnalysisScope scope, boolean runGlobalToolsOnly, boolean isOfflineInspections) { IJTracer tracer = TelemetryManager.getInstance().getTracer(GlobalInspectionScope); runToolsSpan = tracer.spanBuilder("globalInspections").setNoParent().startSpan(); myInspectionStartedTimestamp = System.currentTimeMillis(); ProgressIndicator progressIndicator = ProgressIndicatorProvider.getGlobalProgressIndicator(); if (!(progressIndicator instanceof ProgressIndicatorWithDelayedPresentation)) { throw new IncorrectOperationException("Must be run under ProgressWindow"); } if (!isOfflineInspections) { ApplicationManager.getApplication().assertIsNonDispatchThread(); } if (ApplicationManager.getApplication().isWriteAccessAllowed()) { throw new IncorrectOperationException("Must not start inspections from within write action"); } // in offline inspection application we don't care about global read action if (!isOfflineInspections && ApplicationManager.getApplication().isReadAccessAllowed()) { throw new IncorrectOperationException("Must not start inspections from within global read action"); } InspectionManager inspectionManager = InspectionManager.getInstance(getProject()); ((RefManagerImpl)getRefManager()).initializeAnnotators(); List<Tools> globalTools = new ArrayList<>(); List<Tools> localTools = new ArrayList<>(); List<Tools> globalSimpleTools = new ArrayList<>(); initializeTools(globalTools, localTools, globalSimpleTools); appendPairedInspectionsForUnfairTools(globalTools, globalSimpleTools, localTools); runGlobalTools(scope, inspectionManager, globalTools, isOfflineInspections); TraceUtil.runWithSpanThrows(tracer, "externalInspectionsAnalysis", (__) -> { runExternalTools(); }); if (runGlobalToolsOnly || localTools.isEmpty() && globalSimpleTools.isEmpty()) return; SearchScope searchScope = ReadAction.compute(scope::toSearchScope); Set<VirtualFile> localScopeFiles = searchScope instanceof LocalSearchScope ? new HashSet<>() : null; for (Tools tools : globalSimpleTools) { GlobalInspectionToolWrapper toolWrapper = (GlobalInspectionToolWrapper)tools.getTool(); GlobalSimpleInspectionTool tool = (GlobalSimpleInspectionTool)toolWrapper.getTool(); tool.inspectionStarted(inspectionManager, this, getPresentation(toolWrapper)); } boolean headlessEnvironment = ApplicationManager.getApplication().isHeadlessEnvironment(); Map<String, InspectionToolWrapper<?, ?>> map = getInspectionWrappersMap(localTools); BlockingQueue<VirtualFile> filesToInspect = new ArrayBlockingQueue<>(1000); // use original progress indicator here since we don't want it to cancel on write action start ProgressIndicator fileScanningIndicator = new SensitiveProgressWrapper(progressIndicator); Future<?> future = startIterateScopeInBackground(scope, fileScanningIndicator, headlessEnvironment, localScopeFiles, filesToInspect); var enabledInspectionsProvider = createEnabledInspectionsProvider(localTools, globalSimpleTools, getProject()); Processor<VirtualFile> processor = buildProcessor(scope, enabledInspectionsProvider, searchScope, inspectionManager, map); var localInspectionsSpan = tracer.spanBuilder("localInspectionsAnalysis").startSpan(); try { Queue<VirtualFile> filesFailedToInspect = new LinkedBlockingQueue<>(); while (true) { Disposable disposable = Disposer.newDisposable(); ProgressIndicator wrapper = new DaemonProgressIndicator(); dependentIndicators.add(wrapper); try { setupCancelOnWriteProgress(disposable, wrapper); // use wrapper here to cancel early when write action start but do not affect the original indicator ((JobLauncherImpl)JobLauncher.getInstance()).processQueue(filesToInspect, filesFailedToInspect, wrapper, TOMBSTONE, processor); break; } catch (ProcessCanceledException e) { progressIndicator.checkCanceled(); // PCE may be thrown from inside wrapper when write action started. // Go on with the write action and then resume processing the rest of the queue. if (!isOfflineInspections) { ApplicationManager.getApplication().assertReadAccessNotAllowed(); ApplicationManager.getApplication().assertIsNonDispatchThread(); } // wait for write action to complete ApplicationManager.getApplication().runReadAction(EmptyRunnable.getInstance()); } finally { dependentIndicators.remove(wrapper); Disposer.dispose(disposable); } } } finally { fileScanningIndicator.cancel(); // tell file scanning thread to stop filesToInspect.clear(); // let file scanning thread a chance to put TOMBSTONE and complete try { future.get(30, TimeUnit.SECONDS); } catch (Exception e) { LOG.error("Thread dump: \n" + ThreadDumper.dumpThreadsToString(), e); } localInspectionsSpan.end(); } ProgressManager.checkCanceled(); for (Tools tools : globalSimpleTools) { GlobalInspectionToolWrapper toolWrapper = (GlobalInspectionToolWrapper)tools.getTool(); GlobalSimpleInspectionTool tool = (GlobalSimpleInspectionTool)toolWrapper.getTool(); ProblemDescriptionsProcessor problemDescriptionProcessor = getProblemDescriptionProcessor(toolWrapper, map); tool.inspectionFinished(inspectionManager, this, problemDescriptionProcessor); } addProblemsToView(globalSimpleTools); }