mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java] IDEA-210466 Suggest to move Java file to the source root
GitOrigin-RevId: f225ebbb2bcb6084b36ca504aae4e5463c074fc5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b5808d2c51
commit
f5effaaeb3
@@ -638,4 +638,6 @@ inspection.extract.method.message=Extract method returning ''{0}''
|
||||
inspection.extract.method.option.min.length=Minimum length of code to extract:|symbols
|
||||
inspection.extract.method.option.max.parameters=Maximum number of parameters:
|
||||
inspection.extract.method.dont.suggest.parameters=Don''t suggest to extract method with {0} or more parameters
|
||||
inspection.extract.method.dont.suggest.length=Don\u2019t suggest to extract methods as short as this
|
||||
inspection.extract.method.dont.suggest.length=Don\u2019t suggest to extract methods as short as this
|
||||
notification.file.system.issue=File Operation Issue
|
||||
notification.content.cannot.move.file=Cannot move ''{0}'' into ''{1}'': {2}
|
||||
|
||||
@@ -320,5 +320,6 @@
|
||||
<lang.jvm.annotationPackageSupport implementation="com.intellij.codeInsight.annoPackages.CheckerFrameworkSupport"/>
|
||||
<lang.jvm.annotationPackageSupport implementation="com.intellij.codeInsight.annoPackages.EclipseAnnotationSupport"/>
|
||||
<lang.jvm.annotationPackageSupport implementation="com.intellij.codeInsight.annoPackages.JSpecifyAnnotationSupport"/>
|
||||
<notificationGroup id="FileSystemIssue" displayType="BALLOON" bundle="messages.JavaAnalysisBundle" key="notification.file.system.issue"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
+20
-16
@@ -1,24 +1,16 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// 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.codeInsight.daemon.impl.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo;
|
||||
import com.intellij.codeInspection.util.IntentionName;
|
||||
import com.intellij.java.analysis.JavaAnalysisBundle;
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationGroup;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
@@ -63,14 +55,26 @@ public class MoveFileFix implements IntentionAction {
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||
int offset = -1;
|
||||
if (editor.getVirtualFile().equals(myFile)) {
|
||||
offset = editor.getCaretModel().getOffset();
|
||||
}
|
||||
if (myFile.isValid() && myTarget.isValid()) {
|
||||
try {
|
||||
myFile.move(this, myTarget);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IncorrectOperationException("Cannot move '" + myFile.getPath() + "' into '" + myTarget.getPath() + "'", (Throwable)e);
|
||||
new Notification("FileSystemIssue",
|
||||
JavaAnalysisBundle.message("notification.content.cannot.move.file", myFile.getPath(), myTarget.getPath(), e.getMessage()),
|
||||
NotificationType.ERROR)
|
||||
.notify(project);
|
||||
}
|
||||
}
|
||||
FileEditorManager manager = FileEditorManager.getInstance(project);
|
||||
manager.closeFile(myFile);
|
||||
if (offset >= 0) {
|
||||
manager.openTextEditor(new OpenFileDescriptor(project, myFile, offset), true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2398,6 +2398,7 @@
|
||||
<dataflowIRProvider language="JAVA" implementationClass="com.intellij.codeInspection.dataFlow.java.JavaDataFlowIRProvider"/>
|
||||
<java.effectively.final.fixer implementation="com.intellij.codeInsight.daemon.impl.quickfix.makefinal.MoveInitializerToIfBranchFixer"/>
|
||||
<java.effectively.final.fixer implementation="com.intellij.codeInspection.streamMigration.ConvertToStreamFixer"/>
|
||||
<postStartupActivity implementation="com.intellij.ide.FileNotInSourceRootChecker"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains">
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
// 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
|
||||
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoType
|
||||
import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.MoveFileFix
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.ide.util.PropertiesComponent
|
||||
import com.intellij.java.JavaBundle
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.ReadAction
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.editor.event.EditorFactoryEvent
|
||||
import com.intellij.openapi.editor.event.EditorFactoryListener
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.openapi.roots.ui.configuration.DefaultModulesProvider
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiJavaFile
|
||||
|
||||
class FileNotInSourceRootChecker : ProjectActivity {
|
||||
override suspend fun execute(project: Project) {
|
||||
project.getService(FileNotInSourceRootService::class.java).init()
|
||||
}
|
||||
}
|
||||
|
||||
private const val GROUP : Int = 1234
|
||||
private const val JAVA_DONT_CHECK_OUT_OF_SOURCE_FILES : String = "com.intellij.ide.FileNotInSourceRootChecker.no.check"
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
class FileNotInSourceRootService(val project: Project) : Disposable {
|
||||
|
||||
fun init() {
|
||||
if (PropertiesComponent.getInstance(project).getBoolean(JAVA_DONT_CHECK_OUT_OF_SOURCE_FILES, false)) return
|
||||
val editorFactory = EditorFactory.getInstance()
|
||||
editorFactory.addEditorFactoryListener(object : EditorFactoryListener {
|
||||
override fun editorCreated(event: EditorFactoryEvent) {
|
||||
checkEditor(event.editor)
|
||||
}
|
||||
}, this)
|
||||
editorFactory.allEditors.forEach { editor -> checkEditor(editor) }
|
||||
}
|
||||
|
||||
private fun checkEditor(editor: Editor) {
|
||||
if (editor.project !== project) return
|
||||
if (PropertiesComponent.getInstance(project).getBoolean(JAVA_DONT_CHECK_OUT_OF_SOURCE_FILES, false)) return
|
||||
val virtualFile = editor.virtualFile
|
||||
if (virtualFile == null) return
|
||||
ReadAction.run<RuntimeException> {
|
||||
val fileIndex = ProjectFileIndex.getInstance(project)
|
||||
if (fileIndex.isInSource(virtualFile) || fileIndex.isExcluded(virtualFile) || fileIndex.isUnderIgnored(virtualFile)) return@run
|
||||
if (!fileIndex.getOrderEntriesForFile(virtualFile).isEmpty()) return@run
|
||||
val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.document) as? PsiJavaFile ?: return@run
|
||||
val packageName = psiFile.packageName
|
||||
val module = fileIndex.getModuleForFile(virtualFile) ?: return@run
|
||||
val rootModel = DefaultModulesProvider.createForProject(project).getRootModel(module)
|
||||
val roots = rootModel.sourceRoots
|
||||
if (roots.isEmpty()) return@run
|
||||
var root = roots[0]
|
||||
if (packageName.isNotEmpty()) {
|
||||
root = VfsUtil.findRelativeFile(root, *packageName.split('.').toTypedArray()) ?: root
|
||||
}
|
||||
if (root.findChild(virtualFile.name) != null) return@run
|
||||
val moveFileFix = MoveFileFix(virtualFile, root, JavaBundle.message("fix.move.to.source.root"))
|
||||
val info = HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING)
|
||||
.range(psiFile)
|
||||
.description(JavaBundle.message("warning.java.file.outside.source.root"))
|
||||
.fileLevelAnnotation()
|
||||
.group(GROUP)
|
||||
.registerFix(moveFileFix, listOf(DismissFix(), IgnoreForThisProjectFix()), null, null, null)
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
UpdateHighlightersUtil.setHighlightersToSingleEditor(project, editor, 0, editor.document.textLength,
|
||||
listOf(info.create()), null, GROUP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
|
||||
class DismissFix: IntentionAction {
|
||||
override fun startInWriteAction(): Boolean = false
|
||||
override fun getText(): String = familyName
|
||||
override fun getFamilyName(): String = JavaBundle.message("intention.family.name.dismiss")
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean = true
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
|
||||
file ?: return
|
||||
DaemonCodeAnalyzerEx.getInstanceEx(project).cleanFileLevelHighlights(GROUP, file)
|
||||
}
|
||||
}
|
||||
|
||||
class IgnoreForThisProjectFix: IntentionAction {
|
||||
override fun startInWriteAction(): Boolean = false
|
||||
override fun getText(): String = familyName
|
||||
override fun getFamilyName(): String = JavaBundle.message("intention.family.name.ignore.project")
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean = true
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
|
||||
file ?: return
|
||||
val codeAnalyzer = DaemonCodeAnalyzerEx.getInstanceEx(project)
|
||||
PropertiesComponent.getInstance(project).setValue(JAVA_DONT_CHECK_OUT_OF_SOURCE_FILES, true)
|
||||
codeAnalyzer.cleanFileLevelHighlights(GROUP, file)
|
||||
for (ed in EditorFactory.getInstance().allEditors) {
|
||||
if (ed.project != project) continue
|
||||
val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(ed.document) as? PsiJavaFile ?: continue
|
||||
if (psiFile == file) continue
|
||||
codeAnalyzer.cleanFileLevelHighlights(GROUP, psiFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1813,3 +1813,7 @@ hint.text.not.valid.java.identifier=Not a valid Java identifier
|
||||
command.name.replace.type=Replace Type
|
||||
java.completion.tag=Tag:
|
||||
java.completion.tags=Tags:
|
||||
intention.family.name.dismiss=Dismiss
|
||||
intention.family.name.ignore.project=Do not show again in this project
|
||||
fix.move.to.source.root=Move to source root
|
||||
warning.java.file.outside.source.root=Java file is located outside of the module source root, so it won't be compiled
|
||||
|
||||
Reference in New Issue
Block a user