diff --git a/src/main/java/spoon/reflect/code/CtComment.java b/src/main/java/spoon/reflect/code/CtComment.java new file mode 100644 index 00000000000..f6563e65b39 --- /dev/null +++ b/src/main/java/spoon/reflect/code/CtComment.java @@ -0,0 +1,33 @@ +/** + * Copyright (C) 2006-2015 INRIA and contributors + * Spoon - http://spoon.gforge.inria.fr/ + * + * This software is governed by the CeCILL-C License under French law and + * abiding by the rules of distribution of free software. You can use, modify + * and/or redistribute the software under the terms of the CeCILL-C license as + * circulated by CEA, CNRS and INRIA at http://www.cecill.info. + * + * This program 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 CeCILL-C License for more details. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. + */ +package spoon.reflect.code; + +import spoon.reflect.declaration.CtElement; + +/** + * This code element defines a comment + * + */ +public interface CtComment extends CtElement { + String getContent(); + + boolean isInline(); + + E setContent(String content); + + E setInline(boolean inline); +} diff --git a/src/main/java/spoon/reflect/declaration/CtElement.java b/src/main/java/spoon/reflect/declaration/CtElement.java index 56332d30e93..d7a04cd54b8 100644 --- a/src/main/java/spoon/reflect/declaration/CtElement.java +++ b/src/main/java/spoon/reflect/declaration/CtElement.java @@ -17,6 +17,7 @@ package spoon.reflect.declaration; import spoon.processing.FactoryAccessor; +import spoon.reflect.code.CtComment; import spoon.reflect.cu.SourcePosition; import spoon.reflect.reference.CtReference; import spoon.reflect.reference.CtTypeReference; @@ -253,4 +254,16 @@ List getAnnotatedChildren( * Returns the metadata keys stored in an element. */ Set getMetadataKeys(); + + E setComments(List comments); + + /** + * The list of comments + * @return the list of comment + */ + List getComments(); + + E addComment(CtComment comment); + + E removeComment(CtComment comment); } diff --git a/src/main/java/spoon/reflect/factory/CoreFactory.java b/src/main/java/spoon/reflect/factory/CoreFactory.java index 61b23bec148..16c32597696 100644 --- a/src/main/java/spoon/reflect/factory/CoreFactory.java +++ b/src/main/java/spoon/reflect/factory/CoreFactory.java @@ -29,6 +29,7 @@ import spoon.reflect.code.CtCatchVariable; import spoon.reflect.code.CtCodeSnippetExpression; import spoon.reflect.code.CtCodeSnippetStatement; +import spoon.reflect.code.CtComment; import spoon.reflect.code.CtConditional; import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtContinue; @@ -443,6 +444,11 @@ SourcePosition createSourcePosition( */ CtCodeSnippetStatement createCodeSnippetStatement(); + /** + * Creates a comment. + */ + CtComment createComment(); + /** * Gets the main factory of that core factory (cannot be null). */ diff --git a/src/main/java/spoon/reflect/visitor/CtAbstractVisitor.java b/src/main/java/spoon/reflect/visitor/CtAbstractVisitor.java index 429024fc482..bb9d5ee3b89 100644 --- a/src/main/java/spoon/reflect/visitor/CtAbstractVisitor.java +++ b/src/main/java/spoon/reflect/visitor/CtAbstractVisitor.java @@ -16,8 +16,6 @@ */ package spoon.reflect.visitor; -import java.lang.annotation.Annotation; - import spoon.reflect.code.CtAnnotationFieldAccess; import spoon.reflect.code.CtArrayRead; import spoon.reflect.code.CtArrayWrite; @@ -31,6 +29,7 @@ import spoon.reflect.code.CtCatchVariable; import spoon.reflect.code.CtCodeSnippetExpression; import spoon.reflect.code.CtCodeSnippetStatement; +import spoon.reflect.code.CtComment; import spoon.reflect.code.CtConditional; import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtContinue; @@ -90,6 +89,8 @@ import spoon.reflect.reference.CtTypeReference; import spoon.reflect.reference.CtUnboundVariableReference; +import java.lang.annotation.Annotation; + /** Provides an empty implementation of CtVIsitor. * See {@link CtScanner} for a much more powerful implementation of CtVisitor. */ @@ -447,4 +448,9 @@ public void visitCtFieldWrite(CtFieldWrite fieldWrite) { public void visitCtSuperAccess(CtSuperAccess f) { } + + @Override + public void visitCtComment(CtComment comment) { + + } } diff --git a/src/main/java/spoon/reflect/visitor/CtInheritanceScanner.java b/src/main/java/spoon/reflect/visitor/CtInheritanceScanner.java index 6a2ccc1d908..70893ae24f4 100644 --- a/src/main/java/spoon/reflect/visitor/CtInheritanceScanner.java +++ b/src/main/java/spoon/reflect/visitor/CtInheritanceScanner.java @@ -33,6 +33,7 @@ import spoon.reflect.code.CtCodeElement; import spoon.reflect.code.CtCodeSnippetExpression; import spoon.reflect.code.CtCodeSnippetStatement; +import spoon.reflect.code.CtComment; import spoon.reflect.code.CtConditional; import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtContinue; @@ -834,6 +835,12 @@ public void visitCtVariableWrite(CtVariableWrite e) { scanCtVisitable(e); } + @Override + public void visitCtComment(CtComment e) { + scanCtElement(e); + scanCtVisitable(e); + } + public void visitCtAnnotationFieldAccess( CtAnnotationFieldAccess e) { visitCtVariableRead(e); diff --git a/src/main/java/spoon/reflect/visitor/CtScanner.java b/src/main/java/spoon/reflect/visitor/CtScanner.java index 6a13bd8f050..dbed9e2b7b8 100644 --- a/src/main/java/spoon/reflect/visitor/CtScanner.java +++ b/src/main/java/spoon/reflect/visitor/CtScanner.java @@ -30,6 +30,7 @@ import spoon.reflect.code.CtCatchVariable; import spoon.reflect.code.CtCodeSnippetExpression; import spoon.reflect.code.CtCodeSnippetStatement; +import spoon.reflect.code.CtComment; import spoon.reflect.code.CtConditional; import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtContinue; @@ -181,6 +182,7 @@ public void visitCtAnnotationType( scan(annotationType.getAnnotations()); scan(annotationType.getNestedTypes()); scan(annotationType.getFields()); + scan(annotationType.getComments()); exit(annotationType); } @@ -188,6 +190,7 @@ public void visitCtAnonymousExecutable(CtAnonymousExecutable anonymousExec) { enter(anonymousExec); scan(anonymousExec.getAnnotations()); scan(anonymousExec.getBody()); + scan(anonymousExec.getComments()); exit(anonymousExec); } @@ -198,6 +201,7 @@ public > void visitCtArrayAccess(CtArrayAccess void visitCtArrayRead(CtArrayRead arrayRead) { scan(arrayRead.getTypeCasts()); scan(arrayRead.getTarget()); scan(arrayRead.getIndexExpression()); + scan(arrayRead.getComments()); exit(arrayRead); } @@ -220,6 +225,7 @@ public void visitCtArrayWrite(CtArrayWrite arrayWrite) { scan(arrayWrite.getTypeCasts()); scan(arrayWrite.getTarget()); scan(arrayWrite.getIndexExpression()); + scan(arrayWrite.getComments()); exit(arrayWrite); } @@ -243,6 +249,7 @@ public void visitCtAssert(CtAssert asserted) { scan(asserted.getAnnotations()); scan(asserted.getAssertExpression()); scan(asserted.getExpression()); + scan(asserted.getComments()); exit(asserted); } @@ -254,6 +261,7 @@ public void visitCtAssignment( scan(assignement.getTypeCasts()); scan(assignement.getAssigned()); scan(assignement.getAssignment()); + scan(assignement.getComments()); exit(assignement); } @@ -264,6 +272,7 @@ public void visitCtBinaryOperator(CtBinaryOperator operator) { scan(operator.getTypeCasts()); scan(operator.getLeftHandOperand()); scan(operator.getRightHandOperand()); + scan(operator.getComments()); exit(operator); } @@ -271,12 +280,14 @@ public void visitCtBlock(CtBlock block) { enter(block); scan(block.getAnnotations()); scan(block.getStatements()); + scan(block.getComments()); exit(block); } public void visitCtBreak(CtBreak breakStatement) { enter(breakStatement); scan(breakStatement.getAnnotations()); + scan(breakStatement.getComments()); exit(breakStatement); } @@ -285,6 +296,7 @@ public void visitCtCase(CtCase caseStatement) { scan(caseStatement.getAnnotations()); scan(caseStatement.getCaseExpression()); scan(caseStatement.getStatements()); + scan(caseStatement.getComments()); exit(caseStatement); } @@ -293,6 +305,7 @@ public void visitCtCatch(CtCatch catchBlock) { scan(catchBlock.getAnnotations()); scan(catchBlock.getParameter()); scan(catchBlock.getBody()); + scan(catchBlock.getComments()); exit(catchBlock); } @@ -307,6 +320,7 @@ public void visitCtClass(CtClass ctClass) { scan(ctClass.getFields()); scan(ctClass.getConstructors()); scan(ctClass.getMethods()); + scan(ctClass.getComments()); exit(ctClass); } @@ -316,6 +330,7 @@ public void visitCtConditional(CtConditional conditional) { scan(conditional.getCondition()); scan(conditional.getThenExpression()); scan(conditional.getElseExpression()); + scan(conditional.getComments()); exit(conditional); } @@ -326,6 +341,7 @@ public void visitCtConstructor(CtConstructor c) { scan(c.getThrownTypes()); scan(c.getFormalTypeParameters()); scan(c.getBody()); + scan(c.getComments()); exit(c); } @@ -333,6 +349,7 @@ public void visitCtContinue(CtContinue continueStatement) { enter(continueStatement); scan(continueStatement.getAnnotations()); scan(continueStatement.getLabelledStatement()); + scan(continueStatement.getComments()); exit(continueStatement); } @@ -341,6 +358,7 @@ public void visitCtDo(CtDo doLoop) { scan(doLoop.getAnnotations()); scan(doLoop.getLoopingExpression()); scan(doLoop.getBody()); + scan(doLoop.getComments()); exit(doLoop); } @@ -352,6 +370,7 @@ public > void visitCtEnum(CtEnum ctEnum) { scan(ctEnum.getConstructors()); scan(ctEnum.getMethods()); scan(ctEnum.getNestedTypes()); + scan(ctEnum.getComments()); exit(ctEnum); } @@ -362,6 +381,7 @@ public void visitCtExecutableReference( scan(reference.getType()); scan(reference.getActualTypeArguments()); scan(reference.getAnnotations()); + scan(reference.getComments()); exit(reference); } @@ -370,6 +390,7 @@ public void visitCtField(CtField f) { scan(f.getAnnotations()); scan(f.getType()); scan(f.getDefaultExpression()); + scan(f.getComments()); exit(f); } @@ -379,6 +400,7 @@ public void visitCtEnumValue(CtEnumValue enumValue) { scan(enumValue.getAnnotations()); scan(enumValue.getType()); scan(enumValue.getDefaultExpression()); + scan(enumValue.getComments()); exit(enumValue); } @@ -388,6 +410,7 @@ public void visitCtThisAccess(CtThisAccess thisAccess) { scan(thisAccess.getType()); scan(thisAccess.getTypeCasts()); scan(thisAccess.getTarget()); + scan(thisAccess.getComments()); exit(thisAccess); } @@ -399,6 +422,7 @@ public void visitCtAnnotationFieldAccess( scan(annotationFieldAccess.getTypeCasts()); scan(annotationFieldAccess.getTarget()); scan(annotationFieldAccess.getVariable()); + scan(annotationFieldAccess.getComments()); exit(annotationFieldAccess); } @@ -417,6 +441,7 @@ public void visitCtFor(CtFor forLoop) { scan(forLoop.getExpression()); scan(forLoop.getForUpdate()); scan(forLoop.getBody()); + scan(forLoop.getComments()); exit(forLoop); } @@ -426,6 +451,7 @@ public void visitCtForEach(CtForEach foreach) { scan(foreach.getVariable()); scan(foreach.getExpression()); scan(foreach.getBody()); + scan(foreach.getComments()); exit(foreach); } @@ -435,6 +461,7 @@ public void visitCtIf(CtIf ifElement) { scan(ifElement.getCondition()); scan((CtStatement) ifElement.getThenStatement()); scan((CtStatement) ifElement.getElseStatement()); + scan(ifElement.getComments()); exit(ifElement); } @@ -446,6 +473,7 @@ public void visitCtInterface(CtInterface intrface) { scan(intrface.getNestedTypes()); scan(intrface.getFields()); scan(intrface.getMethods()); + scan(intrface.getComments()); exit(intrface); } @@ -456,6 +484,7 @@ public void visitCtInvocation(CtInvocation invocation) { scan(invocation.getTarget()); scan(invocation.getExecutable()); scan(invocation.getArguments()); + scan(invocation.getComments()); exit(invocation); } @@ -465,6 +494,7 @@ public void visitCtLiteral(CtLiteral literal) { scan(literal.getType()); scan(literal.getValue()); scan(literal.getTypeCasts()); + scan(literal.getComments()); exit(literal); } @@ -473,6 +503,7 @@ public void visitCtLocalVariable(CtLocalVariable localVariable) { scan(localVariable.getAnnotations()); scan(localVariable.getType()); scan(localVariable.getDefaultExpression()); + scan(localVariable.getComments()); exit(localVariable); } @@ -488,6 +519,7 @@ public void visitCtCatchVariable(CtCatchVariable catchVariable) { enter(catchVariable); scan(catchVariable.getAnnotations()); scan(catchVariable.getType()); + scan(catchVariable.getComments()); exit(catchVariable); } @@ -506,6 +538,7 @@ public void visitCtMethod(CtMethod m) { scan(m.getParameters()); scan(m.getThrownTypes()); scan(m.getBody()); + scan(m.getComments()); exit(m); } @@ -516,6 +549,7 @@ public void visitCtNewArray(CtNewArray newArray) { scan(newArray.getTypeCasts()); scan(newArray.getElements()); scan(newArray.getDimensionExpressions()); + scan(newArray.getComments()); exit(newArray); } @@ -527,6 +561,7 @@ public void visitCtConstructorCall(CtConstructorCall ctConstructorCall) { scan(ctConstructorCall.getExecutable()); scan(ctConstructorCall.getTarget()); scan(ctConstructorCall.getArguments()); + scan(ctConstructorCall.getComments()); exit(ctConstructorCall); } @@ -539,6 +574,7 @@ public void visitCtNewClass(CtNewClass newClass) { scan(newClass.getTarget()); scan(newClass.getArguments()); scan(newClass.getAnonymousClass()); + scan(newClass.getComments()); exit(newClass); } @@ -551,6 +587,7 @@ public void visitCtLambda(CtLambda lambda) { scan(lambda.getParameters()); scan(lambda.getBody()); scan(lambda.getExpression()); + scan(lambda.getComments()); exit(lambda); } @@ -573,6 +610,7 @@ public void visitCtOperatorAssignment( scan(assignment.getTypeCasts()); scan(assignment.getAssigned()); scan(assignment.getAssignment()); + scan(assignment.getComments()); exit(assignment); } @@ -581,6 +619,7 @@ public void visitCtPackage(CtPackage ctPackage) { scan(ctPackage.getAnnotations()); scan(ctPackage.getPackages()); scan(ctPackage.getTypes()); + scan(ctPackage.getComments()); exit(ctPackage); } @@ -593,6 +632,7 @@ public void visitCtParameter(CtParameter parameter) { enter(parameter); scan(parameter.getAnnotations()); scan(parameter.getType()); + scan(parameter.getComments()); exit(parameter); } @@ -607,6 +647,7 @@ public void visitCtReturn(CtReturn returnStatement) { enter(returnStatement); scan(returnStatement.getAnnotations()); scan(returnStatement.getReturnedExpression()); + scan(returnStatement.getComments()); exit(returnStatement); } @@ -614,6 +655,7 @@ public void visitCtStatementList(CtStatementList statements) { enter(statements); scan(statements.getAnnotations()); scan(statements.getStatements()); + scan(statements.getComments()); exit(statements); } @@ -622,6 +664,7 @@ public void visitCtSwitch(CtSwitch switchStatement) { scan(switchStatement.getAnnotations()); scan(switchStatement.getSelector()); scan(switchStatement.getCases()); + scan(switchStatement.getComments()); exit(switchStatement); } @@ -630,6 +673,7 @@ public void visitCtSynchronized(CtSynchronized synchro) { scan(synchro.getAnnotations()); scan(synchro.getExpression()); scan(synchro.getBlock()); + scan(synchro.getComments()); exit(synchro); } @@ -637,6 +681,7 @@ public void visitCtThrow(CtThrow throwStatement) { enter(throwStatement); scan(throwStatement.getAnnotations()); scan(throwStatement.getThrownExpression()); + scan(throwStatement.getComments()); exit(throwStatement); } @@ -646,6 +691,7 @@ public void visitCtTry(CtTry tryBlock) { scan(tryBlock.getBody()); scan(tryBlock.getCatchers()); scan(tryBlock.getFinalizer()); + scan(tryBlock.getComments()); exit(tryBlock); } @@ -657,6 +703,7 @@ public void visitCtTryWithResource(CtTryWithResource tryWithResource) { scan(tryWithResource.getBody()); scan(tryWithResource.getCatchers()); scan(tryWithResource.getFinalizer()); + scan(tryWithResource.getComments()); exit(tryWithResource); } @@ -683,6 +730,7 @@ public void visitCtTypeReference(CtTypeReference reference) { scan(reference.getDeclaringType()); scan(reference.getActualTypeArguments()); scan(reference.getAnnotations()); + scan(reference.getComments()); exit(reference); } @@ -704,6 +752,7 @@ public void visitCtTypeAccess(CtTypeAccess typeAccess) { scan(typeAccess.getType()); scan(typeAccess.getTypeCasts()); scan(typeAccess.getAccessedType()); + scan(typeAccess.getComments()); exit(typeAccess); } @@ -713,6 +762,7 @@ public void visitCtUnaryOperator(CtUnaryOperator operator) { scan(operator.getType()); scan(operator.getTypeCasts()); scan(operator.getOperand()); + scan(operator.getComments()); exit(operator); } @@ -723,6 +773,7 @@ public void visitCtVariableRead(CtVariableRead variableRead) { scan(variableRead.getType()); scan(variableRead.getTypeCasts()); scan(variableRead.getVariable()); + scan(variableRead.getComments()); exit(variableRead); } @@ -733,6 +784,7 @@ public void visitCtVariableWrite(CtVariableWrite variableWrite) { scan(variableWrite.getType()); scan(variableWrite.getTypeCasts()); scan(variableWrite.getVariable()); + scan(variableWrite.getComments()); exit(variableWrite); } @@ -741,6 +793,7 @@ public void visitCtWhile(CtWhile whileLoop) { scan(whileLoop.getAnnotations()); scan(whileLoop.getLoopingExpression()); scan(whileLoop.getBody()); + scan(whileLoop.getComments()); exit(whileLoop); } @@ -766,6 +819,7 @@ public void visitCtFieldRead(CtFieldRead fieldRead) { scan(fieldRead.getTypeCasts()); scan(fieldRead.getTarget()); scan(fieldRead.getVariable()); + scan(fieldRead.getComments()); exit(fieldRead); } @@ -776,6 +830,7 @@ public void visitCtFieldWrite(CtFieldWrite fieldWrite) { scan(fieldWrite.getTypeCasts()); scan(fieldWrite.getTarget()); scan(fieldWrite.getVariable()); + scan(fieldWrite.getComments()); exit(fieldWrite); } @@ -786,6 +841,13 @@ public void visitCtSuperAccess(CtSuperAccess f) { scan(f.getType()); scan(f.getTypeCasts()); scan(f.getTarget()); + scan(f.getComments()); exit(f); } + + @Override + public void visitCtComment(CtComment comment) { + enter(comment); + exit(comment); + } } diff --git a/src/main/java/spoon/reflect/visitor/CtVisitor.java b/src/main/java/spoon/reflect/visitor/CtVisitor.java index 3285ed6ff3b..1350e43fd05 100644 --- a/src/main/java/spoon/reflect/visitor/CtVisitor.java +++ b/src/main/java/spoon/reflect/visitor/CtVisitor.java @@ -29,6 +29,7 @@ import spoon.reflect.code.CtCatchVariable; import spoon.reflect.code.CtCodeSnippetExpression; import spoon.reflect.code.CtCodeSnippetStatement; +import spoon.reflect.code.CtComment; import spoon.reflect.code.CtConditional; import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtContinue; @@ -448,4 +449,9 @@ void visitCtOperatorAssignment( * Visits an access to a super invocation. */ void visitCtSuperAccess(CtSuperAccess f); + + /** + * Visits a comment + */ + void visitCtComment(CtComment comment); } diff --git a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java index e44f0e7ffa5..2000bedbc06 100644 --- a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java +++ b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java @@ -34,6 +34,7 @@ import spoon.reflect.code.CtCodeElement; import spoon.reflect.code.CtCodeSnippetExpression; import spoon.reflect.code.CtCodeSnippetStatement; +import spoon.reflect.code.CtComment; import spoon.reflect.code.CtConditional; import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtContinue; @@ -681,6 +682,10 @@ public void visitCtBinaryOperator(CtBinaryOperator operator) { public void visitCtBlock(CtBlock block) { enterCtStatement(block); write("{").incTab(); + for (CtComment comment : block.getComments()) { + writeln().writeTabs(); + scan(comment); + } for (CtStatement e : block.getStatements()) { if (!e.isImplicit()) { writeln().writeTabs(); @@ -795,6 +800,7 @@ public void visitCtClass(CtClass ctClass) { lst.addAll(ctClass.getNestedTypes()); lst.addAll(ctClass.getFields()); lst.addAll(ctClass.getMethods()); + lst.addAll(ctClass.getComments()); if ((ctClass.getSimpleName() == null || ctClass.getSimpleName().isEmpty()) && ctClass.getParent() != null && ctClass.getParent() instanceof CtNewClass) { context.currentThis.push(((CtNewClass) ctClass.getParent()).getType()); @@ -1079,6 +1085,11 @@ public void visitCtSuperAccess(CtSuperAccess f) { exitCtExpression(f); } + @Override + public void visitCtComment(CtComment comment) { + write(comment.getContent()); + } + public void visitCtAnnotationFieldAccess(CtAnnotationFieldAccess annotationFieldAccess) { enterCtExpression(annotationFieldAccess); if (annotationFieldAccess.getTarget() != null) { @@ -2270,6 +2281,12 @@ protected void writeParameters(Collection> params) { * Writes a statement. */ protected void writeStatement(CtStatement e) { + if (e != null) { + for (CtComment comment : e.getComments()) { + scan(comment); + writeln().writeTabs(); + } + } scan(e); if (!((e instanceof CtBlock) || (e instanceof CtIf) || (e instanceof CtFor) || (e instanceof CtForEach) || (e instanceof CtWhile) || (e instanceof CtTry) || (e instanceof CtSwitch) || (e instanceof CtSynchronized) || (e instanceof CtClass))) { diff --git a/src/main/java/spoon/support/DefaultCoreFactory.java b/src/main/java/spoon/support/DefaultCoreFactory.java index 7e21e6e167a..1dd6f5f2a6b 100644 --- a/src/main/java/spoon/support/DefaultCoreFactory.java +++ b/src/main/java/spoon/support/DefaultCoreFactory.java @@ -30,6 +30,7 @@ import spoon.reflect.code.CtCatchVariable; import spoon.reflect.code.CtCodeSnippetExpression; import spoon.reflect.code.CtCodeSnippetStatement; +import spoon.reflect.code.CtComment; import spoon.reflect.code.CtConditional; import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtContinue; @@ -103,6 +104,7 @@ import spoon.support.reflect.code.CtCatchVariableImpl; import spoon.support.reflect.code.CtCodeSnippetExpressionImpl; import spoon.support.reflect.code.CtCodeSnippetStatementImpl; +import spoon.support.reflect.code.CtCommentImpl; import spoon.support.reflect.code.CtConditionalImpl; import spoon.support.reflect.code.CtConstructorCallImpl; import spoon.support.reflect.code.CtContinueImpl; @@ -658,6 +660,12 @@ public CtCodeSnippetStatement createCodeSnippetStatement() { return e; } + public CtComment createComment() { + CtComment e = new CtCommentImpl(); + e.setFactory(getMainFactory()); + return e; + } + public CtWhile createWhile() { CtWhile e = new CtWhileImpl(); e.setFactory(getMainFactory()); diff --git a/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java b/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java index 093eb17fbf2..f0a6da917cd 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTBasedSpoonCompiler.java @@ -20,9 +20,11 @@ import org.apache.commons.io.IOUtils; import org.apache.log4j.Level; import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.batch.Main; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.env.INameEnvironment; import spoon.Launcher; import spoon.OutputType; @@ -43,10 +45,12 @@ import spoon.compiler.builder.SourceOptions; import spoon.processing.ProcessingManager; import spoon.processing.Processor; +import spoon.reflect.code.CtComment; import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtPackage; import spoon.reflect.declaration.CtType; import spoon.reflect.factory.Factory; +import spoon.reflect.visitor.CtScanner; import spoon.reflect.visitor.DefaultJavaPrettyPrinter; import spoon.reflect.visitor.Filter; import spoon.reflect.visitor.PrettyPrinter; @@ -429,16 +433,72 @@ protected boolean buildSources(JDTBuilder jdtBuilder) { } } CompilationUnitDeclaration[] units = batchCompiler.getUnits(filesToBuild); - // here we build the model JDTTreeBuilder builder = new JDTTreeBuilder(factory); - for (CompilationUnitDeclaration unit : units) { + for (int i = 0; i < units.length; i++) { + CompilationUnitDeclaration unit = units[i]; unit.traverse(builder, unit.scope); + buildComment(unit, factory); } return probs.size() == 0; } + private void buildComment(CompilationUnitDeclaration declarationUnit, Factory factory) { + if (declarationUnit.comments == null) { + return; + } + ICompilationUnit sourceUnit = declarationUnit.compilationResult.compilationUnit; + char[] contents = sourceUnit.getContents(); + for (int j = 0; j < declarationUnit.comments.length; j++) { + int[] positions = declarationUnit.comments[j]; + int start = positions[0]; + final int end = -positions[1]; + + boolean isInline = false; + if (start < 0) { + isInline = true; + start = -start; + } + // Javadoc comments have positive end position + if (end <= 0) { + continue; + } + String content = ""; + for (int f = start; f < end; f++) { + content += contents[f]; + } + CtComment comment = factory.Core().createComment(); + comment.setContent(content.trim()); + comment.setInline(isInline); + String filePath = CharOperation.charToString(sourceUnit.getFileName()); + spoon.reflect.cu.CompilationUnit spoonUnit = factory.CompilationUnit().create(filePath); + comment.setPosition(getFactory().Core().createSourcePosition( + spoonUnit, start, start, end, declarationUnit.compilationResult.lineSeparatorPositions)); + final int finalStart = start; + final CtElement[] last = { null }; + CtScanner ctScanner = new CtScanner() { + + @Override + public void scan(CtElement element) { + if (element != null + && element.getPosition() != null + && element.getPosition().getSourceStart() <= finalStart + && element.getPosition().getSourceEnd() >= end) { + last[0] = element; + element.accept(this); + } + } + }; + ctScanner.scan(spoonUnit.getDeclaredTypes()); + if (last[0] == null) { + spoonUnit.getDeclaredTypes().get(0).addComment(comment); + } else { + last[0].addComment(comment); + } + } + } + protected boolean buildTemplates(JDTBuilder jdtBuilder) { if (templates.getAllJavaFiles().isEmpty()) { return true; @@ -479,8 +539,10 @@ protected boolean buildTemplates(JDTBuilder jdtBuilder) { // here we build the model in the template factory JDTTreeBuilder builder = new JDTTreeBuilder(factory); - for (CompilationUnitDeclaration unit : units) { + for (int i = 0; i < units.length; i++) { + CompilationUnitDeclaration unit = units[i]; unit.traverse(builder, unit.scope); + buildComment(unit, factory); } return probs.size() == 0; diff --git a/src/main/java/spoon/support/compiler/jdt/JDTBatchCompiler.java b/src/main/java/spoon/support/compiler/jdt/JDTBatchCompiler.java index b85c1db372c..2f4dbc33a09 100644 --- a/src/main/java/spoon/support/compiler/jdt/JDTBatchCompiler.java +++ b/src/main/java/spoon/support/compiler/jdt/JDTBatchCompiler.java @@ -20,17 +20,23 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import org.apache.commons.io.IOUtils; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.ICompilerRequestor; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.batch.CompilationUnit; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; import org.eclipse.jdt.internal.compiler.env.INameEnvironment; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.core.util.CommentRecorderParser; import spoon.Launcher; import spoon.compiler.SpoonFile; @@ -135,6 +141,26 @@ this.jdtCompiler.requestor, getProblemFactory(), this.out, null); CompilationUnitDeclaration[] units = treeBuilderCompiler .buildUnits(getCompilationUnits(files)); + for (int i = 0; i < units.length; i++) { + CompilationUnitDeclaration unit = units[i]; + CommentRecorderParser parser = + new CommentRecorderParser( + new ProblemReporter( + DefaultErrorHandlingPolicies.proceedWithAllProblems(), + compilerOptions, + new DefaultProblemFactory(Locale.getDefault())), + false); + ICompilationUnit sourceUnit = + new CompilationUnit( + getCompilationUnits()[i].getContents(), + "", //$NON-NLS-1$ + compilerOptions.defaultEncoding); + final CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit); + CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult); + unit.comments = compilationUnitDeclaration.comments; + } + + return units; } diff --git a/src/main/java/spoon/support/reflect/code/CtCommentImpl.java b/src/main/java/spoon/support/reflect/code/CtCommentImpl.java new file mode 100644 index 00000000000..a7e49b1f50e --- /dev/null +++ b/src/main/java/spoon/support/reflect/code/CtCommentImpl.java @@ -0,0 +1,56 @@ +/** + * Copyright (C) 2006-2015 INRIA and contributors + * Spoon - http://spoon.gforge.inria.fr/ + * + * This software is governed by the CeCILL-C License under French law and + * abiding by the rules of distribution of free software. You can use, modify + * and/or redistribute the software under the terms of the CeCILL-C license as + * circulated by CEA, CNRS and INRIA at http://www.cecill.info. + * + * This program 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 CeCILL-C License for more details. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. + */ +package spoon.support.reflect.code; + +import spoon.reflect.code.CtComment; +import spoon.reflect.visitor.CtVisitor; +import spoon.support.reflect.declaration.CtElementImpl; + +public class CtCommentImpl extends CtElementImpl implements CtComment { + private static final long serialVersionUID = 1L; + + private String content; + + private boolean isInline; + + @Override + public String getContent() { + return content; + } + + @Override + public E setContent(String content) { + this.content = content; + return (E) this; + } + + @Override + public boolean isInline() { + return isInline; + } + + @Override + public E setInline(boolean inline) { + isInline = inline; + return (E) this; + } + + @Override + public void accept(CtVisitor visitor) { + visitor.visitCtComment(this); + } +} diff --git a/src/main/java/spoon/support/reflect/declaration/CtAnonymousExecutableImpl.java b/src/main/java/spoon/support/reflect/declaration/CtAnonymousExecutableImpl.java index ec93c7152ec..95256b313f1 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtAnonymousExecutableImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtAnonymousExecutableImpl.java @@ -154,7 +154,7 @@ public T setSimpleName(String simpleName) { @Override public CtTypeReference getType() { - return factory.Type().VOID_PRIMITIVE; + return getFactory().Type().VOID_PRIMITIVE; } @Override diff --git a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java index f1a8efc7714..5bae2243a83 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtElementImpl.java @@ -16,23 +16,10 @@ */ package spoon.support.reflect.declaration; -import static spoon.reflect.ModelElementContainerDefaultCapacities.ANNOTATIONS_CONTAINER_DEFAULT_CAPACITY; - -import java.io.Serializable; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - import org.apache.log4j.Logger; - import spoon.Launcher; import spoon.processing.FactoryAccessor; +import spoon.reflect.code.CtComment; import spoon.reflect.cu.SourcePosition; import spoon.reflect.declaration.CtAnnotation; import spoon.reflect.declaration.CtElement; @@ -54,6 +41,19 @@ import spoon.support.visitor.SignaturePrinter; import spoon.support.visitor.TypeReferenceScanner; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static spoon.reflect.ModelElementContainerDefaultCapacities.ANNOTATIONS_CONTAINER_DEFAULT_CAPACITY; + /** * Contains the default implementation of most CtElement methods. * @@ -64,6 +64,8 @@ public abstract class CtElementImpl implements CtElement, Serializable, Comparab protected static final Logger LOGGER = Logger.getLogger(CtElementImpl.class); public static final String ERROR_MESSAGE_TO_STRING = "Error in printing the node. One parent isn't initialized!"; + private List comments = new ArrayList(); + // we don't use Collections.unmodifiableList and Collections.unmodifiableSet // because we need clear() for all set* methods // and UnmodifiableList and unmodifiableCollection are not overridable (not visible grrrr) @@ -496,4 +498,32 @@ public Object getMetadata(String key) { public Set getMetadataKeys() { return metadata.keySet(); } + + + @Override + public List getComments() { + return Collections.unmodifiableList(comments); + } + + @Override + public E addComment(CtComment comment) { + comments.add(comment); + comment.setParent(this); + return (E) this; + } + + @Override + public E removeComment(CtComment comment) { + comments.remove(comment); + return (E) this; + } + + @Override + public E setComments(List comments) { + this.comments = new ArrayList(); + for (CtComment comment : comments) { + this.addComment(comment); + } + return (E) this; + } } diff --git a/src/main/java/spoon/support/reflect/eval/VisitorPartialEvaluator.java b/src/main/java/spoon/support/reflect/eval/VisitorPartialEvaluator.java index e761ffb5441..adfbe1f77b4 100644 --- a/src/main/java/spoon/support/reflect/eval/VisitorPartialEvaluator.java +++ b/src/main/java/spoon/support/reflect/eval/VisitorPartialEvaluator.java @@ -32,6 +32,7 @@ import spoon.reflect.code.CtCodeElement; import spoon.reflect.code.CtCodeSnippetExpression; import spoon.reflect.code.CtCodeSnippetStatement; +import spoon.reflect.code.CtComment; import spoon.reflect.code.CtConditional; import spoon.reflect.code.CtConstructorCall; import spoon.reflect.code.CtContinue; @@ -742,6 +743,11 @@ public void visitCtImplicitTypeReference(CtImplicitTypeReference referenc throw new RuntimeException("Unknow Element"); } + @Override + public void visitCtComment(CtComment comment) { + throw new RuntimeException("Unknow Element"); + } + @Override public void visitCtTypeAccess(CtTypeAccess typeAccess) { throw new RuntimeException("Unknown Element"); diff --git a/src/main/java/spoon/template/TemplateMatcher.java b/src/main/java/spoon/template/TemplateMatcher.java index a658ea6a65e..b596ce51de1 100644 --- a/src/main/java/spoon/template/TemplateMatcher.java +++ b/src/main/java/spoon/template/TemplateMatcher.java @@ -16,17 +16,6 @@ */ package spoon.template; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import spoon.Launcher; import spoon.reflect.code.CtFieldAccess; import spoon.reflect.code.CtInvocation; @@ -53,6 +42,17 @@ import spoon.support.template.Parameters; import spoon.support.util.RtHelper; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * This class defines an engine for matching a template to pieces of code. */ @@ -365,6 +365,12 @@ private boolean helperMatch(Object target, Object template) { if (f.getName().equals("factory")) { continue; } + if (f.getName().equals("comments")) { + continue; + } + if (f.getName().equals("metadata")) { + continue; + } try { if (!helperMatch(f.get(target), f.get(template))) { return false; diff --git a/src/test/java/spoon/test/prettyprinter/LinesTest.java b/src/test/java/spoon/test/prettyprinter/LinesTest.java index 5c231a2ca33..8ece721416e 100644 --- a/src/test/java/spoon/test/prettyprinter/LinesTest.java +++ b/src/test/java/spoon/test/prettyprinter/LinesTest.java @@ -1,16 +1,15 @@ package spoon.test.prettyprinter; -import static org.junit.Assert.assertEquals; - import org.junit.Before; import org.junit.Test; - import spoon.Launcher; import spoon.compiler.SpoonResourceHelper; import spoon.reflect.declaration.CtType; import spoon.reflect.factory.Factory; import spoon.reflect.visitor.DefaultJavaPrettyPrinter; +import static org.junit.Assert.assertEquals; + public class LinesTest { Factory factory; @@ -33,12 +32,12 @@ public void testPrettyPrinterWithLines() throws Exception { for (CtType t : factory.Type().getAll()) { if (t.isTopLevel()) { - // System.out.println("calculate " + t.getSimpleName()); + System.out.println("calculate " + t.getSimpleName()); DefaultJavaPrettyPrinter pp = new DefaultJavaPrettyPrinter( factory.getEnvironment()); pp.calculate(t.getPosition().getCompilationUnit(), t .getPosition().getCompilationUnit().getDeclaredTypes()); - // System.out.println(pp.getResult().toString()); + System.out.println(pp.getResult().toString()); } } assertEquals(0, factory.getEnvironment().getWarningCount());