mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[maven] [IDEA-381098] maven4 quick fixes
Merge-request: IJ-MR-175311 Merged-by: Aleksandr Bubenchikov <alexander.bubenchikov@jetbrains.com> (cherry picked from commit e3cd28795c7a24db59fd581d93843f72bfea3278) IJ-CR-180089 GitOrigin-RevId: 1147b8e6ee9d02eb7f43d5f89787bcbc41712fff
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9da0d7106e
commit
936c2c4625
+14
-4
@@ -5,10 +5,20 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class MavenConstants {
|
||||
public static final String MAVEN_4_XLMNS = "http://maven.apache.org/POM/4.1.0";
|
||||
public static final String MAVEN_4_XLMNS_HTTPS = "https://maven.apache.org/POM/4.1.0";
|
||||
public static final String MAVEN_4_XSD = "https://maven.apache.org/xsd/maven-4.1.0.xsd";
|
||||
public static final String MAVEN_4_XSD_HTTPS = "http://maven.apache.org/xsd/maven-4.1.0.xsd";
|
||||
public static final String MAVEN_4_XMLNS = "http://maven.apache.org/POM/4.1.0";
|
||||
public static final String MAVEN_4_XMLNS_HTTPS = "https://maven.apache.org/POM/4.1.0";
|
||||
public static final String MAVEN_4_XSD = "http://maven.apache.org/xsd/maven-4.1.0.xsd";
|
||||
public static final String MAVEN_4_XSD_HTTPS = "https://maven.apache.org/xsd/maven-4.1.0.xsd";
|
||||
public static final String MAVEN_4_XSD_UNDERSCORE = "http://maven.apache.org/maven-v4_1_0.xsd";
|
||||
public static final String MAVEN_4_XSD_HTTPS_UNDERSCORE = "https://maven.apache.org/maven-v4_1_0.xsd";
|
||||
|
||||
|
||||
public static final String MAVEN_3_XMLNS = "http://maven.apache.org/POM/4.0.0";
|
||||
public static final String MAVEN_3_XMLNS_HTTPS = "https://maven.apache.org/POM/4.0.0";
|
||||
public static final String MAVEN_3_XSD = "http://maven.apache.org/xsd/maven-4.0.0.xsd";
|
||||
public static final String MAVEN_3_XSD_HTTPS = "https://maven.apache.org/xsd/maven-4..0.xsd";
|
||||
|
||||
|
||||
public static final String POM_EXTENSION = "pom";
|
||||
public static final String POM_XML = "pom.xml";
|
||||
|
||||
|
||||
+34
-11
@@ -8,8 +8,12 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.xml.XmlTag
|
||||
import org.jetbrains.idea.maven.model.MavenConstants
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_4_XLMNS
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_3_XMLNS
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_3_XMLNS_HTTPS
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_4_XMLNS
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_4_XMLNS_HTTPS
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_4_XSD
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_4_XSD_HTTPS
|
||||
import org.jetbrains.idea.maven.project.MavenProjectBundle
|
||||
|
||||
class UpdateXmlsTo410 : LocalQuickFix {
|
||||
@@ -24,16 +28,7 @@ class UpdateXmlsTo410 : LocalQuickFix {
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
|
||||
val rootTag = findProjectTag(descriptor) ?: return
|
||||
val xmlnsXsi = rootTag.getAttribute("xmlns:xsi")
|
||||
rootTag.setAttribute("xmlns", MAVEN_4_XLMNS)
|
||||
if (xmlnsXsi == null) {
|
||||
rootTag.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
}
|
||||
rootTag.setAttribute("xsi:schemaLocation", "$MAVEN_4_XLMNS $MAVEN_4_XSD")
|
||||
val modelVersion = rootTag.findSubTags("modelVersion")
|
||||
if (modelVersion.isNotEmpty()) {
|
||||
modelVersion.forEach { it.value.setText(MavenConstants.MODEL_VERSION_4_1_0) }
|
||||
}
|
||||
updateTagTo410(rootTag)
|
||||
}
|
||||
|
||||
private fun findProjectTag(descriptor: ProblemDescriptor): XmlTag? {
|
||||
@@ -45,4 +40,32 @@ class UpdateXmlsTo410 : LocalQuickFix {
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun updateTagTo410(rootTag: XmlTag) {
|
||||
val xmlnsXsi = rootTag.getAttribute("xmlns:xsi")
|
||||
val xmlns = rootTag.getAttribute("xmlns")?.value
|
||||
if(xmlns.isNullOrBlank()|| xmlns == MAVEN_3_XMLNS) {
|
||||
rootTag.setAttribute("xmlns", MAVEN_4_XMLNS)
|
||||
} else if(xmlns == MAVEN_3_XMLNS_HTTPS) {
|
||||
rootTag.setAttribute("xmlns", MAVEN_4_XMLNS_HTTPS)
|
||||
}
|
||||
|
||||
if (xmlnsXsi == null) {
|
||||
rootTag.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
}
|
||||
|
||||
val schemaLocation = rootTag.getAttribute("xsi:schemaLocation")?.value
|
||||
|
||||
if(schemaLocation.isNullOrBlank() || schemaLocation.startsWith(MAVEN_3_XMLNS)) {
|
||||
rootTag.setAttribute("xsi:schemaLocation", "$MAVEN_4_XMLNS $MAVEN_4_XSD")
|
||||
} else if(schemaLocation.startsWith(MAVEN_3_XMLNS_HTTPS)) {
|
||||
rootTag.setAttribute("xsi:schemaLocation", "$MAVEN_4_XMLNS_HTTPS $MAVEN_4_XSD_HTTPS")
|
||||
}
|
||||
|
||||
val modelVersion = rootTag.findSubTags("modelVersion")
|
||||
if (modelVersion.isNotEmpty()) {
|
||||
modelVersion.forEach { it.value.setText(MavenConstants.MODEL_VERSION_4_1_0) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.xml.*
|
||||
import org.jetbrains.idea.maven.dom.model.*
|
||||
import org.jetbrains.idea.maven.model.MavenConstants
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MODEL_VERSION_4_0_0
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MODEL_VERSION_4_1_0
|
||||
import org.jetbrains.idea.maven.model.MavenCoordinate
|
||||
import org.jetbrains.idea.maven.model.MavenId
|
||||
import org.jetbrains.idea.maven.model.MavenResource
|
||||
@@ -37,6 +39,7 @@ import org.jetbrains.idea.maven.project.MavenProjectsManager
|
||||
import org.jetbrains.idea.maven.server.MavenDistribution
|
||||
import org.jetbrains.idea.maven.server.MavenDistributionsCache
|
||||
import org.jetbrains.idea.maven.utils.MavenLog
|
||||
import org.jetbrains.idea.maven.utils.MavenUtil
|
||||
import org.jetbrains.idea.maven.utils.MavenUtil.isPomFileName
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@@ -71,6 +74,29 @@ object MavenDomUtil {
|
||||
return isPomFileName(file.getName())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isProjectFileWithModel410(file: PsiFile?): Boolean {
|
||||
if (file !is XmlFile) return false
|
||||
|
||||
val rootTag = file.getRootTag()
|
||||
if (rootTag == null || "project" != rootTag.getName()) return false
|
||||
|
||||
val xmlns = rootTag.getAttributeValue("xmlns")
|
||||
if (xmlns != "http://maven.apache.org/POM/4.1.0" && xmlns != "https://maven.apache.org/POM/4.1.0"){
|
||||
return false
|
||||
}
|
||||
|
||||
if (!isPomFileName(file.getName())) return false
|
||||
|
||||
val modelTag = rootTag.findSubTags("modelVersion").singleOrNull()
|
||||
if (modelTag?.value?.text == MODEL_VERSION_4_1_0) return true
|
||||
if (modelTag?.value?.text == MODEL_VERSION_4_0_0) return false
|
||||
return MavenUtil.isMaven410(
|
||||
rootTag?.getAttribute("xmlns")?.value,
|
||||
rootTag?.getAttribute("xsi:schemaLocation")?.value)
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getXmlProjectModelVersion(file: PsiFile?): @NlsSafe String? {
|
||||
if (file !is XmlFile) return null
|
||||
|
||||
+17
-2
@@ -18,6 +18,7 @@ import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.maven.dom.references.MavenPsiElementWrapper;
|
||||
import org.jetbrains.idea.maven.server.MavenDistributionsCache;
|
||||
import org.jetbrains.idea.maven.utils.MavenLog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -54,7 +55,8 @@ public final class MavenModelDocumentationProvider implements DocumentationProvi
|
||||
@Override
|
||||
public @Nls String getElementDescription(@NotNull PsiElement element, @NotNull ElementDescriptionLocation location) {
|
||||
return ReadAction.compute(() ->
|
||||
getMavenElementDescription(element, location instanceof UsageViewTypeLocation ? DescKind.TYPE : DescKind.NAME, false)
|
||||
getMavenElementDescription(element,
|
||||
location instanceof UsageViewTypeLocation ? DescKind.TYPE : DescKind.NAME, false)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -81,13 +83,26 @@ public final class MavenModelDocumentationProvider implements DocumentationProvi
|
||||
if (e instanceof XmlTag) {
|
||||
valueSuffix = ": " + bold[0] + ((XmlTag)e).getValue().getTrimmedText() + bold[1];
|
||||
}
|
||||
return type + br + name + valueSuffix;
|
||||
var tip = getTip(name, kind, valueSuffix, e);
|
||||
if (tip == null) {
|
||||
return type + br + name + valueSuffix;
|
||||
}
|
||||
return type + br + name + valueSuffix + br + tip;
|
||||
}
|
||||
|
||||
MavenLog.LOG.error("unexpected desc kind: " + kind);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static @Nullable @Nls String getTip(String name, DescKind kind, String suffix, PsiElement e) {
|
||||
if (!"project.modelVersion".equals(name)) return null;
|
||||
var project = e.getProject();
|
||||
if (project.isDefault()) return null;
|
||||
var mavenVersion = MavenDistributionsCache.getInstance(project)
|
||||
.getMavenDistribution(e.getContainingFile().getVirtualFile());
|
||||
return MavenDomBundle.message("maven.version.tip", mavenVersion.getVersion());
|
||||
}
|
||||
|
||||
private static @NlsContexts.DetailedDescription String buildPropertyName(PsiElement e, boolean property) {
|
||||
if (property) return DescriptiveNameUtil.getDescriptiveName(e); //NON-NLS - suprress warning
|
||||
|
||||
|
||||
+5
-2
@@ -21,9 +21,10 @@ import org.jetbrains.idea.maven.dom.MavenDomBundle
|
||||
import org.jetbrains.idea.maven.dom.MavenDomUtil.isAtLeastMaven4
|
||||
import org.jetbrains.idea.maven.model.MavenConstants
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MODEL_VERSION_4_1_0
|
||||
import org.jetbrains.idea.maven.server.MavenDistributionsCache
|
||||
import org.jetbrains.idea.maven.utils.MavenUtil
|
||||
|
||||
class MavenModelVersionConverter : MavenConstantListConverter() {
|
||||
class MavenModelVersionConverter : MavenConstantListConverter(false) {
|
||||
override fun getValues(context: ConvertContext): Collection<String> {
|
||||
return if (isAtLeastMaven4(context.getFile().getVirtualFile(), context.getProject())) {
|
||||
VALUES_MAVEN_4
|
||||
@@ -43,7 +44,9 @@ class MavenModelVersionConverter : MavenConstantListConverter() {
|
||||
}
|
||||
|
||||
override fun getErrorMessage(s: String?, context: ConvertContext): String? {
|
||||
return MavenDomBundle.message("inspection.message.unsupported.model.version.only.version.supported", getValues(context))
|
||||
val project = context.project
|
||||
val version = MavenDistributionsCache.getInstance(project).getMavenDistribution(context.file.virtualFile).version
|
||||
return MavenDomBundle.message("inspection.message.unsupported.model.version.only.version.supported", getValues(context), version)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
*/
|
||||
package org.jetbrains.idea.maven.dom.converters;
|
||||
|
||||
import com.intellij.util.xml.ConvertContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.idea.maven.project.MavenProject;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class MavenPackagingConverter extends MavenProjectConstantListConverter {
|
||||
public MavenPackagingConverter() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> getValues(@NotNull ConvertContext context, @NotNull MavenProject project) {
|
||||
return project.getSupportedPackagings();
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2000-2009 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.
|
||||
*/
|
||||
package org.jetbrains.idea.maven.dom.converters
|
||||
|
||||
import com.intellij.util.xml.ConvertContext
|
||||
import com.intellij.util.xml.DomManager
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel
|
||||
import org.jetbrains.idea.maven.importing.MavenImporter
|
||||
import org.jetbrains.idea.maven.model.MavenConstants
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MODEL_VERSION_4_0_0
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MODEL_VERSION_4_1_0
|
||||
import org.jetbrains.idea.maven.project.MavenProject
|
||||
|
||||
class MavenPackagingConverter : MavenProjectConstantListConverter(false) {
|
||||
override fun getValues(context: ConvertContext, project: MavenProject): Collection<String> {
|
||||
val result = mutableSetOf<String>()
|
||||
result.addAll(DEFAULT_PACKAGES)
|
||||
for (each: MavenImporter in MavenImporter.getSuitableImporters(project)) {
|
||||
each.getSupportedPackagings(result)
|
||||
}
|
||||
val file = context.file
|
||||
val model =
|
||||
DomManager.getDomManager(file.getProject()).getFileElement(file, MavenDomProjectModel::class.java)
|
||||
val rootElement = model?.rootElement
|
||||
val modelVersion = rootElement?.modelVersion?.stringValue?.trim()
|
||||
if (modelVersion != MODEL_VERSION_4_0_0) {
|
||||
result.addAll(MAVEN_4_SPECIFIC)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
val DEFAULT_PACKAGES: Set<String> = setOf(MavenConstants.TYPE_POM, MavenConstants.TYPE_JAR, "ejb", "ejb-client", "war", "ear", "bundle", "maven-plugin")
|
||||
val MAVEN_4_SPECIFIC: Set<String> = setOf("bom")
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inlay
|
||||
|
||||
import com.intellij.codeInsight.hints.declarative.*
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import org.jetbrains.idea.maven.dom.MavenDomBundle
|
||||
import org.jetbrains.idea.maven.dom.MavenDomUtil
|
||||
import org.jetbrains.idea.maven.model.MavenConstants
|
||||
import org.jetbrains.idea.maven.project.MavenProjectsManager
|
||||
|
||||
class MavenModelVersionInlayHintProvider : InlayHintsProvider {
|
||||
override fun createCollector(file: PsiFile, editor: Editor): MavenModelVersionInlayHintCollector = MavenModelVersionInlayHintCollector(editor)
|
||||
|
||||
override fun isDumbAware(): Boolean = true
|
||||
}
|
||||
|
||||
class MavenModelVersionInlayHintCollector(val editor: Editor) : OwnBypassCollector {
|
||||
override fun collectHintsForFile(file: PsiFile, sink: InlayTreeSink) {
|
||||
if (file !is XmlFile) return
|
||||
val manager = MavenProjectsManager.getInstance(file.project)
|
||||
val vFile = file.virtualFile
|
||||
if (manager.findProject(vFile) == null) return
|
||||
val modelTag = file.rootTag?.findFirstSubTag("modelVersion") ?: return
|
||||
val line = editor.document.getLineNumber(modelTag.textOffset)
|
||||
val modelVersion = MavenDomUtil.getXmlProjectModelVersion(file) ?: return
|
||||
if (modelVersion == MavenConstants.MODEL_VERSION_4_0_0) {
|
||||
sink.addPresentation(EndOfLinePosition(line), hintFormat = HintFormat.default) {
|
||||
text(MavenDomBundle.message("maven.version.inlay.hint.text.3"))
|
||||
}
|
||||
}
|
||||
else if (modelVersion == MavenConstants.MODEL_VERSION_4_1_0) {
|
||||
sink.addPresentation(EndOfLinePosition(line), hintFormat = HintFormat.default) {
|
||||
text(MavenDomBundle.message("maven.version.inlay.hint.text.4"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inspections
|
||||
|
||||
import com.intellij.codeInspection.*
|
||||
import com.intellij.codeInspection.util.IntentionFamilyName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import com.intellij.psi.xml.XmlTag
|
||||
import com.intellij.util.xml.DomManager
|
||||
import org.jetbrains.idea.maven.dom.MavenDomBundle
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel
|
||||
import org.jetbrains.idea.maven.server.MavenDistribution
|
||||
|
||||
abstract class AbstractMavenRedundantParentInspection : XmlSuppressableInspectionTool() {
|
||||
override fun getGroupDisplayName(): String {
|
||||
return MavenDomBundle.message("inspection.group")
|
||||
}
|
||||
|
||||
protected abstract val elementName: String
|
||||
abstract override fun getShortName(): String
|
||||
|
||||
override fun checkFile(file: PsiFile, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor?>? {
|
||||
if (file is XmlFile && file.isPhysical()) {
|
||||
val model =
|
||||
DomManager.getDomManager(file.getProject()).getFileElement<MavenDomProjectModel?>(file, MavenDomProjectModel::class.java)
|
||||
|
||||
|
||||
if (model != null) {
|
||||
val projectModel = model.getRootElement()
|
||||
if (projectModel == null) return null
|
||||
|
||||
if (!supportedForFile(file)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val selfValue = getSelfValue(projectModel)
|
||||
if (selfValue != null && !selfValue.isEmpty()) {
|
||||
val parentValue = getParentValue(projectModel, file.project)
|
||||
if (selfValue == parentValue) {
|
||||
val xmlTag = getXmlTag(projectModel) ?: return null
|
||||
|
||||
val fix: LocalQuickFix = object : LocalQuickFix {
|
||||
|
||||
|
||||
override fun getFamilyName(): @IntentionFamilyName String {
|
||||
return MavenDomBundle.message("inspection.redundant.element.fix", elementName)
|
||||
}
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
descriptor.getPsiElement().delete()
|
||||
}
|
||||
}
|
||||
|
||||
return arrayOf(manager.createProblemDescriptor(xmlTag,
|
||||
MavenDomBundle.message("inspection.redundant.element.fix.description", elementName),
|
||||
fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||
isOnTheFly)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
abstract fun getXmlTag(projectModel: MavenDomProjectModel): XmlTag?
|
||||
|
||||
abstract fun getSelfValue(projectModel: MavenDomProjectModel): String?
|
||||
abstract fun getParentValue(projectModel: MavenDomProjectModel, project: Project): String?
|
||||
|
||||
protected abstract fun supportedForFile(file: XmlFile): Boolean
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inspections
|
||||
|
||||
import com.intellij.codeInspection.*
|
||||
import com.intellij.codeInspection.util.IntentionFamilyName
|
||||
import com.intellij.codeInspection.util.IntentionName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import com.intellij.util.xml.DomManager
|
||||
import org.jetbrains.idea.maven.dom.MavenDomBundle
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomParent
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel
|
||||
import org.jetbrains.idea.maven.server.MavenDistributionsCache
|
||||
import org.jetbrains.idea.maven.server.isMaven4
|
||||
|
||||
class Maven4RedundantParentCoordinatesInspection : XmlSuppressableInspectionTool() {
|
||||
|
||||
override fun getShortName(): String = "Maven4RedundantParentCoordinates"
|
||||
|
||||
@Suppress("NULLABILITY_MISMATCH_BASED_ON_EXPLICIT_TYPE_ARGUMENTS_FOR_JAVA")
|
||||
override fun checkFile(file: PsiFile, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor?>? {
|
||||
val project = file.project
|
||||
|
||||
if (file is XmlFile && file.isPhysical()) {
|
||||
val dist = MavenDistributionsCache.getInstance(file.project).getMavenDistribution(file.virtualFile)
|
||||
if (!dist.isMaven4()) return null
|
||||
val dom =
|
||||
DomManager.getDomManager(file.getProject()).getFileElement(file, MavenDomProjectModel::class.java)
|
||||
?: return null
|
||||
|
||||
val model = dom.rootElement
|
||||
val declaredParentGroupId = model.mavenParent.groupId.stringValue
|
||||
val declaredParentVersion = model.mavenParent.version.stringValue
|
||||
val declaredParentArtifactId = model.mavenParent.artifactId.stringValue
|
||||
if (declaredParentGroupId.isNullOrEmpty() && declaredParentVersion.isNullOrEmpty()) return null
|
||||
val parentFile = model.mavenParent.relativePath.value ?: file.parent?.parent?.findFile("pom.xml") ?: return null
|
||||
if (parentFile is XmlFile && parentFile.isPhysical()) {
|
||||
val parentDom =
|
||||
DomManager.getDomManager(project).getFileElement(parentFile, MavenDomProjectModel::class.java)
|
||||
?: return null
|
||||
val parentModel = parentDom.rootElement
|
||||
val parentGroupId = parentModel.groupId.stringValue
|
||||
val parentVersion = parentModel.version.stringValue
|
||||
val parentArtifactId = parentModel.artifactId.stringValue
|
||||
|
||||
if (declaredParentGroupId != parentGroupId) return null
|
||||
if (declaredParentVersion != parentVersion) return null
|
||||
if (declaredParentArtifactId != parentArtifactId) return null
|
||||
val fix = getCleanParentFix(model.mavenParent)
|
||||
return listOf(model.mavenParent.groupId,
|
||||
model.mavenParent.artifactId,
|
||||
model.mavenParent.version)
|
||||
.filter { it.exists() }
|
||||
.mapNotNull { it.getXmlTag() }
|
||||
.map {
|
||||
manager.createProblemDescriptor(it,
|
||||
MavenDomBundle.message("inspection.redundant.parent.coordinates.maven.4"),
|
||||
fix,
|
||||
ProblemHighlightType.WARNING,
|
||||
isOnTheFly)
|
||||
}.toTypedArray()
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getCleanParentFix(mavenParent: MavenDomParent): LocalQuickFix {
|
||||
return object : LocalQuickFix {
|
||||
override fun getFamilyName(): @IntentionFamilyName String {
|
||||
return MavenDomBundle.message("inspection.redundant.parent.coordinates.maven.4")
|
||||
}
|
||||
|
||||
override fun getName(): @IntentionName String {
|
||||
return MavenDomBundle.message("inspection.redundant.parent.coordinates.maven.4.clean")
|
||||
}
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
mavenParent.groupId.xmlTag?.delete()
|
||||
mavenParent.artifactId.xmlTag?.delete()
|
||||
mavenParent.version.xmlTag?.delete()
|
||||
mavenParent.xmlTag?.collapseIfEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inspections
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.util.xml.DomFileElement
|
||||
import com.intellij.util.xml.highlighting.BasicDomElementsInspection
|
||||
import com.intellij.util.xml.highlighting.DomElementAnnotationHolder
|
||||
import org.jetbrains.idea.maven.buildtool.quickfix.UpdateXmlsTo410
|
||||
import org.jetbrains.idea.maven.dom.MavenDomBundle
|
||||
import org.jetbrains.idea.maven.dom.converters.MavenPackagingConverter.Companion.MAVEN_4_SPECIFIC
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MODEL_VERSION_4_1_0
|
||||
|
||||
class MavenBomPackagingInOldSchema : BasicDomElementsInspection<MavenDomProjectModel?>(MavenDomProjectModel::class.java) {
|
||||
override fun getGroupDisplayName(): String {
|
||||
return MavenDomBundle.message("inspection.group")
|
||||
}
|
||||
|
||||
override fun getDefaultLevel(): HighlightDisplayLevel {
|
||||
return HighlightDisplayLevel.ERROR
|
||||
}
|
||||
|
||||
override fun checkFileElement(
|
||||
domFileElement: DomFileElement<MavenDomProjectModel?>,
|
||||
holder: DomElementAnnotationHolder,
|
||||
) {
|
||||
val projectModel = domFileElement.getRootElement()
|
||||
|
||||
if (!projectModel.modelVersion.exists() || projectModel.modelVersion.stringValue == MODEL_VERSION_4_1_0) return
|
||||
val packaging = if (projectModel.packaging.exists()) projectModel.packaging.stringValue else return
|
||||
if (packaging == null || projectModel.packaging.stringValue !in MAVEN_4_SPECIFIC) return
|
||||
|
||||
holder.createProblem(projectModel.modelVersion,
|
||||
HighlightSeverity.ERROR,
|
||||
MavenDomBundle.message("inspection.new.packaging.in.old.model", packaging),
|
||||
UpdateXmlsTo410()
|
||||
)
|
||||
holder.createProblem(projectModel.packaging,
|
||||
HighlightSeverity.ERROR,
|
||||
MavenDomBundle.message("inspection.new.packaging.in.old.model", packaging),
|
||||
UpdateXmlsTo410()
|
||||
)
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inspections
|
||||
|
||||
import com.intellij.codeInspection.*
|
||||
|
||||
import com.intellij.codeInspection.util.IntentionFamilyName
|
||||
import com.intellij.codeInspection.util.IntentionName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElementFactory
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.XmlElementFactory
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import com.intellij.psi.xml.XmlTag
|
||||
import com.intellij.util.containers.addAllIfNotNull
|
||||
import com.intellij.util.containers.addIfNotNull
|
||||
import com.intellij.util.xml.DomManager
|
||||
import org.jetbrains.idea.maven.dom.MavenDomBundle
|
||||
import org.jetbrains.idea.maven.dom.MavenDomUtil
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel
|
||||
|
||||
class MavenModulesInMaven4Inspection : XmlSuppressableInspectionTool() {
|
||||
|
||||
override fun getShortName(): String = "MavenModulesInMaven4"
|
||||
|
||||
override fun checkFile(file: PsiFile, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor?>? {
|
||||
if (file is XmlFile && file.isPhysical()) {
|
||||
|
||||
if (!MavenDomUtil.isProjectFileWithModel410(file)) return null
|
||||
val dom =
|
||||
DomManager.getDomManager(file.getProject()).getFileElement(file, MavenDomProjectModel::class.java)
|
||||
?: return null
|
||||
|
||||
val model = dom.rootElement
|
||||
if (!model.modules.exists()) return null
|
||||
val tag = model.modules.xmlTag?:return null
|
||||
val fix = replaceModulesToSubprojects(model)
|
||||
|
||||
|
||||
|
||||
return arrayOf(
|
||||
manager.createProblemDescriptor(
|
||||
tag,
|
||||
MavenDomBundle.message("inspection.modules.tag.in.maven.4"),
|
||||
fix,
|
||||
ProblemHighlightType.WARNING,
|
||||
isOnTheFly
|
||||
)
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun replaceModulesToSubprojects(model: MavenDomProjectModel): LocalQuickFix {
|
||||
return object: LocalQuickFix {
|
||||
override fun getFamilyName(): @IntentionFamilyName String {
|
||||
return MavenDomBundle.message("inspection.modules.tag.in.maven.4")
|
||||
}
|
||||
|
||||
override fun getName(): @IntentionName String {
|
||||
return MavenDomBundle.message("inspection.modules.tag.in.maven.4.name")
|
||||
}
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val modulesList = model.modules.modules.map {
|
||||
it.stringValue
|
||||
}
|
||||
|
||||
val factory = XmlElementFactory.getInstance(project)
|
||||
val subprojectsTag = factory.createTagFromText("<subprojects/>")
|
||||
modulesList.forEach {
|
||||
val tag = factory.createTagFromText("<subproject>$it</subproject>")
|
||||
subprojectsTag.addSubTag(tag, false)
|
||||
|
||||
}
|
||||
model.modules.xmlTag?.replace(subprojectsTag)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inspections
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.codeInspection.util.IntentionFamilyName
|
||||
import com.intellij.execution.process.ProcessEvent
|
||||
import com.intellij.execution.process.ProcessListener
|
||||
import com.intellij.lang.annotation.HighlightSeverity
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.platform.eel.provider.utils.EelPathUtils
|
||||
import com.intellij.util.xml.DomFileElement
|
||||
import com.intellij.util.xml.highlighting.BasicDomElementsInspection
|
||||
import com.intellij.util.xml.highlighting.DomElementAnnotationHolder
|
||||
import org.jetbrains.idea.maven.buildtool.MavenSyncSpec
|
||||
import org.jetbrains.idea.maven.dom.MavenDomBundle
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel
|
||||
import org.jetbrains.idea.maven.execution.MavenRunConfigurationType
|
||||
import org.jetbrains.idea.maven.execution.MavenRunnerParameters
|
||||
import org.jetbrains.idea.maven.execution.MavenRunnerSettings
|
||||
import org.jetbrains.idea.maven.execution.SyncBundle
|
||||
import org.jetbrains.idea.maven.model.MavenConstants
|
||||
import org.jetbrains.idea.maven.project.MavenProject
|
||||
import org.jetbrains.idea.maven.project.MavenProjectsManager
|
||||
import org.jetbrains.idea.maven.project.MavenWorkspaceSettingsComponent
|
||||
import org.jetbrains.idea.maven.project.MavenWrapper
|
||||
import org.jetbrains.idea.maven.server.MavenDistributionsCache
|
||||
import org.jetbrains.idea.maven.server.MavenServerManager
|
||||
import org.jetbrains.idea.maven.server.isMaven4
|
||||
import java.nio.file.FileAlreadyExistsException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardCopyOption
|
||||
import kotlin.io.path.*
|
||||
|
||||
|
||||
private val VERSION_TO_UPDATE_TO = "4.0.0-rc-4"
|
||||
|
||||
class MavenNewModelVersionInOldMavenInspection : BasicDomElementsInspection<MavenDomProjectModel?>(MavenDomProjectModel::class.java) {
|
||||
override fun getGroupDisplayName(): String {
|
||||
return MavenDomBundle.message("inspection.group")
|
||||
}
|
||||
|
||||
override fun getDefaultLevel(): HighlightDisplayLevel {
|
||||
return HighlightDisplayLevel.ERROR
|
||||
}
|
||||
|
||||
override fun checkFileElement(
|
||||
domFileElement: DomFileElement<MavenDomProjectModel?>,
|
||||
holder: DomElementAnnotationHolder,
|
||||
) {
|
||||
|
||||
val project = domFileElement.file.project
|
||||
val psiFile = domFileElement.file
|
||||
val vFile = psiFile.virtualFile
|
||||
val mavenProject =
|
||||
MavenProjectsManager.getInstance(project).findProject(vFile) ?: return
|
||||
|
||||
val rootProject = MavenProjectsManager.getInstance(project).findRootProject(mavenProject) ?: return
|
||||
|
||||
val projectModel = domFileElement.getRootElement()
|
||||
if (projectModel.modelVersion.stringValue == MavenConstants.MODEL_VERSION_4_0_0) return
|
||||
|
||||
val distribution = MavenDistributionsCache.getInstance(psiFile.project).getMavenDistribution(psiFile.virtualFile)
|
||||
if (distribution.isMaven4()) return
|
||||
|
||||
holder.createProblem(projectModel.modelVersion,
|
||||
HighlightSeverity.ERROR,
|
||||
MavenDomBundle.message("inspection.new.model.version.with.old.maven"),
|
||||
UpdateMavenWrapper(rootProject, VERSION_TO_UPDATE_TO)
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateMavenWrapper(@Suppress("ActionIsNotPreviewFriendly") val mavenProject: MavenProject, val version: String) : LocalQuickFix {
|
||||
override fun getName(): String {
|
||||
return SyncBundle.message("maven.sync.quickfixes.update.maven.version", version)
|
||||
}
|
||||
|
||||
override fun getFamilyName(): @IntentionFamilyName String {
|
||||
return name
|
||||
}
|
||||
|
||||
private fun createTempProject(project: Project): Path {
|
||||
val tmp = EelPathUtils.createTemporaryDirectory(project,
|
||||
prefix = "mvn-wrapper-update",
|
||||
deleteOnExit = true)
|
||||
tmp.resolve("pom.xml").writeText(createDummyPomContent())
|
||||
return tmp
|
||||
}
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
|
||||
val workingDir = mavenProject.directoryFile
|
||||
val tempDir = createTempProject(project)
|
||||
MavenRunConfigurationType.runConfiguration(project,
|
||||
MavenRunnerParameters(
|
||||
true,
|
||||
tempDir.toString(),
|
||||
null as String?,
|
||||
listOf("wrapper:wrapper"),
|
||||
null
|
||||
).also { it.cmdOptions = "-N" },
|
||||
null,
|
||||
MavenRunnerSettings().also {
|
||||
it.setVmOptions("-Dmaven=$version")
|
||||
}
|
||||
) {
|
||||
it.processHandler?.addProcessListener(object : ProcessListener {
|
||||
override fun processTerminated(event: ProcessEvent) {
|
||||
if (event.exitCode == 0) {
|
||||
copyFromTempDir(tempDir, workingDir.toNioPath())
|
||||
workingDir.refresh(true, true) {
|
||||
MavenWorkspaceSettingsComponent.getInstance(project).settings.generalSettings.mavenHomeType = MavenWrapper
|
||||
MavenDistributionsCache.getInstance(project).cleanCaches()
|
||||
MavenServerManager.getInstance().shutdownMavenConnectors(project){true}
|
||||
MavenProjectsManager.getInstance(project).forceUpdateAllProjectsOrFindAllAvailablePomFiles()
|
||||
}
|
||||
|
||||
}
|
||||
removeTempDirSafely(tempDir)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyFromTempDir(from: Path, to: Path) {
|
||||
Files.walk(from).use { stream ->
|
||||
stream.forEach { file ->
|
||||
val relative = from.relativize(file)
|
||||
if (!relative.toString().isEmpty()
|
||||
&& !file.name.equals("pom.xml", true)) {
|
||||
val newFile = to.resolve(relative)
|
||||
if (file.isDirectory()) {
|
||||
try {
|
||||
Files.createDirectory(newFile)
|
||||
}
|
||||
catch (_: FileAlreadyExistsException) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
Files.copy(file, newFile, StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
private fun removeTempDirSafely(tempDir: Path) {
|
||||
try {
|
||||
tempDir.deleteRecursively()
|
||||
}
|
||||
catch (_: Throwable) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun createDummyPomContent(): String {
|
||||
return """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>${mavenProject.mavenId.groupId}</groupId>
|
||||
<artifactId>${mavenProject.mavenId.artifactId}</artifactId>
|
||||
<version>${mavenProject.mavenId.version}</version>
|
||||
</project>
|
||||
"""
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inspections
|
||||
|
||||
import com.intellij.codeHighlighting.HighlightDisplayLevel
|
||||
import com.intellij.codeInspection.InspectionManager
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.codeInspection.util.IntentionFamilyName
|
||||
import com.intellij.codeInspection.util.IntentionName
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import com.intellij.psi.xml.XmlTag
|
||||
import com.intellij.util.xml.DomManager
|
||||
import com.intellij.util.xml.highlighting.BasicDomElementsInspection
|
||||
import org.jetbrains.idea.maven.dom.MavenDomBundle
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MODEL_VERSION_4_1_0
|
||||
import org.jetbrains.idea.maven.project.MavenProjectsManager
|
||||
import kotlin.io.path.isDirectory
|
||||
|
||||
class MavenNoRootDefinedInspection : BasicDomElementsInspection<MavenDomProjectModel?>(MavenDomProjectModel::class.java) {
|
||||
override fun getGroupDisplayName(): String {
|
||||
return MavenDomBundle.message("inspection.group")
|
||||
}
|
||||
|
||||
override fun getDefaultLevel(): HighlightDisplayLevel {
|
||||
return HighlightDisplayLevel.WARNING
|
||||
}
|
||||
|
||||
override fun checkFile(file: PsiFile, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor?>? {
|
||||
if (file is XmlFile && file.isPhysical()) {
|
||||
val projectManager = MavenProjectsManager.getInstanceIfCreated(file.project) ?: return null
|
||||
val rootMavenProject = projectManager.rootProjects.singleOrNull { file.virtualFile.equals(it.file) } ?: return null
|
||||
val model =
|
||||
DomManager.getDomManager(file.getProject()).getFileElement<MavenDomProjectModel?>(file, MavenDomProjectModel::class.java)
|
||||
?: return null
|
||||
|
||||
@Suppress("USELESS_ELVIS")
|
||||
//KTLC-284
|
||||
|
||||
val rootElement = model.rootElement ?: return null
|
||||
val rootTag = model.rootTag ?: return null
|
||||
|
||||
if (rootMavenProject.file.parent.toNioPath().resolve(".mvn").isDirectory()) return null;
|
||||
if (rootElement.modelVersion.stringValue == MODEL_VERSION_4_1_0
|
||||
&& model.rootTag?.getAttributeValue("root")?.toBoolean() == true) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
if (rootElement.modelVersion.stringValue == MODEL_VERSION_4_1_0) {
|
||||
return arrayOf(manager.createProblemDescriptor(rootTag,
|
||||
MavenDomBundle.message("inspection.absence.root.dir.description"),
|
||||
arrayOf(fixAddRootTag, fixAddMvnDirectoryInRootDir), ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||
isOnTheFly, false))
|
||||
}
|
||||
return arrayOf(manager.createProblemDescriptor(rootTag,
|
||||
MavenDomBundle.message("inspection.absence.root.dir.description"),
|
||||
fixAddMvnDirectoryInRootDir, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||
isOnTheFly))
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
private val fixAddMvnDirectoryInRootDir: LocalQuickFix = object : LocalQuickFix {
|
||||
override fun getName(): @IntentionName String {
|
||||
return MavenDomBundle.message("inspection.absence.dir.fix.create.dir")
|
||||
}
|
||||
|
||||
override fun getFamilyName(): @IntentionFamilyName String {
|
||||
return MavenDomBundle.message("inspection.absence.root.dir.description")
|
||||
}
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
descriptor.psiElement.containingFile.containingDirectory.createSubdirectory(".mvn")
|
||||
}
|
||||
}
|
||||
|
||||
private val fixAddRootTag: LocalQuickFix = object : LocalQuickFix {
|
||||
override fun getName(): @IntentionName String {
|
||||
return MavenDomBundle.message("inspection.absence.dir.fix.add.root")
|
||||
}
|
||||
|
||||
override fun getFamilyName(): @IntentionFamilyName String {
|
||||
return MavenDomBundle.message("inspection.absence.root.dir.description")
|
||||
}
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
(descriptor.psiElement as? XmlTag)?.setAttribute("root", "true")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inspections;
|
||||
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.util.IntentionFamilyName;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.xml.DomFileElement;
|
||||
import com.intellij.util.xml.DomManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.maven.dom.MavenDomBundle;
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomParent;
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel;
|
||||
|
||||
public final class MavenRedundantGroupIdInspection extends XmlSuppressableInspectionTool implements DumbAware {
|
||||
|
||||
@Override
|
||||
public @NotNull String getGroupDisplayName() {
|
||||
return MavenDomBundle.message("inspection.group");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getShortName() {
|
||||
return "MavenRedundantGroupId";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProblemDescriptor @Nullable [] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
|
||||
if (file instanceof XmlFile && file.isPhysical()) {
|
||||
DomFileElement<MavenDomProjectModel> model =
|
||||
DomManager.getDomManager(file.getProject()).getFileElement((XmlFile)file, MavenDomProjectModel.class);
|
||||
|
||||
if (model != null) {
|
||||
MavenDomProjectModel projectModel = model.getRootElement();
|
||||
|
||||
String groupId = projectModel.getGroupId().getStringValue();
|
||||
if (groupId != null && !groupId.isEmpty()) {
|
||||
MavenDomParent parent = projectModel.getMavenParent();
|
||||
|
||||
String parentGroupId = parent.getGroupId().getStringValue();
|
||||
|
||||
if (groupId.equals(parentGroupId)) {
|
||||
XmlTag xmlTag = projectModel.getGroupId().getXmlTag();
|
||||
|
||||
LocalQuickFix fix = new MavenRedundantGroupIdQuickFix();
|
||||
|
||||
return new ProblemDescriptor[]{
|
||||
manager.createProblemDescriptor(xmlTag,
|
||||
MavenDomBundle.message("inspection.redundant.groupId.fix.description"),
|
||||
fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final class MavenRedundantGroupIdQuickFix implements LocalQuickFix, DumbAware {
|
||||
@Override
|
||||
public @IntentionFamilyName @NotNull String getFamilyName() {
|
||||
return MavenDomBundle.message("inspection.redundant.groupId.fix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
descriptor.getPsiElement().delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inspections
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import com.intellij.psi.xml.XmlTag
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel
|
||||
import org.jetbrains.idea.maven.server.MavenDistribution
|
||||
|
||||
class MavenRedundantGroupIdInspection : AbstractMavenRedundantParentInspection() {
|
||||
override val elementName: String = "groupId"
|
||||
|
||||
override fun getShortName(): String = "MavenRedundantGroupId"
|
||||
|
||||
override fun getXmlTag(projectModel: MavenDomProjectModel): XmlTag? = projectModel.groupId.getXmlTag()
|
||||
|
||||
override fun getSelfValue(projectModel: MavenDomProjectModel): String? = projectModel.groupId.stringValue
|
||||
|
||||
override fun getParentValue(projectModel: MavenDomProjectModel, project: Project): String? = projectModel.mavenParent.groupId.stringValue
|
||||
|
||||
override fun supportedForFile(file: XmlFile): Boolean= true
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom.inspections
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import com.intellij.psi.xml.XmlTag
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel
|
||||
import org.jetbrains.idea.maven.server.MavenDistribution
|
||||
|
||||
|
||||
class MavenRedundantVersionInspection : AbstractMavenRedundantParentInspection() {
|
||||
override val elementName: String = "version"
|
||||
|
||||
override fun getShortName(): String = "MavenRedundantVersion"
|
||||
|
||||
override fun getXmlTag(projectModel: MavenDomProjectModel): XmlTag? = projectModel.version.getXmlTag()
|
||||
|
||||
override fun getSelfValue(projectModel: MavenDomProjectModel): String? = projectModel.version.stringValue
|
||||
|
||||
override fun getParentValue(projectModel: MavenDomProjectModel, project: Project): String? = projectModel.mavenParent.version.stringValue
|
||||
|
||||
override fun supportedForFile(file: XmlFile): Boolean = true
|
||||
}
|
||||
+31
-3
@@ -51,6 +51,7 @@ import org.jetbrains.idea.maven.model.MavenId;
|
||||
import org.jetbrains.idea.maven.model.MavenPlugin;
|
||||
import org.jetbrains.idea.maven.plugins.api.MavenPluginDescriptor;
|
||||
import org.jetbrains.idea.maven.project.MavenProject;
|
||||
import org.jetbrains.idea.maven.project.MavenProjectsManager;
|
||||
import org.jetbrains.idea.maven.project.MavenSettingsCache;
|
||||
import org.jetbrains.idea.maven.utils.MavenUtil;
|
||||
import org.jetbrains.idea.maven.vfs.MavenPropertiesVirtualFileSystem;
|
||||
@@ -162,9 +163,16 @@ public class MavenPropertyPsiReference extends MavenPsiReference implements Loca
|
||||
return myElement;
|
||||
}
|
||||
|
||||
|
||||
if (myText.equals(MULTIPROJECT_DIR_PROP)) {
|
||||
MavenProject rootProject = myProjectsManager.findRootProject(myMavenProject);
|
||||
if(rootProject == null) return null;
|
||||
if (rootProject == null) return null;
|
||||
return getBaseDir(rootProject);
|
||||
}
|
||||
|
||||
if (isModel410() && (myText.equals("project.rootDirectory") || myText.equals("session.rootDirectory") || myText.equals("session.topDirectory"))) {
|
||||
MavenProject rootProject = myProjectsManager.findRootProject(myMavenProject);
|
||||
if (rootProject == null) return null;
|
||||
return getBaseDir(rootProject);
|
||||
}
|
||||
|
||||
@@ -306,6 +314,11 @@ public class MavenPropertyPsiReference extends MavenPsiReference implements Loca
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isModel410() {
|
||||
var e = getElement();
|
||||
return MavenDomUtil.isProjectFileWithModel410(e.getContainingFile());
|
||||
}
|
||||
|
||||
private @Nullable PsiElement resolveToCustomSystemProperty(@NotNull String propertyName, @Nullable String propertyValue) {
|
||||
if (propertyValue == null) return null;
|
||||
|
||||
@@ -319,6 +332,12 @@ public class MavenPropertyPsiReference extends MavenPsiReference implements Loca
|
||||
return PsiManager.getInstance(myProject).findDirectory(mavenProject.getDirectoryFile());
|
||||
}
|
||||
|
||||
private PsiDirectory getRootDir(@NotNull MavenProject mavenProject) {
|
||||
MavenProject root = MavenProjectsManager.getInstance(myProject).findRootProject(mavenProject);
|
||||
if (root == null) return getBaseDir(mavenProject);
|
||||
return PsiManager.getInstance(myProject).findDirectory(root.getDirectoryFile());
|
||||
}
|
||||
|
||||
private PsiElement resolveConfigFileProperty(@SystemIndependent String fileRelativePath, String propertyValue) {
|
||||
VirtualFile baseDir = VfsUtil.findFile(MavenUtil.getBaseDir(myMavenProject.getDirectoryFile()), false);
|
||||
if (baseDir != null) {
|
||||
@@ -360,7 +379,7 @@ public class MavenPropertyPsiReference extends MavenPsiReference implements Loca
|
||||
String pathWithProjectPrefix = "project." + path;
|
||||
|
||||
if (!MavenModelClassesProperties.isPathValid(MavenModelClassesProperties.MAVEN_PROJECT_CLASS, path)
|
||||
&& !MavenModelClassesProperties.isPathValid(MavenModelClassesProperties.MAVEN_MODEL_CLASS, path)) {
|
||||
&& !MavenModelClassesProperties.isPathValid(MavenModelClassesProperties.MAVEN_MODEL_CLASS, path)) {
|
||||
if (!schemaHasProperty(getSchemaUrl(), pathWithProjectPrefix)) return null;
|
||||
}
|
||||
|
||||
@@ -427,6 +446,14 @@ public class MavenPropertyPsiReference extends MavenPsiReference implements Loca
|
||||
|
||||
PsiDirectory baseDir = getBaseDir(mavenProject);
|
||||
addVariant(result, "basedir", baseDir, prefix, RepositoryLibraryLogo);
|
||||
|
||||
if (isModel410()) {
|
||||
PsiDirectory rootDir = getRootDir(mavenProject);
|
||||
addVariant(result, "rootDirectory", rootDir, "project.", RepositoryLibraryLogo);
|
||||
addVariant(result, "rootDirectory", rootDir, "session.", RepositoryLibraryLogo);
|
||||
addVariant(result, "topDirectory", rootDir, "session.", RepositoryLibraryLogo);
|
||||
}
|
||||
addVariant(result, "basedir", baseDir, prefix, RepositoryLibraryLogo);
|
||||
if (prefix == null) {
|
||||
result.add(createLookupElement(baseDir, "project.baseUri", RepositoryLibraryLogo));
|
||||
result.add(createLookupElement(baseDir, "pom.baseUri", RepositoryLibraryLogo));
|
||||
@@ -626,7 +653,7 @@ public class MavenPropertyPsiReference extends MavenPsiReference implements Loca
|
||||
|
||||
@Override
|
||||
public @NotNull LocalQuickFix @Nullable [] getQuickFixes() {
|
||||
return new LocalQuickFix[]{ new MyLocalQuickFix() };
|
||||
return new LocalQuickFix[]{new MyLocalQuickFix()};
|
||||
}
|
||||
|
||||
private static class MyLocalQuickFix implements LocalQuickFix {
|
||||
@@ -648,6 +675,7 @@ public class MavenPropertyPsiReference extends MavenPsiReference implements Loca
|
||||
/**
|
||||
* If "build-helper-maven-plugin" has `parse-version` goal, probably it could resolve properties starting with a defined prefix
|
||||
* to something related to the version from the `version` tag (e.g., `${parsedVersion.majorVersion}`)
|
||||
*
|
||||
* @see <a href="https://www.mojohaus.org/build-helper-maven-plugin/parse-version-mojo.html#propertyPrefix">mojohaus documentation</a>
|
||||
*/
|
||||
private @Nullable PsiElement resolveAsParsedVersion(@NotNull String propertyText, @NotNull MavenProject mavenProject) {
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.editor
|
||||
|
||||
import com.intellij.application.options.editor.WebEditorOptions
|
||||
import com.intellij.ide.plugins.DynamicPluginListener
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.command.CommandEvent
|
||||
import com.intellij.openapi.command.CommandListener
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.editor.event.EditorFactoryEvent
|
||||
import com.intellij.openapi.editor.event.EditorFactoryListener
|
||||
import com.intellij.openapi.editor.impl.EditorImpl
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.idea.maven.project.MavenProjectsManager
|
||||
import kotlin.streams.asSequence
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
class MavenModelVersionSynchronizerService(private val project: Project, val cs: CoroutineScope) {
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
internal val SYNCHRONIZER_KEY: Key<MavenModelVersionSyncronizerImpl> = Key.create("maven.version.xml.sync")
|
||||
|
||||
@JvmField
|
||||
internal val SKIP_COMMAND_KEY: Key<Boolean> = Key.create("maven.version.synchronizer.skip.command")
|
||||
}
|
||||
|
||||
private val writeLock = Semaphore(1)
|
||||
|
||||
|
||||
private fun recreateSynchronizersFor(editors: List<EditorImpl>) {
|
||||
cs.launch {
|
||||
writeLock.withPermit {
|
||||
editors.forEach { editor ->
|
||||
editor.getUserData(SYNCHRONIZER_KEY)?.let {
|
||||
Disposer.dispose(it)
|
||||
}
|
||||
ensureSynchronizerCreated(editor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun scheduleEnsureSynchronizerCreated(editor: EditorImpl) {
|
||||
cs.launch {
|
||||
writeLock.withPermit {
|
||||
ensureSynchronizerCreated(editor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun ensureSynchronizerCreated(editor: EditorImpl) {
|
||||
if (!Registry.`is`("maven.sync.model.editing")) return
|
||||
if (editor.getUserData(SYNCHRONIZER_KEY) != null) return
|
||||
|
||||
val mavenProjectManager = MavenProjectsManager.getInstanceIfCreated(project) ?: return
|
||||
val file = FileDocumentManager.getInstance().getFile(editor.document) ?: return
|
||||
if (mavenProjectManager.findProject(file) == null) return
|
||||
withContext(Dispatchers.EDT) {
|
||||
if (editor.isDisposed || project.isDisposed()) return@withContext
|
||||
MavenModelVersionSyncronizerImpl(editor, project).listenForDocumentChanges()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MyCommandListener : CommandListener {
|
||||
override fun beforeCommandFinished(event: CommandEvent) {
|
||||
findSynchronizers(event.document).forEach { it.beforeCommandFinished() }
|
||||
}
|
||||
|
||||
private fun findSynchronizers(document: Document?): Sequence<MavenModelVersionSyncronizerImpl> =
|
||||
if (document == null || !Registry.`is`("maven.sync.model.editing"))
|
||||
emptySequence()
|
||||
else
|
||||
EditorFactory.getInstance().editors(document, null)
|
||||
.asSequence()
|
||||
.mapNotNull { editor -> editor.getUserData(SYNCHRONIZER_KEY) }
|
||||
}
|
||||
|
||||
class MyDynamicPluginListener : DynamicPluginListener {
|
||||
override fun pluginLoaded(pluginDescriptor: IdeaPluginDescriptor) {
|
||||
recreateSynchronizers()
|
||||
}
|
||||
|
||||
override fun pluginUnloaded(pluginDescriptor: IdeaPluginDescriptor, isUpdate: Boolean) {
|
||||
recreateSynchronizers()
|
||||
}
|
||||
|
||||
private fun recreateSynchronizers() {
|
||||
EditorFactory.getInstance().getAllEditors().groupBy { it.project }.forEach { (project, editors) ->
|
||||
project?.service<MavenModelVersionSynchronizerService>()?.recreateSynchronizersFor(editors.filterIsInstance<EditorImpl>())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MavenModelVersionEditorFactoryListener : EditorFactoryListener {
|
||||
override fun editorCreated(event: EditorFactoryEvent) {
|
||||
val editor = event.editor
|
||||
val project = editor.project
|
||||
project?.service<MavenModelVersionSynchronizerService>()?.scheduleEnsureSynchronizerCreated(editor as? EditorImpl ?: return)
|
||||
}
|
||||
}
|
||||
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
package org.jetbrains.idea.maven.editor
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupManager
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl
|
||||
import com.intellij.lang.xml.XMLLanguage
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.command.undo.UndoManager
|
||||
import com.intellij.openapi.editor.Caret
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.editor.RangeMarker
|
||||
import com.intellij.openapi.editor.event.CaretEvent
|
||||
import com.intellij.openapi.editor.event.CaretListener
|
||||
import com.intellij.openapi.editor.event.DocumentEvent
|
||||
import com.intellij.openapi.editor.event.DocumentListener
|
||||
import com.intellij.openapi.editor.impl.EditorImpl
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.impl.PsiDocumentManagerBase
|
||||
import com.intellij.psi.xml.XmlAttributeValue
|
||||
import com.intellij.psi.xml.XmlElement
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import com.intellij.psi.xml.XmlText
|
||||
import com.intellij.util.containers.addIfNotNull
|
||||
import com.intellij.util.containers.nullize
|
||||
import com.intellij.util.containers.tail
|
||||
import org.jetbrains.idea.maven.editor.MavenModelVersionSynchronizerService.Companion.SKIP_COMMAND_KEY
|
||||
import org.jetbrains.idea.maven.editor.MavenModelVersionSynchronizerService.Companion.SYNCHRONIZER_KEY
|
||||
|
||||
class MavenModelVersionSyncronizerImpl(
|
||||
private val editor: EditorImpl,
|
||||
private val project: Project,
|
||||
) : DocumentListener, Disposable, CaretListener {
|
||||
companion object {
|
||||
private val MARKERS_KEY: Key<List<SynchronizationData>> = Key("maven.version.synchronizer.markers")
|
||||
}
|
||||
|
||||
private var applying = false
|
||||
private val pdm = PsiDocumentManager.getInstance(project) as PsiDocumentManagerBase
|
||||
|
||||
fun listenForDocumentChanges() {
|
||||
Disposer.register(editor.disposable, this)
|
||||
editor.document.addDocumentListener(this, this)
|
||||
val prev = editor.getUserData(SYNCHRONIZER_KEY)
|
||||
if (prev != null && prev !== this) {
|
||||
Disposer.dispose(prev)
|
||||
}
|
||||
editor.putUserData(SYNCHRONIZER_KEY, this)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
editor.putUserData(SYNCHRONIZER_KEY, null)
|
||||
}
|
||||
|
||||
override fun caretRemoved(event: CaretEvent) {
|
||||
val caret = event.getCaret()
|
||||
clearMarkers(caret)
|
||||
}
|
||||
|
||||
override fun beforeDocumentChange(event: DocumentEvent) {
|
||||
val document = event.document
|
||||
val ideProject = project
|
||||
if (applying
|
||||
|| ideProject.isDefault
|
||||
|| UndoManager.getInstance(ideProject).isUndoInProgress
|
||||
|| document.isInBulkUpdate) {
|
||||
return
|
||||
}
|
||||
|
||||
if (document.getUserData(SKIP_COMMAND_KEY) == true) {
|
||||
return
|
||||
}
|
||||
|
||||
val offset = event.offset
|
||||
val oldLen = event.oldLength
|
||||
val fragment = event.newFragment
|
||||
val newLen = event.newLength
|
||||
|
||||
|
||||
for (i in 0 until newLen) {
|
||||
if (!isValidModelSymbols(fragment[i])) {
|
||||
return
|
||||
}
|
||||
}
|
||||
val caret = editor.caretModel.currentCaret
|
||||
|
||||
var markers = getMarkers(caret)
|
||||
|
||||
// if there are changes outside leader
|
||||
markers?.let {
|
||||
if (!fitsInLeader(it.first(), offset, oldLen)) {
|
||||
markers = null
|
||||
clearMarkers(caret)
|
||||
}
|
||||
}
|
||||
|
||||
if (markers == null) {
|
||||
if (pdm.synchronizer.isInSynchronization(document)) return
|
||||
val psiFile = pdm.getPsiFile(document) as? XmlFile ?: return
|
||||
|
||||
val leader = createLeaderMarker(psiFile, document, editor.caretModel.offset) ?: return
|
||||
if (!fitsInLeader(leader, offset, oldLen)) return
|
||||
|
||||
leader.rangeMarker.isGreedyToLeft = true
|
||||
leader.rangeMarker.isGreedyToRight = true
|
||||
|
||||
if (pdm.isUncommited(document)) {
|
||||
pdm.commitDocument(document)
|
||||
}
|
||||
val supports = findSupports(leader, psiFile, document) ?: return
|
||||
setMarkers(caret, leader, supports)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMarkers(caret: Caret, leader: SynchronizationData, followers: List<SynchronizationData>?) {
|
||||
if (followers == null) {
|
||||
clearMarkers(caret)
|
||||
}
|
||||
else {
|
||||
caret.putUserData(MARKERS_KEY, listOf(leader) + followers)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMarkers(caret: Caret): List<SynchronizationData>? {
|
||||
return caret.getUserData(MARKERS_KEY)
|
||||
}
|
||||
|
||||
private fun createLeaderMarker(psiFile: XmlFile, document: Document, offset: Int): SynchronizationData? {
|
||||
val projectElement = psiFile.rootTag
|
||||
val xmlnsElement = projectElement?.getAttribute("xmlns")?.valueElement
|
||||
val schemaElement = projectElement?.getAttribute("xsi:schemaLocation")?.valueElement
|
||||
val modelElement = projectElement?.findSubTags("modelVersion")?.firstOrNull()?.children?.filterIsInstance<XmlText>()?.first()
|
||||
if (xmlnsElement?.textRange?.contains(offset) == true) return fromXmlns(xmlnsElement, document)
|
||||
if (modelElement?.textRange?.contains(offset) == true) return fromModel(modelElement, document)
|
||||
if (schemaElement?.textRange?.contains(offset) == true) return fromSchema(schemaElement, document)?.firstOrNull { it.rangeMarker.contains(offset) }
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
private fun clearMarkers(caret: Caret) {
|
||||
caret.putUserData(MARKERS_KEY, null)
|
||||
}
|
||||
|
||||
|
||||
private fun findSupports(leader: SynchronizationData, psiFile: XmlFile, document: Document): List<SynchronizationData>? {
|
||||
val leaderRange = leader.rangeMarker.textRange
|
||||
val leaderElement = psiFile.getViewProvider().findElementAt(leader.rangeMarker.startOffset, XMLLanguage.INSTANCE) ?: return null
|
||||
val projectElement = psiFile.rootTag
|
||||
|
||||
val xmlnsElement = projectElement?.getAttribute("xmlns")?.valueElement
|
||||
val schemaElement = projectElement?.getAttribute("xsi:schemaLocation")?.valueElement
|
||||
val modelElement = projectElement?.findSubTags("modelVersion")?.firstOrNull()?.children?.filterIsInstance<XmlText>()?.first()
|
||||
|
||||
if (!same(leaderElement, xmlnsElement) && !same(leaderElement, schemaElement) && !same(leaderElement, modelElement)) return null
|
||||
val result = ArrayList<SynchronizationData>()
|
||||
result.addIfNotNull(fromXmlns(xmlnsElement, document))
|
||||
fromSchema(schemaElement, document)?.let { result.addAll(it) }
|
||||
result.addIfNotNull(fromModel(modelElement, document))
|
||||
result.forEach { it.rangeMarker.isGreedyToLeft = true; it.rangeMarker.isGreedyToRight = true }
|
||||
return result.filter { it.rangeMarker.isValid }.filterNot { it.rangeMarker.textRange.intersects(leaderRange) }.nullize()
|
||||
}
|
||||
|
||||
private fun same(leader: PsiElement?, supporter: XmlElement?): Boolean {
|
||||
if (leader == null || supporter == null) return false
|
||||
return leader === supporter || leader.parent === supporter
|
||||
}
|
||||
|
||||
private fun fromXmlns(xmlnsElement: XmlAttributeValue?, document: Document): SynchronizationData? {
|
||||
if (xmlnsElement == null) return null
|
||||
val pomRange = findRangeAfter(xmlnsElement, "maven.apache.org/POM/")
|
||||
return pomRange?.let { document.createRangeMarker(it).synchronizedDots() }
|
||||
|
||||
}
|
||||
|
||||
private fun fromModel(modelElement: XmlText?, document: Document): SynchronizationData? {
|
||||
if (modelElement == null) return null
|
||||
return document.createRangeMarker(modelElement.textRange).synchronizedDots()
|
||||
}
|
||||
|
||||
|
||||
private fun fromSchema(schemaElement: XmlAttributeValue?, document: Document): List<SynchronizationData>? {
|
||||
if (schemaElement == null) return null
|
||||
val result = ArrayList<SynchronizationData>(2)
|
||||
val pomRange = findRangeAfter(schemaElement, "maven.apache.org/POM/")
|
||||
pomRange?.let { result.add(document.createRangeMarker(it).synchronizedDots()) };
|
||||
|
||||
val xsdRange = findRangeAfter(schemaElement, "maven.apache.org/xsd/maven-", ".xsd")
|
||||
xsdRange?.let { result.add(document.createRangeMarker(it).synchronizedDots()) }
|
||||
|
||||
val xsdRangeUnderscores = findRangeAfter(schemaElement, "maven.apache.org/maven-v", ".xsd")
|
||||
xsdRangeUnderscores?.let { result.add(document.createRangeMarker(it).synchronizedUnderscore()) }
|
||||
|
||||
return result.nullize()
|
||||
}
|
||||
|
||||
private fun findRangeAfter(schemaElement: XmlAttributeValue, needle: String, end: String = " "): TextRange? {
|
||||
val value = schemaElement.value
|
||||
val schemaTextRange = schemaElement.valueTextRange
|
||||
|
||||
val foundIndex = value.indexOf(needle)
|
||||
|
||||
if (foundIndex != -1) {
|
||||
val endIndex = value.indexOf(end, foundIndex + needle.length)
|
||||
val endIdx = if (endIndex != -1) endIndex else value.length
|
||||
val start = schemaTextRange.startOffset + foundIndex + needle.length
|
||||
val end = schemaTextRange.startOffset + endIdx
|
||||
if (start <= end) return TextRange(start, end)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun isValidModelSymbols(ch: Char): Boolean {
|
||||
return ch.isLetterOrDigit() || ch in setOf('.', '_')
|
||||
}
|
||||
|
||||
private fun fitsInLeader(leader: SynchronizationData, offset: Int, oldLength: Int): Boolean {
|
||||
return leader.rangeMarker.isValid && offset >= leader.rangeMarker.startOffset && (offset + oldLength) <= leader.rangeMarker.endOffset
|
||||
}
|
||||
|
||||
fun performReplacement(caret: Caret) {
|
||||
val markers = getMarkers(caret) ?: return
|
||||
val document: Document = editor.document
|
||||
val leader = markers.first()
|
||||
val name = getValueToReplace(document, leader)
|
||||
if (markers.any { !it.rangeMarker.isValid } || name == null) {
|
||||
return
|
||||
}
|
||||
val apply = Runnable {
|
||||
markers.tail().forEach {
|
||||
document.replaceString(it.rangeMarker.startOffset, it.rangeMarker.endOffset, it.transformation(name))
|
||||
}
|
||||
}
|
||||
ApplicationManager.getApplication().runWriteAction {
|
||||
val lookup = LookupManager.getActiveLookup(editor) as? LookupImpl
|
||||
if (lookup != null) {
|
||||
lookup.performGuardedChange(apply)
|
||||
}
|
||||
else {
|
||||
apply.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun beforeCommandFinished() {
|
||||
applying = true
|
||||
try {
|
||||
if (editor.caretModel.isIteratingOverCarets) {
|
||||
performReplacement(editor.caretModel.getCurrentCaret())
|
||||
}
|
||||
else {
|
||||
editor.caretModel.runForEachCaret(::performReplacement)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
applying = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun getValueToReplace(document: Document, leader: SynchronizationData): String? {
|
||||
if (document.getTextLength() < leader.rangeMarker.getEndOffset()) {
|
||||
return null
|
||||
}
|
||||
return document.getText(leader.rangeMarker.textRange)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun RangeMarker.synchronizedUnderscore(): SynchronizationData {
|
||||
return SynchronizationData(this){
|
||||
it.replace('.', '_')
|
||||
}
|
||||
}
|
||||
|
||||
private fun RangeMarker.synchronizedDots(): SynchronizationData {
|
||||
return SynchronizationData(this){
|
||||
it.replace('_', '.')
|
||||
}
|
||||
}
|
||||
|
||||
private data class SynchronizationData(val rangeMarker: RangeMarker, val transformation: (String) -> String)
|
||||
@@ -548,15 +548,6 @@ class MavenProject(val file: VirtualFile) {
|
||||
return myState.dependencyTree
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
val supportedPackagings: Set<String>
|
||||
get() {
|
||||
val result = mutableSetOf(MavenConstants.TYPE_POM, MavenConstants.TYPE_JAR, "ejb", "ejb-client", "war", "ear", "bundle", "maven-plugin")
|
||||
for (each: MavenImporter in MavenImporter.getSuitableImporters(this)) {
|
||||
each.getSupportedPackagings(result)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun getDependencyTypesFromImporters(type: SupportedRequestType): Set<String> {
|
||||
val res: MutableSet<String> = HashSet()
|
||||
|
||||
+10
-7
@@ -122,7 +122,6 @@ public abstract class MavenProjectsManager extends MavenSimpleProjectComponent
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void loadState(@NotNull MavenProjectsManagerState state) {
|
||||
myState = state;
|
||||
@@ -159,7 +158,7 @@ public abstract class MavenProjectsManager extends MavenSimpleProjectComponent
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public File getLocalRepository() {
|
||||
return MavenSettingsCache.getInstance(myProject).getEffectiveUserLocalRepo().toFile();
|
||||
return MavenSettingsCache.getInstance(myProject).getEffectiveUserLocalRepo().toFile();
|
||||
}
|
||||
|
||||
public Path getRepositoryPath() {
|
||||
@@ -254,6 +253,7 @@ public abstract class MavenProjectsManager extends MavenSimpleProjectComponent
|
||||
scheduleUpdateAllMavenProjects(MavenSyncSpec.full("MavenProjectsManager.onProjectStartup"));
|
||||
}
|
||||
}
|
||||
|
||||
private void initProjectsTree() {
|
||||
initLock.lock();
|
||||
try {
|
||||
@@ -289,12 +289,13 @@ public abstract class MavenProjectsManager extends MavenSimpleProjectComponent
|
||||
Update update = new Update(this) {
|
||||
@Override
|
||||
public void run() {
|
||||
saveTree();
|
||||
saveTree();
|
||||
}
|
||||
};
|
||||
if (MavenUtil.isMavenUnitTestModeEnabled()) {
|
||||
mySaveQueue.queue(update);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
MergingQueueUtil.queueTracked(mySaveQueue, update);
|
||||
}
|
||||
}
|
||||
@@ -383,7 +384,9 @@ public abstract class MavenProjectsManager extends MavenSimpleProjectComponent
|
||||
if (!isInitialized()) {
|
||||
doInit();
|
||||
doActivate();
|
||||
var distributionUrl = getWrapperDistributionUrl(ProjectUtil.guessProjectDir(myProject));
|
||||
var baseDir = ProjectUtil.guessProjectDir(myProject);
|
||||
|
||||
var distributionUrl = baseDir == null ? null : getWrapperDistributionUrl(baseDir.toNioPath());
|
||||
if (distributionUrl != null) {
|
||||
getGeneralSettings().setMavenHomeType(MavenWrapper.INSTANCE);
|
||||
}
|
||||
@@ -662,8 +665,8 @@ public abstract class MavenProjectsManager extends MavenSimpleProjectComponent
|
||||
}
|
||||
|
||||
public void updateProjectTargetFolders() {
|
||||
if (myProject.isDisposed()) return;
|
||||
MavenProjectImporter.scheduleUpdateTargetFolders(myProject);
|
||||
if (myProject.isDisposed()) return;
|
||||
MavenProjectImporter.scheduleUpdateTargetFolders(myProject);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.idea.maven.server
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.idea.maven.utils.MavenUtil
|
||||
import java.nio.file.Path
|
||||
@@ -8,7 +9,7 @@ import java.nio.file.Path
|
||||
interface MavenDistribution {
|
||||
val name: String
|
||||
val mavenHome: Path
|
||||
val version: String?
|
||||
val version: @NlsSafe String?
|
||||
fun isValid(): Boolean
|
||||
fun compatibleWith(mavenDistribution: MavenDistribution): Boolean
|
||||
}
|
||||
|
||||
+27
-10
@@ -50,6 +50,7 @@ public final class MavenDistributionsCache {
|
||||
}
|
||||
|
||||
public void cleanCaches() {
|
||||
MavenWrapperDownloader.invalidateCaches();
|
||||
mySettingsDistribution.drop();
|
||||
myWorkingDirToMultiModuleMap.clear();
|
||||
myMultimoduleDirToWrapperedMavenDistributionsMap.clear();
|
||||
@@ -107,6 +108,20 @@ public final class MavenDistributionsCache {
|
||||
return myVmSettingsMap.computeIfAbsent(multiModuleDir, MavenExternalParameters::readJvmConfigOptions);
|
||||
}
|
||||
|
||||
|
||||
public @NotNull MavenDistribution getMavenDistribution(@Nullable VirtualFile file) {
|
||||
if (!useWrapper() || file == null) {
|
||||
return mySettingsDistribution.getValue();
|
||||
}
|
||||
|
||||
if (file.isDirectory()) {
|
||||
return getMavenDistribution(file.getPath());
|
||||
}
|
||||
else {
|
||||
return getMavenDistribution(file.getParent());
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull MavenDistribution getMavenDistribution(@Nullable String workingDirectory) {
|
||||
if (!useWrapper() || workingDirectory == null) {
|
||||
return mySettingsDistribution.getValue();
|
||||
@@ -145,7 +160,8 @@ public final class MavenDistributionsCache {
|
||||
if (PluginManagerCore.isRunningFromSources()) { // running from sources
|
||||
Path mavenPath = mySourcePath.getValue();
|
||||
return new LocalMavenDistribution(mavenPath, BundledMaven3.INSTANCE.getTitle());
|
||||
} else if (mavenPlugin != null) { // running with production classloading. Use maven3 folder inside maven plugin layout
|
||||
}
|
||||
else if (mavenPlugin != null) { // running with production classloading. Use maven3 folder inside maven plugin layout
|
||||
Path pathToBundledMaven = mavenPlugin.getPluginPath().resolve("lib").resolve("maven3");
|
||||
return new LocalMavenDistribution(pathToBundledMaven, BundledMaven3.INSTANCE.getTitle());
|
||||
}
|
||||
@@ -163,11 +179,12 @@ public final class MavenDistributionsCache {
|
||||
|
||||
@Nullable
|
||||
String getWrapperDistributionUrl(String multimoduleDirectory) {
|
||||
VirtualFile baseDir = LocalFileSystem.getInstance().findFileByPath(multimoduleDirectory);
|
||||
if (baseDir == null) {
|
||||
return null;
|
||||
}
|
||||
return MavenWrapperSupport.getWrapperDistributionUrl(baseDir);
|
||||
return getWrapperDistributionUrl(Path.of(multimoduleDirectory));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getWrapperDistributionUrl(Path multimoduleDirectory) {
|
||||
return MavenWrapperSupport.getWrapperDistributionUrl(multimoduleDirectory);
|
||||
}
|
||||
|
||||
private @NotNull String resolveMultiModuleDirectory(@NotNull String workingDirectory) {
|
||||
@@ -176,10 +193,10 @@ public final class MavenDistributionsCache {
|
||||
return FileUtilRt.toSystemIndependentName(calculateMultimoduleDirUpToFileTree(workingDirectory));
|
||||
}
|
||||
return FileUtilRt.toSystemIndependentName(manager.getRootProjects().stream()
|
||||
.map(MavenProject::getDirectory)
|
||||
.filter(rpDirectory -> FileUtil.isAncestor(rpDirectory, workingDirectory, false))
|
||||
.findFirst()
|
||||
.orElseGet(() -> calculateMultimoduleDirUpToFileTree(workingDirectory)));
|
||||
.map(MavenProject::getDirectory)
|
||||
.filter(rpDirectory -> FileUtil.isAncestor(rpDirectory, workingDirectory, false))
|
||||
.findFirst()
|
||||
.orElseGet(() -> calculateMultimoduleDirUpToFileTree(workingDirectory)));
|
||||
}
|
||||
|
||||
private @NotNull String calculateMultimoduleDirUpToFileTree(String directory) {
|
||||
|
||||
+6
-1
@@ -17,6 +17,7 @@ import org.jetbrains.idea.maven.project.MavenWorkspaceSettings;
|
||||
import org.jetbrains.idea.maven.project.MavenWorkspaceSettingsComponent;
|
||||
import org.jetbrains.idea.maven.utils.MavenLog;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
public final class MavenWrapperDownloader {
|
||||
@@ -31,6 +32,10 @@ public final class MavenWrapperDownloader {
|
||||
checkOrInstall(project, workingDir, MavenProjectsManager.getInstance(project).getSyncConsole(), showNotificationIfUrlMissing);
|
||||
}
|
||||
|
||||
public static void invalidateCaches() {
|
||||
MavenWrapperMapping.getInstance().invalidate();
|
||||
}
|
||||
|
||||
private static synchronized void checkOrInstall(@NotNull Project project,
|
||||
@Nullable String workingDir,
|
||||
@Nullable MavenSyncConsole syncConsole,
|
||||
@@ -59,7 +64,7 @@ public final class MavenWrapperDownloader {
|
||||
try {
|
||||
distribution = new MavenWrapperSupport().downloadAndInstallMaven(distributionUrl, indicator, project);
|
||||
if (syncConsole != null && distributionUrl.toLowerCase(Locale.ENGLISH).startsWith("http:")) {
|
||||
MavenWrapperSupport.showUnsecureWarning(syncConsole, LocalFileSystem.getInstance().findFileByPath(multiModuleDir));
|
||||
MavenWrapperSupport.showUnsecureWarning(syncConsole, Path.of(multiModuleDir));
|
||||
}
|
||||
distributionsCache.addWrapper(multiModuleDir, distribution);
|
||||
if (syncConsole != null) syncConsole.finishWrapperResolving(null);
|
||||
|
||||
+5
-3
@@ -16,6 +16,7 @@ import org.jetbrains.idea.maven.execution.SyncBundle.message
|
||||
import org.jetbrains.idea.maven.project.MavenProjectBundle
|
||||
import org.jetbrains.idea.maven.server.MavenWrapperSupport.Companion.getWrapperProperties
|
||||
import org.jetbrains.idea.maven.statistics.MavenNotificationDisplayIds
|
||||
import java.nio.file.Path
|
||||
|
||||
class MavenWrapperEventLogNotification {
|
||||
companion object {
|
||||
@@ -23,7 +24,7 @@ class MavenWrapperEventLogNotification {
|
||||
fun noDistributionUrlEvent(project: Project, multiModuleDir: String) {
|
||||
val notificationGroup = NotificationGroupManager.getInstance().getNotificationGroup("Maven") ?: return
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
val wrapperPropertyFile = LocalFileSystem.getInstance().findFileByPath(multiModuleDir)?.let { getWrapperProperties(it) }
|
||||
val wrapperPropertyFile = LocalFileSystem.getInstance().findFileByPath(multiModuleDir)?.let { getWrapperProperties(it.toNioPath()) }
|
||||
if (wrapperPropertyFile == null) {
|
||||
wrapperPropertyFileNotFound(notificationGroup, project)
|
||||
}
|
||||
@@ -84,7 +85,8 @@ class MavenWrapperEventLogNotification {
|
||||
|
||||
private fun distributionUrlEmpty(notificationGroup: NotificationGroup,
|
||||
project: Project,
|
||||
wrapperPropertyFile: VirtualFile) {
|
||||
wrapperPropertyFile: Path
|
||||
) {
|
||||
notificationGroup
|
||||
.createNotification(
|
||||
message("maven.wrapper.notification.title"),
|
||||
@@ -93,7 +95,7 @@ class MavenWrapperEventLogNotification {
|
||||
)
|
||||
.setDisplayId(MavenNotificationDisplayIds.WRAPPER_EMPTY_URL)
|
||||
.addAction(NotificationAction.createSimple(message("maven.wrapper.notification.empty.url.action.check")) {
|
||||
showFile(project, wrapperPropertyFile.toNioPath(), null)
|
||||
showFile(project, wrapperPropertyFile, null)
|
||||
})
|
||||
.addAction(NotificationAction.createSimple(message("maven.wrapper.notification.empty.url.action.disable")) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(project,
|
||||
|
||||
+15
-13
@@ -9,7 +9,6 @@ import com.intellij.openapi.externalSystem.util.environment.Environment
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.eel.isPosix
|
||||
import com.intellij.platform.eel.provider.LocalEelDescriptor
|
||||
import com.intellij.platform.eel.provider.getEelDescriptor
|
||||
@@ -30,10 +29,7 @@ import java.nio.file.attribute.PosixFilePermissions
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.*
|
||||
|
||||
@State(name = "MavenWrapperMapping",
|
||||
storages = [Storage(value = "maven.wrapper.mapping.xml", roamingType = RoamingType.PER_OS)],
|
||||
@@ -52,6 +48,10 @@ internal class MavenWrapperMapping : PersistentStateComponent<MavenWrapperMappin
|
||||
myState.mapping.putAll(state.mapping)
|
||||
}
|
||||
|
||||
fun invalidate() {
|
||||
myState.mapping.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(): MavenWrapperMapping {
|
||||
@@ -74,7 +74,7 @@ internal class MavenWrapperSupport {
|
||||
indicator?.apply { text = SyncBundle.message("maven.sync.wrapper.downloading.from", urlString) }
|
||||
try {
|
||||
HttpRequests.request(urlString)
|
||||
.tuner{
|
||||
.tuner {
|
||||
val username = Environment.getVariable("MVNW_USERNAME")
|
||||
val password = Environment.getVariable("MVNW_PASSWORD")
|
||||
if (!username.isNullOrBlank() && !password.isNullOrBlank()) {
|
||||
@@ -177,6 +177,7 @@ internal class MavenWrapperSupport {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun getZipFile(distributionUrl: String, project: Project): Path {
|
||||
val baseName: String = getDistName(distributionUrl)
|
||||
val distName: String = FileUtil.getNameWithoutExtension(baseName)
|
||||
@@ -208,13 +209,13 @@ internal class MavenWrapperSupport {
|
||||
private val DISTRIBUTION_URL_PROPERTY = "distributionUrl"
|
||||
|
||||
@JvmStatic
|
||||
fun getWrapperDistributionUrl(baseDir: VirtualFile?): String? {
|
||||
fun getWrapperDistributionUrl(baseDir: Path?): String? {
|
||||
try {
|
||||
val wrapperProperties = getWrapperProperties(baseDir) ?: return null
|
||||
|
||||
val properties = Properties()
|
||||
|
||||
val stream = ByteArrayInputStream(wrapperProperties.contentsToByteArray(true))
|
||||
val stream = ByteArrayInputStream(wrapperProperties.readBytes())
|
||||
properties.load(stream)
|
||||
val configuredProperty = properties.getProperty(DISTRIBUTION_URL_PROPERTY)
|
||||
val urlBase = Environment.getVariable("MVNW_REPOURL")
|
||||
@@ -233,13 +234,13 @@ internal class MavenWrapperSupport {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showUnsecureWarning(console: MavenSyncConsole, mavenProjectMultimodulePath: VirtualFile?) {
|
||||
fun showUnsecureWarning(console: MavenSyncConsole, mavenProjectMultimodulePath: Path?) {
|
||||
val properties = getWrapperProperties(mavenProjectMultimodulePath)
|
||||
|
||||
val line = properties?.inputStream?.bufferedReader(properties.charset)?.readLines()?.indexOfFirst {
|
||||
val line = properties?.readLines()?.indexOfFirst {
|
||||
it.startsWith(DISTRIBUTION_URL_PROPERTY)
|
||||
} ?: -1
|
||||
val position = properties?.let { FilePosition(it.toNioPath().toFile(), line, 0) }
|
||||
val position = properties?.let { FilePosition(it.toFile(), line, 0) }
|
||||
console.addWarning(SyncBundle.message("maven.sync.wrapper.http.title"),
|
||||
SyncBundle.message("maven.sync.wrapper.http.description"),
|
||||
position)
|
||||
@@ -254,6 +255,7 @@ internal class MavenWrapperSupport {
|
||||
MavenWrapperMapping.getInstance().myState.mapping[createDistributionKey(project, urlString)] = path.toAbsolutePath().toString()
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic
|
||||
fun getCurrentDistribution(project: Project, urlString: String): MavenDistribution? {
|
||||
val mapping = MavenWrapperMapping.getInstance()
|
||||
@@ -272,7 +274,7 @@ internal class MavenWrapperSupport {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getWrapperProperties(baseDir: VirtualFile?) =
|
||||
baseDir?.findChild(".mvn")?.findChild("wrapper")?.findChild("maven-wrapper.properties")
|
||||
fun getWrapperProperties(baseDir: Path?): Path? =
|
||||
baseDir?.resolve(".mvn")?.resolve("wrapper")?.resolve("maven-wrapper.properties")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,6 @@ import java.util.stream.Stream
|
||||
import java.util.zip.CRC32
|
||||
import javax.xml.parsers.ParserConfigurationException
|
||||
import javax.xml.parsers.SAXParserFactory
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.isDirectory
|
||||
|
||||
object MavenUtil {
|
||||
@@ -1985,12 +1984,14 @@ object MavenUtil {
|
||||
fun isMaven410(xmlns: String?, schemaLocation: String?): Boolean {
|
||||
if (xmlns == null || schemaLocation == null) return false
|
||||
val schemaLocations = schemaLocation.split(' ')
|
||||
return (xmlns == MAVEN_4_XLMNS || xmlns == MAVEN_4_XLMNS_HTTPS)
|
||||
return (xmlns == MAVEN_4_XMLNS || xmlns == MAVEN_4_XMLNS_HTTPS)
|
||||
&& schemaLocations.all {
|
||||
it == MAVEN_4_XLMNS ||
|
||||
it == MAVEN_4_XLMNS_HTTPS ||
|
||||
it == MAVEN_4_XMLNS ||
|
||||
it == MAVEN_4_XMLNS_HTTPS ||
|
||||
it == MAVEN_4_XSD ||
|
||||
it == MAVEN_4_XSD_HTTPS
|
||||
it == MAVEN_4_XSD_HTTPS ||
|
||||
it == MAVEN_4_XSD_UNDERSCORE ||
|
||||
it == MAVEN_4_XSD_HTTPS_UNDERSCORE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -18,7 +18,6 @@ import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.progress.coroutineToIndicator
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
@@ -158,7 +157,7 @@ class MavenProjectAsyncBuilder {
|
||||
tree.addManagedFilesWithProfiles(files, MavenExplicitProfiles.NONE)
|
||||
|
||||
generalSettings.updateFromMavenConfig(files)
|
||||
updateMavenSettingsFromEnvironment(project, generalSettings, importingSettings)
|
||||
updateMavenSettingsFromEnvironment(project, generalSettings, importingSettings, rootDirectory)
|
||||
MavenSettingsCache.getInstance(project).reloadAsync()
|
||||
|
||||
val manager = MavenProjectsManager.getInstance(project)
|
||||
@@ -210,6 +209,7 @@ class MavenProjectAsyncBuilder {
|
||||
project: Project,
|
||||
generalSettings: MavenGeneralSettings,
|
||||
importingSettings: MavenImportingSettings,
|
||||
rootDirectory: Path,
|
||||
) {
|
||||
val settings = MavenWorkspaceSettingsComponent.getInstance(project).settings
|
||||
settings.generalSettings = generalSettings
|
||||
@@ -218,7 +218,7 @@ class MavenProjectAsyncBuilder {
|
||||
if (!settingsFile.isNullOrBlank()) {
|
||||
settings.generalSettings.setUserSettingsFile(settingsFile.trim { it <= ' ' })
|
||||
}
|
||||
val distributionUrl = getWrapperDistributionUrl(project.guessProjectDir())
|
||||
val distributionUrl = getWrapperDistributionUrl(rootDirectory)
|
||||
if (distributionUrl != null) {
|
||||
settings.generalSettings.mavenHomeType = MavenWrapper
|
||||
}
|
||||
|
||||
@@ -58,7 +58,8 @@
|
||||
|
||||
<extensionPoint name="mavenAdditionalHighlighter" interface="org.jetbrains.idea.maven.dom.MavenAdditionalHightligher" dynamic="true"/>
|
||||
|
||||
<extensionPoint name="mavenRemoteConnectionCreator" interface="org.jetbrains.idea.maven.execution.MavenRemoteConnectionCreator" dynamic="true"/>
|
||||
<extensionPoint name="mavenRemoteConnectionCreator" interface="org.jetbrains.idea.maven.execution.MavenRemoteConnectionCreator"
|
||||
dynamic="true"/>
|
||||
</extensionPoints>
|
||||
|
||||
<dependencies>
|
||||
@@ -224,6 +225,14 @@
|
||||
key="inspection.redundant.groupId.name"
|
||||
groupKey="inspection.group" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="org.jetbrains.idea.maven.dom.inspections.MavenRedundantGroupIdInspection"/>
|
||||
<localInspection language="XML" shortName="MavenRedundantVersion" bundle="messages.MavenDomBundle"
|
||||
key="inspection.redundant.version.name"
|
||||
groupKey="inspection.group" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="org.jetbrains.idea.maven.dom.inspections.MavenRedundantVersionInspection"/>
|
||||
<localInspection language="XML" shortName="MavenNoRootDefined" bundle="messages.MavenDomBundle"
|
||||
key="inspection.no.root.defined.name"
|
||||
groupKey="inspection.group" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="org.jetbrains.idea.maven.dom.inspections.MavenNoRootDefinedInspection"/>
|
||||
<localInspection language="XML" shortName="MavenPropertyInParent" bundle="messages.MavenDomBundle"
|
||||
key="inspection.property.in.parent.name"
|
||||
groupKey="inspection.group" enabledByDefault="true" level="WARNING"
|
||||
@@ -244,6 +253,26 @@
|
||||
groupKey="inspection.group" enabledByDefault="true" level="ERROR"
|
||||
implementationClass="org.jetbrains.idea.maven.dom.inspections.MavenNewModelVersionInOldSchemaInspection"/>
|
||||
|
||||
<localInspection language="XML" shortName="MavenNewModelVersionInOldMaven" bundle="messages.MavenDomBundle"
|
||||
key="inspection.new.model.version.with.old.maven"
|
||||
groupKey="inspection.group" enabledByDefault="true" level="ERROR"
|
||||
implementationClass="org.jetbrains.idea.maven.dom.inspections.MavenNewModelVersionInOldMavenInspection"/>
|
||||
|
||||
<localInspection language="XML" shortName="MavenBomPackagingInOldSchema" bundle="messages.MavenDomBundle"
|
||||
key="inspection.new.packaging.in.old.model.name"
|
||||
groupKey="inspection.group" enabledByDefault="true" level="ERROR"
|
||||
implementationClass="org.jetbrains.idea.maven.dom.inspections.MavenBomPackagingInOldSchema"/>
|
||||
|
||||
<localInspection language="XML" shortName="Maven4RedundantParentCoordinates" bundle="messages.MavenDomBundle"
|
||||
key="inspection.redundant.parent.coordinates.maven.4"
|
||||
groupKey="inspection.group" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="org.jetbrains.idea.maven.dom.inspections.Maven4RedundantParentCoordinatesInspection"/>
|
||||
|
||||
<localInspection language="XML" shortName="MavenModulesInMaven4" bundle="messages.MavenDomBundle"
|
||||
key="inspection.modules.tag.in.maven.4"
|
||||
groupKey="inspection.group" enabledByDefault="true" level="WARNING"
|
||||
implementationClass="org.jetbrains.idea.maven.dom.inspections.MavenModulesInMaven4Inspection"/>
|
||||
|
||||
<xml.xmlExtension implementation="org.jetbrains.idea.maven.dom.MavenXmlExtension"/>
|
||||
<dom.extender domClass="org.jetbrains.idea.maven.dom.model.MavenDomConfiguration"
|
||||
extenderClass="org.jetbrains.idea.maven.dom.MavenPluginConfigurationDomExtender"/>
|
||||
@@ -313,6 +342,12 @@
|
||||
<codeInsight.unresolvedReferenceQuickFixProvider
|
||||
implementation="org.jetbrains.idea.maven.dom.intentions.AddMavenDependencyQuickFixProvider"/>
|
||||
|
||||
<codeInsight.declarativeInlayProvider language="XML"
|
||||
implementationClass="org.jetbrains.idea.maven.dom.inlay.MavenModelVersionInlayHintProvider"
|
||||
providerId="maven.pom.model.version.hints" group="OTHER_GROUP" isEnabledByDefault="true"
|
||||
bundle="messages.MavenDomBundle" nameKey="maven.version.inlay.hint.name"
|
||||
descriptionKey="maven.version.inlay.hint.description"/>
|
||||
|
||||
<gotoFileContributor implementation="org.jetbrains.idea.maven.utils.MavenGotoFileContributor"/>
|
||||
<gotoFileContributor implementation="org.jetbrains.idea.maven.utils.MavenGotoSettingsFileContributor"/>
|
||||
<gotoFileContributor implementation="org.jetbrains.idea.maven.vfs.MavenGotoPropertyFileContributor"/>
|
||||
@@ -349,6 +384,10 @@
|
||||
implementation="org.jetbrains.idea.maven.statistics.MavenLibraryCoordinatesWhitelistValidationRule"/>
|
||||
|
||||
|
||||
<editorFactoryListener implementation="org.jetbrains.idea.maven.editor.MavenModelVersionEditorFactoryListener"/>
|
||||
<registryKey key="maven.sync.model.editing" defaultValue="true"
|
||||
description="Synchronize editing model and xmlns in pom.xml"/>
|
||||
|
||||
<registryKey key="maven.collect.local.stat" defaultValue="false"
|
||||
description="Collect local maven statistics. Used in Internal mode. Does not affect FUS"/>
|
||||
|
||||
@@ -997,5 +1036,10 @@
|
||||
<listener class="org.jetbrains.idea.maven.plugins.compatibility.PluginCompatibilityConfiguratorListener"
|
||||
topic="org.jetbrains.idea.maven.project.MavenSyncListener"
|
||||
activeInTestMode="false" activeInHeadlessMode="false"/>
|
||||
|
||||
<listener class="org.jetbrains.idea.maven.editor.MavenModelVersionSynchronizerService$MyCommandListener"
|
||||
topic="com.intellij.openapi.command.CommandListener"/>
|
||||
<listener class="org.jetbrains.idea.maven.editor.MavenModelVersionSynchronizerService$MyDynamicPluginListener"
|
||||
topic="com.intellij.ide.plugins.DynamicPluginListener"/>
|
||||
</applicationListeners>
|
||||
</idea-plugin>
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>/*<# Compatible with Maven 4 #>*/
|
||||
<groupId>group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports redundant parent coordinates for Maven 4 projects
|
||||
</body>
|
||||
</html>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Ensures that the new Maven packaging does not appear in the legacy model version
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports the presence of the <modules> tag in the Maven 4.1.0 model version
|
||||
</body>
|
||||
</html>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Reporst about old maven version in projects with model 4.1.0
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports the absence of the .mvn directory/root tag, or when .mvn is located above the managed root project
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports an unnecessary <version> definition, as it is already specified in the parent pom.xml
|
||||
</body>
|
||||
</html>
|
||||
@@ -12,6 +12,10 @@
|
||||
"id": "MavenRedundantGroupId",
|
||||
"codeQualityCategory": "Sanity"
|
||||
},
|
||||
{
|
||||
"id": "MavenRedundantVersion",
|
||||
"codeQualityCategory": "Sanity"
|
||||
},
|
||||
{
|
||||
"id": "MavenDuplicatePluginInspection",
|
||||
"codeQualityCategory": "Sanity"
|
||||
@@ -20,6 +24,10 @@
|
||||
"id": "MavenParentMissedVersionInspection",
|
||||
"codeQualityCategory": "Sanity"
|
||||
},
|
||||
{
|
||||
"id": "Maven4RedundantParentCoordinates",
|
||||
"codeQualityCategory": "Sanity"
|
||||
},
|
||||
{
|
||||
"id": "MavenPropertyInParent",
|
||||
"codeQualityCategory": "Reliability"
|
||||
@@ -31,6 +39,10 @@
|
||||
{
|
||||
"id": "MavenNewElementsInOldSchema",
|
||||
"codeQualityCategory": "Reliability"
|
||||
},
|
||||
{
|
||||
"id": "MavenNoRootDefined",
|
||||
"codeQualityCategory": "Reliability"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -36,18 +36,30 @@ inspection.duplicate.dependencies.name=Duplicate Dependencies
|
||||
inspection.duplicate.plugin.declaration=Duplicate plugin declaration
|
||||
MavenDuplicateDependenciesInspection.has.duplicates=<html><body>Dependency is duplicated in file(s)#treeend: {0} </body></html>
|
||||
inspection.redundant.groupId.name=Redundant groupId
|
||||
inspection.redundant.version.name=Redundant version
|
||||
inspection.redundant.packaging.name=Redundant packaging
|
||||
inspection.no.root.defined.name=Multi-module directory is not defined
|
||||
|
||||
inspection.missed.parent.version=Parent version missed
|
||||
inspection.missed.parent.groupIdArtifactId=Parent groupId or artifactId is missing
|
||||
|
||||
inspection.redundant.groupId.fix=Remove unnecessary <groupId>
|
||||
inspection.redundant.groupId.fix.description=Definition of groupId is redundant, because it's inherited from the parent
|
||||
inspection.redundant.element.fix=Remove unnecessary {0}
|
||||
inspection.redundant.element.fix.description=Definition of {0} is redundant, because it''s inherited from the parent
|
||||
inspection.property.in.parent.name=Usage of properties in parent description
|
||||
inspection.property.in.parent.description=Properties in parent definition are prohibited
|
||||
fix.ignore.unresolved.maven.property=Ignore unresolved maven property
|
||||
|
||||
inspection.redundant.parent.coordinates.maven.4=The parent coordinates are redundant and not required in Maven 4
|
||||
inspection.redundant.parent.coordinates.maven.4.clean=Remove unnecessary tags
|
||||
|
||||
|
||||
inspection.absence.root.dir.description=Multi-module directory should be defined for all maven projects
|
||||
inspection.absence.dir.fix.create.dir=Create .mvn dir
|
||||
inspection.absence.dir.fix.add.root=Add root="true" tag (Maven 4 only)
|
||||
|
||||
inspection.modules.tag.in.maven.4=The <modules> tag is deprecated; use <subprojects> instead
|
||||
inspection.modules.tag.in.maven.4.name=Change to <subprojects>
|
||||
|
||||
property.introduce.name=Name
|
||||
property.introduce.value=Value
|
||||
property.title.add=Add Maven Property
|
||||
@@ -66,9 +78,10 @@ maven.search.results.list.accessible.name=Search results
|
||||
maven.search.text.field.accessible.name=Search
|
||||
maven.dom.quickfix.add.maven.dependency=Add Maven Dependency
|
||||
maven.type.name.property=Property
|
||||
inspection.message.unsupported.model.version.only.version.supported=Unsupported model version. Only versions {0} are supported.
|
||||
inspection.message.unsupported.model.version.only.version.supported=Unsupported model version. Only versions {0} are supported in current Maven version ({1})
|
||||
text.property=Property
|
||||
text.model.property=Model property
|
||||
maven.version.tip=Maven version: {0}
|
||||
artifact.0.not.found=Artifact ''{0}'' not found
|
||||
dependency.0.not.found=Dependency ''{0}'' not found
|
||||
project.0.not.found=Project ''{0}'' not found
|
||||
@@ -84,4 +97,12 @@ plugin.model.doc.required=Required
|
||||
|
||||
inspection.missed.model.version='modelVersion' child tag should be defined
|
||||
inspection.wrong.model.version=Wrong model version. Model version should be 4.1.0 for this tag
|
||||
inspection.new.model.version.in.old.schema=Model version 4.1.0 is required for projects with 4.1.0 schema
|
||||
inspection.new.model.version.in.old.schema=Model version 4.1.0 is required for projects with 4.1.0 schema
|
||||
inspection.new.model.version.with.old.maven=Maven version 4+ is required for projects with 4.1.0 schema
|
||||
inspection.new.packaging.in.old.model=Model version 4.1.0 is required for packaging {0}
|
||||
inspection.new.packaging.in.old.model.name=Model version 4.1.0 is required for the packaging
|
||||
|
||||
maven.version.inlay.hint.name=Maven Version
|
||||
maven.version.inlay.hint.description=Shows Maven version for the model
|
||||
maven.version.inlay.hint.text.3=Compatible with Maven 3
|
||||
maven.version.inlay.hint.text.4=Compatible with Maven 4
|
||||
|
||||
@@ -18,7 +18,7 @@ maven.sync.quickfixes.maven360=You use Maven 3.6.0, there could be issues import
|
||||
|
||||
maven.sync.quickfixes.upgrade.to.jdk7=Maven version {0} requires at least JDK version 1.7
|
||||
maven.sync.quickfixes.maven.version.title=Maven version issue
|
||||
maven.sync.quickfixes.open.settings=Open Settings
|
||||
maven.sync.quickfixes.update.maven.version=Update Maven version to {0}
|
||||
maven.sync.quickfixes.use.bundled.settings=Use Bundled {0}
|
||||
|
||||
maven.sync.quickfixes.repository.blocked.title=Since Maven 3.8.1 http repositories are blocked
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom
|
||||
|
||||
import com.intellij.ide.highlighter.XmlFileType
|
||||
import com.intellij.maven.testFramework.MavenTestCase
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiFileFactory
|
||||
|
||||
|
||||
class MavenDomUtilTest : MavenTestCase() {
|
||||
|
||||
fun testIsProjectFileWithModel400() {
|
||||
assertFalse(MavenDomUtil.isProjectFileWithModel410(
|
||||
createXmlFile("""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
))
|
||||
}
|
||||
|
||||
fun testIsProjectFileWithModel410() {
|
||||
assertTrue(MavenDomUtil.isProjectFileWithModel410(
|
||||
createXmlFile("""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
))
|
||||
}
|
||||
|
||||
fun testIsProjectFileWithModel410Incomplete() {
|
||||
assertFalse(MavenDomUtil.isProjectFileWithModel410(
|
||||
createXmlFile("""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
fun testIsProjectFileWithModel410Incomplete2() {
|
||||
assertFalse(MavenDomUtil.isProjectFileWithModel410(
|
||||
createXmlFile("""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
))
|
||||
}
|
||||
|
||||
fun testIsProjectFileWithModel410NoModel() {
|
||||
assertTrue(MavenDomUtil.isProjectFileWithModel410(
|
||||
createXmlFile("""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
))
|
||||
}
|
||||
|
||||
fun createXmlFile(text: String) : PsiFile {
|
||||
return PsiFileFactory.getInstance(project).createFileFromText("pom.xml", XmlFileType.INSTANCE, text);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.dom
|
||||
|
||||
import com.intellij.maven.testFramework.MavenDomTestCase
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
|
||||
class MavenModelDocumentationProviderTest : MavenDomTestCase() {
|
||||
|
||||
@Test
|
||||
fun testModelVersionDocumentation() = runBlocking {
|
||||
createProjectPom(
|
||||
"""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
""".trimIndent())
|
||||
|
||||
val provider = MavenModelDocumentationProvider()
|
||||
val psi = findPsiFile(projectPom) as XmlFile
|
||||
val doc = readAction {
|
||||
provider.generateDoc(psi.rootTag!!.findSubTags("modelVersion").single(), null)
|
||||
}
|
||||
|
||||
assertEquals("Model property<br>project.modelVersion: <b>$modelVersion</b><br>Maven version: ${getActualVersion(myMavenVersion!!)}", doc)
|
||||
}
|
||||
}
|
||||
@@ -139,31 +139,6 @@ class MavenModelValidationTest : MavenDomWithIndicesTestCase() {
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnknownModelVersionMaven4() = runBlocking {
|
||||
assumeMaven4()
|
||||
fixture.saveText(projectPom,
|
||||
"""
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion><error descr="Unsupported model version. Only versions [4.0.0, 4.1.0] are supported.">666</error></modelVersion>
|
||||
<artifactId>foo</artifactId>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testModelVersion41isUnsupportedInMaven3() = runBlocking {
|
||||
assumeMaven3()
|
||||
fixture.saveText(projectPom,
|
||||
"""
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion><error descr="Unsupported model version. Only versions [4.0.0] are supported.">4.1.0</error></modelVersion>
|
||||
<artifactId>foo</artifactId>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testModelVersion41isSupportedInMaven4() = runBlocking {
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ class MavenPackagingCompletionTest : MavenDomTestCase() {
|
||||
<packaging><caret></packaging>
|
||||
""".trimIndent())
|
||||
|
||||
assertCompletionVariants(projectPom, "jar", "pom", "war", "ejb", "ejb-client", "ear", "bundle", "maven-plugin")
|
||||
assertCompletionVariants(projectPom, *arrayOfNotNull("jar", "pom", "war", "ejb", "ejb-client", "ear", "bundle", "maven-plugin", withModel410Only("bom")))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+159
@@ -1207,6 +1207,165 @@ class MavenPropertyCompletionAndResolutionTest : MavenDomTestCase() {
|
||||
assertCompletionVariantsDoNotInclude(projectPom, "project.groupId")
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testCompletingMaven4Specific() = runBlocking {
|
||||
assumeModel_4_1_0("applicable for maven4")
|
||||
updateProjectPom("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
<name>${'$'}{project.<caret></name>
|
||||
""".trimIndent())
|
||||
|
||||
val variants = getCompletionVariants(projectPom)
|
||||
assertContain(variants, "project.rootDirectory")
|
||||
|
||||
updateProjectPom("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
<name>${'$'}{session.<caret></name>
|
||||
""".trimIndent())
|
||||
val sessionVariants = getCompletionVariants(projectPom)
|
||||
assertContain(sessionVariants, "session.rootDirectory", "session.topDirectory")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolveMaven4SpecificRootDir() = runBlocking {
|
||||
assumeModel_4_1_0("applicable for maven4")
|
||||
|
||||
updateProjectPom("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
<properties>
|
||||
<myProp>${'$'}{<caret>project.rootDirectory}</myProp>
|
||||
</properties>
|
||||
|
||||
""".trimIndent())
|
||||
|
||||
val rootDirectory = readAction { PsiManager.getInstance(project).findDirectory(projectPom.getParent())!! }
|
||||
assertResolved(projectPom, rootDirectory)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolveMaven4SpecificRootDirForSubmodules() = runBlocking {
|
||||
assumeModel_4_1_0("applicable for maven4")
|
||||
createModulePom("m1",
|
||||
"""
|
||||
<parent>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
</parent>
|
||||
<artifactId>m1</artifactId>
|
||||
""".trimIndent())
|
||||
updateProjectPom("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>m1</module>
|
||||
</modules>
|
||||
""".trimIndent())
|
||||
updateAllProjects()
|
||||
|
||||
val m1 = updateModulePom("m1",
|
||||
"""
|
||||
<parent>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
</parent>
|
||||
<artifactId>m1</artifactId>
|
||||
<properties>
|
||||
<myDir>${'$'}{<caret>project.rootDirectory}</myDir>
|
||||
</properties>
|
||||
""".trimIndent())
|
||||
val rootDirectory = readAction { PsiManager.getInstance(project).findDirectory(projectPom.getParent()) }
|
||||
assertResolved(m1, rootDirectory!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolveMaven4SpecificSessionRootDirForSubmodules() = runBlocking {
|
||||
assumeModel_4_1_0("applicable for maven4")
|
||||
createModulePom("m1",
|
||||
"""
|
||||
<parent>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
</parent>
|
||||
<artifactId>m1</artifactId>
|
||||
""".trimIndent())
|
||||
updateProjectPom("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>m1</module>
|
||||
</modules>
|
||||
""".trimIndent())
|
||||
updateAllProjects()
|
||||
|
||||
val m1 = updateModulePom("m1",
|
||||
"""
|
||||
<parent>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
</parent>
|
||||
<artifactId>m1</artifactId>
|
||||
<properties>
|
||||
<myDir>${'$'}{<caret>session.rootDirectory}</myDir>
|
||||
</properties>
|
||||
""".trimIndent())
|
||||
val rootDirectory = readAction { PsiManager.getInstance(project).findDirectory(projectPom.getParent()) }
|
||||
assertResolved(m1, rootDirectory!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testResolveMaven4SpecificSessionTopDirForSubmodules() = runBlocking {
|
||||
assumeModel_4_1_0("applicable for maven4")
|
||||
createModulePom("m1",
|
||||
"""
|
||||
<parent>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
</parent>
|
||||
<artifactId>m1</artifactId>
|
||||
""".trimIndent())
|
||||
updateProjectPom("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>m1</module>
|
||||
</modules>
|
||||
""".trimIndent())
|
||||
updateAllProjects()
|
||||
|
||||
val m1 = updateModulePom("m1",
|
||||
"""
|
||||
<parent>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1</version>
|
||||
</parent>
|
||||
<artifactId>m1</artifactId>
|
||||
<properties>
|
||||
<myDir>${'$'}{<caret>session.topDirectory}</myDir>
|
||||
</properties>
|
||||
""".trimIndent())
|
||||
val rootDirectory = readAction { PsiManager.getInstance(project).findDirectory(projectPom.getParent()) }
|
||||
assertResolved(m1, rootDirectory!!)
|
||||
}
|
||||
|
||||
private suspend fun readWithProfiles(vararg profiles: String) {
|
||||
projectsManager.explicitProfiles = MavenExplicitProfiles(listOf(*profiles))
|
||||
updateAllProjects()
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.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.editor.impl.EditorImpl
|
||||
import com.intellij.openapi.fileTypes.FileTypeManager
|
||||
import com.intellij.testFramework.fixtures.BasePlatformTestCase
|
||||
|
||||
class MavenModelSynchronizerTest : BasePlatformTestCase() {
|
||||
@Throws(Exception::class)
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
myFixture.setCaresAboutInjection(false)
|
||||
registerSyncSynchronization()
|
||||
}
|
||||
|
||||
private fun registerSyncSynchronization() {
|
||||
EditorFactory.getInstance().addEditorFactoryListener(object : EditorFactoryListener {
|
||||
override fun editorCreated(event: EditorFactoryEvent) {
|
||||
if (event.editor.project === project) {
|
||||
val editor = event.editor as? EditorImpl ?: return
|
||||
MavenModelVersionSyncronizerImpl(editor, project).listenForDocumentChanges()
|
||||
}
|
||||
}
|
||||
|
||||
}, testRootDisposable)
|
||||
}
|
||||
|
||||
fun testTypingInModel() {
|
||||
|
||||
doTest("""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0<caret>.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""", "\b1", """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""")
|
||||
}
|
||||
|
||||
fun testTypingInModeWithUnderscoresSchemaLocation() {
|
||||
|
||||
doTest("""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0<caret>.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""", "\b1", """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/maven-v4_1_0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""")
|
||||
}
|
||||
|
||||
fun testTypingInUnderscoresSchemaLocation() {
|
||||
|
||||
doTest("""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0<caret>_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""", "\b1", """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/maven-v4_1_0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""")
|
||||
}
|
||||
|
||||
fun testTypingInXmlns() {
|
||||
doTest("""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0<caret>.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""", "\b1", """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""")
|
||||
}
|
||||
|
||||
fun testTypingInSchemaLocationPom() {
|
||||
doTest("""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0<caret>.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""", "\b1", """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""")
|
||||
}
|
||||
|
||||
fun testTypingInSchemaLocationXsd() {
|
||||
doTest("""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0<caret>.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""", "\b1", """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</project>""")
|
||||
}
|
||||
|
||||
fun doTest(content: String, toType: String, expected: String) {
|
||||
val xmlFileType = FileTypeManager.getInstance().getFileTypeByExtension("xml")
|
||||
myFixture.configureByText(xmlFileType, content)
|
||||
myFixture.type(toType)
|
||||
myFixture.checkResult(expected)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.inspections.dom
|
||||
|
||||
import com.intellij.maven.testFramework.MavenDomTestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.idea.maven.dom.inspections.Maven4RedundantParentCoordinatesInspection
|
||||
import org.junit.Test
|
||||
|
||||
class Maven4RedundantParentCoordinatesInspectionTest : MavenDomTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
fixture.enableInspections(Maven4RedundantParentCoordinatesInspection::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoNotFireHighlightInMaven3() = runBlocking {
|
||||
assumeMaven3()
|
||||
val moduleFile = createModulePom("m1", """
|
||||
<parent>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
</parent>
|
||||
<artifactId>m1</artifactId>
|
||||
""")
|
||||
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>m1</module>
|
||||
</modules>
|
||||
""")
|
||||
checkHighlighting(moduleFile)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testFireHighlightInMaven4() = runBlocking {
|
||||
assumeMaven4()
|
||||
val moduleFile = createModulePom("m1", """
|
||||
<parent>
|
||||
<warning descr="The parent coordinates are redundant and not required in Maven 4"><groupId>test</groupId></warning>
|
||||
<warning descr="The parent coordinates are redundant and not required in Maven 4"><artifactId>test</artifactId></warning>
|
||||
<warning descr="The parent coordinates are redundant and not required in Maven 4"><version>1</version></warning>
|
||||
</parent>
|
||||
<artifactId>m1</artifactId>
|
||||
""")
|
||||
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>m1</module>
|
||||
</modules>
|
||||
""")
|
||||
checkHighlighting(moduleFile)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoQuickFixForParent() = runBlocking {
|
||||
assumeMaven4()
|
||||
val moduleFile = createModulePom("m1", """
|
||||
<parent>
|
||||
<warning descr="The parent coordinates are redundant and not required in Maven 4"><groupId>test</groupId></warning>
|
||||
<warning descr="The parent coordinates are redundant and not required in Maven 4"><artifactId>test</artifactId></warning>
|
||||
<warning descr="The parent coordinates are redundant and not required in Maven 4"><caret><version>1</version></warning>
|
||||
</parent>
|
||||
<artifactId>m1</artifactId>
|
||||
""")
|
||||
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>m1</module>
|
||||
</modules>
|
||||
""")
|
||||
checkHighlighting(moduleFile)
|
||||
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text == "Remove unnecessary tags"}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
|
||||
fixture.checkResult(createPomXml("""
|
||||
<parent/>
|
||||
<artifactId>m1</artifactId>
|
||||
"""), true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoQuickFixForParentWithRelativePath() = runBlocking {
|
||||
assumeMaven4()
|
||||
val module1File = createModulePom("m1", """
|
||||
<groupId>test</groupId>
|
||||
<version>1</version>
|
||||
<packaging>pom</packaging>
|
||||
<artifactId>m1</artifactId>
|
||||
""")
|
||||
|
||||
val module2File = createModulePom("m2", """
|
||||
<parent>
|
||||
<warning descr="The parent coordinates are redundant and not required in Maven 4"><groupId>test</groupId></warning>
|
||||
<warning descr="The parent coordinates are redundant and not required in Maven 4"><artifactId>m1</artifactId></warning>
|
||||
<warning descr="The parent coordinates are redundant and not required in Maven 4"><caret><version>1</version></warning>
|
||||
<relativePath>../m1/pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>m2</artifactId>
|
||||
""")
|
||||
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1</version>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>m1</module>
|
||||
<module>m2</module>
|
||||
</modules>
|
||||
""")
|
||||
checkHighlighting(module2File)
|
||||
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text == "Remove unnecessary tags"}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
|
||||
fixture.checkResult(createPomXml("""
|
||||
<parent>
|
||||
<relativePath>../m1/pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>m2</artifactId>
|
||||
"""), true)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.inspections.dom
|
||||
|
||||
import com.intellij.maven.testFramework.MavenDomTestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.idea.maven.dom.inspections.MavenBomPackagingInOldSchema
|
||||
import org.junit.Test
|
||||
|
||||
class MavenBomInOldModelInspectionTest : MavenDomTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
fixture.enableInspections(MavenBomPackagingInOldSchema::class.java)
|
||||
runBlocking {
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDoNotFireHighlightIn41() = runBlocking {
|
||||
assumeModel_4_1_0("")
|
||||
createProjectPom("""
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>bom</packaging>
|
||||
""".trimIndent())
|
||||
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFireHighlightIn40() = runBlocking {
|
||||
assumeModel_4_0_0("")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/$modelVersion"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/$modelVersion http://maven.apache.org/xsd/maven-$modelVersion.xsd">
|
||||
<modelVersion><error descr="Model version 4.1.0 is required for packaging bom">4.0.0</error></modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging><error descr="Model version 4.1.0 is required for packaging bom">bom</error></packaging>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdateToModel41() = runBlocking {
|
||||
assumeModel_4_0_0("")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion><error descr="Model version 4.1.0 is required for packaging bom">4.0.0</error></modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging><error descr="Model version 4.1.0 is required for packaging bom">bo<caret>m</error></packaging> </project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text.contains("Update Maven Model and XSD to 4.1.0")}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
fixture.checkResult("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>bom</packaging> </project>""".trimIndent())
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.inspections.dom
|
||||
|
||||
import com.intellij.maven.testFramework.MavenDomTestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.idea.maven.dom.inspections.MavenModulesInMaven4Inspection
|
||||
import org.junit.Test
|
||||
|
||||
class MavenModulesInMaven4InspectionTest : MavenDomTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
fixture.enableInspections(MavenModulesInMaven4Inspection::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldHighlight() = runBlocking {
|
||||
assumeModel_4_1_0("applicable only for model 4.1.0")
|
||||
createModulePom("m1", """
|
||||
<groupId>test</groupId>
|
||||
<artifactId>m1</artifactId>
|
||||
<version>test</version>
|
||||
""")
|
||||
|
||||
createModulePom("m2", """
|
||||
<groupId>test</groupId>
|
||||
<artifactId>m2</artifactId>
|
||||
<version>test</version>
|
||||
""")
|
||||
createModulePom("m1/sub1", """
|
||||
<groupId>test</groupId>
|
||||
<artifactId>sub1</artifactId>
|
||||
<version>test</version>
|
||||
""")
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>test</version>
|
||||
<modules>
|
||||
<module>m1</module>
|
||||
<module>m2</module>
|
||||
<module>m1/sub1</module>
|
||||
</modules>
|
||||
""")
|
||||
createProjectPom("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>test</version>
|
||||
<warning descr="Tag <modules> is deprecated, should be replaced to <subprojects>"><modules>
|
||||
<module>m1</module>
|
||||
<module>m2</module>
|
||||
<module>m1/sub1</module>
|
||||
</modules><caret></warning>
|
||||
""")
|
||||
checkHighlighting()
|
||||
|
||||
val intention = fixture.availableIntentions.singleOrNull { it.text == "Replace to <subprojects>" }
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
|
||||
fixture.checkResult("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>test</version>
|
||||
<subprojects>
|
||||
<subproject>m1</subproject>
|
||||
<subproject>m2</subproject>
|
||||
<subproject>m1/sub1</subproject>
|
||||
</subprojects>
|
||||
</project>""")
|
||||
}
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.inspections.dom
|
||||
|
||||
import com.intellij.maven.testFramework.MavenDomTestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.idea.maven.dom.inspections.MavenNewModelVersionInOldSchemaInspection
|
||||
import org.junit.Test
|
||||
|
||||
class MavenNewModelVersionInOldSchemaInspectionTest: MavenDomTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
|
||||
fixture.enableInspections(MavenNewModelVersionInOldSchemaInspection::class.java)
|
||||
runBlocking {
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCheckHighlightingWrongModel() = runBlocking{
|
||||
assumeModel_4_0_0("testing only for model 4.0.0")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion><error descr="Model version 4.1.0 is required for projects with 4.1.0 schema">4.1.0</error></modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCheckNotHighlightingModel4_0() = runBlocking{
|
||||
assumeModel_4_0_0("testing only for model 4.0.0")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCheckNotHighlightingModel4_1() = runBlocking{
|
||||
assumeModel_4_1_0("testing only for model 4.1.0")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCheckNotHighlightingModel4_1_underscore() = runBlocking{
|
||||
assumeModel_4_1_0("testing only for model 4.1.0")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/maven-v4_1_0.xsd ">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCheckQuickFix() = runBlocking{
|
||||
assumeModel_4_0_0("testing only for model 4.0.0")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion><error descr="Model version 4.1.0 is required for projects with 4.1.0 schema"><caret>4.1.0</error></modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text.contains("Update Maven Model and XSD to 4.1.0")}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
|
||||
fixture.checkResult("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testCheckQuickFixAddsXMLSchemaInstance() = runBlocking{
|
||||
assumeModel_4_0_0("testing only for model 4.0.0")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project>
|
||||
<modelVersion><error descr="Model version 4.1.0 is required for projects with 4.1.0 schema"><caret>4.1.0</error></modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text.contains("Update Maven Model and XSD to 4.1.0")}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
|
||||
fixture.checkResult("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testQuickFixLeavesHttpsIfWasDefined() = runBlocking{
|
||||
assumeModel_4_0_0("testing only for model 4.0.0")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion><error descr="Model version 4.1.0 is required for projects with 4.1.0 schema"><caret>4.1.0</error></modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text.contains("Update Maven Model and XSD to 4.1.0")}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
|
||||
fixture.checkResult("""<?xml version="1.0"?>
|
||||
<project xmlns="https://maven.apache.org/POM/4.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.inspections.dom
|
||||
|
||||
import com.intellij.maven.testFramework.MavenDomTestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.idea.maven.dom.inspections.MavenNewModelVersionInOldMavenInspection
|
||||
import org.junit.Test
|
||||
|
||||
class MavenNewModelVersionWithOldMavenInspectionTest : MavenDomTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
fixture.enableInspections(MavenNewModelVersionInOldMavenInspection::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCheckNoHighlightingInNewMaven() = runBlocking {
|
||||
assumeModel_4_1_0("not applicable for old model version")
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>test</version>
|
||||
""")
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCheckHighlightingInOldMaven() = runBlocking {
|
||||
assumeMaven3()
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>test</version>
|
||||
""")
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd">
|
||||
<modelVersion><error descr="Maven version 4+ is required for projects with 4.1.0 schema">4.1.0</error></modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>artifact</artifactId>
|
||||
<version>1.0</version>
|
||||
</project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.idea.maven.inspections.dom
|
||||
|
||||
import com.intellij.maven.testFramework.MavenDomTestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.idea.maven.dom.inspections.MavenNoRootDefinedInspection
|
||||
import org.junit.Test
|
||||
import kotlin.io.path.isDirectory
|
||||
|
||||
class MavenNoRootDefinedInspectionTest : MavenDomTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
fixture.enableInspections(MavenNoRootDefinedInspection::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHighlightingWithMvn() = runBlocking {
|
||||
importProjectAsync("""
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
createProjectSubDir(".mvn")
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHighlightingWithoutMvn() = runBlocking {
|
||||
importProjectAsync("""
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
|
||||
<warning descr="Multi-module directory should be defined for all maven projects"><project xmlns="http://maven.apache.org/POM/$modelVersion"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/$modelVersion http://maven.apache.org/xsd/maven-$modelVersion.xsd">
|
||||
<modelVersion>$modelVersion</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version></project></warning>
|
||||
""".trimIndent())
|
||||
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHighlightingWithRoot() = runBlocking {
|
||||
assumeModel_4_1_0("only for model 4.1.0")
|
||||
importProjectAsync("""
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
|
||||
setRawPomFile("""
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/$modelVersion"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/$modelVersion http://maven.apache.org/xsd/maven-$modelVersion.xsd"
|
||||
root="true">
|
||||
<modelVersion>$modelVersion</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version></project>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testRootTagQuickFix() = runBlocking {
|
||||
assumeModel_4_1_0("applicable for model version 4.1.0")
|
||||
importProjectAsync("""
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
val mvnDir = projectRoot.toNioPath().resolve(".mvn")
|
||||
assertFalse("Directory should not exist!", mvnDir.isDirectory())
|
||||
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<warning descr="Multi-module directory should be defined for all maven projects"><<caret>project xmlns="http://maven.apache.org/POM/$modelVersion"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/$modelVersion http://maven.apache.org/xsd/maven-$modelVersion.xsd">
|
||||
<modelVersion>$modelVersion</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version></project></warning>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text.contains("Add root")}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
|
||||
fixture.checkResult("""<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd"
|
||||
root="true">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version></project>
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMvnDirectoryQuickFix() = runBlocking {
|
||||
|
||||
importProjectAsync("""
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
val mvnDir = projectRoot.toNioPath().resolve(".mvn")
|
||||
assertFalse("Directory should not exist!", mvnDir.isDirectory())
|
||||
|
||||
setRawPomFile("""<?xml version="1.0"?>
|
||||
<warning descr="Multi-module directory should be defined for all maven projects"><<caret>project xmlns="http://maven.apache.org/POM/$modelVersion"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/$modelVersion http://maven.apache.org/xsd/maven-$modelVersion.xsd">
|
||||
<modelVersion>$modelVersion</modelVersion>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version></project></warning>
|
||||
""".trimIndent())
|
||||
checkHighlighting()
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text.contains("Create .mvn dir")}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
assertTrue("Directory should be created", mvnDir.isDirectory())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+20
-15
@@ -11,6 +11,14 @@ class MavenRedundantGroupIdTest : MavenDomTestCase() {
|
||||
super.setUp()
|
||||
|
||||
fixture.enableInspections(MavenRedundantGroupIdInspection::class.java)
|
||||
|
||||
runBlocking {
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -31,11 +39,11 @@ class MavenRedundantGroupIdTest : MavenDomTestCase() {
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
<parent>
|
||||
<groupId><error descr="Project 'my.group:parent:1.0' not found">my.group</error></groupId>
|
||||
<artifactId><error descr="Project 'my.group:parent:1.0' not found">parent</error></artifactId>
|
||||
<version><error descr="Project 'my.group:parent:1.0' not found">1.0</error></version>
|
||||
</parent>
|
||||
""".trimIndent())
|
||||
|
||||
checkHighlighting()
|
||||
@@ -49,10 +57,10 @@ class MavenRedundantGroupIdTest : MavenDomTestCase() {
|
||||
<version>1.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
<groupId><error descr="Project 'my.group:parent:1.0' not found">my.group</error></groupId>
|
||||
<artifactId><error descr="Project 'my.group:parent:1.0' not found">parent</error></artifactId>
|
||||
<version><error descr="Project 'my.group:parent:1.0' not found">1.0</error></version>
|
||||
</parent>
|
||||
""".trimIndent())
|
||||
|
||||
checkHighlighting()
|
||||
@@ -75,12 +83,9 @@ class MavenRedundantGroupIdTest : MavenDomTestCase() {
|
||||
fixture.configureFromExistingVirtualFile(projectPom)
|
||||
fixture.doHighlighting()
|
||||
|
||||
for (intention in fixture.availableIntentions) {
|
||||
if (intention.text.startsWith("Remove ") && intention.text.contains("<groupId>")) {
|
||||
fixture.launchAction(intention)
|
||||
break
|
||||
}
|
||||
}
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text.startsWith("Remove ") && it.text.contains("groupId")}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
|
||||
|
||||
//doPostponedFormatting(myProject)
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package org.jetbrains.idea.maven.inspections.dom
|
||||
|
||||
import com.intellij.maven.testFramework.MavenDomTestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.idea.maven.dom.inspections.MavenRedundantVersionInspection
|
||||
import org.junit.Test
|
||||
|
||||
class MavenRedundantVersionTest : MavenDomTestCase() {
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
|
||||
fixture.enableInspections(MavenRedundantVersionInspection::class.java)
|
||||
|
||||
runBlocking {
|
||||
importProjectAsync("""
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHighlighting1() = runBlocking {
|
||||
createProjectPom("""
|
||||
<groupId>my.group</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>1.0</version>
|
||||
""".trimIndent())
|
||||
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHighlighting2() = runBlocking {
|
||||
createProjectPom("""
|
||||
<groupId>childGroupId</groupId>
|
||||
<artifactId>childA</artifactId>
|
||||
<version>2.0</version>
|
||||
|
||||
<parent>
|
||||
<groupId><error descr="Project 'my.group:parent:1.0' not found">my.group</error></groupId>
|
||||
<artifactId><error descr="Project 'my.group:parent:1.0' not found">parent</error></artifactId>
|
||||
<version><error descr="Project 'my.group:parent:1.0' not found">1.0</error></version>
|
||||
</parent>
|
||||
""".trimIndent())
|
||||
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHighlighting3() = runBlocking {
|
||||
createProjectPom("""
|
||||
<artifactId>childA</artifactId>
|
||||
<warning descr="Definition of version is redundant, because it's inherited from the parent"><version>1.0</version></warning>
|
||||
|
||||
<parent>
|
||||
<groupId><error descr="Project 'my.group:parent:1.0' not found">my.group</error></groupId>
|
||||
<artifactId><error descr="Project 'my.group:parent:1.0' not found">parent</error></artifactId>
|
||||
<version><error descr="Project 'my.group:parent:1.0' not found">1.0</error></version>
|
||||
</parent>
|
||||
""".trimIndent())
|
||||
|
||||
checkHighlighting()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testQuickFix() = runBlocking {
|
||||
createProjectPom("""
|
||||
<artifactId>childA</artifactId>
|
||||
<groupId>mavenParent</groupId>
|
||||
<version<caret>>1.0</version>
|
||||
<parent>
|
||||
<groupId>mavenParent</groupId>
|
||||
<artifactId>mavenParent</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
""".trimIndent())
|
||||
|
||||
fixture.configureFromExistingVirtualFile(projectPom)
|
||||
fixture.doHighlighting()
|
||||
|
||||
val intention = fixture.availableIntentions.singleOrNull{it.text.startsWith("Remove ") && it.text.contains("version")}
|
||||
assertNotNull("Cannot find intention", intention)
|
||||
fixture.launchAction(intention!!)
|
||||
|
||||
fixture.checkResult(createPomXml("""
|
||||
<artifactId>childA</artifactId>
|
||||
<groupId>mavenParent</groupId>
|
||||
<parent>
|
||||
<groupId>mavenParent</groupId>
|
||||
<artifactId>mavenParent</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
""".trimIndent()))
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -9,7 +9,7 @@ import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.idea.maven.buildtool.quickfix.UpdateXmlsTo410
|
||||
import org.jetbrains.idea.maven.model.MavenConstants
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_4_XLMNS
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_4_XMLNS
|
||||
import org.jetbrains.idea.maven.model.MavenConstants.MAVEN_4_XSD
|
||||
import org.mockito.Mockito.mock
|
||||
import org.mockito.Mockito.`when`
|
||||
@@ -42,9 +42,9 @@ class UpdateXmlsTo410Test : LightJavaCodeInsightFixtureTestCase() {
|
||||
|
||||
readAction {
|
||||
val updatedProjectTag = xmlFile.document?.rootTag
|
||||
assertEquals(MavenConstants.MAVEN_4_XLMNS, updatedProjectTag?.getAttribute("xmlns")?.value)
|
||||
assertEquals(MavenConstants.MAVEN_4_XMLNS, updatedProjectTag?.getAttribute("xmlns")?.value)
|
||||
assertEquals("http://www.w3.org/2001/XMLSchema-instance", updatedProjectTag?.getAttribute("xmlns:xsi")?.value)
|
||||
assertEquals("$MAVEN_4_XLMNS $MAVEN_4_XSD", updatedProjectTag?.getAttribute("xsi:schemaLocation")?.value)
|
||||
assertEquals("$MAVEN_4_XMLNS $MAVEN_4_XSD", updatedProjectTag?.getAttribute("xsi:schemaLocation")?.value)
|
||||
assertEquals(MavenConstants.MODEL_VERSION_4_1_0,
|
||||
updatedProjectTag?.findFirstSubTag("modelVersion")?.value?.text)
|
||||
}
|
||||
|
||||
@@ -736,4 +736,5 @@ abstract class MavenDomTestCase : MavenMultiVersionImportingTestCase() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+2
-1
@@ -468,7 +468,8 @@ abstract class MavenMultiVersionImportingTestCase : MavenImportingTestCase() {
|
||||
}.toList()
|
||||
}
|
||||
|
||||
internal fun getActualVersion(version: String): String {
|
||||
@JvmStatic
|
||||
protected fun getActualVersion(version: String): String {
|
||||
if (version == "bundled") {
|
||||
return MavenDistributionsCache.resolveEmbeddedMavenHome().version!!
|
||||
}
|
||||
|
||||
@@ -758,6 +758,13 @@ abstract class MavenTestCase : UsefulTestCase() {
|
||||
assumeTrue("Unable to run the test in non-local environment: $cause", LocalEelDescriptor == project.getEelDescriptor())
|
||||
}
|
||||
|
||||
protected fun setRawPomFile(content: String) {
|
||||
Files.write(projectPom.toNioPath(), content.toByteArray(StandardCharsets.UTF_8))
|
||||
projectRoot.refresh(false, false)
|
||||
val f = projectRoot.findChild("pom.xml") ?: throw AssertionError("can't find pom.xml in vfs")
|
||||
refreshFiles(listOf(f))
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Language("XML")
|
||||
fun createPomXml(modelVersion: String, @Language(value = "XML", prefix = "<project>", suffix = "</project>") xml: @NonNls String?): @NonNls String {
|
||||
|
||||
Reference in New Issue
Block a user