Commit 0c60dfb4 authored by Roman Shevchenko's avatar Roman Shevchenko
Browse files

[java] handling for automatic modules with invalid names (IDEA-184590)

Shows a descriptive error, doesn't suggest "add requires" quick fix, and excludes such modules from completion.
parent 831aa13a
Branches unavailable Tags unavailable
No related merge requests found
Showing with 40 additions and 55 deletions
+40 -55
// Copyright 2000-2017 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.
/*
* Copyright 2000-2018 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 com.intellij.codeInsight.completion;
import com.intellij.codeInsight.ExpectedTypeInfo;
......@@ -938,7 +940,9 @@ public class JavaCompletionContributor extends CompletionContributor {
VirtualFile[] roots = ModuleRootManager.getInstance(module).orderEntries().withoutSdk().librariesOnly().getClassesRoots();
scope = GlobalSearchScope.filesScope(project, Arrays.asList(roots));
for (String name : JavaAutoModuleNameIndex.getAllKeys(project)) {
if (JavaAutoModuleNameIndex.getFilesByKey(name, scope).size() > 0 && filter.add(name)) {
if (JavaAutoModuleNameIndex.getFilesByKey(name, scope).size() > 0 &&
PsiNameHelper.isValidModuleName(name, parent) &&
filter.add(name)) {
LookupElement lookup = LookupElementBuilder.create(name).withIcon(AllIcons.FileTypes.Archive);
lookup = TailTypeDecorator.withTail(lookup, TailType.SEMICOLON);
lookup = PrioritizedLookupElement.withPriority(lookup, -1);
......
// Copyright 2000-2017 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.
/*
* Copyright 2000-2018 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 com.intellij.psi.impl
import com.intellij.codeInsight.JavaModuleSystemEx
......@@ -119,9 +121,13 @@ class JavaPlatformModuleSystem : JavaModuleSystemEx {
}
if (!(targetName == PsiJavaModule.JAVA_BASE || JavaModuleGraphUtil.reads(useModule, targetModule))) {
return if (quick) ERR else ErrorWithFixes(
JavaErrorMessages.message("module.access.does.not.read", packageName, targetName, useName),
listOf(AddRequiresDirectiveFix(useModule, targetName)))
return when {
quick -> ERR
PsiNameHelper.isValidModuleName(targetName, useModule) -> ErrorWithFixes(
JavaErrorMessages.message("module.access.does.not.read", packageName, targetName, useName),
listOf(AddRequiresDirectiveFix(useModule, targetName)))
else -> ErrorWithFixes(JavaErrorMessages.message("module.access.bad.name", packageName, targetName))
}
}
}
else if (useModule != null) {
......
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2018 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 com.intellij.refactoring.rename;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
......@@ -35,9 +22,6 @@ public class JavaModuleRenameValidator implements RenameInputValidator {
@Override
public boolean isInputValid(@NotNull String newName, @NotNull PsiElement element, @NotNull ProcessingContext context) {
if (StringUtil.isEmptyOrSpaces(newName)) return false;
PsiNameHelper helper = PsiNameHelper.getInstance(element.getProject());
return StringUtil.split(newName, ".", true, false).stream().allMatch(helper::isIdentifier);
return PsiNameHelper.isValidModuleName(newName, element);
}
}
\ No newline at end of file
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2018 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 com.intellij.psi;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
......@@ -304,4 +294,10 @@ public abstract class PsiNameHelper {
}
return updated;
}
}
public static boolean isValidModuleName(@NotNull String name, @NotNull PsiElement context) {
PsiNameHelper helper = getInstance(context.getProject());
LanguageLevel level = PsiUtil.getLanguageLevel(context);
return StringUtil.split(name, ".", true, false).stream().allMatch(part -> helper.isIdentifier(part, level));
}
}
\ No newline at end of file
......@@ -437,6 +437,7 @@ module.access.from.named=Package ''{0}'' is declared in module ''{1}'', which do
module.access.from.unnamed=Package ''{0}'' is declared in module ''{1}'', which does not export it to the unnamed module
module.access.does.not.read=Package ''{0}'' is declared in module ''{1}'', but module ''{2}'' does not read it
module.access.not.in.graph=Package ''{0}'' is declared in module ''{1}'', which is not in the module graph
module.access.bad.name=Package ''{0}'' is declared in module with an invalid name (''{1}'')
feature.generics=Generics
feature.annotations=Annotations
......
File added
// Copyright 2000-2017 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.
/*
* Copyright 2000-2018 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 com.intellij.java.codeInsight.daemon
import com.intellij.codeInsight.daemon.impl.JavaHighlightInfoTypes
......@@ -273,6 +275,8 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
import java.util.List;
import java.util.function.Supplier;
import <error descr="Package 'pkg.libInvalid' is declared in module with an invalid name ('lib.invalid.1.2')">pkg.libInvalid</error>.LCInv;
/** See also {@link C2Impl#I} and {@link C2Impl#make} */
class C {{
<error descr="Package 'pkg.m2.impl' is declared in module 'M2', which does not export it to module 'M'">C2Impl</error>.I = 0;
......
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2000-2018 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 com.intellij.java.psi.impl.light
......@@ -26,6 +14,7 @@ class JavaModuleNameDetectionTest {
@Test fun replacing() = doTest("foo_bar", "foo.bar")
@Test fun collapsing() = doTest("foo...bar", "foo.bar")
@Test fun trimming() = doTest("...foo.bar...", "foo.bar")
@Test fun invalid() = doTest("lib_invalid_1_2", "lib.invalid.1.2")
private fun doTest(original: String, expected: String) = assertEquals(expected, LightJavaModule.moduleName(original))
}
\ No newline at end of file
// Copyright 2000-2017 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.
/*
* Copyright 2000-2018 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 com.intellij.java.testFramework.fixtures
import com.intellij.openapi.application.ex.PathManagerEx
......@@ -74,6 +74,7 @@ object MultiModuleJava9ProjectDescriptor : DefaultLightProjectDescriptor() {
ModuleRootModificationUtil.addModuleLibrary(main, "${libDir}/lib-auto-1.0.jar!/")
ModuleRootModificationUtil.addModuleLibrary(main, "${libDir}/lib-auto-2.0.jar!/")
ModuleRootModificationUtil.addModuleLibrary(main, "${libDir}/lib-multi-release.jar!/")
ModuleRootModificationUtil.addModuleLibrary(main, "${libDir}/lib_invalid_1_2.jar!/")
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment