mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 11:53:49 +07:00
internal-tools: move the InvalidCompilationListener to the internal tools
There is no demand for the feature in the Java plugin at the moment. At the same time, we'd like to extend it by some internal capabilities like reporting to Slack, which is more convenient to do when the whole feature is located in a single module. GitOrigin-RevId: 0249858bb6824a3cab4e416b9ebc2eb83ba295ae
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8fad92c453
commit
ba0d2499cd
@@ -2501,9 +2501,6 @@
|
||||
|
||||
<spellchecker.dictionary.checker implementation="com.intellij.java.frameworks.MavenDictionaryChecker"/>
|
||||
|
||||
<statistics.counterUsagesCollector implementationClass="com.intellij.ide.compilation.InvalidCompilationStatistics"/>
|
||||
<notificationGroup id="Invalid Compilation Errors" displayType="STICKY_BALLOON" hideFromSettings="true" />
|
||||
|
||||
<iconMapper mappingFile="JavaUIIconsMapping.json"/>
|
||||
<optionController implementation="com.intellij.compiler.JavaCompilerConfiguration$Provider"/>
|
||||
|
||||
@@ -2550,9 +2547,6 @@
|
||||
topic="com.intellij.codeInsight.hints.InlayHintsSettings$SettingsListener"/>
|
||||
<listener class="com.intellij.codeInsight.daemon.problems.pass.ProjectProblemFileRefactoringEventListener"
|
||||
topic="com.intellij.refactoring.listeners.RefactoringEventListener"/>
|
||||
<listener class="com.intellij.ide.compilation.InvalidCompilationListener"
|
||||
topic="com.intellij.openapi.compiler.CompilationStatusListener"
|
||||
activeInHeadlessMode="false"/>
|
||||
<listener class="com.intellij.openapi.roots.impl.LanguageLevelChangedListener"
|
||||
topic="com.intellij.platform.backend.workspace.WorkspaceModelChangeListener"/>
|
||||
</projectListeners>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.compilation
|
||||
|
||||
import com.intellij.openapi.compiler.CompilationStatusListener
|
||||
import com.intellij.openapi.compiler.CompileContext
|
||||
import com.intellij.openapi.compiler.CompilerMessageCategory
|
||||
import com.intellij.psi.util.ProjectIconsAccessor.isIdeaProject
|
||||
|
||||
internal class InvalidCompilationListener : CompilationStatusListener {
|
||||
override fun compilationFinished(aborted: Boolean, errors: Int, warnings: Int, compileContext: CompileContext) {
|
||||
val project = compileContext.getProject()
|
||||
|
||||
if (!isIdeaProject(project)) {
|
||||
return
|
||||
}
|
||||
|
||||
val errorMessages = compileContext.getMessages(CompilerMessageCategory.ERROR)
|
||||
if (errorMessages.isNotEmpty()) {
|
||||
InvalidCompilationTracker.getInstance(project).analyzeCompilerErrorsInBackground(errorMessages.toList())
|
||||
}
|
||||
else if (!aborted) {
|
||||
InvalidCompilationTracker.getInstance(project).compilationSucceeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.compilation
|
||||
|
||||
import com.intellij.internal.statistic.eventLog.EventLogGroup
|
||||
import com.intellij.internal.statistic.eventLog.events.EventFields
|
||||
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
|
||||
|
||||
internal object InvalidCompilationStatistics : CounterUsagesCollector() {
|
||||
val GROUP: EventLogGroup = EventLogGroup("idea.project.statistics", 2)
|
||||
|
||||
val INVALID_COMPILATION_FAILURE = GROUP.registerEvent("invalid.compilation.failure", EventFields.Language)
|
||||
|
||||
override fun getGroup(): EventLogGroup {
|
||||
return GROUP
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.compilation
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.MainPassesRunner
|
||||
import com.intellij.java.JavaBundle
|
||||
import com.intellij.lang.LanguageUtil
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationAction
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.compiler.CompilerMessage
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.FileIndexFacade
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.profile.codeInspection.InspectionProjectProfileManager
|
||||
import com.intellij.task.ProjectTaskManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
internal class InvalidCompilationTracker(
|
||||
private val project: Project,
|
||||
private val scope: CoroutineScope) {
|
||||
|
||||
private val notificationRef: AtomicReference<Notification?> = AtomicReference(null)
|
||||
|
||||
internal fun analyzeCompilerErrorsInBackground(errorMessages: List<CompilerMessage>) {
|
||||
scope.launch(Dispatchers.Default) {
|
||||
val scannedFiles = mutableSetOf<VirtualFile>()
|
||||
for (message in errorMessages) {
|
||||
val file = message.getVirtualFile()
|
||||
if (file != null && scannedFiles.add(file) && isFileGreen(project, file)) {
|
||||
LOG.warn("Invalid compilation failure in $file")
|
||||
InvalidCompilationStatistics.INVALID_COMPILATION_FAILURE.log(project, LanguageUtil.getFileLanguage(file))
|
||||
proposeToRebuildModule(project, file)
|
||||
break
|
||||
}
|
||||
if (scannedFiles.size >= MAX_FILES_TO_SCAN) {
|
||||
// don't scan too many files to save CPU resources: if there are many errors, and files are also red,
|
||||
// then probably it is not an invalid compilation case, and manual actions are needed anyway.
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isFileGreen(project: Project, file: VirtualFile): Boolean {
|
||||
var green = false
|
||||
ProgressManager.getInstance().executeProcessUnderProgress(Runnable {
|
||||
val inspectionProfile = InspectionProjectProfileManager.getInstance(project).currentProfile
|
||||
val errors = MainPassesRunner(project, "", inspectionProfile).runMainPasses(listOf(file), HighlightSeverity.ERROR)
|
||||
.filterValues { highlightInfos ->
|
||||
highlightInfos.any { it.severity == HighlightSeverity.ERROR }
|
||||
}
|
||||
green = errors.isEmpty()
|
||||
}, ProgressIndicatorBase())
|
||||
return green
|
||||
}
|
||||
|
||||
private suspend fun proposeToRebuildModule(project: Project, file: VirtualFile) {
|
||||
val module = readAction {
|
||||
FileIndexFacade.getInstance(project).getModuleForFile(file)
|
||||
}
|
||||
if (module == null) {
|
||||
LOG.warn("No module for $file")
|
||||
return
|
||||
}
|
||||
|
||||
val notification = createNotification(module.name, project)
|
||||
|
||||
val previousNotification = notificationRef.getAndSet(notification)
|
||||
if (previousNotification != null) {
|
||||
previousNotification.expire()
|
||||
}
|
||||
|
||||
notification.notify(project)
|
||||
}
|
||||
|
||||
private fun createNotification(moduleName: @NlsSafe String, project: Project): Notification {
|
||||
return Notification(NOTIFICATION_GROUP_ID,
|
||||
JavaBundle.message("invalid.compilation.notification.title"),
|
||||
JavaBundle.message("invalid.compilation.notification.content"),
|
||||
NotificationType.WARNING)
|
||||
.addAction(NotificationAction.createSimpleExpiring(
|
||||
JavaBundle.message("invalid.compilation.notification.action.rebuild", moduleName),
|
||||
Runnable {
|
||||
val module = ModuleManager.getInstance(project).findModuleByName(moduleName)
|
||||
if (module != null) {
|
||||
ProjectTaskManager.getInstance(project).rebuild(module)
|
||||
}
|
||||
else {
|
||||
LOG.warn("Module $moduleName not found")
|
||||
Messages.showErrorDialog(project,
|
||||
JavaBundle.message("invalid.compilation.notification.action.rebuild.error.description", moduleName),
|
||||
JavaBundle.message("invalid.compilation.notification.action.rebuild.error.title", moduleName))
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
fun compilationSucceeded() {
|
||||
val previousNotification = notificationRef.getAndSet(null)
|
||||
if (previousNotification != null) {
|
||||
previousNotification.expire()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = logger<InvalidCompilationTracker>()
|
||||
private const val NOTIFICATION_GROUP_ID = "Invalid Compilation Errors"
|
||||
private const val MAX_FILES_TO_SCAN = 5
|
||||
|
||||
fun getInstance(project: Project): InvalidCompilationTracker {
|
||||
return project.service()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1921,11 +1921,6 @@ intention.family.name.add.main.method=Add 'main' method
|
||||
intention.sequenced.collection.can.be.used.display.name=SequencedCollection method can be used
|
||||
intention.sequenced.collection.can.be.used.fix.name=Replace with SequencedCollection method call
|
||||
|
||||
invalid.compilation.notification.title=Invalid compilation error
|
||||
invalid.compilation.notification.content=Try to rebuild only the affected module
|
||||
invalid.compilation.notification.action.rebuild=Rebuild module {0}
|
||||
invalid.compilation.notification.action.rebuild.error.description=Module {0} not found
|
||||
invalid.compilation.notification.action.rebuild.error.title=Can''t Rebuild Module {0}
|
||||
inspection.mapping.before.count.family.name=Mapping call before count()
|
||||
inspection.mapping.before.count.message=The ''{0}()'' call does not change the final count and might be optimized out.
|
||||
unknown.library=Unknown Library
|
||||
|
||||
Reference in New Issue
Block a user