Skip to content

Commit

Permalink
javadoc and some cleaning
Browse files Browse the repository at this point in the history
  • Loading branch information
pvojtechovsky committed Apr 11, 2018
1 parent e938998 commit 09a32aa
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 194 deletions.
Expand Up @@ -16,10 +16,6 @@
*/
package spoon.reflect.visitor.printer.change;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayDeque;
import java.util.Deque;

Expand All @@ -30,17 +26,23 @@
import spoon.reflect.declaration.CtElement;
import spoon.reflect.path.CtRole;
import spoon.reflect.visitor.DefaultJavaPrettyPrinter;
import spoon.reflect.visitor.PrettyPrinter;
import spoon.reflect.visitor.PrinterHelper;
import spoon.reflect.visitor.TokenWriter;

/**
* SourcePositionUtils#descriptors
* {@link PrettyPrinter} implementation which copies as much as possible from origin sources
* and prints only changed elements
*/
public class ChangesAwareDefaultJavaPrettyPrinter extends DefaultJavaPrettyPrinter {

final MutableTokenWriter mutableTokenWriter;
private final MutableTokenWriter mutableTokenWriter;
private final ChangeCollector changeCollector;
private final Deque<SourceFragmentContext> sourceFragmentContextStack = new ArrayDeque<>();

/**
* Creates a new {@link PrettyPrinter} which copies origin sources and prints only changes.
*/
public ChangesAwareDefaultJavaPrettyPrinter(Environment env) {
super(env);
this.changeCollector = ChangeCollector.getChangeCollector(env);
Expand All @@ -60,70 +62,89 @@ public ChangesAwareDefaultJavaPrettyPrinter(Environment env) {
* @return a wrapped {@link TokenWriter}
*/
private TokenWriter createTokenWriterListener(TokenWriter tokenWriter) {
return (TokenWriter) Proxy.newProxyInstance(
getClass().getClassLoader(),
new Class[] {TokenWriter.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Runnable printAction = () -> {
try {
method.invoke(tokenWriter, args);
} catch (IllegalAccessException | IllegalArgumentException e) {
throw new SpoonException("Cannot invoke TokenWriter method", e);
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof RuntimeException) {
throw (RuntimeException) e.getTargetException();
}
throw new SpoonException("Invokation target exception TokenWriter method", e);
}
};
if (method.getName().startsWith("write")) {
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length == 1) {
if (paramTypes[0] == String.class) {
//writeXxx(String)
onTokenWriterWrite(method.getName(), (String) args[0], null, printAction);
} else if (paramTypes[0] == CtComment.class) {
//writeComment(CtComment)
onTokenWriterWrite(method.getName(), null, (CtComment) args[0], printAction);
}
return proxy;
} else if (paramTypes.length == 0) {
//writeSpace() and writeln()
String token = method.getName().equals("writeSpace") ? " " : "\n";
onTokenWriterWrite(method.getName(), token, null, printAction);
return proxy;
}
}
if (method.getName().endsWith("Tab")) {
//incTab(), decTab()
onTokenWriterWrite(method.getName(), (String) null, null, printAction);
return proxy;
}
if (method.getName().equals("getPrinterHelper") || method.getName().equals("reset")) {
try {
return method.invoke(tokenWriter, args);
} catch (IllegalAccessException | IllegalArgumentException e) {
throw new SpoonException("Cannot invoke TokenWriter method", e);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
throw new SpoonException("Unexpected method TokenWriter#" + method.getName());
}
});
return new TokenWriterProxy(tokenWriter);
}

private class TokenWriterProxy implements TokenWriter {
private final TokenWriter delegate;

TokenWriterProxy(TokenWriter delegate) {
super();
this.delegate = delegate;
}

public TokenWriter writeSeparator(String token) {
onTokenWriterWrite("writeSeparator", token, null, () -> delegate.writeSeparator(token));
return this;
}

public TokenWriter writeOperator(String token) {
onTokenWriterWrite("writeOperator", token, null, () -> delegate.writeOperator(token));
return this;
}

public TokenWriter writeLiteral(String token) {
onTokenWriterWrite("writeLiteral", token, null, () -> delegate.writeLiteral(token));
return this;
}

public TokenWriter writeKeyword(String token) {
onTokenWriterWrite("writeKeyword", token, null, () -> delegate.writeKeyword(token));
return this;
}

public TokenWriter writeIdentifier(String token) {
onTokenWriterWrite("writeIdentifier", token, null, () -> delegate.writeIdentifier(token));
return this;
}

public TokenWriter writeCodeSnippet(String token) {
onTokenWriterWrite("writeCodeSnippet", token, null, () -> delegate.writeCodeSnippet(token));
return this;
}

public TokenWriter writeComment(CtComment comment) {
onTokenWriterWrite("writeComment", null, comment, () -> delegate.writeComment(comment));
return this;
}

public TokenWriter writeln() {
onTokenWriterWrite("writeln", "\n", null, () -> delegate.writeln());
return this;
}

public TokenWriter incTab() {
onTokenWriterWrite("incTab", null, null, () -> delegate.incTab());
return this;
}

public TokenWriter decTab() {
onTokenWriterWrite("decTab", null, null, () -> delegate.decTab());
return this;
}

public PrinterHelper getPrinterHelper() {
return delegate.getPrinterHelper();
}

public void reset() {
delegate.reset();
}

public TokenWriter writeSpace() {
onTokenWriterWrite("writeSpace", " ", null, () -> delegate.writeSpace());
return this;
}
}

/**
* Is called for each printed token
* @param tokenWriterMethodName the name of {@link TokenWriter} method
* @param token the actual token value
* @param comment TODO
* @param token the actual token value. It may be null for some `tokenWriterMethodName`
* @param comment the comment when `tokenWriterMethodName` == `writeComment`
* @param printAction the executor of the action, we are listening for.
* @throws Exception
*/
protected void onTokenWriterWrite(String tokenWriterMethodName, String token, CtComment comment, Runnable printAction) {
private void onTokenWriterWrite(String tokenWriterMethodName, String token, CtComment comment, Runnable printAction) {
SourceFragmentContext sfc = sourceFragmentContextStack.peek();
if (sfc != null) {
sfc.onTokenWriterToken(tokenWriterMethodName, token, printAction);
Expand All @@ -132,14 +153,18 @@ protected void onTokenWriterWrite(String tokenWriterMethodName, String token, Ct
printAction.run();
}

private final SourceFragmentContextNormal EMPTY_FRAGMENT_CONTEXT = new SourceFragmentContextNormal(this);
private final SourceFragmentContextNormal EMPTY_FRAGMENT_CONTEXT = new SourceFragmentContextNormal();

/**
* Called whenever {@link DefaultJavaPrettyPrinter} scans/prints an element
*/
@Override
public ChangesAwareDefaultJavaPrettyPrinter scan(CtElement element) {
SourceFragmentContext sfc = sourceFragmentContextStack.peek();
if (sfc != null) {
CtRole role = element.getRoleInParent();
if (role != null) {
//there is an context in the child element, let it handle scanning
sfc.onScanElementOnRole(element, role, () -> scanInternal(element));
return this;
}
Expand All @@ -161,20 +186,19 @@ private void scanInternal(CtElement element) {
//detect SourceFragments of element and whether they are modified or not
SourceFragment rootFragmentOfElement = SourcePositionUtils.getSourceFragmentsOfElement(changeCollector, element);
if (rootFragmentOfElement == null) {
//we have no origin sources. Use normal printing
//we have no origin sources or this element has one source fragment only and it is modified. Use normal printing
sourceFragmentContextStack.push(EMPTY_FRAGMENT_CONTEXT);
super.scan(element);
sourceFragmentContextStack.pop();
return;
}
try {
SourceFragmentContextNormal sfx = new SourceFragmentContextNormal(this, element, rootFragmentOfElement);
sourceFragmentContextStack.push(sfx);
super.scan(element);
} finally {
//at the end we always un-mute the token writer
mutableTokenWriter.setMuted(false);
sourceFragmentContextStack.pop();
}
//the element is modified and it consists of more source fragments, and some of them are not modified
//so we can copy the origin sources for them
SourceFragmentContextNormal sfx = new SourceFragmentContextNormal(mutableTokenWriter, element, rootFragmentOfElement);
sourceFragmentContextStack.push(sfx);
super.scan(element);
sourceFragmentContextStack.pop();
//at the end we always un-mute the token writer
mutableTokenWriter.setMuted(false);
}
}
Expand Up @@ -29,15 +29,20 @@ class DirectPrinterHelper extends PrinterHelper {
}

/**
* Prints `str` directly into output buffer ignoring any Environment rules.
* @param str to be printed string
* Prints `text` directly into output buffer ignoring any Environment rules.
* @param text to be printed string
*/
void directPrint(String str) {
void directPrint(String text) {
autoWriteTabs();
sbf.append(str);
sbf.append(text);
}

public void setShouldWriteTabs(boolean shouldWriteTabs) {
/**
* Allows to set the protected field of {@link PrinterHelper}.
*
* @param shouldWriteTabs true if we just printed EndOfLine and we should pring tabs if next character is not another EndOfLine
*/
void setShouldWriteTabs(boolean shouldWriteTabs) {
this.shouldWriteTabs = shouldWriteTabs;
}
}
Expand Up @@ -27,7 +27,7 @@ public enum FragmentType {
*/
MAIN_FRAGMENT,
/**
* modifiers of an Type or Variable. {@link DeclarationSourcePosition#getModifierSourceStart()}, {@link DeclarationSourcePosition#getModifierSourceEnd()}
* modifiers and annotations of an Type, Executable or Variable. {@link DeclarationSourcePosition#getModifierSourceStart()}, {@link DeclarationSourcePosition#getModifierSourceEnd()}
*/
MODIFIERS,
/**
Expand Down
Expand Up @@ -32,17 +32,24 @@ class MutableTokenWriter implements TokenWriter {

MutableTokenWriter(Environment env) {
super();
this.delegate = new DefaultTokenWriter(new DirectPrinterHelper(env));;
this.delegate = new DefaultTokenWriter(new DirectPrinterHelper(env));
}

/**
* @return true if tokens are ignored. false if they are forwarded to `delegate`
*/
boolean isMuted() {
return muted;
}

/**
* @param muted true if tokens are ignored. false if they are forwarded to `delegate`
*/
void setMuted(boolean muted) {
this.muted = muted;
}

@Override
public TokenWriter writeSeparator(String token) {
if (isMuted()) {
getPrinterHelper().setShouldWriteTabs(false);
Expand All @@ -51,6 +58,7 @@ public TokenWriter writeSeparator(String token) {
delegate.writeSeparator(token);
return this;
}
@Override
public TokenWriter writeOperator(String token) {
if (isMuted()) {
getPrinterHelper().setShouldWriteTabs(false);
Expand All @@ -59,6 +67,7 @@ public TokenWriter writeOperator(String token) {
delegate.writeOperator(token);
return this;
}
@Override
public TokenWriter writeLiteral(String token) {
if (isMuted()) {
getPrinterHelper().setShouldWriteTabs(false);
Expand All @@ -67,6 +76,7 @@ public TokenWriter writeLiteral(String token) {
delegate.writeLiteral(token);
return this;
}
@Override
public TokenWriter writeKeyword(String token) {
if (isMuted()) {
getPrinterHelper().setShouldWriteTabs(false);
Expand All @@ -75,6 +85,7 @@ public TokenWriter writeKeyword(String token) {
delegate.writeKeyword(token);
return this;
}
@Override
public TokenWriter writeIdentifier(String token) {
if (isMuted()) {
getPrinterHelper().setShouldWriteTabs(false);
Expand All @@ -83,6 +94,7 @@ public TokenWriter writeIdentifier(String token) {
delegate.writeIdentifier(token);
return this;
}
@Override
public TokenWriter writeCodeSnippet(String token) {
if (isMuted()) {
getPrinterHelper().setShouldWriteTabs(false);
Expand All @@ -91,6 +103,7 @@ public TokenWriter writeCodeSnippet(String token) {
delegate.writeCodeSnippet(token);
return this;
}
@Override
public TokenWriter writeComment(CtComment comment) {
if (isMuted()) {
getPrinterHelper().setShouldWriteTabs(false);
Expand All @@ -99,6 +112,7 @@ public TokenWriter writeComment(CtComment comment) {
delegate.writeComment(comment);
return this;
}
@Override
public TokenWriter writeln() {
if (isMuted()) {
getPrinterHelper().setShouldWriteTabs(true);
Expand All @@ -107,29 +121,34 @@ public TokenWriter writeln() {
delegate.writeln();
return this;
}
@Override
public TokenWriter incTab() {
if (isMuted()) {
return this;
}
delegate.incTab();
return this;
}
@Override
public TokenWriter decTab() {
if (isMuted()) {
return this;
}
delegate.decTab();
return this;
}
@Override
public DirectPrinterHelper getPrinterHelper() {
return (DirectPrinterHelper) delegate.getPrinterHelper();
}
@Override
public void reset() {
if (isMuted()) {
return;
}
delegate.reset();
}
@Override
public TokenWriter writeSpace() {
if (isMuted()) {
getPrinterHelper().setShouldWriteTabs(false);
Expand Down

0 comments on commit 09a32aa

Please sign in to comment.