blob: 1d6df8e0ad3e554b46650fa753907801e71126a9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 University of Illinois at Urbana-Champaign and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.rephraserengine.core.preservation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.rephraserengine.core.vpg.IVPGNode;
import org.eclipse.rephraserengine.core.vpg.VPG;
import org.eclipse.rephraserengine.core.vpg.VPGEdge;
import org.eclipse.rephraserengine.core.vpg.eclipse.EclipseVPG;
/**
* A mutable, in-memory copy of the edges in part of a program graph.
*
* @author Jeff Overbey
*/
final class Model<A, T, R extends IVPGNode<T>>
{
private String name;
private EclipseVPG<A,T,R> vpg;
private List<String> files;
private Set<String> filesWithNoEdges;
private Collection<VPGEdge<A,T,R>> edges;
public Model(String name, IProgressMonitor pm, int ticks, EclipseVPG<A,T,R> vpg, String... filenames)
{
this(name, pm, ticks, vpg, Arrays.asList(filenames));
}
public Model(String name, IProgressMonitor pm, int ticks, EclipseVPG<A,T,R> vpg, List<String> filenames)
{
this.name = name;
this.vpg = vpg;
pm.subTask(Messages.Model_PreparingToCompute + name);
this.files = vpg.sortFilesAccordingToDependencies(new ArrayList<String>(filenames)); //, new NullProgressMonitor());
this.filesWithNoEdges = new TreeSet<String>();
pm = new SubProgressMonitor(pm, ticks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
pm.beginTask(Messages.bind(Messages.Model_Computing, name), files.size());
this.edges = new ArrayList<VPGEdge<A,T,R>>();
for (String thisFile : files)
{
pm.subTask(VPG.lastSegmentOfFilename(thisFile));
addEdges(thisFile, pm);
pm.worked(1);
}
pm.done();
}
private void addEdges(String filename, IProgressMonitor pm)
{
int count = 0;
for (VPGEdge<A,T,R> edge : vpg.getAllEdgesFor(filename))
{
edges.add(edge);
count++;
}
if (count == 0)
filesWithNoEdges.add(filename);
}
List<String> getFiles()
{
return files;
}
void inormalize(ReplacementList replacements, IProgressMonitor pm)
{
pm = new SubProgressMonitor(pm, 0, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
pm.beginTask(Messages.bind(Messages.Model_Normalizing, name), edges.size());
// Use a set to eliminate duplicates
Set<VPGEdge<A,T,R>> newEdges = createNewEdgeSet();
for (VPGEdge<A,T,R> e : edges)
{
newEdges.add(e.projectInitial(replacements, vpg));
pm.worked(1);
}
edges = newEdges;
pm.done();
}
void dnormalize(ReplacementList replacements, IProgressMonitor pm)
{
pm = new SubProgressMonitor(pm, 0, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
pm.beginTask(Messages.bind(Messages.Model_Normalizing, name), edges.size());
// Use a set to eliminate duplicates
Set<VPGEdge<A,T,R>> newEdges = createNewEdgeSet();
for (VPGEdge<A,T,R> e : edges)
{
newEdges.add(e.projectFinal(replacements, vpg));
pm.worked(1);
}
edges = newEdges;
pm.done();
}
protected Set<VPGEdge<A,T,R>> createNewEdgeSet()
{
return new TreeSet<VPGEdge<A,T,R>>();
}
ModelDiff checkPreservation(Model<A,T,R> that, PreservationRuleset ruleset, IProgressMonitor pm)
{
pm = new SubProgressMonitor(pm, 0, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
pm.beginTask(
Messages.bind(Messages.Model_Differencing, this.name, that.name),
this.edges.size() + that.edges.size());
ModelDiff diff = new ModelDiff();
int type = 0;
PreservationAnalyzer<A,T,R> analyzer = new MergePreservationAnalyzer<A,T,R>(this.edges, that.edges, ruleset);
while (analyzer.hasEdgesRemaining())
{
int edgesRemainingBefore = analyzer.countEdgesRemaining();
for (VPGEdge.Classification classification : VPGEdge.Classification.values())
analyzer.checkPreservation(type, classification, diff);
analyzer.ensureNoEdgesRemaining(type);
type++;
pm.worked(analyzer.countEdgesRemaining() - edgesRemainingBefore);
}
pm.done();
return diff;
}
@Override public String toString()
{
if (edges.size() > 100)
return "(Model contains more than 100 edges)"; //$NON-NLS-1$
else
return toString(null, null, null);
}
public String toString(String filename, String fileContents, ArrayList<Integer> lineMap)
{
StringBuilder sb = new StringBuilder();
sb.append(edges.size());
sb.append(" edges\n\n"); //$NON-NLS-1$
Set<Integer> edgeTypes = new TreeSet<Integer>();
for (VPGEdge<?,?,?> entry : edges)
edgeTypes.add(entry.getType());
for (int edgeType : edgeTypes)
{
for (VPGEdge<?,?,?> entry : edges)
{
if (entry.getType() == edgeType)
{
if (entry.getSource() == null)
{
sb.append("(null"); //$NON-NLS-1$
}
else
{
if (!entry.getSource().getFilename().equals(filename))
{
sb.append(entry.getSource().getFilename());
sb.append(':');
}
sb.append('[');
sb.append(String.format("%5d", entry.getSource().getOffset())); //$NON-NLS-1$
sb.append(", "); //$NON-NLS-1$
sb.append(String.format("%5d", entry.getSource().getEndOffset())); //$NON-NLS-1$
}
sb.append(") ===("); //$NON-NLS-1$
sb.append(entry.getType());
sb.append(")==> "); //$NON-NLS-1$
if (entry.getSink() == null)
{
sb.append("(null"); //$NON-NLS-1$
}
else
{
if (!entry.getSink().getFilename().equals(filename))
{
sb.append(entry.getSink().getFilename());
sb.append(':');
}
sb.append('[');
sb.append(String.format("%5d", entry.getSink().getOffset())); //$NON-NLS-1$
sb.append(", "); //$NON-NLS-1$
sb.append(String.format("%5d", entry.getSink().getEndOffset())); //$NON-NLS-1$
}
sb.append(")"); //$NON-NLS-1$
if (fileContents != null)
{
sb.append(" ["); //$NON-NLS-1$
if (entry.getSource() == null || !entry.getSource().getFilename().equals(filename))
sb.append('?');
else if (entry.getSource().getOffset() >= 0 && entry.getSource().getEndOffset() >= entry.getSource().getOffset())
sb.append(extractText(fileContents, entry.getSource()));
sb.append("]"); //$NON-NLS-1$
if (lineMap != null)
{
sb.append(" (Line "); //$NON-NLS-1$
sb.append(getLine(entry.getSource().getOffset(), lineMap));
sb.append(")"); //$NON-NLS-1$
}
sb.append(" ===("); //$NON-NLS-1$
sb.append(vpg.describeEdgeType(entry.getType()));
sb.append(")==> ["); //$NON-NLS-1$
if (entry.getSink() == null || !entry.getSink().getFilename().equals(filename))
sb.append('?');
else if (entry.getSink().getOffset() >= 0 && entry.getSink().getEndOffset() >= entry.getSink().getOffset())
sb.append(extractText(fileContents, entry.getSink()));
sb.append("]"); //$NON-NLS-1$
if (lineMap != null)
{
sb.append(" (Line "); //$NON-NLS-1$
sb.append(getLine(entry.getSink().getOffset(), lineMap));
sb.append(")"); //$NON-NLS-1$
}
}
sb.append('\n');
}
}
}
return sb.toString();
}
private String extractText(String fileContents, IVPGNode<?> tokenRef)
{
String result = fileContents.substring(tokenRef.getOffset(), tokenRef.getEndOffset());
result = result.replace("\t", "\\t"); //$NON-NLS-1$ //$NON-NLS-2$
result = result.replace("\r", "\\r"); //$NON-NLS-1$ //$NON-NLS-2$
result = result.replace("\n", "\\n"); //$NON-NLS-1$ //$NON-NLS-2$
if (result.length() > 17)
result = result.substring(0, 18) + "..."; //$NON-NLS-1$
return result;
}
private int getLine(int offset, ArrayList<Integer> lineMap)
{
for (int i = 0; i < lineMap.size(); i++)
if (offset < lineMap.get(i))
return i+1;
return lineMap.size();
}
}