/*
* Cobertura - http://cobertura.sourceforge.net/
*
* Copyright (C) 2011 Piotr Tabor
*
* Note: This file is dual licensed under the GPL and the Apache
* Source License (so that it can be used from both the main
* Cobertura classes and the ant tasks).
*
* Cobertura 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 2 of the License,
* or (at your option) any later version.
*
* Cobertura 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 Cobertura; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
package net.sourceforge.cobertura.instrument.tp;
import net.sourceforge.cobertura.coveragedata.LineData;
import org.objectweb.asm.Label;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Class representing a touch-point connected to a a SWITCH instruction in a source-code
* <p/>
* <p>A SWITCH touch-point uses one more counter then distinct number destination labels ({@link #getCountersForLabelsCnt()}).<br/>
* One 'internal' counterId ({@link #counterId}) is a special identifier of SWITCH statement (used in runtime), but in fact we don't expect any
* incrementation of the counter. We implemented this to use a counterId because we are storing the value inside 'internal variable' and we need to be sure
* that the value is connected to the last seen SWITCH statement.<br/>
* <p/>
* Or other counterIds represents different branches (different destination labels of the switch).
* </p>
* <p/>
* <p>We also storing a {@link #methodName} and a {@link #methodSignature} (consider to move this fields into {@link TouchPointDescriptor}).
* Those fields are needed to properly create instance of {@link LineData}. </p>
*
* @author piotr.tabor@gmail.com
*/
public class SwitchTouchPointDescriptor extends TouchPointDescriptor {
private final Label defaultDestinationLabel;
private final Label[] labels;
/**
* Encoded as: {@link org.objectweb.asm.commons#AnalyzerAdapter#stack}
*/
private final String enum_type;
private Integer counterId;
private Map<Label, Integer> label2counterId;
/**
* Creates o new switch-touch point.
*
* @param eventId - eventId connected to the SWITCH instruction
* @param currentLine - line number of the switch
* @param def - internal identifier of a default destination label
* @param labels - table of other destination labels for different values (duplicates allowed)
*/
public SwitchTouchPointDescriptor(int eventId, int currentLine, Label def,
Label[] labels, String enum_type) {
super(eventId, currentLine);
this.labels = labels;
this.defaultDestinationLabel = def;
this.enum_type = enum_type;
}
public Integer getCounterId() {
return counterId;
}
public void setCounterId(Integer counterId) {
this.counterId = counterId;
}
@Override
public int assignCounters(AtomicInteger idGenerator) {
counterId = idGenerator.incrementAndGet();
label2counterId = new HashMap<Label, Integer>();
int idp = idGenerator.incrementAndGet();
label2counterId.put(defaultDestinationLabel, idp);
int i = 0;
for (Label l : labels) {
i++;
idp = idGenerator.incrementAndGet();
label2counterId.put(l, idp);
}
return i + 2;
}
public Integer getCounterIdForLabel(Label label) {
return label2counterId.get(label);
}
public Collection<Integer> getCountersForLabels() {
return label2counterId.values();
}
/**
* <p>Works before calling 'assignCounters'</p>
*
* @return Number of distinct destination labels of the SWITCH (It's the same as number of branches supported by the switch).
*/
public int getCountersForLabelsCnt() {
Set<Label> l = new HashSet<Label>(Arrays.asList(labels));
l.add(defaultDestinationLabel);
return l.size();
}
public String getEnumType() {
return enum_type;
}
}