001/*
002 * Cobertura - http://cobertura.sourceforge.net/
003 *
004 * Copyright (C) 2011 Piotr Tabor
005 *
006 * Note: This file is dual licensed under the GPL and the Apache
007 * Source License (so that it can be used from both the main
008 * Cobertura classes and the ant tasks).
009 *
010 * Cobertura is free software; you can redistribute it and/or modify
011 * it under the terms of the GNU General Public License as published
012 * by the Free Software Foundation; either version 2 of the License,
013 * or (at your option) any later version.
014 *
015 * Cobertura is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of
017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018 * General Public License for more details.
019 *
020 * You should have received a copy of the GNU General Public License
021 * along with Cobertura; if not, write to the Free Software
022 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
023 * USA
024 */
025
026package net.sourceforge.cobertura.instrument.tp;
027
028import java.util.Arrays;
029import java.util.Collection;
030import java.util.HashMap;
031import java.util.HashSet;
032import java.util.Map;
033import java.util.Set;
034import java.util.concurrent.atomic.AtomicInteger;
035
036import net.sourceforge.cobertura.coveragedata.LineData;
037
038import org.objectweb.asm.Label;
039
040/**
041 * Class representing a touch-point connected to a a SWITCH instruction in a source-code
042 * 
043 * <p>A SWITCH touch-point uses one more counter then distinct number destination labels ({@link #getCountersForLabelsCnt()}).<br/>
044 *       One 'internal' counterId ({@link #counterId}) is a special identifier of SWITCH statement (used in runtime), but in fact we don't expect any
045 * 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
046 * that the value is connected to the last seen SWITCH statement.<br/>
047 * 
048 * Or other counterIds represents different branches (different destination labels of the switch). 
049 * </p> 
050 * 
051 * <p>We also storing a {@link #methodName} and a {@link #methodSignature} (consider to move this fields into {@link TouchPointDescriptor}).
052 * Those fields are needed to properly create instance of {@link LineData}. </p> 
053 *   
054 * @author piotr.tabor@gmail.com
055 */
056public class SwitchTouchPointDescriptor extends TouchPointDescriptor{   
057        private final Label defaultDestinationLabel;
058        private final Label[] labels;
059        /** Encoded as: {@link org.objectweb.asm.commons#AnalyzerAdapter#stack}*/       
060        private final String enum_type;
061        
062        private Integer counterId;
063        private Map<Label,Integer> label2counterId;
064
065        /**
066         * Creates o new switch-touch point. 
067         * @param eventId     - eventId connected to the SWITCH instruction
068         * @param currentLine - line number of the switch
069         * @param def         - internal identifier of a default destination label
070         * @param labels      - table of other destination labels for different values (duplicates allowed) 
071         */
072        public SwitchTouchPointDescriptor(int eventId, int currentLine, Label def,      Label[] labels, String enum_type) {
073                super(eventId, currentLine);
074                this.labels=labels;
075                this.defaultDestinationLabel=def;
076                this.enum_type = enum_type;
077        }
078        
079        public Integer getCounterId() {
080                return counterId;
081        }
082        public void setCounterId(Integer counterId) {
083                this.counterId = counterId;
084        }
085        
086        @Override
087        public int assignCounters(AtomicInteger idGenerator) {
088                counterId=idGenerator.incrementAndGet();
089                label2counterId=new HashMap<Label, Integer>();
090                int idp=idGenerator.incrementAndGet();
091                label2counterId.put(defaultDestinationLabel,idp);
092                int i=0; 
093                for(Label l:labels){
094                        i++;
095                        idp=idGenerator.incrementAndGet();
096                        label2counterId.put(l, idp);
097                }
098                return i+2;
099        }
100
101
102        public Integer getCounterIdForLabel(Label label) {
103                return label2counterId.get(label);
104        }
105        
106        public Collection<Integer> getCountersForLabels(){
107                return label2counterId.values();
108        }
109        
110        /**
111         * <p>Works before calling 'assignCounters'</p>
112         * 
113         * @return Number of distinct destination labels of the SWITCH (It's the same as number of branches supported by the switch).
114         *  
115         */
116        public int getCountersForLabelsCnt(){
117                Set<Label> l=new HashSet<Label>(Arrays.asList(labels));
118                l.add(defaultDestinationLabel);
119                return l.size();
120        }
121        
122        public String getEnumType(){
123                return enum_type;
124        }
125        
126}