/* * #%~ * The Overture Abstract Syntax Tree * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * 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 * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.ast.lex; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Vector; import org.overture.ast.intf.lex.ILexLocation; import org.overture.ast.intf.lex.ILexNameToken; import org.overture.ast.node.INode; public class LexLocationUtils implements Serializable { public static boolean absoluteToStringLocation = true; private static final long serialVersionUID = 1L; /** A collection of all LexLocation objects. */ private static List<ILexLocation> allLocations = new Vector<ILexLocation>(); /** A collection of all LexLocation objects to the AstNodes. */ private static Map<ILexLocation, INode> locationToAstNode = new Hashtable<ILexLocation, INode>(); /** A map of f/op/class names to their lexical span, for coverage. */ private static Map<LexNameToken, ILexLocation> nameSpans = new HashMap<LexNameToken, ILexLocation>();// TODO public static void clearLocations() { synchronized (allLocations) { for (ILexLocation loc : allLocations) { loc.setHits(0); } } } public static void resetLocations() { synchronized (allLocations) { allLocations = new Vector<ILexLocation>(); } synchronized (locationToAstNode) { locationToAstNode = new Hashtable<ILexLocation, INode>(); } // // synchronized (nameSpans) // { // nameSpans = new HashMap<LexNameToken, LexLocation>(); // } } public static void clearAfter(File file, int linecount, int charpos) { // Called from the LexTokenReader's pop method, to remove any // locations "popped". We assume any pushes are on the end of // the vector. synchronized (allLocations) { ListIterator<ILexLocation> it = allLocations.listIterator(allLocations.size()); while (it.hasPrevious()) { ILexLocation l = it.previous(); if (!l.getFile().equals(file) || l.getStartLine() < linecount || l.getStartLine() == linecount && l.getStartPos() < charpos) { break; } else { it.remove(); } } } } public static void addSpan(LexNameToken name, LexToken upto) { LexLocation span = new LexLocation(name.location.getFile(), name.location.getModule(), name.location.getStartLine(), name.location.getStartPos(), upto.location.getEndLine(), upto.location.getEndPos(), upto.location.getStartOffset(), upto.location.getEndOffset()); nameSpans.put(name, span); } public static LexNameList getSpanNames(File filename) { LexNameList list = new LexNameList(); for (LexNameToken name : nameSpans.keySet()) { ILexLocation span = nameSpans.get(name); if (span.getFile().equals(filename)) { list.add(name); } } return list; } public static float getSpanPercent(ILexNameToken name) { int hits = 0; int misses = 0; ILexLocation span = null; synchronized (nameSpans) { span = nameSpans.get(name); } synchronized (allLocations) { for (ILexLocation l : allLocations) { if (l.getExecutable() && l.within(span)) { if (l.getHits() > 0) { hits++; } else { misses++; } } } } int sum = hits + misses; return sum == 0 ? 0 : (float) (1000 * hits / sum) / 10; // NN.N% } public static long getSpanCalls(ILexNameToken name) { // The assumption is that the first executable location in // the span for the name is hit as many time as the span is called. ILexLocation span = null; synchronized (nameSpans) { span = nameSpans.get(name); } synchronized (allLocations) { for (ILexLocation l : allLocations) { if (l.getExecutable() && l.within(span)) { return l.getHits(); } } } return 0; } public static List<Integer> getHitList(File file) { List<Integer> hits = new Vector<Integer>(); synchronized (allLocations) { for (ILexLocation l : allLocations) { if (l.getHits() > 0 && l.getFile().equals(file)) { hits.add(l.getStartLine()); } } } return hits; } public static List<Integer> getMissList(File file) { List<Integer> misses = new Vector<Integer>(); synchronized (allLocations) { for (ILexLocation l : allLocations) { if (l.getHits() == 0 && l.getFile().equals(file)) { misses.add(l.getStartLine()); } } } return misses; } public static List<Integer> getSourceList(File file) { List<Integer> lines = new Vector<Integer>(); int last = 0; synchronized (allLocations) { for (ILexLocation l : allLocations) { if (l.getExecutable() && l.getStartLine() != last && l.getFile().equals(file)) { lines.add(l.getStartLine()); last = l.getStartLine(); } } } return lines; } public static Map<Integer, List<ILexLocation>> getHitLocations(File file) { Map<Integer, List<ILexLocation>> map = new HashMap<Integer, List<ILexLocation>>(); synchronized (allLocations) { for (ILexLocation l : allLocations) { if (l.getExecutable() && l.getHits() > 0 && l.getFile().equals(file)) { List<ILexLocation> list = map.get(l.getStartLine()); if (list == null) { list = new Vector<ILexLocation>(); map.put(l.getStartLine(), list); } list.add(l); } } } return map; } public static float getHitPercent(File file) { int hits = 0; int misses = 0; synchronized (allLocations) { for (ILexLocation l : allLocations) { if (l.getFile().equals(file) && l.getExecutable()) { if (l.getHits() > 0) { hits++; } else { misses++; } } } } int sum = hits + misses; return sum == 0 ? 0 : (float) (1000 * hits / sum) / 10; // NN.N% } public static Map<Integer, List<ILexLocation>> getMissLocations(File file) { Map<Integer, List<ILexLocation>> map = new HashMap<Integer, List<ILexLocation>>(); synchronized (allLocations) { for (ILexLocation l : allLocations) { if (l.getExecutable() && l.getHits() == 0 && l.getFile().equals(file)) { List<ILexLocation> list = map.get(l.getStartLine()); if (list == null) { list = new Vector<ILexLocation>(); map.put(l.getStartLine(), list); } list.add(l); } } } return map; } public static List<ILexLocation> getSourceLocations(File file) { List<ILexLocation> locations = new Vector<ILexLocation>(); synchronized (allLocations) { for (ILexLocation l : allLocations) { if (l.getExecutable() && l.getFile().equals(file)) { locations.add(l); } } } return locations; } public static void mergeHits(File source, File coverage) throws IOException { List<ILexLocation> locations = getSourceLocations(source); BufferedReader br = new BufferedReader(new FileReader(coverage)); String line = br.readLine(); while (line != null) { if (line.charAt(0) == '+') { // Hit lines are "+line from-to=hits" int s1 = line.indexOf(' '); int s2 = line.indexOf('-'); int s3 = line.indexOf('='); int lnum = Integer.parseInt(line.substring(1, s1)); int from = Integer.parseInt(line.substring(s1 + 1, s2)); int to = Integer.parseInt(line.substring(s2 + 1, s3)); int hits = Integer.parseInt(line.substring(s3 + 1)); for (ILexLocation l : locations) // Only executable locations { if (l.getStartLine() == lnum && l.getStartPos() == from && l.getEndPos() == to) { l.setHits(l.getHits() + hits); // l.hits += hits; break; } } } line = br.readLine(); } br.close(); } // FIXME we know this is never called a new solutions is needed public static void addAstNode(LexLocation location, INode node) { synchronized (locationToAstNode) { locationToAstNode.put(location, node); } } public static Map<ILexLocation, INode> getLocationToAstNodeMap() { return locationToAstNode; } public static List<ILexLocation> getAllLocations() { return allLocations; } }