diff --git a/org.eclipse.jdt.apt.pluggable.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.apt.pluggable.core/META-INF/MANIFEST.MF index 697a3c4fec6..188e2459e2b 100644 --- a/org.eclipse.jdt.apt.pluggable.core/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.apt.pluggable.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.apt.pluggable.core;singleton:=true -Bundle-Version: 1.4.600.qualifier +Bundle-Version: 1.4.700.qualifier Bundle-Activator: org.eclipse.jdt.internal.apt.pluggable.core.Apt6Plugin Bundle-Vendor: %providerName Require-Bundle: org.eclipse.core.runtime, diff --git a/org.eclipse.jdt.apt.pluggable.core/src/org/eclipse/jdt/internal/apt/pluggable/core/dispatch/IdeProcessingEnvImpl.java b/org.eclipse.jdt.apt.pluggable.core/src/org/eclipse/jdt/internal/apt/pluggable/core/dispatch/IdeProcessingEnvImpl.java index bd12734fadc..b14a1dd2305 100644 --- a/org.eclipse.jdt.apt.pluggable.core/src/org/eclipse/jdt/internal/apt/pluggable/core/dispatch/IdeProcessingEnvImpl.java +++ b/org.eclipse.jdt.apt.pluggable.core/src/org/eclipse/jdt/internal/apt/pluggable/core/dispatch/IdeProcessingEnvImpl.java @@ -102,7 +102,7 @@ public Map getOptions() { private Function, String> replacePlaceholdersUsing(Map commandLineOptions) { return option -> { - String variable, replacement, optionValue = option.getValue(); + String variable, replacement, optionValue = option.getValue() == null ? "" : option.getValue(); Matcher placeholder = Pattern.compile("%([^%]+)%").matcher(optionValue); if (placeholder.find() && (variable = placeholder.group(1)) != null && (replacement = commandLineOptions.get(variable)) != null) { diff --git a/org.eclipse.jdt.apt.pluggable.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.apt.pluggable.tests/META-INF/MANIFEST.MF index fce02106d04..d2e3ba964bd 100644 --- a/org.eclipse.jdt.apt.pluggable.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.apt.pluggable.tests/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.apt.pluggable.tests;singleton:=true -Bundle-Version: 3.6.800.qualifier +Bundle-Version: 3.6.900.qualifier Bundle-Activator: org.eclipse.jdt.apt.pluggable.tests.Apt6TestsPlugin Bundle-Localization: plugin Require-Bundle: org.junit, diff --git a/org.eclipse.jdt.apt.pluggable.tests/pom.xml b/org.eclipse.jdt.apt.pluggable.tests/pom.xml index d19b75809aa..12733a96201 100644 --- a/org.eclipse.jdt.apt.pluggable.tests/pom.xml +++ b/org.eclipse.jdt.apt.pluggable.tests/pom.xml @@ -19,7 +19,7 @@ ../tests-pom/ org.eclipse.jdt.apt.pluggable.tests - 3.6.800-SNAPSHOT + 3.6.900-SNAPSHOT eclipse-test-plugin ${project.artifactId} diff --git a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java index 57157c1b672..f95830bf54b 100644 --- a/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java +++ b/org.eclipse.jdt.apt.pluggable.tests/src/org/eclipse/jdt/apt/pluggable/tests/BuilderTests.java @@ -415,6 +415,25 @@ public void testBug341298() throws Throwable { fullBuild(); assertTrue("Processor should be able to compile with passed options", Bug341298Processor.success()); } + public void testGHIssue4640() throws Throwable { + ProcessorTestStatus.reset(); + IJavaProject project = createJavaProject(_projectName); + IPath root = project.getProject().getFullPath().append("src"); + env.addClass(root, "test341298", "Annotated", + "package test341298;\n" + + "@Annotation public class Annotated {}" + ); + env.addClass(root, "test341298", "Annotation", + "package test341298;\n" + + "public @interface Annotation {}" + ); + AptConfig.addProcessorOption(project, "classpath", "%classpath%"); + AptConfig.addProcessorOption(project, "sourcepath", "%sourcepath%"); + AptConfig.addProcessorOption(project, "phase", null); + AptConfig.setEnabled(project, true); + fullBuild(); + assertTrue("Processor should be able to compile with passed options", Bug341298Processor.success()); + } public void testBug539663() throws Throwable { if (!canRunJava9()) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/Annotation.java index ba57fede665..3e525eae5b2 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/Annotation.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/Annotation.java @@ -1377,6 +1377,8 @@ public static void isTypeUseCompatible(TypeReference reference, Scope scope, Ann nextAnnotation: for (Annotation annotation : annotations) { + if (annotation.resolvedType == null) // barked elsewhere or still cooking and we come here due to re-entrancy + continue; long metaTagBits = annotation.resolvedType.getAnnotationTagBits(); if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0 && (metaTagBits & TagBits.AnnotationForDeclarationMASK) == 0) { ReferenceBinding currentType = (ReferenceBinding) resolvedType; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java index efef82c9a1c..346b9dc53dc 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java @@ -239,6 +239,8 @@ public VisibilityInspector(FunctionalExpression expression, Scope scope, boolean } private void checkVisibility(ReferenceBinding referenceBinding) { + if (referenceBinding.isUnresolvedType()) + referenceBinding = (ReferenceBinding) BinaryTypeBinding.resolveType(referenceBinding, this.scope.environment(), false); if (!referenceBinding.canBeSeenBy(this.scope)) { this.visible = false; if (this.shouldChatter) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java index febc1371256..e388e98087a 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java @@ -128,12 +128,13 @@ public TypeBinding resolveType(BlockScope scope) { } } + RecordComponentBinding[] componentBindings = this.resolvedType.components(); LocalVariableBinding [] bindings = NO_VARIABLES; for (int i = 0, l = this.patterns.length; i < l; ++i) { Pattern p = this.patterns[i]; + p.setOuterExpressionType(componentBindings[i].type); p.resolveTypeWithBindings(bindings, scope); bindings = LocalVariableBinding.merge(bindings, p.bindingsWhenTrue()); - p.setOuterExpressionType(this.resolvedType.components()[i].type); } if (this.resolvedType == null || !this.resolvedType.isValidBinding()) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java index 358175a3511..191af10de56 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java @@ -1387,9 +1387,9 @@ void buildComponents() { void connectTypeHierarchy() { SourceTypeBinding sourceType = this.referenceContext.binding; + boolean previousFlag = environment().enterSuperTypeLookup(sourceType); if ((sourceType.tagBits & TagBits.BeginHierarchyCheck) == 0) { sourceType.tagBits |= TagBits.BeginHierarchyCheck; - environment().typesBeingConnected.add(sourceType); boolean noProblems = connectSuperclass(); noProblems &= connectSuperInterfaces(); if ((sourceType.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) { @@ -1412,6 +1412,7 @@ void connectTypeHierarchy() { throw e; } finally { env.missingClassFileLocation = null; + env.root.isResolvingSuperType = previousFlag; } } @@ -1429,17 +1430,20 @@ private void connectTypeHierarchyWithoutMembers() { SourceTypeBinding sourceType = this.referenceContext.binding; if ((sourceType.tagBits & TagBits.BeginHierarchyCheck) != 0) return; - - sourceType.tagBits |= TagBits.BeginHierarchyCheck; - environment().typesBeingConnected.add(sourceType); - boolean noProblems = connectSuperclass(); - noProblems &= connectSuperInterfaces(); - environment().typesBeingConnected.remove(sourceType); - sourceType.tagBits |= TagBits.EndHierarchyCheck; - noProblems &= connectTypeVariables(this.referenceContext.typeParameters, false); - sourceType.tagBits |= TagBits.TypeVariablesAreConnected; - if (noProblems && sourceType.isHierarchyInconsistent()) - problemReporter().hierarchyHasProblems(sourceType); + boolean previousFlag = environment().enterSuperTypeLookup(sourceType); + try { + sourceType.tagBits |= TagBits.BeginHierarchyCheck; + boolean noProblems = connectSuperclass(); + noProblems &= connectSuperInterfaces(); + environment().typesBeingConnected.remove(sourceType); + sourceType.tagBits |= TagBits.EndHierarchyCheck; + noProblems &= connectTypeVariables(this.referenceContext.typeParameters, false); + sourceType.tagBits |= TagBits.TypeVariablesAreConnected; + if (noProblems && sourceType.isHierarchyInconsistent()) + problemReporter().hierarchyHasProblems(sourceType); + } finally { + environment().root.isResolvingSuperType = previousFlag; + } } public boolean detectHierarchyCycle(TypeBinding superType, TypeReference reference) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java index ed47a69a681..853d782c231 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -125,6 +125,7 @@ public class LookupEnvironment implements ProblemReasons, TypeConstants { private ArrayList missingTypes; final Set typesBeingConnected; // SHARED public boolean isProcessingAnnotations = false; // ROOT_ONLY + public boolean isResolvingSuperType = false; // ROOT_ONLY public boolean mayTolerateMissingType = false; AnnotationBinding nonNullAnnotation; @@ -154,14 +155,19 @@ public class LookupEnvironment implements ProblemReasons, TypeConstants { static class GlobalDataMemento { Set typesBeingConnected; boolean mayTolerateMissingType = false; - GlobalDataMemento(Set typesBeingConnected, boolean mayTolerateMissingType) { + boolean isResolvingSuperType = false; + GlobalDataMemento(Set typesBeingConnected, boolean mayTolerateMissingType, boolean isResolvingSuperType) { this.typesBeingConnected = typesBeingConnected; this.mayTolerateMissingType = mayTolerateMissingType; + this.isResolvingSuperType = isResolvingSuperType; } } GlobalDataMemento stashGlobalData() { - GlobalDataMemento memento = new GlobalDataMemento(new LinkedHashSet<>(this.typesBeingConnected), this.mayTolerateMissingType); - this.typesBeingConnected.clear(); + GlobalDataMemento memento = new GlobalDataMemento(new LinkedHashSet<>(this.typesBeingConnected), + this.mayTolerateMissingType, this.root.isResolvingSuperType); + if (!this.root.isResolvingSuperType) + this.typesBeingConnected.clear(); // lookup is not within the hierarchy of these types + this.root.isResolvingSuperType = false; this.mayTolerateMissingType = false; return memento; } @@ -169,6 +175,14 @@ void restoreFrom(GlobalDataMemento memento) { this.typesBeingConnected.clear(); this.typesBeingConnected.addAll(memento.typesBeingConnected); this.mayTolerateMissingType = memento.mayTolerateMissingType; + this.root.isResolvingSuperType = memento.isResolvingSuperType; + } + + public boolean enterSuperTypeLookup(SourceTypeBinding sourceType) { + this.typesBeingConnected.add(sourceType); + boolean previous = this.root.isResolvingSuperType; + this.root.isResolvingSuperType = true; + return previous; } static enum CompleteTypeBindingsSteps { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java index eecf95311c8..392c9f35914 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java @@ -365,6 +365,7 @@ protected boolean commentParse() { considerTagAsPlainText = false; // re-enable tag validation } } + boolean isLiteralOrCode = this.tagValue == TAG_LITERAL_VALUE || this.tagValue == TAG_CODE_VALUE; if (this.inlineTagStarted) { textEndPosition = this.index - 1; boolean treatAsText= considerTagAsPlainText || (this.inlineReturn && this.inlineReturnOpenBraces > 0); @@ -377,8 +378,12 @@ protected boolean commentParse() { } if (!isFormatterParser && !treatAsText && (!this.inlineReturn || this.inlineReturnOpenBraces <= 0)) this.textStart = this.index; - if ((!isTagElementClose && this.markdown) || !this.markdown) { //The comment parser should create a TagElement only if the previous one is closed - markdown. + if (!isTagElementClose && this.markdown) { //The comment parser should create a TagElement only if the previous one is closed - markdown. setInlineTagStarted(false); + } else if (!this.markdown) { + if (!(isLiteralOrCode && openingBraces != 0)) { + setInlineTagStarted(false); + } } if (this.inlineReturn) { if (this.inlineReturnOpenBraces > 0) { @@ -470,8 +475,8 @@ protected boolean commentParse() { } } } - break; } + break; //$FALL-THROUGH$ case '/': if (this.markdown) { @@ -1393,6 +1398,40 @@ protected boolean parseReference() throws InvalidInputException { return parseReference(false); } + // Parses a complete URL reference starting from current position + protected boolean parseURLReference(int pos, boolean advanceEndPos) throws InvalidInputException { + char[]fullURL = null; + int firstTokenStartPos; + StringBuilder urlBuilder = new StringBuilder(); + char c; + firstTokenStartPos = pos; + while (pos < this.source.length) { + c = this.source[pos]; + if (c == '[') // invalid syntax for url + return false; + if (c == '(' || c == ' ') { + pos++; + continue; + } + if (c == '\n' || c == '\r' || c == ')') { + break; + } + urlBuilder.append(c); + pos++; + } + if (advanceEndPos) + this.index = pos; + fullURL = urlBuilder.toString().toCharArray(); + + this.identifierPtr = 0; + this.identifierStack[this.identifierPtr] = fullURL; + this.identifierPositionStack[this.identifierPtr] = (((long) firstTokenStartPos) << 32) + (pos - 1); + this.identifierLengthStack[this.identifierLengthPtr] = 1; + Object typeRef = createTypeReference(TerminalToken.TokenNameInvalid, true); + pushSeeRef(typeRef); + return true; + } + /* * Parse a reference in @see tag */ @@ -3612,6 +3651,7 @@ protected boolean verifySpaceOrEndComment() { // Whitespace or inline tag closing brace char ch = peekChar(); switch (ch) { + case ')': case ']': // TODO: Check if we need to exclude escaped ] if (this.markdown) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java index 4b52bc978ef..9bb5ae6c782 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java @@ -581,6 +581,8 @@ protected boolean parseMarkdownLinks(int previousPosition) throws InvalidInputEx // move it past '[' currentChar = readChar(); start = this.index; + } else if (peekChar() == '(') { + valid = parseURLReference(this.index, true); } else { break loop; } @@ -602,7 +604,8 @@ protected boolean parseMarkdownLinks(int previousPosition) throws InvalidInputEx int eofBkup = this.scanner.eofPosition; this.scanner.resetTo(start, Math.max(this.javadocEnd, this.index)); this.tagValue = TAG_LINK_VALUE; - valid = parseReference(true); + if (!valid) + valid = parseReference(true); this.tagValue = NO_TAG_VALUE; this.scanner.eofPosition = eofBkup; this.markdownHelper.resetLineStart(); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java index 4975ccae065..b7062800bda 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java @@ -1730,7 +1730,7 @@ protected TerminalToken getNextToken0() throws InvalidInputException { } isUnicode = false; previous = this.currentPosition; - if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') + if ((this.currentPosition < this.eofPosition && (this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) { //-------------unicode traitement ------------ getNextUnicodeChar(); @@ -1746,8 +1746,8 @@ protected TerminalToken getNextToken0() throws InvalidInputException { //loop as long as lines start with /// int firstTag = 0; while(true) { - if (this.currentPosition > this.eofPosition) { - throw unterminatedComment(); + if (this.currentPosition == this.eofPosition) { + break; } if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) { if (this.recordLineSeparator) { diff --git a/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF index eb405a9e42c..5915821370b 100644 --- a/org.eclipse.jdt.core.tests.builder/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.core.tests.builder/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.builder; singleton:=true -Bundle-Version: 3.12.1000.qualifier +Bundle-Version: 3.12.1100.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: org.eclipse.jdt.core.tests.builder diff --git a/org.eclipse.jdt.core.tests.builder/pom.xml b/org.eclipse.jdt.core.tests.builder/pom.xml index 41f9288100e..537be974325 100644 --- a/org.eclipse.jdt.core.tests.builder/pom.xml +++ b/org.eclipse.jdt.core.tests.builder/pom.xml @@ -18,7 +18,7 @@ ../tests-pom/ org.eclipse.jdt.core.tests.builder - 3.12.1000-SNAPSHOT + 3.12.1100-SNAPSHOT eclipse-test-plugin diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/IncrementalTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/IncrementalTests.java index 722e6ae161a..1fac79b4251 100644 --- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/IncrementalTests.java +++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/IncrementalTests.java @@ -1835,4 +1835,73 @@ public static void main(String [] args) { env.removeProject(projectPath); } + + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4632 + // The type ... from the descriptor computed for the target context is not visible here + public void testIssue4632() throws JavaModelException { + IPath projectPath = env.addProject("Project", "19"); + env.addExternalJars(projectPath, Util.getJavaClassLibs()); + + // remove old package fragment root so that names don't collide + env.removePackageFragmentRoot(projectPath, ""); + + IPath root = env.addPackageFragmentRoot(projectPath, "src"); + env.setOutputFolder(projectPath, "bin"); + + env.addClass(root, "other", "AuthorizeHttpRequestsConfigurer", + """ + package other; + + public class AuthorizeHttpRequestsConfigurer { + public class AuthorizationManagerRequestMatcherRegistry {} + } + """); + env.addClass(root, "other", "Customizer", + """ + package other; + + public interface Customizer { + void customize(T t); + } + """); + env.addClass(root, "other", "HttpSecurity", + """ + package other; + + public class HttpSecurity { + } + """); + env.addClass(root, "test", "FrontEndSecurityCustomizer", + """ + package test; + + import other.AuthorizeHttpRequestsConfigurer; + import other.Customizer; + import other.HttpSecurity; + + public interface FrontEndSecurityCustomizer extends Customizer.AuthorizationManagerRequestMatcherRegistry> { + + } + """); + fullBuild(projectPath); + expectingNoProblems(); + + env.addClass(root, "test", "ProfileSecurityConfiguration", + """ + package test; + + public class ProfileSecurityConfiguration { + + FrontEndSecurityCustomizer profileFrontEndSecurityCustomizer() { + return auth -> System.out.println(auth); + } + } + """); + + incrementalBuild(projectPath); + expectingNoProblems(); + + env.removeProject(projectPath); + } + } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PreviewFeatureTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PreviewFeatureTest.java index 26993c1fe6d..6a58b3a56a3 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PreviewFeatureTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PreviewFeatureTest.java @@ -106,40 +106,64 @@ public void test001() { Map options = getCompilerOptions(); String old = options.get(CompilerOptions.OPTION_EnablePreviews); options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.DISABLED); - try { - runNegativeTest( - new String[] { - "X.java", - "import p.*;\n"+ - "public class X {\n"+ - " Zork z = null;\n" + - " ABC abc = null;\n" + - " public void foo () {\n"+ - " (new ABC()).doSomething();\n"+ - " }\n"+ - "}\n", - }, + String output = this.complianceLevel == ClassFileConstants.JDK17 ? + "----------\n" + + "1. ERROR in X.java (at line 3)\n" + + " Zork z = null;\n" + + " ^^^^\n" + + "Zork cannot be resolved to a type\n" + + "----------\n" + + "2. WARNING in X.java (at line 4)\n" + + " ABC abc = null;\n" + + " ^^^\n" + + "You are using an API that is part of the preview feature \'Test Feature\' and may be removed in future\n" + + "----------\n" + + "3. WARNING in X.java (at line 6)\n" + + " (new ABC()).doSomething();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "You are using an API that is part of the preview feature \'Test Feature\' and may be removed in future\n" + + "----------\n" + + "4. WARNING in X.java (at line 6)\n" + + " (new ABC()).doSomething();\n" + + " ^^^\n" + + "You are using an API that is part of the preview feature \'Test Feature\' and may be removed in future\n" + + "----------\n" : "----------\n" + "1. ERROR in X.java (at line 3)\n" + " Zork z = null;\n" + " ^^^^\n" + "Zork cannot be resolved to a type\n" + "----------\n" + - "2. ERROR in X.java (at line 4)\n" + + "2. WARNING in X.java (at line 4)\n" + " ABC abc = null;\n" + " ^^^\n" + - "This API is part of the preview feature \'Test Feature\' which is disabled by default. Use --enable-preview to enable\n" + + "You are using an API that is part of the preview feature \'Test Feature\' and may be removed in future\n" + "----------\n" + - "3. ERROR in X.java (at line 6)\n" + + "3. WARNING in X.java (at line 6)\n" + " (new ABC()).doSomething();\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "This API is part of the preview feature \'Test Feature\' which is disabled by default. Use --enable-preview to enable\n" + + "You are using an API that is part of the preview feature \'Test Feature\' and may be removed in future\n" + "----------\n" + - "4. ERROR in X.java (at line 6)\n" + + "4. WARNING in X.java (at line 6)\n" + " (new ABC()).doSomething();\n" + " ^^^\n" + - "This API is part of the preview feature \'Test Feature\' which is disabled by default. Use --enable-preview to enable\n" + - "----------\n", + "You are using an API that is part of the preview feature \'Test Feature\' and may be removed in future\n" + + "----------\n"; + + try { + runNegativeTest( + new String[] { + "X.java", + "import p.*;\n"+ + "public class X {\n"+ + " Zork z = null;\n" + + " ABC abc = null;\n" + + " public void foo () {\n"+ + " (new ABC()).doSomething();\n"+ + " }\n"+ + "}\n", + }, + output, classLibs, true, options); @@ -158,6 +182,34 @@ public void test002() { String old = options.get(CompilerOptions.OPTION_EnablePreviews); options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.DISABLED); String[] classLibs = getClasspathWithPreviewAPI(); + String output = this.complianceLevel == ClassFileConstants.JDK17 ? + "----------\n" + + "1. ERROR in X.java (at line 3)\n" + + " Zork z = null;\n" + + " ^^^^\n" + + "Zork cannot be resolved to a type\n" + + "----------\n" + + "2. WARNING in X.java (at line 4)\n" + + " ABC abc = null;\n" + + " ^^^\n" + + "You are using an API that is part of the preview feature \'Test Feature\' and may be removed in future\n" + + "----------\n" + + "3. WARNING in X.java (at line 6)\n" + + " (new ABC()).doSomething();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "You are using an API that is part of the preview feature \'Test Feature\' and may be removed in future\n" + + "----------\n" + + "4. WARNING in X.java (at line 6)\n" + + " (new ABC()).doSomething();\n" + + " ^^^\n" + + "You are using an API that is part of the preview feature \'Test Feature\' and may be removed in future\n" + + "----------\n" : + "----------\n" + + "1. ERROR in X.java (at line 4)\n" + + " Zork z = null;\n" + + " ^^^^\n" + + "Zork cannot be resolved to a type\n" + + "----------\n"; try { runNegativeTest( new String[] { @@ -172,27 +224,7 @@ public void test002() { " }\n"+ "}\n", }, - "----------\n" + - "1. ERROR in X.java (at line 4)\n" + - " Zork z = null;\n" + - " ^^^^\n" + - "Zork cannot be resolved to a type\n" + - "----------\n" + - "2. ERROR in X.java (at line 5)\n" + - " ABC abc = null;\n" + - " ^^^\n" + - "This API is part of the preview feature \'Test Feature\' which is disabled by default. Use --enable-preview to enable\n" + - "----------\n" + - "3. ERROR in X.java (at line 7)\n" + - " (new ABC()).doSomething();\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "This API is part of the preview feature \'Test Feature\' which is disabled by default. Use --enable-preview to enable\n" + - "----------\n" + - "4. ERROR in X.java (at line 7)\n" + - " (new ABC()).doSomething();\n" + - " ^^^\n" + - "This API is part of the preview feature \'Test Feature\' which is disabled by default. Use --enable-preview to enable\n" + - "----------\n", + output, classLibs, true, options); diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordPatternTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordPatternTest.java index 7eea16c45d2..f3f5a38adc0 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordPatternTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/RecordPatternTest.java @@ -28,7 +28,7 @@ public class RecordPatternTest extends AbstractRegressionTest9 { static { // TESTS_NUMBERS = new int [] { 40 }; // TESTS_RANGE = new int[] { 1, -1 }; -// TESTS_NAMES = new String[] { "testRecPatExhaust018" }; +// TESTS_NAMES = new String[] { "testRecordTypeInfer_4643" }; } private String extraLibPath; public static Class testClass() { @@ -5046,4 +5046,48 @@ record Wildcard(Class bound) implements ComponentType> { """ }); } + public void testRecordTypeInfer_4643_001() { + runConformTest(new String[] { "X.java", """ + public class X { + + private static void foo() { + record Box(T t) {} + + Box> bo = new Box<>(new Box<>("str")); + if (bo instanceof Box(Box(var sString))) { + System.out.println(sString.length()); + } + } + + public static void main(String[] args) { + foo(); + } + } + """ }, "3"); + } + public void testRecordTypeInfer_4643_002() { + runNegativeTest(new String[] { + "X.java", + """ + public class X { + + private static void foo() { + record Box(T t) {} + Box> bo = new Box<>(new Box<>(1)); + if (bo instanceof Box(Box(String sString))) {} + } + public static void main(String[] args) { + foo(); + } + } + """ + }, + "----------\n" + + "1. ERROR in X.java (at line 6)\n" + + " if (bo instanceof Box(Box(String sString))) {}\n" + + " ^^^^^^^^^^^^^^\n" + + "Record component with type Integer is not compatible with type String\n" + + "----------\n"); + } + } \ No newline at end of file diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ScannerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ScannerTest.java index 320527c2466..f3b3397cc55 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ScannerTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ScannerTest.java @@ -1848,4 +1848,38 @@ public void testTerminalTokensAPIs() { assertTrue(TerminalToken.getRestrictedKeyword("When".toCharArray()) == TerminalToken.TokenNameNotAToken); assertTrue(TerminalToken.getRestrictedKeyword("blah".toCharArray()) == TerminalToken.TokenNameNotAToken); } + + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/4674 + public void testIssue4674() { + IScanner scanner = ToolFactory.createScanner(true, true, true, "23", "23"); + final char[] source = "/// @return a string".toCharArray(); + scanner.setSource(source); + final StringBuilder buffer = new StringBuilder(); + try { + int token; + boolean foundMarkdown = false; + boolean foundOther = false; + while ((token = scanner.getNextToken()) != ITerminalSymbols.TokenNameEOF) { + try { + switch(token) { + case ITerminalSymbols.TokenNameCOMMENT_MARKDOWN : + foundMarkdown = true; + break; + default : + foundOther = true; + buffer.append(scanner.getCurrentTokenSource()); + break; + } + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + } + } + assertTrue("Should have found markdown comment", foundMarkdown); + assertTrue("Should have found EOF token", token == ITerminalSymbols.TokenNameEOF); + assertFalse("Should not have found other", foundOther); + } catch (InvalidInputException e) { + assertTrue("Should not have InvalidInputException", false); + } + } + } diff --git a/org.eclipse.jdt.core.tests.model/pom.xml b/org.eclipse.jdt.core.tests.model/pom.xml index 59f714160c0..e264c4ccfcc 100644 --- a/org.eclipse.jdt.core.tests.model/pom.xml +++ b/org.eclipse.jdt.core.tests.model/pom.xml @@ -19,7 +19,7 @@ ../tests-pom/ org.eclipse.jdt.core.tests.model - 3.13.650-SNAPSHOT + 3.13.750-SNAPSHOT eclipse-test-plugin diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunVariousSealedTypeTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunVariousSealedTypeTests.java index 5b5e0b257c5..4d717bfd522 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunVariousSealedTypeTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunVariousSealedTypeTests.java @@ -63,7 +63,7 @@ public static Class[] getAllTestClasses() { FormatterRegressionTests.class, CompletionTests16_1.class, CompletionTests17.class, - Java21ElementTests.class, + Java25ElementTests.class, JavaSearchBugs15Tests.class, JavaSearchBugs17Tests.class, JavaSearchBugs19Tests.class, diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocTest.java index 495758f0a6b..499853b7252 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocTest.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocTest.java @@ -3404,19 +3404,16 @@ public void testBug206345a() throws JavaModelException { assumeEquals(this.prefix+"Wrong number of tags", 1, docComment.tags().size()); TagElement tagElement = (TagElement) docComment.tags().get(0); assumeNull(this.prefix+"Wrong type of tag ["+tagElement+"]", tagElement.getTagName()); - assumeEquals(this.prefix+"Wrong number of fragments in tag ["+tagElement+"]", 3, tagElement.fragments().size()); + assumeEquals(this.prefix+"Wrong number of fragments in tag ["+tagElement+"]", 2, tagElement.fragments().size()); ASTNode fragment = (ASTNode) tagElement.fragments().get(0); assumeEquals(this.prefix+"Invalid type for fragment ["+fragment+"]", ASTNode.TEXT_ELEMENT, fragment.getNodeType()); fragment = (ASTNode) tagElement.fragments().get(1); assumeEquals(this.prefix+"Invalid type for fragment ["+fragment+"]", ASTNode.TAG_ELEMENT, fragment.getNodeType()); TagElement inlineTag = (TagElement) fragment; - assumeEquals(this.prefix+"Wrong number of fragments in tag ["+inlineTag+"]", 1, inlineTag.fragments().size()); - fragment = (ASTNode) inlineTag.fragments().get(0); - assumeEquals(this.prefix+"Invalid type for fragment ["+fragment+"]", ASTNode.TEXT_ELEMENT, fragment.getNodeType()); - fragment = (ASTNode) tagElement.fragments().get(2); - assumeEquals(this.prefix+"Invalid type for fragment ["+fragment+"]", ASTNode.TEXT_ELEMENT, fragment.getNodeType()); - TextElement textElement = (TextElement) fragment; - assumeEquals(this.prefix+"Invalid content for text element ", "{@link BadLink} is just text}", textElement.getText()); + assumeEquals(this.prefix+"Wrong number of fragments in tag ["+inlineTag+"]", 2, inlineTag.fragments().size()); + ASTNode fragment1 = (ASTNode) inlineTag.fragments().get(0); + assumeEquals(this.prefix+"Invalid type for fragment ["+fragment1+"]", ASTNode.TEXT_ELEMENT, fragment1.getNodeType()); + assumeEquals(this.prefix+"Invalid content for text element ", "{@literal raw text:{@link BadLink} is just text}", fragment.toString()); } } /** @@ -3451,19 +3448,139 @@ public void testBug206345b() throws JavaModelException { assumeEquals(this.prefix+"Wrong number of tags", 1, docComment.tags().size()); TagElement tagElement = (TagElement) docComment.tags().get(0); assumeNull(this.prefix+"Wrong type of tag ["+tagElement+"]", tagElement.getTagName()); - assumeEquals(this.prefix+"Wrong number of fragments in tag ["+tagElement+"]", 3, tagElement.fragments().size()); + assumeEquals(this.prefix+"Wrong number of fragments in tag ["+tagElement+"]", 2, tagElement.fragments().size()); ASTNode fragment = (ASTNode) tagElement.fragments().get(0); assumeEquals(this.prefix+"Invalid type for fragment ["+fragment+"]", ASTNode.TEXT_ELEMENT, fragment.getNodeType()); fragment = (ASTNode) tagElement.fragments().get(1); assumeEquals(this.prefix+"Invalid type for fragment ["+fragment+"]", ASTNode.TAG_ELEMENT, fragment.getNodeType()); TagElement inlineTag = (TagElement) fragment; - assumeEquals(this.prefix+"Wrong number of fragments in tag ["+inlineTag+"]", 1, inlineTag.fragments().size()); + assumeEquals(this.prefix+"Wrong number of fragments in tag ["+inlineTag+"]", 2, inlineTag.fragments().size()); fragment = (ASTNode) inlineTag.fragments().get(0); assumeEquals(this.prefix+"Invalid type for fragment ["+fragment+"]", ASTNode.TEXT_ELEMENT, fragment.getNodeType()); - fragment = (ASTNode) tagElement.fragments().get(2); - assumeEquals(this.prefix+"Invalid type for fragment ["+fragment+"]", ASTNode.TEXT_ELEMENT, fragment.getNodeType()); - TextElement textElement = (TextElement) fragment; - assumeEquals(this.prefix+"Invalid content for text element ", "{@link BadLink} is just text}", textElement.getText()); + assumeEquals(this.prefix+"Invalid content for text element ", "{@link BadLink} is just text", inlineTag.fragments().get(1).toString()); } } + + public void testContentOfCodeParsedOutside4615_01() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.astLevel = AST.JLS25; + this.workingCopies[0] = getWorkingCopy("/Converter25/src/javadoc/X.java", + """ + /** + * {@code public class Example { final int a = 1; } } + */ + public class X {} + """ + ); + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + List unitComments = compilUnit.getCommentList(); + assertEquals("Wrong number of comments", 1, unitComments.size()); + Comment comment = (Comment) unitComments.get(0); + assertEquals("Comment should be javadoc", comment.getNodeType(), ASTNode.JAVADOC); + Javadoc docComment = (Javadoc) compilUnit.getCommentList().get(0); + assumeEquals("Wrong number of tags", 1, docComment.tags().size()); + TagElement tagElement = (TagElement) docComment.tags().get(0); + List listFrag = tagElement.fragments(); + assumeEquals("wrong number of tags", 1, listFrag.size()); + } + + public void testContentOfCodeParsedOutside4615_02() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.astLevel = AST.JLS25; + this.workingCopies[0] = getWorkingCopy("/Converter25/src/javadoc/X.java", + """ + /** + * {@code com/{filename:\\w+}.jsp} + */ + public class X {} + """ + ); + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + List unitComments = compilUnit.getCommentList(); + assertEquals("Wrong number of comments", 1, unitComments.size()); + Comment comment = (Comment) unitComments.get(0); + assertEquals("Comment should be javadoc", comment.getNodeType(), ASTNode.JAVADOC); + Javadoc docComment = (Javadoc) compilUnit.getCommentList().get(0); + assumeEquals("wrong number of tags", 1, docComment.tags().size()); + TagElement parentTag = (TagElement) docComment.tags().get(0); + List frags = parentTag.fragments(); + assumeEquals("wrong number of frags", 1, frags.size()); + TagElement problematicTag = (TagElement) frags.get(0); + assumeEquals("invalid content", "{@code com/{filename:\\w+}.jsp}", problematicTag.toString()); + } + + public void testContentOfCodeParsedOutside4615_03() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.astLevel = AST.JLS25; + this.workingCopies[0] = getWorkingCopy("/Converter25/src/javadoc/X.java", + """ + /** + * {@code public class X { void foo() { int x; } } } + */ + public class X {} + """ + ); + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + List unitComments = compilUnit.getCommentList(); + assertEquals("Wrong number of comments", 1, unitComments.size()); + Comment comment = (Comment) unitComments.get(0); + assertEquals("Comment should be javadoc", comment.getNodeType(), ASTNode.JAVADOC); + Javadoc docComment = (Javadoc) compilUnit.getCommentList().get(0); + assumeEquals("Wrong number of tags", 1, docComment.tags().size()); + TagElement tagElement = (TagElement) docComment.tags().get(0); + List listFrag = tagElement.fragments(); + assumeEquals("wrong number of tags", 1, listFrag.size()); + assumeEquals("Invalid content", "{@code public class X { void foo() { int x; } } }", listFrag.get(0).toString()); + } + + public void testContentOfCodeParsedOutside4615_04() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.astLevel = AST.JLS25; + this.workingCopies[0] = getWorkingCopy("/Converter25/src/javadoc/X.java", + """ + /** + * {@code public class Example { final int sasi; } class B{}} + */ + public class X {} + """ + ); + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + List unitComments = compilUnit.getCommentList(); + assertEquals("Wrong number of comments", 1, unitComments.size()); + Comment comment = (Comment) unitComments.get(0); + assertEquals("Comment should be javadoc", comment.getNodeType(), ASTNode.JAVADOC); + Javadoc docComment = (Javadoc) compilUnit.getCommentList().get(0); + assumeEquals("Wrong number of tags", 1, docComment.tags().size()); + TagElement tagElement = (TagElement) docComment.tags().get(0); + List listFrag = tagElement.fragments(); + assumeEquals("wrong number of tags", 1, listFrag.size()); + assumeEquals("Invalid content", "{@code public class Example { final int sasi; } class B{}}", listFrag.get(0).toString()); + } + + //code tag in multiple lines + public void testContentOfCodeParsedOutside4615_05() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.astLevel = AST.JLS25; + this.workingCopies[0] = getWorkingCopy("/Converter25/src/javadoc/X.java", + """ + /** + * {@code com/{filename:\\w+} + * .jsp} + */ + public class X {} + """ + ); + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + List unitComments = compilUnit.getCommentList(); + assertEquals("Wrong number of comments", 1, unitComments.size()); + Comment comment = (Comment) unitComments.get(0); + assertEquals("Comment should be javadoc", comment.getNodeType(), ASTNode.JAVADOC); + Javadoc docComment = (Javadoc) compilUnit.getCommentList().get(0); + assumeEquals("wrong number of tags", 1, docComment.tags().size()); + TagElement parentTag = (TagElement) docComment.tags().get(0); + List frags = parentTag.fragments(); + assumeEquals("wrong number of frags", 1, frags.size()); + TagElement problematicTag = (TagElement) frags.get(0); + assumeEquals("invalid content", "{@code com/{filename:\\w+}.jsp}", problematicTag.toString()); + } } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterMarkdownTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterMarkdownTest.java index 9678b38d45d..5f991bfb4b1 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterMarkdownTest.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterMarkdownTest.java @@ -1914,4 +1914,267 @@ public class Table {} assertEquals("Incorrect TagElement", 1, (fragments.get(3).getFlags() & ASTNode.MALFORMED)); //MALFOUND flag } } + + public void testMarkdownSupportForBold4608() throws JavaModelException { + String source = """ + /// Where is my **bold text**??? + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tag = (TagElement) javadoc.tags().get(0); + TextElement textElement = (TextElement) tag.fragments().get(0); + assertEquals("Incorrect TextElement value", "Where is my **bold text**???", textElement.getText()); + } + } + public void testMarkdownURLs4531_01() throws JavaModelException { + String source = """ + /// @see [Ex Si](ex.com) + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 2, tags.fragments().size()); + TagElement tagElement = (TagElement) tags.fragments().get(1); + List tagFragments = tagElement.fragments(); + assertTrue(tagFragments.get(0) instanceof TextElement); + assertTrue(tagFragments.get(1) instanceof SimpleName); + } + } + + public void testMarkdownURLs4531_02() throws JavaModelException { + String source = """ + /// @see [Ex Si](http://ex.com) + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 2, tags.fragments().size()); + TagElement tagElement = (TagElement) tags.fragments().get(1); + List tagFragments = tagElement.fragments(); + assertTrue(tagFragments.get(0) instanceof TextElement); + assertTrue(tagFragments.get(1) instanceof SimpleName); + } + } + + public void testMarkdownURLs4531_03() throws JavaModelException { + String source = """ + /// @see [Ex Si](https://ex.com/a) + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 2, tags.fragments().size()); + TagElement tagElement = (TagElement) tags.fragments().get(1); + List tagFragments = tagElement.fragments(); + assertTrue(tagFragments.get(0) instanceof TextElement); + assertTrue(tagFragments.get(1) instanceof SimpleName); + } + } + + public void testMarkdownURLs4531_04() throws JavaModelException { + String source = """ + /// @see [Ex Si](https://www.ex.net/a) + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 2, tags.fragments().size()); + TagElement tagElement = (TagElement) tags.fragments().get(1); + List tagFragments = tagElement.fragments(); + assertTrue(tagFragments.get(0) instanceof TextElement); + assertTrue(tagFragments.get(1) instanceof SimpleName); + } + } + + // invalid syntax + public void testMarkdownURLs4531_05() throws JavaModelException { + String source = """ + /// @see [Ex Si][http://ex.com] + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 3, tags.fragments().size()); + assertTrue(tags.fragments().get(0) instanceof TextElement); + assertTrue(tags.fragments().get(1) instanceof TextElement); + assertTrue(tags.fragments().get(2) instanceof TextElement); + } + } + + // [)[) - invalid condition + public void testMarkdownURLs4531_06() throws JavaModelException { + String source = """ + /// @see [Ex Si)[http://ex.com) + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + assertEquals("Tags count does not match", 1, javadoc.tags().size()); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertTrue(tags.fragments().get(0) instanceof TextElement); + assertTrue(tags.fragments().get(1) instanceof TextElement); + } + } + + // (](] - invalid condition + public void testMarkdownURLs4531_07() throws JavaModelException { + String source = """ + /// @see (Ex Si](http://ex.com] + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 1, tags.fragments().size()); + assertTrue(tags.fragments().get(0) instanceof TextElement); + } + } + + // ()[] - invalid condition + public void testMarkdownURLs4531_08() throws JavaModelException { + String source = """ + /// @see (Ex Si)[http://ex.com] + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 2, tags.fragments().size()); + assertTrue(tags.fragments().get(0) instanceof TextElement); + assertTrue(tags.fragments().get(1) instanceof TextElement); + } + } + + public void testMarkdownURLs4531_09() throws JavaModelException { + String source = """ + /// @see [Ex Si]( http://ex.com) + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 2, tags.fragments().size()); + assertTrue(tags.fragments().get(0) instanceof TextElement); + assertTrue(tags.fragments().get(1) instanceof TagElement); + TagElement fragTag = (TagElement) tags.fragments().get(1); + assertTrue(fragTag.fragments().get(0) instanceof TextElement); + assertTrue(fragTag.fragments().get(1) instanceof SimpleName); + } + } + + public void testMarkdownURLs4531_10() throws JavaModelException { + String source = """ + /// @see [Ex Si][java.lang.String] + public class Markdown() {} + """; + + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 2, tags.fragments().size()); + assertTrue(tags.fragments().get(0) instanceof TextElement); + assertTrue(tags.fragments().get(1) instanceof TagElement); + TagElement fragTag = (TagElement) tags.fragments().get(1); + assertTrue(fragTag.fragments().get(0) instanceof TextElement); + assertTrue(fragTag.fragments().get(1) instanceof QualifiedName); + } + } + + public void testMarkdownURLs4531_11() throws JavaModelException { + String source = """ + /// @see [Ex Si][ java.lang.String] + public class Markdown() {} + """; + + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 2, tags.fragments().size()); + assertTrue(tags.fragments().get(0) instanceof TextElement); + assertTrue(tags.fragments().get(1) instanceof TagElement); + TagElement fragTag = (TagElement) tags.fragments().get(1); + assertTrue(fragTag.fragments().get(0) instanceof TextElement); + assertTrue(fragTag.fragments().get(1) instanceof QualifiedName); + } + } + + public void testMarkdownURLs4531_12() throws JavaModelException { + String source = """ + /// @see [Ex Si](http://ex.com ) [Ex Si]( https://www.ex.com) + public class Markdown() {} + """; + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Converter_25/src/markdown/gh3761/Markdown.java", source, null); + if (this.docCommentSupport.equals(JavaCore.ENABLED)) { + CompilationUnit compilUnit = (CompilationUnit) runConversion(this.workingCopies[0], true); + TypeDeclaration typedeclaration = (TypeDeclaration) compilUnit.types().get(0); + Javadoc javadoc = typedeclaration.getJavadoc(); + TagElement tags = (TagElement) javadoc.tags().get(0); + assertEquals("fragments count does not match", 4, tags.fragments().size()); + assertTrue(tags.fragments().get(0) instanceof TextElement); + assertTrue(tags.fragments().get(1) instanceof TagElement); + TagElement tagFrag1 = (TagElement) tags.fragments().get(1); + SimpleName simplName1 = (SimpleName) tagFrag1.fragments().get(1); + assertEquals("SimpleName1 value not match", "http://ex.com", simplName1.getIdentifier()); + assertTrue(tags.fragments().get(0) instanceof TextElement); + assertTrue(tags.fragments().get(1) instanceof TagElement); + TagElement tagFrag2 = (TagElement) tags.fragments().get(3); + SimpleName simplName2 = (SimpleName) tagFrag2.fragments().get(1); + assertEquals("SimpleName2 value not match", "https://www.ex.com", simplName2.getIdentifier()); + } + } } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java index 5422dd129c6..0930b681807 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java @@ -16536,4 +16536,68 @@ public int sample(String param1) { """; formatSource(input, expected); } + + public void testRecordWithOpeningParanthesisInParam() throws JavaModelException { + setComplianceLevel(CompilerOptions.VERSION_16); + this.formatterPrefs.insert_space_before_opening_brace_in_record_declaration = true; + String input = """ + public record X(String a, @SuppressWarnings({ + "a", "b" }) String b){ + + } + """; + String expected = """ + public record X(String a, @SuppressWarnings({ + "a", "b" }) String b) { + + } + """; + formatSource(input, expected); + } + public void testRecordWithOpeningParanthesisInParamWithSuperInterfaces() throws JavaModelException { + setComplianceLevel(CompilerOptions.VERSION_16); + this.formatterPrefs.insert_space_before_opening_brace_in_record_declaration = true; + String input = """ + public record X2(String a, + @SuppressWarnings({ + "a", "b" }) String b) + implements Runnable, AutoCloseable{ + + @Override + public void run() { + } + + @Override + public void close() { + } + } + """; + String expected = """ + public record X2(String a, @SuppressWarnings({ + "a", "b" }) String b) implements Runnable, AutoCloseable { + + @Override + public void run() { + } + + @Override + public void close() { + } + } + """; + formatSource(input, expected); + } + + public void testRecordWithTypeParams() throws JavaModelException { + setComplianceLevel(CompilerOptions.VERSION_16); + this.formatterPrefs.insert_space_before_opening_brace_in_record_declaration = true; + String input = """ + record X(T value){} + """; + String expected = """ + record X(T value) { + } + """; + formatSource(input, expected); + } } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java index ec375e9b7ab..90b11defb2b 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java @@ -243,7 +243,7 @@ private static Class[] getAllTestClasses() { JavaElement8Tests.class, Java9ElementTests.class, - Java21ElementTests.class, + Java25ElementTests.class, NullAnnotationModelTests9.class, diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java21ElementTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java25ElementTests.java similarity index 72% rename from org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java21ElementTests.java rename to org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java25ElementTests.java index 27bdfb0516d..2d9528fdfe8 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java21ElementTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java25ElementTests.java @@ -20,7 +20,7 @@ import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.tests.util.AbstractCompilerTest; -public class Java21ElementTests extends AbstractJavaModelTests { +public class Java25ElementTests extends AbstractJavaModelTests { private IJavaProject project; @@ -34,24 +34,24 @@ private void advanceProjectVersion() { this.project.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_25); this.project.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_25); } - public Java21ElementTests(String name) { + public Java25ElementTests(String name) { super(name); } public static Test suite() { - return buildModelTestSuite(AbstractCompilerTest.F_25, Java21ElementTests.class); + return buildModelTestSuite(AbstractCompilerTest.F_25, Java25ElementTests.class); } @Override protected void setUp() throws Exception { super.setUp(); - this.project = createJavaProject("Java21Elements", new String[] { "src" }, - new String[] { "JCL21_LIB" }, "bin", "25"); + this.project = createJavaProject("Java25Elements", new String[] { "src" }, + new String[] { "JCL_25_LIB" }, "bin", "25"); } @Override protected void tearDown() throws Exception { - deleteProject("Java21Elements"); + deleteProject("Java25Elements"); super.tearDown(); } @@ -63,9 +63,9 @@ public static void main(String[] args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertTrue(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -77,9 +77,9 @@ public static void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertTrue(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -91,9 +91,9 @@ public void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertTrue(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -105,9 +105,9 @@ protected void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertTrue(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -119,9 +119,9 @@ void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertTrue(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -133,9 +133,9 @@ private void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -147,9 +147,9 @@ protected void main(String[] args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertTrue(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -161,9 +161,9 @@ void main(String[] args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertTrue(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -175,9 +175,9 @@ private void main(String[] args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -189,9 +189,9 @@ protected void main(int args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -203,9 +203,9 @@ void main(int args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -217,9 +217,9 @@ private void main(int args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -233,9 +233,9 @@ public static void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } finally { advanceProjectVersion(); @@ -252,9 +252,9 @@ public void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } finally { advanceProjectVersion(); @@ -271,9 +271,9 @@ protected void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } finally { advanceProjectVersion(); @@ -290,9 +290,9 @@ void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } finally { advanceProjectVersion(); @@ -309,9 +309,9 @@ private void main() { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } finally { advanceProjectVersion(); @@ -328,9 +328,9 @@ protected void main(String[] args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } finally { advanceProjectVersion(); @@ -347,9 +347,9 @@ void main(String[] args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } finally { advanceProjectVersion(); @@ -364,9 +364,9 @@ protected void main(java.lang.String[] args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertTrue(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -378,9 +378,9 @@ void main(java.lang.String[] args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertTrue(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -392,9 +392,9 @@ private void main(java.lang.String[] args) { } } """; - createFile("/Java21Elements/src/Test.java", fileContent); + createFile("/Java25Elements/src/Test.java", fileContent); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Test.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Test.java"); assertFalse(unit.getTypes()[0].getMethods()[0].isMainMethodCandidate()); } @@ -404,17 +404,17 @@ public void testIssue2574() throws Exception { this.project.open(null); - createFile("/Java21Elements/src/Top.java", "public sealed interface Top permits Middle {}\n"); - createFile("/Java21Elements/src/Middle.java", "public sealed interface Middle extends Top permits Down {}\n"); - createFile("/Java21Elements/src/Down.java", "public record Down(String foo) implements Middle {}\n"); - createFile("/Java21Elements/src/String.java", "public class String {}\n"); + createFile("/Java25Elements/src/Top.java", "public sealed interface Top permits Middle {}\n"); + createFile("/Java25Elements/src/Middle.java", "public sealed interface Middle extends Top permits Down {}\n"); + createFile("/Java25Elements/src/Down.java", "public record Down(String foo) implements Middle {}\n"); + createFile("/Java25Elements/src/String.java", "public class String {}\n"); - ICompilationUnit unit = getCompilationUnit("/Java21Elements/src/Down.java"); + ICompilationUnit unit = getCompilationUnit("/Java25Elements/src/Down.java"); int start = unit.getWorkingCopy(null).getSource().lastIndexOf("String"); IJavaElement[] elements = unit.codeSelect(start, 6); assertElementsEqual( "Unexpected elements", - "String [in String.java [in [in src [in Java21Elements]]]]", + "String [in String.java [in [in src [in Java25Elements]]]]", elements ); } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeHierarchyTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeHierarchyTests.java index 8cac0ec2480..f9e31792942 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeHierarchyTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeHierarchyTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. + * Copyright (c) 2000, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -22,6 +22,10 @@ import java.nio.file.Paths; import java.util.Arrays; import java.util.HashMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import junit.framework.Test; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; @@ -3734,4 +3738,49 @@ public void testBugGh269() throws Exception { } } +public void testHierarchyOfCircular() throws CoreException { + final String PROJECT_NAME = "CircularDependency"; + try { + createJavaProject(PROJECT_NAME, new String[] { "src" }, + new String[] { "JCL_21_LIB" }, "bin", "21"); + IPackageFragmentRoot sourceFolder = getPackageFragmentRoot(PROJECT_NAME, "src"); + IPackageFragment pack1 = sourceFolder.createPackageFragment("test1", false, null); + ICompilationUnit cuC= pack1.createCompilationUnit("C.java", + """ + package test1; + public class C extends B {} + """, false, null); + pack1.createCompilationUnit("B.java", + """ + package test1; + public class B extends A {} + """, false, null); + pack1.createCompilationUnit("A.java", + """ + package test1; + public class A extends C {} + """, false, null); + + IType type = cuC.getType("C"); + + CompletableFuture hierarchyFuture = CompletableFuture.supplyAsync(() -> { + try { + return type.newSupertypeHierarchy(new NullProgressMonitor()); + } catch (JavaModelException e) { + throw new RuntimeException(e); + } + }); + + try { + // throws if the operation takes more than 5 seconds + hierarchyFuture.get(5, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + fail("Timed out while attempting to build the type hierarchy"); + } + } finally { + deleteProject(PROJECT_NAME); + } + +} + } diff --git a/org.eclipse.jdt.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.core/META-INF/MANIFEST.MF index b1bc5e0261c..d5666c02314 100644 --- a/org.eclipse.jdt.core/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.core/META-INF/MANIFEST.MF @@ -23,7 +23,7 @@ Export-Package: org.eclipse.jdt.core, org.eclipse.jdt.internal.codeassist.select;x-friends:="org.eclipse.jdt.core.tests.model, org.eclipse.jdt.core.tests.compiler, org.eclipse.jdt.core.tests.builder, org.eclipse.jdt.core.tests.performance, org.eclipse.jdt.ui.tests", org.eclipse.jdt.internal.compiler;x-friends:="org.eclipse.jdt.apt.pluggable.core, org.eclipse.jdt.core.tests.model, org.eclipse.jdt.core.tests.compiler, org.eclipse.jdt.core.tests.builder, org.eclipse.jdt.core.tests.performance, org.eclipse.jdt.ui.tests", org.eclipse.jdt.internal.compiler.parser;x-friends:="org.eclipse.jdt.apt.pluggable.core, org.eclipse.jdt.core.tests.model, org.eclipse.jdt.core.tests.compiler, org.eclipse.jdt.core.tests.builder, org.eclipse.jdt.core.tests.performance, org.eclipse.jdt.ui.tests", - org.eclipse.jdt.internal.core;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools,org.eclipse.jdt.launching, org.eclipse.jdt.core.tests.model, org.eclipse.jdt.core.tests.compiler, org.eclipse.jdt.core.tests.builder, org.eclipse.jdt.core.tests.performance, org.eclipse.jdt.ui.tests", + org.eclipse.jdt.internal.core;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools,org.eclipse.jdt.launching,org.eclipse.jdt.junit.core,org.eclipse.jdt.core.tests.model, org.eclipse.jdt.core.tests.compiler, org.eclipse.jdt.core.tests.builder, org.eclipse.jdt.core.tests.performance, org.eclipse.jdt.ui.tests", org.eclipse.jdt.internal.core.builder;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools, org.eclipse.jdt.core.tests.model, org.eclipse.jdt.core.tests.compiler, org.eclipse.jdt.core.tests.builder, org.eclipse.jdt.core.tests.performance, org.eclipse.jdt.ui.tests", org.eclipse.jdt.internal.core.dom;x-friends:="org.eclipse.jdt.core.tests.model, org.eclipse.jdt.core.tests.compiler, org.eclipse.jdt.core.tests.builder, org.eclipse.jdt.core.tests.performance, org.eclipse.jdt.ui.tests", org.eclipse.jdt.internal.core.dom.rewrite;x-friends:="org.eclipse.jdt.core.tests.model, org.eclipse.jdt.core.tests.compiler, org.eclipse.jdt.core.tests.builder, org.eclipse.jdt.core.tests.performance, org.eclipse.jdt.ui.tests", diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java index 8031b76aa39..2020a553a8b 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java @@ -733,53 +733,20 @@ protected boolean parseMarkdownLinks(int previousPosition) throws InvalidInputEx readChar(); } break; + case ')': + if (peekChar() == '\n' || peekChar() == ' ') { + valid = parseMarkdownLinkTags(true, start, previousPosition, tStart, tEnd); + break loop; + } + break; case ']': - if (peekChar() == '[') { + if ((peekChar() == '[' ) || peekChar() == '(') { tStart = start; tEnd = this.index - 1; currentChar = readChar(); start = this.index; - } else { - int eofBkup = this.scanner.eofPosition; - this.scanner.eofPosition = this.index - 1; - this.scanner.resetTo(start, this.javadocEnd); - this.inlineTagStarted = true; - this.inlineTagStart = previousPosition; - this.tagValue = TAG_LINK_VALUE; - int indexBkup = this.index; - valid = parseReference(true); - this.index = indexBkup; - // This creates a two level structure. The @link tag is added to - // another tag element, which gets added to the astStack - // Both tag elements must get the same source range. - TagElement previousTag = (TagElement) this.astStack[this.astPtr]; - int parentStart = previousTag.getStartPosition(); - previousTag.setSourceRange(parentStart, this.index - parentStart); - List fragments = previousTag.fragments(); - int size = fragments.size(); - if (size == 0) { - // no existing fragment => just add the element - TagElement inlineTag = this.ast.newTagElement(); - fragments.add(inlineTag); - previousTag = inlineTag; - } else { - // If last fragment is a tag, then use it as previous tag - ASTNode lastFragment = (ASTNode) fragments.get(size-1); - if (lastFragment.getNodeType() == ASTNode.TAG_ELEMENT) { - lastFragment.setSourceRange(lastFragment.getStartPosition(), this.index - previousPosition); - previousTag = (TagElement) lastFragment; - } - } - if (tEnd != -1) { - TextElement text = this.ast.newTextElement(); - text.setText(new String( this.source, tStart, tEnd-tStart)); - text.setSourceRange(tStart, tEnd-tStart); - previousTag.fragments().add(0, text); - } - this.tagValue = NO_TAG_VALUE; - this.inlineTagStarted = false; - this.inlineTagStart = -1; - this.scanner.eofPosition = eofBkup; + } else if (peekChar() != ']') { + valid = parseMarkdownLinkTags(false, start, previousPosition, tStart, tEnd); break loop; } break; @@ -795,6 +762,54 @@ protected boolean parseMarkdownLinks(int previousPosition) throws InvalidInputEx return valid; } + private boolean parseMarkdownLinkTags(boolean refFlag, int start, int previousPosition, int tStart, int tEnd ) throws InvalidInputException { + boolean valid = false; + int eofBkup = this.scanner.eofPosition; + this.scanner.eofPosition = this.index - 1; + this.scanner.resetTo(start, this.javadocEnd); + this.inlineTagStarted = true; + this.inlineTagStart = previousPosition; + this.tagValue = TAG_LINK_VALUE; + int indexBkup = this.index; + if (refFlag) + valid = parseURLReference(this.scanner.startPosition - 1, false); + else + valid = parseReference(true); + this.index = indexBkup; + // This creates a two level structure. The @link tag is added to + // another tag element, which gets added to the astStack + // Both tag elements must get the same source range. + TagElement previousTag = (TagElement) this.astStack[this.astPtr]; + int parentStart = previousTag.getStartPosition(); + previousTag.setSourceRange(parentStart, this.index - parentStart); + List fragments = previousTag.fragments(); + int size = fragments.size(); + if (size == 0) { + // no existing fragment => just add the element + TagElement inlineTag = this.ast.newTagElement(); + fragments.add(inlineTag); + previousTag = inlineTag; + } else { + // If last fragment is a tag, then use it as previous tag + ASTNode lastFragment = (ASTNode) fragments.get(size-1); + if (lastFragment.getNodeType() == ASTNode.TAG_ELEMENT) { + lastFragment.setSourceRange(lastFragment.getStartPosition(), this.index - previousPosition); + previousTag = (TagElement) lastFragment; + } + } + if (tEnd != -1) { + TextElement text = this.ast.newTextElement(); + text.setText(new String( this.source, tStart, tEnd-tStart)); + text.setSourceRange(tStart, tEnd-tStart); + previousTag.fragments().add(0, text); + } + this.tagValue = NO_TAG_VALUE; + this.inlineTagStarted = false; + this.inlineTagStart = -1; + this.scanner.eofPosition = eofBkup; + return valid; + } + @Override protected boolean parseTag(int previousPosition) throws InvalidInputException { this.markdownHelper.resetLineStart(); diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java index 4a37b96940a..5ab121e3539 100644 --- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java +++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java @@ -178,9 +178,6 @@ public boolean visit(RecordDeclaration node) { List typeParameters = node.typeParameters(); handleTypeParameters(typeParameters); - - handleToken(node.getName(), TokenNameLBRACE, - this.options.insert_space_before_opening_brace_in_record_declaration, false); List superInterfaces = node.superInterfaceTypes(); if (!superInterfaces.isEmpty()) { handleTokenBefore(superInterfaces.get(0), TokenNameimplements, true, true); @@ -188,7 +185,19 @@ public boolean visit(RecordDeclaration node) { this.options.insert_space_after_comma_in_superinterfaces); } - handleRecordComponents(node.recordComponents(), node.getName(), typeParameters); + List components = node.recordComponents(); + handleRecordComponents(components, node.getName(), typeParameters); + + ASTNode lastBeforeBrace = node.getName(); + if (!superInterfaces.isEmpty()) { + lastBeforeBrace = superInterfaces.get(superInterfaces.size() - 1); + } else if (!components.isEmpty()) { + lastBeforeBrace = components.get(components.size() - 1); + } else if (!typeParameters.isEmpty()) { + lastBeforeBrace = typeParameters.get(typeParameters.size() - 1); + } + handleTokenAfter(lastBeforeBrace, TokenNameLBRACE, + this.options.insert_space_before_opening_brace_in_record_declaration, false); return true; }