Skip to content

[Bug]: Spoon cannot transform file #5044

Open
@Ryan-Rong-24

Description

@Ryan-Rong-24

Describe the bug

I am using spoon to add comments to code blocks. For example when there is a "for" loop, I would add "start of for loop" to the code. I am using spoon's processor to achieve this. But when I run spoon processors on my files, I receive an error that I cannot understand. Do you have any idea what is going on?

Source code you are trying to analyze/transform

public class Temp {
    public void printHeaders()
	{
		int nbCols = columns.size();
		for( int i = 0; i < nbCols; i++ )
			columns.get( i ).hdrPrintsOn.print( null, new HdrInTreeTablePrinter( table, i ) );
	}

	@Override
	public void print( Iterable<T> data )
	{
		killCurrentEdit();
		table.emptyTable();

		if( data == null )
			return;

		// sort if needed
		if( userComparator != null )
		{
			ArrayList<T> tmp = new ArrayList<T>();
			for( T t : data )
			{
				int ins = Collections.binarySearch( tmp, t, userComparator );
				if( ins >= 0 )
					tmp.add( ins, t );
				else
					tmp.add( -ins - 1, t );
			}
			data = tmp;
		}

		// each row
		for( T d : data )
		{
			Row row = table.addRow( null );
			row.setRef( refMng.getRef( d ) );

			printRow( d, row );
		}
	}

	@Override
	public void updateRow( T object )
	{
		// find the row associated with this object
		int objectRef = refMng.getRef( object );
		Row item = getRow( objectRef );

		if( edition != null && refMng.getRef( edition.editedObject ) == objectRef )
			killCurrentEdit();

		Row insPos = userComparator != null ? getInsertPoint( object ) : item;

		// insert or move the row to the right place and create a cell printer
		if( item == null )
		{
			// new
			if( insPos != null )
				insPos = insPos.addBefore();
			else
				insPos = table.addRow( null );

			insPos.setRef( refMng.getRef( object ) );
		}
		else
		{
			if( insPos != item )
			{
				// GWT.log( "is at row " + row + " but should be at " + insPos
				// );
				item.moveBefore( insPos );
				insPos = item;
			}
		}

		// print the row
		printRow( object, insPos );
	}

	private Row getInsertPoint( T object )
	{
		ArrayList<Row> items = table.getItemChilds( null );
		int nbRows = items.size();
		int objectRef = refMng.getRef( object );

		if( userComparator != null )
		{
			for( Row item : items )
			{
				int refAtRow = item.getRef();

				if( userComparator.compare( object, refMng.getObject( refAtRow ) ) <= 0 )
				{
					if( refAtRow == objectRef )
					{
						// keep the same place only if lesser than the nxt item
						// or if there is no next
						if( items.indexOf( item ) == nbRows - 1 )
						{
							return item;
						}
						else
						{
							int refAtNextRow = getRefAtRow( item.getNextSiblingItem() );
							if( userComparator.compare( object, refMng.getObject( refAtNextRow ) ) <= 0 )
								return item;
						}
					}
					else
					{
						return item;
					}
				}
			}
		}

		return null;
	}

	@Override
	public void deleteRow( int ref )
	{
		Row item = getRow( ref );
		if( item == null )
			return;

		// to reset the edition state, just in case... (an only if we are
		// editing on the row we delete)
		if( edition != null && refMng.getRef( edition.editedObject ) == ref )
			killCurrentEdit();

		item.remove();
	}

	@Override
	public void setComparator( Comparator<T> comparator )
	{
		userComparator = comparator;
		sortAndPrint( comparator );
	}

	public void sortAndPrint( final Comparator<T> userComparator )
	{
		class It
		{
			Row item;
			T object;

			It( Row item, T object )
			{
				this.object = object;
				this.item = item;
			}
		}
		;

		ArrayList<It> its = new ArrayList<It>();

		// get all objects from the table
		ArrayList<Row> childs = table.getItemChilds( null );
		for( Row item : childs )
		{
			int ref = getRefAtRow( item );

			its.add( new It( item, refMng.getObject( ref ) ) );
		}

		// sort them
		Collections.sort( its, new Comparator<It>()
		{
			@Override
			public int compare( It o1, It o2 )
			{
				return userComparator.compare( o1.object, o2.object );
			}
		} );

		// now reorder the lines
		for( int j = 0; j < its.size(); j++ )
		{
			// item at position j ?
			Row atJ = table.getItemChilds( null ).get( j );
			// needed item is its[i].item
			Row neededItem = its.get( j ).item;

			if( atJ != neededItem )
			{
				// move its[i].item before item at position i
				neededItem.moveBefore( atJ );
			}
		}
	}

	private int getRefAtRow( Row item )
	{
		return item.getRef();
	}

	// return the row index of the row associated to the object referenced as
	// objectRef
	// returns null if the row is not found
	private Row getRow( int objectRef )
	{
		return table.getItemForRef( objectRef );
	}

	// returns a printer that can be used for the next call. a new one can be
	// created
	// WARNING : assumes the printer item is correctly initialized
	private void printRow( T object, Row row )
	{
		// to reset the edition state, just in case...
		if( edition != null && refMng.getRef( edition.editedObject ) == refMng.getRef( object ) )
			killCurrentEdit();

		// writes the element reference on the corresponding row element
		// note that this does not create a hard link to the referenced object
		// so
		// no garbage is created here
		row.setRef( refMng.getRef( object ) );

		// each column
		for( int i = 0; i < columns.size(); i++ )
			columns.get( i ).prints.print( object, new CellInTreeTablePrinter( row, i ) );
	}

	private boolean beginEdit( Row item, int col )
	{
		int ref = getRefAtRow( item );

		if( edition != null && ref == refMng.getRef( edition.editedObject ) )
			return true; // already began !!!

		killCurrentEdit();

		Edits<T> editMng = columns.get( col ).edits;
		if( editMng == null )
			return false;

		// find the T object that has been clicked
		T object = refMng.getObject( ref );
		assert object != null;
		if( object == null )
			return false;

		Element td = item.getTdElement( col );

		edition = new EditionState();

		// initialize and set the current edit
		edition.editedCol = col;
		edition.editedObject = object;

		// create a Printer corresponding to this cell
		edition.editedPrinter = new CellInTreeTablePrinter( item, col );

		// create an editor and init it
		// -2 to remove padding : HACK HACK HACK
		edition.editedEditor = editMng.createEditor( edition.editedObject, edition.editedPrinter, onEdit, td.getOffsetWidth() - 2, td.getClientHeight() - 2 );

		return true;
	}

	private static class CellPos
	{
		Row item;
		int col;

		CellPos( Row item, int col )
		{
			this.item = item;
			this.col = col;
		}
	}

	private final MouseDownHandler onTableMouseDown = new MouseDownHandler()
	{
		@Override
		public void onMouseDown( MouseDownEvent event )
		{
			Element source = DOM.eventGetTarget( Event.as( event.getNativeEvent() ) );

			// try to see if it's not on a th element
			int hdr = table.getEventTargetHeaderIdx( source );
			if( hdr < 0 )
				return;

			DragDrop.initiate( source, onDragDrop, hdr, Event.as( event.getNativeEvent() ) );
		}
	};

	DragDrop.Callback<Integer> onDragDrop = new DragDrop.Callback<Integer>()
	{
		@Override
		public String getGhostInnerHTML( Integer cookie, Element source )
		{
			class TempPrinter implements Printer
			{
				String html = null;

				@Override
				public void setWidget( Widget widget )
				{
					assert false;
				}

				@Override
				public void setText( String text )
				{
					html = text;
				}

				@Override
				public void setHTML( String html )
				{
					this.html = html;
				}
			}

			TempPrinter printer = new TempPrinter();

			columns.get( cookie ).hdrPrintsOn.print( null, printer );

			// Due to asynchronism, it may be possible that the printer did not
			// yet print anything, well... Too late, we use the source element
			// instead !!
			if( printer.html == null )
				return "<div style='background-color:rgba(120,120,120,0.4);'>" + source.getInnerHTML() + "</div>";

			return "<div style='background-color:rgba(120,120,120,0.4);width:20px;height:20px;'>" + printer.html + "</div>";
		}

		@Override
		public void onDragDropFinished( Integer cookie, Element source, Element destination )
		{
			int newPos = table.getEventTargetHeaderIdx( destination );
			if( newPos < 0 )
				return;

			ColumnMng<T> dum = columns.get( cookie );
			columns.set( cookie, columns.get( newPos ) );
			columns.set( newPos, dum );

			// Redraw headers
			printHeaders();

			// Redraw all objects in the table
			ArrayList<Row> items = table.getItemChilds( null );
			for( Row item : items )
			{
				int ref = item.getRef();
				printRow( refMng.getObject( ref ), item );
			}
		}
	};

	private final Edits.Callback onEdit = new Edits.Callback()
	{
		@Override
		public void cancelEdition()
		{
			killCurrentEdit();
		}

		@Override
		public void validateEdition( boolean fJumpNext )
		{
			// just forget the edition state, but don't redraw
			// that means we let the client continue drawing on its cell
			if( edition != null && fJumpNext )
			{
				CellPos next = getNextPos( getRow( refMng.getRef( edition.editedObject ) ), edition.editedCol );

				edition.close();
				edition = null;

				beginEdit( next.item, next.col );
			}
		}
	};

	// wait a bit to avoid ui jitter...
	// use refMng in case the data change during the time waited
	private void killCurrentEdit()
	{
		if( edition == null )
			return;

		// reprints the cell, with uptodate data
		columns.get( edition.editedCol ).prints.print( refMng.getObject( refMng.getRef( edition.editedObject ) ), edition.editedPrinter );

		edition.close();
		edition = null;
	}

	CellPos getNextPos( Row item, int col )
	{

		// either on the same row
		for( int c = col + 1; c < columns.size(); c++ )
		{
			if( columns.get( c ).edits != null )
				return new CellPos( item, c );
		}

		// or on the next
		item = item.getNextSiblingItem();
		for( int c = 0; c < columns.size(); c++ )
		{
			if( columns.get( c ).edits != null )
				return new CellPos( item, c );
		}

		return null;
	}
}

Source code for your Spoon processing

// file processors/ForProcessor.java
package spoon.processors;

import spoon.processing.AbstractProcessor;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.reflect.visitor.CtIterator;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.code.CtFor;
import spoon.reflect.code.CtComment;
import spoon.reflect.factory.Factory;

import java.util.List;
import java.io.*;

public class ForProcessor extends AbstractProcessor<CtFor> {
	public void process(CtFor element) {
		element.addComment(element.getFactory().Code().createComment("START OF FOR LOOP STATEMENT",CtComment.CommentType.INLINE));
	}
}

Actual output

Exception in thread "main" java.lang.Runtime Exception: Inconsistent Stack public static @Nonnull IMicroNode convertToMicroNode (fi
nal @Nonnull Node aNode) {
ValueEnforcer.notNull(aNode, "Node");
IMicroNode ret;
final short nNodeType=aNode.getNode Type();
case Node. DOCUMENT_NODE :
{
ret = new MicroDocument ();
break;
}
case Node. DOCUMENT_TYPE_NODE :
{
final DocumentType aDT = (DocumentType) aNode;
ret = new MicroDocument Type (aDT.getName(), aDT.getPublicId(), aDT.getSystemId());
break;
}
case Node.ELEMENT_NODE :
final Element a Element = (Element) aNode;
final String sNamespaceURI = aElement.getNamespaceURI();
final IMicroElement eElement = ((sNamespaceURI != null)? new Micro Element(sNamespaceURI, aElement.getLocalName()): new MicroE
lement (aElement.getTagName()));
}
case Node. ELEMENT_NODE :
at
at spoon.support.compiler.jdt. JDTTree Builder.endVisit(JDTTree Builder.java:541)
at org.eclipse.jdt.internal.compiler.ast.MethodDeclaration. traverse(MethodDeclaration.java:440)
at org.eclipse.jdt.internal.compiler.ast. Type Declaration. traverse (Type Declaration.java:1699)
at org.eclipse.jdt.internal.compiler.ast.CompilationUnit Declaration. traverse (Compilation Unit Declaration.java:827)
at org.eclipse.jdt.internal.compiler.ast.CompilationUnit Declaration. traverse (CompilationUnit Declaration.java:788)
at spoon.support.compiler.jdt. JDTBased SpoonCompiler.traverseUnit Declaration (JDTBased SpoonCompiler.java:481)
at spoon.support.compiler.jdt. JDTBased SpoonCompiler.lambda$buildModel$0 (JDTBased SpoonCompiler.java:438)
at spoon.support.compiler.jdt. JDTBased SpoonCompiler.forEach CompilationUnit (JDTBased SpoonCompiler.java:465)
at spoon.support.compiler.jdt.JDTBased SpoonCompiler.buildModel (JDTBased Spoon Compiler.java:436)
at spoon.support.compiler.jdt.JDTBased SpoonCompiler.build Units And Model (JDTBased SpoonCompiler.java:373)
at spoon.support.compiler.jdt.JDTBased Spoon Compiler.buildSources (JDTBased SpoonCompiler.java:336)
at spoon.support.compiler.jdt. JDTBased SpoonCompiler.build(JDTBased Spoon Compiler.java:117)
at spoon.support.compiler.jdt. JDTBased SpoonCompiler.build(JDTBased SpoonCompiler.java:100)
at spoon. Launcher.buildModel (Launcher.java:782)
at spoon. Launcher.run(Launcher.java:733)
at spoon. Launcher.run(Launcher.java:112)
at spoon. Launcher.main(Launcher.java:105)
spoon.support.compiler.jdt.ContextBuilder.exit(ContextBuilder.java:122)

Expected output

No response

Spoon Version

10.2.0

JVM Version

11

What operating system are you using?

Linux

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions