[java] automatic modules
authorRoman Shevchenko <roman.shevchenko@jetbrains.com>
Fri, 14 Oct 2016 17:08:29 +0000 (19:08 +0200)
committerRoman Shevchenko <roman.shevchenko@jetbrains.com>
Fri, 14 Oct 2016 17:08:29 +0000 (19:08 +0200)
14 files changed:
java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/ModuleHighlightUtil.java
java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java
java/java-indexing-impl/src/com/intellij/psi/impl/file/impl/JavaFileManagerImpl.java
java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaAutoModuleNameIndex.java [new file with mode: 0644]
java/java-psi-impl/src/com/intellij/psi/impl/light/LightJavaModule.java [new file with mode: 0644]
java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaModuleReference.java
java/java-tests/testData/codeInsight/jigsaw/lib-auto-1.0.jar [new file with mode: 0644]
java/java-tests/testData/codeInsight/jigsaw/lib-named-1.0.jar [new file with mode: 0644]
java/java-tests/testData/codeInsight/jigsaw/lib1.jar [deleted file]
java/java-tests/testSrc/com/intellij/codeInsight/daemon/ModuleHighlightingTest.kt
java/java-tests/testSrc/com/intellij/psi/impl/light/JavaModuleNameDetectionTest.kt [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/testFramework/fixtures/MultiModuleJava9ProjectDescriptor.kt
resources/src/META-INF/IdeaPlugin.xml

index 6ee5c450a1bb9a36d2d782d2cde0651c86faaec7..5d8f580716c0ec2626bf5b67b0de739430a76f81 100644 (file)
@@ -28,8 +28,10 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.ProjectFileIndex;
 import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.JarFileSystem;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.*;
+import com.intellij.psi.impl.light.LightJavaModule;
 import com.intellij.psi.search.FilenameIndex;
 import com.intellij.psi.util.InheritanceUtil;
 import com.intellij.psi.util.PsiTreeUtil;
@@ -62,11 +64,21 @@ public class ModuleHighlightUtil {
     Project project = fsItem.getProject();
     ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
     if (index.isInLibraryClasses(file)) {
-      return Optional.ofNullable(index.getClassRootForFile(file))
-        .map(r -> r.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE))
-        .map(PsiManager.getInstance(project)::findFile)
-        .map(f -> f instanceof PsiJavaFile ? ((PsiJavaFile)f).getModuleDeclaration() : null)
-        .orElse(null);
+      VirtualFile classRoot = index.getClassRootForFile(file);
+      if (classRoot != null) {
+        VirtualFile descriptorFile = classRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE);
+        if (descriptorFile != null) {
+          PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
+          if (psiFile instanceof PsiJavaFile) {
+            return ((PsiJavaFile)psiFile).getModuleDeclaration();
+          }
+        }
+        else if (classRoot.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(classRoot.getExtension())) {
+          return LightJavaModule.getModule(PsiManager.getInstance(project), classRoot);
+        }
+      }
+
+      return null;
     }
     else {
       Module module = index.getModuleForFile(file);
@@ -374,7 +386,7 @@ public class ModuleHighlightUtil {
 
       String refModuleName = refModule.getModuleName();
       String requiredName = targetModule.getModuleName();
-      if (!JavaModuleGraphUtil.exports(targetModule, packageName, refModule)) {
+      if (!(targetModule instanceof LightJavaModule || JavaModuleGraphUtil.exports(targetModule, packageName, refModule))) {
         String message = JavaErrorMessages.message("module.package.not.exported", requiredName, packageName, refModuleName);
         return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(ref).description(message).create();
       }
index 016830bb9ad5293796cba6ca0b81cf27e9dcebbc..ad600c2ec778239ea22fd506b6bc3e4d6a47d6ed 100644 (file)
@@ -729,7 +729,7 @@ public class JavaDocInfoGenerator {
   private void generateModuleJavaDoc(StringBuilder buffer, PsiJavaModule module, boolean generatePrologueAndEpilogue) {
     if (generatePrologueAndEpilogue) generatePrologue(buffer);
 
-    buffer.append("<pre>module <b>").append(module.getName()).append("</b></pre>");
+    buffer.append("<pre>module <b>").append(module.getModuleName()).append("</b></pre>");
 
     PsiDocComment comment = module.getDocComment();
     if (comment != null) {
index 35c2c74bcf095eabad50914a9ef752e665456d4f..676216df89812554199f5c184a0e95e023e93880 100644 (file)
@@ -33,12 +33,10 @@ import com.intellij.lang.documentation.ExternalDocumentationProvider;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleUtilCore;
 import com.intellij.openapi.progress.ProcessCanceledException;
 import com.intellij.openapi.project.IndexNotReadyException;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.*;
-import com.intellij.openapi.util.Conditions;
 import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.util.text.StringUtil;
@@ -47,6 +45,7 @@ import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileSystem;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.beanProperties.BeanPropertyElement;
+import com.intellij.psi.impl.light.LightJavaModule;
 import com.intellij.psi.impl.source.javadoc.PsiDocParamRef;
 import com.intellij.psi.infos.CandidateInfo;
 import com.intellij.psi.javadoc.PsiDocComment;
@@ -141,7 +140,6 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
 
   private static void generateModifiers(StringBuilder buffer, PsiElement element) {
     String modifiers = PsiFormatUtil.formatModifiers(element, PsiFormatUtilBase.JAVADOC_MODIFIERS_ONLY);
-
     if (modifiers.length() > 0) {
       buffer.append(modifiers);
       buffer.append(" ");
@@ -154,20 +152,9 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
 
   private static void generateOrderEntryAndPackageInfo(StringBuilder buffer, @NotNull PsiElement element) {
     PsiFile file = element.getContainingFile();
-    ProjectFileIndex fileIndex = ProjectRootManager.getInstance(element.getProject()).getFileIndex();
-    VirtualFile vFile = file.getVirtualFile();
-    if (vFile != null && (fileIndex.isInLibrarySource(vFile) || fileIndex.isInLibraryClasses(vFile))) {
-      final List<OrderEntry> orderEntries = fileIndex.getOrderEntriesForFile(vFile);
-      OrderEntry orderEntry = ContainerUtil.find(orderEntries, Conditions.instanceOf(LibraryOrSdkOrderEntry.class));
-      if (orderEntry != null) {
-        buffer.append("[").append(StringUtil.escapeXml(orderEntry.getPresentableName())).append("] ");
-      }
-    }
-    else {
-      final Module module = ModuleUtilCore.findModuleForPsiElement(file);
-      if (module != null) {
-        buffer.append('[').append(module.getName()).append("] ");
-      }
+
+    if (file != null) {
+      generateOrderEntryInfo(buffer, file.getVirtualFile(), element.getProject());
     }
 
     if (file instanceof PsiJavaFile) {
@@ -179,6 +166,23 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
     }
   }
 
+  private static void generateOrderEntryInfo(StringBuilder buffer, VirtualFile file, Project project) {
+    if (file != null) {
+      ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex();
+      if (index.isInLibrarySource(file) || index.isInLibraryClasses(file)) {
+        index.getOrderEntriesForFile(file).stream()
+          .filter(LibraryOrSdkOrderEntry.class::isInstance).findFirst()
+          .ifPresent(entry -> buffer.append('[').append(StringUtil.escapeXml(entry.getPresentableName())).append("] "));
+      }
+      else {
+        Module module = index.getModuleForFile(file);
+        if (module != null) {
+          buffer.append('[').append(module.getName()).append("] ");
+        }
+      }
+    }
+  }
+
   @SuppressWarnings({"HardCodedStringLiteral"})
   public static String generateClassInfo(PsiClass aClass) {
     StringBuilder buffer = new StringBuilder();
@@ -376,8 +380,21 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
 
   private static String generateModuleInfo(PsiJavaModule module) {
     StringBuilder sb = new StringBuilder();
-    generateOrderEntryAndPackageInfo(sb, module);
+
+    VirtualFile file = null;
+    if (module instanceof LightJavaModule) {
+      PsiElement target = module.getNavigationElement();
+      if (target instanceof PsiDirectory) {
+        file = ((PsiDirectory)target).getVirtualFile();
+      }
+    }
+    else {
+      file = module.getContainingFile().getVirtualFile();
+    }
+    generateOrderEntryInfo(sb, file, module.getProject());
+
     sb.append(LangBundle.message("java.terms.module")).append(' ').append(module.getModuleName());
+
     return sb.toString();
   }
 
index 7d4e64b812688588ca515a5d7dee900efada9ca1..b4933487b99734853d8ff6f187b0ce77700f33b2 100644 (file)
@@ -28,8 +28,10 @@ import com.intellij.openapi.vfs.VirtualFileWithId;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.PsiManagerEx;
 import com.intellij.psi.impl.file.PsiPackageImpl;
+import com.intellij.psi.impl.java.stubs.index.JavaAutoModuleNameIndex;
 import com.intellij.psi.impl.java.stubs.index.JavaFullClassNameIndex;
 import com.intellij.psi.impl.java.stubs.index.JavaModuleNameIndex;
+import com.intellij.psi.impl.light.LightJavaModule;
 import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.util.Query;
 import com.intellij.util.containers.ContainerUtil;
@@ -38,6 +40,7 @@ import org.jetbrains.annotations.Nullable;
 import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
 
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @author dmitry lomov
@@ -180,6 +183,19 @@ public class JavaFileManagerImpl implements JavaFileManager, Disposable {
   @NotNull
   @Override
   public Collection<PsiJavaModule> findModules(@NotNull String moduleName, @NotNull GlobalSearchScope scope) {
-    return JavaModuleNameIndex.getInstance().get(moduleName, myManager.getProject(), scope);
+    Collection<PsiJavaModule> named = JavaModuleNameIndex.getInstance().get(moduleName, myManager.getProject(), scope);
+    if (!named.isEmpty()) {
+      return named;
+    }
+
+    Collection<VirtualFile> jars = JavaAutoModuleNameIndex.getFilesByKey(moduleName, scope);
+    if (!jars.isEmpty()) {
+      List<PsiJavaModule> automatic = jars.stream().map(f -> LightJavaModule.getModule(myManager, f)).collect(Collectors.toList());
+      if (!automatic.isEmpty()) {
+        return automatic;
+      }
+    }
+
+    return Collections.emptyList();
   }
 }
\ No newline at end of file
diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaAutoModuleNameIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaAutoModuleNameIndex.java
new file mode 100644 (file)
index 0000000..e63ec4e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.impl.java.stubs.index;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.impl.light.LightJavaModule;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.indexing.*;
+import com.intellij.util.io.EnumeratorStringDescriptor;
+import com.intellij.util.io.KeyDescriptor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+
+import static java.util.Collections.singletonMap;
+
+public class JavaAutoModuleNameIndex extends ScalarIndexExtension<String> {
+  private static final ID<String, Void> NAME = ID.create("java.auto.module.name");
+
+  private final FileBasedIndex.InputFilter myFilter =
+    file -> file.isDirectory() && file.getParent() == null && "jar".equalsIgnoreCase(file.getExtension());
+
+  private final DataIndexer<String, Void, FileContent> myIndexer =
+    data -> singletonMap(LightJavaModule.moduleName(data.getFile().getNameWithoutExtension()), null);
+
+  @NotNull
+  @Override
+  public ID<String, Void> getName() {
+    return NAME;
+  }
+
+  @Override
+  public int getVersion() {
+    return 1 + (FileBasedIndex.ourEnableTracingOfKeyHashToVirtualFileMapping ? 2 : 0);
+  }
+
+  @NotNull
+  @Override
+  public KeyDescriptor<String> getKeyDescriptor() {
+    return EnumeratorStringDescriptor.INSTANCE;
+  }
+
+  @Override
+  public boolean dependsOnFileContent() {
+    return false;
+  }
+
+  @NotNull
+  @Override
+  public FileBasedIndex.InputFilter getInputFilter() {
+    return myFilter;
+  }
+
+  @NotNull
+  @Override
+  public DataIndexer<String, Void, FileContent> getIndexer() {
+    return myIndexer;
+  }
+
+  @NotNull
+  public static Collection<VirtualFile> getFilesByKey(@NotNull String moduleName, @NotNull GlobalSearchScope scope) {
+    return FileBasedIndex.getInstance().getContainingFiles(NAME, moduleName, scope);
+  }
+}
\ No newline at end of file
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightJavaModule.java b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightJavaModule.java
new file mode 100644 (file)
index 0000000..e7b14c5
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.impl.light;
+
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectRootModificationTracker;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.javadoc.PsiDocComment;
+import com.intellij.psi.util.CachedValueProvider.Result;
+import com.intellij.psi.util.CachedValuesManager;
+import com.intellij.psi.util.ParameterizedCachedValue;
+import com.intellij.psi.util.ParameterizedCachedValueProvider;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collections;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static com.intellij.openapi.util.Pair.pair;
+import static com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT;
+import static com.intellij.util.ObjectUtils.notNull;
+
+public class LightJavaModule extends LightElement implements PsiJavaModule {
+  private final LightJavaModuleReferenceElement myRefElement;
+  private final VirtualFile myJarRoot;
+
+  private LightJavaModule(@NotNull PsiManager manager, @NotNull VirtualFile jarRoot) {
+    super(manager, JavaLanguage.INSTANCE);
+    myJarRoot = jarRoot;
+    myRefElement = new LightJavaModuleReferenceElement(manager, moduleName(jarRoot.getNameWithoutExtension()));
+  }
+
+  @Nullable
+  @Override
+  public PsiDocComment getDocComment() {
+    return null;
+  }
+
+  @NotNull
+  @Override
+  public PsiJavaModuleReferenceElement getNameElement() {
+    return myRefElement;
+  }
+
+  @NotNull
+  @Override
+  public String getModuleName() {
+    return myRefElement.getReferenceText();
+  }
+
+  @NotNull
+  @Override
+  public Iterable<PsiRequiresStatement> getRequires() {
+    return Collections.emptyList();
+  }
+
+  @NotNull
+  @Override
+  public Iterable<PsiExportsStatement> getExports() {
+    return Collections.emptyList();
+  }
+
+  @Override
+  public String getName() {
+    return getModuleName();
+  }
+
+  @Override
+  public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
+    throw new IncorrectOperationException("Cannot modify automatic module '" + getName() + "'");
+  }
+
+  @NotNull
+  @Override
+  public PsiElement getNavigationElement() {
+    return notNull(myManager.findDirectory(myJarRoot), super.getNavigationElement());
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    return obj instanceof LightJavaModule && myJarRoot.equals(((LightJavaModule)obj).myJarRoot) && getManager() == ((LightJavaModule)obj).getManager();
+  }
+
+  @Override
+  public int hashCode() {
+    return getModuleName().hashCode() * 31 + getManager().hashCode();
+  }
+
+  @Override
+  public String toString() {
+    return "PsiJavaModule:" + getModuleName();
+  }
+
+  private static class LightJavaModuleReferenceElement extends LightElement implements PsiJavaModuleReferenceElement {
+    private final String myText;
+
+    public LightJavaModuleReferenceElement(@NotNull PsiManager manager, @NotNull String text) {
+      super(manager, JavaLanguage.INSTANCE);
+      myText = text;
+    }
+
+    @NotNull
+    @Override
+    public String getReferenceText() {
+      return myText;
+    }
+
+    @Nullable
+    @Override
+    public PsiPolyVariantReference getReference() {
+      return null;
+    }
+
+    @Override
+    public String toString() {
+      return "PsiJavaModuleReference";
+    }
+  }
+
+  @NotNull
+  public static LightJavaModule getModule(@NotNull PsiManager manager, @NotNull VirtualFile jarRoot) {
+    Project project = manager.getProject();
+    CachedValuesManager cache = CachedValuesManager.getManager(project);
+    return cache.getParameterizedCachedValue(project, KEY, new ParameterizedCachedValueProvider<LightJavaModule, Pair<PsiManager, VirtualFile>>() {
+      @Nullable
+      @Override
+      public Result<LightJavaModule> compute(Pair<PsiManager, VirtualFile> p) {
+        LightJavaModule module = new LightJavaModule(p.first, p.second);
+        return Result.create(module, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, ProjectRootModificationTracker.getInstance(p.first.getProject()));
+      }
+    }, false, pair(manager, jarRoot));
+  }
+
+  private static final Key<ParameterizedCachedValue<LightJavaModule, Pair<PsiManager, VirtualFile>>> KEY = Key.create("java.light.module");
+
+  /**
+   * Implements a name deriving for  automatic modules as described in ModuleFinder.of(Path...) method documentation.
+   *
+   * @param name a .jar file name without extension
+   * @see <a href="http://download.java.net/java/jigsaw/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-">ModuleFinder.of(Path...)</a>
+   */
+  @NotNull
+  public static String moduleName(@NotNull String name) {
+    // If the name matches the regular expression "-(\\d+(\\.|$))" then the module name will be derived from the sub-sequence
+    // preceding the hyphen of the first occurrence.
+    Matcher m = Patterns.VERSION.matcher(name);
+    if (m.find()) {
+      name = name.substring(0, m.start());
+    }
+
+    // For the module name, then any trailing digits and dots are removed ...
+    name = Patterns.TAIL_VERSION.matcher(name).replaceFirst("");
+    // ... all non-alphanumeric characters ([^A-Za-z0-9]) are replaced with a dot (".") ...
+    name = Patterns.NON_NAME.matcher(name).replaceAll(".");
+    // ... all repeating dots are replaced with one dot ...
+    name = Patterns.DOT_SEQUENCE.matcher(name).replaceAll(".");
+    // ... and all leading and trailing dots are removed
+    name = StringUtil.trimLeading(StringUtil.trimTrailing(name, '.'), '.');
+
+    return name;
+  }
+
+  private static class Patterns {
+    private static final Pattern VERSION = Pattern.compile("-(\\d+(\\.|$))");
+    private static final Pattern TAIL_VERSION = Pattern.compile("[0-9.]+$");
+    private static final Pattern NON_NAME = Pattern.compile("[^A-Za-z0-9]");
+    private static final Pattern DOT_SEQUENCE = Pattern.compile("\\.{2,}");
+  }
+}
\ No newline at end of file
index f9b98a3ace86b7d8e288985829a9b1219e110dba..0a2d11ecc2b68dcf946b4b52f42f9ff76f3a54a8 100644 (file)
@@ -28,7 +28,7 @@ import com.intellij.psi.*;
 import com.intellij.psi.impl.file.impl.JavaFileManager;
 import com.intellij.psi.impl.source.resolve.ResolveCache;
 import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.util.CachedValueProvider;
+import com.intellij.psi.util.CachedValueProvider.Result;
 import com.intellij.psi.util.CachedValuesManager;
 import com.intellij.psi.util.ParameterizedCachedValue;
 import com.intellij.psi.util.ParameterizedCachedValueProvider;
@@ -131,10 +131,10 @@ public class PsiJavaModuleReference extends PsiReferenceBase.Poly<PsiJavaModuleR
     return manager.getParameterizedCachedValue(refOwner, KEY, new ParameterizedCachedValueProvider<PsiJavaModule, Pair<String, Boolean>>() {
       @Nullable
       @Override
-      public CachedValueProvider.Result<PsiJavaModule> compute(Pair<String, Boolean> p) {
+      public Result<PsiJavaModule> compute(Pair<String, Boolean> p) {
         Collection<PsiJavaModule> modules = Resolver.findModules(refOwner.getContainingFile(), p.first, p.second);
         PsiJavaModule module = modules.size() == 1 ? modules.iterator().next() : null;
-        return CachedValueProvider.Result.create(module, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
+        return Result.create(module, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
       }
     }, false, pair(refText, incompleteCode));
   }
diff --git a/java/java-tests/testData/codeInsight/jigsaw/lib-auto-1.0.jar b/java/java-tests/testData/codeInsight/jigsaw/lib-auto-1.0.jar
new file mode 100644 (file)
index 0000000..086f623
Binary files /dev/null and b/java/java-tests/testData/codeInsight/jigsaw/lib-auto-1.0.jar differ
diff --git a/java/java-tests/testData/codeInsight/jigsaw/lib-named-1.0.jar b/java/java-tests/testData/codeInsight/jigsaw/lib-named-1.0.jar
new file mode 100644 (file)
index 0000000..43cee83
Binary files /dev/null and b/java/java-tests/testData/codeInsight/jigsaw/lib-named-1.0.jar differ
diff --git a/java/java-tests/testData/codeInsight/jigsaw/lib1.jar b/java/java-tests/testData/codeInsight/jigsaw/lib1.jar
deleted file mode 100644 (file)
index f719fc6..0000000
Binary files a/java/java-tests/testData/codeInsight/jigsaw/lib1.jar and /dev/null differ
index 292ebf1159850d7748763a819c383626f7098ecc..96665872d40b252fbdc35996ca7ab7bfe2869738 100644 (file)
@@ -134,7 +134,7 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
   }
 
   fun testPackageAccessibility() {
-    addFile("module-info.java", "module M { requires M2; requires M6; requires LIB1; }")
+    addFile("module-info.java", "module M { requires M2; requires M6; requires lib.named; requires lib.auto; }")
     addFile("module-info.java", "module M2 { exports pkg.m2; exports pkg.m2.impl to close.friends.only; }", M2)
     addFile("pkg/m2/C2.java", "package pkg.m2;\npublic class C2 { }", M2)
     addFile("pkg/m2/impl/C2Impl.java", "package pkg.m2.impl;\nimport pkg.m2.C2;\npublic class C2Impl { public static C2 make() {} }", M2)
@@ -155,8 +155,11 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
         import pkg.m7.C7;
 
         import pkg.lib1.LC1;
-        import <error descr="The module 'LIB1' does not export the package 'pkg.lib1.impl' to the module 'M'">pkg.lib1.impl.LC1Impl</error>;
-        import <error descr="The module 'LIB1' does not export the package 'pkg.lib1.impl' to the module 'M'">pkg.lib1.impl</error>.*;
+        import <error descr="The module 'lib.named' does not export the package 'pkg.lib1.impl' to the module 'M'">pkg.lib1.impl.LC1Impl</error>;
+        import <error descr="The module 'lib.named' does not export the package 'pkg.lib1.impl' to the module 'M'">pkg.lib1.impl</error>.*;
+
+        import pkg.lib2.LC2;
+        import pkg.lib2.impl.LC2Impl;
 
         import static <error descr="The module 'M2' does not export the package 'pkg.m2.impl' to the module 'M'">pkg.m2.impl.C2Impl</error>.make;
 
diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/light/JavaModuleNameDetectionTest.kt b/java/java-tests/testSrc/com/intellij/psi/impl/light/JavaModuleNameDetectionTest.kt
new file mode 100644 (file)
index 0000000..39ad73a
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.impl.light
+
+import org.junit.Test
+import kotlin.test.assertEquals
+
+class JavaModuleNameDetectionTest {
+  @Test fun plain() = doTest("foo", "foo")
+  @Test fun versioned() = doTest("foo-1.2.3-SNAPSHOT", "foo")
+  @Test fun trailing() = doTest("foo2bar1.2.3", "foo2bar")
+  @Test fun replacing() = doTest("foo_bar", "foo.bar")
+  @Test fun collapsing() = doTest("foo...bar", "foo.bar")
+  @Test fun trimming() = doTest("...foo.bar...", "foo.bar")
+
+  private fun doTest(original: String, expected: String) = assertEquals(expected, LightJavaModule.moduleName(original))
+}
\ No newline at end of file
index f29828fc4d912470583f9bc03f20b3e574a3ecaf..94102d94076607c049508f7eecea378c1621dd77 100644 (file)
@@ -71,8 +71,9 @@ object MultiModuleJava9ProjectDescriptor : DefaultLightProjectDescriptor() {
       val m7 = makeModule(project, ModuleDescriptor.M7)
       ModuleRootModificationUtil.addDependency(m6, m7, DependencyScope.COMPILE, true)
 
-      val libDir = "jar://${PathManagerEx.getTestDataPath()}/codeInsight/jigsaw/"
-      ModuleRootModificationUtil.addModuleLibrary(main, libDir + "lib1.jar!/")
+      val libDir = "jar://${PathManagerEx.getTestDataPath()}/codeInsight/jigsaw"
+      ModuleRootModificationUtil.addModuleLibrary(main, "${libDir}/lib-named-1.0.jar!/")
+      ModuleRootModificationUtil.addModuleLibrary(main, "${libDir}/lib-auto-1.0.jar!/")
     }
   }
 
index 3c2b3cbe3061227c8407fd03d0bd45e482f53046..21853176ce56f5a1c52a5a230945dae2394d0248 100644 (file)
     <fileBasedIndex implementation="com.intellij.psi.impl.java.JavaFunctionalExpressionIndex"/>
     <fileBasedIndex implementation="com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisIndex"/>
     <fileBasedIndex implementation="com.intellij.psi.RefQueueIndex"/>
+    <fileBasedIndex implementation="com.intellij.psi.impl.java.stubs.index.JavaAutoModuleNameIndex"/>
 
     <stubElementTypeHolder class="com.intellij.psi.impl.java.stubs.JavaStubElementTypes"/>