Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion doc/processor.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ of the processor class. There is also an optional overridable method for queryin
elements at a finer grain.

The process method takes the requested element as input and does the analysis
(here detecting empty catch blocks).
(here detecting empty catch blocks). At any time, you can interrupt the processing
of the model with a call to `interrupt()` (this stops all processors, and proceeds
with the next step which is usually pretty-printing the code to disk).

Since a real world analysis combines multiple queries, multiple processors can
be used at the same time. The launcher applies them in the order they have been declared.
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/spoon/processing/AbstractManualProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
*/
package spoon.processing;

import java.util.Set;

import spoon.compiler.Environment;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.factory.Factory;

import java.util.Set;

/**
* This class defines an abstract processor to be subclassed by the user for
* defining new manual processors. A manual processor should override the init
Expand Down Expand Up @@ -100,4 +100,9 @@ public final void setFactory(Factory factory) {
public final void initProperties(ProcessorProperties properties) {
AbstractProcessor.initProperties(this, properties);
}

@Override
public void interrupt() {
throw new ProcessInterruption();
}
}
18 changes: 11 additions & 7 deletions src/main/java/spoon/processing/AbstractProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@
*/
package spoon.processing;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import org.apache.log4j.Level;
import spoon.Launcher;
import spoon.compiler.Environment;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.factory.Factory;
import spoon.support.util.RtHelper;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
* This class defines an abstract processor to be subclassed by the user for
* defining new processors.
Expand Down Expand Up @@ -172,4 +172,8 @@ public void setFactory(Factory factory) {
this.factory = factory;
}

@Override
public void interrupt() {
throw new ProcessInterruption();
}
}
37 changes: 37 additions & 0 deletions src/main/java/spoon/processing/ProcessInterruption.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* 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.processing;

/**
* This exception is used to interrupt a processor during its processing.
*/
public class ProcessInterruption extends RuntimeException {
public ProcessInterruption() {
}

public ProcessInterruption(String message) {
super(message);
}

public ProcessInterruption(String message, Throwable cause) {
super(message, cause);
}

public ProcessInterruption(Throwable cause) {
super(cause);
}
}
10 changes: 8 additions & 2 deletions src/main/java/spoon/processing/Processor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
*/
package spoon.processing;

import java.util.Set;

import spoon.compiler.Environment;
import spoon.reflect.declaration.CtElement;

import java.util.Set;

/**
* This interface defines a generic code processor. To define a new processor,
* the user should subclass {@link spoon.processing.AbstractProcessor}, the
Expand Down Expand Up @@ -122,4 +122,10 @@ public interface Processor<E extends CtElement> extends FactoryAccessor {
*/
void initProperties(ProcessorProperties properties);

/**
* Interrupts the processing of this processor but changes on your AST are kept
* and the invocation of this method doesn't interrupt the processing of all
* processors specified in the {@link ProcessingManager}.
*/
void interrupt();
}
35 changes: 22 additions & 13 deletions src/main/java/spoon/support/QueueProcessingManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.log4j.Level;
import spoon.SpoonException;
import spoon.processing.AbstractProcessor;
import spoon.processing.ProcessInterruption;
import spoon.processing.ProcessingManager;
import spoon.processing.Processor;
import spoon.reflect.declaration.CtElement;
Expand Down Expand Up @@ -105,26 +106,34 @@ protected ProcessingVisitor getVisitor() {
public void process(Collection<? extends CtElement> elements) {
Processor<?> p;
while ((p = getProcessors().poll()) != null) {
getFactory().getEnvironment().reportProgressMessage(p.getClass().getName());
current = p;
p.initProperties(AbstractProcessor.loadProperties(p));
p.init();
p.process();
for (CtElement e : new ArrayList<CtElement>(elements)) {
process(e, p);
try {
getFactory().getEnvironment().reportProgressMessage(p.getClass().getName());
current = p;
p.initProperties(AbstractProcessor.loadProperties(p));
p.init();
p.process();
for (CtElement e : new ArrayList<CtElement>(elements)) {
process(e, p);
}
} catch (ProcessInterruption ignore) {
} finally {
p.processingDone();
}
p.processingDone();
}
}

public void process(CtElement element) {
Processor<?> p;
while ((p = getProcessors().poll()) != null) {
current = p;
p.init();
p.process();
process(element, p);
p.processingDone();
try {
current = p;
p.init();
p.process();
process(element, p);
} catch (ProcessInterruption ignore) {
} finally {
p.processingDone();
}
}
}

Expand Down
24 changes: 14 additions & 10 deletions src/main/java/spoon/support/RuntimeProcessingManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@
*/
package spoon.support;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Level;
import spoon.processing.ProcessInterruption;
import spoon.processing.ProcessingManager;
import spoon.processing.Processor;
import spoon.reflect.declaration.CtElement;
Expand All @@ -29,6 +26,10 @@
import spoon.support.util.Timer;
import spoon.support.visitor.ProcessingVisitor;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

/**
* This processing manager implements a blocking processing policy that consists
* of applying the processors in a FIFO order until no processors remain to be
Expand Down Expand Up @@ -114,13 +115,16 @@ public void process(Collection<? extends CtElement> elements) {
* Recursively processes elements and their children with a given processor.
*/
public void process(Collection<? extends CtElement> elements, Processor<?> processor) {
getFactory().getEnvironment().debugMessage("processing with '" + processor.getClass().getName() + "'...");
current = processor;
Timer.start(processor.getClass().getName());
for (CtElement e : elements) {
process(e, processor);
try {
getFactory().getEnvironment().debugMessage("processing with '" + processor.getClass().getName() + "'...");
current = processor;
Timer.start(processor.getClass().getName());
for (CtElement e : elements) {
process(e, processor);
}
Timer.stop(processor.getClass().getName());
} catch (ProcessInterruption ignored) {
}
Timer.stop(processor.getClass().getName());
}

public void process(CtElement element) {
Expand Down
43 changes: 43 additions & 0 deletions src/test/java/spoon/processing/ProcessingTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.processing;

import org.junit.Test;
import spoon.Launcher;
import spoon.processing.processors.MyProcessor;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;

public class ProcessingTest {
@Test
public void testInterruptAProcessor() throws Exception {
final Launcher launcher = new Launcher();
launcher.getEnvironment().setNoClasspath(true);
launcher.addInputResource("./src/tets/java/spoon/processing/");
launcher.setSourceOutputDirectory("./target/trash");
final MyProcessor processor = new MyProcessor();
launcher.addProcessor(processor);
try {
launcher.run();
} catch (ProcessInterruption e) {
fail("ProcessInterrupt exception must be catch in the ProcessingManager.");
}
assertFalse(processor.isShouldStayAtFalse());
}
}
35 changes: 35 additions & 0 deletions src/test/java/spoon/processing/processors/MyProcessor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.processing.processors;

import spoon.processing.AbstractProcessor;
import spoon.reflect.declaration.CtElement;

public class MyProcessor extends AbstractProcessor<CtElement> {
private boolean shouldStayAtFalse;

@Override
public void process(CtElement element) {
interrupt();
shouldStayAtFalse = true;
}

public boolean isShouldStayAtFalse() {
return shouldStayAtFalse;
}
}