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}