blob: f62de9889d515ddc3cdc745f2bc828e607ad0eae [file] [log] [blame]
Yue Ganaf3c4122016-12-05 14:36:02 +00001// Copyright 2016 The Bazel Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.testing.coverage;
16
iirina88a313d2019-05-22 00:45:46 -070017import java.io.IOException;
18import java.io.InputStream;
Yue Ganaf3c4122016-12-05 14:36:02 +000019import java.util.List;
20import java.util.Map;
21import java.util.TreeMap;
22import org.jacoco.core.analysis.Analyzer;
Lukacs Berki22b79d32017-01-05 08:59:22 +000023import org.jacoco.core.analysis.IClassCoverage;
24import org.jacoco.core.analysis.ICoverageVisitor;
Yue Ganaf3c4122016-12-05 14:36:02 +000025import org.jacoco.core.data.ExecutionData;
26import org.jacoco.core.data.ExecutionDataStore;
iirina88a313d2019-05-22 00:45:46 -070027import org.jacoco.core.internal.InputStreams;
Yue Ganaf3c4122016-12-05 14:36:02 +000028import org.jacoco.core.internal.data.CRC64;
29import org.jacoco.core.internal.flow.ClassProbesAdapter;
30import org.objectweb.asm.ClassReader;
31
32/**
33 * Analyzer that process the branch coverage detail information.
34 *
35 * <p>Reuse the Analyzer class from Jacoco to avoid duplicating the content detection logic.
36 * Override the main {@code Analyzer.analyzeClass} method which does the main work.
37 */
38public class BranchDetailAnalyzer extends Analyzer {
39
40 private final ExecutionDataStore executionData;
41 private final Map<String, BranchCoverageDetail> branchDetails;
42
43 public BranchDetailAnalyzer(final ExecutionDataStore executionData) {
iirina88a313d2019-05-22 00:45:46 -070044 super(
45 executionData,
46 new ICoverageVisitor() {
47 @Override
48 public void visitCoverage(IClassCoverage coverage) {}
49 });
Yue Ganaf3c4122016-12-05 14:36:02 +000050 this.executionData = executionData;
51 this.branchDetails = new TreeMap<String, BranchCoverageDetail>();
52 }
53
iirina88a313d2019-05-22 00:45:46 -070054 // Override all analyzeClass methods.
55 @Override
56 public void analyzeClass(final InputStream input, final String location) throws IOException {
57 final byte[] buffer;
58 try {
59 buffer = InputStreams.readFully(input);
60 } catch (final IOException e) {
61 throw analyzerError(location, e);
62 }
63 analyzeClass(buffer, location);
64 }
65
66 @Override
67 public void analyzeClass(final byte[] buffer, final String location) throws IOException {
68 try {
69 analyzeClass(buffer);
70 } catch (final RuntimeException cause) {
71 throw analyzerError(location, cause);
72 }
73 }
74
Yue Ganaf3c4122016-12-05 14:36:02 +000075 public void analyzeClass(final ClassReader reader) {
76 final Map<Integer, BranchExp> lineToBranchExp = mapProbes(reader);
77
iirinaff1f7452019-05-20 09:02:49 -070078 long classid = CRC64.classId(reader.b);
Yue Ganaf3c4122016-12-05 14:36:02 +000079 ExecutionData classData = executionData.get(classid);
80 if (classData == null) {
81 return;
82 }
83 boolean[] probes = classData.getProbes();
84
85 BranchCoverageDetail detail = new BranchCoverageDetail();
86
87 for (Map.Entry<Integer, BranchExp> entry : lineToBranchExp.entrySet()) {
88 int line = entry.getKey();
89 BranchExp branchExp = entry.getValue();
90 List<CovExp> branches = branchExp.getBranches();
91
92 detail.setBranches(line, branches.size());
93 for (int branchIdx = 0; branchIdx < branches.size(); branchIdx++) {
94 if (branches.get(branchIdx).eval(probes)) {
95 detail.setTakenBit(line, branchIdx);
96 }
97 }
98 }
99 if (detail.linesWithBranches().size() > 0) {
100 branchDetails.put(reader.getClassName(), detail);
101 }
102 }
103
iirina88a313d2019-05-22 00:45:46 -0700104 private void analyzeClass(final byte[] source) {
105 final ClassReader reader = new ClassReader(source);
106 analyzeClass(reader);
107 }
108
109 private IOException analyzerError(final String location, final Exception cause) {
110 final IOException ex = new IOException(String.format("Error while analyzing %s.", location));
111 ex.initCause(cause);
112 return ex;
113 }
114
Yue Ganaf3c4122016-12-05 14:36:02 +0000115 // Generate the line to probeExp map so that we can evaluate the coverage.
116 private Map<Integer, BranchExp> mapProbes(final ClassReader reader) {
117 final ClassProbesMapper mapper = new ClassProbesMapper();
118 final ClassProbesAdapter adapter = new ClassProbesAdapter(mapper, false);
119 reader.accept(adapter, 0);
120
121 return mapper.result();
122 }
123
124 public Map<String, BranchCoverageDetail> getBranchDetails() {
125 return branchDetails;
126 }
127}