Bug 278006 - [compare] JavaStructure Comparator not reporting correct number of lines modified
Summary: [compare] JavaStructure Comparator not reporting correct number of lines modi...
Status: RESOLVED WORKSFORME
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Text (show other bugs)
Version: 3.3   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Text-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: needinfo
Depends on:
Blocks:
 
Reported: 2009-05-27 05:31 EDT by Nanjangud C Narendra CLA
Modified: 2009-06-03 03:25 EDT (History)
2 users (show)

See Also:


Attachments
This attachment contains the two versions of the java file for which the incorrect number of lines were reported. (1.82 KB, application/x-zip-compressed)
2009-05-27 05:31 EDT, Nanjangud C Narendra CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Nanjangud C Narendra CLA 2009-05-27 05:31:45 EDT
Created attachment 137291 [details]
This attachment contains the two versions of the java file for which the incorrect number of lines were reported.

Build ID: 3.2

Steps To Reproduce:
We are running the following compare routine to compare two versions of a java file:

package com.ibm.file.compare;

import java.util.LinkedList;
import java.util.ResourceBundle;

import javax.swing.event.ChangeListener;

import org.eclipse.compare.CompareUI;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.ResourceNode;
import org.eclipse.compare.internal.CompareUIPlugin;
import org.eclipse.compare.internal.DocLineComparator;
import org.eclipse.compare.internal.StructureCreatorDescriptor;
import org.eclipse.compare.rangedifferencer.IRangeComparator;
import org.eclipse.compare.rangedifferencer.RangeDifference;
import org.eclipse.compare.rangedifferencer.RangeDifferencer;
import org.eclipse.compare.structuremergeviewer.DiffContainer;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.compare.structuremergeviewer.DocumentRangeNode;
import org.eclipse.compare.structuremergeviewer.IStructureComparator;
import org.eclipse.compare.structuremergeviewer.IStructureCreator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;

public class VersionCompare 	{
	
	
	private ResourceBundle resourceBundle;

	private static final String ID = "org.softevo.rose.compare";


/**
 * The constructor.
 */
public VersionCompare() {
	
}

/**
 * Returns an structure creator descriptor for the given type.
 *
 * @param type the type for which to find a descriptor
 * @return a descriptor for the given type, or <code>null</code> if no
 *   descriptor has been registered
 */
public static IStructureCreator getStructureCreator(String type) {
    if (type == null) return null;
    if (type.startsWith(".")) type = type.substring(1);
    CompareUIPlugin ui = CompareUIPlugin.getDefault();
    StructureCreatorDescriptor creator = ui.getStructureCreator(type);
    if (creator == null) return null;
    return creator.createStructureCreator();
}


/**
 * 
 * @param leftFile
 * @param rightFile
 * @return
 */
public static LinkedList doStructureCompare(IStructureCreator creator, IFile leftFile, IFile rightFile) {
	    return doStructureCompare(creator, new ResourceNode(leftFile), new ResourceNode(rightFile));
}


/**
 * Left and right objects "should" implement IStreamContentAccessor.
 * E.g.:
 * <ul>
 * <li><code>new ResourceNode(leftFile)</code>
 * <li><code>new HistoryItem(oldFile, IFileState)</code>
 * </ul>
 * @param creator
 * @param left
 * @param right
 * @return
 */
public static LinkedList doStructureCompare(IStructureCreator creator, Object left, Object right) {
		// Create the structure of the two versions
	IStructureComparator leftStructure = creator.getStructure(left);
	IStructureComparator rightStructure = creator.getStructure(right);
	
		return doStructureCompare(leftStructure, rightStructure);
}


/**
 * @param leftStructure
 * @param rightStructure
 * @return
 */
public static LinkedList doStructureCompare(IStructureComparator leftStructure, IStructureComparator rightStructure) {
    LinkedList result = new LinkedList();

		// Create the differencer
	Differencer differencer = new Differencer();

	// Find the differences
	// System.out.println("Create differences by findDifferences...");
	Object outcome =
		differencer.findDifferences(
			false,
			new NullProgressMonitor(),
			null,
			null,
			leftStructure,
			rightStructure);		
	// System.out.println(outcome);

	// Analyze outcome via a DFS
	if (outcome != null && outcome instanceof DiffNode) {
		DiffNode dn = (DiffNode) outcome;
				
		// Initialize DFS stack
		LinkedList stack = new LinkedList();
		for (int i = 0; i < dn.getChildren().length; i++) {
			stack.addLast(dn.getChildren()[i]);
		}

		// Work off stack
		while (!stack.isEmpty()) {
			Object element = stack.removeFirst();

			if (element instanceof DiffContainer) {
				DiffContainer dc = (DiffContainer) element;

				if (dc.getChildren() == null 
					|| dc.getChildren().length==0) {
					// We have reached a leaf - found a difference
					if (dc instanceof DiffNode) {
						// Add difference to list
						result.addAll(getModificationItems((DiffNode) dc));
					}
				} else {
					// Push elements on stack (in reverse order)
					for (int i = dc.getChildren().length-1 ; i > -1; i--) {
						stack.addFirst(dc.getChildren()[i]);
					}									
				}
			}
		}
	}
	
	//for (Iterator iter = result.iterator(); iter.hasNext();) {
     //   ModificationItem element = (ModificationItem) iter.next();
     //   if (element != null && element.isDocumentRangeNode()) {
     //       DocumentRangeNode drn = element.getDocumentRangeNode();
     //       System.out.println(drn.getId());                
     //   }
     //}
    return result;
}

/**
 * @param dc
 * @return
 */
private static LinkedList getModificationItems(DiffNode dn) {

	int type = ModificationItem.CHANGED; 
	if (dn.getLeft() == null) {
		type = ModificationItem.ADDED; 
	} else if (dn.getRight() == null) {
		type = ModificationItem.DELETED;
	}
	
	int changedLines = getChangedLines(dn);
//	System.out.println(" No of changed line are : " + dn.getId().getName() + " :" + changedLines);
	return ModificationItem.createModificationItems(dn.getId(), type,changedLines);   
}

private static int getChangedLines(DiffNode dn) {

	ITypedElement lElement = dn.getLeft();
	ITypedElement rElement = dn.getRight();
	IDocument lDoc = null;
	IDocument rDoc = null;
	Position lRegion= null;
	Position rRegion= null;
	int changedLines = 0;
	if( lElement != null && lElement instanceof DocumentRangeNode )	{
			lDoc = ((DocumentRangeNode)lElement).getDocument();
			lRegion = ((DocumentRangeNode)lElement).getRange();
			changedLines =countLines(lDoc,lRegion);
	}
	if( rElement != null && rElement instanceof DocumentRangeNode) {
		rDoc = ((DocumentRangeNode)rElement).getDocument();
		rRegion = ((DocumentRangeNode)rElement).getRange();
		changedLines = countLines(rDoc,rRegion);
	}
	if(lDoc !=null && rDoc !=null) {
		changedLines = 0;
		DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), true);
		DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), true);
		RangeDifference[] result = RangeDifferencer.findRanges(sleft,sright);
		if (result == null ) return changedLines;
		for(int i=0;i<result.length;i++) {
			if (result[i].kind() == RangeDifference.NOCHANGE )
				continue;
			else
				++changedLines;
		}
		
	}
	return changedLines;
	
}

private static int countLines(IDocument document, Position region) {
		
	if(region != null) {
		int length = region.getLength();
		int start= region.getOffset();
		int offset = 0;
		try {
			 offset = document.getLineOfOffset(start);
		} catch (BadLocationException ex) {
			// silently ignored
		}

		if (length == 0)
			return 0;
		else {
			int endLine= document.getNumberOfLines();
			try {
				endLine= document.getLineOfOffset(start + length);
			} catch (BadLocationException ex) {
				// silently ignored
			}
			int linecount= endLine - offset + 1;
			return linecount;
		}

	} else {
		return document.getNumberOfLines();
	}	
	
}
private static IRegion toRegion(Position position) {
	if (position != null)
		return new Region(position.getOffset(), position.getLength());
	return null;
}
}


More information:
The Comparator reports only 1 line changed in method "importAndValidate(String file)", although 22 lines have been added in that method. We have also attached the two versions of the java file as an attachment.
Comment 1 Olivier Thomann CLA 2009-05-27 08:27:47 EDT
Move to JDT/Text. This might be a platform/compare issue.
Comment 2 Dani Megert CLA 2009-05-27 08:35:31 EDT
>We are running the following compare routine to compare two versions of a java
>file:
How? Can you provide either a JUnit test case or a main method that displays the wrong result.

In addition please attach a test file/case that we can actually use i.e. that compiles inside Eclipse SDK. The current one has types which are not available and hence many compile errors.
Comment 3 Dani Megert CLA 2009-05-30 03:11:35 EDT
Please provide the requested information, otherwise we cannot proceed with this bug report.
Comment 4 Dani Megert CLA 2009-06-03 03:25:56 EDT
Please reopen once the requested information has been provided.