/**
* This file is licensed under the University of Illinois/NCSA Open Source License. See LICENSE.TXT for details.
*/
package edu.illinois.keshmesh.detector.tests;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Set;
import org.eclipse.core.runtime.IPath;
import edu.illinois.keshmesh.detector.bugs.BugInstance;
import edu.illinois.keshmesh.detector.bugs.BugPatterns;
import edu.illinois.keshmesh.detector.bugs.CodePosition;
/**
*
* @author Mohsen Vakilian
* @author Stas Negara
*
*/
public class BugInstanceParser {
private final static String BEGIN_MARKER = "/*["; //$NON-NLS-1$
private final static String END_MARKER = "/*]*/"; //$NON-NLS-1$
private final static String CLOSE_BEGIN_MARKER = "*/"; //$NON-NLS-1$
private final static String SEPARATOR = ","; //$NON-NLS-1$
Deque<NumberedBugInstance> stack;
Set<NumberedBugInstance> numberedBugInstances;
BugInstanceCreator bugInstanceCreator;
IPath filePath;
public BugInstanceParser(BugInstanceCreator bugInstanceCreator, IPath filePath) {
this.stack = new LinkedList<NumberedBugInstance>();
this.numberedBugInstances = new HashSet<NumberedBugInstance>();
this.bugInstanceCreator = bugInstanceCreator;
this.filePath = filePath;
}
//FIXME: This long method should be refactored.
public Set<NumberedBugInstance> parseLine(String line, int currentLineNumber) {
line = line.replaceAll("\\s", "");
Set<NumberedBugInstance> numberedBugInstances = new HashSet<NumberedBugInstance>();
int nextIndex = 0;
while (true) {
int beginMarkerIndex = line.indexOf(BEGIN_MARKER, nextIndex);
int endMarkerIndex = line.indexOf(END_MARKER, nextIndex);
if (beginMarkerIndex == -1 && endMarkerIndex == -1) {
break;
} else if (beginMarkerIndex != -1 && (beginMarkerIndex < endMarkerIndex || endMarkerIndex == -1)) {
nextIndex = beginMarkerIndex + BEGIN_MARKER.length();
String marker = line.substring(nextIndex, line.indexOf(CLOSE_BEGIN_MARKER, nextIndex));
Deque<String> markerParts = new LinkedList<String>(Arrays.asList(marker.split(SEPARATOR)));
String bugPatternName = markerParts.getFirst();
markerParts.removeFirst();
String bugInstanceNumber = markerParts.getFirst();
markerParts.removeFirst();
String[] replacements = markerParts.toArray(new String[markerParts.size()]);
BugInstance testBugInstance = bugInstanceCreator.createTestBugInstance(BugPatterns.getBugPatternByName(bugPatternName), currentLineNumber, -1, filePath, replacements);
NumberedBugInstance numberedBugInstance = new NumberedBugInstance(testBugInstance, bugInstanceNumber);
stack.addLast(numberedBugInstance);
} else if (endMarkerIndex != -1 && (endMarkerIndex < beginMarkerIndex || beginMarkerIndex == -1)) {
nextIndex = endMarkerIndex + END_MARKER.length();
//TODO: Maybe make a setter for BugPosition to return a new instance.
NumberedBugInstance numberedBugInstance = stack.removeLast();
BugInstance testBugInstance = numberedBugInstance.getBugInstance();
CodePosition testBugPosition = testBugInstance.getBugPosition();
BugInstance testBugInstanceWithLastLineNumber = new BugInstance(testBugInstance.getBugPattern(), new CodePosition(testBugPosition.getFirstLine(), currentLineNumber,
testBugPosition.getSourcePath(), null), testBugInstance.getFixInformation());
numberedBugInstances.add(new NumberedBugInstance(testBugInstanceWithLastLineNumber, numberedBugInstance.getNumber()));
}
}
return numberedBugInstances;
}
public Set<NumberedBugInstance> parseExpectedBugInstances(Iterator<String> lineIterator) {
Set<NumberedBugInstance> numberedBugInstances = new HashSet<NumberedBugInstance>();
String line;
int currentLineNumber = 0;
while (lineIterator.hasNext()) {
line = lineIterator.next();
++currentLineNumber;
numberedBugInstances.addAll(parseLine(line, currentLineNumber));
}
return numberedBugInstances;
}
public Set<NumberedBugInstance> parseExpectedBugInstances() throws IOException {
return parseExpectedBugInstances(new FileLineIterator(filePath));
}
public static class FileLineIterator implements Iterator<String> {
private BufferedReader in;
private String nextLine = null;
private boolean needToCheckHashNext = true;
private boolean lastHasNext;
public FileLineIterator(IPath path) throws FileNotFoundException {
in = new BufferedReader(new FileReader(path.toFile()));
}
public boolean hasNextEagerly() {
try {
nextLine = in.readLine();
return (nextLine != null);
} catch (IOException e) {
return false;
}
}
@Override
public boolean hasNext() {
if (!needToCheckHashNext) {
return lastHasNext;
}
lastHasNext = hasNextEagerly();
needToCheckHashNext = false;
return lastHasNext;
}
@Override
public String next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
needToCheckHashNext = true;
return nextLine;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}