mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java] using module stubs in analysis/highlighting code
This commit is contained in:
+30
-28
@@ -20,10 +20,10 @@ import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.PsiJavaModuleReference;
|
||||
import com.intellij.psi.search.FilenameIndex;
|
||||
import com.intellij.psi.util.CachedValueProvider.Result;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.graph.DFSTBuilder;
|
||||
@@ -36,7 +36,6 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
|
||||
import static com.intellij.psi.SyntaxTraverser.psiTraverser;
|
||||
import static com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT;
|
||||
|
||||
public class JavaModuleGraphUtil {
|
||||
@@ -50,6 +49,13 @@ public class JavaModuleGraphUtil {
|
||||
return ContainerUtil.find(cycles, set -> set.contains(module));
|
||||
}
|
||||
|
||||
public static boolean exports(@NotNull PsiJavaModule source, @NotNull String packageName, @NotNull PsiJavaModule target) {
|
||||
Map<String, Set<String>> exports = CachedValuesManager.getCachedValue(source, () ->
|
||||
Result.create(exportsMap(source), OUT_OF_CODE_BLOCK_MODIFICATION_COUNT));
|
||||
Set<String> targets = exports.get(packageName);
|
||||
return targets != null && (targets.isEmpty() || targets.contains(target.getModuleName()));
|
||||
}
|
||||
|
||||
public static boolean reads(@NotNull PsiJavaModule source, @NotNull PsiJavaModule destination) {
|
||||
Project project = source.getProject();
|
||||
RequiresGraph graph = CachedValuesManager.getManager(project).getCachedValue(project, () ->
|
||||
@@ -74,14 +80,11 @@ public class JavaModuleGraphUtil {
|
||||
if (!projectModules.isEmpty()) {
|
||||
MultiMap<PsiJavaModule, PsiJavaModule> relations = MultiMap.create();
|
||||
for (PsiJavaModule module : projectModules) {
|
||||
for (PsiRequiresStatement statement : psiTraverser().children(module).filter(PsiRequiresStatement.class)) {
|
||||
Optional.ofNullable(statement.getReferenceElement())
|
||||
.map(PsiJavaModuleReferenceElement::getReference)
|
||||
.map(ref -> ref.multiResolve(true))
|
||||
.map(a -> a.length == 1 ? a[0].getElement() : null)
|
||||
.map(e -> e instanceof PsiJavaModule ? (PsiJavaModule)e : null)
|
||||
.filter(projectModules::contains)
|
||||
.ifPresent(dependency -> relations.putValue(module, dependency));
|
||||
for (PsiRequiresStatement statement : module.getRequires()) {
|
||||
PsiJavaModule dependency = PsiJavaModuleReference.resolve(statement, statement.getModuleName(), true);
|
||||
if (dependency != null && projectModules.contains(dependency)) {
|
||||
relations.putValue(module, dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +101,16 @@ public class JavaModuleGraphUtil {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static Map<String, Set<String>> exportsMap(@NotNull PsiJavaModule source) {
|
||||
Map<String, Set<String>> map = ContainerUtil.newHashMap();
|
||||
for (PsiExportsStatement statement : source.getExports()) {
|
||||
String pkg = statement.getPackageName();
|
||||
List<String> targets = statement.getModuleNames();
|
||||
map.put(pkg, targets.isEmpty() ? Collections.emptySet() : ContainerUtil.newTroveSet(targets));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// Starting from source modules, collects all module dependencies in the project.
|
||||
// The resulting graph is used for tracing readability.
|
||||
private static RequiresGraph buildRequiresGraph(Project project) {
|
||||
@@ -118,28 +131,17 @@ public class JavaModuleGraphUtil {
|
||||
private static void visit(PsiJavaModule module, MultiMap<PsiJavaModule, PsiJavaModule> relations, Set<String> publicEdges) {
|
||||
if (!relations.containsKey(module)) {
|
||||
relations.putValues(module, Collections.emptyList());
|
||||
for (PsiRequiresStatement statement : psiTraverser().children(module).filter(PsiRequiresStatement.class)) {
|
||||
Optional.ofNullable(statement.getReferenceElement())
|
||||
.map(PsiJavaModuleReferenceElement::getReference)
|
||||
.map(PsiReference::resolve)
|
||||
.map(e -> e instanceof PsiJavaModule ? (PsiJavaModule)e : null)
|
||||
.ifPresent(dependency -> {
|
||||
relations.putValue(module, dependency);
|
||||
if (isPublic(statement)) publicEdges.add(RequiresGraph.key(dependency, module));
|
||||
visit(dependency, relations, publicEdges);
|
||||
});
|
||||
for (PsiRequiresStatement statement : module.getRequires()) {
|
||||
PsiJavaModule dependency = PsiJavaModuleReference.resolve(statement, statement.getModuleName(), false);
|
||||
if (dependency != null) {
|
||||
relations.putValue(module, dependency);
|
||||
if (statement.isPublic()) publicEdges.add(RequiresGraph.key(dependency, module));
|
||||
visit(dependency, relations, publicEdges);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPublic(PsiRequiresStatement statement) {
|
||||
for (PsiElement child = statement.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (PsiUtil.isJavaToken(child, JavaTokenType.PUBLIC_KEYWORD)) return true;
|
||||
if (child instanceof PsiJavaModuleReferenceElement) break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class RequiresGraph {
|
||||
private final Graph<PsiJavaModule> myGraph;
|
||||
private final Set<String> myPublicEdges;
|
||||
|
||||
+4
-14
@@ -118,12 +118,12 @@ public class ModuleHighlightUtil {
|
||||
List<HighlightInfo> results = ContainerUtil.newSmartList();
|
||||
|
||||
checkDuplicateRefs(
|
||||
psiTraverser().children(module).filter(PsiRequiresStatement.class),
|
||||
module.getRequires(),
|
||||
st -> Optional.ofNullable(st.getReferenceElement()).map(PsiJavaModuleReferenceElement::getReferenceText),
|
||||
"module.duplicate.requires", results);
|
||||
|
||||
checkDuplicateRefs(
|
||||
psiTraverser().children(module).filter(PsiExportsStatement.class),
|
||||
module.getExports(),
|
||||
st -> Optional.ofNullable(st.getPackageReference()).map(ModuleHighlightUtil::refText),
|
||||
"module.duplicate.export", results);
|
||||
|
||||
@@ -267,7 +267,7 @@ public class ModuleHighlightUtil {
|
||||
List<HighlightInfo> results = ContainerUtil.newSmartList();
|
||||
|
||||
Set<String> targets = ContainerUtil.newTroveSet();
|
||||
for (PsiJavaModuleReferenceElement refElement : psiTraverser().children(statement).filter(PsiJavaModuleReferenceElement.class)) {
|
||||
for (PsiJavaModuleReferenceElement refElement : statement.getModuleReferences()) {
|
||||
String refText = refElement.getReferenceText();
|
||||
PsiPolyVariantReference ref = refElement.getReference();
|
||||
assert ref != null : statement;
|
||||
@@ -376,7 +376,7 @@ public class ModuleHighlightUtil {
|
||||
|
||||
String refModuleName = refModule.getModuleName();
|
||||
String requiredName = targetModule.getModuleName();
|
||||
if (!(targetModule instanceof PsiCompiledElement) && !isExported(targetModule, packageName)) {
|
||||
if (!(targetModule instanceof PsiCompiledElement) && !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();
|
||||
}
|
||||
@@ -389,16 +389,6 @@ public class ModuleHighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isExported(PsiJavaModule module, String packageName) {
|
||||
for (PsiExportsStatement statement : psiTraverser().children(module).filter(PsiExportsStatement.class)) {
|
||||
String exportedName = Optional.ofNullable(statement.getPackageReference()).map(ModuleHighlightUtil::refText).orElse("");
|
||||
if (packageName.equals(exportedName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static HighlightInfo moduleResolveError(PsiJavaModuleReferenceElement refElement, PsiPolyVariantReference ref) {
|
||||
boolean missing = ref.multiResolve(true).length == 0;
|
||||
String message = JavaErrorMessages.message(missing ? "module.not.found" : "module.not.on.path", refElement.getReferenceText());
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents an {@code exports} statement of a Java module declaration.
|
||||
*
|
||||
@@ -26,4 +29,8 @@ public interface PsiExportsStatement extends PsiElement {
|
||||
PsiExportsStatement[] EMPTY_ARRAY = new PsiExportsStatement[0];
|
||||
|
||||
@Nullable PsiJavaCodeReferenceElement getPackageReference();
|
||||
@Nullable String getPackageName();
|
||||
|
||||
@NotNull Iterable<PsiJavaModuleReferenceElement> getModuleReferences();
|
||||
@NotNull List<String> getModuleNames();
|
||||
}
|
||||
@@ -26,4 +26,7 @@ public interface PsiRequiresStatement extends PsiElement {
|
||||
PsiRequiresStatement[] EMPTY_ARRAY = new PsiRequiresStatement[0];
|
||||
|
||||
@Nullable PsiJavaModuleReferenceElement getReferenceElement();
|
||||
@Nullable String getModuleName();
|
||||
|
||||
boolean isPublic();
|
||||
}
|
||||
@@ -15,26 +15,70 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.compiled;
|
||||
|
||||
import com.intellij.openapi.util.AtomicNotNullLazyValue;
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiExportsStatement;
|
||||
import com.intellij.psi.PsiJavaCodeReferenceElement;
|
||||
import com.intellij.psi.PsiJavaModuleReferenceElement;
|
||||
import com.intellij.psi.impl.java.stubs.PsiExportsStatementStub;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.impl.source.tree.TreeElement;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ClsExportsStatementImpl extends ClsRepositoryPsiElement<PsiExportsStatementStub> implements PsiExportsStatement {
|
||||
private final NotNullLazyValue<PsiJavaCodeReferenceElement> myPackageReference;
|
||||
private final NotNullLazyValue<Iterable<PsiJavaModuleReferenceElement>> myModuleReferences;
|
||||
|
||||
public ClsExportsStatementImpl(PsiExportsStatementStub stub) {
|
||||
super(stub);
|
||||
myPackageReference = new AtomicNotNullLazyValue<PsiJavaCodeReferenceElement>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiJavaCodeReferenceElement compute() {
|
||||
return new ClsJavaCodeReferenceElementImpl(ClsExportsStatementImpl.this, getStub().getPackageName());
|
||||
}
|
||||
};
|
||||
myModuleReferences = new AtomicNotNullLazyValue<Iterable<PsiJavaModuleReferenceElement>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Iterable<PsiJavaModuleReferenceElement> compute() {
|
||||
return ContainerUtil.map(getStub().getTargets(), new Function<String, PsiJavaModuleReferenceElement>() {
|
||||
@Override
|
||||
public PsiJavaModuleReferenceElement fun(String target) {
|
||||
return new ClsJavaModuleReferenceElementImpl(ClsExportsStatementImpl.this, target);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiJavaCodeReferenceElement getPackageReference() {
|
||||
return myPackageReference.getValue();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiJavaCodeReferenceElement getPackageReference() {
|
||||
return null;
|
||||
public String getPackageName() {
|
||||
return StringUtil.nullize(getStub().getPackageName());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<PsiJavaModuleReferenceElement> getModuleReferences() {
|
||||
return myModuleReferences.getValue();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getModuleNames() {
|
||||
return getStub().getTargets();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+23
-1
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.compiled;
|
||||
|
||||
import com.intellij.openapi.util.AtomicNotNullLazyValue;
|
||||
import com.intellij.openapi.util.NotNullLazyValue;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiJavaModuleReferenceElement;
|
||||
import com.intellij.psi.PsiRequiresStatement;
|
||||
@@ -25,14 +27,34 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ClsRequiresStatementImpl extends ClsRepositoryPsiElement<PsiRequiresStatementStub> implements PsiRequiresStatement {
|
||||
private final NotNullLazyValue<PsiJavaModuleReferenceElement> myModuleReference;
|
||||
|
||||
public ClsRequiresStatementImpl(PsiRequiresStatementStub stub) {
|
||||
super(stub);
|
||||
myModuleReference = new AtomicNotNullLazyValue<PsiJavaModuleReferenceElement>() {
|
||||
@NotNull
|
||||
@Override
|
||||
protected PsiJavaModuleReferenceElement compute() {
|
||||
return new ClsJavaModuleReferenceElementImpl(ClsRequiresStatementImpl.this, getStub().getModuleName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiJavaModuleReferenceElement getReferenceElement() {
|
||||
return null;
|
||||
return myModuleReference.getValue();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getModuleName() {
|
||||
return getStub().getModuleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPublic() {
|
||||
return getStub().isPublic();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,16 +16,19 @@
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.JavaElementVisitor;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiExportsStatement;
|
||||
import com.intellij.psi.PsiJavaCodeReferenceElement;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
|
||||
import com.intellij.psi.impl.java.stubs.PsiExportsStatementStub;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.SyntaxTraverser.psiTraverser;
|
||||
|
||||
public class PsiExportsStatementImpl extends JavaStubPsiElement<PsiExportsStatementStub> implements PsiExportsStatement {
|
||||
public PsiExportsStatementImpl(@NotNull PsiExportsStatementStub stub) {
|
||||
super(stub, JavaStubElementTypes.EXPORTS_STATEMENT);
|
||||
@@ -41,6 +44,39 @@ public class PsiExportsStatementImpl extends JavaStubPsiElement<PsiExportsStatem
|
||||
return PsiTreeUtil.getChildOfType(this, PsiJavaCodeReferenceElement.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getPackageName() {
|
||||
PsiExportsStatementStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return StringUtil.nullize(stub.getPackageName());
|
||||
}
|
||||
else {
|
||||
PsiJavaCodeReferenceElement ref = getPackageReference();
|
||||
return ref != null ? PsiNameHelper.getQualifiedClassName(ref.getText(), true) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<PsiJavaModuleReferenceElement> getModuleReferences() {
|
||||
return psiTraverser().children(this).filter(PsiJavaModuleReferenceElement.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<String> getModuleNames() {
|
||||
PsiExportsStatementStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getTargets();
|
||||
}
|
||||
else {
|
||||
List<String> targets = ContainerUtil.newSmartList();
|
||||
for (PsiJavaModuleReferenceElement refElement : getModuleReferences()) targets.add(refElement.getReferenceText());
|
||||
return targets;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JavaElementVisitor) {
|
||||
|
||||
@@ -19,17 +19,29 @@ import com.intellij.core.JavaCoreBundle;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.FileIndexFacade;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
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.CachedValuesManager;
|
||||
import com.intellij.psi.util.ParameterizedCachedValue;
|
||||
import com.intellij.psi.util.ParameterizedCachedValueProvider;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import static com.intellij.openapi.util.Pair.pair;
|
||||
import static com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT;
|
||||
|
||||
public class PsiJavaModuleReference extends PsiReferenceBase.Poly<PsiJavaModuleReferenceElement> {
|
||||
public PsiJavaModuleReference(@NotNull PsiJavaModuleReferenceElement element) {
|
||||
@@ -75,10 +87,24 @@ public class PsiJavaModuleReference extends PsiReferenceBase.Poly<PsiJavaModuleR
|
||||
@NotNull
|
||||
@Override
|
||||
public ResolveResult[] resolve(@NotNull PsiJavaModuleReference reference, boolean incompleteCode) {
|
||||
Project project = reference.getProject();
|
||||
PsiFile file = reference.getElement().getContainingFile();
|
||||
String moduleName = reference.getCanonicalText();
|
||||
Collection<PsiJavaModule> modules = findModules(file, moduleName, incompleteCode);
|
||||
if (!modules.isEmpty()) {
|
||||
ResolveResult[] result = new ResolveResult[modules.size()];
|
||||
int i = 0;
|
||||
for (PsiJavaModule module : modules) result[i++] = new PsiElementResolveResult(module);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return ResolveResult.EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
private static Collection<PsiJavaModule> findModules(PsiFile file, String moduleName, boolean incompleteCode) {
|
||||
Project project = file.getProject();
|
||||
|
||||
GlobalSearchScope scope = null;
|
||||
PsiFile file = reference.getElement().getContainingFile();
|
||||
if (incompleteCode || file.getOriginalFile() instanceof PsiCompiledFile) {
|
||||
scope = GlobalSearchScope.allScope(project);
|
||||
}
|
||||
@@ -92,18 +118,24 @@ public class PsiJavaModuleReference extends PsiReferenceBase.Poly<PsiJavaModuleR
|
||||
}
|
||||
}
|
||||
|
||||
if (scope != null) {
|
||||
JavaFileManager service = JavaFileManager.SERVICE.getInstance(project);
|
||||
Collection<PsiJavaModule> modules = service.findModules(reference.getCanonicalText(), scope);
|
||||
if (!modules.isEmpty()) {
|
||||
ResolveResult[] result = new ResolveResult[modules.size()];
|
||||
int i = 0;
|
||||
for (PsiJavaModule module : modules) result[i++] = new PsiElementResolveResult(module);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return ResolveResult.EMPTY_ARRAY;
|
||||
return scope != null ? JavaFileManager.SERVICE.getInstance(project).findModules(moduleName, scope) : Collections.<PsiJavaModule>emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Key<ParameterizedCachedValue<PsiJavaModule, Pair<String, Boolean>>> KEY = Key.create("java.module.ref.text.resolve");
|
||||
|
||||
@Nullable
|
||||
public static PsiJavaModule resolve(@NotNull final PsiElement refOwner, String refText, boolean incompleteCode) {
|
||||
if (StringUtil.isEmpty(refText)) return null;
|
||||
CachedValuesManager manager = CachedValuesManager.getManager(refOwner.getProject());
|
||||
return manager.getParameterizedCachedValue(refOwner, KEY, new ParameterizedCachedValueProvider<PsiJavaModule, Pair<String, Boolean>>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CachedValueProvider.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);
|
||||
}
|
||||
}, false, pair(refText, incompleteCode));
|
||||
}
|
||||
}
|
||||
@@ -16,13 +16,11 @@
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.JavaElementVisitor;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiJavaModuleReferenceElement;
|
||||
import com.intellij.psi.PsiRequiresStatement;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
|
||||
import com.intellij.psi.impl.java.stubs.PsiRequiresStatementStub;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -41,6 +39,34 @@ public class PsiRequiresStatementImpl extends JavaStubPsiElement<PsiRequiresStat
|
||||
return PsiTreeUtil.getChildOfType(this, PsiJavaModuleReferenceElement.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getModuleName() {
|
||||
PsiRequiresStatementStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.getModuleName();
|
||||
}
|
||||
else {
|
||||
PsiJavaModuleReferenceElement refElement = getReferenceElement();
|
||||
return refElement != null ? refElement.getReferenceText() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPublic() {
|
||||
PsiRequiresStatementStub stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isPublic();
|
||||
}
|
||||
else {
|
||||
for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (PsiUtil.isJavaToken(child, JavaTokenType.PUBLIC_KEYWORD)) return true;
|
||||
if (child instanceof PsiJavaModuleReferenceElement) break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor) {
|
||||
if (visitor instanceof JavaElementVisitor) {
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon
|
||||
|
||||
import com.intellij.psi.PsiJavaModule
|
||||
import com.intellij.testFramework.fixtures.LightJava9ModulesCodeInsightFixtureTestCase
|
||||
import com.intellij.testFramework.fixtures.MultiModuleJava9ProjectDescriptor.ModuleDescriptor.*
|
||||
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
|
||||
class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
|
||||
@@ -54,7 +52,7 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
|
||||
<error descr="Duplicate uses: pkg.main.C">uses pkg. main . /*...*/ C;</error>
|
||||
provides pkg .main .C with pkg.main.Impl;
|
||||
<error descr="Duplicate provides: pkg.main.C / pkg.main.Impl">provides pkg.main.C with pkg. main. Impl;</error>
|
||||
}""".trimIndent(), true)
|
||||
}""".trimIndent())
|
||||
}
|
||||
|
||||
fun testUnusedStatements() {
|
||||
@@ -63,7 +61,7 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
|
||||
highlight("""
|
||||
module M {
|
||||
provides pkg.main.<warning descr="Service interface provided but not exported or used">C</warning> with pkg.main.Impl;
|
||||
}""".trimIndent(), true)
|
||||
}""".trimIndent())
|
||||
}
|
||||
|
||||
fun testRequires() {
|
||||
@@ -74,7 +72,7 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
|
||||
requires <error descr="Cyclic dependence: M1">M1</error>;
|
||||
requires <error descr="Cyclic dependence: M1, M2">M2</error>;
|
||||
requires <error descr="Module is not in dependencies: M3">M3</error>;
|
||||
}""".trimIndent(), true)
|
||||
}""".trimIndent())
|
||||
}
|
||||
|
||||
fun testExports() {
|
||||
@@ -137,7 +135,7 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
|
||||
|
||||
fun testPackageAccessibility() {
|
||||
addFile("module-info.java", "module M { requires M2; requires M6; }")
|
||||
addFile("module-info.java", "module M2 { exports pkg.m2; }", M2)
|
||||
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)
|
||||
addFile("pkg/m4/C4.java", "package pkg.m4;\npublic class C4 { }", M4)
|
||||
@@ -159,17 +157,14 @@ class ModuleHighlightingTest : LightJava9ModulesCodeInsightFixtureTestCase() {
|
||||
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;
|
||||
|
||||
class C { }
|
||||
""".trimIndent(), true)
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
//<editor-fold desc="Helpers.">
|
||||
private fun highlight(text: String, filter: Boolean = false) = highlight("module-info.java", text, filter)
|
||||
private fun highlight(text: String) = highlight("module-info.java", text)
|
||||
|
||||
private fun highlight(path: String, text: String, filter: Boolean = false) {
|
||||
private fun highlight(path: String, text: String) {
|
||||
myFixture.configureFromExistingVirtualFile(addFile(path, text))
|
||||
if (filter) {
|
||||
(myFixture as CodeInsightTestFixtureImpl).setVirtualFileFilter { it.name != PsiJavaModule.MODULE_INFO_FILE }
|
||||
}
|
||||
myFixture.checkHighlighting()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user