Bug 550474 - Linuxtools GCov incorrectly interprets gcc 9.1 data files

- modify Line to store blocks that specify it (can be more than 1
  in later releases)
- modify SourceFile.createLines() method to store blocks for each
  line
- modify GcdaRecordsParser.parseGcdaRecord() method to note whether
  arcs are out of order (not currently used but may be needed in
  future)
- modify GcnoFunction.addLineCounts() method to account for multiple
  blocks pointing to same line in which case add all entry arc counts
  from blocks that are not registered for the line
- also remove kludge that set arc counts to 0 when totals ended up
  less than 0
- add destination block indice info to Arc to make it easier to debug
  in conjunction with gcov-dump output
- bump up gcov plug-in version

Change-Id: I2ac25c968d46871652f74ecb6bbb99cdd3d608fa
Reviewed-on: https://git.eclipse.org/r/149004
Tested-by: Linux Tools Bot <linuxtools-bot@eclipse.org>
Reviewed-by: Jeff Johnston <jjohnstn@redhat.com>
(cherry picked from commit 376e09dd9a67ed50f73707323ba845e3f521cb79)
Reviewed-on: https://git.eclipse.org/r/149008
diff --git a/gcov/org.eclipse.linuxtools.gcov.core/META-INF/MANIFEST.MF b/gcov/org.eclipse.linuxtools.gcov.core/META-INF/MANIFEST.MF
index 3db8462..6aa520d 100644
--- a/gcov/org.eclipse.linuxtools.gcov.core/META-INF/MANIFEST.MF
+++ b/gcov/org.eclipse.linuxtools.gcov.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %bundleName
 Bundle-SymbolicName: org.eclipse.linuxtools.gcov.core;singleton:=true
-Bundle-Version: 6.1.0.qualifier
+Bundle-Version: 6.2.0.qualifier
 Bundle-Activator: org.eclipse.linuxtools.internal.gcov.Activator
 Bundle-Vendor: %bundleProvider
 Require-Bundle: org.eclipse.ui,
diff --git a/gcov/org.eclipse.linuxtools.gcov.core/pom.xml b/gcov/org.eclipse.linuxtools.gcov.core/pom.xml
index 68fabd4..9add7ed 100644
--- a/gcov/org.eclipse.linuxtools.gcov.core/pom.xml
+++ b/gcov/org.eclipse.linuxtools.gcov.core/pom.xml
@@ -19,7 +19,7 @@
   </parent>
 
   <artifactId>org.eclipse.linuxtools.gcov.core</artifactId>
-  <version>6.1.0-SNAPSHOT</version>
+  <version>6.2.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <name>Linux Tools GCov Plug-in</name>
diff --git a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/Arc.java b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/Arc.java
index 7539e8a..ee245d9 100644
--- a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/Arc.java
+++ b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/Arc.java
@@ -1,6 +1,6 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2018 STMicroelectronics and others.
- * 
+ * Copyright (c) 2009, 2019 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/
@@ -28,6 +28,7 @@
 
     private final Block srcBlock;
     private final Block dstnatnBlock;
+	private final int dstnatnBlockIndice;
     private final long flag;
     private final boolean fake;
     private final boolean onTree;
@@ -44,6 +45,7 @@
      */
     public Arc(int srcBlockIndice, int dstnatnBlockIndice, long flag, List<Block> otherArcParams) {
         this.flag = flag;
+		this.dstnatnBlockIndice = dstnatnBlockIndice;
         this.dstnatnBlock = otherArcParams.get(dstnatnBlockIndice);
         this.srcBlock = otherArcParams.get(srcBlockIndice);
         this.count = 0;
@@ -71,6 +73,10 @@
         return dstnatnBlock;
     }
 
+	public int getDstnatnBlockIndice() {
+		return dstnatnBlockIndice;
+	}
+
     public long getFlag() {
         return flag;
     }
diff --git a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/GcdaRecordsParser.java b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/GcdaRecordsParser.java
index 5b984e8..ef0e53e 100644
--- a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/GcdaRecordsParser.java
+++ b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/GcdaRecordsParser.java
@@ -156,6 +156,9 @@
 
                     for (Block b : fnctnBlcks) {
                         int nonFakeExit = 0;
+						int prevBlockIndice = 0;
+						@SuppressWarnings("unused")
+						boolean outOfOrder = false;
 
                         ArrayList<Arc> arcsExit = b.getExitArcs();
                         for (Arc extArc : arcsExit) {
@@ -168,6 +171,11 @@
                                 extArc.setCountValid(true);
                                 b.decNumSuccs();
                                 extArc.getDstnatnBlock().decNumPreds();
+								if (prevBlockIndice > extArc.getDstnatnBlockIndice()) {
+//									System.err.println("out of order"); //$NON-NLS-1$
+									outOfOrder = true;
+								}
+								prevBlockIndice = extArc.getDstnatnBlockIndice();
                             }
                         }
 
diff --git a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/GcnoFunction.java b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/GcnoFunction.java
index 7ba4055..f8107b8 100644
--- a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/GcnoFunction.java
+++ b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/GcnoFunction.java
@@ -14,6 +14,8 @@
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
 
 public class GcnoFunction implements Serializable, Comparable<GcnoFunction> {
 
@@ -47,6 +49,7 @@
     }
 
     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;
@@ -71,10 +74,28 @@
                         cvrge.incLinesExecuted();
                     }
                     line.setExists(true);
-                    line.setCount(line.getCount() + blk.getCount());
+					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() {
@@ -108,7 +129,7 @@
 
                     if (invb.getNumPreds() != 0 && invb.getNumSuccs() != 0)
                     	continue;
-                    
+
                     if (invb.getNumSuccs() == 0) {
                         ArrayList<Arc> extArcs = invb.getExitArcs();
                         for (Arc arc : extArcs) {
@@ -183,7 +204,7 @@
 
                     blcksrc = invarc.getSrcBlock();
                     invarc.setCountValid(true);
-					invarc.setCount(total < 0 ? 0 : total); /* temporary kludge */
+					invarc.setCount(total); /* temporary kludge */
                     vb.decNumPreds();
                     blcksrc.decNumSuccs();
 
diff --git a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/Line.java b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/Line.java
index b7575ce..8b2868d 100644
--- a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/Line.java
+++ b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/Line.java
@@ -1,6 +1,6 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2018 STMicroelectronics and others.
- * 
+ * Copyright (c) 2009, 2019 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/
@@ -13,6 +13,8 @@
 package org.eclipse.linuxtools.internal.gcov.parser;
 
 import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
 
 
 public class Line implements Serializable{
@@ -20,6 +22,7 @@
     private static final long serialVersionUID = 8804878976767948267L;
     private boolean exists = false;
     private long count = 0;
+	private Set<Block> blocks = new HashSet<>();
 
     /*Getters & setters*/
 
@@ -39,4 +42,21 @@
         return count;
     }
 
+	public void addBlock(Block b) {
+		blocks.add(b);
+	}
+
+	public boolean hasBlock(Block b) {
+		return blocks.contains(b);
+	}
+
+	public Set<Block> getBlocks() {
+		return blocks;
+	}
+
+	@Override
+	public int hashCode() {
+		return blocks.hashCode();
+	}
+
 }
diff --git a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/SourceFile.java b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/SourceFile.java
index b1dc235..9ebbdd6 100644
--- a/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/SourceFile.java
+++ b/gcov/org.eclipse.linuxtools.gcov.core/src/org/eclipse/linuxtools/internal/gcov/parser/SourceFile.java
@@ -1,6 +1,6 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2018 STMicroelectronics and others.
- * 
+ * Copyright (c) 2009, 2019 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/
@@ -108,6 +108,21 @@
         for (int j = 0; j < n; j++) {
             lines.add(new Line());
         }
+		for (GcnoFunction fn : getFnctns()) {
+			for (Block b : fn.getFunctionBlocks()) {
+				long[] blockLines = b.getEncoding();
+				if (blockLines == null) {
+					continue;
+				}
+				for (int i = 2; i < blockLines.length; ++i) {
+					long lineno = blockLines[i];
+					if (lineno == 0)
+						break;
+					Line line = lines.get((int) lineno);
+					line.addBlock(b);
+				}
+			}
+		}
     }