diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTVisitorTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTVisitorTest.java index 63a558e602c..08d28a8a3a1 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTVisitorTest.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTVisitorTest.java @@ -15,6 +15,11 @@ package org.eclipse.jdt.core.tests.dom; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import junit.framework.Test; import org.eclipse.jdt.core.dom.*; @@ -1370,6 +1375,25 @@ public void testCharacterLiteral() { String result = this.b.toString(); assertTrue(result.equals("[(eCL'q''q'eCL)]")); //$NON-NLS-1$ } + public void testCharacterLiteralConcurrent() throws Exception { + CharacterLiteral x1 = this.ast.newCharacterLiteral(); + x1.setCharValue('q'); + + ExecutorService executorService = Executors.newFixedThreadPool(10); + List> futures = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + CompletableFuture future = CompletableFuture.runAsync(() -> { + try { + x1.charValue(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, executorService); + futures.add(future); + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(); + executorService.shutdown(); + } /** @deprecated using deprecated code */ public void testClassInstanceCreation() { ClassInstanceCreation x1 = this.ast.newClassInstanceCreation(); @@ -2028,6 +2052,26 @@ public void testStringLiteral() { String result = this.b.toString(); assertTrue(result.equals("[(eSLHHeSL)]")); //$NON-NLS-1$ } + public void testStringLiteralConcurrent() throws Exception { + StringLiteral x1 = this.ast.newStringLiteral(); + x1.setEscapedValue("\"hello\\nworld\""); //$NON-NLS-1$ + + ExecutorService executorService = Executors.newFixedThreadPool(10); + List> futures = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + CompletableFuture future = CompletableFuture.runAsync(() -> { + try { + x1.getLiteralValue(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, executorService); + futures.add(future); + } + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(); + executorService.shutdown(); + } + /** @deprecated using deprecated code */ public void testSuperConstructorInvocation() { SuperConstructorInvocation x1 = this.ast.newSuperConstructorInvocation(); diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java index eebb4848ccb..96c18184593 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java @@ -205,7 +205,18 @@ void internalSetEscapedValue(String value) { * @exception IllegalArgumentException if the literal value cannot be converted */ public char charValue() { - Scanner scanner = this.ast.scanner; + // create a new local scanner to allow concurrent use + Scanner scanner = new Scanner( + this.ast.scanner.tokenizeComments, + this.ast.scanner.tokenizeWhiteSpace, + this.ast.scanner.checkNonExternalizedStringLiterals, + this.ast.scanner.sourceLevel, + this.ast.scanner.complianceLevel, + this.ast.scanner.taskTags, + this.ast.scanner.taskPriorities, + this.ast.scanner.isTaskCaseSensitive, + this.ast.scanner.previewEnabled); + char[] source = this.escapedValue.toCharArray(); scanner.setSource(source); scanner.resetTo(0, source.length); diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StringLiteral.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StringLiteral.java index 277a1080e96..d9b21fdb7f3 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StringLiteral.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StringLiteral.java @@ -216,7 +216,18 @@ public String getLiteralValue() { throw new IllegalArgumentException(); } - Scanner scanner = this.ast.scanner; + // create a new local scanner to allow concurrent use + Scanner scanner = new Scanner( + this.ast.scanner.tokenizeComments, + this.ast.scanner.tokenizeWhiteSpace, + this.ast.scanner.checkNonExternalizedStringLiterals, + this.ast.scanner.sourceLevel, + this.ast.scanner.complianceLevel, + this.ast.scanner.taskTags, + this.ast.scanner.taskPriorities, + this.ast.scanner.isTaskCaseSensitive, + this.ast.scanner.previewEnabled); + char[] source = s.toCharArray(); scanner.setSource(source); scanner.resetTo(0, source.length); @@ -226,10 +237,10 @@ public String getLiteralValue() { case TerminalTokens.TokenNameStringLiteral: return scanner.getCurrentStringLiteral(); default: - throw new IllegalArgumentException(); + throw new IllegalArgumentException("tokenType: " + tokenType); //$NON-NLS-1$ } } catch(InvalidInputException e) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException(e); } }