| /******************************************************************************* |
| * 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); |
| } |
| } |
| } |