blob: 0f8398bca41d6ce86c21c74ca658566d51875f54 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2016 Google, Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Stefan Xenos (Google) - Initial implementation
*******************************************************************************/
package org.eclipse.jdt.core.tests.nd.indexer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Semaphore;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IOrdinaryClassFile;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IParent;
import org.eclipse.jdt.core.tests.model.AbstractJavaModelTests;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.core.nd.IReader;
import org.eclipse.jdt.internal.core.nd.db.ChunkCache;
import org.eclipse.jdt.internal.core.nd.db.Database;
import org.eclipse.jdt.internal.core.nd.indexer.IndexTester;
import org.eclipse.jdt.internal.core.nd.indexer.Indexer;
import org.eclipse.jdt.internal.core.nd.java.JavaIndex;
import org.eclipse.jdt.internal.core.nd.java.NdType;
import org.eclipse.jdt.internal.core.nd.java.NdTypeId;
import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeDescriptor;
import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeFactory;
import org.eclipse.jdt.internal.core.nd.java.model.IndexBinaryType;
import junit.framework.Test;
/**
* Tests for the {@link Database} class.
*/
public class IndexerTest extends AbstractJavaModelTests {
public IndexerTest(String name) {
super(name);
}
private static final String PROJECT_NAME = "IndexerTest";
private static JavaIndex index;
@Override
protected void setUp() throws Exception {
String testName = getName();
index = JavaIndexTestUtil.createTempIndex(testName);
super.setUp();
}
@Override
protected void tearDown() throws Exception {
deleteProject(PROJECT_NAME);
index.getNd().getPath().delete();
index = null;
super.tearDown();
}
public static Test suite() {
return buildModelTestSuite(IndexerTest.class);
}
/**
* Verifies that if the index fails a read due to call to {@link Thread#interrupt()}, subsequent reads will
* still succeed.
*/
public void testInterruptedException() throws Exception {
createJavaProject(PROJECT_NAME, new String[] {"src"}, new String[] {"JCL18_FULL"}, "bin", "1.8", true);
// Create an indexfa
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
Indexer indexer = new Indexer(index.getNd(), root);
indexer.rescan(SubMonitor.convert(null));
// Ensure we're starting with an empty page cache by creating a new
// Index accessor object on the same database
JavaIndex testIndex = JavaIndex
.getIndex(JavaIndex.createNd(index.getNd().getDB().getLocation(), new ChunkCache()));
Semaphore semaphore = new Semaphore(0);
boolean[] wasInterrupted = new boolean[1];
Thread newThread = new Thread(() -> {
try (IReader reader = testIndex.getNd().acquireReadLock()) {
Thread.currentThread().interrupt();
testIndex.findType("Ljava/util/List;".toCharArray());
} catch (OperationCanceledException e) {
wasInterrupted[0] = true;
} finally {
semaphore.release();
}
});
newThread.start();
semaphore.acquire();
assertTrue(wasInterrupted[0]);
try (IReader reader = testIndex.getNd().acquireReadLock()) {
NdTypeId type = testIndex.findType("Ljava/util/List;".toCharArray());
assertNotNull(type);
}
}
public void testSubclassesOfGenericTypeCanBeFound() throws Exception {
createJavaProject(PROJECT_NAME, new String[] {"src"}, new String[] {"JCL18_FULL"}, "bin", "1.8", true);
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
Indexer indexer = new Indexer(index.getNd(), root);
indexer.rescan(SubMonitor.convert(null));
try (IReader reader = IndexerTest.index.getNd().acquireReadLock()) {
NdTypeId javaUtilList = IndexerTest.index.findType("Ljava/util/List;".toCharArray());
NdTypeId javaUtilArrayList = IndexerTest.index.findType("Ljava/util/ArrayList;".toCharArray());
boolean found = false;
List<NdType> subtypes = javaUtilList.getSubTypes();
for (NdType next : subtypes) {
if (Objects.equals(next.getTypeId(), javaUtilArrayList)) {
found = true;
}
}
assertTrue("ArrayList was found as a subtype of List", found);
}
}
private void collectAllClassFiles(List<? super IClassFile> result, IParent nextRoot) throws CoreException {
for (IJavaElement child : nextRoot.getChildren()) {
int type = child.getElementType();
if (type == IJavaElement.CLASS_FILE) {
result.add((IClassFile) child);
} else if (child instanceof IParent) {
IParent parent = (IParent) child;
collectAllClassFiles(result, parent);
}
}
}
public void testReadingAllClassesInIndexAreEquivalentToOriginalJarFiles() throws Exception {
IJavaProject javaProject = createJavaProject(PROJECT_NAME, new String[] {"src"}, new String[] {"JCL18_FULL"}, "bin", "1.8", true);
addClassFolder(javaProject, "lib", new String[] {
"p/Outer.java",
"import java.lang.annotation.*;\n" +
"\n" +
"@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) @interface A0 {}\n" +
"@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) @interface A {}\n" +
"@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface M {}\n" +
"@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) @interface P {}\n" +
"\n" +
"class Outer {\n" +
" class Middle1 {\n" +
" class Inner {}\n" +
" }\n" +
" static class Middle2 {\n" +
" class Inner {}\n" +
" static class Middle3 {\n" +
" class Inner2{};\n" +
" }\n" +
" }\n" +
" Middle1.@A Inner e1;\n" +
" Middle2.@A Inner e2;\n" +
" Middle2.Middle3.@A Inner2 e3;\n" +
" @M void foo(@A0 Object p0, @P Middle2.Middle3.@A Inner2 e3) {};\n" +
" class Middle4 extends @A Middle1 {}\n" +
"}\n",
}, "1.8");
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
Indexer indexer = new Indexer(index.getNd(), root);
indexer.rescan(SubMonitor.convert(null));
boolean foundAtLeastOneClass = false;
SubMonitor subMonitor = SubMonitor.convert(null);
JavaIndex localIndex = IndexerTest.index;
try (IReader reader = localIndex.getNd().acquireReadLock()) {
IPackageFragmentRoot[] roots = javaProject.getAllPackageFragmentRoots();
subMonitor.setWorkRemaining(roots.length);
for (IPackageFragmentRoot next : roots) {
SubMonitor iterationMon = subMonitor.split(1);
if (next.getKind() == IPackageFragmentRoot.K_BINARY) {
List<IClassFile> result = new ArrayList<>();
collectAllClassFiles(result, next);
iterationMon.setWorkRemaining(result.size());
for (IClassFile nextClass : result) {
if (!(nextClass instanceof IOrdinaryClassFile)) continue;
SubMonitor classMon = iterationMon.split(1);
BinaryTypeDescriptor descriptor = BinaryTypeFactory.createDescriptor((IOrdinaryClassFile) nextClass);
IndexBinaryType indexedBinaryType = (IndexBinaryType)BinaryTypeFactory.readFromIndex(localIndex, descriptor, classMon);
ClassFileReader originalBinaryType = BinaryTypeFactory.rawReadType(descriptor, true);
if (!indexedBinaryType.exists()) {
throw new IllegalStateException("Unable to find class in index " + new String(descriptor.indexPath));
}
IndexTester.testType(originalBinaryType, indexedBinaryType);
foundAtLeastOneClass = true;
}
}
}
}
assertTrue("No classes found in the index", foundAtLeastOneClass);
}
public void testFindTypesBySimpleName() throws CoreException {
createJavaProject(PROJECT_NAME, new String[] {"src"}, new String[] {"JCL18_FULL"}, "bin", "1.8", true);
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
Indexer indexer = new Indexer(index.getNd(), root);
indexer.rescan(SubMonitor.convert(null));
try (IReader reader = IndexerTest.index.getNd().acquireReadLock()) {
List<Object> javaUtilList = IndexerTest.index.findTypesBySimpleName("ArrayList".toCharArray()).stream()
.map(new Function<NdTypeId, String>() {
@Override
public String apply(NdTypeId typeId) {
return typeId.toString();
}
}).collect(Collectors.toList());
System.out.println(javaUtilList);
assertTrue("Test failed", javaUtilList.contains("Ljava/util/ArrayList;"));
}
}
public void testFindTypesBySimpleNameFirstWord() throws CoreException {
createJavaProject(PROJECT_NAME, new String[] {"src"}, new String[] {"JCL18_FULL"}, "bin", "1.8", true);
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
Indexer indexer = new Indexer(index.getNd(), root);
indexer.rescan(SubMonitor.convert(null));
try (IReader reader = IndexerTest.index.getNd().acquireReadLock()) {
List<Object> javaUtilList = IndexerTest.index.findTypesBySimpleName("Array".toCharArray()).stream()
.map(new Function<NdTypeId, String>() {
@Override
public String apply(NdTypeId typeId) {
return typeId.toString();
}
}).collect(Collectors.toList());
System.out.println(javaUtilList);
assertTrue("Test failed",
javaUtilList.containsAll(Arrays.asList("Ljava/sql/Array;", "Ljava/lang/reflect/Array;",
"Ljava/util/concurrent/ArrayBlockingQueue;", "Ljava/util/ArrayDeque;",
"Ljava/lang/ArrayIndexOutOfBoundsException;", "Ljava/util/ArrayList;",
"Ljava/util/ArrayPrefixHelpers;", "Ljava/util/Arrays;",
"Ljava/util/ArraysParallelSortHelpers;", "Ljava/lang/ArrayStoreException;")));
}
}
public void testFindTypesBySimpleNameFirstLetterCount10() throws CoreException {
createJavaProject(PROJECT_NAME, new String[] {"src"}, new String[] {"JCL18_FULL"}, "bin", "1.8", true);
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
Indexer indexer = new Indexer(index.getNd(), root);
indexer.rescan(SubMonitor.convert(null));
try (IReader reader = IndexerTest.index.getNd().acquireReadLock()) {
List<Object> javaUtilList = IndexerTest.index.findTypesBySimpleName("A".toCharArray(), 10).stream()
.map(new Function<NdTypeId, String>() {
@Override
public String apply(NdTypeId typeId) {
return typeId.toString();
}
}).collect(Collectors.toList());
System.out.println(javaUtilList);
assertTrue("Test failed", javaUtilList.size() == 10);
}
}
}