| /******************************************************************************* |
| * Copyright (c) 2009, 2021 STMicroelectronics and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Xavier Raynaud <xavier.raynaud@st.com> - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.linuxtools.internal.gcov.parser; |
| |
| import java.io.Serializable; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| public class GcnoFunction implements Serializable, Comparable<GcnoFunction> { |
| |
| private static final long serialVersionUID = -4159055012321132651L; |
| |
| private final long ident; |
| private final long cheksum; |
| private final long firstLineNmbr; |
| private final String name; |
| private final String srcFile; |
| private ArrayList<Block> functionBlocks = new ArrayList<>(); |
| private int numCounts = 0, numBlocks = 0; |
| private final CoverageInfo cvrge = new CoverageInfo(); |
| private boolean hasCatch = false; |
| |
| public GcnoFunction(long fnctnIdent, long fnctnChksm, String fnctnName, String fnctnSrcFle, long fnctnFrstLnNmbr) { |
| this.ident = fnctnIdent; |
| this.cheksum = fnctnChksm; |
| this.name = fnctnName; |
| this.srcFile = fnctnSrcFle; |
| this.firstLineNmbr = fnctnFrstLnNmbr; |
| } |
| |
| @Override |
| public int compareTo(GcnoFunction o) { |
| if (getFirstLineNmbr() > o.getFirstLineNmbr()) { |
| return 1; |
| } else if (getFirstLineNmbr() < o.getFirstLineNmbr()) { |
| return -1; |
| } |
| return 0; |
| } |
| |
| public void addLineCounts(ArrayList<SourceFile> srcs) { |
| Set<Line> linesToCalculate = new HashSet<>(); |
| for (int i = 0; i != numBlocks; i++) { |
| Block blk = functionBlocks.get(i); |
| SourceFile fileSrc = null; |
| |
| long[] enc = blk.getEncoding(); |
| for (int j = 0, k = 0; j != blk.getLineNum(); j++, k++) { |
| if (enc[k] == 0) { |
| int srcn = (int) enc[++k]; |
| for (SourceFile sf : srcs) { |
| if (sf.getIndex() == srcn) { |
| fileSrc = sf; |
| break; |
| } |
| } |
| j++; |
| } else if ((fileSrc != null) && enc[k] < fileSrc.getLines().size()) { |
| Line line = fileSrc.getLines().get((int) enc[k]); |
| if (!line.exists()) { |
| cvrge.incLinesInstrumented(); |
| } |
| if ((line.getCount() == 0) && (blk.getCount() != 0)) { |
| cvrge.incLinesExecuted(); |
| } |
| line.setExists(true); |
| if (line.getBlocks().size() > 1) { |
| // we can't count on the blk count to be accurate (multiple blocks have same |
| // line |
| linesToCalculate.add(line); |
| line.setCount(1); // to avoid counting it twice in execution total |
| } else { |
| line.setCount(line.getCount() + blk.getCount()); |
| } |
| } |
| } |
| } |
| for (Line line : linesToCalculate) { |
| long count = 0; |
| for (Block b : line.getBlocks()) { |
| for (Arc arc : b.getEntryArcs()) { |
| if (!line.hasBlock(arc.getSrcBlock())) { |
| count += arc.getCount(); |
| } |
| } |
| } |
| line.setCount(count); |
| } |
| } |
| |
| public void solveGraphFnctn() { |
| ArrayList<Block> fnctnBlcks = this.functionBlocks; |
| ArrayList<Block> validBlocks = new ArrayList<>(); |
| ArrayList<Block> invalidBlocks = new ArrayList<>(); |
| |
| // Function should contain at least one block |
| if (fnctnBlcks.size() >= 2) { |
| if (fnctnBlcks.get(0).getNumPreds() == 0) { |
| fnctnBlcks.get(0).setNumPreds(50000); |
| } |
| if (fnctnBlcks.get(fnctnBlcks.size() - 1).getNumSuccs() == 0) { |
| fnctnBlcks.get(fnctnBlcks.size() - 1).setNumSuccs(50000); |
| } |
| } |
| |
| for (Block b: fnctnBlcks) { |
| b.setInvalidChain(true); |
| invalidBlocks.add(b); |
| } |
| |
| while (!validBlocks.isEmpty() || !invalidBlocks.isEmpty()) { |
| |
| if (!invalidBlocks.isEmpty()) { |
| for (int i = invalidBlocks.size() - 1; i >= 0; i--) { |
| Block invb = invalidBlocks.get(i); |
| long total = 0; |
| invalidBlocks.remove(i); |
| invb.setInvalidChain(false); |
| |
| if (invb.getNumPreds() != 0 && invb.getNumSuccs() != 0) |
| continue; |
| |
| if (invb.getNumSuccs() == 0) { |
| ArrayList<Arc> extArcs = invb.getExitArcs(); |
| for (Arc arc : extArcs) { |
| total += arc.getCount(); |
| } |
| } |
| // On Windows, we can end up with both numpreds and numsuccs 0 for |
| // a closing brace of a function so we need to check the entry arcs |
| // as well if we don't have a total > 0. |
| if (invb.getNumPreds() == 0 && total == 0) { |
| ArrayList<Arc> entrArcs = invb.getEntryArcs(); |
| for (Arc arc : entrArcs) { |
| total += arc.getCount(); |
| } |
| } |
| |
| invb.setCount(total); |
| invb.setCountValid(true); |
| invb.setValidChain(true); |
| validBlocks.add(invb); |
| } |
| } |
| while (!validBlocks.isEmpty()) { |
| int last = validBlocks.size() - 1; |
| Block vb = validBlocks.get(last); |
| Arc invarc = null; |
| int total = 0; |
| validBlocks.remove(last); |
| |
| vb.setValidChain(false); |
| |
| if (vb.getNumSuccs() == 1) { |
| Block blcksdst; |
| total = (int) vb.getCount(); |
| |
| for (Arc extAr : vb.getExitArcs()) { |
| total -= extAr.getCount(); |
| if (extAr.isCountValid() == false) { |
| invarc = extAr; |
| } |
| } |
| blcksdst = invarc.getDstnatnBlock(); |
| invarc.setCountValid(true); |
| invarc.setCount(total); |
| vb.decNumSuccs(); |
| blcksdst.decNumPreds(); |
| |
| if (blcksdst.isCountValid()) { |
| if (blcksdst.getNumPreds() == 1 && !blcksdst.isValidChain()) { |
| blcksdst.setValidChain(true); |
| validBlocks.add(blcksdst); |
| } |
| } else { |
| if (blcksdst.getNumPreds() == 0 && !blcksdst.isInvalidChain()) { |
| blcksdst.setInvalidChain(true); |
| invalidBlocks.add(blcksdst); |
| } |
| } |
| } |
| |
| if (vb.getNumPreds() == 1) { |
| Block blcksrc; |
| total = (int) vb.getCount(); |
| invarc = null; |
| |
| for (Arc entrAr : vb.getEntryArcs()) { |
| total -= entrAr.getCount(); /* total can end up negative here ?? */ |
| if (!entrAr.isCountValid()) { |
| invarc = entrAr; |
| } |
| } |
| |
| blcksrc = invarc.getSrcBlock(); |
| invarc.setCountValid(true); |
| invarc.setCount(total); /* temporary kludge */ |
| vb.decNumPreds(); |
| blcksrc.decNumSuccs(); |
| |
| if (blcksrc.isCountValid()) { |
| if (blcksrc.getNumSuccs() == 1 && !blcksrc.isInvalidChain()) { |
| blcksrc.setValidChain(true); |
| validBlocks.add(blcksrc); |
| } |
| } else if (blcksrc.getNumSuccs() == 0 && !blcksrc.isInvalidChain()) { |
| blcksrc.setInvalidChain(true); |
| invalidBlocks.add(blcksrc); |
| } |
| } |
| } |
| } |
| } |
| |
| /* getters & setters */ |
| |
| public long getIdent() { |
| return ident; |
| } |
| |
| public long getCheksum() { |
| return cheksum; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public String getSrcFile() { |
| return srcFile; |
| } |
| |
| public long getFirstLineNmbr() { |
| return firstLineNmbr; |
| } |
| |
| public ArrayList<Block> getFunctionBlocks() { |
| return functionBlocks; |
| } |
| |
| public Block getFunctionBlock(int i) { |
| return functionBlocks.get(i); |
| } |
| |
| public void setFunctionBlocks(ArrayList<Block> functionBlocks) { |
| this.functionBlocks = functionBlocks; |
| } |
| |
| public boolean hasCatch() { |
| return hasCatch; |
| } |
| |
| public void incNumCounts() { |
| this.numCounts++; |
| } |
| |
| public int getNumCounts() { |
| return numCounts; |
| } |
| |
| public int getNumBlocks() { |
| return numBlocks; |
| } |
| |
| public void setNumBlocks(int numBlocks) { |
| this.numBlocks = numBlocks; |
| } |
| |
| public CoverageInfo getCvrge() { |
| return cvrge; |
| } |
| |
| public void setHasCatch(boolean hasCatch) { |
| this.hasCatch = hasCatch; |
| } |
| |
| } |