From c44358dbdf5dee9544d0db00c2138372032261cb Mon Sep 17 00:00:00 2001 From: Suby S Surendran Date: Tue, 3 Sep 2024 23:30:02 +0530 Subject: [PATCH] Added ASTRewrite support(Unit test & Rewrite) and ASTConverter unit test --- .../core/tests/dom/ASTConverter_23Test.java | 30 +++ ...TRewritingImplicitTypeDeclarationTest.java | 239 ++++++++++++++++++ .../rewrite/describing/ASTRewritingTest.java | 13 + .../dom/org/eclipse/jdt/core/dom/AST.java | 17 ++ .../jdt/core/dom/ImplicitTypeDeclaration.java | 5 + .../internal/core/dom/NaiveASTFlattener.java | 19 ++ .../core/dom/rewrite/ASTRewriteAnalyzer.java | 14 + .../core/dom/rewrite/ASTRewriteFlattener.java | 11 + 8 files changed, 348 insertions(+) create mode 100644 org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingImplicitTypeDeclarationTest.java diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_23Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_23Test.java index f04b6b03bd7..d7a5f1d0cc0 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_23Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter_23Test.java @@ -24,8 +24,12 @@ import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ImplicitTypeDeclaration; import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Modifier; import junit.framework.Test; @@ -109,4 +113,30 @@ void m() { assertEquals("Incorrect name", "java.lang.System.out", imp.getName().toString()); } } + + public void test002() throws CoreException { + String contents = """ + /** */ + void main() { + System.out.println("Eclipse"); + } + """; + this.workingCopy = getWorkingCopy("/Converter_23/src/X.java", true/*resolve*/); + ASTNode node = buildAST(contents, this.workingCopy); + assertEquals("Wrong type of statement", ASTNode.COMPILATION_UNIT, node.getNodeType()); + CompilationUnit compilationUnit = (CompilationUnit) node; + ImplicitTypeDeclaration implicitTypeDeclaration = (ImplicitTypeDeclaration) compilationUnit.types().get(0); + assertEquals("Not an ImplicitTypeDeclaration Type", implicitTypeDeclaration.getNodeType(), ASTNode.UNNAMED_CLASS); + assertEquals("Not an ImplicitTypeDeclaration Name Type", implicitTypeDeclaration.getName().getNodeType(), ASTNode.SIMPLE_NAME); + assertEquals("Identifier is not empty String", implicitTypeDeclaration.getName().getIdentifier(), ""); + MethodDeclaration bodyDeclaration = (MethodDeclaration) implicitTypeDeclaration.bodyDeclarations().get(0); + assertEquals("Not a Method Declaration", bodyDeclaration.getNodeType(), ASTNode.METHOD_DECLARATION); + assertEquals("Method Declaration start is not one", bodyDeclaration.getStartPosition(), 1); + Javadoc javaDoc = bodyDeclaration.getJavadoc(); + assertEquals("Not a JavaDoc", javaDoc.getNodeType(), ASTNode.JAVADOC); + assertEquals("JavaDoc startPosition is not One", javaDoc.getStartPosition(), 1); + Block block = bodyDeclaration.getBody(); + assertEquals("Not a Block", block.getNodeType(), ASTNode.BLOCK); + assertEquals("Block startPosition is not correct", block.getStartPosition(), 21); + } } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingImplicitTypeDeclarationTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingImplicitTypeDeclarationTest.java new file mode 100644 index 00000000000..35192b71b45 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingImplicitTypeDeclarationTest.java @@ -0,0 +1,239 @@ +/******************************************************************************* + * Copyright (c) 2024 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.tests.rewrite.describing; + +import java.util.List; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ExpressionStatement; +import org.eclipse.jdt.core.dom.ImplicitTypeDeclaration; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.PrimitiveType; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.TagElement; +import org.eclipse.jdt.core.dom.TextElement; +import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; +import org.eclipse.jdt.core.dom.rewrite.ListRewrite; + +import junit.framework.Test; + +public class ASTRewritingImplicitTypeDeclarationTest extends ASTRewritingTest{ + + public ASTRewritingImplicitTypeDeclarationTest(String name, int apiLevel) { + super(name, apiLevel); + } + + public static Test suite() { + return createSuite(ASTRewritingImplicitTypeDeclarationTest.class, 23); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + if (this.apiLevel == AST.JLS23 ) { + this.project1.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_23); + this.project1.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_23); + this.project1.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_23); + this.project1.setOption(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED); + } + } + + public void test001() throws Exception { + AST ast = AST.newAST(AST.JLS23, true); + // Create CompilationUnit + CompilationUnit compilationUnit = ast.newCompilationUnit(); + + ImplicitTypeDeclaration implicitTypeDeclaration = ast.newImplicitTypeDeclaration(); + + Javadoc javaDoc= ast.newJavadoc(); + TextElement textElem= ast.newTextElement(); + textElem.setText("Hello"); + TagElement tagElement= ast.newTagElement(); + tagElement.fragments().add(textElem); + javaDoc.tags().add(tagElement); + implicitTypeDeclaration.setJavadoc(javaDoc); + + QualifiedName qualifiedName = ast.newQualifiedName(ast.newName("System"), ast.newSimpleName("out")); + MethodInvocation methodInvocation = ast.newMethodInvocation(); + methodInvocation.setExpression(qualifiedName); + methodInvocation.setName(ast.newSimpleName("println")); + + StringLiteral literal = ast.newStringLiteral(); + literal.setLiteralValue("Eclipse"); + methodInvocation.arguments().add(literal); + ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocation); + + Block block= ast.newBlock(); + block.statements().add(expressionStatement); + MethodDeclaration methodDeclaration = ast.newMethodDeclaration(); + methodDeclaration.setReturnType2(ast.newPrimitiveType(PrimitiveType.VOID)); + methodDeclaration.setName(ast.newSimpleName("main")); + methodDeclaration.setBody(block); + implicitTypeDeclaration.bodyDeclarations().add(methodDeclaration); + // Add Implicity Type class to compilation unit + compilationUnit.types().add(implicitTypeDeclaration); + + StringBuilder buf = new StringBuilder(); + buf.append("/** \n"); + buf.append(" * Hello\n"); + buf.append(" */\n"); + buf.append(" void main(){\n"); + buf.append(" System.out.println(\"Eclipse\");\n"); + buf.append(" }\n"); + + assertEqualString(compilationUnit.toString(), buf.toString()); + } + + //javaDoc + public void test002() throws Exception { + AST ast = AST.newAST(AST.JLS23, true); + IPackageFragment pack1= this.sourceFolder.createPackageFragment("test1", false, null); + StringBuilder buf = new StringBuilder(); + buf= new StringBuilder(); + buf.append("/** \n"); + buf.append(" * Hello\n"); + buf.append(" */\n"); + buf.append("void main(){\n"); + buf.append(" System.out.println(\"Eclipse\");\n"); + buf.append("}\n"); + + ICompilationUnit cu= pack1.createCompilationUnit("X.java", buf.toString(), false, null); + CompilationUnit astRoot= createAST(cu); + ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST()); + + assertTrue("Parse errors", (astRoot.getFlags() & ASTNode.MALFORMED) == 0); + + ImplicitTypeDeclaration implicitTypeDeclaration= findImplicitDeclaration(astRoot, ""); + List methodDeclarationsList = implicitTypeDeclaration.bodyDeclarations(); + MethodDeclaration methodDeclaration = methodDeclarationsList.get(0); + { + + Javadoc javaDoc = methodDeclaration.getJavadoc(); + + Javadoc newJavaDoc= ast.newJavadoc(); + TextElement textElem= ast.newTextElement(); + textElem.setText("Eclipse"); + TagElement tagElement= ast.newTagElement(); + tagElement.fragments().add(textElem); + newJavaDoc.tags().add(tagElement); + + rewrite.replace(javaDoc, newJavaDoc, null); + } + + String preview = evaluateRewrite(cu, rewrite); + buf= new StringBuilder(); + + buf.append("/**\n"); + buf.append(" * Eclipse\n"); + buf.append(" */\n"); + buf.append("void main(){\n"); + buf.append(" System.out.println(\"Eclipse\");\n"); + buf.append("}\n"); + + assertEqualString(preview, buf.toString()); + + { + Javadoc javaDoc = methodDeclaration.getJavadoc(); + Javadoc newJavaDoc = null; + + rewrite.replace(javaDoc, newJavaDoc, null); + } + + preview = evaluateRewrite(cu, rewrite); + buf= new StringBuilder(); + + buf.append("void main(){\n"); + buf.append(" System.out.println(\"Eclipse\");\n"); + buf.append("}\n"); + + assertEqualString(preview, buf.toString()); + } + + //adding more MEthodDeclaration + public void test003() throws Exception { + AST ast = AST.newAST(AST.JLS23, true); + IPackageFragment pack1= this.sourceFolder.createPackageFragment("test1", false, null); + StringBuilder buf = new StringBuilder(); + buf= new StringBuilder(); + buf.append("/** \n"); + buf.append(" * Hello\n"); + buf.append(" */\n"); + buf.append("void main(){\n"); + buf.append(" System.out.println(\"Eclipse\");\n"); + buf.append("}\n"); + + ICompilationUnit cu= pack1.createCompilationUnit("X.java", buf.toString(), false, null); + CompilationUnit astRoot= createAST(cu); + ASTRewrite rewrite= ASTRewrite.create(astRoot.getAST()); + + assertTrue("Parse errors", (astRoot.getFlags() & ASTNode.MALFORMED) == 0); + ImplicitTypeDeclaration implicitTypeDeclaration= findImplicitDeclaration(astRoot, ""); + { + MethodInvocation methodInvocation = ast.newMethodInvocation(); + methodInvocation.setName(ast.newSimpleName("println")); + + StringLiteral literal = ast.newStringLiteral(); + literal.setLiteralValue("abc"); + + QualifiedName qualifiedName = ast.newQualifiedName(ast.newName("System"), ast.newSimpleName("out")); + + methodInvocation.setExpression(qualifiedName); + methodInvocation.arguments().add(literal); + + ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocation); + + Block block = ast.newBlock(); + block.statements().add(expressionStatement); + + MethodDeclaration methodDeclaration = ast.newMethodDeclaration(); + methodDeclaration.setBody(block); + methodDeclaration.setName(ast.newSimpleName("abc")); + methodDeclaration.setReturnType2(ast.newPrimitiveType(PrimitiveType.VOID)); + + ListRewrite listRewrite= rewrite.getListRewrite(implicitTypeDeclaration, ImplicitTypeDeclaration.BODY_DECLARATIONS_PROPERTY); + listRewrite.insertAt(methodDeclaration, 1, null); + } + + String preview = evaluateRewrite(cu, rewrite); + buf= new StringBuilder(); + + buf.append("/** \n"); + buf.append(" * Hello\n"); + buf.append(" */\n"); + buf.append("void main(){\n"); + buf.append(" System.out.println(\"Eclipse\");\n"); + buf.append("}\n"); + buf.append("\n"); + buf.append("void abc() {\n"); + buf.append(" System.out.println(\"abc\");\n"); + buf.append("}\n"); + + assertEqualString(preview, buf.toString()); + } + +} \ No newline at end of file diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingTest.java index 2eca20701bf..323800c8f13 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingTest.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/describing/ASTRewritingTest.java @@ -30,6 +30,7 @@ import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.ImplicitTypeDeclaration; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.PrimitiveType; @@ -170,6 +171,7 @@ public static Test suite() { suite.addTest(ImportRewrite_RecordTest.suite()); suite.addTest(ASTRewritingSuperAfterStatementsTest.suite()); suite.addTest(ASTRewritingEitherOrMultiPatternNodeTest.suite()); + suite.addTest(ASTRewritingImplicitTypeDeclarationTest.suite()); return suite; } @@ -463,4 +465,15 @@ protected static MethodDeclaration createNewMethod(AST ast, String name, boolean return decl; } + public static ImplicitTypeDeclaration findImplicitDeclaration(CompilationUnit astRoot, String simpleTypeName) { + List types= astRoot.types(); + for (int i= 0; i < types.size(); i++) { + ImplicitTypeDeclaration elem= (ImplicitTypeDeclaration) types.get(i); + if (simpleTypeName.equals(elem.getName().getIdentifier())) { + return elem; + } + } + return null; + } + } diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java index 42a00650630..cf358eff45b 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java @@ -3195,6 +3195,23 @@ public TryStatement newTryStatement() { return new TryStatement(this); } + /** + * Creates an unparented class declaration node owned by this AST. + * The name of the class is an unspecified, but legal, name; + * no modifiers; no doc comment; no superclass or superinterfaces; + * and an empty class body. + *

+ * To create an interface, use this method and then call + * ImplicitTypeDeclaration. + *

+ * + * @return a new unparented type declaration node + * @since 3.39 + */ + public ImplicitTypeDeclaration newImplicitTypeDeclaration() { + return new ImplicitTypeDeclaration(this); + } + /** * Creates an unparented class declaration node owned by this AST. * The name of the class is an unspecified, but legal, name; diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ImplicitTypeDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ImplicitTypeDeclaration.java index f15af351d1d..8075e46dc78 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ImplicitTypeDeclaration.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ImplicitTypeDeclaration.java @@ -122,6 +122,11 @@ int treeSize() { return memSize() + this.bodyDeclarations.listSize(); } + @Override + int memSize() { + return BASE_NODE_SIZE + 2 * 4 ; + } + @Override final ChildListPropertyDescriptor internalBodyDeclarationsProperty() { return BODY_DECLARATIONS_PROPERTY; diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java index 80e5ddc2017..cf768bfec1f 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java @@ -1913,6 +1913,25 @@ public boolean visit(TryStatement node) { return false; } + @Override + public boolean visit(ImplicitTypeDeclaration node) { + //javaDoc + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + + //bodyDeclaration + this.indent++; + for (Object element : node.bodyDeclarations()) { + BodyDeclaration d = (BodyDeclaration) element; + d.accept(this); + } + this.indent--; + printIndent(); + + return false; + } + @Override public boolean visit(TypeDeclaration node) { if (node.getJavadoc() != null) { diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java index 7794272dbf0..782e21901a9 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java @@ -1859,6 +1859,20 @@ public boolean visit(CompilationUnit node) { return false; } + @Override + public boolean visit(ImplicitTypeDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + //javaDoc + int pos= rewriteJavadoc(node, ImplicitTypeDeclaration.JAVADOC_PROPERTY); + + int startIndent= getIndent(node.getStartPosition()) + 1; + int startPos= getPosAfterLeftBrace(pos); + rewriteParagraphList(node, ImplicitTypeDeclaration.BODY_DECLARATIONS_PROPERTY, startPos, startIndent, -1, 2); + return false; + } + @Override public boolean visit(TypeDeclaration node) { if (!hasChildrenChanges(node)) { diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java index 256df95e64a..62bc6b2cea2 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java @@ -1210,6 +1210,17 @@ public boolean visit(TryStatement node) { return false; } + @Override + public boolean visit(ImplicitTypeDeclaration node) { + ASTNode javadoc= getChildNode(node, TypeDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + + visitList(node, TypeDeclaration.BODY_DECLARATIONS_PROPERTY, null); + return false; + } + @Override public boolean visit(TypeDeclaration node) { int apiLevel= node.getAST().apiLevel();