diff --git a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java index 443357bc1d5..7f466ab1129 100644 --- a/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java +++ b/src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java @@ -103,16 +103,14 @@ import spoon.reflect.reference.CtTypeReference; import spoon.reflect.reference.CtUnboundVariableReference; import spoon.reflect.reference.CtWildcardReference; +import spoon.reflect.visitor.PrintingContext.Writable; import spoon.reflect.visitor.printer.CommentOffset; import spoon.reflect.visitor.printer.ElementPrinterHelper; import spoon.reflect.visitor.printer.PrinterHelper; import java.lang.annotation.Annotation; -import java.util.ArrayDeque; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Deque; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -140,99 +138,6 @@ public class DefaultJavaPrettyPrinter implements CtVisitor, PrettyPrinter { */ public static final String LINE_SEPARATOR = System.getProperty("line.separator"); - protected static class TypeContext { - CtTypeReference type; - Set memberNames; - boolean inBody = false; - - TypeContext(CtTypeReference p_type) { - type = p_type; - } - - public boolean isNameConflict(String name) { - if (memberNames == null) { - Collection> allFields = type.getAllFields(); - memberNames = new HashSet<>(allFields.size()); - for (CtFieldReference field : allFields) { - memberNames.add(field.getSimpleName()); - } - } - return memberNames.contains(name); - } - - public String getSimpleName() { - return type.getSimpleName(); - } - - public CtPackageReference getPackage() { - return type.getPackage(); - } - } - - public class PrintingContext { - boolean noTypeDecl = false; - - List currentThis = new ArrayList<>(); - - /** - * @param inBody if false then it returns the nearest wrapping class which is actually printed. - * if true then it returns nearest wrapping class whose body we are printing - * @return top level type - */ - public CtTypeReference getCurrentTypeReference(boolean inBody) { - if (currentTopLevel != null) { - if (currentThis != null && currentThis.size() > 0) { - TypeContext tc = currentThis.get(currentThis.size() - 1); - if (!inBody || tc.inBody) { - return tc.type; - } else if (currentThis.size() > 1) { - return currentThis.get(currentThis.size() - 2).type; - } - } - return currentTopLevel.getReference(); - } - return null; - } - - public void pushCurrentThis(CtTypeReference type) { - currentThis.add(new TypeContext(type)); - } - public void markCurrentThisInBody() { - currentThis.get(currentThis.size() - 1).inBody = true; - } - public void popCurrentThis() { - currentThis.remove(currentThis.size() - 1); - } - - - Deque elementStack = new ArrayDeque<>(); - - Deque> parenthesedExpression = new ArrayDeque<>(); - - CtType currentTopLevel; - - boolean ignoreGenerics = false; - - boolean skipArray = false; - - boolean ignoreStaticAccess = false; - - boolean ignoreEnclosingClass = false; - - public void enterIgnoreGenerics() { - ignoreGenerics = true; - } - - public void exitIgnoreGenerics() { - ignoreGenerics = false; - } - - @Override - public String toString() { - return "context.ignoreGenerics: " + context.ignoreGenerics + "\n"; - } - } - /** * The printing context. */ @@ -446,7 +351,7 @@ public void visitCtArrayTypeReference(CtArrayTypeReference reference) { return; } scan(reference.getComponentType()); - if (!context.skipArray) { + if (!context.skipArray()) { printer.write("[]"); } } @@ -773,22 +678,21 @@ public void visitCtFieldWrite(CtFieldWrite fieldWrite) { private void printCtFieldAccess(CtFieldAccess f) { enterCtExpression(f); - if (f.getVariable().isStatic() && f.getTarget() instanceof CtTypeAccess) { - context.ignoreGenerics = true; - } - if (f.getTarget() != null) { - if (!isInitializeStaticFinalField(f.getTarget())) { - scan(f.getTarget()); - if (!f.getTarget().isImplicit()) { - printer.write("."); + try (Writable _context = context.modify()) { + if (f.getVariable().isStatic() && f.getTarget() instanceof CtTypeAccess) { + _context.ignoreGenerics(true); + } + if (f.getTarget() != null) { + if (!isInitializeStaticFinalField(f.getTarget())) { + scan(f.getTarget()); + if (!f.getTarget().isImplicit()) { + printer.write("."); + } } + _context.ignoreStaticAccess(true); } - context.ignoreStaticAccess = true; + scan(f.getVariable()); } - scan(f.getVariable()); - - context.ignoreGenerics = false; - context.ignoreStaticAccess = false; exitCtExpression(f); } @@ -932,16 +836,16 @@ public void visitCtComment(CtComment comment) { @Override public void visitCtAnnotationFieldAccess(CtAnnotationFieldAccess annotationFieldAccess) { enterCtExpression(annotationFieldAccess); - if (annotationFieldAccess.getTarget() != null) { - scan(annotationFieldAccess.getTarget()); - printer.write("."); - context.ignoreStaticAccess = true; + try (Writable _context = context.modify()) { + if (annotationFieldAccess.getTarget() != null) { + scan(annotationFieldAccess.getTarget()); + printer.write("."); + _context.ignoreStaticAccess(true); + } + _context.ignoreGenerics(true); + scan(annotationFieldAccess.getVariable()); + printer.write("()"); } - context.ignoreGenerics = true; - scan(annotationFieldAccess.getVariable()); - printer.write("()"); - context.ignoreGenerics = false; - context.ignoreStaticAccess = false; exitCtExpression(annotationFieldAccess); } @@ -963,10 +867,10 @@ public void visitCtFieldReference(CtFieldReference reference) { } } - if (isStatic && printType && !context.ignoreStaticAccess) { - context.ignoreGenerics = true; - scan(reference.getDeclaringType()); - context.ignoreGenerics = false; + if (isStatic && printType && !context.ignoreStaticAccess()) { + try (Writable _context = context.modify().ignoreGenerics(true)) { + scan(reference.getDeclaringType()); + } printer.write("."); } printer.write(reference.getSimpleName()); @@ -981,12 +885,12 @@ public void visitCtFor(CtFor forLoop) { scan(st.get(0)); } if (st.size() > 1) { - context.noTypeDecl = true; - for (int i = 1; i < st.size(); i++) { - printer.write(", "); - scan(st.get(i)); + try (Writable _context = context.modify().noTypeDecl(true)) { + for (int i = 1; i < st.size(); i++) { + printer.write(", "); + scan(st.get(i)); + } } - context.noTypeDecl = false; } printer.write("; "); scan(forLoop.getExpression()); @@ -1086,11 +990,12 @@ public void visitCtInvocation(CtInvocation invocation) { } else { // It's a method invocation if (invocation.getTarget() != null) { - if (invocation.getTarget() instanceof CtTypeAccess) { - context.ignoreGenerics = true; + try (Writable _context = context.modify()) { + if (invocation.getTarget() instanceof CtTypeAccess) { + _context.ignoreGenerics(true); + } + scan(invocation.getTarget()); } - scan(invocation.getTarget()); - context.ignoreGenerics = false; if (!invocation.getTarget().isImplicit()) { printer.write("."); } @@ -1164,13 +1069,13 @@ public void visitCtLiteral(CtLiteral literal) { @Override public void visitCtLocalVariable(CtLocalVariable localVariable) { - if (!context.noTypeDecl) { + if (!context.noTypeDecl()) { enterCtStatement(localVariable); } if (env.isPreserveLineNumbers()) { printer.adjustPosition(localVariable, sourceCompilationUnit); } - if (!context.noTypeDecl) { + if (!context.noTypeDecl()) { elementPrinterHelper.writeModifiers(localVariable); scan(localVariable.getType()); printer.write(" "); @@ -1215,10 +1120,9 @@ public void visitCtMethod(CtMethod m) { if (m.getFormalCtTypeParameters().size() > 0) { printer.write(' '); } - final boolean old = context.ignoreGenerics; - context.ignoreGenerics = false; - scan(m.getType()); - context.ignoreGenerics = old; + try (Writable _context = context.modify().ignoreGenerics(false)) { + scan(m.getType()); + } printer.write(" "); printer.write(m.getSimpleName()); elementPrinterHelper.writeExecutableParameters(m); @@ -1278,9 +1182,9 @@ public void visitCtNewArray(CtNewArray newArray) { printer.write("new "); } - context.skipArray = true; - scan(ref); - context.skipArray = false; + try (Writable _context = context.modify().skipArray(true)) { + scan(ref); + } for (int i = 0; ref instanceof CtArrayTypeReference; i++) { printer.write("["); if (newArray.getDimensionExpressions().size() > i) { @@ -1347,24 +1251,25 @@ public void visitCtNewClass(CtNewClass newClass) { } private void printConstructorCall(CtConstructorCall ctConstructorCall) { - if (ctConstructorCall.getTarget() != null) { - scan(ctConstructorCall.getTarget()); - printer.write("."); - context.ignoreEnclosingClass = true; - } + try (Writable _context = context.modify()) { + if (ctConstructorCall.getTarget() != null) { + scan(ctConstructorCall.getTarget()); + printer.write("."); + _context.ignoreEnclosingClass(true); + } - if (hasDeclaringTypeWithGenerics(ctConstructorCall.getType())) { - context.ignoreEnclosingClass = true; - } + if (hasDeclaringTypeWithGenerics(ctConstructorCall.getType())) { + _context.ignoreEnclosingClass(true); + } - printer.write("new "); + printer.write("new "); - if (ctConstructorCall.getActualTypeArguments().size() > 0) { - elementPrinterHelper.writeActualTypeArguments(ctConstructorCall); - } + if (ctConstructorCall.getActualTypeArguments().size() > 0) { + elementPrinterHelper.writeActualTypeArguments(ctConstructorCall); + } - scan(ctConstructorCall.getType()); - context.ignoreEnclosingClass = false; + scan(ctConstructorCall.getType()); + } printer.write("("); for (CtCodeElement exp : ctConstructorCall.getArguments()) { @@ -1674,17 +1579,15 @@ private void visitCtTypeReference(CtTypeReference ref, boolean withGenerics) } boolean isInner = ref.getDeclaringType() != null; if (isInner) { - if (!context.ignoreEnclosingClass && !ref.isLocalType()) { + if (!context.ignoreEnclosingClass() && !ref.isLocalType()) { //compute visible type which can be used to print access path to ref CtTypeReference accessType = ref.getAccessType(context.getCurrentTypeReference(true)); if (!accessType.isAnonymous()) { - boolean ign = context.ignoreGenerics; - if (!withGenerics) { - context.ignoreGenerics = true; - } - scan(accessType); - if (!withGenerics) { - context.ignoreGenerics = ign; + try (Writable _context = context.modify()) { + if (!withGenerics) { + _context.ignoreGenerics(true); + } + scan(accessType); } printer.write("."); } @@ -1706,11 +1609,10 @@ private void visitCtTypeReference(CtTypeReference ref, boolean withGenerics) elementPrinterHelper.writeAnnotations(ref); printer.write(ref.getSimpleName()); } - if (withGenerics && !context.ignoreGenerics) { - final boolean old = context.ignoreEnclosingClass; - context.ignoreEnclosingClass = false; - elementPrinterHelper.writeActualTypeArguments(ref); - context.ignoreEnclosingClass = old; + if (withGenerics && !context.ignoreGenerics()) { + try (Writable _context = context.modify().ignoreEnclosingClass(false)) { + elementPrinterHelper.writeActualTypeArguments(ref); + } } } diff --git a/src/main/java/spoon/reflect/visitor/PrintingContext.java b/src/main/java/spoon/reflect/visitor/PrintingContext.java new file mode 100644 index 00000000000..7087bf9a3d5 --- /dev/null +++ b/src/main/java/spoon/reflect/visitor/PrintingContext.java @@ -0,0 +1,119 @@ +package spoon.reflect.visitor; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +import spoon.reflect.code.CtExpression; +import spoon.reflect.declaration.CtElement; +import spoon.reflect.declaration.CtType; +import spoon.reflect.reference.CtTypeReference; + +public class PrintingContext { + + private long NO_TYPE_DECL = 1 << 0; + private long IGNORE_GENERICS = 1 << 1; + private long SKIP_ARRAY = 1 << 2; + private long IGNORE_STATIC_ACCESS = 1 << 3; + private long IGNORE_ENCLOSING_CLASS = 1 << 4; + + private long state; + + public boolean noTypeDecl() { + return (state & NO_TYPE_DECL) != 0L; + } + public boolean ignoreGenerics() { + return (state & IGNORE_GENERICS) != 0L; + } + public boolean skipArray() { + return (state & SKIP_ARRAY) != 0L; + } + public boolean ignoreStaticAccess() { + return (state & IGNORE_STATIC_ACCESS) != 0L; + } + public boolean ignoreEnclosingClass() { + return (state & IGNORE_ENCLOSING_CLASS) != 0L; + } + + public class Writable implements AutoCloseable { + private long oldState; + + protected Writable() { + oldState = state; + } + @Override + public void close() { + state = oldState; + } + + public T noTypeDecl(boolean v) { + state |= NO_TYPE_DECL; + return (T) this; + } + public T ignoreGenerics(boolean v) { + state |= IGNORE_GENERICS; + return (T) this; + } + public T skipArray(boolean v) { + state |= SKIP_ARRAY; + return (T) this; + } + public T ignoreStaticAccess(boolean v) { + state |= IGNORE_STATIC_ACCESS; + return (T) this; + } + public T ignoreEnclosingClass(boolean v) { + state |= IGNORE_ENCLOSING_CLASS; + return (T) this; + } + } + + public Writable modify() { + return new Writable(); + } + + List currentThis = new ArrayList<>(); + + /** + * @param inBody if false then it returns the nearest wrapping class which is actually printed. + * if true then it returns nearest wrapping class whose body we are printing + * @return top level type + */ + public CtTypeReference getCurrentTypeReference(boolean inBody) { + if (currentTopLevel != null) { + if (currentThis != null && currentThis.size() > 0) { + TypeContext tc = currentThis.get(currentThis.size() - 1); + if (!inBody || tc.inBody) { + return tc.type; + } else if (currentThis.size() > 1) { + return currentThis.get(currentThis.size() - 2).type; + } + } + return currentTopLevel.getReference(); + } + return null; + } + + public void pushCurrentThis(CtTypeReference type) { + currentThis.add(new TypeContext(type)); + } + public void markCurrentThisInBody() { + currentThis.get(currentThis.size() - 1).inBody = true; + } + public void popCurrentThis() { + currentThis.remove(currentThis.size() - 1); + } + + + Deque elementStack = new ArrayDeque<>(); + + Deque> parenthesedExpression = new ArrayDeque<>(); + + CtType currentTopLevel; + + @Override + public String toString() { + return "context.ignoreGenerics: " + ignoreGenerics() + "\n"; + } +} diff --git a/src/main/java/spoon/reflect/visitor/TypeContext.java b/src/main/java/spoon/reflect/visitor/TypeContext.java new file mode 100644 index 00000000000..efbb3c4f7cf --- /dev/null +++ b/src/main/java/spoon/reflect/visitor/TypeContext.java @@ -0,0 +1,38 @@ +package spoon.reflect.visitor; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import spoon.reflect.reference.CtFieldReference; +import spoon.reflect.reference.CtPackageReference; +import spoon.reflect.reference.CtTypeReference; + +public class TypeContext { + CtTypeReference type; + Set memberNames; + boolean inBody = false; + + TypeContext(CtTypeReference p_type) { + type = p_type; + } + + public boolean isNameConflict(String name) { + if (memberNames == null) { + Collection> allFields = type.getAllFields(); + memberNames = new HashSet<>(allFields.size()); + for (CtFieldReference field : allFields) { + memberNames.add(field.getSimpleName()); + } + } + return memberNames.contains(name); + } + + public String getSimpleName() { + return type.getSimpleName(); + } + + public CtPackageReference getPackage() { + return type.getPackage(); + } +} diff --git a/src/main/java/spoon/reflect/visitor/printer/ElementPrinterHelper.java b/src/main/java/spoon/reflect/visitor/printer/ElementPrinterHelper.java index a9109b00599..73b7e22a576 100644 --- a/src/main/java/spoon/reflect/visitor/printer/ElementPrinterHelper.java +++ b/src/main/java/spoon/reflect/visitor/printer/ElementPrinterHelper.java @@ -47,6 +47,7 @@ import spoon.reflect.reference.CtFieldReference; import spoon.reflect.reference.CtTypeReference; import spoon.reflect.visitor.DefaultJavaPrettyPrinter; +import spoon.reflect.visitor.PrintingContext.Writable; import java.util.ArrayList; import java.util.Collection; @@ -190,9 +191,9 @@ public void writeAnnotationElement(Factory factory, Object value) { } printer.write("}"); } else if (value instanceof Enum) { - prettyPrinter.getContext().enterIgnoreGenerics(); - prettyPrinter.scan(factory.Type().createReference(((Enum) value).getDeclaringClass())); - prettyPrinter.getContext().exitIgnoreGenerics(); + try (Writable c = prettyPrinter.getContext().modify().ignoreGenerics(true)) { + prettyPrinter.scan(factory.Type().createReference(((Enum) value).getDeclaringClass())); + } printer.write("."); printer.write(value.toString()); } else {