Skip to content

Commit

Permalink
[23] Search support for module imports (eclipse-jdt#2855)
Browse files Browse the repository at this point in the history
+ several locations to generalize from isStatic to modifiers
+ remove bogus subarray() calls "extracting" the entire array

fixes eclipse-jdt#2852
  • Loading branch information
stephan-herrmann authored Aug 22, 2024
1 parent 2246806 commit 4e4e4fd
Show file tree
Hide file tree
Showing 15 changed files with 201 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ public abstract class ASTNode implements TypeConstants, TypeIds {
// for import reference
public static final int OnDemand = Bit18;
public static final int Used = Bit2;
public static final int inModule = Bit19;
public static final int inModule = Bit19; // signals the package reference of an exports or opens declaration

// for parameterized qualified/single type ref
public static final int DidResolve = Bit19;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -792,10 +792,19 @@ ImportBinding[] getDefaultImports() {
return this.environment.root.defaultImports = new ImportBinding[] {new ImportBinding(TypeConstants.JAVA_LANG, true, importBinding, null)};
}
// NOT Public API
public final Binding getImport(char[][] compoundName, boolean onDemand, boolean isStaticImport) {
if (onDemand)
return findImport(compoundName, compoundName.length);
return findSingleImport(compoundName, Binding.TYPE | Binding.FIELD | Binding.METHOD, isStaticImport);
public final Binding getImport(char[][] compoundName, boolean onDemand, int modifiers) {
if (onDemand) {
if ((modifiers & ClassFileConstants.AccModule) != 0) {
ModuleBinding importedModule = this.environment.getModule(CharOperation.concatWith(compoundName, '.'));
if (importedModule != null && module().reads(importedModule))
return importedModule;
return null;
} else {
return findImport(compoundName, compoundName.length);
}
} else {
return findSingleImport(compoundName, Binding.TYPE | Binding.FIELD | Binding.METHOD, (modifiers & ClassFileConstants.AccStatic) != 0);
}
}

public int nextCaptureID() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*******************************************************************************
* Copyright (c) 2024 GK Software SE and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* Stephan Herrmann - Initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.model;

import java.io.IOException;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchPattern;

import junit.framework.Test;

public class JavaSearchBugs23Tests extends AbstractJavaSearchTests {

public JavaSearchBugs23Tests(String name) {
super(name);
}

public static Test suite() {
return buildModelTestSuite(JavaSearchBugs23Tests.class, BYTECODE_DECLARATION_ORDER);
}

class TestCollector extends JavaSearchResultCollector {
@Override
public void acceptSearchMatch(SearchMatch searchMatch) throws CoreException {
super.acceptSearchMatch(searchMatch);
}
}

@Override
IJavaSearchScope getJavaSearchScope() {
return SearchEngine.createJavaSearchScope(new IJavaProject[] {getJavaProject("JavaSearchBugs23")});
}
IJavaSearchScope getJavaSearchScopeBugs(String packageName, boolean addSubpackages) throws JavaModelException {
if (packageName == null) return getJavaSearchScope();
return getJavaSearchPackageScope("JavaSearchBugs", packageName, addSubpackages);
}
@Override
public ICompilationUnit getWorkingCopy(String path, String source) throws JavaModelException {
if (this.wcOwner == null) {
this.wcOwner = new WorkingCopyOwner() {};
}
return getWorkingCopy(path, source, this.wcOwner);
}
@Override
public void setUpSuite() throws Exception {
super.setUpSuite();
JAVA_PROJECT = setUpJavaProject("JavaSearchBugs23", "23");
JAVA_PROJECT.setOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
}
@Override
public void tearDownSuite() throws Exception {
deleteProject("JavaSearchBugs23");
super.tearDownSuite();
}
@Override
protected void setUp () throws Exception {
super.setUp();
this.resultCollector = new TestCollector();
this.resultCollector.showAccuracy(true);
}

public void testModuleImport() throws CoreException, IOException {
IModuleDescription module = JAVA_PROJECT.findModule("mod.one", this.wcOwner);
search(module, ALL_OCCURRENCES, EXACT_RULE);
assertSearchResults("""
src/modimp/X.java [mod.one] EXACT_MATCH
lib/mod.one.jar mod.one [No source] EXACT_MATCH""");
}

public void testModuleImportPatternReferences() throws CoreException, IOException {
SearchPattern pattern = SearchPattern.createPattern("*od.*", IJavaSearchConstants.MODULE, REFERENCES, SearchPattern.R_EXACT_MATCH);
search(pattern, getJavaSearchScope(), this.resultCollector);
assertSearchResults("""
src/modimp/X.java [mod.one] EXACT_MATCH""");
}

public void testModuleImportPrefixDeclaration() throws CoreException, IOException {
SearchPattern pattern = SearchPattern.createPattern("mod", IJavaSearchConstants.MODULE, DECLARATIONS, SearchPattern.R_PREFIX_MATCH);
search(pattern, getJavaSearchScope(), this.resultCollector);
assertSearchResults("""
lib/mod.one.jar mod.one [No source] EXACT_MATCH""");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
*******************************************************************************/
package org.eclipse.jdt.core.tests.model;

import java.lang.reflect.*;
import java.util.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.core.tests.junit.extension.TestCase;

Expand Down Expand Up @@ -71,6 +73,7 @@ public static Test suite() {
allClasses.add(JavaSearchBugs17Tests.class);
allClasses.add(JavaSearchBugs19Tests.class);
allClasses.add(JavaSearchBugs21Tests.class);
allClasses.add(JavaSearchBugs23Tests.class);
allClasses.add(JavaSearchMultipleProjectsTests.class);
allClasses.add(SearchTests.class);
allClasses.add(JavaSearchScopeTests.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="var" path="JCL_23_LIB" sourcepath="JCL_23_SRC" rootpath="JCL_SRCROOT"/>
<classpathentry kind="lib" path="lib/mod.one.jar">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin"/>
</classpath>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>JavaSearchBugs23</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package mod;

import mod.one.*; // try to confuse the search for module 'mod.one'

public class Y {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package mod.one;

public class Z {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package modimp;

import module mod.one;

public class X {}
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ synchronized IBinding resolveImport(ImportDeclaration importDeclaration) {
ImportReference importReference = (ImportReference) node;
final boolean isStatic = importReference.isStatic();
if ((importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0) {
Binding binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, importReference.tokens.length), true, isStatic);
Binding binding = this.scope.getImport(importReference.tokens, true, importReference.modifiers);
if (binding != null) {
if (isStatic) {
if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
Expand All @@ -864,7 +864,7 @@ synchronized IBinding resolveImport(ImportDeclaration importDeclaration) {
}
}
} else {
Binding binding = this.scope.getImport(importReference.tokens, false, isStatic);
Binding binding = this.scope.getImport(importReference.tokens, false, importReference.modifiers);
if (binding != null) {
if (isStatic) {
if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) {
Expand Down Expand Up @@ -1172,13 +1172,13 @@ synchronized ITypeBinding resolveTypeBindingForName(Name name) {
if (this.scope == null) return null;
if (importReferenceLength == index) {
try {
binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), (importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0, importReference.isStatic());
binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), (importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0, importReference.modifiers);
} catch (AbortCompilation e) {
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
}
} else {
try {
binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), true, importReference.isStatic());
binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), true, importReference.modifiers);
} catch (AbortCompilation e) {
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
}
Expand Down Expand Up @@ -1404,13 +1404,13 @@ synchronized IBinding resolveName(Name name) {
if (this.scope == null) return null;
if (importReferenceLength == index && !inModule) {
try {
binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), (importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0, importReference.isStatic());
binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), (importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0, importReference.modifiers);
} catch (AbortCompilation e) {
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
}
} else {
try {
binding = this.scope.getImport(inModule ? importReference.tokens : CharOperation.subarray(importReference.tokens, 0, index), true, importReference.isStatic());
binding = this.scope.getImport(inModule ? importReference.tokens : CharOperation.subarray(importReference.tokens, 0, index), true, importReference.modifiers);
} catch (AbortCompilation e) {
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.core.search.processing.JobManager;

Expand Down Expand Up @@ -91,7 +92,10 @@ public void acceptFieldReference(char[] fieldName, int sourcePosition) {
*/
@Override
public void acceptImport(int declarationStart, int declarationEnd, int nameStart, int nameEnd, char[][] tokens, boolean onDemand, int modifiers) {
// imports have already been reported while creating the ImportRef node (see SourceElementParser#comsume*ImportDeclarationName() methods)
if ((modifiers & ClassFileConstants.AccModule) != 0) {
this.indexer.addModuleReference(CharOperation.concatWithAll(tokens, '.'));
}
// other imports have already been reported while creating the ImportRef node (see SourceElementParser#comsume*ImportDeclarationName() methods)
}
/**
* @see ISourceElementRequestor#acceptLineSeparatorPositions(int[])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ protected void consumeStaticImportOnDemandDeclarationName() {
}
}
@Override
protected void consumeSingleStaticImportDeclarationName() {
super.consumeSingleStaticImportDeclarationName();
protected void consumeSingleModifierImportDeclarationName(int modifier) {
super.consumeSingleModifierImportDeclarationName(modifier);
if (this.reportImportMatch) {
this.patternLocator.match(this.astStack[this.astPtr], this.nodeSet);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2793,11 +2793,10 @@ protected void reportMatching(CompilationUnitDeclaration unit, boolean mustResol

ImportReference importRef = (ImportReference) node;
boolean inModule = (importRef.bits & ASTNode.inModule) != 0;
boolean getOnDemand = (importRef.bits & ASTNode.OnDemand) != 0 || inModule;
Binding binding = getOnDemand
? this.unitScope.getImport(CharOperation.subarray(importRef.tokens, 0, importRef.tokens.length), true, importRef.isStatic())
: this.unitScope.getImport(importRef.tokens, false, importRef.isStatic());
if (inModule) {
boolean isOnDemand = (importRef.bits & ASTNode.OnDemand) != 0 || inModule;
boolean isModuleImport = (importRef.modifiers & ClassFileConstants.AccModule) != 0;
Binding binding = this.unitScope.getImport(importRef.tokens, isOnDemand, importRef.modifiers);
if (inModule || isModuleImport) {
nodeSet.addMatch(node, this.patternLocator.resolveLevel(binding)); // report all module-info together
} else {
this.patternLocator.matchLevelAndReportImportRef(importRef, binding, this);
Expand Down Expand Up @@ -3069,7 +3068,7 @@ private void reportMatching(PackageVisibilityStatement[] psvs, MatchingNodeSet n
ImportReference importRef = psv.pkgRef;
Integer level = (Integer) nodeSet.matchingNodes.removeKey(importRef);
if (level != null) {
Binding binding = this.unitScope.getImport(CharOperation.subarray(importRef.tokens, 0, importRef.tokens.length), true, false);
Binding binding = this.unitScope.getImport(importRef.tokens, true, 0);
this.patternLocator.matchReportImportRef(importRef, binding, moduleDesc, level.intValue(), this);
}
ModuleReference[] tgts = psv.targets;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
import org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ModuleReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;

Expand Down Expand Up @@ -50,6 +53,17 @@ protected int match(ModuleReference node, MatchingNodeSet nodeSet) {
return nodeSet.addMatch(node, POSSIBLE_MATCH);
}
@Override
public int match(ASTNode node, MatchingNodeSet nodeSet) {
if (node instanceof ImportReference impt && (impt.modifiers & ClassFileConstants.AccModule) != 0) {
if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
char[] moduleName = CharOperation.concatWith(impt.tokens, '.');
if (!matchesName(this.pattern.name, moduleName)) return IMPOSSIBLE_MATCH;
nodeSet.mustResolve = true;
return nodeSet.addMatch(node, POSSIBLE_MATCH);
}
return IMPOSSIBLE_MATCH;
}
@Override
protected int matchContainer() {
return COMPILATION_UNIT_CONTAINER;
}
Expand Down

0 comments on commit 4e4e4fd

Please sign in to comment.