diff --git a/.github/workflows/create_github_release.yml b/.github/workflows/create_github_release.yml index 7925db0aee..9e89346d55 100644 --- a/.github/workflows/create_github_release.yml +++ b/.github/workflows/create_github_release.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.2 - name: Create Release id: create_release diff --git a/.github/workflows/prepare_release_changelog.yml b/.github/workflows/prepare_release_changelog.yml index 2dd8d1b9a4..f245548d82 100644 --- a/.github/workflows/prepare_release_changelog.yml +++ b/.github/workflows/prepare_release_changelog.yml @@ -17,7 +17,7 @@ jobs: # Check out current repository - name: Fetch Sources - uses: actions/checkout@v4.1.1 + uses: actions/checkout@v4.1.2 # Setup Java 11 environment for the next steps - name: Setup Java diff --git a/changelog.md b/changelog.md index 82df6170f9..d1345544e4 100644 --- a/changelog.md +++ b/changelog.md @@ -1,7 +1,6 @@ - -Next Release (Version 3.25.9-snapshot) +Next Release (Version 3.25.11-snapshot) -------------------------------------- -[issues resolved](https://github.com/javaparser/javaparser/milestone/205?closed=1) +[issues resolved](https://github.com/javaparser/javaparser/milestone/207?closed=1) ### Added ### Changed @@ -10,6 +9,98 @@ Next Release (Version 3.25.9-snapshot) ### Fixed ### Security +Version 3.25.10 +--------------- +[issues resolved](https://github.com/javaparser/javaparser/milestone/206?closed=1) + +### Fixed + +* Fix issue 4345 Strange error when trying to find erasure of generic t… ( + PR [#4362](https://github.com/javaparser/javaparser/pull/4362) by [@jlerbsc](https://github.com/jlerbsc)) +* fix: issue 4358 prevent infinite cycles with static imports ( + PR [#4359](https://github.com/javaparser/javaparser/pull/4359) by [@kdunee](https://github.com/kdunee)) +* Refactor `ResolvedReferenceType#equals` (PR [#4351](https://github.com/javaparser/javaparser/pull/4351) + by [@freya022](https://github.com/freya022)) +* fix: issue 4331 Cannot be 'abstract' and also 'private'. for a private method in an interface ( + PR [#4332](https://github.com/javaparser/javaparser/pull/4332) by [@jlerbsc](https://github.com/jlerbsc)) + +### Developer Changes + +* chore(deps): bump actions/checkout from 4.1.1 to 4.1.2 (PR [#4341](https://github.com/javaparser/javaparser/pull/4341) + by [@dependabot[bot]](https://github.com/apps/dependabot)) + +### :heart: Contributors + +Thank You to all contributors who worked on this release! + +* [@kdunee](https://github.com/kdunee) +* [@freya022](https://github.com/freya022) +* [@jlerbsc](https://github.com/jlerbsc) + +Version 3.25.9 +-------------- +[issues resolved](https://github.com/javaparser/javaparser/milestone/205?closed=1) + +### Added + +* Fix: issue #3878 resolve MethodReference in ObjectCreationExpr ( + PR [#4296](https://github.com/javaparser/javaparser/pull/4296) by [@fishautumn](https://github.com/fishautumn)) + +### Changed + +* Switch order of literals to prevent NullPointerException ( + PR [#4322](https://github.com/javaparser/javaparser/pull/4322) by [@citizenjosh](https://github.com/citizenjosh)) +* Minor refactoring to use the existing getArgumentPosition method ( + PR [#4306](https://github.com/javaparser/javaparser/pull/4306) by [@jlerbsc](https://github.com/jlerbsc)) +* Optimize find ancestor (PR [#4294](https://github.com/javaparser/javaparser/pull/4294) + by [@magicwerk](https://github.com/magicwerk)) +* refac: Removes useless ExpressionHelper utility class and replaces some explicit casts by using the javaparser API ( + PR [#4291](https://github.com/javaparser/javaparser/pull/4291) by [@jlerbsc](https://github.com/jlerbsc)) + +### Fixed + +* fix: Dead stores should be removed (sonar rule) (PR [#4329](https://github.com/javaparser/javaparser/pull/4329) + by [@jlerbsc](https://github.com/jlerbsc)) +* fix: Replace this if-then-else statement by a single return statement (sonar rule) ( + PR [#4328](https://github.com/javaparser/javaparser/pull/4328) by [@jlerbsc](https://github.com/jlerbsc)) +* fix: issue 2043 getAccessSpecifier should return public for interface methods ( + PR [#4317](https://github.com/javaparser/javaparser/pull/4317) by [@jlerbsc](https://github.com/jlerbsc)) +* Further improve correction of whitespace during difference application ( + PR [#4316](https://github.com/javaparser/javaparser/pull/4316) by [@jlerbsc](https://github.com/jlerbsc)) +* Fix: issue #3946 Symbol solver is unable to resolve inherited inner classes ( + PR [#4314](https://github.com/javaparser/javaparser/pull/4314) by [@jlerbsc](https://github.com/jlerbsc)) +* fix: issue 4311 IllegalStateException when removing all comments with LexicalPreservingPrinter ( + PR [#4313](https://github.com/javaparser/javaparser/pull/4313) by [@jlerbsc](https://github.com/jlerbsc)) +* Fix: issue 3939 SymbolResolver.calculateType(Expression) may fails on first try, then succeed on later tries ( + PR [#4290](https://github.com/javaparser/javaparser/pull/4290) by [@jlerbsc](https://github.com/jlerbsc)) +* Adds unit test for issue 4284 "ClassCastException when resolving MethodCallExpr inside an enhanced switch statement" ( + PR [#4285](https://github.com/javaparser/javaparser/pull/4285) by [@jlerbsc](https://github.com/jlerbsc)) +* Change `SwitchStmt` to `SwitchNode` in `SwitchEntryContext` to avoid `ClassCastException` ( + PR [#4283](https://github.com/javaparser/javaparser/pull/4283) + by [@PalashSharma20](https://github.com/PalashSharma20)) + +### Developer Changes + +* chore(deps): bump org.codehaus.mojo:exec-maven-plugin from 3.1.1 to 3.2.0 ( + PR [#4323](https://github.com/javaparser/javaparser/pull/4323) + by [@dependabot[bot]](https://github.com/apps/dependabot)) +* chore(deps): update junit5 monorepo to v5.10.2 (PR [#4307](https://github.com/javaparser/javaparser/pull/4307) + by [@renovate[bot]](https://github.com/apps/renovate)) +* chore(deps): update codecov/codecov-action action to v4 ( + PR [#4304](https://github.com/javaparser/javaparser/pull/4304) by [@renovate[bot]](https://github.com/apps/renovate)) +* chore(deps): update actions/cache action to v4 (PR [#4293](https://github.com/javaparser/javaparser/pull/4293) + by [@renovate[bot]](https://github.com/apps/renovate)) + +### :heart: Contributors + +Thank You to all contributors who worked on this release! + +* [@citizenjosh](https://github.com/citizenjosh) +* [@magicwerk](https://github.com/magicwerk) +* [@PalashSharma20](https://github.com/PalashSharma20) +* [@jlerbsc](https://github.com/jlerbsc) +* [@fishautumn](https://github.com/fishautumn) + Version 3.25.8 -------------- [issues resolved](https://github.com/javaparser/javaparser/milestone/204?closed=1) diff --git a/javaparser-core-generators/pom.xml b/javaparser-core-generators/pom.xml index 0eb000901c..2d280afdcd 100644 --- a/javaparser-core-generators/pom.xml +++ b/javaparser-core-generators/pom.xml @@ -4,7 +4,7 @@ jmlparser-parent io.github.jmltoolkit - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT 4.0.0 diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/VisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/VisitorGenerator.java index 20c3d469af..43efbffb03 100644 --- a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/VisitorGenerator.java +++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/VisitorGenerator.java @@ -79,7 +79,7 @@ protected void after() throws Exception { private void generateVisitMethodForNode(BaseNodeMetaModel node, ClassOrInterfaceDeclaration visitorClass, CompilationUnit compilationUnit) { final Optional existingVisitMethod = visitorClass.getMethods().stream() - .filter(m -> m.getNameAsString().equals("visit")) + .filter(m -> "visit".equals(m.getNameAsString())) .filter(m -> m.getParameter(0).getType().toString().equals(node.getTypeName())) .findFirst(); diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/TokenKindGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/TokenKindGenerator.java index 9de626391e..85da0084d6 100644 --- a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/TokenKindGenerator.java +++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/other/TokenKindGenerator.java @@ -53,7 +53,7 @@ public void generate() { final CompilationUnit javaTokenCu = sourceRoot.parse("com.github.javaparser", "JavaToken.java"); final ClassOrInterfaceDeclaration javaToken = javaTokenCu.getClassByName("JavaToken").orElseThrow(() -> new AssertionError("Can't find class in java file.")); - final EnumDeclaration kindEnum = javaToken.findFirst(EnumDeclaration.class, e -> e.getNameAsString().equals("Kind")).orElseThrow(() -> new AssertionError("Can't find class in java file.")); + final EnumDeclaration kindEnum = javaToken.findFirst(EnumDeclaration.class, e -> "Kind".equals(e.getNameAsString())).orElseThrow(() -> new AssertionError("Can't find class in java file.")); kindEnum.getEntries().clear(); annotateGenerated(kindEnum); diff --git a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/CloneVisitorGenerator.java b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/CloneVisitorGenerator.java index 2551b4623b..e4654ba844 100644 --- a/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/CloneVisitorGenerator.java +++ b/javaparser-core-generators/src/main/java/com/github/javaparser/generator/core/visitor/CloneVisitorGenerator.java @@ -64,7 +64,7 @@ protected void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration SeparatedItemStringBuilder builder = new SeparatedItemStringBuilder(f("%s r = new %s(", node.getTypeNameGenerified(), node.getTypeNameGenerified()), ",", ");"); builder.append("n.getTokenRange().orElse(null)"); for (PropertyMetaModel field : node.getConstructorParameters()) { - if (field.getName().equals("comment")) { + if ("comment".equals(field.getName())) { continue; } if (field.getNodeReference().isPresent()) { diff --git a/javaparser-core-metamodel-generator/pom.xml b/javaparser-core-metamodel-generator/pom.xml index ef7bad1dd5..f773a55596 100644 --- a/javaparser-core-metamodel-generator/pom.xml +++ b/javaparser-core-metamodel-generator/pom.xml @@ -4,7 +4,7 @@ jmlparser-parent io.github.jmltoolkit - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT 4.0.0 diff --git a/javaparser-core-serialization/pom.xml b/javaparser-core-serialization/pom.xml index 0ef06f80e8..9ea446e4dd 100644 --- a/javaparser-core-serialization/pom.xml +++ b/javaparser-core-serialization/pom.xml @@ -3,7 +3,7 @@ jmlparser-parent io.github.jmltoolkit - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT 4.0.0 diff --git a/javaparser-core-testing-bdd/pom.xml b/javaparser-core-testing-bdd/pom.xml index 7ebacafe64..6f0b8e8e04 100644 --- a/javaparser-core-testing-bdd/pom.xml +++ b/javaparser-core-testing-bdd/pom.xml @@ -3,7 +3,7 @@ jmlparser-parent io.github.jmltoolkit - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT 4.0.0 diff --git a/javaparser-core-testing/pom.xml b/javaparser-core-testing/pom.xml index d224b1dd7a..b4d57eac35 100644 --- a/javaparser-core-testing/pom.xml +++ b/javaparser-core-testing/pom.xml @@ -3,7 +3,7 @@ jmlparser-parent io.github.jmltoolkit - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT 4.0.0 @@ -128,7 +128,7 @@ org.assertj assertj-core - 3.25.0 + 3.25.3 test diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/ast/body/MethodDeclarationTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/ast/body/MethodDeclarationTest.java index a981fe9cb7..e773bc77b3 100644 --- a/javaparser-core-testing/src/test/java/com/github/javaparser/ast/body/MethodDeclarationTest.java +++ b/javaparser-core-testing/src/test/java/com/github/javaparser/ast/body/MethodDeclarationTest.java @@ -21,10 +21,16 @@ package com.github.javaparser.ast.body; +import static com.github.javaparser.StaticJavaParser.parse; +import static com.github.javaparser.StaticJavaParser.parseBodyDeclaration; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import org.junit.jupiter.api.Test; -import static com.github.javaparser.StaticJavaParser.parseBodyDeclaration; -import static org.junit.jupiter.api.Assertions.*; +import com.github.javaparser.ast.CompilationUnit; class MethodDeclarationTest { @Test @@ -118,4 +124,39 @@ void isFixedArityMethod() { MethodDeclaration method2 = parseBodyDeclaration("int x();").asMethodDeclaration(); assertTrue(method2.isFixedArityMethod()); } + + /* + * A method in the body of an interface may be declared public or private + * (§6.6). If no access modifier is given, the method is implicitly public. + * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.4 + */ + @Test + void isMethodInterfaceImplictlyPublic() { + CompilationUnit cu = parse("interface Foo { void m(); }"); + assertTrue(cu.findFirst(MethodDeclaration.class).get().isPublic()); + cu = parse("interface Foo { public void m(); }"); + assertTrue(cu.findFirst(MethodDeclaration.class).get().isPublic()); + cu = parse("interface Foo { abstract void m(); }"); + assertTrue(cu.findFirst(MethodDeclaration.class).get().isPublic()); + cu = parse("interface Foo { private void m(); }"); + assertFalse(cu.findFirst(MethodDeclaration.class).get().isPublic()); + } + + /* + * An interface method lacking a private, default, or static modifier is implicitly abstract. + * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.4 + */ + @Test + void isMethodInterfaceImplictlyAbstract() { + CompilationUnit cu = parse("interface Foo { void m(); }"); + assertTrue(cu.findFirst(MethodDeclaration.class).get().isAbstract()); + cu = parse("interface Foo { abstract void m(); }"); + assertTrue(cu.findFirst(MethodDeclaration.class).get().isAbstract()); + cu = parse("interface Foo { private void m(); }"); + assertFalse(cu.findFirst(MethodDeclaration.class).get().isAbstract()); + cu = parse("interface Foo { static void m(); }"); + assertFalse(cu.findFirst(MethodDeclaration.class).get().isAbstract()); + cu = parse("interface Foo { default void m(){} }"); + assertFalse(cu.findFirst(MethodDeclaration.class).get().isAbstract()); + } } diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/LexicalPreservingPrinterTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/LexicalPreservingPrinterTest.java index 25a56549d3..2d19df05aa 100644 --- a/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/LexicalPreservingPrinterTest.java +++ b/javaparser-core-testing/src/test/java/com/github/javaparser/printer/lexicalpreservation/LexicalPreservingPrinterTest.java @@ -26,7 +26,10 @@ import static com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter.NODE_TEXT_DATA; import static com.github.javaparser.utils.TestUtils.assertEqualsStringIgnoringEol; import static com.github.javaparser.utils.Utils.SYSTEM_EOL; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.util.Arrays; @@ -1702,6 +1705,24 @@ void removedIndentationLineCommentsPrinted() { assertEqualsStringIgnoringEol(expected, LexicalPreservingPrinter.print(cu)); } + // issue 4311 IllegalStateException when removing all comments with LexicalPreservingPrinter + @Test + void removedLineCommentsWithSameContent() { + considerCode("public class Foo {\n" + + " //line 1 \n" + + " //line 1 \n" + + " void mymethod() {\n" + + " }\n" + + "}"); + String expected = + "public class Foo {\n" + + " void mymethod() {\n" + + " }\n" + + "}"; + cu.getAllContainedComments().stream().forEach(c -> c.remove()); + assertEqualsStringIgnoringEol(expected, LexicalPreservingPrinter.print(cu)); + } + // issue 3216 LexicalPreservingPrinter add Wrong indentation when removing comments @Test void removedIndentationBlockCommentsPrinted() { diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/remove/NodeRemovalTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/remove/NodeRemovalTest.java index 5358a59a07..8d1db3f695 100644 --- a/javaparser-core-testing/src/test/java/com/github/javaparser/remove/NodeRemovalTest.java +++ b/javaparser-core-testing/src/test/java/com/github/javaparser/remove/NodeRemovalTest.java @@ -21,6 +21,14 @@ package com.github.javaparser.remove; +import static com.github.javaparser.utils.TestUtils.assertEqualsStringIgnoringEol; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import org.junit.jupiter.api.Test; + import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; @@ -29,69 +37,88 @@ import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.printer.lexicalpreservation.AbstractLexicalPreservingTest; -import org.junit.jupiter.api.Test; +import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter; -import java.util.List; +class NodeRemovalTest extends AbstractLexicalPreservingTest { -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; + private final CompilationUnit compilationUnit = new CompilationUnit(); -class NodeRemovalTest extends AbstractLexicalPreservingTest { + @Test + void testRemoveClassFromCompilationUnit() { + ClassOrInterfaceDeclaration testClass = compilationUnit.addClass("test"); + assertEquals(1, compilationUnit.getTypes().size()); + boolean remove = testClass.remove(); + assertTrue(remove); + assertEquals(0, compilationUnit.getTypes().size()); + } + + @Test + void testRemoveFieldFromClass() { + ClassOrInterfaceDeclaration testClass = compilationUnit.addClass("test"); + + FieldDeclaration addField = testClass.addField(String.class, "test"); + assertEquals(1, testClass.getMembers().size()); + boolean remove = addField.remove(); + assertTrue(remove); + assertEquals(0, testClass.getMembers().size()); + } + + @Test + void testRemoveStatementFromMethodBody() { + ClassOrInterfaceDeclaration testClass = compilationUnit.addClass("testC"); + + MethodDeclaration addMethod = testClass.addMethod("testM"); + BlockStmt methodBody = addMethod.createBody(); + Statement addStatement = methodBody.addAndGetStatement("test"); + assertEquals(1, methodBody.getStatements().size()); + boolean remove = addStatement.remove(); + assertTrue(remove); + assertEquals(0, methodBody.getStatements().size()); + } + + @Test + void testRemoveStatementFromMethodBodyWithLexicalPreservingPrinter() { + considerStatement( + "{\r\n" + + " log.error(\"context\", e);\r\n" + + " log.error(\"context\", e);\r\n" + + " throw new ApplicationException(e);\r\n" + + "}\r\n"); + BlockStmt bstmt = statement.asBlockStmt(); + List children = bstmt.getChildNodes(); + remove(children.get(0)); + assertTrue(children.size() == 2); + remove(children.get(0)); + assertTrue(children.size() == 1); + assertTrue(children.stream().allMatch(n -> n.getParentNode() != null)); + } + + @Test + // issue 1638 + public void removingAnnotationsFormattedWithAdditionalSpaces() { + considerCode( + "class X {\n" + + " @Override\n" + + " public void testCase() {\n" + + " }\n" + + "}" + ); + + cu.getType(0).getMethods().get(0).getAnnotationByName("Override").get().remove(); + + String result = LexicalPreservingPrinter.print(cu.findCompilationUnit().get()); + assertEqualsStringIgnoringEol( + "class X {\n" + + " public void testCase() {\n" + + " }\n" + + "}", result); + } - private final CompilationUnit compilationUnit = new CompilationUnit(); - - @Test - void testRemoveClassFromCompilationUnit() { - ClassOrInterfaceDeclaration testClass = compilationUnit.addClass("test"); - assertEquals(1, compilationUnit.getTypes().size()); - boolean remove = testClass.remove(); - assertTrue(remove); - assertEquals(0, compilationUnit.getTypes().size()); - } - - @Test - void testRemoveFieldFromClass() { - ClassOrInterfaceDeclaration testClass = compilationUnit.addClass("test"); - - FieldDeclaration addField = testClass.addField(String.class, "test"); - assertEquals(1, testClass.getMembers().size()); - boolean remove = addField.remove(); - assertTrue(remove); - assertEquals(0, testClass.getMembers().size()); - } - - @Test - void testRemoveStatementFromMethodBody() { - ClassOrInterfaceDeclaration testClass = compilationUnit.addClass("testC"); - - MethodDeclaration addMethod = testClass.addMethod("testM"); - BlockStmt methodBody = addMethod.createBody(); - Statement addStatement = methodBody.addAndGetStatement("test"); - assertEquals(1, methodBody.getStatements().size()); - boolean remove = addStatement.remove(); - assertTrue(remove); - assertEquals(0, methodBody.getStatements().size()); - } - - @Test - void testRemoveStatementFromMethodBodyWithLexicalPreservingPrinter() { - considerStatement("{\r\n" + " log.error(\"context\", e);\r\n" + - " log.error(\"context\", e);\r\n" + - " throw new ApplicationException(e);\r\n" + "}\r\n"); - BlockStmt bstmt = statement.asBlockStmt(); - List children = bstmt.getChildNodes(); - remove(children.get(0)); - assertTrue(children.size() == 2); - remove(children.get(0)); - assertTrue(children.size() == 1); - assertTrue(children.stream().allMatch(n -> n.getParentNode() != null)); - } - - // remove the node and parent's node until response is true - boolean remove(Node node) { - boolean result = node.remove(); - if (!result && node.getParentNode().isPresent()) - result = remove(node.getParentNode().get()); - return result; - } + // remove the node and parent's node until response is true + boolean remove(Node node) { + boolean result = node.remove(); + if (!result && node.getParentNode().isPresent()) + result = remove(node.getParentNode().get()); + return result; + } } diff --git a/javaparser-core-testing/src/test/java/com/github/javaparser/utils/UtilsTest.java b/javaparser-core-testing/src/test/java/com/github/javaparser/utils/UtilsTest.java index 8f92ec2c37..250750661f 100644 --- a/javaparser-core-testing/src/test/java/com/github/javaparser/utils/UtilsTest.java +++ b/javaparser-core-testing/src/test/java/com/github/javaparser/utils/UtilsTest.java @@ -21,7 +21,11 @@ package com.github.javaparser.utils; -import org.junit.jupiter.api.Test; +import static com.github.javaparser.utils.Utils.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.io.Reader; @@ -30,9 +34,7 @@ import java.util.HashSet; import java.util.Optional; -import static com.github.javaparser.utils.Utils.assertNotNull; -import static com.github.javaparser.utils.Utils.*; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class UtilsTest { @@ -182,8 +184,11 @@ void testValueIsNullOrEmptyStringOrOptional() { Optional.empty())); assertFalse(valueIsNullOrEmptyStringOrOptional("foo")); + assertFalse(valueIsNullOrEmptyStringOrOptional("")); assertFalse(valueIsNullOrEmptyStringOrOptional( Optional.ofNullable("foo"))); + assertFalse(valueIsNullOrEmptyStringOrOptional( + Optional.ofNullable(""))); } @Test diff --git a/javaparser-core/pom.xml b/javaparser-core/pom.xml index 4cef6d311e..49fece578c 100644 --- a/javaparser-core/pom.xml +++ b/javaparser-core/pom.xml @@ -3,7 +3,7 @@ jmlparser-parent io.github.jmltoolkit - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT 4.0.0 diff --git a/javaparser-core/src/main/java/com/github/javaparser/HasParentNode.java b/javaparser-core/src/main/java/com/github/javaparser/HasParentNode.java index 90f348cd0a..8b5b07450a 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/HasParentNode.java +++ b/javaparser-core/src/main/java/com/github/javaparser/HasParentNode.java @@ -20,12 +20,12 @@ */ package com.github.javaparser; -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.observer.Observable; -import java.util.Arrays; import java.util.Optional; import java.util.function.Predicate; +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.observer.Observable; + /** * An object that can have a parent node. */ @@ -72,8 +72,8 @@ default Optional findAncestor(Class... types) { * Walks the parents of this node and returns the first node of type {@code type} that matches {@code predicate}, or * {@code empty()} if none is found. The given type may also be an interface type, such as one of the * {@code NodeWith...} interface types. - * - * @deprecated This method is no longer acceptable to find ancestor. + * @deprecated + * This method is no longer acceptable to find ancestor. *

Use {@link findAncestor(Predicate, Class)} instead. */ @Deprecated @@ -85,16 +85,16 @@ default Optional findAncestor(Class type, Predicate predicate) { * Walks the parents of this node and returns the first node that matches one of types {@code types}, or * {@code empty()} if none is found. The given type may also be an interface type, such as one of the * {@code NodeWith...} interface types. - * * @param */ default Optional findAncestor(Predicate predicate, Class... types) { if (!hasParentNode()) return Optional.empty(); Node parent = getParentNode().get(); - Optional> oType = Arrays.stream(types).filter(type -> type.isAssignableFrom(parent.getClass()) && predicate.test(type.cast(parent))).findFirst(); - if (oType.isPresent()) { - return Optional.of(oType.get().cast(parent)); + for (Class type : types) { + if (type.isAssignableFrom(parent.getClass()) && predicate.test(type.cast(parent))) { + return Optional.of(type.cast(parent)); + } } return parent.findAncestor(predicate, types); } diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java b/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java index 62cf54ba94..2b6acaa2c4 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java +++ b/javaparser-core/src/main/java/com/github/javaparser/ast/Node.java @@ -539,6 +539,22 @@ public M getData(final DataKey key) { return value; } + /** + * Gets data for this node using the given key or returns an {@code Optional.empty()}. + * + * @param The type of the data. + * @param key The key for the data + * @return The data. + * @see DataKey + */ + @SuppressWarnings("unchecked") + public Optional findData(final DataKey key) { + if (containsData(key)) { + return Optional.of(getData(key)); + } + return Optional.empty(); + } + /** * This method was added to support the clone method. * diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/body/MethodDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/ast/body/MethodDeclaration.java index 2e0962fb41..1ac76db62a 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/ast/body/MethodDeclaration.java +++ b/javaparser-core/src/main/java/com/github/javaparser/ast/body/MethodDeclaration.java @@ -20,11 +20,9 @@ */ package com.github.javaparser.ast.body; -import static com.github.javaparser.utils.Utils.assertNotNull; -import java.util.Optional; -import java.util.function.Consumer; import com.github.javaparser.TokenRange; import com.github.javaparser.ast.*; +import com.github.javaparser.ast.Modifier.Keyword; import com.github.javaparser.ast.expr.AnnotationExpr; import com.github.javaparser.ast.expr.SimpleName; import com.github.javaparser.ast.jml.clauses.JmlContract; @@ -45,6 +43,13 @@ import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import java.util.Arrays; +import java.util.Optional; +import java.util.function.Consumer; + +import static com.github.javaparser.ast.Modifier.DefaultKeyword.*; +import static com.github.javaparser.utils.Utils.assertNotNull; + /** * A method declaration. "public int abc() {return 1;}" in this example: {@code class X { public int abc() {return 1;} * }} @@ -250,6 +255,40 @@ public String toDescriptor() { return sb.toString(); } + /* + * A method in the body of an interface may be declared public or private + * (§6.6). If no access modifier is given, the method is implicitly public. + * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.4 + */ + @Override + public boolean isPublic() { + return hasModifier(PUBLIC) || isImplicitlyPublic(); + } + + private boolean isImplicitlyPublic() { + return getAccessSpecifier() == AccessSpecifier.NONE + && hasParentNode() + && getParentNode().get() instanceof ClassOrInterfaceDeclaration + && ((ClassOrInterfaceDeclaration) getParentNode().get()).isInterface(); + } + + /* + * An interface method lacking a private, default, or static modifier is implicitly abstract. + * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.4 + */ + @Override + public boolean isAbstract() { + return super.isAbstract() || isImplicitlyAbstract(); + } + + private boolean isImplicitlyAbstract() { + return hasParentNode() && getParentNode().get() instanceof ClassOrInterfaceDeclaration + && ((ClassOrInterfaceDeclaration) getParentNode().get()).isInterface() + && Arrays.asList(STATIC, DEFAULT, PRIVATE).stream() + .noneMatch(modifier -> hasModifier(modifier)); + } + + public boolean isNative() { return hasModifier(Modifier.DefaultKeyword.NATIVE); } @@ -259,7 +298,7 @@ public boolean isSynchronized() { } public boolean isDefault() { - return hasModifier(Modifier.DefaultKeyword.DEFAULT); + return hasModifier(DEFAULT); } public MethodDeclaration setNative(boolean set) { @@ -271,7 +310,7 @@ public MethodDeclaration setSynchronized(boolean set) { } public MethodDeclaration setDefault(boolean set) { - return setModifier(Modifier.DefaultKeyword.DEFAULT, set); + return setModifier(DEFAULT, set); } @Override diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/expr/LambdaExpr.java b/javaparser-core/src/main/java/com/github/javaparser/ast/expr/LambdaExpr.java index 5cef6df01d..2f83755c74 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/ast/expr/LambdaExpr.java +++ b/javaparser-core/src/main/java/com/github/javaparser/ast/expr/LambdaExpr.java @@ -20,6 +20,11 @@ */ package com.github.javaparser.ast.expr; +import static com.github.javaparser.utils.Utils.assertNotNull; + +import java.util.Optional; +import java.util.function.Consumer; + import com.github.javaparser.TokenRange; import com.github.javaparser.ast.AllFieldsConstructor; import com.github.javaparser.ast.Generated; @@ -38,9 +43,6 @@ import com.github.javaparser.metamodel.DerivedProperty; import com.github.javaparser.metamodel.JavaParserMetaModel; import com.github.javaparser.metamodel.LambdaExprMetaModel; -import java.util.Optional; -import java.util.function.Consumer; -import static com.github.javaparser.utils.Utils.assertNotNull; /** *

A lambda expression

@@ -115,11 +117,13 @@ public LambdaExpr(TokenRange tokenRange, NodeList parameters, Stateme customInitialization(); } + @Override @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") public NodeList getParameters() { return parameters; } + @Override @Generated("com.github.javaparser.generator.core.node.PropertyGenerator") public LambdaExpr setParameters(final NodeList parameters) { assertNotNull(parameters); @@ -272,4 +276,11 @@ public Optional toLambdaExpr() { public boolean isPolyExpression() { return true; } + + /* + * Returns true if no type parameter has been defined + */ + public boolean isExplicitlyTyped() { + return getParameters().stream().allMatch(p -> !(p.getType().isUnknownType())); + } } diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/RecordAsTypeIdentifierNotAllowed.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/RecordAsTypeIdentifierNotAllowed.java index 5a7f0b5272..4fe7bd7736 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/RecordAsTypeIdentifierNotAllowed.java +++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/RecordAsTypeIdentifierNotAllowed.java @@ -39,7 +39,7 @@ public RecordAsTypeIdentifierNotAllowed() { @Override public void visit(Name n, ProblemReporter arg) { - if (n.getIdentifier().equals("record") && !validUsage(n)) { + if ("record".equals(n.getIdentifier()) && !validUsage(n)) { arg.report(n, error); } super.visit(n, arg); @@ -47,7 +47,7 @@ public void visit(Name n, ProblemReporter arg) { @Override public void visit(SimpleName n, ProblemReporter arg) { - if (n.getIdentifier().equals("record") && !validUsage(n)) { + if ("record".equals(n.getIdentifier()) && !validUsage(n)) { arg.report(n, error); } super.visit(n, arg); diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/language_level_validations/chunks/UnderscoreKeywordValidator.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/language_level_validations/chunks/UnderscoreKeywordValidator.java index 873eba395f..6613ef83aa 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/language_level_validations/chunks/UnderscoreKeywordValidator.java +++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/language_level_validations/chunks/UnderscoreKeywordValidator.java @@ -41,7 +41,7 @@ public void visit(SimpleName n, ProblemReporter arg) { } private static void validateIdentifier(Node n, String id, ProblemReporter arg) { - if (id.equals("_")) { + if ("_".equals(id)) { arg.report(n, "'_' is a reserved keyword."); } } diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/postprocessors/Java10PostProcessor.java b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/postprocessors/Java10PostProcessor.java index 7baee89145..c33a109eae 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/ast/validator/postprocessors/Java10PostProcessor.java +++ b/javaparser-core/src/main/java/com/github/javaparser/ast/validator/postprocessors/Java10PostProcessor.java @@ -27,6 +27,7 @@ import com.github.javaparser.ast.expr.ClassExpr; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.VarType; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -39,7 +40,6 @@ public class Java10PostProcessor extends PostProcessors { // List of parent contexts in which a var type must not be detected. // for example: in this statement var.class.getCanonicalName(), var must not be considered as a VarType private static List FORBIDEN_PARENT_CONTEXT_TO_DETECT_POTENTIAL_VAR_TYPE = new ArrayList<>(); - static { FORBIDEN_PARENT_CONTEXT_TO_DETECT_POTENTIAL_VAR_TYPE.addAll(Arrays.asList(ClassExpr.class)); } @@ -49,19 +49,23 @@ public class Java10PostProcessor extends PostProcessors { @Override public void postProcess(ParseResult result, ParserConfiguration configuration) { result.getResult().ifPresent(node -> { - node.findAll(ClassOrInterfaceType.class).forEach(n -> { - if (n.getNameAsString().equals("var") && !matchForbiddenContext(n)) { - n.replace(new VarType(n.getTokenRange().orElse(null))); - } + node.findAll(ClassOrInterfaceType.class) + .forEach(n -> { + if ("var".equals(n.getNameAsString()) + && !matchForbiddenContext(n)) { + n.replace(new VarType(n.getTokenRange().orElse(null))); + } }); }); } private boolean matchForbiddenContext(ClassOrInterfaceType cit) { - return cit.getParentNode().isPresent() && FORBIDEN_PARENT_CONTEXT_TO_DETECT_POTENTIAL_VAR_TYPE.stream().anyMatch(cl -> cl.isInstance(cit.getParentNode().get())); + return cit.getParentNode().isPresent() + && FORBIDEN_PARENT_CONTEXT_TO_DETECT_POTENTIAL_VAR_TYPE.stream().anyMatch(cl -> cl.isInstance(cit.getParentNode().get())); } }; + public Java10PostProcessor() { add(varNodeCreator); } diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/visitor/CloneVisitor.java b/javaparser-core/src/main/java/com/github/javaparser/ast/visitor/CloneVisitor.java index 3512de80b9..05fdb31c50 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/ast/visitor/CloneVisitor.java +++ b/javaparser-core/src/main/java/com/github/javaparser/ast/visitor/CloneVisitor.java @@ -20,6 +20,8 @@ */ package com.github.javaparser.ast.visitor; +import java.util.Optional; + import com.github.javaparser.ast.*; import com.github.javaparser.ast.body.*; import com.github.javaparser.ast.comments.BlockComment; @@ -39,8 +41,6 @@ import com.github.javaparser.ast.modules.*; import com.github.javaparser.ast.stmt.*; import com.github.javaparser.ast.type.*; -import java.util.Optional; - /** * A visitor that clones (copies) a node and all its children. */ @@ -268,7 +268,6 @@ public Visitable visit(final Parameter n, final Object arg) { @Override public Visitable visit(final InitializerDeclaration n, final Object arg) { BlockStmt body = cloneNode(n.getBody(), arg); - NodeList annotations = cloneList(n.getAnnotations(), arg); Comment comment = cloneNode(n.getComment(), arg); InitializerDeclaration r = new InitializerDeclaration(n.getTokenRange().orElse(null), n.isStatic(), body); r.setComment(comment); @@ -339,7 +338,6 @@ public Visitable visit(final ArrayCreationLevel n, final Object arg) { @Override public Visitable visit(final IntersectionType n, final Object arg) { NodeList elements = cloneList(n.getElements(), arg); - NodeList annotations = cloneList(n.getAnnotations(), arg); Comment comment = cloneNode(n.getComment(), arg); IntersectionType r = new IntersectionType(n.getTokenRange().orElse(null), elements); r.setComment(comment); @@ -351,7 +349,6 @@ public Visitable visit(final IntersectionType n, final Object arg) { @Override public Visitable visit(final UnionType n, final Object arg) { NodeList elements = cloneList(n.getElements(), arg); - NodeList annotations = cloneList(n.getAnnotations(), arg); Comment comment = cloneNode(n.getComment(), arg); UnionType r = new UnionType(n.getTokenRange().orElse(null), elements); r.setComment(comment); @@ -362,7 +359,6 @@ public Visitable visit(final UnionType n, final Object arg) { @Override public Visitable visit(final VoidType n, final Object arg) { - NodeList annotations = cloneList(n.getAnnotations(), arg); Comment comment = cloneNode(n.getComment(), arg); VoidType r = new VoidType(n.getTokenRange().orElse(null)); r.setComment(comment); @@ -386,7 +382,6 @@ public Visitable visit(final WildcardType n, final Object arg) { @Override public Visitable visit(final UnknownType n, final Object arg) { - NodeList annotations = cloneList(n.getAnnotations(), arg); Comment comment = cloneNode(n.getComment(), arg); UnknownType r = new UnknownType(n.getTokenRange().orElse(null)); r.setComment(comment); @@ -1204,7 +1199,6 @@ public Visitable visit(final ReceiverParameter n, final Object arg) { @Override public Visitable visit(final VarType n, final Object arg) { - NodeList annotations = cloneList(n.getAnnotations(), arg); Comment comment = cloneNode(n.getComment(), arg); VarType r = new VarType(n.getTokenRange().orElse(null)); r.setComment(comment); diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/Difference.java b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/Difference.java index d0198bc45f..bdb92b5fb5 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/Difference.java +++ b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/Difference.java @@ -20,10 +20,14 @@ */ package com.github.javaparser.printer.lexicalpreservation; -import static com.github.javaparser.GeneratedJavaParserConstants.*; +import static com.github.javaparser.GeneratedJavaParserConstants.LBRACE; +import static com.github.javaparser.GeneratedJavaParserConstants.RBRACE; +import static com.github.javaparser.GeneratedJavaParserConstants.SPACE; + import java.util.*; import java.util.function.Predicate; import java.util.stream.IntStream; + import com.github.javaparser.GeneratedJavaParserConstants; import com.github.javaparser.JavaToken; import com.github.javaparser.JavaToken.Kind; @@ -43,7 +47,7 @@ /** * A Difference should give me a sequence of elements I should find (to indicate the context) followed by a list of elements * to remove or to add and follow by another sequence of elements. - *

+ * * I should later be able to apply such difference to a nodeText. */ public class Difference { @@ -107,8 +111,13 @@ List takeWhile(List prevElements, Predicate source) { - return IntStream.range(0, source.size()).map(i -> source.size() - i - 1).filter(i -> source.get(i).isNewline()).findFirst().orElse(-1); + return IntStream.range(0, source.size()) + .map(i -> source.size() - i - 1) + .filter(i -> source.get(i).isNewline()) + .findFirst() + .orElse(-1); } /* @@ -235,11 +244,15 @@ private int considerIndentation(NodeText nodeText, int nodeTextIndex, int number } private boolean isEnforcingIndentationActivable(RemovedGroup removedGroup) { - return (isLastElement(diffElements, diffIndex) || !(nextDiffElement(diffElements, diffIndex).isAdded())) && originalIndex < originalElements.size() && !removedGroup.isACompleteLine(); + return (isLastElement(diffElements, diffIndex) || !(nextDiffElement(diffElements, diffIndex).isAdded())) + && originalIndex < originalElements.size() + && !removedGroup.isACompleteLine(); } private boolean isRemovingIndentationActivable(RemovedGroup removedGroup) { - return (isLastElement(diffElements, diffIndex) || !(nextDiffElement(diffElements, diffIndex).isAdded())) && originalIndex < originalElements.size() && removedGroup.isACompleteLine(); + return (isLastElement(diffElements, diffIndex) || !(nextDiffElement(diffElements, diffIndex).isAdded())) + && originalIndex < originalElements.size() + && removedGroup.isACompleteLine(); } private boolean isLastElement(List list, int index) { @@ -255,9 +268,7 @@ private DifferenceElement nextDiffElement(List list, int inde * and the number of consecutive whitespace (or tab) characters */ private class EnforcingIndentationContext { - int start; - int extraCharacters; public EnforcingIndentationContext(int start) { @@ -272,8 +283,7 @@ public EnforcingIndentationContext(int start, int extraCharacters) { /** * Remove excess white space after deleting element. - * - * @param nodeText Contains a list of elements to analyze + * @param nodeText Contains a list of elements to analyze * @param nodeTextIndex Starting position in the input list * @return The current position in the list of the elements */ @@ -289,8 +299,7 @@ private int removeExtraCharacters(NodeText nodeText, int nodeTextIndex, int extr /** * Starting at {@code nodeTextIndex} this method tries to determine how many contiguous spaces there are between * the previous end of line and the next non whitespace (or tab) character - * - * @param nodeText List of elements to analyze + * @param nodeText List of elements to analyze * @param nodeTextIndex Starting position in the input list * @return EnforcingIndentationContext Data structure that hold the starting position of the first whitespace char and * The number of consecutive whitespace (or tab) characters @@ -314,7 +323,7 @@ private EnforcingIndentationContext defineEnforcingIndentationContext(NodeText n } // compute space after the deleted element if (startIndex < nodeText.numberOfElements() && isSpaceOrTabElement(nodeText, startIndex)) { - // int startingFromIndex = startIndex == 0 ? startIndex : startIndex + 1; +// int startingFromIndex = startIndex == 0 ? startIndex : startIndex + 1; for (int i = startIndex; i >= 0 && i < nodeText.numberOfElements(); i++) { if (nodeText.getTextElement(i).isNewline()) { break; @@ -325,9 +334,30 @@ private EnforcingIndentationContext defineEnforcingIndentationContext(NodeText n ctx.extraCharacters++; } } + return ctx; } + /* + * An element is considered inlined if, before the line break, there are nodes in the list of elements + */ + private boolean isInlined(NodeText nodeText, int startIndex) { + boolean inlined = false; + if (startIndex < nodeText.numberOfElements() && startIndex >= 0) { + // at this stage startIndex points to the first element before the deleted one + for (int i = startIndex; i < nodeText.numberOfElements(); i++) { + if (nodeText.getTextElement(i).isNewline()) { + break; + } + if (nodeText.getTextElement(i).isChild()) { + inlined = true; + break; + } + } + } + return inlined; + } + /* * Returns true if the indexed element is a space or a tab */ @@ -458,6 +488,26 @@ private void applyRemovedDiffElement(RemovedGroup removedGroup, Removed removed, originalIndex++; } } else { + // If we delete the first element, it is possible that there is an indentation to be deleted which is stored in the parent node. + NodeText parentNodeText = new NodeText(); + List indentationTokens = new ArrayList<>(); + if (originalIndex == 0 && removed.getChild().getParentNode().isPresent()) { + Node startingNodeForFindingIndentation = removed.getChild(); + Node parentNode = removed.getChild().getParentNode().get(); + parentNodeText = LexicalPreservingPrinter.getOrCreateNodeText(parentNode); + // If we are trying to delete the first element of a node and that node is also the first element of the parent node, we need to look for the grandfather node which logically contains the indentation characters. + // This is the case, for example, when trying to delete an annotation positioned on a method declaration. + // The token corresponding to the annotation is the first element of the annotation node + // and it is also the first element of the parent node (MethodDeclaration), + // so the previous indentation is defined in the parent node of the method declaration. + if (!parentNodeText.getElements().isEmpty() + && parentNode.getParentNode().isPresent() + && parentNodeText.getTextElement(0).equals(nodeText.getTextElement(originalIndex))) { + startingNodeForFindingIndentation = parentNode; + parentNodeText = LexicalPreservingPrinter.getOrCreateNodeText(parentNode.getParentNode().get()); + } + indentationTokens = LexicalPreservingPrinter.findIndentation(startingNodeForFindingIndentation); + } nodeText.removeElement(originalIndex); // When we don't try to remove a complete line // and removing the element is not the first action of a replacement (removal followed by addition) @@ -488,6 +538,19 @@ private void applyRemovedDiffElement(RemovedGroup removedGroup, Removed removed, if (isRemovingIndentationActivable(removedGroup)) { // Since the element has been deleted we try to start the analysis from the previous element originalIndex = considerRemovingIndentation(nodeText, originalIndex); + // If we delete the first element, it is possible that there is an indentation + // to be deleted which is stored in the parent node. + // We don't want to remove indentation when the node to remove is not the only + // node in the line (if there are other nodes before the next character + // indicating the end of line). + // This is for example the case when we want to delete an annotation declared on + // the same line as a method declaration. + if (originalIndex == 0 && !indentationTokens.isEmpty() && !isInlined(nodeText, originalIndex)) { + for (TextElement indentationToken : indentationTokens) { + parentNodeText.removeElement( + parentNodeText.findElement(indentationToken.and(indentationToken.matchByRange()))); + } + } } diffIndex++; } @@ -497,12 +560,13 @@ private void applyRemovedDiffElement(RemovedGroup removedGroup, Removed removed, if (isRemovingIndentationActivable(removedGroup)) { originalIndex = considerRemovingIndentation(nodeText, originalIndex); } - } else if (removed.isToken() && originalElementIsToken && (// handle EOLs separately as their token kind might not be equal. This is because the 'removed' + } else if (removed.isToken() && originalElementIsToken && (removed.getTokenType() == ((TokenTextElement) originalElement).getTokenKind() || // handle EOLs separately as their token kind might not be equal. This is because the 'removed' // element always has the current operating system's EOL as type - removed.getTokenType() == ((TokenTextElement) originalElement).getTokenKind() || (((TokenTextElement) originalElement).getToken().getCategory().isEndOfLine() && removed.isNewLine()))) { + (((TokenTextElement) originalElement).getToken().getCategory().isEndOfLine() && removed.isNewLine()))) { nodeText.removeElement(originalIndex); diffIndex++; - } else if ((removed.isWhiteSpaceNotEol() || removed.getElement() instanceof CsmIndent || removed.getElement() instanceof CsmUnindent) && originalElement.isSpaceOrTab()) { + } else if ((removed.isWhiteSpaceNotEol() || removed.getElement() instanceof CsmIndent || removed.getElement() instanceof CsmUnindent) + && originalElement.isSpaceOrTab()) { // remove the current space nodeText.removeElement(originalIndex); } else if (originalElementIsToken && originalElement.isWhiteSpaceOrComment()) { @@ -545,7 +609,10 @@ private void cleanTheLineOfLeftOverSpace(RemovedGroup removedGroup, Removed remo } // we dont want to remove the indentation if the last removed element is a newline // because in this case we are trying to remove the indentation of the next child element - if (!removedGroup.isProcessed() && removedGroup.isLastElement(removed) && removedGroup.isACompleteLine() && !removed.isNewLine()) { + if (!removedGroup.isProcessed() + && removedGroup.isLastElement(removed) + && removedGroup.isACompleteLine() + && !removed.isNewLine()) { Integer lastElementIndex = removedGroup.getLastElementIndex(); Optional indentation = removedGroup.getIndentation(); if (indentation.isPresent() && !isReplaced(lastElementIndex)) { @@ -721,7 +788,7 @@ private int getIndexToNextTokenElement(TokenTextElement element, DifferenceEleme if (part.equals(token.asString())) { // get 'dot' token token = token.getNextToken().get(); - if (!token.asString().equals(".")) + if (!".".equals(token.asString())) break; // get the next part token = token.getNextToken().get(); @@ -889,7 +956,9 @@ private void applyAddedDiffElement(Added added) { boolean currentIsNewline = nodeText.getTextElement(originalIndex).isNewline(); boolean isFirstElement = originalIndex == 0; boolean previousIsWhiteSpace = originalIndex > 0 && nodeText.getTextElement(originalIndex - 1).isWhiteSpace(); - boolean commentIsBeforeAddedElement = currentIsAComment && addedTextElement.getRange().isPresent() && nodeText.getTextElement(originalIndex).getRange().map(range -> range.isBefore(addedTextElement.getRange().get())).orElse(false); + boolean commentIsBeforeAddedElement = currentIsAComment && addedTextElement.getRange().isPresent() + && nodeText.getTextElement(originalIndex).getRange() + .map(range -> range.isBefore(addedTextElement.getRange().get())).orElse(false); if (sufficientTokensRemainToSkip && currentIsAComment && commentIsBeforeAddedElement) { // Need to get behind the comment: // FIXME: Why 2? This comment and the next newline? @@ -951,7 +1020,6 @@ private void applyAddedDiffElement(Added added) { * A list iterator which provides a method to know the current positioning */ public static class ArrayIterator implements ListIterator { - ListIterator iterator; public ArrayIterator(List elements) { @@ -1015,6 +1083,7 @@ public void add(T e) { iterator.add(e); ; } + } /* diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/LexicalPreservingPrinter.java b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/LexicalPreservingPrinter.java index 123f186921..d6c5a5b82e 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/LexicalPreservingPrinter.java +++ b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/LexicalPreservingPrinter.java @@ -26,10 +26,12 @@ import static com.github.javaparser.utils.Utils.decapitalize; import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toList; + import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.util.*; + import com.github.javaparser.JavaToken; import com.github.javaparser.Range; import com.github.javaparser.ast.DataKey; @@ -132,11 +134,10 @@ public void concretePropertyChange(Node observedNode, ObservableProperty propert if (property == ObservableProperty.COMMENT) { Optional parentNode = observedNode.getParentNode(); NodeText nodeText = parentNode.map(parent -> getOrCreateNodeText(parentNode.get())).orElseGet(() -> getOrCreateNodeText(observedNode)); - if (oldValue == null) { - // this case corresponds to the addition of a comment - int index = // Find the position of the comment node and put in front of it the [...] - parentNode.isPresent() ? // - nodeText.findChild(observedNode) : 0; + if (oldValue == null) { // this case corresponds to the addition of a comment + int index = parentNode.isPresent() ? // Find the position of the comment node and put in front of it the [...] + nodeText.findChild(observedNode) : // + 0; /* Add the same indentation to the comment as the previous node * for example if we want to add a comment on the body of the method declaration : * Actual code @@ -162,8 +163,7 @@ public void concretePropertyChange(Node observedNode, ObservableProperty propert nodeText.addElement(index++, makeCommentToken((Comment) newValue)); nodeText.addToken(index, eolTokenKind(lineSeparator), lineSeparator.asRawString()); // code indentation after inserting an eol token may be wrong - } else if (newValue == null) { - // this case corresponds to a deletion of a comment + } else if (newValue == null) { // this case corresponds to a deletion of a comment if (oldValue instanceof Comment) { if (((Comment) oldValue).isOrphan()) { nodeText = getOrCreateNodeText(observedNode); @@ -175,9 +175,6 @@ public void concretePropertyChange(Node observedNode, ObservableProperty propert } else { removeAllExtraCharactersStartingFrom(nodeText.getElements().listIterator(index)); } - // if (nodeText.getElements().get(index).isNewline()) { - // nodeText.removeElement(index); - // } } else { throw new UnsupportedOperationException("Trying to remove something that is not a comment!"); } @@ -200,17 +197,14 @@ public void concretePropertyChange(Node observedNode, ObservableProperty propert } private boolean isCompleteLine(List elements, int index) { - if (index <= 0 || index >= elements.size()) - return false; + if (index <= 0 || index >= elements.size()) return false; boolean isCompleteLine = true; ListIterator iterator = elements.listIterator(index); // verify if elements after the index are only spaces or tabs while (iterator.hasNext()) { TextElement textElement = iterator.next(); - if (textElement.isNewline()) - break; - if (textElement.isSpaceOrTab()) - continue; + if (textElement.isNewline()) break; + if (textElement.isSpaceOrTab()) continue; isCompleteLine = false; break; } @@ -218,18 +212,16 @@ private boolean isCompleteLine(List elements, int index) { iterator = elements.listIterator(index); while (iterator.hasPrevious() && isCompleteLine) { TextElement textElement = iterator.previous(); - if (textElement.isNewline()) - break; - if (textElement.isSpaceOrTab()) - continue; + if (textElement.isNewline()) break; + if (textElement.isSpaceOrTab()) continue; isCompleteLine = false; } + return isCompleteLine; } private void removeAllExtraCharacters(List elements, int index) { - if (index < 0 || index >= elements.size()) - return; + if (index < 0 || index >= elements.size()) return; removeAllExtraCharactersStartingFrom(elements.listIterator(index)); removeAllExtraCharactersBeforePosition(elements.listIterator(index)); } @@ -290,12 +282,21 @@ private int getIndexOfComment(Comment oldValue, NodeText nodeText) { return nodeText.findElement(matchingChild.and(matchingChild.matchByRange())); } + /* + * Comment + */ private List findChildTextElementForComment(Comment oldValue, NodeText nodeText) { List matchingChildElements; matchingChildElements = selectMatchingChildElements(oldValue, nodeText); if (matchingChildElements.size() > 1) { // Duplicate child nodes found, refine the result - matchingChildElements = matchingChildElements.stream().filter(t -> isEqualRange(t.getChild().getRange(), oldValue.getRange())).collect(toList()); + matchingChildElements = matchingChildElements.stream() + .filter(t -> t.getChild().hasRange() && oldValue.hasRange()) + .filter(t -> t.getChild().getRange().get().equals(oldValue.getRange().get()) + || (t.getChild().getComment().isPresent() + && t.getChild().getComment().get().hasRange() + && t.getChild().getComment().get().getRange().get().equals(oldValue.getRange().get()))) + .collect(toList()); } if (matchingChildElements.size() != 1) { throw new IllegalStateException("The matching child text element for the comment to be removed could not be found."); @@ -305,7 +306,8 @@ private List findChildTextElementForComment(Comment oldValue, private List selectMatchingChildElements(Comment oldValue, NodeText nodeText) { List result = new ArrayList<>(); - List childTextElements = nodeText.getElements().stream().filter(e -> e.isChild()).map(c -> (ChildTextElement) c).collect(toList()); + List childTextElements = nodeText.getElements().stream().filter(e -> e.isChild()) + .map(c -> (ChildTextElement) c).collect(toList()); ListIterator iterator = childTextElements.listIterator(); while (iterator.hasNext()) { ChildTextElement textElement = iterator.next(); @@ -329,24 +331,31 @@ private boolean isSameComment(Comment childValue, Comment oldValue) { private List findTokenTextElementForComment(Comment oldValue, NodeText nodeText) { List matchingTokens; if (oldValue instanceof JavadocComment) { - matchingTokens = nodeText.getElements().stream().filter(e -> e.isToken(JAVADOC_COMMENT)).map(e -> (TokenTextElement) e).filter(t -> t.getText().equals(oldValue.getHeader() + oldValue.getContent() + oldValue.getFooter())).collect(toList()); + matchingTokens = nodeText.getElements().stream() + .filter(e -> e.isToken(JAVADOC_COMMENT)) + .map(e -> (TokenTextElement) e) + .filter(t -> t.getText().equals(oldValue.asString())) + .collect(toList()); } else if (oldValue instanceof BlockComment) { - matchingTokens = nodeText.getElements().stream().filter(e -> e.isToken(MULTI_LINE_COMMENT)).map(e -> (TokenTextElement) e).filter(t -> t.getText().equals(oldValue.getHeader() + oldValue.getContent() + oldValue.getFooter())).collect(toList()); + matchingTokens = nodeText.getElements().stream() + .filter(e -> e.isToken(MULTI_LINE_COMMENT)) + .map(e -> (TokenTextElement) e) + .filter(t -> t.getText().equals(oldValue.asString())) + .collect(toList()); } else { - matchingTokens = nodeText.getElements().stream().filter(e -> e.isToken(SINGLE_LINE_COMMENT)).map(e -> (TokenTextElement) e).filter(t -> t.getText().trim().equals((oldValue.getHeader() + oldValue.getContent()).trim())).collect(toList()); - } - if (matchingTokens.size() > 1) { - // Duplicate comments found, refine the result - matchingTokens = matchingTokens.stream().filter(t -> isEqualRange(t.getToken().getRange(), oldValue.getRange())).collect(toList()); - } - return matchingTokens; - } - - private boolean isEqualRange(Optional range1, Optional range2) { - if (range1.isPresent() && range2.isPresent()) { - return range1.get().equals(range2.get()); + matchingTokens = nodeText.getElements().stream() + .filter(e -> e.isToken(SINGLE_LINE_COMMENT)) + .map(e -> (TokenTextElement) e) + .filter(t -> t.getText().trim().equals((oldValue.asString()).trim())) + .collect(toList()); } - return false; + // To check that a comment matches in the list of tokens, if exists the range must be always checked, + // as comments with the same content may exist on different lines. + return matchingTokens.stream() + .filter(t -> (!t.getToken().hasRange() && !oldValue.hasRange()) + || (t.getToken().hasRange() && oldValue.hasRange() + && t.getToken().getRange().get().equals(oldValue.getRange().get()))) + .collect(toList()); } /** @@ -507,6 +516,7 @@ public static String print(Node node) { final NodeText nodeText = getOrCreateNodeText(node); nodeText.getElements().forEach(element -> element.accept(visitor)); return visitor.toString(); + } // @@ -581,8 +591,8 @@ private static NodeText interpret(Node node, CsmElement csm, NodeText nodeText) if (!comment.hasRange()) { LineSeparator lineSeparator = node.getLineEndingStyleOrDefault(LineSeparator.SYSTEM); calculatedSyntaxModel.elements.add(0, new CsmToken(eolTokenKind(lineSeparator), lineSeparator.asRawString())); - calculatedSyntaxModel.elements.add(0, new CsmChild(comment)); - } + calculatedSyntaxModel.elements.add(0,new CsmChild(comment)); + } }); for (CsmElement element : calculatedSyntaxModel.elements) { if (element instanceof CsmIndent) { diff --git a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/changes/ListRemovalChange.java b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/changes/ListRemovalChange.java index ba9a723f02..5e19065d8c 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/changes/ListRemovalChange.java +++ b/javaparser-core/src/main/java/com/github/javaparser/printer/lexicalpreservation/changes/ListRemovalChange.java @@ -21,6 +21,8 @@ package com.github.javaparser.printer.lexicalpreservation.changes; import java.util.Optional; + +import com.github.javaparser.Range; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.observer.ObservableProperty; @@ -55,14 +57,33 @@ public Object getValue(ObservableProperty property, Node node) { NodeList newNodeList = new NodeList<>(); // fix #2187 set the parent node in the new list newNodeList.setParentNode(currentNodeList.getParentNodeForChildren()); - newNodeList.addAll(currentNodeList); - // Perform modification -- remove an item from the list - newNodeList.remove(index); + // Here we want to obtain a sub-list that does not contain an element. + // It is important not to implement this by first adding all the elements in the + // list and then deleting the element to be removed, as this involves event + // propagation mechanisms, particularly for lexical preservation, + // which deletes the relationship between a node and its parent node. + // This relationship is necessary to reinforce indentation, for example when + // deleting a node, as indentation can be carried by the parent node. + currentNodeList.stream().filter(n -> !isSameNode(currentNodeList.get(index), n)) + .forEach(selectedNode -> newNodeList.add(selectedNode)); return newNodeList; } return new NoChange().getValue(property, node); } + private boolean isSameNode(Node n1, Node n2) { + return n1.equals(n2) && isSameRange(n1, n2); + } + + private boolean isSameRange(Node n1, Node n2) { + return (!n1.hasRange() && !n2.hasRange()) + || (n1.hasRange() && n2.hasRange() && isSameRange(n1.getRange().get(), n2.getRange().get())); + } + + private boolean isSameRange(Range r1, Range r2) { + return r1.equals(r2); + } + @Override public ObservableProperty getProperty() { return observableProperty; diff --git a/javaparser-core/src/main/java/com/github/javaparser/resolution/declarations/ResolvedReferenceTypeDeclaration.java b/javaparser-core/src/main/java/com/github/javaparser/resolution/declarations/ResolvedReferenceTypeDeclaration.java index be966d5661..112414bc6e 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/resolution/declarations/ResolvedReferenceTypeDeclaration.java +++ b/javaparser-core/src/main/java/com/github/javaparser/resolution/declarations/ResolvedReferenceTypeDeclaration.java @@ -24,6 +24,7 @@ import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; + import com.github.javaparser.ast.AccessSpecifier; import com.github.javaparser.resolution.MethodUsage; import com.github.javaparser.resolution.UnsolvedSymbolException; @@ -36,11 +37,8 @@ public interface ResolvedReferenceTypeDeclaration extends ResolvedTypeDeclaration, ResolvedTypeParametrizable { String JAVA_LANG_ENUM = java.lang.Enum.class.getCanonicalName(); - String JAVA_LANG_COMPARABLE = java.lang.Comparable.class.getCanonicalName(); - String JAVA_IO_SERIALIZABLE = Serializable.class.getCanonicalName(); - String JAVA_LANG_OBJECT = java.lang.Object.class.getCanonicalName(); @Override @@ -295,7 +293,12 @@ default boolean hasAnnotation(String qualifiedName) { if (hasDirectlyAnnotation(qualifiedName)) { return true; } - return isClass() && getAllAncestors().stream().filter(it -> it.asReferenceType().getTypeDeclaration().isPresent()).filter(it -> it.asReferenceType().getTypeDeclaration().get().isClass()).map(it -> it.asReferenceType().getTypeDeclaration().get()).anyMatch(rrtd -> rrtd.hasDirectlyAnnotation(qualifiedName) && rrtd.isInheritedAnnotation(qualifiedName)); + return isClass() && getAllAncestors().stream() + .filter(it -> it.asReferenceType().getTypeDeclaration().isPresent()) + .filter(it -> it.asReferenceType().getTypeDeclaration().get().isClass()) + .map(it -> it.asReferenceType().getTypeDeclaration().get()) + .anyMatch(rrtd -> rrtd.hasDirectlyAnnotation(qualifiedName) + && rrtd.isInheritedAnnotation(qualifiedName)); } /** @@ -310,7 +313,9 @@ default boolean isInheritedAnnotation(String name) { * Returns the resolved annotation corresponding to the specified name and declared in this type declaration. */ default Optional getDeclaredAnnotation(String name) { - return getDeclaredAnnotations().stream().filter(annotation -> annotation.getQualifiedName().endsWith(name)).findFirst(); + return getDeclaredAnnotations().stream() + .filter(annotation -> annotation.getQualifiedName().endsWith(name)) + .findFirst(); } /** @@ -320,6 +325,7 @@ default Set getDeclaredAnnotations() { throw new UnsupportedOperationException("Getting declared annotation is not supproted on this type " + this.getName()); } + /** * This means that the type has a functional method. Conceptually, a functional interface has exactly one abstract method. * Typically these classes has the FunctionInterface annotation but this is not mandatory. @@ -353,8 +359,8 @@ default Optional findTypeParameter(String name * @see https://github.com/javaparser/javaparser/issues/2044 */ default boolean isJavaLangObject() { - return // Consider anonymous classes - this.isClass() && !isAnonymousClass() && hasName() && getQualifiedName().equals(JAVA_LANG_OBJECT); + return this.isClass() && !isAnonymousClass() && // Consider anonymous classes + hasName() && JAVA_LANG_OBJECT.equals(getQualifiedName()); } /** @@ -362,6 +368,6 @@ default boolean isJavaLangObject() { * @see ResolvedReferenceType#isJavaLangEnum() */ default boolean isJavaLangEnum() { - return this.isEnum() && getQualifiedName().equals(JAVA_LANG_ENUM); + return this.isEnum() && JAVA_LANG_ENUM.equals(getQualifiedName()); } } diff --git a/javaparser-core/src/main/java/com/github/javaparser/resolution/logic/MethodResolutionLogic.java b/javaparser-core/src/main/java/com/github/javaparser/resolution/logic/MethodResolutionLogic.java index 8720330235..e7d9431388 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/resolution/logic/MethodResolutionLogic.java +++ b/javaparser-core/src/main/java/com/github/javaparser/resolution/logic/MethodResolutionLogic.java @@ -116,7 +116,6 @@ private static boolean isApplicable(ResolvedMethodDeclaration methodDeclaration, } // The index of the final argument passed (on the method usage). int countOfNeedleArgumentsPassedAfterGrouping = needleArgumentTypes.size(); - int lastNeedleArgumentIndexAfterGrouping = getLastParameterIndex(countOfNeedleArgumentsPassed); // If variadic parameters are possible then they will have been "grouped" into a single argument. // At this point, therefore, the number of arguments must be equal -- if they're not, then there is no match. if (countOfNeedleArgumentsPassedAfterGrouping != countOfMethodParametersDeclared) { @@ -383,7 +382,6 @@ public static boolean isApplicable(MethodUsage methodUsage, String needleName, L int lastMethodUsageArgumentIndex = getLastParameterIndex(countOfMethodUsageArgumentsPassed); // The index of the final argument passed (on the method usage). int needleParameterCount = needleParameterTypes.size(); - int lastNeedleParameterIndex = getLastParameterIndex(needleParameterCount); // TODO: Does the method usage have a declaration at this point..? boolean methodIsDeclaredWithVariadicParameter = methodUsage.getDeclaration().hasVariadicParameter(); // If the counts do not match and the method is not variadic, this is not a match. diff --git a/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java b/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java index 0316ece22d..ceb44a564a 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java +++ b/javaparser-core/src/main/java/com/github/javaparser/resolution/types/ResolvedReferenceType.java @@ -23,6 +23,7 @@ import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; + import com.github.javaparser.ast.AccessSpecifier; import com.github.javaparser.resolution.MethodUsage; import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration; @@ -87,9 +88,20 @@ public ResolvedReferenceType(ResolvedReferenceTypeDeclaration typeDeclaration, L public boolean equals(Object o) { if (this == o) return true; - if (o == null || (!isLazyType(o) && getClass() != o.getClass()) || (isLazyType(o) && !this.equals(asResolvedReferenceType(o)))) + if (o == null) + return false; + + if (o instanceof LazyType) { + final LazyType lazyType = (LazyType) o; + if (!lazyType.isReferenceType()) + return false; + return this.equals(lazyType.asReferenceType()); + } + + if (getClass() != o.getClass()) return false; - ResolvedReferenceType that = asResolvedReferenceType(o); + + ResolvedReferenceType that = (ResolvedReferenceType) o; if (!typeDeclaration.equals(that.typeDeclaration)) return false; if (!typeParametersMap.equals(that.typeParametersMap)) @@ -97,17 +109,6 @@ public boolean equals(Object o) { return true; } - private boolean isLazyType(Object type) { - return type != null && type instanceof LazyType; - } - - private ResolvedReferenceType asResolvedReferenceType(Object o) { - if (isLazyType(o)) { - return ((LazyType) o).asReferenceType(); - } - return ResolvedReferenceType.class.cast(o); - } - @Override public int hashCode() { int result = typeDeclaration.hashCode(); @@ -523,8 +524,8 @@ private static List deriveParams(ResolvedReferenceTypeDeclaration * @see https://github.com/javaparser/javaparser/issues/2044 */ public boolean isJavaLangObject() { - return // Consider anonymous classes - this.isReferenceType() && hasName() && getQualifiedName().equals(JAVA_LANG_OBJECT); + return this.isReferenceType() && // Consider anonymous classes + hasName() && getQualifiedName().equals(JAVA_LANG_OBJECT); } /** @@ -532,8 +533,8 @@ public boolean isJavaLangObject() { * @see ResolvedReferenceTypeDeclaration#isJavaLangEnum() */ public boolean isJavaLangEnum() { - return // Consider anonymous classes - this.isReferenceType() && hasName() && getQualifiedName().equals(JAVA_LANG_ENUM); + return this.isReferenceType() && // Consider anonymous classes + hasName() && getQualifiedName().equals(JAVA_LANG_ENUM); } // / @@ -574,13 +575,7 @@ public ResolvedType erasure() { } private List erasureOfParamaters(ResolvedTypeParametersMap typeParametersMap) { - List erasedParameters = new ArrayList(); - if (!typeParametersMap.isEmpty()) { - // add erased type except java.lang.object - List parameters = typeParametersMap.getTypes().stream().filter(type -> !type.isReferenceType()).map(type -> type.erasure()).filter(erasedType -> !(isJavaObject(erasedType))).filter(erasedType -> erasedType != null).collect(Collectors.toList()); - erasedParameters.addAll(parameters); - } - return erasedParameters; + return new ArrayList(); } private boolean isJavaObject(ResolvedType rt) { diff --git a/javaparser-core/src/main/java/com/github/javaparser/utils/CollectionStrategy.java b/javaparser-core/src/main/java/com/github/javaparser/utils/CollectionStrategy.java index 86259ae4db..df2ab58df8 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/utils/CollectionStrategy.java +++ b/javaparser-core/src/main/java/com/github/javaparser/utils/CollectionStrategy.java @@ -49,7 +49,7 @@ default Optional getRoot(Path file) { if (parseResult.getResult().isPresent()) { final Optional storage = parseResult.getResult().flatMap(CompilationUnit::getStorage); if (storage.isPresent()) { - if (storage.get().getFileName().equals("module-info.java")) { + if ("module-info.java".equals(storage.get().getFileName())) { // module-info.java is useless for finding the source root, since it can be placed in any directory. return Optional.empty(); } diff --git a/javaparser-core/src/main/java/com/github/javaparser/utils/ParserCollectionStrategy.java b/javaparser-core/src/main/java/com/github/javaparser/utils/ParserCollectionStrategy.java index 9dbf7c5546..8f059e8b10 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/utils/ParserCollectionStrategy.java +++ b/javaparser-core/src/main/java/com/github/javaparser/utils/ParserCollectionStrategy.java @@ -64,7 +64,7 @@ public ProjectRoot collect(Path path) { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - if (file.getFileName().toString().equals("module-info.java")) { + if ("module-info.java".equals(file.getFileName().toString())) { // module-info.java is useless for finding the source root, since it can be placed within any directory. return CONTINUE; } diff --git a/javaparser-core/src/main/java/com/github/javaparser/utils/Utils.java b/javaparser-core/src/main/java/com/github/javaparser/utils/Utils.java index 085f010705..24fa37ae15 100644 --- a/javaparser-core/src/main/java/com/github/javaparser/utils/Utils.java +++ b/javaparser-core/src/main/java/com/github/javaparser/utils/Utils.java @@ -20,13 +20,14 @@ */ package com.github.javaparser.utils; -import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.expr.UnaryExpr; +import static java.util.Arrays.asList; import java.io.IOException; import java.io.Reader; import java.util.*; import java.util.function.Function; -import static java.util.Arrays.asList; + +import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.expr.UnaryExpr; /** * Any kind of utility. @@ -219,17 +220,20 @@ public static boolean valueIsNullOrEmpty(Object value) { } public static boolean valueIsNullOrEmptyStringOrOptional(Object value) { + // is null? if (value == null) { return true; } - if (value instanceof Optional) { - if (((Optional) value).isPresent()) { - value = ((Optional) value).get(); - } else { - return true; - } - } - return false; +// // is not Optional? +// if (!(value instanceof Optional)) { +// return false; +// } +// // is an empty Optional? +// if (!((Optional) value).isPresent()) { +// return true; +// } +// return false; + return value instanceof Optional ? !((Optional) value).isPresent() : false; } /** diff --git a/javaparser-symbol-solver-core/pom.xml b/javaparser-symbol-solver-core/pom.xml index 24e69b843f..85d1d50447 100644 --- a/javaparser-symbol-solver-core/pom.xml +++ b/javaparser-symbol-solver-core/pom.xml @@ -4,7 +4,7 @@ jmlparser-parent io.github.jmltoolkit - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT 4.0.0 diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/JavaSymbolSolver.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/JavaSymbolSolver.java index f541fade87..1c14edffb1 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/JavaSymbolSolver.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/JavaSymbolSolver.java @@ -247,7 +247,7 @@ public T resolveDeclarationImpl(Node node, Class resultClass) { return resultClass.cast(result.getCorrespondingDeclaration()); } } else { - if (((FieldAccessExpr) node).getName().getId().equals("length")) { + if ("length".equals(((FieldAccessExpr) node).getName().getId())) { ResolvedType scopeType = ((FieldAccessExpr) node).getScope().calculateResolvedType(); if (scopeType.isArray()) { if (resultClass.isInstance(ArrayLengthValueDeclaration.INSTANCE)) { diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java index 435c1b2d04..d7f0e98af3 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacade.java @@ -343,53 +343,45 @@ public ResolvedType getType(Node node) { } } + /* + * Returns the resolved Type of the {@code Node}. If the node is a method call + * expression and and the flag activates lambda expression resolution, the type + * of the arguments to the expression are looked up beforehand so that the type + * resolution is as relevant as possible. + */ public ResolvedType getType(Node node, boolean solveLambdas) { if (solveLambdas) { if (!node.containsData(TYPE_WITH_LAMBDAS_RESOLVED)) { - ResolvedType res = getTypeConcrete(node, solveLambdas); - - node.setData(TYPE_WITH_LAMBDAS_RESOLVED, res); - boolean secondPassNecessary = false; if (node instanceof MethodCallExpr) { MethodCallExpr methodCallExpr = (MethodCallExpr) node; for (Node arg : methodCallExpr.getArguments()) { if (!arg.containsData(TYPE_WITH_LAMBDAS_RESOLVED)) { getType(arg, true); - secondPassNecessary = true; } } } - if (secondPassNecessary) { - node.removeData(TYPE_WITH_LAMBDAS_RESOLVED); - ResolvedType type = getType(node, true); - node.setData(TYPE_WITH_LAMBDAS_RESOLVED, type); - - } + ResolvedType res = getTypeConcrete(node, solveLambdas); + node.setData(TYPE_WITH_LAMBDAS_RESOLVED, res); Log.trace("getType on %s -> %s", () -> node, () -> res); } return node.getData(TYPE_WITH_LAMBDAS_RESOLVED); } - Optional res = find(TYPE_WITH_LAMBDAS_RESOLVED, node); + + // Try to return a value from the cache of resolved types using lambda expressions + Optional res = node.findData(TYPE_WITH_LAMBDAS_RESOLVED); if (res.isPresent()) { return res.get(); - } - res = find(TYPE_WITHOUT_LAMBDAS_RESOLVED, node); - if (!res.isPresent()) { - ResolvedType resType = getTypeConcrete(node, solveLambdas); - node.setData(TYPE_WITHOUT_LAMBDAS_RESOLVED, resType); - Optional finalRes = res; - Log.trace("getType on %s (no solveLambdas) -> %s", () -> node, () -> finalRes); - return resType; - } - return res.get(); - } - - private Optional find(DataKey dataKey, Node node) { - if (node.containsData(dataKey)) { - return Optional.of(node.getData(dataKey)); } - return Optional.empty(); + + // else try to return a value from the cache of resolved types without lambda expressions + // Or resolves the node type without resolving the lambda expressions + return node.findData(TYPE_WITHOUT_LAMBDAS_RESOLVED).orElseGet(() -> { + ResolvedType resType = getTypeConcrete(node, solveLambdas); + node.setData(TYPE_WITHOUT_LAMBDAS_RESOLVED, resType); + Log.trace("getType on %s (no solveLambdas) -> %s", () -> node, () -> res); + return resType; + }); } protected MethodUsage toMethodUsage(MethodReferenceExpr methodReferenceExpr, List paramTypes) { diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/FieldAccessContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/FieldAccessContext.java index e814810546..baf8dff6d6 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/FieldAccessContext.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/FieldAccessContext.java @@ -83,7 +83,7 @@ public Optional solveSymbolAsValue(String name) { Expression scope = wrappedNode.getScope(); if (wrappedNode.getName().toString().equals(name)) { ResolvedType typeOfScope = JavaParserFacade.get(typeSolver).getType(scope); - if (typeOfScope.isArray() && name.equals(ARRAY_LENGTH_FIELD_NAME)) { + if (typeOfScope.isArray() && ARRAY_LENGTH_FIELD_NAME.equals(name)) { return Optional.of(new Value(ResolvedPrimitiveType.INT, ARRAY_LENGTH_FIELD_NAME)); } if (typeOfScope.isReferenceType()) { diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java index 9a68102dfe..c171ae2668 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapter.java @@ -96,7 +96,9 @@ public SymbolReference solveType(String name, List symbolRef = context.getParent() .orElseThrow(() -> new RuntimeException("Parent context unexpectedly empty.")) .solveType(name, typeArguments); @@ -140,17 +142,7 @@ public SymbolReference solveType(String name, List solveMethod(String name, List< // If we haven't located any candidates that are declared on this type or its ancestors, consider the parent context. // This is relevant e.g. with nested classes. // Note that we want to avoid infinite recursion when a class is using its own method - see issue #75 - if (candidateMethods.isEmpty()) { + // We also want to avoid infinite recursion when handling static imports - see issue #4358 + if (candidateMethods.isEmpty() && !staticOnly) { SymbolReference parentSolution = context.getParent() .orElseThrow(() -> new RuntimeException("Parent context unexpectedly empty.")) .solveMethod(name, argumentsTypes, staticOnly); diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodReferenceExprContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodReferenceExprContext.java index 7b4374a4a3..f86aa9ca8a 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodReferenceExprContext.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/MethodReferenceExprContext.java @@ -27,12 +27,13 @@ import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.VariableDeclarator; -import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.MethodReferenceExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.resolution.MethodUsage; import com.github.javaparser.resolution.TypeSolver; +import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration; import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; @@ -99,7 +100,7 @@ private List inferArgumentTypes() { if (demandParentNode(wrappedNode) instanceof MethodCallExpr) { MethodCallExpr methodCallExpr = (MethodCallExpr) demandParentNode(wrappedNode); MethodUsage methodUsage = JavaParserFacade.get(typeSolver).solveMethodAsUsage(methodCallExpr); - int pos = pos(methodCallExpr, wrappedNode); + int pos = methodCallExpr.getArgumentPosition(wrappedNode); ResolvedMethodDeclaration rmd = methodUsage.getDeclaration(); // Since variable parameters are represented by an array, in case we deal with // the variadic parameter we have to take into account the base type of the @@ -108,37 +109,24 @@ private List inferArgumentTypes() { rmd.getLastParam().getType().asArrayType().getComponentType() : methodUsage.getParamType(pos); - // Get the functional method in order for us to resolve it's type arguments properly - Optional functionalMethodOpt = FunctionalInterfaceLogic.getFunctionalMethod(lambdaType); - if (functionalMethodOpt.isPresent()) { - MethodUsage functionalMethod = functionalMethodOpt.get(); - - List resolvedTypes = new ArrayList<>(); - - for (ResolvedType type : functionalMethod.getParamTypes()) { - InferenceContext inferenceContext = new InferenceContext(typeSolver); - - // Resolve each type variable of the lambda, and use this later to infer the type of each - // implicit parameter - inferenceContext.addPair(new ReferenceTypeImpl(functionalMethod.declaringType()), lambdaType); - - // Now resolve the argument type using the inference context - ResolvedType argType = inferenceContext.resolve(inferenceContext.addSingle(type)); - - ResolvedLambdaConstraintType conType; - if (argType.isWildcard()) { - conType = ResolvedLambdaConstraintType.bound(argType.asWildcard().getBoundedType()); - } else { - conType = ResolvedLambdaConstraintType.bound(argType); - } + return resolveLambdaTypes(lambdaType); + } - resolvedTypes.add(conType); - } + if (demandParentNode(wrappedNode) instanceof ObjectCreationExpr) { + ObjectCreationExpr objectCreationExpr = (ObjectCreationExpr) demandParentNode(wrappedNode); + ResolvedConstructorDeclaration rcd = JavaParserFacade.get(typeSolver).solve(objectCreationExpr) + .getCorrespondingDeclaration(); + int pos = objectCreationExpr.getArgumentPosition(wrappedNode); + // Since variable parameters are represented by an array, in case we deal with + // the variadic parameter we have to take into account the base type of the + // array. + ResolvedType lambdaType = (rcd.hasVariadicParameter() && pos >= rcd.getNumberOfParams() - 1) ? + rcd.getLastParam().getType().asArrayType().getComponentType() : + rcd.getParam(pos).getType(); - return resolvedTypes; - } - throw new UnsupportedOperationException(); + return resolveLambdaTypes(lambdaType); } + if (demandParentNode(wrappedNode) instanceof VariableDeclarator) { VariableDeclarator variableDeclarator = (VariableDeclarator) demandParentNode(wrappedNode); ResolvedType t = JavaParserFacade.get(typeSolver).convertToUsage(variableDeclarator.getType()); @@ -165,6 +153,7 @@ private List inferArgumentTypes() { } throw new UnsupportedOperationException(); } + if (demandParentNode(wrappedNode) instanceof ReturnStmt) { ReturnStmt returnStmt = (ReturnStmt) demandParentNode(wrappedNode); Optional optDeclaration = returnStmt.findAncestor(MethodDeclaration.class); @@ -198,15 +187,37 @@ private List inferArgumentTypes() { throw new UnsupportedOperationException(); } - private int pos(MethodCallExpr callExpr, Expression param) { - int i = 0; - for (Expression p : callExpr.getArguments()) { - if (p == param) { - return i; + private List resolveLambdaTypes(ResolvedType lambdaType) { + // Get the functional method in order for us to resolve it's type arguments properly + Optional functionalMethodOpt = FunctionalInterfaceLogic.getFunctionalMethod(lambdaType); + if (functionalMethodOpt.isPresent()) { + MethodUsage functionalMethod = functionalMethodOpt.get(); + + List resolvedTypes = new ArrayList<>(); + + for (ResolvedType type : functionalMethod.getParamTypes()) { + InferenceContext inferenceContext = new InferenceContext(typeSolver); + + // Resolve each type variable of the lambda, and use this later to infer the type of each + // implicit parameter + inferenceContext.addPair(new ReferenceTypeImpl(functionalMethod.declaringType()), lambdaType); + + // Now resolve the argument type using the inference context + ResolvedType argType = inferenceContext.resolve(inferenceContext.addSingle(type)); + + ResolvedLambdaConstraintType conType; + if (argType.isWildcard()) { + conType = ResolvedLambdaConstraintType.bound(argType.asWildcard().getBoundedType()); + } else { + conType = ResolvedLambdaConstraintType.bound(argType); + } + + resolvedTypes.add(conType); } - i++; + + return resolvedTypes; } - throw new IllegalArgumentException(); + throw new UnsupportedOperationException(); } } diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/SwitchEntryContext.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/SwitchEntryContext.java index d5dbbd808a..fdc78cced8 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/SwitchEntryContext.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/SwitchEntryContext.java @@ -21,9 +21,9 @@ package com.github.javaparser.symbolsolver.javaparsermodel.contexts; +import com.github.javaparser.ast.nodeTypes.SwitchNode; import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.ast.stmt.SwitchEntry; -import com.github.javaparser.ast.stmt.SwitchStmt; import com.github.javaparser.resolution.SymbolDeclarator; import com.github.javaparser.resolution.TypeSolver; import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; @@ -50,8 +50,8 @@ public SwitchEntryContext(SwitchEntry wrappedNode, TypeSolver typeSolver) { @Override public SymbolReference solveSymbol(String name) { - SwitchStmt switchStmt = (SwitchStmt) demandParentNode(wrappedNode); - ResolvedType type = JavaParserFacade.get(typeSolver).getType(switchStmt.getSelector()); + SwitchNode switchNode = (SwitchNode) demandParentNode(wrappedNode); + ResolvedType type = JavaParserFacade.get(typeSolver).getType(switchNode.getSelector()); if (type.isReferenceType() && type.asReferenceType().getTypeDeclaration().isPresent()) { ResolvedReferenceTypeDeclaration typeDeclaration = type.asReferenceType().getTypeDeclaration().get(); if (typeDeclaration.isEnum()) { @@ -75,7 +75,7 @@ public SymbolReference solveSymbol(String na } // look for declaration in this and previous switch entry statements - for (SwitchEntry seStmt : switchStmt.getEntries()) { + for (SwitchEntry seStmt : switchNode.getEntries()) { for (Statement stmt : seStmt.getStatements()) { SymbolDeclarator symbolDeclarator = JavaParserFactory.getSymbolDeclarator(stmt, typeSolver); SymbolReference symbolReference = solveWith(symbolDeclarator, name); diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumDeclaration.java index e2459891eb..008903c915 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumDeclaration.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserEnumDeclaration.java @@ -122,7 +122,7 @@ public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { if (otherName.equals(this.getQualifiedName())) { return true; } - if (otherName.equals(JAVA_LANG_ENUM)) { + if (JAVA_LANG_ENUM.equals(otherName)) { return true; } // Enum implements Comparable and Serializable @@ -132,10 +132,7 @@ public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { if (otherName.equals(JAVA_IO_SERIALIZABLE)) { return true; } - if (other.isJavaLangObject()) { - return true; - } - return false; + return other.isJavaLangObject(); } @Override @@ -185,9 +182,7 @@ public boolean equals(Object o) { JavaParserEnumDeclaration that = (JavaParserEnumDeclaration) o; - if (!wrappedNode.equals(that.wrappedNode)) return false; - - return true; + return wrappedNode.equals(that.wrappedNode); } @Override @@ -204,10 +199,10 @@ public Optional solveMethodAsUsage(String name, List @Override public SymbolReference solveMethod(String name, List argumentsTypes, boolean staticOnly) { - if (name.equals("values") && argumentsTypes.isEmpty()) { + if ("values".equals(name) && argumentsTypes.isEmpty()) { return SymbolReference.solved(new JavaParserEnumDeclaration.ValuesMethod(this, typeSolver)); } - if (name.equals("valueOf") && argumentsTypes.size() == 1) { + if ("valueOf".equals(name) && argumentsTypes.size() == 1) { ResolvedType argument = argumentsTypes.get(0); if (argument.isReferenceType() && "java.lang.String".equals(argument.asReferenceType().getQualifiedName())) { return SymbolReference.solved(new JavaParserEnumDeclaration.ValueOfMethod(this, typeSolver)); diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeParameter.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeParameter.java index aa86a53013..a175ad7cf6 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeParameter.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javaparsermodel/declarations/JavaParserTypeParameter.java @@ -21,6 +21,11 @@ package com.github.javaparser.symbolsolver.javaparsermodel.declarations; +import static com.github.javaparser.resolution.Navigator.demandParentNode; + +import java.util.*; +import java.util.stream.Collectors; + import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.type.ClassOrInterfaceType; @@ -34,11 +39,6 @@ import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration; -import java.util.*; -import java.util.stream.Collectors; - -import static com.github.javaparser.resolution.Navigator.demandParentNode; - /** * @author Federico Tomassetti @@ -69,9 +69,7 @@ public boolean equals(Object o) { JavaParserTypeParameter that = (JavaParserTypeParameter) o; - if (wrappedNode != null ? !wrappedNode.equals(that.wrappedNode) : that.wrappedNode != null) return false; - - return true; + return wrappedNode != null && wrappedNode.equals(that.wrappedNode); } @Override diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java index e241de948f..f2688e61fc 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistEnumDeclaration.java @@ -127,7 +127,7 @@ public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { if (otherName.equals(this.getQualifiedName())) { return true; } - if (otherName.equals(JAVA_LANG_ENUM)) { + if (JAVA_LANG_ENUM.equals(otherName)) { return true; } // Enum implements Comparable and Serializable @@ -137,10 +137,7 @@ public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { if (otherName.equals(JAVA_IO_SERIALIZABLE)) { return true; } - if (other.isJavaLangObject()) { - return true; - } - return false; + return other.isJavaLangObject(); } @Override diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistTypeParameter.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistTypeParameter.java index b3f6929733..02f325ba15 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistTypeParameter.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/javassistmodel/JavassistTypeParameter.java @@ -21,6 +21,11 @@ package com.github.javaparser.symbolsolver.javassistmodel; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + import com.github.javaparser.resolution.TypeSolver; import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; @@ -28,12 +33,8 @@ import com.github.javaparser.resolution.declarations.ResolvedTypeParametrizable; import com.github.javaparser.resolution.model.typesystem.ReferenceTypeImpl; import com.github.javaparser.resolution.types.ResolvedReferenceType; -import javassist.bytecode.SignatureAttribute; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import javassist.bytecode.SignatureAttribute; /** * @author Federico Tomassetti @@ -60,14 +61,11 @@ public boolean equals(Object o) { if (!getQualifiedName().equals(that.getQualifiedName())) { return false; } - if (declaredOnType() != that.declaredOnType()) { - return false; - } - if (declaredOnMethod() != that.declaredOnMethod()) { - return false; + if (declaredOnType() == that.declaredOnType()) { + return true; } // TODO check bounds - return true; + return declaredOnMethod() == that.declaredOnMethod(); } @Override diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionClassDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionClassDeclaration.java index 48ce4ddf0f..5cec199887 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionClassDeclaration.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionClassDeclaration.java @@ -21,6 +21,13 @@ package com.github.javaparser.symbolsolver.reflectionmodel; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import com.github.javaparser.ast.AccessSpecifier; import com.github.javaparser.ast.Node; import com.github.javaparser.resolution.Context; @@ -39,13 +46,6 @@ import com.github.javaparser.symbolsolver.logic.AbstractClassDeclaration; import com.github.javaparser.symbolsolver.reflectionmodel.comparators.MethodComparator; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.function.Predicate; -import java.util.stream.Collectors; - /** * @author Federico Tomassetti */ @@ -108,9 +108,7 @@ public boolean equals(Object o) { ReflectionClassDeclaration that = (ReflectionClassDeclaration) o; - if (!clazz.getCanonicalName().equals(that.clazz.getCanonicalName())) return false; - - return true; + return clazz.getCanonicalName().equals(that.clazz.getCanonicalName()); } @Override @@ -190,8 +188,8 @@ public SymbolReference solveMethod(String name, List< } // When empty there is no sense in trying to find the most applicable. - // This is useful for debugging. Performance is not affected as - // MethodResolutionLogic.findMostApplicable method returns very early + // This is useful for debugging. Performance is not affected as + // MethodResolutionLogic.findMostApplicable method returns very early // when candidateSolvedMethods is empty. if (candidateSolvedMethods.isEmpty()) { return SymbolReference.unsolved(); @@ -211,6 +209,7 @@ public ResolvedType getUsage(Node node) { return new ReferenceTypeImpl(this); } + @Override public Optional solveMethodAsUsage(String name, List argumentsTypes, Context invokationContext, List typeParameterValues) { List methodUsages = new ArrayList<>(); diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionEnumDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionEnumDeclaration.java index 9a56bc3be3..12546310b3 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionEnumDeclaration.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionEnumDeclaration.java @@ -151,7 +151,7 @@ public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { if (otherName.equals(this.getQualifiedName())) { return true; } - if (otherName.equals(JAVA_LANG_ENUM)) { + if (JAVA_LANG_ENUM.equals(otherName)) { return true; } // Enum implements Comparable and Serializable @@ -161,10 +161,7 @@ public boolean canBeAssignedTo(ResolvedReferenceTypeDeclaration other) { if (otherName.equals(JAVA_IO_SERIALIZABLE)) { return true; } - if (other.isJavaLangObject()) { - return true; - } - return false; + return other.isJavaLangObject(); } @Override diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionInterfaceDeclaration.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionInterfaceDeclaration.java index 7ef1af6731..369c19c18a 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionInterfaceDeclaration.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionInterfaceDeclaration.java @@ -21,6 +21,10 @@ package com.github.javaparser.symbolsolver.reflectionmodel; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + import com.github.javaparser.ast.AccessSpecifier; import com.github.javaparser.ast.Node; import com.github.javaparser.resolution.Context; @@ -40,10 +44,6 @@ import com.github.javaparser.symbolsolver.core.resolution.SymbolResolutionCapability; import com.github.javaparser.symbolsolver.logic.AbstractTypeDeclaration; -import java.lang.reflect.Field; -import java.util.*; -import java.util.stream.Collectors; - /** * @author Federico Tomassetti */ @@ -131,11 +131,7 @@ public boolean equals(Object o) { if (!clazz.getCanonicalName().equals(that.clazz.getCanonicalName())) return false; - if (!getTypeParameters().equals(that.getTypeParameters())) { - return false; - } - - return true; + return getTypeParameters().equals(that.getTypeParameters()); } @Override @@ -143,6 +139,7 @@ public int hashCode() { return clazz.hashCode(); } + @Override public Optional solveMethodAsUsage(String name, List parameterTypes, Context invokationContext, List typeParameterValues) { Optional res = ReflectionMethodResolutionLogic.solveMethodAsUsage(name, parameterTypes, typeSolver, invokationContext, @@ -193,12 +190,8 @@ && new ReflectionInterfaceDeclaration(clazz.getSuperclass(), typeSolver).canBeAs } } - if (other.isJavaLangObject()) { - // Everything can be assigned to {@code java.lang.Object} - return true; - } - - return false; + // Everything can be assigned to {@code java.lang.Object} + return other.isJavaLangObject(); } @Override diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionTypeParameter.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionTypeParameter.java index 29d9d26896..016a02a2af 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionTypeParameter.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/reflectionmodel/ReflectionTypeParameter.java @@ -21,14 +21,6 @@ package com.github.javaparser.symbolsolver.reflectionmodel; -import com.github.javaparser.resolution.TypeSolver; -import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; -import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; -import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; -import com.github.javaparser.resolution.declarations.ResolvedTypeParametrizable; -import com.github.javaparser.resolution.model.typesystem.ReferenceTypeImpl; -import com.github.javaparser.resolution.types.ResolvedReferenceType; - import java.lang.reflect.Constructor; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.Method; @@ -38,6 +30,14 @@ import java.util.Optional; import java.util.stream.Collectors; +import com.github.javaparser.resolution.TypeSolver; +import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration; +import com.github.javaparser.resolution.declarations.ResolvedTypeParametrizable; +import com.github.javaparser.resolution.model.typesystem.ReferenceTypeImpl; +import com.github.javaparser.resolution.types.ResolvedReferenceType; + /** * @author Federico Tomassetti */ @@ -70,14 +70,11 @@ public boolean equals(Object o) { if (!getQualifiedName().equals(that.getQualifiedName())) { return false; } - if (declaredOnType() != that.declaredOnType()) { - return false; - } - if (declaredOnMethod() != that.declaredOnMethod()) { - return false; + if (declaredOnType() == that.declaredOnType()) { + return true; } // TODO check bounds - return true; + return declaredOnMethod() == that.declaredOnMethod(); } @Override diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/naming/NameLogic.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/naming/NameLogic.java index 3ed190549c..3c3b4c9360 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/naming/NameLogic.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/naming/NameLogic.java @@ -592,12 +592,8 @@ private static boolean isSyntacticallyAPackageOrTypeName(Node name) { // 2. In a type-import-on-demand declaration (§7.5.2) - if (whenParentIs(ImportDeclaration.class, name, (p, c) -> - !p.isStatic() && p.isAsterisk() && p.getName() == name)) { - return true; - } - - return false; + return whenParentIs(ImportDeclaration.class, name, (p, c) -> + !p.isStatic() && p.isAsterisk() && p.getName() == name); } private static boolean isSyntacticallyAMethodName(Node name) { @@ -605,11 +601,7 @@ private static boolean isSyntacticallyAMethodName(Node name) { // // 1. Before the "(" in a method invocation expression (§15.12) - if (whenParentIs(MethodCallExpr.class, name, (p, c) -> p.getName() == c)) { - return true; - } - - return false; + return whenParentIs(MethodCallExpr.class, name, (p, c) -> p.getName() == c); } private static boolean isSyntacticallyAModuleName(Node name) { @@ -626,11 +618,8 @@ private static boolean isSyntacticallyAModuleName(Node name) { if (whenParentIs(ModuleExportsDirective.class, name, (p, c) -> p.getModuleNames().contains(name))) { return true; } - if (whenParentIs(ModuleOpensDirective.class, name, (p, c) -> p.getModuleNames().contains(name))) { - return true; - } - return false; + return whenParentIs(ModuleOpensDirective.class, name, (p, c) -> p.getModuleNames().contains(name)); } private static boolean isSyntacticallyAPackageName(Node name) { @@ -644,12 +633,9 @@ private static boolean isSyntacticallyAPackageName(Node name) { return true; } // 2. To the left of the "." in a qualified PackageName - if (whenParentIs(Name.class, name, (p, c) -> p.getQualifier().isPresent() + return whenParentIs(Name.class, name, (p, c) -> p.getQualifier().isPresent() && p.getQualifier().get() == name - && isSyntacticallyAPackageName(p))) { - return true; - } - return false; + && isSyntacticallyAPackageName(p)); } private static boolean isSyntacticallyATypeName(Node name) { diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/ExpressionHelper.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/ExpressionHelper.java deleted file mode 100644 index 011fc80577..0000000000 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/ExpressionHelper.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2015-2016 Federico Tomassetti - * Copyright (C) 2017-2024 The JavaParser Team. - * - * This file is part of JavaParser. - * - * JavaParser can be used either under the terms of - * a) the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * b) the terms of the Apache License - * - * You should have received a copy of both licenses in LICENCE.LGPL and - * LICENCE.APACHE. Please refer to those files for details. - * - * JavaParser is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - */ - -package com.github.javaparser.symbolsolver.resolution.typeinference; - -import com.github.javaparser.ast.expr.Expression; -import com.github.javaparser.ast.expr.LambdaExpr; -import com.github.javaparser.ast.stmt.BlockStmt; -import com.github.javaparser.resolution.TypeSolver; -import com.github.javaparser.resolution.types.ResolvedType; -import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; - -import java.util.List; - -/** - * @author Federico Tomassetti - */ -public class ExpressionHelper { - - public static boolean isExplicitlyTyped(LambdaExpr lambdaExpr) { - return lambdaExpr.getParameters().stream().allMatch(p -> !(p.getType().isUnknownType())); - } - - public static List getResultExpressions(BlockStmt blockStmt) { - throw new UnsupportedOperationException(); - } - - public static boolean isCompatibleInAssignmentContext(Expression expression, ResolvedType type, TypeSolver typeSolver) { - return type.isAssignableBy(JavaParserFacade.get(typeSolver).getType(expression, false)); - } -} diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/TypeHelper.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/TypeHelper.java index 8c08c5dfc9..bdaadaba6c 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/TypeHelper.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/TypeHelper.java @@ -227,7 +227,7 @@ public static Pair groundTargetTypeOfLambda(LambdaExpr la // - If T is a wildcard-parameterized functional interface type and the lambda expression is explicitly typed, // then the ground target type is inferred as described in §18.5.3. - if (ExpressionHelper.isExplicitlyTyped(lambdaExpr)) { + if (lambdaExpr.isExplicitlyTyped()) { used18_5_3 = true; throw new UnsupportedOperationException(); } diff --git a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/constraintformulas/ExpressionCompatibleWithType.java b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/constraintformulas/ExpressionCompatibleWithType.java index c0b541c84d..5c2b763ec3 100644 --- a/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/constraintformulas/ExpressionCompatibleWithType.java +++ b/javaparser-symbol-solver-core/src/main/java/com/github/javaparser/symbolsolver/resolution/typeinference/constraintformulas/ExpressionCompatibleWithType.java @@ -21,9 +21,20 @@ package com.github.javaparser.symbolsolver.resolution.typeinference.constraintformulas; -import com.github.javaparser.ast.expr.*; +import static com.github.javaparser.symbolsolver.resolution.typeinference.TypeHelper.isCompatibleInALooseInvocationContext; +import static com.github.javaparser.symbolsolver.resolution.typeinference.TypeHelper.isProperType; +import static java.util.stream.Collectors.toList; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import com.github.javaparser.ast.expr.ConditionalExpr; +import com.github.javaparser.ast.expr.EnclosedExpr; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.ast.expr.LambdaExpr; import com.github.javaparser.ast.stmt.BlockStmt; -import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.ast.stmt.Statement; import com.github.javaparser.resolution.TypeSolver; @@ -34,15 +45,6 @@ import com.github.javaparser.symbolsolver.resolution.typeinference.*; import com.github.javaparser.utils.Pair; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import static com.github.javaparser.symbolsolver.resolution.typeinference.TypeHelper.isCompatibleInALooseInvocationContext; -import static com.github.javaparser.symbolsolver.resolution.typeinference.TypeHelper.isProperType; -import static java.util.stream.Collectors.toList; - /** * An expression is compatible in a loose invocation context with type T * @@ -86,8 +88,8 @@ public ReductionResult reduce(BoundSet currentBoundSet) { // - If the expression is a parenthesized expression of the form ( Expression' ), the constraint reduces // to ‹Expression' → T›. - if (expression instanceof EnclosedExpr) { - EnclosedExpr enclosedExpr = (EnclosedExpr) expression; + if (expression.isEnclosedExpr()) { + EnclosedExpr enclosedExpr = expression.asEnclosedExpr(); return ReductionResult.oneConstraint(new ExpressionCompatibleWithType(typeSolver, enclosedExpr.getInner(), T)); } @@ -99,20 +101,20 @@ public ReductionResult reduce(BoundSet currentBoundSet) { // This bound set may contain new inference variables, as well as dependencies between these new // variables and the inference variables in T. - if (expression instanceof ObjectCreationExpr) { + if (expression.isObjectCreationExpr()) { BoundSet B3 = new TypeInference(typeSolver).invocationTypeInferenceBoundsSetB3(); return ReductionResult.bounds(B3); } - if (expression instanceof MethodCallExpr) { + if (expression.isMethodCallExpr()) { throw new UnsupportedOperationException(); } // - If the expression is a conditional expression of the form e1 ? e2 : e3, the constraint reduces to two // constraint formulas, ‹e2 → T› and ‹e3 → T›. - if (expression instanceof ConditionalExpr) { - ConditionalExpr conditionalExpr = (ConditionalExpr) expression; + if (expression.isConditionalExpr()) { + ConditionalExpr conditionalExpr = expression.asConditionalExpr(); return ReductionResult.withConstraints( new ExpressionCompatibleWithType(typeSolver, conditionalExpr.getThenExpr(), T), new ExpressionCompatibleWithType(typeSolver, conditionalExpr.getElseExpr(), T)); @@ -123,8 +125,8 @@ public ReductionResult reduce(BoundSet currentBoundSet) { // A constraint formula of the form ‹LambdaExpression → T›, where T mentions at least one inference variable, is reduced as follows: - if (expression instanceof LambdaExpr) { - LambdaExpr lambdaExpr = (LambdaExpr) expression; + if (expression.isLambdaExpr()) { + LambdaExpr lambdaExpr = expression.asLambdaExpr(); // - If T is not a functional interface type (§9.8), the constraint reduces to false. @@ -150,7 +152,7 @@ public ReductionResult reduce(BoundSet currentBoundSet) { // // Federico: THIS SHOULD NOT HAPPEN, IN CASE WE WILL THROW AN EXCEPTION // - // - Otherwise, the congruence of LambdaExpression with the target function type is asserted as + // - Otherwise,) the congruence of LambdaExpression with the target function type is asserted as // follows: // // - If the number of lambda parameters differs from the number of parameter types of the function @@ -176,7 +178,7 @@ public ReductionResult reduce(BoundSet currentBoundSet) { // - If the function type's result is not void and the lambda body is a block that is not // value-compatible, the constraint reduces to false. - if (!targetFunctionType.getReturnType().isVoid() && lambdaExpr.getBody() instanceof BlockStmt + if (!targetFunctionType.getReturnType().isVoid() && lambdaExpr.getBody().isBlockStmt() && !isValueCompatibleBlock(lambdaExpr.getBody())) { return ReductionResult.falseResult(); } @@ -204,16 +206,16 @@ public ReductionResult reduce(BoundSet currentBoundSet) { // - If R is a proper type, and if the lambda body or some result expression in the lambda body // is not compatible in an assignment context with R, then false. - if (lambdaExpr.getBody() instanceof BlockStmt) { - List resultExpressions = ExpressionHelper.getResultExpressions((BlockStmt) lambdaExpr.getBody()); + if (lambdaExpr.getBody().isBlockStmt()) { + List resultExpressions = getResultExpressions(lambdaExpr.getBody().asBlockStmt()); for (Expression e : resultExpressions) { - if (!ExpressionHelper.isCompatibleInAssignmentContext(e, R, typeSolver)) { + if (!isCompatibleInAssignmentContext(e, R, typeSolver)) { return ReductionResult.falseResult(); } } } else { - Expression e = ((ExpressionStmt) lambdaExpr.getBody()).getExpression(); - if (!ExpressionHelper.isCompatibleInAssignmentContext(e, R, typeSolver)) { + Expression e = lambdaExpr.getBody().asExpressionStmt().getExpression(); + if (!isCompatibleInAssignmentContext(e, R, typeSolver)) { return ReductionResult.falseResult(); } } @@ -222,8 +224,8 @@ public ReductionResult reduce(BoundSet currentBoundSet) { // the constraint ‹Expression → R›; or where the lambda body is a block with result // expressions e1, ..., em, for all i (1 ≤ i ≤ m), ‹ei → R›. - if (lambdaExpr.getBody() instanceof BlockStmt) { - getAllReturnExpressions((BlockStmt) lambdaExpr.getBody()).forEach(e -> constraints.add(new ExpressionCompatibleWithType(typeSolver, e, R))); + if (lambdaExpr.getBody().isBlockStmt()) { + getAllReturnExpressions(lambdaExpr.getBody().asBlockStmt()).forEach(e -> constraints.add(new ExpressionCompatibleWithType(typeSolver, e, R))); } else { // FEDERICO: Added - Start for (int i = 0; i < lambdaExpr.getParameters().size(); i++) { @@ -231,7 +233,7 @@ public ReductionResult reduce(BoundSet currentBoundSet) { TypeInferenceCache.addRecord(typeSolver, lambdaExpr, lambdaExpr.getParameter(i).getNameAsString(), paramType); } // FEDERICO: Added - End - Expression e = ((ExpressionStmt) lambdaExpr.getBody()).getExpression(); + Expression e = lambdaExpr.getBody().asExpressionStmt().getExpression(); constraints.add(new ExpressionCompatibleWithType(typeSolver, e, R)); } } @@ -242,7 +244,7 @@ public ReductionResult reduce(BoundSet currentBoundSet) { // A constraint formula of the form ‹MethodReference → T›, where T mentions at least one inference variable, is reduced as follows: - if (expression instanceof MethodReferenceExpr) { + if (expression.isMethodReferenceExpr()) { // - If T is not a functional interface type, or if T is a functional interface type that does not have a function type (§9.9), the constraint reduces to false. // @@ -279,6 +281,14 @@ public ReductionResult reduce(BoundSet currentBoundSet) { throw new RuntimeException("This should not happen"); } + private List getResultExpressions(BlockStmt blockStmt) { + throw new UnsupportedOperationException(); + } + + private boolean isCompatibleInAssignmentContext(Expression expression, ResolvedType type, TypeSolver typeSolver) { + return type.isAssignableBy(JavaParserFacade.get(typeSolver).getType(expression, false)); + } + private List getAllReturnExpressions(BlockStmt blockStmt) { return blockStmt.findAll(ReturnStmt.class).stream() .filter(r -> r.getExpression().isPresent()) @@ -290,7 +300,7 @@ private boolean isValueCompatibleBlock(Statement statement) { // A block lambda body is value-compatible if it cannot complete normally (§14.21) and every return statement // in the block has the form return Expression;. - if (statement instanceof BlockStmt) { + if (statement.isBlockStmt()) { if (!ControlFlowLogic.getInstance().canCompleteNormally(statement)) { return true; } diff --git a/javaparser-symbol-solver-testing/pom.xml b/javaparser-symbol-solver-testing/pom.xml index 54e199ddff..6d5136aea3 100644 --- a/javaparser-symbol-solver-testing/pom.xml +++ b/javaparser-symbol-solver-testing/pom.xml @@ -4,7 +4,7 @@ jmlparser-parent io.github.jmltoolkit - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT 4.0.0 diff --git a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue3878Test.java b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue3878Test.java new file mode 100644 index 0000000000..6a5e269bd9 --- /dev/null +++ b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue3878Test.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013-2024 The JavaParser Team. + * + * This file is part of JavaParser. + * + * JavaParser can be used either under the terms of + * a) the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * b) the terms of the Apache License + * + * You should have received a copy of both licenses in LICENCE.LGPL and + * LICENCE.APACHE. Please refer to those files for details. + * + * JavaParser is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +package com.github.javaparser.symbolsolver; + +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.expr.MethodReferenceExpr; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class Issue3878Test { + + @BeforeEach + void setup() { + JavaSymbolSolver symbolSolver = new JavaSymbolSolver(new ReflectionTypeSolver()); + StaticJavaParser.getParserConfiguration().setSymbolResolver(symbolSolver); + } + + @Test + void resolve_method_reference_in_ObjectCreationExpr() { + String code = "package test;\n" + + "import java.util.function.Consumer;\n" + + "\n" + + "class A {\n" + + "A(Consumer f) {}\n" + + "void bar(int i) {}\n" + + "void foo() { new A(this::bar); }\n" + + "}"; + CompilationUnit cu = StaticJavaParser.parse(code); + MethodReferenceExpr expr = cu.findFirst(MethodReferenceExpr.class).get(); + + ResolvedMethodDeclaration decl = expr.resolve(); + + assertEquals("test.A.bar(int)", decl.getQualifiedSignature()); + } +} diff --git a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue4284Test.java b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue4284Test.java new file mode 100755 index 0000000000..f243d36cb3 --- /dev/null +++ b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue4284Test.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013-2024 The JavaParser Team. + * + * This file is part of JavaParser. + * + * JavaParser can be used either under the terms of + * a) the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * b) the terms of the Apache License + * + * You should have received a copy of both licenses in LICENCE.LGPL and + * LICENCE.APACHE. Please refer to those files for details. + * + * JavaParser is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +package com.github.javaparser.symbolsolver; + +import org.junit.jupiter.api.Test; + +import com.github.javaparser.JavaParser; +import com.github.javaparser.JavaParserAdapter; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.symbolsolver.resolution.AbstractResolutionTest; + +public class Issue4284Test extends AbstractResolutionTest { + + @Test + void test() { + + String code = + "public class SampleCode {\n" + + " public static void main(String... args) {\n" + + " char ch = args[0].charAt(0);\n" + + " int result = switch (ch) {\n" + + " default -> System.out.println(ch);\n" + + " };\n" + + " }\n" + + "}"; + + ParserConfiguration parserConfiguration = new ParserConfiguration() + .setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_17) + .setSymbolResolver(symbolResolver(defaultTypeSolver())); + + CompilationUnit cu = JavaParserAdapter.of(new JavaParser(parserConfiguration)).parse(code); + + cu.findAll(MethodCallExpr.class).forEach(MethodCallExpr::resolve); + + } + +} diff --git a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue4358Test.java b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue4358Test.java new file mode 100644 index 0000000000..6779e229f7 --- /dev/null +++ b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/Issue4358Test.java @@ -0,0 +1,40 @@ +package com.github.javaparser.symbolsolver; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; + +import java.io.IOException; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; + +public class Issue4358Test extends AbstractSymbolResolutionTest { + @Test + public void testIssue4358() throws IOException { + Path issueResourcesPath = adaptPath("src/test/resources/issue4358"); + ReflectionTypeSolver rts = new ReflectionTypeSolver(); + JavaParserTypeSolver jpts = new JavaParserTypeSolver(issueResourcesPath); + CombinedTypeSolver cts = new CombinedTypeSolver(); + cts.add(rts); + cts.add(jpts); + ParserConfiguration pc = new ParserConfiguration() + .setSymbolResolver(new JavaSymbolSolver(cts)); + StaticJavaParser.setConfiguration(pc); + CompilationUnit cu = StaticJavaParser.parse(issueResourcesPath.resolve("foo/A.java")); + + // There's only one method call in this compilation unit + ResolvedMethodDeclaration actual = cu.findAll(MethodCallExpr.class).stream() + .map(MethodCallExpr::resolve) + .findAny().get(); + + assertEquals("foo.B.d()", actual.getQualifiedSignature()); + } +} diff --git a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacadeTest.java b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacadeTest.java index 31a3d416c2..ae387a108c 100644 --- a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacadeTest.java +++ b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/javaparsermodel/JavaParserFacadeTest.java @@ -21,15 +21,22 @@ package com.github.javaparser.symbolsolver.javaparsermodel; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +import com.github.javaparser.JavaParserAdapter; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.resolution.Solver; +import com.github.javaparser.resolution.UnsolvedSymbolException; import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.symbolsolver.resolution.AbstractResolutionTest; import com.github.javaparser.symbolsolver.resolution.SymbolSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - -class JavaParserFacadeTest { +class JavaParserFacadeTest extends AbstractResolutionTest { private final Solver symbolSolver = new SymbolSolver(new ReflectionTypeSolver()); @@ -70,4 +77,25 @@ private enum TestEnum { A, B; } + // issue 3939 + @Test + public void checksThatTheBehaviourIsConsistentInTheEventOfAnUnsolvedSymbol() { + String code = + "import java.util.List;\n" + + "import java.util.stream.Collectors;\n" + + "\n" + + "public class Foo {\n" + + "\n" + + " void m(List> classNames) {\n" + + " classNames.stream().map(c -> c.asSubclass(IMutator.class));\n" + + " }\n" + + "}"; + CompilationUnit cu = JavaParserAdapter.of(createParserWithResolver(defaultTypeSolver())).parse(code); + MethodCallExpr expr = cu.findFirst(MethodCallExpr.class).get(); + // First pass, there must be an UnsolvedSymbolException because the type of the method parameter cannot be resolved + assertThrows(UnsolvedSymbolException.class, () -> expr.getSymbolResolver().calculateType(expr)); + // Second pass, we always want an exception to ensure consistent behaviour + assertThrows(UnsolvedSymbolException.class, () -> expr.getSymbolResolver().calculateType(expr)); + } + } diff --git a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapterTest.java b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapterTest.java index 3e2369d9fb..e4573821a3 100644 --- a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapterTest.java +++ b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/javaparsermodel/contexts/JavaParserTypeDeclarationAdapterTest.java @@ -18,59 +18,95 @@ * GNU Lesser General Public License for more details. */ -package com.github.javaparser.symbolsolver.javaparsermodel.contexts; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.*; - -import com.github.javaparser.JavaParserAdapter; -import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.expr.MethodCallExpr; -import com.github.javaparser.symbolsolver.resolution.AbstractResolutionTest; - -class JavaParserTypeDeclarationAdapterTest extends AbstractResolutionTest { - - @BeforeAll - static void setUpBeforeClass() throws Exception { - } - - @AfterAll - static void tearDownAfterClass() throws Exception { - } - - @BeforeEach - void setUp() throws Exception { - } - - @AfterEach - void tearDownAfterEach() throws Exception { - } - - @Test - void issue3214() { - String code = - "public interface Foo {\n" - + " interface Bar {}\n" - + " }\n" - + "\n" - + " public interface Bar {\n" - + " void show();\n" - + " }\n" - + "\n" - + " public class Test implements Foo.Bar {\n" - + " private Bar bar;\n" - + " private void m() {\n" - + " bar.show();\n" - + " }\n" - + " }"; - - JavaParserAdapter parser = JavaParserAdapter.of(createParserWithResolver(defaultTypeSolver())); - CompilationUnit cu = parser.parse(code); - - MethodCallExpr mce = cu.findAll(MethodCallExpr.class).get(0); - - assertEquals("Bar.show()", mce.resolve().getQualifiedSignature()); - } - -} +package com.github.javaparser.symbolsolver.javaparsermodel.contexts; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.*; + +import com.github.javaparser.JavaParserAdapter; +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.symbolsolver.JavaSymbolSolver; +import com.github.javaparser.symbolsolver.resolution.AbstractResolutionTest; +import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; + +class JavaParserTypeDeclarationAdapterTest extends AbstractResolutionTest { + + @BeforeAll + static void setUpBeforeClass() throws Exception { + } + + @AfterAll + static void tearDownAfterClass() throws Exception { + } + + @BeforeEach + void setUp() throws Exception { + } + + @AfterEach + void tearDownAfterEach() throws Exception { + } + + @Test + void issue3214() { + String code = + "public interface Foo {\n" + + " interface Bar {}\n" + + " }\n" + + "\n" + + " public interface Bar {\n" + + " void show();\n" + + " }\n" + + "\n" + + " public class Test implements Foo.Bar {\n" + + " private Bar bar;\n" + + " private void m() {\n" + + " bar.show();\n" + + " }\n" + + " }"; + + JavaParserAdapter parser = JavaParserAdapter.of(createParserWithResolver(defaultTypeSolver())); + CompilationUnit cu = parser.parse(code); + + MethodCallExpr mce = cu.findAll(MethodCallExpr.class).get(0); + + assertEquals("Bar.show()", mce.resolve().getQualifiedSignature()); + } + + @Test + void issue3946() { + + String code = + "interface Activity {\n" + + "class Timestamps {}\n" + + " Timestamps getTimestamps();\n" + + "}\n" + + "interface RichPresence extends Activity {}\n" + + " class ActivityImpl implements Activity {\n" + + " RichPresence.Timestamps timestamps;\n" + + " @Override\n" + + " public RichPresence.Timestamps getTimestamps() { return timestamps; }\n" + + " }\n" + + "class RichPresenceImpl extends ActivityImpl implements RichPresence { }"; + + final JavaSymbolSolver solver = new JavaSymbolSolver(new ReflectionTypeSolver(false)); + StaticJavaParser.getParserConfiguration().setSymbolResolver(solver); + final CompilationUnit compilationUnit = StaticJavaParser.parse(code); + + final List returnTypes = compilationUnit.findAll(MethodDeclaration.class) + .stream() + .map(md -> md.resolve()) + .map(rmd -> rmd.getReturnType().describe()) + .collect(Collectors.toList()); + + returnTypes.forEach(type -> assertEquals("Activity.Timestamps", type)); + } + +} diff --git a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/model/typesystem/ReferenceTypeTest.java b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/model/typesystem/ReferenceTypeTest.java index 0edd9128ec..3493f4dbc3 100644 --- a/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/model/typesystem/ReferenceTypeTest.java +++ b/javaparser-symbol-solver-testing/src/test/java/com/github/javaparser/symbolsolver/model/typesystem/ReferenceTypeTest.java @@ -21,10 +21,15 @@ package com.github.javaparser.symbolsolver.model.typesystem; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.io.Serializable; @@ -39,7 +44,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.github.javaparser.*; +import com.github.javaparser.JavaParser; +import com.github.javaparser.ParserConfiguration; +import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.resolution.TypeSolver; @@ -811,7 +818,7 @@ void testDeclaredFields() { parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver)); CompilationUnit cu = new JavaParser(parserConfiguration) - .parse(ParseStart.COMPILATION_UNIT, new StringProvider(code)).getResult().get(); + .parse(code).getResult().get(); ClassOrInterfaceDeclaration classA = cu.getClassByName("A").get(); ClassOrInterfaceDeclaration classB = cu.getClassByName("B").get(); @@ -837,7 +844,7 @@ void testGetAllFieldsVisibleToInheritors() { parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver)); CompilationUnit cu = new JavaParser(parserConfiguration) - .parse(ParseStart.COMPILATION_UNIT, new StringProvider(code)).getResult().get(); + .parse(code).getResult().get(); ClassOrInterfaceDeclaration classA = cu.getClassByName("A").get(); ClassOrInterfaceDeclaration classB = cu.getClassByName("B").get(); @@ -876,10 +883,28 @@ void erasure_rawtype() { assertEquals(expected, erasedType.describe()); } + @Test + // The erasure of a parameterized type with bound. + void erasure_type_variable() { + List types = declaredTypes( + "class A {}"); + ResolvedType rt = types.get(0); + String expected = "A"; + assertEquals(expected, rt.erasure().describe()); + } + + @Test + // The erasure of a parameterized type + void erasure_parametrizedType() { + ResolvedType parametrizedType = genericType(Map.class.getCanonicalName(), Integer.class.getCanonicalName(), Integer.class.getCanonicalName()); + String expected = "java.util.Map"; + assertEquals(expected, parametrizedType.erasure().describe()); + } + @Test // The erasure of an array type T[] is |T|[]. void erasure_arraytype() { - // create a type : List + // create a type : List [] ResolvedType genericList = array(genericType(List.class.getCanonicalName(), String.class.getCanonicalName())); String expected = "java.util.List[]"; assertEquals(expected, genericList.erasure().describe()); @@ -888,21 +913,20 @@ void erasure_arraytype() { @Test // The erasure of an array type T[] is |T|[]. void erasure_arraytype_with_bound() { - // create a type : List + // create a type : List [] ResolvedTypeVariable typeArguments = parametrizedType("T", Serializable.class.getCanonicalName()); ResolvedType genericList = array(genericType(List.class.getCanonicalName(), typeArguments)); - String expected = "java.util.List[]"; + String expected = "java.util.List[]"; assertEquals(expected, genericList.erasure().describe()); } @Test - // The erasure of a type variable (§4.4) is the erasure of its leftmost bound. - void erasure_type_variable() { - List types = declaredTypes( - "class A {}"); - ResolvedType rt = types.get(0); - String expected = "A"; - assertEquals(expected, rt.erasure().describe()); + // The erasure of T extends Serializable is the erasure of its leftmost bound. + void erasure_bounded_type_parameter() { + // create a type : T extends Serializable + ResolvedTypeVariable typeArguments = parametrizedType("T", Serializable.class.getCanonicalName()); + String expected = "java.io.Serializable"; + assertEquals(expected, typeArguments.erasure().describe()); } @Test diff --git a/javaparser-symbol-solver-testing/src/test/resources/issue4358/foo/A.java b/javaparser-symbol-solver-testing/src/test/resources/issue4358/foo/A.java new file mode 100644 index 0000000000..dfeaf5ceff --- /dev/null +++ b/javaparser-symbol-solver-testing/src/test/resources/issue4358/foo/A.java @@ -0,0 +1,9 @@ +package foo; + +import static foo.B.d; + +class A { + void c() { + d(); + } +} diff --git a/javaparser-symbol-solver-testing/src/test/resources/issue4358/foo/B.java b/javaparser-symbol-solver-testing/src/test/resources/issue4358/foo/B.java new file mode 100644 index 0000000000..dbafa5726a --- /dev/null +++ b/javaparser-symbol-solver-testing/src/test/resources/issue4358/foo/B.java @@ -0,0 +1,6 @@ +package foo; + +class B extends A { + static void d() { + } +} diff --git a/jmlparser-jml-tests/pom.xml b/jmlparser-jml-tests/pom.xml index a1da4d3771..6f243cb50f 100644 --- a/jmlparser-jml-tests/pom.xml +++ b/jmlparser-jml-tests/pom.xml @@ -2,7 +2,7 @@ jmlparser-parent io.github.jmltoolkit - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 5f2472af37..6cc599f999 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ io.github.jmltoolkit jmlparser-parent pom - 3.25.8-SNAPSHOT + 3.25.10-SNAPSHOT jmlparser-parent https://github.com/wadoon/jmlparser @@ -153,9 +153,9 @@ ${project.basedir}/jmlparser-jml-tests/target/site/jacoco/jacoco.xml, ${project.basedir}/javaparser-core-testing-bdd/target/site/jacoco/jacoco.xml, - 1.14.11 + 1.14.13 -javaagent:${settings.localRepository}/net/bytebuddy/byte-buddy-agent/${byte-buddy.version}/byte-buddy-agent-${byte-buddy.version}.jar - 2024-01-01T00:00:00Z + 2024-04-04T00:00:00Z @@ -208,12 +208,12 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 org.apache.maven.plugins maven-gpg-plugin - 3.1.1 + 3.2.2 org.apache.maven.plugins @@ -272,7 +272,7 @@ org.jacoco jacoco-maven-plugin - 0.8.11 + 0.8.12 org.apache.maven.plugins @@ -300,12 +300,12 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.3 + 3.2.5 org.codehaus.mojo exec-maven-plugin - 3.1.1 + 3.2.0 org.apache.maven.plugins @@ -348,7 +348,7 @@ com.puppycrawl.tools checkstyle - 10.12.7 + 10.15.0 @@ -367,7 +367,7 @@ com.google.guava guava - 33.0.0-jre + 33.1.0-jre junit @@ -390,19 +390,19 @@ org.junit.jupiter junit-jupiter-engine - 5.10.1 + 5.10.2 test org.junit.jupiter junit-jupiter-params - 5.10.1 + 5.10.2 test org.junit.vintage junit-vintage-engine - 5.10.1 + 5.10.2 test @@ -518,7 +518,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.1.0 + 3.2.2 sign-artifacts