diff options
author | Manoj Palat | 2021-01-04 05:56:01 +0000 |
---|---|---|
committer | Manoj Palat | 2021-01-04 06:07:53 +0000 |
commit | 9007a83c2488885d0ccac052ef8a8c04f1cd5736 (patch) | |
tree | 6bde76e28758a9ff0a4d3d30bc4877ebe4a9c43c | |
parent | 11169783ee3de0c3c47bdfe2fe93c52f17b1b06a (diff) | |
parent | d5c188d78ee37a5a78869313b94fa62ff542cea6 (diff) | |
download | eclipse.jdt.core-9007a83c2488885d0ccac052ef8a8c04f1cd5736.tar.gz eclipse.jdt.core-9007a83c2488885d0ccac052ef8a8c04f1cd5736.tar.xz eclipse.jdt.core-9007a83c2488885d0ccac052ef8a8c04f1cd5736.zip |
Merge branch 'master' into BETA_JAVA16
Change-Id: I1e5c50ff51bfb0165660070e94d9a85cfbc98089
Signed-off-by: Manoj Palat <manpalat@in.ibm.com>
37 files changed, 700 insertions, 92 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.tests.compiler/META-INF/MANIFEST.MF index 48ccc37f34..96ae5aa3b7 100644 --- a/org.eclipse.jdt.core.tests.compiler/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.core.tests.compiler/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.core.tests.compiler;singleton:=true -Bundle-Version: 3.12.1400.qualifier +Bundle-Version: 3.12.1500.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: org.eclipse.jdt.core.tests.compiler, diff --git a/org.eclipse.jdt.core.tests.compiler/pom.xml b/org.eclipse.jdt.core.tests.compiler/pom.xml index b9f1b7f33d..793238888a 100644 --- a/org.eclipse.jdt.core.tests.compiler/pom.xml +++ b/org.eclipse.jdt.core.tests.compiler/pom.xml @@ -20,7 +20,7 @@ </parent> <groupId>org.eclipse.jdt</groupId> <artifactId>org.eclipse.jdt.core.tests.compiler</artifactId> - <version>3.12.1400-SNAPSHOT</version> + <version>3.12.1500-SNAPSHOT</version> <packaging>eclipse-test-plugin</packaging> <properties> diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConstantTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConstantTest.java index 3d23a15138..0b9d164003 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConstantTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConstantTest.java @@ -45,7 +45,7 @@ public ConstantTest(String name) { // All specified tests which does not belong to the class are skipped... static { // TESTS_PREFIX = "testBug95521"; -// TESTS_NAMES = new String[] { "testBug83127a" }; +// TESTS_NAMES = new String[] { "testBug566332_01" }; // TESTS_NUMBERS = new int[] { 21 }; // TESTS_RANGE = new int[] { 23, -1 }; } @@ -1604,6 +1604,25 @@ public void testBug566332_04() { "case expressions must be constant expressions\n" + "----------\n"); } +public void testBug569498() { + if (this.complianceLevel < ClassFileConstants.JDK11) { + return; + } + this.runNegativeTest( + new String[] { + "X.java", + "public class X {\n" + + " final String s1 = \"\";\n" + + " public void m(Object s) {\n" + + " final boolean b = false;\n" + + " final String s2 = \"\";\n" + + " m(b? s1 : s2);\n" + + " }\n" + + " public static void main(String[] args) {}\n" + + "}", + }, + ""); +} public static Class testClass() { return ConstantTest.class; } diff --git a/org.eclipse.jdt.core.tests.model/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.tests.model/META-INF/MANIFEST.MF index bfe5fed044..dac7d7b51b 100644 --- a/org.eclipse.jdt.core.tests.model/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.core.tests.model/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.core.tests.model;singleton:=true -Bundle-Version: 3.10.1400.qualifier +Bundle-Version: 3.10.1500.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: org.eclipse.jdt.core.tests, diff --git a/org.eclipse.jdt.core.tests.model/pom.xml b/org.eclipse.jdt.core.tests.model/pom.xml index 396818dfd3..ad77b5273d 100644 --- a/org.eclipse.jdt.core.tests.model/pom.xml +++ b/org.eclipse.jdt.core.tests.model/pom.xml @@ -20,7 +20,7 @@ </parent> <groupId>org.eclipse.jdt</groupId> <artifactId>org.eclipse.jdt.core.tests.model</artifactId> - <version>3.10.1400-SNAPSHOT</version> + <version>3.10.1500-SNAPSHOT</version> <packaging>eclipse-test-plugin</packaging> <properties> diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java index 80a8a1dd2e..8e78f96099 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. + * Copyright (c) 2000, 2021 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -13231,4 +13231,36 @@ public void testBug567714() { " }\n" + "}"); } +/** + * https://bugs.eclipse.org/569798 - [formatter] Brace position - next line indented: bug for array within annotation + */ +public void testBug569798() { + this.formatterPrefs.brace_position_for_array_initializer = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED; + formatSource( + "class Test {\n" + + " @Nullable\n" + + " @SuppressWarnings(\n" + + " { \"\" })\n" + + " @Something(a =\n" + + " { \"\" })\n" + + " void f() {\n" + + " }\n" + + "}" + ); +} +/** + * https://bugs.eclipse.org/569964 - [formatter] Keep braced code on one line: problem with comments after javadoc + */ +public void testBug569964() { + this.formatterPrefs.keep_method_body_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_IF_EMPTY; + formatSource( + "class Test {\n" + + " /**\n" + + " * More Java doc comment\n" + + " */\n" + + " // A line comment\n" + + " /* package */ void nothing() {}\n" + + "}" + ); +} } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java index 06ff023b20..5024a9ed75 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java @@ -315,6 +315,13 @@ public class ExternalAnnotations18Test extends ModifyingResourceTests { this.project.setRawClasspath(rawClasspath, new NullProgressMonitor()); } + protected void addSourceFolderWithExternalAnnotations(IJavaProject javaProject, String sourceFolder, String outputFolder, String externalAnnotationPath) throws JavaModelException { + IClasspathAttribute[] extraAttributes = new IClasspathAttribute[] { new ClasspathAttribute(IClasspathAttribute.EXTERNAL_ANNOTATION_PATH, externalAnnotationPath) }; + IClasspathEntry entry = JavaCore.newSourceEntry(new Path(sourceFolder), null, null, + outputFolder != null ? new Path(outputFolder) : null, extraAttributes); + addClasspathEntry(javaProject, entry); + } + protected void createFileInProject(String projectRelativeFolder, String fileName, String content) throws CoreException { String folderPath = this.project.getProject().getName()+'/'+projectRelativeFolder; createFolder(folderPath); @@ -2666,4 +2673,154 @@ public class ExternalAnnotations18Test extends ModifyingResourceTests { deleteProject("Bug500024"); } } + + // reconcile client of a "generated" source+eea + @SuppressWarnings("deprecation") + public void testSourceFolder1() throws CoreException { + myCreateJavaProject("Bug509397"); + addSourceFolderWithExternalAnnotations(this.project, "/Bug509397/src-gen", "/Bug509397/bin-gen", "/Bug509397/annot-gen"); + + createFileInProject("annot-gen/pgen", "CGen.eea", + "class pgen/CGen\n" + + "\n" + + "get\n" + + " (Ljava/lang/String;)Ljava/lang/String;\n" + + " (L1java/lang/String;)L1java/lang/String;\n"); + + createFileInProject("src-gen/pgen", "CGen.java", + "package pgen;\n" + + "public class CGen {\n" + + " public String get(String in) { return in; }\n" + + "}\n"); + + IPackageFragment fragment = this.project.getPackageFragmentRoots()[0].createPackageFragment("p", true, null); + ICompilationUnit unit = fragment.createCompilationUnit("Use.java", + "package p;\n" + + "import pgen.CGen;\n" + + "import org.eclipse.jdt.annotation.NonNull;\n" + + "public class Use {\n" + + " public @NonNull String test(CGen c) {\n" + + " String s = c.get(null);\n" + // problem here (6) + " return s;\n" + // no problem here + " }\n" + + "}\n", + true, new NullProgressMonitor()).getWorkingCopy(new NullProgressMonitor()); + CompilationUnit reconciled = unit.reconcile(AST.JLS8, true, null, new NullProgressMonitor()); + IProblem[] problems = reconciled.getProblems(); + assertProblems(problems, new String[] { + "Pb(910) Null type mismatch: required '@NonNull String' but the provided value is null" + }, new int[] { 6 }); + } + + // reconcile client of a "generated" source+eea + // single merged output folder + @SuppressWarnings("deprecation") + public void testSourceFolder1a() throws CoreException { + myCreateJavaProject("Bug509397"); + addSourceFolderWithExternalAnnotations(this.project, "/Bug509397/src-gen", null, "/Bug509397/annot-gen"); + + createFileInProject("annot-gen/pgen", "CGen.eea", + "class pgen/CGen\n" + + "\n" + + "get\n" + + " (Ljava/lang/String;)Ljava/lang/String;\n" + + " (L1java/lang/String;)L1java/lang/String;\n"); + + createFileInProject("src-gen/pgen", "CGen.java", + "package pgen;\n" + + "public class CGen {\n" + + " public String get(String in) { return in; }\n" + + "}\n"); + this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); + + IPackageFragment fragment = this.project.getPackageFragmentRoots()[0].createPackageFragment("p", true, null); + ICompilationUnit unit = fragment.createCompilationUnit("Use.java", + "package p;\n" + + "import pgen.CGen;\n" + + "import org.eclipse.jdt.annotation.NonNull;\n" + + "public class Use {\n" + + " public @NonNull String test(CGen c) {\n" + + " String s = c.get(null);\n" + // problem here (6) + " return s;\n" + // no problem here + " }\n" + + "}\n", + true, new NullProgressMonitor()).getWorkingCopy(new NullProgressMonitor()); + CompilationUnit reconciled = unit.reconcile(AST.JLS8, true, null, new NullProgressMonitor()); + IProblem[] problems = reconciled.getProblems(); + assertProblems(problems, new String[] { + "Pb(910) Null type mismatch: required '@NonNull String' but the provided value is null" + }, new int[] { 6 }); + } + + // full build of a project with src-gen & annot-gen + public void testSourceFolder2() throws CoreException { + myCreateJavaProject("Bug509397"); + addSourceFolderWithExternalAnnotations(this.project, "/Bug509397/src-gen", "/Bug509397/bin-gen", "/Bug509397/annot-gen"); + + createFileInProject("annot-gen/pgen", "CGen.eea", + "class pgen/CGen\n" + + "\n" + + "get\n" + + " (Ljava/lang/String;)Ljava/lang/String;\n" + + " (L1java/lang/String;)L1java/lang/String;\n"); + + createFileInProject("src-gen/pgen", "CGen.java", + "package pgen;\n" + + "public class CGen {\n" + + " public String get(String in) { return in; }\n" + + "}\n"); + + createFileInProject("src/p", "Use.java", + "package p;\n" + + "import pgen.CGen;\n" + + "import org.eclipse.jdt.annotation.NonNull;\n" + + "public class Use {\n" + + " public @NonNull String test(CGen c) {\n" + + " String s = c.get(null);\n" + // problem here (6) + " return s;\n" + // no problem here + " }\n" + + "}\n"); + this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); + IMarker[] markers = this.project.getProject().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "Null type mismatch: required '@NonNull String' but the provided value is null", + markers); + } + + // full build of a project with src-gen & annot-gen + // single merged output folder + public void testSourceFolder2a() throws CoreException { + myCreateJavaProject("Bug509397"); + addSourceFolderWithExternalAnnotations(this.project, "/Bug509397/src-gen", null, "/Bug509397/annot-gen"); + + createFileInProject("annot-gen/pgen", "CGen.eea", + "class pgen/CGen\n" + + "\n" + + "get\n" + + " (Ljava/lang/String;)Ljava/lang/String;\n" + + " (L1java/lang/String;)L1java/lang/String;\n"); + + createFileInProject("src-gen/pgen", "CGen.java", + "package pgen;\n" + + "public class CGen {\n" + + " public String get(String in) { return in; }\n" + + "}\n"); + + createFileInProject("src/p", "Use.java", + "package p;\n" + + "import pgen.CGen;\n" + + "import org.eclipse.jdt.annotation.NonNull;\n" + + "public class Use {\n" + + " public @NonNull String test(CGen c) {\n" + + " String s = c.get(null);\n" + // problem here (6) + " return s;\n" + // no problem here + " }\n" + + "}\n"); + this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); + IMarker[] markers = this.project.getProject().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE); + assertMarkers("Unexpected markers", + "Null type mismatch: required '@NonNull String' but the provided value is null", + markers); + } + } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java index 53740a9e94..705a5ea3b3 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java @@ -8618,7 +8618,16 @@ public void testBug166348_Qualified() throws CoreException { * @test Ensure that types are found even when scope is not a {@link org.eclipse.jdt.internal.core.search.JavaSearchScope} * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=167190" */ +public void testBug167190_Parallel() throws CoreException, JavaModelException { + bug167190(true); +} + public void testBug167190() throws CoreException, JavaModelException { + bug167190(false); +} + +private void bug167190(boolean parallel) throws JavaModelException { + IJavaSearchScope scope = new AbstractSearchScope() { IJavaSearchScope jsScope = getJavaSearchScope(); public void processDelta(IJavaElementDelta delta, int eventType) { @@ -8633,6 +8642,10 @@ public void testBug167190() throws CoreException, JavaModelException { public IPath[] enclosingProjectsAndJars() { return this.jsScope.enclosingProjectsAndJars(); } + @Override + public boolean isParallelSearchSupported() { + return parallel; + } }; // Search all type names with TypeNameMatchRequestor TypeNameMatchCollector collector = new TypeNameMatchCollector() { @@ -8664,7 +8677,7 @@ public void testBug167190() throws CoreException, JavaModelException { IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, null); // Should have same types with these 2 searches - assertEquals("Found types sounds not to be correct", requestor.toString(), collector.toString()); + assertEquals(String.format("Found types sounds not to be correct [Parallel=%s]", parallel), requestor.toString(), collector.toString()); } /** diff --git a/org.eclipse.jdt.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.core/META-INF/MANIFEST.MF index 9ee7dc3fc8..8283b9880e 100644 --- a/org.eclipse.jdt.core/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.core/META-INF/MANIFEST.MF @@ -3,7 +3,7 @@ Main-Class: org.eclipse.jdt.internal.compiler.batch.Main Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.core; singleton:=true -Bundle-Version: 3.24.0.qualifier +Bundle-Version: 3.25.0.qualifier Bundle-Activator: org.eclipse.jdt.core.JavaCore Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java index 0dcd9d3fef..8d49d80066 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java @@ -521,6 +521,9 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, } if (isPolyExpression()) { if (this.expectedType == null || !this.expectedType.isProperType(true)) { + // We will be back here in case of a PolyTypeBinding. So, to enable + // further processing, set it back to default. + this.constant = Constant.NotAConstant; return new PolyTypeBinding(this); } return this.resolvedType = computeConversions(scope, this.expectedType) ? this.expectedType : null; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java index 24bd52d73d..5e2cdfa662 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java @@ -74,4 +74,10 @@ default char[] getModuleName() { default String getDestinationPath() { return null; } +/** + * Answers a path for external annotations that has been configured for + * the providing classpath entry, or <code>null</code>. + */ +default String getExternalAnnotationPath() { return null; } + } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java index 57cfa33fe4..6b231bd335 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java @@ -56,6 +56,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; @@ -526,6 +527,13 @@ public class ClassScope extends Scope { SourceTypeBinding sourceType = this.referenceContext.binding; sourceType.module = module(); environment().setAccessRestriction(sourceType, accessRestriction); + ICompilationUnit compilationUnit = this.referenceContext.compilationResult.getCompilationUnit(); + if (compilationUnit != null && compilerOptions().isAnnotationBasedNullAnalysisEnabled) { + String externalAnnotationPath = compilationUnit.getExternalAnnotationPath(); + if (externalAnnotationPath != null) { + ExternalAnnotationSuperimposer.apply(sourceType, externalAnnotationPath); + } + } TypeParameter[] typeParameters = this.referenceContext.typeParameters; sourceType.typeVariables = typeParameters == null || typeParameters.length == 0 ? Binding.NO_TYPE_VARIABLES : null; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExternalAnnotationSuperimposer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExternalAnnotationSuperimposer.java index 9fd2eba530..ee946d3a23 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExternalAnnotationSuperimposer.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExternalAnnotationSuperimposer.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider; import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation; import org.eclipse.jdt.internal.compiler.env.ITypeAnnotationWalker; @@ -101,7 +102,7 @@ class ExternalAnnotationSuperimposer extends TypeBindingVisitor { field.type = visitor.superimpose(field.type, TypeBinding.class); } - public static void annotateMethodBinding(MethodBinding method, ExternalAnnotationProvider provider, LookupEnvironment environment) { + public static void annotateMethodBinding(MethodBinding method, Argument[] arguments, ExternalAnnotationProvider provider, LookupEnvironment environment) { char[] methodSignature = method.genericSignature(); if (methodSignature == null) methodSignature = method.signature(); @@ -119,8 +120,11 @@ class ExternalAnnotationSuperimposer extends TypeBindingVisitor { } TypeBinding[] parameters = method.parameters; for (short i = 0; i < parameters.length; i++) { - if (visitor.go(walker.toMethodParameter(i))) + if (visitor.go(walker.toMethodParameter(i))) { parameters[i] = visitor.superimpose(parameters[i], TypeBinding.class); + if (arguments != null && i < arguments.length) + arguments[i].binding.type = parameters[i]; + } } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java index 4a475f532e..7a1b542b22 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java @@ -2841,7 +2841,7 @@ private MethodBinding resolveTypesWithSuspendedTempErrorHandlingPolicy(MethodBin method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved; if (this.externalAnnotationProvider != null) { - ExternalAnnotationSuperimposer.annotateMethodBinding(method, this.externalAnnotationProvider, this.environment); + ExternalAnnotationSuperimposer.annotateMethodBinding(method, arguments, this.externalAnnotationProvider, this.environment); } return method; } diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Token.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Token.java index b2b7144267..ca4d701f38 100644 --- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Token.java +++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Token.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014, 2015 Mateusz Matela and others. + * Copyright (c) 2014, 2021 Mateusz Matela and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -143,16 +143,19 @@ public class Token { int start = scanner.getCurrentTokenStartPosition(); int end = scanner.getCurrentTokenEndPosition(); if (currentToken == TokenNameCOMMENT_LINE) { - // don't include line separator - while(end >= start) { + // don't include line separator, but set break-after + while (end > start) { char c = scanner.source[end]; if (c != '\r' && c != '\n') break; end--; } + Token token = new Token(start, end, currentToken); + token.breakAfter(); + return token; + } else { + return new Token(start, end, currentToken); } - Token token = new Token(start, end, currentToken); - return token; } /** Adds space before this token */ diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java index bb3301426c..d81b254ecf 100644 --- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java +++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java @@ -81,6 +81,7 @@ import org.eclipse.jdt.core.dom.IfStatement; import org.eclipse.jdt.core.dom.InfixExpression; import org.eclipse.jdt.core.dom.InfixExpression.Operator; import org.eclipse.jdt.core.dom.LambdaExpression; +import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Name; @@ -795,6 +796,13 @@ public class WrapPreparator extends ASTVisitor { closingBraceIndex, 0, this.currentDepth, 1, true, false)); } } + if (this.options.brace_position_for_array_initializer.equals(DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED) + && openingBrace.getWrapPolicy() == null && (node.getParent() instanceof SingleMemberAnnotation + || node.getParent() instanceof MemberValuePair)) { + int parentIndex = this.tm.firstIndexIn(node.getParent(), -1); + int indent = this.options.indentation_size; + openingBrace.setWrapPolicy(new WrapPolicy(WrapMode.BLOCK_INDENT, parentIndex, indent)); + } return true; } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java index 031a67c4e9..b99ba966ec 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java @@ -26,6 +26,7 @@ import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.core.nd.db.ChunkCache; +import org.eclipse.jdt.internal.core.search.PatternSearchJob; /** * JavaCore eclipse preferences initializer. @@ -116,6 +117,7 @@ public class JavaCorePreferenceInitializer extends AbstractPreferenceInitializer defaultOptionsMap.put(ChunkCache.CHUNK_CACHE_SIZE_MB, Double.toString(ChunkCache.CHUNK_CACHE_SIZE_MB_DEFAULT)); defaultOptionsMap.put(ChunkCache.CHUNK_CACHE_SIZE_PERCENT, Double.toString(ChunkCache.CHUNK_CACHE_SIZE_PERCENT_DEFAULT)); + defaultOptionsMap.put(PatternSearchJob.ENABLE_PARALLEL_SEARCH, Boolean.toString(PatternSearchJob.ENABLE_PARALLEL_SEARCH_DEFAULT)); // Time out for parameter names defaultOptionsMap.put(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, "50"); //$NON-NLS-1$ diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java index 4cdb930aae..44fc370bad 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java @@ -121,9 +121,8 @@ public abstract class ClasspathLocation { return true; } static ClasspathLocation forSourceFolder(IContainer sourceFolder, IContainer outputFolder, - char[][] inclusionPatterns, char[][] exclusionPatterns, boolean ignoreOptionalProblems) { - return new ClasspathMultiDirectory(sourceFolder, outputFolder, inclusionPatterns, exclusionPatterns, - ignoreOptionalProblems); + char[][] inclusionPatterns, char[][] exclusionPatterns, boolean ignoreOptionalProblems, IPath externalAnnotationPath) { + return new ClasspathMultiDirectory(sourceFolder, outputFolder, inclusionPatterns, exclusionPatterns, ignoreOptionalProblems, externalAnnotationPath); } public static ClasspathLocation forBinaryFolder(IContainer binaryFolder, boolean isOutputFolder, AccessRuleSet accessRuleSet, IPath externalAnnotationPath, boolean autoModule) { return new ClasspathDirectory(binaryFolder, isOutputFolder, accessRuleSet, externalAnnotationPath, autoModule); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java index 96b26f2552..e127fb7c71 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java @@ -15,6 +15,7 @@ package org.eclipse.jdt.internal.core.builder; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; @@ -32,8 +33,9 @@ char[][] exclusionPatterns; // used by builders when walking source folders boolean hasIndependentOutputFolder; // if output folder is not equal to any of the source folders public boolean ignoreOptionalProblems; -ClasspathMultiDirectory(IContainer sourceFolder, IContainer binaryFolder, char[][] inclusionPatterns, char[][] exclusionPatterns, boolean ignoreOptionalProblems) { - super(binaryFolder, true, null, null, false /* source never an automatic module*/); +ClasspathMultiDirectory(IContainer sourceFolder, IContainer binaryFolder, char[][] inclusionPatterns, char[][] exclusionPatterns, + boolean ignoreOptionalProblems, IPath externalAnnotationPath) { + super(binaryFolder, true, null, externalAnnotationPath, false /* source never an automatic module*/); this.sourceFolder = sourceFolder; this.inclusionPatterns = inclusionPatterns; diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java index 577b3eed72..837ebc11bd 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java @@ -181,7 +181,8 @@ private void computeClasspathLocations( outputFolder, entry.fullInclusionPatternChars(), entry.fullExclusionPatternChars(), - entry.ignoreOptionalProblems()); + entry.ignoreOptionalProblems(), + externalAnnotationPath); if (patchedModule != null) { ModuleEntryProcessor.combinePatchIntoModuleEntry(sourceLocation, patchedModule, moduleEntries); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java index 8425b8a456..891a4ec581 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/SourceFile.java @@ -117,6 +117,10 @@ public int hashCode() { public boolean ignoreOptionalProblems() { return this.sourceLocation.ignoreOptionalProblems; } +@Override +public String getExternalAnnotationPath() { + return this.sourceLocation.externalAnnotationPath; +} String typeLocator() { return this.resource.getProjectRelativePath().toString(); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java index eb188d4d91..e855d95a72 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java @@ -76,7 +76,7 @@ private long previousStructuralBuildTime; private StringSet structurallyChangedTypes; public static int MaxStructurallyChangedTypes = 100; // keep track of ? structurally changed types, otherwise consider all to be changed -public static final byte VERSION = 0x0023; +public static final byte VERSION = 0x0024; static final byte SOURCE_FOLDER = 1; static final byte BINARY_FOLDER = 2; @@ -338,7 +338,7 @@ private static ClasspathMultiDirectory[] readSourceLocations(IProject project, D if ((folderName = in.readUTF()).length() > 0) sourceFolder = project.getFolder(folderName); if ((folderName = in.readUTF()).length() > 0) outputFolder = project.getFolder(folderName); ClasspathMultiDirectory md = - (ClasspathMultiDirectory) ClasspathLocation.forSourceFolder(sourceFolder, outputFolder, readNames(in), readNames(in), in.readBoolean()); + (ClasspathMultiDirectory) ClasspathLocation.forSourceFolder(sourceFolder, outputFolder, readNames(in), readNames(in), in.readBoolean(), readNullablePath(in)); if (in.readBoolean()) md.hasIndependentOutputFolder = true; sourceLocations[i] = md; @@ -429,6 +429,13 @@ private static char[][] readNames(DataInputStream in) throws IOException { return names; } +private static IPath readNullablePath(DataInputStream in) throws IOException { + String path = in.readUTF(); + if (!path.isEmpty()) + return new Path(path); + return null; +} + private static AccessRuleSet readRestriction(DataInputStream in) throws IOException { int length = in.readInt(); if (length == 0) return null; // no restriction specified @@ -711,6 +718,7 @@ private void writeSourceLocations(DataOutputStream out, ClasspathMultiDirectory[ writeNames(md.inclusionPatterns, out); writeNames(md.exclusionPatterns, out); out.writeBoolean(md.ignoreOptionalProblems); + writeNullablePath(md.externalAnnotationPath, out); out.writeBoolean(md.hasIndependentOutputFolder); } } @@ -741,7 +749,7 @@ private void writeBinaryLocations(DataOutputStream out, ClasspathLocation[] loca out.writeUTF(cd.binaryFolder.getFullPath().toString()); out.writeBoolean(cd.isOutputFolder); writeRestriction(cd.accessRuleSet, out); - out.writeUTF(cd.externalAnnotationPath != null ? cd.externalAnnotationPath : ""); //$NON-NLS-1$ + writeNullablePath(cd.externalAnnotationPath, out); out.writeBoolean(cd.isOnModulePath); } else if (c instanceof ClasspathJar) { ClasspathJar jar = (ClasspathJar) c; @@ -754,7 +762,7 @@ private void writeBinaryLocations(DataOutputStream out, ClasspathLocation[] loca out.writeUTF(jar.resource.getFullPath().toString()); } writeRestriction(jar.accessRuleSet, out); - out.writeUTF(jar.externalAnnotationPath != null ? jar.externalAnnotationPath : ""); //$NON-NLS-1$ + writeNullablePath(jar.externalAnnotationPath, out); out.writeBoolean(jar.isOnModulePath); out.writeUTF(jar.compliance == null ? "" : jar.compliance); //$NON-NLS-1$ @@ -763,7 +771,7 @@ private void writeBinaryLocations(DataOutputStream out, ClasspathLocation[] loca out.writeByte(EXTERNAL_JAR); out.writeUTF(jrt.zipFilename); writeRestriction(jrt.accessRuleSet, out); - out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$ + writeNullablePath(jrt.externalAnnotationPath, out); if (jrt instanceof ClasspathJrtWithReleaseOption) out.writeUTF(((ClasspathJrtWithReleaseOption) jrt).release); else @@ -835,6 +843,10 @@ private void writeNames(char[][] names, DataOutputStream out) throws IOException writeName(names[i], out); } +private void writeNullablePath(String path, DataOutputStream out) throws IOException { + out.writeUTF(path != null ? path : ""); //$NON-NLS-1$ +} + private void writeRestriction(AccessRuleSet accessRuleSet, DataOutputStream out) throws IOException { if (accessRuleSet == null) { out.writeInt(0); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java index 7ec88709e6..f68ec4c98c 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java @@ -74,6 +74,7 @@ import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants; import org.eclipse.jdt.internal.core.search.indexing.IndexManager; import org.eclipse.jdt.internal.core.search.matching.MatchLocator; import org.eclipse.jdt.internal.core.search.matching.SuperTypeReferencePattern; +import org.eclipse.jdt.internal.core.search.processing.JobManager; import org.eclipse.jdt.internal.core.util.HandleFactory; import org.eclipse.jdt.internal.core.util.Util; @@ -662,6 +663,7 @@ private static void legacySearchAllPossibleSubTypes( searchRequestor); queue.add(type.getElementName().toCharArray()); + long startTime = System.currentTimeMillis(); try { while (queue.start <= queue.end) { subMonitor.setWorkRemaining(Math.max(queue.end - queue.start + 1, 100)); @@ -680,6 +682,10 @@ private static void legacySearchAllPossibleSubTypes( } } finally { job.finished(); + if (JobManager.VERBOSE) { + long wallClockTime = System.currentTimeMillis() - startTime; + Util.verbose("-> execution time: " + wallClockTime + "ms - " + IndexBasedHierarchyBuilder.class.getSimpleName());//$NON-NLS-1$//$NON-NLS-2$ + } } } } diff --git a/org.eclipse.jdt.core/pom.xml b/org.eclipse.jdt.core/pom.xml index 0bbb433d4e..3de233ee95 100644 --- a/org.eclipse.jdt.core/pom.xml +++ b/org.eclipse.jdt.core/pom.xml @@ -18,7 +18,7 @@ </parent> <groupId>org.eclipse.jdt</groupId> <artifactId>org.eclipse.jdt.core</artifactId> - <version>3.24.0-SNAPSHOT</version> + <version>3.25.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> <properties> diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IParallelizable.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IParallelizable.java new file mode 100644 index 0000000000..f310fb1f3d --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/IParallelizable.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2020 Gayan Perera 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 + * + * Contributors: + * Gayan Perera - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.search; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.internal.core.search.JavaSearchParticipant; + +/** + * This interface can be used by {@link IJavaSearchScope}, {@link JavaSearchParticipant} and {@link SearchPattern} to + * mark implementors as eligible for parallel index search. + * + * @since 3.25 + */ +public interface IParallelizable { + /** + * Answers {@code true} if the current instance supports parallel index search + * + * @return Returns <code>true</code> if the implementation is safe to be used in a parallel search. + */ + boolean isParallelSearchSupported(); + + /** + * Initialize all needed data before search is started + * + * @param monitor + * non null progress callback + */ + default void initBeforeSearch(IProgressMonitor monitor) throws JavaModelException { + // no op + } + + /** + * Checks if the given object implements this interface and also returns <code>true</code> for + * {@link #isParallelSearchSupported()}. + * + * @param o + * The object that needs to be checked. <code>null</code> value will result in returning + * <code>false</code>. + * @return <code>true</code> if the given object can be used in parallel search. + */ + public static boolean isParallelSearchSupported(Object o) { + return (o instanceof IParallelizable) && ((IParallelizable) o).isParallelSearchSupported(); + } + +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java index db59626672..22ea4af367 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java @@ -2419,13 +2419,13 @@ public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchP EntryResult[] entries = pattern.queryIn(index); if (entries == null) return; - SearchPattern decodedResult = pattern.getBlankPattern(); String containerPath = index.containerPath; char separator = index.separator; for (int i = 0, l = entries.length; i < l; i++) { if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException(); EntryResult entry = entries[i]; + SearchPattern decodedResult = pattern.getBlankPattern(); decodedResult.decodeIndexKey(entry.getWord()); if (pattern.matchesDecodedKey(decodedResult)) { // TODO (kent) some clients may not need the document names @@ -2738,4 +2738,12 @@ public EntryResult[] queryIn(Index index) throws IOException { public String toString() { return "SearchPattern"; //$NON-NLS-1$ } + +/** + * @since 3.25 + */ +@Override +public SearchPattern clone() throws CloneNotSupportedException { + return (SearchPattern) super.clone(); +} } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java index 9ec75b6c25..dcb0cbdad9 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/AbstractSearchScope.java @@ -15,8 +15,9 @@ package org.eclipse.jdt.internal.core.search; import org.eclipse.jdt.core.IJavaElementDelta; import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.IParallelizable; -public abstract class AbstractSearchScope implements IJavaSearchScope { +public abstract class AbstractSearchScope implements IJavaSearchScope, IParallelizable, Cloneable { /** * @see IJavaSearchScope#includesBinaries() @@ -60,4 +61,13 @@ public void setIncludesClasspaths(boolean includesClasspaths) { // implements interface method } +@Override +public boolean isParallelSearchSupported() { + return false; +} + +@Override +public AbstractSearchScope clone() throws CloneNotSupportedException { + return (AbstractSearchScope) super.clone(); +} } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java index 0066665f2e..25933caf1f 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java @@ -18,6 +18,7 @@ import java.io.File; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Set; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.IPath; @@ -41,7 +42,7 @@ public class HierarchyScope extends AbstractSearchScope implements SuffixConstan private HashSet resourcePaths; private IPath[] enclosingProjectsAndJars; - protected IResource[] elements; + protected Set<String> elements; protected int elementCount; public boolean needsRefresh; @@ -55,15 +56,7 @@ public class HierarchyScope extends AbstractSearchScope implements SuffixConstan * Adds the given resource to this search scope. */ public void add(IResource element) { - if (this.elementCount == this.elements.length) { - System.arraycopy( - this.elements, - 0, - this.elements = new IResource[this.elementCount * 2], - 0, - this.elementCount); - } - this.elements[this.elementCount++] = element; + this.elements.add(element.getFullPath().toString()); } /** @@ -140,7 +133,6 @@ public class HierarchyScope extends AbstractSearchScope implements SuffixConstan //JavaModelManager.getJavaModelManager().rememberScope(this); } private void buildResourceVector() { - HashMap resources = new HashMap(); HashMap paths = new HashMap(); IType[] types = null; if (this.subTypes != null) { @@ -160,8 +152,7 @@ public class HierarchyScope extends AbstractSearchScope implements SuffixConstan this.subTypes.add(type); } IResource resource = ((JavaElement)type).resource(); - if (resource != null && resources.get(resource) == null) { - resources.put(resource, resource); + if (resource != null) { add(resource); } IPackageFragmentRoot root = @@ -318,13 +309,8 @@ public class HierarchyScope extends AbstractSearchScope implements SuffixConstan if (separatorIndex != -1) { return this.resourcePaths.contains(resourcePath); } else { - for (int i = 0; i < this.elementCount; i++) { - if (resourcePath.startsWith(this.elements[i].getFullPath().toString())) { - return true; - } - } + return this.elements.contains(resourcePath); } - return false; } /** * Optionally perform additional checks after element has already passed matching based on index/documents. @@ -455,7 +441,7 @@ public class HierarchyScope extends AbstractSearchScope implements SuffixConstan } protected void initialize(IProgressMonitor progressMonitor) throws JavaModelException { this.resourcePaths = new HashSet(); - this.elements = new IResource[5]; + this.elements = new HashSet<>(); this.elementCount = 0; this.needsRefresh = false; if (this.hierarchy == null) { @@ -488,4 +474,15 @@ public class HierarchyScope extends AbstractSearchScope implements SuffixConstan return "HierarchyScope on " + ((JavaElement)this.focusType).toStringWithAncestors(); //$NON-NLS-1$ } + @Override + public boolean isParallelSearchSupported() { + return true; + } + + @Override + public void initBeforeSearch(IProgressMonitor monitor) throws JavaModelException { + if (this.needsRefresh) { + initialize(monitor); + } + } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java index 78d8ab67fa..fe29c40e1f 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java @@ -33,10 +33,10 @@ import org.eclipse.jdt.internal.core.search.matching.MatchLocator; * the workspace or no exist yet, and thus aren't just resources). */ @SuppressWarnings({"rawtypes", "unchecked"}) -public class JavaSearchParticipant extends SearchParticipant { +public class JavaSearchParticipant extends SearchParticipant implements IParallelizable { - private ThreadLocal indexSelector = new ThreadLocal(); - private SourceIndexer sourceIndexer; + private final ThreadLocal indexSelector = new ThreadLocal(); + private final ThreadLocal<SourceIndexer> sourceIndexer = new ThreadLocal<SourceIndexer>(); @Override public void beginSearching() { @@ -67,8 +67,9 @@ public class JavaSearchParticipant extends SearchParticipant { String documentPath = document.getPath(); if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(documentPath)) { - this.sourceIndexer = new SourceIndexer(document); - this.sourceIndexer.indexDocument(); + SourceIndexer indexer = new SourceIndexer(document); + this.sourceIndexer.set(indexer); + indexer.indexDocument(); } else if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(documentPath)) { new BinaryIndexer(document).indexDocument(); } else if (documentPath.endsWith(TypeConstants.AUTOMATIC_MODULE_NAME)) { @@ -80,9 +81,10 @@ public class JavaSearchParticipant extends SearchParticipant { public void indexResolvedDocument(SearchDocument document, IPath indexPath) { String documentPath = document.getPath(); if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(documentPath)) { - if (this.sourceIndexer != null) - this.sourceIndexer.indexResolvedDocument(); - this.sourceIndexer = null; + SourceIndexer indexer = this.sourceIndexer.get(); + if (indexer != null) + indexer.indexResolvedDocument(); + this.sourceIndexer.remove(); } } @@ -90,8 +92,9 @@ public class JavaSearchParticipant extends SearchParticipant { public void resolveDocument(SearchDocument document) { String documentPath = document.getPath(); if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(documentPath)) { - if (this.sourceIndexer != null) - this.sourceIndexer.resolveDocument(); + SourceIndexer indexer = this.sourceIndexer.get(); + if (indexer != null) + indexer.resolveDocument(); } } @@ -114,11 +117,7 @@ public class JavaSearchParticipant extends SearchParticipant { @Override public IPath[] selectIndexes(SearchPattern pattern, IJavaSearchScope scope) { - IndexSelector selector = (IndexSelector) this.indexSelector.get(); - if (selector == null) { - selector = new IndexSelector(scope, pattern); - this.indexSelector.set(selector); - } + IndexSelector selector = getIndexSelector(pattern, scope); IndexLocation[] urls = selector.getIndexLocations(); IPath[] paths = new IPath[urls.length]; for (int i = 0; i < urls.length; i++) { @@ -127,13 +126,23 @@ public class JavaSearchParticipant extends SearchParticipant { return paths; } - public IndexLocation[] selectIndexURLs(SearchPattern pattern, IJavaSearchScope scope) { + private IndexSelector getIndexSelector(SearchPattern pattern, IJavaSearchScope scope) { IndexSelector selector = (IndexSelector) this.indexSelector.get(); if (selector == null) { selector = new IndexSelector(scope, pattern); this.indexSelector.set(selector); } + return selector; + } + + public IndexLocation[] selectIndexURLs(SearchPattern pattern, IJavaSearchScope scope) { + IndexSelector selector = getIndexSelector(pattern, scope); return selector.getIndexLocations(); } + @Override + public boolean isParallelSearchSupported() { + return true; + } + } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java index d6026931cf..697d2d3715 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java @@ -681,4 +681,9 @@ public String toString() { } return result.toString(); } + +@Override +public boolean isParallelSearchSupported() { + return true; +} } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java index 391e059bd0..70fb5a3fb7 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaWorkspaceScope.java @@ -239,4 +239,9 @@ public String toString() { } return result.toString(); } + +@Override +public boolean isParallelSearchSupported() { + return true; +} } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java index 6af6d897b8..32668eed2a 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java @@ -14,12 +14,29 @@ package org.eclipse.jdt.internal.core.search; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicLong; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.jdt.core.search.*; +import org.eclipse.core.runtime.preferences.IPreferencesService; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.IParallelizable; +import org.eclipse.jdt.core.search.SearchParticipant; +import org.eclipse.jdt.core.search.SearchPattern; +import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; import org.eclipse.jdt.internal.core.JavaModelManager; import org.eclipse.jdt.internal.core.index.FileIndexLocation; import org.eclipse.jdt.internal.core.index.Index; @@ -37,9 +54,14 @@ protected IJavaSearchScope scope; protected SearchParticipant participant; protected IndexQueryRequestor requestor; protected boolean areIndexesReady; -protected long executionTime = 0; +protected AtomicLong executionTime; +boolean parallel; + +public static final String ENABLE_PARALLEL_SEARCH = "enableParallelJavaIndexSearch";//$NON-NLS-1$ +public static final boolean ENABLE_PARALLEL_SEARCH_DEFAULT = true; public PatternSearchJob(SearchPattern pattern, SearchParticipant participant, IJavaSearchScope scope, IndexQueryRequestor requestor) { + this.executionTime = new AtomicLong(0); this.pattern = pattern; this.participant = participant; this.scope = scope; @@ -63,21 +85,81 @@ public boolean execute(IProgressMonitor progressMonitor) { SubMonitor subMonitor = SubMonitor.convert(progressMonitor, 3); boolean isComplete = COMPLETE; - this.executionTime = 0; + this.executionTime.set(0); + long startTime = System.currentTimeMillis(); + Index[] indexes = getIndexes(subMonitor.split(1)); try { int max = indexes.length; SubMonitor loopMonitor = subMonitor.split(2).setWorkRemaining(max); - for (int i = 0; i < max; i++) { - isComplete &= search(indexes[i], loopMonitor.split(1)); + this.parallel = canRunInParallel(); + if(this.parallel) { + isComplete = performParallelSearch(indexes, loopMonitor); + } else { + for (int i = 0; i < max; i++) { + isComplete &= search(indexes[i], this.requestor, loopMonitor.split(1)); + } + } + + if (JobManager.VERBOSE) { + if (this.parallel) { + long wallClockTime = System.currentTimeMillis() - startTime; + Util.verbose("-> execution time: " + wallClockTime + "ms - " + this);//$NON-NLS-1$//$NON-NLS-2$ + Util.verbose("-> cumulative execution time (" + ForkJoinPool.getCommonPoolParallelism() + "): " //$NON-NLS-1$//$NON-NLS-2$ + + this.executionTime.get() + "ms - " + this);//$NON-NLS-1$ + } else { + Util.verbose("-> execution time: " + this.executionTime.get() + "ms - " + this);//$NON-NLS-1$//$NON-NLS-2$ + } } - if (JobManager.VERBOSE) - Util.verbose("-> execution time: " + this.executionTime + "ms - " + this);//$NON-NLS-1$//$NON-NLS-2$ return isComplete; } finally { SubMonitor.done(progressMonitor); } } +private boolean performParallelSearch(Index[] indexes, SubMonitor loopMonitor) { + boolean isComplete = true; + List<Future<IndexResult>> futures = new ArrayList<>(indexes.length); + ForkJoinPool commonPool = ForkJoinPool.commonPool(); + ParallelSearchMonitor monitor = new ParallelSearchMonitor(loopMonitor); + + try { + if (this.scope instanceof IParallelizable) { + ((IParallelizable) this.scope).initBeforeSearch(monitor); + } + for (Index index : indexes) { + futures.add(commonPool.submit(() -> search(index, monitor))); + } + + for (Future<IndexResult> future : futures) { + loopMonitor.split(1); + try { + IndexResult result = future.get(); + isComplete &= result.complete; + result.matches.forEach(m -> { + boolean continueSearch = this.requestor.acceptIndexMatch(m.documentPath, m.indexRecord, this.participant, m.access); + if(!continueSearch) { + throw new OperationCanceledException(); + } + }); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new OperationCanceledException(); + } catch (ExecutionException e) { + if(e.getCause() instanceof RuntimeException) { + throw (RuntimeException) e.getCause(); + } + throw new RuntimeException(e); + } + } + } catch (JavaModelException e) { + monitor.setCanceled(true); + throw new RuntimeException("Error initializing scope: " + this.scope, e); //$NON-NLS-1$ + } catch (Exception e) { + monitor.setCanceled(true); + throw e; + } + return isComplete; +} public Index[] getIndexes(IProgressMonitor progressMonitor) { // acquire the in-memory indexes on the fly IndexLocation[] indexLocations; @@ -106,7 +188,16 @@ public boolean waitNeeded() { public String getJobFamily() { return ""; //$NON-NLS-1$ } -public boolean search(Index index, IProgressMonitor progressMonitor) { + +private IndexResult search(Index index, IProgressMonitor progressMonitor) { + List<IndexMatch> matches = new ArrayList<>(); + boolean complete = search(index, + collectTo(matches, progressMonitor), progressMonitor); + return new IndexResult(complete, matches); +} + + +public boolean search(Index index, IndexQueryRequestor queryRequestor, IProgressMonitor progressMonitor) { if (index == null) return COMPLETE; if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException(); ReadWriteMonitor monitor = index.monitor; @@ -114,8 +205,14 @@ public boolean search(Index index, IProgressMonitor progressMonitor) { try { monitor.enterRead(); // ask permission to read long start = System.currentTimeMillis(); - MatchLocator.findIndexMatches(this.pattern, index, this.requestor, this.participant, this.scope, progressMonitor); - this.executionTime += System.currentTimeMillis() - start; + SearchPattern searchPattern = this.pattern; + IJavaSearchScope searchScope = this.scope; + if(this.parallel) { + searchPattern = clone(searchPattern); + searchScope = clone(searchScope); + } + MatchLocator.findIndexMatches(searchPattern, index, queryRequestor, this.participant, searchScope, progressMonitor); + this.executionTime.addAndGet(System.currentTimeMillis() - start); return COMPLETE; } catch (IOException e) { if (e instanceof java.io.EOFException) @@ -125,8 +222,102 @@ public boolean search(Index index, IProgressMonitor progressMonitor) { monitor.exitRead(); // finished reading } } + +private static IJavaSearchScope clone(IJavaSearchScope searchScope) { + if (searchScope instanceof AbstractSearchScope) { + try { + searchScope = ((AbstractSearchScope)searchScope).clone(); + } catch (CloneNotSupportedException e) { + Util.log(new Status(IStatus.WARNING, JavaCore.PLUGIN_ID, + "PatternSearchJob could not clone " + searchScope, e));//$NON-NLS-1$ + } + } + return searchScope; +} + +private static SearchPattern clone(SearchPattern searchPattern) { + if(searchPattern instanceof Cloneable) { + try { + searchPattern = searchPattern.clone(); + } catch (CloneNotSupportedException e) { + Util.log(new Status(IStatus.WARNING, JavaCore.PLUGIN_ID, + "PatternSearchJob could not clone " + searchPattern, e));//$NON-NLS-1$ + } + } + return searchPattern; +} + @Override public String toString() { return "searching " + this.pattern.toString(); //$NON-NLS-1$ } + +private boolean canRunInParallel() { + return isParallelSearchEnabled() && IParallelizable.isParallelSearchSupported(this.scope) + && IParallelizable.isParallelSearchSupported(this.participant) + && IParallelizable.isParallelSearchSupported(this.pattern); +} + +private boolean isParallelSearchEnabled() { + IPreferencesService preferenceService = Platform.getPreferencesService(); + if (preferenceService == null) { + return true; + } + return preferenceService.getBoolean(JavaCore.PLUGIN_ID, ENABLE_PARALLEL_SEARCH, ENABLE_PARALLEL_SEARCH_DEFAULT, + null); +} + +private static IndexQueryRequestor collectTo(final List<IndexMatch> collectTo, final IProgressMonitor monitor) { + return new IndexQueryRequestor() { + + @Override + public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, + AccessRuleSet access) { + collectTo.add(new IndexMatch(documentPath, indexRecord, access)); + return !monitor.isCanceled(); + } + }; +} + +static class IndexResult { + final boolean complete; + final List<IndexMatch> matches; + + IndexResult(boolean complete, List<IndexMatch> matches) { + this.complete = complete; + this.matches = matches; + } +} + +static class IndexMatch { + final String documentPath; + final SearchPattern indexRecord; + final AccessRuleSet access; + + IndexMatch(String documentPath, SearchPattern indexRecord, AccessRuleSet access) { + this.documentPath = documentPath; + this.indexRecord = indexRecord; + this.access = access; + } +} + +static class ParallelSearchMonitor extends NullProgressMonitor { + private volatile boolean canceled; + private IProgressMonitor original; + + public ParallelSearchMonitor(IProgressMonitor original) { + this.original = original; + } + + @Override + public boolean isCanceled() { + return this.canceled || this.original.isCanceled(); + } + + @Override + public void setCanceled(boolean canceled) { + this.canceled = canceled; + } +} + } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java index 42b5656d51..8249530e08 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/SubTypeSearchJob.java @@ -13,39 +13,40 @@ *******************************************************************************/ package org.eclipse.jdt.internal.core.search; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.jdt.core.search.*; -import org.eclipse.jdt.internal.compiler.util.SimpleSet; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchParticipant; +import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.internal.core.index.Index; public class SubTypeSearchJob extends PatternSearchJob { -SimpleSet indexes = new SimpleSet(5); +Set<Index> indexes = Collections.synchronizedSet(new LinkedHashSet<>(5)); public SubTypeSearchJob(SearchPattern pattern, SearchParticipant participant, IJavaSearchScope scope, IndexQueryRequestor requestor) { super(pattern, participant, scope, requestor); } public void finished() { - Object[] values = this.indexes.values; - for (int i = 0, l = values.length; i < l; i++) - if (values[i] != null) - ((Index) values[i]).stopQuery(); + this.indexes.forEach(Index::stopQuery); } @Override public Index[] getIndexes(IProgressMonitor progressMonitor) { - if (this.indexes.elementSize == 0) { + if (this.indexes.isEmpty()) { return super.getIndexes(progressMonitor); } this.areIndexesReady = true; // use stored indexes until the job's end - Index[] values = new Index[this.indexes.elementSize]; - this.indexes.asArray(values); - return values; + return this.indexes.toArray(new Index[0]); } @Override -public boolean search(Index index, IProgressMonitor progressMonitor) { +public boolean search(Index index, IndexQueryRequestor queryRequestor, IProgressMonitor progressMonitor) { if (index == null) return COMPLETE; - if (this.indexes.addIfNotIncluded(index) == index) + if (this.indexes.add(index)) { index.startQuery(); - return super.search(index, progressMonitor); + } + return super.search(index, queryRequestor, progressMonitor); } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/UnindexedSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/UnindexedSearchScope.java index 5fdc740c07..089dfd5b65 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/UnindexedSearchScope.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/UnindexedSearchScope.java @@ -97,4 +97,9 @@ public class UnindexedSearchScope extends AbstractSearchScope { } } + @Override + public boolean isParallelSearchSupported() { + return true; + } + } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java index d2f7ed053f..959382a814 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/AndPattern.java @@ -13,6 +13,9 @@ *******************************************************************************/ package org.eclipse.jdt.internal.core.search.matching; +import java.util.stream.Stream; + +import org.eclipse.jdt.core.search.IParallelizable; import org.eclipse.jdt.core.search.SearchPattern; public class AndPattern extends IntersectingPattern { @@ -77,4 +80,19 @@ protected void resetQuery() { this.current = 0; } +@Override +public boolean isParallelSearchSupported() { + return Stream.of(this.patterns).allMatch(IParallelizable::isParallelSearchSupported); +} + +@Override +public SearchPattern clone() throws CloneNotSupportedException { + AndPattern pattern = (AndPattern) super.clone(); + pattern.patterns = this.patterns.clone(); + for (int i = 0; i < this.patterns.length; i++) { + pattern.patterns[i] = this.patterns[i].clone(); + } + return pattern; +} + } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java index d3b8ea525f..32438f3619 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchPattern.java @@ -22,12 +22,13 @@ import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IParallelizable; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants; import org.eclipse.jdt.internal.core.util.Util; -public class JavaSearchPattern extends SearchPattern implements IIndexConstants { +public class JavaSearchPattern extends SearchPattern implements IIndexConstants, IParallelizable, Cloneable { /* * Whether this pattern is case sensitive. @@ -454,4 +455,10 @@ public class JavaSearchPattern extends SearchPattern implements IIndexConstants public final String toString() { return print(new StringBuffer(30)).toString(); } + + @Override + public boolean isParallelSearchSupported() { + return true; + } + } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java index 9bec6f4d27..784510e020 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/OrPattern.java @@ -14,6 +14,7 @@ package org.eclipse.jdt.internal.core.search.matching; import java.io.IOException; +import java.util.stream.Stream; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.search.*; @@ -21,7 +22,7 @@ import org.eclipse.jdt.internal.core.index.Index; import org.eclipse.jdt.internal.core.search.IndexQueryRequestor; import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants; -public class OrPattern extends SearchPattern implements IIndexConstants { +public class OrPattern extends SearchPattern implements IIndexConstants, IParallelizable, Cloneable { protected SearchPattern[] patterns; @@ -119,4 +120,19 @@ public class OrPattern extends SearchPattern implements IIndexConstants { } return buffer.toString(); } + + @Override + public boolean isParallelSearchSupported() { + return Stream.of(this.patterns).allMatch(IParallelizable::isParallelSearchSupported); + } + + @Override + public SearchPattern clone() throws CloneNotSupportedException { + OrPattern pattern = (OrPattern) super.clone(); + pattern.patterns = this.patterns.clone(); + for (int i = 0; i < this.patterns.length; i++) { + pattern.patterns[i] = this.patterns[i].clone(); + } + return pattern; + } } |