• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright (c) 2009, 2021 Mountainminds GmbH & Co. KG and Contributors
3  * This program and the accompanying materials are made available under
4  * the terms of the Eclipse Public License 2.0 which is available at
5  * http://www.eclipse.org/legal/epl-2.0
6  *
7  * SPDX-License-Identifier: EPL-2.0
8  *
9  * Contributors:
10  *    Marc R. Hoffmann - initial API and implementation
11  *
12  *******************************************************************************/
13 package org.jacoco.core.internal.analysis;
14 
15 import org.jacoco.core.analysis.CoverageNodeImpl;
16 import org.jacoco.core.analysis.ICounter;
17 import org.jacoco.core.analysis.ILine;
18 import org.jacoco.core.analysis.ISourceNode;
19 
20 /**
21  * Implementation of {@link ISourceNode}.
22  */
23 public class SourceNodeImpl extends CoverageNodeImpl implements ISourceNode {
24 
25 	private LineImpl[] lines;
26 
27 	/** first line number in {@link #lines} */
28 	private int offset;
29 
30 	/**
31 	 * Create a new source node implementation instance.
32 	 *
33 	 * @param elementType
34 	 *            element type
35 	 * @param name
36 	 *            name of the element
37 	 */
SourceNodeImpl(final ElementType elementType, final String name)38 	public SourceNodeImpl(final ElementType elementType, final String name) {
39 		super(elementType, name);
40 		lines = null;
41 		offset = UNKNOWN_LINE;
42 	}
43 
44 	/**
45 	 * Make sure that the internal buffer can keep lines from first to last.
46 	 * While the buffer is also incremented automatically, this method allows
47 	 * optimization in case the total range is known in advance.
48 	 *
49 	 * @param first
50 	 *            first line number or {@link ISourceNode#UNKNOWN_LINE}
51 	 * @param last
52 	 *            last line number or {@link ISourceNode#UNKNOWN_LINE}
53 	 */
ensureCapacity(final int first, final int last)54 	public void ensureCapacity(final int first, final int last) {
55 		if (first == UNKNOWN_LINE || last == UNKNOWN_LINE) {
56 			return;
57 		}
58 		if (lines == null) {
59 			offset = first;
60 			lines = new LineImpl[last - first + 1];
61 		} else {
62 			final int newFirst = Math.min(getFirstLine(), first);
63 			final int newLast = Math.max(getLastLine(), last);
64 			final int newLength = newLast - newFirst + 1;
65 			if (newLength > lines.length) {
66 				final LineImpl[] newLines = new LineImpl[newLength];
67 				System.arraycopy(lines, 0, newLines, offset - newFirst,
68 						lines.length);
69 				offset = newFirst;
70 				lines = newLines;
71 			}
72 		}
73 	}
74 
75 	/**
76 	 * Increments all counters by the values of the given child. When
77 	 * incrementing the line counter it is assumed that the child refers to the
78 	 * same source file.
79 	 *
80 	 * @param child
81 	 *            child node to add
82 	 */
increment(final ISourceNode child)83 	public void increment(final ISourceNode child) {
84 		instructionCounter = instructionCounter
85 				.increment(child.getInstructionCounter());
86 		branchCounter = branchCounter.increment(child.getBranchCounter());
87 		complexityCounter = complexityCounter
88 				.increment(child.getComplexityCounter());
89 		methodCounter = methodCounter.increment(child.getMethodCounter());
90 		classCounter = classCounter.increment(child.getClassCounter());
91 		final int firstLine = child.getFirstLine();
92 		if (firstLine != UNKNOWN_LINE) {
93 			final int lastLine = child.getLastLine();
94 			ensureCapacity(firstLine, lastLine);
95 			for (int i = firstLine; i <= lastLine; i++) {
96 				final ILine line = child.getLine(i);
97 				incrementLine(line.getInstructionCounter(),
98 						line.getBranchCounter(), i);
99 			}
100 		}
101 	}
102 
103 	/**
104 	 * Increments instructions and branches by the given counter values. If a
105 	 * optional line number is specified the instructions and branches are added
106 	 * to the given line. The line counter is incremented accordingly.
107 	 *
108 	 * @param instructions
109 	 *            instructions to add
110 	 * @param branches
111 	 *            branches to add
112 	 * @param line
113 	 *            optional line number or {@link ISourceNode#UNKNOWN_LINE}
114 	 */
increment(final ICounter instructions, final ICounter branches, final int line)115 	public void increment(final ICounter instructions, final ICounter branches,
116 			final int line) {
117 		if (line != UNKNOWN_LINE) {
118 			incrementLine(instructions, branches, line);
119 		}
120 		instructionCounter = instructionCounter.increment(instructions);
121 		branchCounter = branchCounter.increment(branches);
122 	}
123 
incrementLine(final ICounter instructions, final ICounter branches, final int line)124 	private void incrementLine(final ICounter instructions,
125 			final ICounter branches, final int line) {
126 		ensureCapacity(line, line);
127 		final LineImpl l = getLine(line);
128 		final int oldTotal = l.getInstructionCounter().getTotalCount();
129 		final int oldCovered = l.getInstructionCounter().getCoveredCount();
130 		lines[line - offset] = l.increment(instructions, branches);
131 
132 		// Increment line counter:
133 		if (instructions.getTotalCount() > 0) {
134 			if (instructions.getCoveredCount() == 0) {
135 				if (oldTotal == 0) {
136 					lineCounter = lineCounter
137 							.increment(CounterImpl.COUNTER_1_0);
138 				}
139 			} else {
140 				if (oldTotal == 0) {
141 					lineCounter = lineCounter
142 							.increment(CounterImpl.COUNTER_0_1);
143 				} else {
144 					if (oldCovered == 0) {
145 						lineCounter = lineCounter.increment(-1, +1);
146 					}
147 				}
148 			}
149 		}
150 	}
151 
152 	// === ISourceNode implementation ===
153 
getFirstLine()154 	public int getFirstLine() {
155 		return offset;
156 	}
157 
getLastLine()158 	public int getLastLine() {
159 		return lines == null ? UNKNOWN_LINE : (offset + lines.length - 1);
160 	}
161 
getLine(final int nr)162 	public LineImpl getLine(final int nr) {
163 		if (lines == null || nr < getFirstLine() || nr > getLastLine()) {
164 			return LineImpl.EMPTY;
165 		}
166 		final LineImpl line = lines[nr - offset];
167 		return line == null ? LineImpl.EMPTY : line;
168 	}
169 
170 }
171