aboutsummaryrefslogtreecommitdiffstats
path: root/org.jacoco.core
diff options
context:
space:
mode:
Diffstat (limited to 'org.jacoco.core')
-rw-r--r--org.jacoco.core/pom.xml12
-rw-r--r--org.jacoco.core/src/org/jacoco/core/JaCoCo.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java26
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java34
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java6
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java6
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java20
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java26
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java35
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/ILine.java8
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java8
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java8
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java6
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java10
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/analysis/package-info.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/IncompatibleExecDataVersionException.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/SessionInfoStore.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/data/package-info.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java24
-rw-r--r--org.jacoco.core/src/org/jacoco/core/instr/package-info.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java9
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/InputStreams.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java91
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java8
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/CounterImpl.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/Instruction.java207
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/InstructionsBuilder.java186
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java290
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageCalculator.java178
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceNodeImpl.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/StringPool.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java66
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java79
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java64
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java61
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java9
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java38
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java6
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilter.java36
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java15
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java48
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java16
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java215
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java97
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java61
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java139
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java52
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java49
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java71
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java101
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java103
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java36
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java36
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java104
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java15
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java10
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java30
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java11
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java145
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java19
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataInput.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataOutput.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesVisitor.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/FrameSnapshot.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/IProbeIdGenerator.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java149
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java3
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/flow/MethodSanitizer.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/ClassFieldProbeArrayStrategy.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/CondyProbeArrayStrategy.java73
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/DuplicateFrameEliminator.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserter.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java87
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/InterfaceFieldProbeArrayStrategy.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/LocalProbeArrayStrategy.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/NoneProbeArrayStrategy.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java28
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeCounter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/SignatureRemover.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/package-info.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java28
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java6
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/IRemoteCommandVisitor.java5
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java6
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/InjectedClassRuntime.java141
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java6
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlReader.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlWriter.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/SystemPropertiesRuntime.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/URLStreamHandlerRuntime.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java11
-rw-r--r--org.jacoco.core/src/org/jacoco/core/runtime/package-info.java4
-rw-r--r--org.jacoco.core/src/org/jacoco/core/tools/ExecDumpClient.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/tools/ExecFileLoader.java2
-rw-r--r--org.jacoco.core/src/org/jacoco/core/tools/package-info.java4
126 files changed, 2744 insertions, 887 deletions
diff --git a/org.jacoco.core/pom.xml b/org.jacoco.core/pom.xml
index d147c113..0bb5b2b8 100644
--- a/org.jacoco.core/pom.xml
+++ b/org.jacoco.core/pom.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
@@ -15,7 +15,7 @@
<parent>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.build</artifactId>
- <version>0.8.0</version>
+ <version>0.8.4</version>
<relativePath>../org.jacoco.build</relativePath>
</parent>
@@ -37,14 +37,6 @@
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
</dependency>
- <dependency>
- <groupId>org.ow2.asm</groupId>
- <artifactId>asm-analysis</artifactId>
- </dependency>
- <dependency>
- <groupId>org.ow2.asm</groupId>
- <artifactId>asm-util</artifactId>
- </dependency>
</dependencies>
<build>
diff --git a/org.jacoco.core/src/org/jacoco/core/JaCoCo.java b/org.jacoco.core/src/org/jacoco/core/JaCoCo.java
index cb3fb4da..ce9ec053 100644
--- a/org.jacoco.core/src/org/jacoco/core/JaCoCo.java
+++ b/org.jacoco.core/src/org/jacoco/core/JaCoCo.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
index 53dbf0c0..76b7be3c 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/Analyzer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -30,8 +30,10 @@ import org.jacoco.core.internal.analysis.ClassCoverageImpl;
import org.jacoco.core.internal.analysis.StringPool;
import org.jacoco.core.internal.data.CRC64;
import org.jacoco.core.internal.flow.ClassProbesAdapter;
+import org.jacoco.core.internal.instr.InstrSupport;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
/**
* An {@link Analyzer} instance processes a set of Java class files and
@@ -99,15 +101,17 @@ public class Analyzer {
return new ClassProbesAdapter(analyzer, false);
}
- /**
- * Analyzes the class given as a ASM reader.
- *
- * @param reader
- * reader with class definitions
- */
- public void analyzeClass(final ClassReader reader) {
- final ClassVisitor visitor = createAnalyzingVisitor(
- CRC64.classId(reader.b), reader.getClassName());
+ private void analyzeClass(final byte[] source) {
+ final long classId = CRC64.classId(source);
+ final ClassReader reader = InstrSupport.classReaderFor(source);
+ if ((reader.getAccess() & Opcodes.ACC_MODULE) != 0) {
+ return;
+ }
+ if ((reader.getAccess() & Opcodes.ACC_SYNTHETIC) != 0) {
+ return;
+ }
+ final ClassVisitor visitor = createAnalyzingVisitor(classId,
+ reader.getClassName());
reader.accept(visitor, 0);
}
@@ -124,7 +128,7 @@ public class Analyzer {
public void analyzeClass(final byte[] buffer, final String location)
throws IOException {
try {
- analyzeClass(new ClassReader(buffer));
+ analyzeClass(buffer);
} catch (final RuntimeException cause) {
throw analyzerError(location, cause);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java b/org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java
index 1848c6fc..8a67b970 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/CounterComparator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java
index a44afb78..784fbd82 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageBuilder.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -95,26 +95,22 @@ public class CoverageBuilder implements ICoverageVisitor {
return result;
}
- // === IStructureVisitor ===
+ // === ICoverageVisitor ===
public void visitCoverage(final IClassCoverage coverage) {
- // Only consider classes that actually contain code:
- if (coverage.getInstructionCounter().getTotalCount() > 0) {
- final String name = coverage.getName();
- final IClassCoverage dup = classes.put(name, coverage);
- if (dup != null) {
- if (dup.getId() != coverage.getId()) {
- throw new IllegalStateException(
- "Can't add different class with same name: "
- + name);
- }
- } else {
- final String source = coverage.getSourceFileName();
- if (source != null) {
- final SourceFileCoverageImpl sourceFile = getSourceFile(
- source, coverage.getPackageName());
- sourceFile.increment(coverage);
- }
+ final String name = coverage.getName();
+ final IClassCoverage dup = classes.put(name, coverage);
+ if (dup != null) {
+ if (dup.getId() != coverage.getId()) {
+ throw new IllegalStateException(
+ "Can't add different class with same name: " + name);
+ }
+ } else {
+ final String source = coverage.getSourceFileName();
+ if (source != null) {
+ final SourceFileCoverageImpl sourceFile = getSourceFile(source,
+ coverage.getPackageName());
+ sourceFile.increment(coverage);
}
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java
index c1bcb26a..6be3bb6f 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/CoverageNodeImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -143,6 +143,10 @@ public class CoverageNodeImpl implements ICoverageNode {
throw new AssertionError(entity);
}
+ public boolean containsCode() {
+ return getInstructionCounter().getTotalCount() != 0;
+ }
+
public ICoverageNode getPlainCopy() {
final CoverageNodeImpl copy = new CoverageNodeImpl(elementType, name);
copy.instructionCounter = CounterImpl.getInstance(instructionCounter);
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java
index afcdc1aa..d488f475 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/IBundleCoverage.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -25,6 +25,6 @@ public interface IBundleCoverage extends ICoverageNode {
*
* @return all packages
*/
- public Collection<IPackageCoverage> getPackages();
+ Collection<IPackageCoverage> getPackages();
-} \ No newline at end of file
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java
index f72b7a85..81cc6fe7 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/IClassCoverage.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -27,7 +27,7 @@ public interface IClassCoverage extends ISourceNode {
*
* @return class identifier
*/
- public long getId();
+ long getId();
/**
* Returns if the the analyzed class does match the execution data provided.
@@ -37,14 +37,14 @@ public interface IClassCoverage extends ISourceNode {
* @return <code>true</code> if this class does not match to the provided
* execution data.
*/
- public boolean isNoMatch();
+ boolean isNoMatch();
/**
* Returns the VM signature of the class.
*
* @return VM signature of the class (may be <code>null</code>)
*/
- public String getSignature();
+ String getSignature();
/**
* Returns the VM name of the superclass.
@@ -52,34 +52,34 @@ public interface IClassCoverage extends ISourceNode {
* @return VM name of the super class (may be <code>null</code>, i.e.
* <code>java/lang/Object</code>)
*/
- public String getSuperName();
+ String getSuperName();
/**
* Returns the VM names of implemented/extended interfaces.
*
* @return VM names of implemented/extended interfaces
*/
- public String[] getInterfaceNames();
+ String[] getInterfaceNames();
/**
* Returns the VM name of the package this class belongs to.
*
* @return VM name of the package
*/
- public String getPackageName();
+ String getPackageName();
/**
* Returns the optional name of the corresponding source file.
*
* @return name of the corresponding source file
*/
- public String getSourceFileName();
+ String getSourceFileName();
/**
* Returns the methods included in this class.
*
* @return methods of this class
*/
- public Collection<IMethodCoverage> getMethods();
+ Collection<IMethodCoverage> getMethods();
-} \ No newline at end of file
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java
index 5f30e02b..60c8dcc5 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICounter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -20,7 +20,7 @@ public interface ICounter {
/**
* Different values provided by a counter.
*/
- public enum CounterValue {
+ enum CounterValue {
/** Total number of items */
TOTALCOUNT,
@@ -41,22 +41,22 @@ public interface ICounter {
/**
* Status flag for no items (value is 0x00).
*/
- public static final int EMPTY = 0x00;
+ int EMPTY = 0x00;
/**
* Status flag when all items are not covered (value is 0x01).
*/
- public static final int NOT_COVERED = 0x01;
+ int NOT_COVERED = 0x01;
/**
* Status flag when all items are covered (value is 0x02).
*/
- public static final int FULLY_COVERED = 0x02;
+ int FULLY_COVERED = 0x02;
/**
* Status flag when items are partly covered (value is 0x03).
*/
- public static final int PARTLY_COVERED = NOT_COVERED | FULLY_COVERED;
+ int PARTLY_COVERED = NOT_COVERED | FULLY_COVERED;
/**
* Returns the counter value of the given type.
@@ -65,28 +65,28 @@ public interface ICounter {
* value type to return
* @return counter value
*/
- public double getValue(CounterValue value);
+ double getValue(CounterValue value);
/**
* Returns the total count of items.
*
* @return total count of items
*/
- public int getTotalCount();
+ int getTotalCount();
/**
* Returns the count of covered items.
*
* @return count of covered items
*/
- public int getCoveredCount();
+ int getCoveredCount();
/**
* Returns the count of missed items.
*
* @return count of missed items
*/
- public int getMissedCount();
+ int getMissedCount();
/**
* Calculates the ratio of covered to total count items. If total count
@@ -94,7 +94,7 @@ public interface ICounter {
*
* @return ratio of covered to total count items
*/
- public double getCoveredRatio();
+ double getCoveredRatio();
/**
* Calculates the ratio of missed to total count items. If total count items
@@ -102,7 +102,7 @@ public interface ICounter {
*
* @return ratio of missed to total count items
*/
- public double getMissedRatio();
+ double getMissedRatio();
/**
* Returns the coverage status of this counter.
@@ -114,6 +114,6 @@ public interface ICounter {
*
* @return status of this line
*/
- public int getStatus();
+ int getStatus();
}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java
index 0756f410..20b107d4 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageNode.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -20,7 +20,7 @@ public interface ICoverageNode {
/**
* Type of a Java element represented by a {@link ICoverageNode} instance.
*/
- public enum ElementType {
+ enum ElementType {
/** Method */
METHOD,
@@ -45,7 +45,7 @@ public interface ICoverageNode {
/**
* Different counter types supported by JaCoCo.
*/
- public enum CounterEntity {
+ enum CounterEntity {
/** Counter for instructions */
INSTRUCTION,
@@ -71,56 +71,56 @@ public interface ICoverageNode {
*
* @return type of this node
*/
- public abstract ElementType getElementType();
+ ElementType getElementType();
/**
* Returns the name of this node.
*
* @return name of this node
*/
- public String getName();
+ String getName();
/**
* Returns the counter for byte code instructions.
*
* @return counter for instructions
*/
- public abstract ICounter getInstructionCounter();
+ ICounter getInstructionCounter();
/**
* Returns the counter for branches.
*
* @return counter for branches
*/
- public ICounter getBranchCounter();
+ ICounter getBranchCounter();
/**
* Returns the counter for lines.
*
* @return counter for lines
*/
- public ICounter getLineCounter();
+ ICounter getLineCounter();
/**
* Returns the counter for cyclomatic complexity.
*
* @return counter for complexity
*/
- public ICounter getComplexityCounter();
+ ICounter getComplexityCounter();
/**
* Returns the counter for methods.
*
* @return counter for methods
*/
- public ICounter getMethodCounter();
+ ICounter getMethodCounter();
/**
* Returns the counter for classes.
*
* @return counter for classes
*/
- public ICounter getClassCounter();
+ ICounter getClassCounter();
/**
* Generic access to the the counters.
@@ -129,7 +129,14 @@ public interface ICoverageNode {
* entity we're we want to have the counter for
* @return counter for the given entity
*/
- public ICounter getCounter(CounterEntity entity);
+ ICounter getCounter(CounterEntity entity);
+
+ /**
+ * Checks whether this node contains code relevant for code coverage.
+ *
+ * @return <code>true</code> if this node contains code relevant for code coverage
+ */
+ boolean containsCode();
/**
* Creates a plain copy of this node. While {@link ICoverageNode}
@@ -139,6 +146,6 @@ public interface ICoverageNode {
*
* @return copy with counters only
*/
- public ICoverageNode getPlainCopy();
+ ICoverageNode getPlainCopy();
-} \ No newline at end of file
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java
index 5a71859f..3f702906 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/ICoverageVisitor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -23,6 +23,6 @@ public interface ICoverageVisitor {
* @param coverage
* coverage data for a class
*/
- public void visitCoverage(IClassCoverage coverage);
+ void visitCoverage(IClassCoverage coverage);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java b/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java
index cdd91eba..ef65dc0d 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/ILine.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -22,14 +22,14 @@ public interface ILine {
*
* @return instruction counter
*/
- public ICounter getInstructionCounter();
+ ICounter getInstructionCounter();
/**
* Returns the branches counter for this line.
*
* @return branches counter
*/
- public ICounter getBranchCounter();
+ ICounter getBranchCounter();
/**
* Returns the coverage status of this line, calculated from the
@@ -42,6 +42,6 @@ public interface ILine {
*
* @return status of this line
*/
- public int getStatus();
+ int getStatus();
}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java
index 3bd75169..b6755170 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/IMethodCoverage.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -22,13 +22,13 @@ public interface IMethodCoverage extends ISourceNode {
*
* @return descriptor
*/
- public String getDesc();
+ String getDesc();
/**
* Returns the generic signature of the method if defined.
*
* @return generic signature or <code>null</code>
*/
- public String getSignature();
+ String getSignature();
-} \ No newline at end of file
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java
index 8ff1a184..32121620 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/IPackageCoverage.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -28,13 +28,13 @@ public interface IPackageCoverage extends ICoverageNode {
*
* @return all classes
*/
- public Collection<IClassCoverage> getClasses();
+ Collection<IClassCoverage> getClasses();
/**
* Returns all source files in this package.
*
* @return all source files
*/
- public Collection<ISourceFileCoverage> getSourceFiles();
+ Collection<ISourceFileCoverage> getSourceFiles();
-} \ No newline at end of file
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java
index 6a49490b..5f01160a 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceFileCoverage.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -22,6 +22,6 @@ public interface ISourceFileCoverage extends ISourceNode {
*
* @return package name
*/
- public String getPackageName();
+ String getPackageName();
-} \ No newline at end of file
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java
index d6c90e5a..d64b2cc1 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/ISourceNode.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -18,7 +18,7 @@ package org.jacoco.core.analysis;
public interface ISourceNode extends ICoverageNode {
/** Place holder for unknown lines (no debug information) */
- public static int UNKNOWN_LINE = -1;
+ int UNKNOWN_LINE = -1;
/**
* The number of the first line coverage information is available for. If no
@@ -26,7 +26,7 @@ public interface ISourceNode extends ICoverageNode {
*
* @return number of the first line or {@link #UNKNOWN_LINE}
*/
- public int getFirstLine();
+ int getFirstLine();
/**
* The number of the last line coverage information is available for. If no
@@ -34,7 +34,7 @@ public interface ISourceNode extends ICoverageNode {
*
* @return number of the last line or {@link #UNKNOWN_LINE}
*/
- public int getLastLine();
+ int getLastLine();
/**
* Returns the line information for given line.
@@ -43,6 +43,6 @@ public interface ISourceNode extends ICoverageNode {
* line number of interest
* @return line information
*/
- public ILine getLine(int nr);
+ ILine getLine(int nr);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java b/org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java
index da94e07c..3fea25fb 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/NodeComparator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/analysis/package-info.java b/org.jacoco.core/src/org/jacoco/core/analysis/package-info.java
index afee23c2..d1a5e73b 100644
--- a/org.jacoco.core/src/org/jacoco/core/analysis/package-info.java
+++ b/org.jacoco.core/src/org/jacoco/core/analysis/package-info.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -34,4 +34,4 @@
* +-- {@linkplain org.jacoco.core.analysis.ICoverageNode.ElementType#METHOD Method}
* </pre>
*/
-package org.jacoco.core.analysis; \ No newline at end of file
+package org.jacoco.core.analysis;
diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java
index 6c4b2e00..d98775eb 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionData.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java
index bdb98600..dd8519b5 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataReader.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java
index 89d9dc66..3e567a3b 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataStore.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java
index 259f1c1d..e697dda3 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/ExecutionDataWriter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java
index b2bccd6c..6cea7c57 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/IExecutionDataVisitor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -24,6 +24,6 @@ public interface IExecutionDataVisitor {
* @param data
* execution data for a class
*/
- public void visitClassExecution(ExecutionData data);
+ void visitClassExecution(ExecutionData data);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java b/org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java
index 23e7711d..b80797a9 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/ISessionInfoVisitor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -25,6 +25,6 @@ public interface ISessionInfoVisitor {
* @param info
* session information
*/
- public void visitSessionInfo(final SessionInfo info);
+ void visitSessionInfo(SessionInfo info);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/data/IncompatibleExecDataVersionException.java b/org.jacoco.core/src/org/jacoco/core/data/IncompatibleExecDataVersionException.java
index b51b821d..cc508e73 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/IncompatibleExecDataVersionException.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/IncompatibleExecDataVersionException.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -55,4 +55,4 @@ public class IncompatibleExecDataVersionException extends IOException {
return actualVersion;
}
-} \ No newline at end of file
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java b/org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java
index 42a0d890..31f7b5e3 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/SessionInfo.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/data/SessionInfoStore.java b/org.jacoco.core/src/org/jacoco/core/data/SessionInfoStore.java
index 0e8d667a..568dcc96 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/SessionInfoStore.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/SessionInfoStore.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/data/package-info.java b/org.jacoco.core/src/org/jacoco/core/data/package-info.java
index 4fb179c4..6e2f37bf 100644
--- a/org.jacoco.core/src/org/jacoco/core/data/package-info.java
+++ b/org.jacoco.core/src/org/jacoco/core/data/package-info.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,4 +13,4 @@
/**
* Representation and persistence of execution data and session information.
*/
-package org.jacoco.core.data; \ No newline at end of file
+package org.jacoco.core.data;
diff --git a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
index c8249784..561b09cb 100644
--- a/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/instr/Instrumenter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -24,9 +24,11 @@ import java.util.zip.ZipOutputStream;
import org.jacoco.core.internal.ContentTypeDetector;
import org.jacoco.core.internal.InputStreams;
import org.jacoco.core.internal.Pack200Streams;
+import org.jacoco.core.internal.data.CRC64;
import org.jacoco.core.internal.flow.ClassProbesAdapter;
import org.jacoco.core.internal.instr.ClassInstrumenter;
import org.jacoco.core.internal.instr.IProbeArrayStrategy;
+import org.jacoco.core.internal.instr.InstrSupport;
import org.jacoco.core.internal.instr.ProbeArrayStrategyFactory;
import org.jacoco.core.internal.instr.SignatureRemover;
import org.jacoco.core.runtime.IExecutionDataAccessorGenerator;
@@ -67,15 +69,9 @@ public class Instrumenter {
signatureRemover.setActive(flag);
}
- /**
- * Creates a instrumented version of the given class if possible.
- *
- * @param reader
- * definition of the class as ASM reader
- * @return instrumented definition
- *
- */
- public byte[] instrument(final ClassReader reader) {
+ private byte[] instrument(final byte[] source) {
+ final long classId = CRC64.classId(source);
+ final ClassReader reader = InstrSupport.classReaderFor(source);
final ClassWriter writer = new ClassWriter(reader, 0) {
@Override
protected String getCommonSuperClass(final String type1,
@@ -84,9 +80,11 @@ public class Instrumenter {
}
};
final IProbeArrayStrategy strategy = ProbeArrayStrategyFactory
- .createFor(reader, accessorGenerator);
+ .createFor(classId, reader, accessorGenerator);
+ final int version = InstrSupport.getMajorVersion(reader);
final ClassVisitor visitor = new ClassProbesAdapter(
- new ClassInstrumenter(strategy, writer), true);
+ new ClassInstrumenter(strategy, writer),
+ InstrSupport.needsFrames(version));
reader.accept(visitor, ClassReader.EXPAND_FRAMES);
return writer.toByteArray();
}
@@ -105,7 +103,7 @@ public class Instrumenter {
public byte[] instrument(final byte[] buffer, final String name)
throws IOException {
try {
- return instrument(new ClassReader(buffer));
+ return instrument(buffer);
} catch (final RuntimeException e) {
throw instrumentError(name, e);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/instr/package-info.java b/org.jacoco.core/src/org/jacoco/core/instr/package-info.java
index 2f474032..1da3ef19 100644
--- a/org.jacoco.core/src/org/jacoco/core/instr/package-info.java
+++ b/org.jacoco.core/src/org/jacoco/core/instr/package-info.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -16,4 +16,4 @@
* is the class {@link org.jacoco.core.instr.Instrumenter}.
* </p>
*/
-package org.jacoco.core.instr; \ No newline at end of file
+package org.jacoco.core.instr;
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java
index ae665624..74574ecc 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/ContentTypeDetector.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -83,6 +83,13 @@ public class ContentTypeDetector {
case Opcodes.V1_7:
case Opcodes.V1_8:
case Opcodes.V9:
+ case Opcodes.V10:
+ case Opcodes.V11:
+ case Opcodes.V11 | Opcodes.V_PREVIEW:
+ case Opcodes.V12:
+ case Opcodes.V12 | Opcodes.V_PREVIEW:
+ case (Opcodes.V12 + 1):
+ case (Opcodes.V12 + 1) | Opcodes.V_PREVIEW:
return CLASSFILE;
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/InputStreams.java b/org.jacoco.core/src/org/jacoco/core/internal/InputStreams.java
index 7a77dd72..93f86f67 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/InputStreams.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/InputStreams.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java b/org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java
index abcbe989..eae4fdfa 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/Pack200Streams.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java
index 5c1e39fd..9c6fcefc 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/BundleCoverageImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java
index afcf387e..a18ee7ed 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassAnalyzer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,22 +11,36 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis;
-import org.jacoco.core.analysis.IMethodCoverage;
+import java.util.HashSet;
+import java.util.Set;
+
import org.jacoco.core.internal.analysis.filter.Filters;
+import org.jacoco.core.internal.analysis.filter.IFilter;
+import org.jacoco.core.internal.analysis.filter.IFilterContext;
import org.jacoco.core.internal.flow.ClassProbesVisitor;
import org.jacoco.core.internal.flow.MethodProbesVisitor;
import org.jacoco.core.internal.instr.InstrSupport;
+import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.tree.MethodNode;
/**
* Analyzes the structure of a class.
*/
-public class ClassAnalyzer extends ClassProbesVisitor {
+public class ClassAnalyzer extends ClassProbesVisitor
+ implements IFilterContext {
private final ClassCoverageImpl coverage;
private final boolean[] probes;
private final StringPool stringPool;
+ private final Set<String> classAnnotations = new HashSet<String>();
+
+ private String sourceDebugExtension;
+
+ private final IFilter filter;
+
/**
* Creates a new analyzer that builds coverage data for a class.
*
@@ -42,6 +56,7 @@ public class ClassAnalyzer extends ClassProbesVisitor {
this.coverage = coverage;
this.probes = probes;
this.stringPool = stringPool;
+ this.filter = Filters.all();
}
@Override
@@ -54,31 +69,57 @@ public class ClassAnalyzer extends ClassProbesVisitor {
}
@Override
+ public AnnotationVisitor visitAnnotation(final String desc,
+ final boolean visible) {
+ classAnnotations.add(desc);
+ return super.visitAnnotation(desc, visible);
+ }
+
+ @Override
public void visitSource(final String source, final String debug) {
coverage.setSourceFileName(stringPool.get(source));
+ sourceDebugExtension = debug;
}
@Override
public MethodProbesVisitor visitMethod(final int access, final String name,
- final String desc, final String signature, final String[] exceptions) {
+ final String desc, final String signature,
+ final String[] exceptions) {
InstrSupport.assertNotInstrumented(name, coverage.getName());
- return new MethodAnalyzer(coverage.getName(), coverage.getSuperName(),
- stringPool.get(name), stringPool.get(desc),
- stringPool.get(signature), probes, Filters.ALL) {
+ final InstructionsBuilder builder = new InstructionsBuilder(probes);
+
+ return new MethodAnalyzer(builder) {
+
@Override
- public void visitEnd() {
- super.visitEnd();
- final IMethodCoverage methodCoverage = getCoverage();
- if (methodCoverage.getInstructionCounter().getTotalCount() > 0) {
- // Only consider methods that actually contain code
- coverage.addMethod(methodCoverage);
- }
+ public void accept(final MethodNode methodNode,
+ final MethodVisitor methodVisitor) {
+ super.accept(methodNode, methodVisitor);
+ addMethodCoverage(stringPool.get(name), stringPool.get(desc),
+ stringPool.get(signature), builder, methodNode);
}
};
}
+ private void addMethodCoverage(final String name, final String desc,
+ final String signature, final InstructionsBuilder icc,
+ final MethodNode methodNode) {
+ final MethodCoverageCalculator mcc = new MethodCoverageCalculator(
+ icc.getInstructions());
+ filter.filter(methodNode, this, mcc);
+
+ final MethodCoverageImpl mc = new MethodCoverageImpl(name, desc,
+ signature);
+ mcc.calculate(mc);
+
+ if (mc.containsCode()) {
+ // Only consider methods that actually contain code
+ coverage.addMethod(mc);
+ }
+
+ }
+
@Override
public FieldVisitor visitField(final int access, final String name,
final String desc, final String signature, final Object value) {
@@ -91,4 +132,26 @@ public class ClassAnalyzer extends ClassProbesVisitor {
// nothing to do
}
+ // IFilterContext implementation
+
+ public String getClassName() {
+ return coverage.getName();
+ }
+
+ public String getSuperClassName() {
+ return coverage.getSuperName();
+ }
+
+ public Set<String> getClassAnnotations() {
+ return classAnnotations;
+ }
+
+ public String getSourceFileName() {
+ return coverage.getSourceFileName();
+ }
+
+ public String getSourceDebugExtension() {
+ return sourceDebugExtension;
+ }
+
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java
index cb45604c..444a81ed 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/ClassCoverageImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -47,7 +47,6 @@ public class ClassCoverageImpl extends SourceNodeImpl implements IClassCoverage
this.id = id;
this.noMatch = noMatch;
this.methods = new ArrayList<IMethodCoverage>();
- this.classCounter = CounterImpl.COUNTER_1_0;
}
/**
@@ -59,10 +58,11 @@ public class ClassCoverageImpl extends SourceNodeImpl implements IClassCoverage
public void addMethod(final IMethodCoverage method) {
this.methods.add(method);
increment(method);
- // As class is considered as covered when at least one method is
- // covered:
+ // Class is considered as covered when at least one method is covered:
if (methodCounter.getCoveredCount() > 0) {
this.classCounter = CounterImpl.COUNTER_0_1;
+ } else {
+ this.classCounter = CounterImpl.COUNTER_1_0;
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/CounterImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/CounterImpl.java
index 5d0317c1..e166c626 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/CounterImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/CounterImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/Instruction.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/Instruction.java
new file mode 100644
index 00000000..c5a1aaae
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/Instruction.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc R. Hoffmann - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis;
+
+import java.util.BitSet;
+import java.util.Collection;
+
+import org.jacoco.core.analysis.ICounter;
+
+/**
+ * Execution status of a single bytecode instruction internally used for
+ * coverage analysis. The execution status is recorded separately for each
+ * outgoing branch. Each instruction has at least one branch, for example in
+ * case of a simple sequence of instructions (by convention branch 0). Instances
+ * of this class are used in two steps:
+ *
+ * <h3>Step 1: Building the CFG</h3>
+ *
+ * For each bytecode instruction of a method a {@link Instruction} instance is
+ * created. In correspondence with the CFG these instances are linked with each
+ * other with the <code>addBranch()</code> methods. The executions status is
+ * either directly derived from a probe which has been inserted in the execution
+ * flow ({@link #addBranch(boolean, int)}) or indirectly propagated along the
+ * CFG edges ({@link #addBranch(Instruction, int)}).
+ *
+ * <h3>Step 2: Querying the Coverage Status</h3>
+ *
+ * After all instructions have been created and linked each instruction knows
+ * its execution status and can be queried with:
+ *
+ * <ul>
+ * <li>{@link #getLine()}</li>
+ * <li>{@link #getInstructionCounter()}</li>
+ * <li>{@link #getBranchCounter()}</li>
+ * </ul>
+ *
+ * For the purpose of filtering instructions can be combined to new
+ * instructions. Note that these methods create new {@link Instruction}
+ * instances and do not modify the existing ones.
+ *
+ * <ul>
+ * <li>{@link #merge(Instruction)}</li>
+ * <li>{@link #replaceBranches(Collection)}</li>
+ * </ul>
+ */
+public class Instruction {
+
+ private final int line;
+
+ private int branches;
+
+ private final BitSet coveredBranches;
+
+ private Instruction predecessor;
+
+ private int predecessorBranch;
+
+ /**
+ * New instruction at the given line.
+ *
+ * @param line
+ * source line this instruction belongs to
+ */
+ public Instruction(final int line) {
+ this.line = line;
+ this.branches = 0;
+ this.coveredBranches = new BitSet();
+ }
+
+ /**
+ * Adds a branch to this instruction which execution status is indirectly
+ * derived from the execution status of the target instruction. In case the
+ * branch is covered the status is propagated also to the predecessors of
+ * this instruction.
+ *
+ * Note: This method is not idempotent and must be called exactly once for
+ * every branch.
+ *
+ * @param target
+ * target instruction of this branch
+ * @param branch
+ * branch identifier unique for this instruction
+ */
+ public void addBranch(final Instruction target, final int branch) {
+ branches++;
+ target.predecessor = this;
+ target.predecessorBranch = branch;
+ if (!target.coveredBranches.isEmpty()) {
+ propagateExecutedBranch(this, branch);
+ }
+ }
+
+ /**
+ * Adds a branch to this instruction which execution status is directly
+ * derived from a probe. In case the branch is covered the status is
+ * propagated also to the predecessors of this instruction.
+ *
+ * Note: This method is not idempotent and must be called exactly once for
+ * every branch.
+ *
+ * @param executed
+ * whether the corresponding probe has been executed
+ * @param branch
+ * branch identifier unique for this instruction
+ */
+ public void addBranch(final boolean executed, final int branch) {
+ branches++;
+ if (executed) {
+ propagateExecutedBranch(this, branch);
+ }
+ }
+
+ private static void propagateExecutedBranch(Instruction insn, int branch) {
+ // No recursion here, as there can be very long chains of instructions
+ while (insn != null) {
+ if (!insn.coveredBranches.isEmpty()) {
+ insn.coveredBranches.set(branch);
+ break;
+ }
+ insn.coveredBranches.set(branch);
+ branch = insn.predecessorBranch;
+ insn = insn.predecessor;
+ }
+ }
+
+ /**
+ * Returns the source line this instruction belongs to.
+ *
+ * @return corresponding source line
+ */
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * Merges information about covered branches of this instruction with
+ * another instruction.
+ *
+ * @param other
+ * instruction to merge with
+ * @return new instance with merged branches
+ */
+ public Instruction merge(final Instruction other) {
+ final Instruction result = new Instruction(this.line);
+ result.branches = this.branches;
+ result.coveredBranches.or(this.coveredBranches);
+ result.coveredBranches.or(other.coveredBranches);
+ return result;
+ }
+
+ /**
+ * Creates a copy of this instruction where all outgoing branches are
+ * replaced with the given instructions. The coverage status of the new
+ * instruction is derived from the status of the given instructions.
+ *
+ * @param newBranches
+ * new branches to consider
+ * @return new instance with replaced branches
+ */
+ public Instruction replaceBranches(
+ final Collection<Instruction> newBranches) {
+ final Instruction result = new Instruction(this.line);
+ result.branches = newBranches.size();
+ int idx = 0;
+ for (final Instruction b : newBranches) {
+ if (!b.coveredBranches.isEmpty()) {
+ result.coveredBranches.set(idx++);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the instruction coverage counter of this instruction. It is
+ * always 1 instruction which is covered or not.
+ *
+ * @return the instruction coverage counter
+ */
+ public ICounter getInstructionCounter() {
+ return coveredBranches.isEmpty() ? CounterImpl.COUNTER_1_0
+ : CounterImpl.COUNTER_0_1;
+ }
+
+ /**
+ * Returns the branch coverage counter of this instruction. Only
+ * instructions with at least 2 outgoing edges report branches.
+ *
+ * @return the branch coverage counter
+ */
+ public ICounter getBranchCounter() {
+ if (branches < 2) {
+ return CounterImpl.COUNTER_0_0;
+ }
+ final int covered = coveredBranches.cardinality();
+ return CounterImpl.getInstance(branches - covered, covered);
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/InstructionsBuilder.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/InstructionsBuilder.java
new file mode 100644
index 00000000..b22d872a
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/InstructionsBuilder.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc R. Hoffmann - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jacoco.core.analysis.ISourceNode;
+import org.jacoco.core.internal.flow.LabelInfo;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.tree.AbstractInsnNode;
+
+/**
+ * Stateful builder for the {@link Instruction}s of a method. All instructions
+ * of a method must be added in their original sequence along with additional
+ * information like line numbers. Afterwards the instructions can be obtained
+ * with the <code>getInstructions()</code> method.
+ */
+class InstructionsBuilder {
+
+ /** Probe array of the class the analyzed method belongs to. */
+ private final boolean[] probes;
+
+ /** The line which belong to subsequently added instructions. */
+ private int currentLine;
+
+ /** The last instruction which has been added. */
+ private Instruction currentInsn;
+
+ /**
+ * All instructions of a method mapped from the ASM node to the
+ * corresponding {@link Instruction} instance.
+ */
+ private final Map<AbstractInsnNode, Instruction> instructions;
+
+ /**
+ * The labels which mark the subsequent instructions.
+ *
+ * Due to ASM issue #315745 there can be more than one label per instruction
+ */
+ private final List<Label> currentLabel;
+
+ /**
+ * List of all jumps within the control flow. We need to store jumps
+ * temporarily as the target {@link Instruction} may not been known yet.
+ */
+ private final List<Jump> jumps;
+
+ /**
+ * Creates a new builder instance which can be used to analyze a single
+ * method.
+ *
+ * @param probes
+ * probe array of the corresponding class used to determine the
+ * coverage status of every instruction.
+ */
+ InstructionsBuilder(final boolean[] probes) {
+ this.probes = probes;
+ this.currentLine = ISourceNode.UNKNOWN_LINE;
+ this.currentInsn = null;
+ this.instructions = new HashMap<AbstractInsnNode, Instruction>();
+ this.currentLabel = new ArrayList<Label>(2);
+ this.jumps = new ArrayList<Jump>();
+ }
+
+ /**
+ * Sets the current source line. All subsequently added instructions will be
+ * assigned to this line. If no line is set (e.g. for classes compiled
+ * without debug information) {@link ISourceNode#UNKNOWN_LINE} is assigned
+ * to the instructions.
+ */
+ void setCurrentLine(final int line) {
+ currentLine = line;
+ }
+
+ /**
+ * Adds a label which applies to the subsequently added instruction. Due to
+ * ASM internals multiple {@link Label}s can be added to an instruction.
+ */
+ void addLabel(final Label label) {
+ currentLabel.add(label);
+ if (!LabelInfo.isSuccessor(label)) {
+ noSuccessor();
+ }
+ }
+
+ /**
+ * Adds a new instruction. Instructions are by default linked with the
+ * previous instruction unless specified otherwise.
+ */
+ void addInstruction(final AbstractInsnNode node) {
+ final Instruction insn = new Instruction(currentLine);
+ final int labelCount = currentLabel.size();
+ if (labelCount > 0) {
+ for (int i = labelCount; --i >= 0;) {
+ LabelInfo.setInstruction(currentLabel.get(i), insn);
+ }
+ currentLabel.clear();
+ }
+ if (currentInsn != null) {
+ currentInsn.addBranch(insn, 0);
+ }
+ currentInsn = insn;
+ instructions.put(node, insn);
+ }
+
+ /**
+ * Declares that the next instruction will not be a successor of the current
+ * instruction. This is the case with an unconditional jump or technically
+ * when a probe was inserted before.
+ */
+ void noSuccessor() {
+ currentInsn = null;
+ }
+
+ /**
+ * Adds a jump from the last added instruction.
+ *
+ * @param target
+ * jump target
+ * @param branch
+ * unique branch number
+ */
+ void addJump(final Label target, final int branch) {
+ jumps.add(new Jump(currentInsn, target, branch));
+ }
+
+ /**
+ * Adds a new probe for the last instruction.
+ *
+ * @param probeId
+ * index in the probe array
+ * @param branch
+ * unique branch number for the last instruction
+ */
+ void addProbe(final int probeId, final int branch) {
+ final boolean executed = probes != null && probes[probeId];
+ currentInsn.addBranch(executed, branch);
+ }
+
+ /**
+ * Returns the status for all instructions of this method. This method must
+ * be called exactly once after the instructions have been added.
+ *
+ * @return map of ASM instruction nodes to corresponding {@link Instruction}
+ * instances
+ */
+ Map<AbstractInsnNode, Instruction> getInstructions() {
+ // Wire jumps:
+ for (final Jump j : jumps) {
+ j.wire();
+ }
+
+ return instructions;
+ }
+
+ private static class Jump {
+
+ private final Instruction source;
+ private final Label target;
+ private final int branch;
+
+ Jump(final Instruction source, final Label target, final int branch) {
+ this.source = source;
+ this.target = target;
+ this.branch = branch;
+ }
+
+ void wire() {
+ source.addBranch(LabelInfo.getInstruction(target), branch);
+ }
+
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java
index 9c03ea76..908bcb60 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/LineImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java
index e10e5d9f..1aaadf2e 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodAnalyzer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,20 +11,7 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.jacoco.core.analysis.ICounter;
-import org.jacoco.core.analysis.IMethodCoverage;
-import org.jacoco.core.analysis.ISourceNode;
-import org.jacoco.core.internal.analysis.filter.IFilter;
-import org.jacoco.core.internal.analysis.filter.IFilterOutput;
import org.jacoco.core.internal.flow.IFrame;
-import org.jacoco.core.internal.flow.Instruction;
import org.jacoco.core.internal.flow.LabelInfo;
import org.jacoco.core.internal.flow.MethodProbesVisitor;
import org.objectweb.asm.Handle;
@@ -35,91 +22,26 @@ import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
/**
- * A {@link MethodProbesVisitor} that analyzes which statements and branches of
- * a method have been executed based on given probe data.
+ * A {@link MethodProbesVisitor} that builds the {@link Instruction}s of a
+ * method to calculate the detailed execution status.
*/
-public class MethodAnalyzer extends MethodProbesVisitor
- implements IFilterOutput {
-
- private final String className;
-
- private final String superClassName;
-
- private final boolean[] probes;
-
- private final IFilter filter;
-
- private final MethodCoverageImpl coverage;
-
- private int currentLine = ISourceNode.UNKNOWN_LINE;
-
- private int firstLine = ISourceNode.UNKNOWN_LINE;
-
- private int lastLine = ISourceNode.UNKNOWN_LINE;
+public class MethodAnalyzer extends MethodProbesVisitor {
- // Due to ASM issue #315745 there can be more than one label per instruction
- private final List<Label> currentLabel = new ArrayList<Label>(2);
+ private final InstructionsBuilder builder;
- /** List of all analyzed instructions */
- private final List<Instruction> instructions = new ArrayList<Instruction>();
-
- /** List of all predecessors of covered probes */
- private final List<CoveredProbe> coveredProbes = new ArrayList<CoveredProbe>();
-
- /** List of all jumps encountered */
- private final List<Jump> jumps = new ArrayList<Jump>();
-
- /** Last instruction in byte code sequence */
- private Instruction lastInsn;
-
- /**
- * New Method analyzer for the given probe data.
- *
- * @param className
- * class name
- * @param superClassName
- * superclass name
- * @param name
- * method name
- * @param desc
- * method descriptor
- * @param signature
- * optional parameterized signature
- * @param probes
- * recorded probe date of the containing class or
- * <code>null</code> if the class is not executed at all
- * @param filter
- * filter
- */
- MethodAnalyzer(final String className, final String superClassName,
- final String name, final String desc, final String signature,
- final boolean[] probes, final IFilter filter) {
- super();
- this.className = className;
- this.superClassName = superClassName;
- this.probes = probes;
- this.filter = filter;
- this.coverage = new MethodCoverageImpl(name, desc, signature);
- }
+ /** Current node of the ASM tree API */
+ private AbstractInsnNode currentNode;
/**
- * Returns the coverage data for this method after this visitor has been
- * processed.
- *
- * @return coverage data for this method
+ * New instance that uses the given builder.
*/
- public IMethodCoverage getCoverage() {
- return coverage;
+ MethodAnalyzer(final InstructionsBuilder builder) {
+ this.builder = builder;
}
- /**
- * {@link MethodNode#accept(MethodVisitor)}
- */
@Override
public void accept(final MethodNode methodNode,
final MethodVisitor methodVisitor) {
- filter.filter(className, superClassName, methodNode, this);
-
methodVisitor.visitCode();
for (final TryCatchBlockNode n : methodNode.tryCatchBlocks) {
n.accept(methodVisitor);
@@ -132,139 +54,68 @@ public class MethodAnalyzer extends MethodProbesVisitor
methodVisitor.visitEnd();
}
- private final Set<AbstractInsnNode> ignored = new HashSet<AbstractInsnNode>();
-
- /**
- * Instructions that should be merged form disjoint sets. Coverage
- * information from instructions of one set will be merged into
- * representative instruction of set.
- *
- * Each such set is represented as a singly linked list: each element except
- * one references another element from the same set, element without
- * reference - is a representative of this set.
- *
- * This map stores reference (value) for elements of sets (key).
- */
- private final Map<AbstractInsnNode, AbstractInsnNode> merged = new HashMap<AbstractInsnNode, AbstractInsnNode>();
-
- private final Map<AbstractInsnNode, Instruction> nodeToInstruction = new HashMap<AbstractInsnNode, Instruction>();
-
- private AbstractInsnNode currentNode;
-
- public void ignore(final AbstractInsnNode fromInclusive,
- final AbstractInsnNode toInclusive) {
- for (AbstractInsnNode i = fromInclusive; i != toInclusive; i = i
- .getNext()) {
- ignored.add(i);
- }
- ignored.add(toInclusive);
- }
-
- private AbstractInsnNode findRepresentative(AbstractInsnNode i) {
- AbstractInsnNode r = merged.get(i);
- while (r != null) {
- i = r;
- r = merged.get(i);
- }
- return i;
- }
-
- public void merge(AbstractInsnNode i1, AbstractInsnNode i2) {
- i1 = findRepresentative(i1);
- i2 = findRepresentative(i2);
- if (i1 != i2) {
- merged.put(i2, i1);
- }
- }
-
@Override
public void visitLabel(final Label label) {
- currentLabel.add(label);
- if (!LabelInfo.isSuccessor(label)) {
- lastInsn = null;
- }
+ builder.addLabel(label);
}
@Override
public void visitLineNumber(final int line, final Label start) {
- currentLine = line;
- if (firstLine > line || lastLine == ISourceNode.UNKNOWN_LINE) {
- firstLine = line;
- }
- if (lastLine < line) {
- lastLine = line;
- }
- }
-
- private void visitInsn() {
- final Instruction insn = new Instruction(currentNode, currentLine);
- nodeToInstruction.put(currentNode, insn);
- instructions.add(insn);
- if (lastInsn != null) {
- insn.setPredecessor(lastInsn, 0);
- }
- final int labelCount = currentLabel.size();
- if (labelCount > 0) {
- for (int i = labelCount; --i >= 0;) {
- LabelInfo.setInstruction(currentLabel.get(i), insn);
- }
- currentLabel.clear();
- }
- lastInsn = insn;
+ builder.setCurrentLine(line);
}
@Override
public void visitInsn(final int opcode) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
public void visitIntInsn(final int opcode, final int operand) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
public void visitVarInsn(final int opcode, final int var) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
public void visitInvokeDynamicInsn(final String name, final String desc,
final Handle bsm, final Object... bsmArgs) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
public void visitJumpInsn(final int opcode, final Label label) {
- visitInsn();
- jumps.add(new Jump(lastInsn, label, 1));
+ builder.addInstruction(currentNode);
+ builder.addJump(label, 1);
}
@Override
public void visitLdcInsn(final Object cst) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
public void visitIincInsn(final int var, final int increment) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
@@ -280,15 +131,15 @@ public class MethodAnalyzer extends MethodProbesVisitor
}
private void visitSwitchInsn(final Label dflt, final Label[] labels) {
- visitInsn();
+ builder.addInstruction(currentNode);
LabelInfo.resetDone(labels);
int branch = 0;
- jumps.add(new Jump(lastInsn, dflt, branch));
+ builder.addJump(dflt, branch);
LabelInfo.setDone(dflt);
for (final Label l : labels) {
if (!LabelInfo.isDone(l)) {
branch++;
- jumps.add(new Jump(lastInsn, l, branch));
+ builder.addJump(l, branch);
LabelInfo.setDone(l);
}
}
@@ -296,26 +147,26 @@ public class MethodAnalyzer extends MethodProbesVisitor
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
- visitInsn();
+ builder.addInstruction(currentNode);
}
@Override
public void visitProbe(final int probeId) {
- addProbe(probeId, 0);
- lastInsn = null;
+ builder.addProbe(probeId, 0);
+ builder.noSuccessor();
}
@Override
public void visitJumpInsnWithProbe(final int opcode, final Label label,
final int probeId, final IFrame frame) {
- visitInsn();
- addProbe(probeId, 1);
+ builder.addInstruction(currentNode);
+ builder.addProbe(probeId, 1);
}
@Override
public void visitInsnWithProbe(final int opcode, final int probeId) {
- visitInsn();
- addProbe(probeId, 0);
+ builder.addInstruction(currentNode);
+ builder.addProbe(probeId, 0);
}
@Override
@@ -332,7 +183,7 @@ public class MethodAnalyzer extends MethodProbesVisitor
private void visitSwitchInsnWithProbes(final Label dflt,
final Label[] labels) {
- visitInsn();
+ builder.addInstruction(currentNode);
LabelInfo.resetDone(dflt);
LabelInfo.resetDone(labels);
int branch = 0;
@@ -347,81 +198,12 @@ public class MethodAnalyzer extends MethodProbesVisitor
final int id = LabelInfo.getProbeId(label);
if (!LabelInfo.isDone(label)) {
if (id == LabelInfo.NO_PROBE) {
- jumps.add(new Jump(lastInsn, label, branch));
+ builder.addJump(label, branch);
} else {
- addProbe(id, branch);
+ builder.addProbe(id, branch);
}
LabelInfo.setDone(label);
}
}
- @Override
- public void visitEnd() {
- // Wire jumps:
- for (final Jump j : jumps) {
- LabelInfo.getInstruction(j.target).setPredecessor(j.source,
- j.branch);
- }
- // Propagate probe values:
- for (final CoveredProbe p : coveredProbes) {
- p.instruction.setCovered(p.branch);
- }
- // Merge:
- for (final Instruction i : instructions) {
- final AbstractInsnNode m = i.getNode();
- final AbstractInsnNode r = findRepresentative(m);
- if (r != m) {
- ignored.add(m);
- nodeToInstruction.get(r).merge(i);
- }
- }
- // Report result:
- coverage.ensureCapacity(firstLine, lastLine);
- for (final Instruction i : instructions) {
- if (ignored.contains(i.getNode())) {
- continue;
- }
-
- final int total = i.getBranches();
- final int covered = i.getCoveredBranches();
- final ICounter instrCounter = covered == 0 ? CounterImpl.COUNTER_1_0
- : CounterImpl.COUNTER_0_1;
- final ICounter branchCounter = total > 1
- ? CounterImpl.getInstance(total - covered, covered)
- : CounterImpl.COUNTER_0_0;
- coverage.increment(instrCounter, branchCounter, i.getLine());
- }
- coverage.incrementMethodCounter();
- }
-
- private void addProbe(final int probeId, final int branch) {
- lastInsn.addBranch();
- if (probes != null && probes[probeId]) {
- coveredProbes.add(new CoveredProbe(lastInsn, branch));
- }
- }
-
- private static class CoveredProbe {
- final Instruction instruction;
- final int branch;
-
- private CoveredProbe(final Instruction instruction, final int branch) {
- this.instruction = instruction;
- this.branch = branch;
- }
- }
-
- private static class Jump {
-
- final Instruction source;
- final Label target;
- final int branch;
-
- Jump(final Instruction source, final Label target, final int branch) {
- this.source = source;
- this.target = target;
- this.branch = branch;
- }
- }
-
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageCalculator.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageCalculator.java
new file mode 100644
index 00000000..ebe167a2
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageCalculator.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.jacoco.core.analysis.ISourceFileCoverage;
+import org.jacoco.core.analysis.ISourceNode;
+import org.jacoco.core.internal.analysis.filter.IFilterOutput;
+import org.objectweb.asm.tree.AbstractInsnNode;
+
+/**
+ * Calculates the filtered coverage of a single method. A instance of this class
+ * can be first used as {@link IFilterOutput} before the coverage result is
+ * calculated.
+ */
+class MethodCoverageCalculator implements IFilterOutput {
+
+ private final Map<AbstractInsnNode, Instruction> instructions;
+
+ private final Set<AbstractInsnNode> ignored;
+
+ /**
+ * Instructions that should be merged form disjoint sets. Coverage
+ * information from instructions of one set will be merged into
+ * representative instruction of set.
+ *
+ * Each such set is represented as a singly linked list: each element except
+ * one references another element from the same set, element without
+ * reference - is a representative of this set.
+ *
+ * This map stores reference (value) for elements of sets (key).
+ */
+ private final Map<AbstractInsnNode, AbstractInsnNode> merged;
+
+ private final Map<AbstractInsnNode, Set<AbstractInsnNode>> replacements;
+
+ MethodCoverageCalculator(
+ final Map<AbstractInsnNode, Instruction> instructions) {
+ this.instructions = instructions;
+ this.ignored = new HashSet<AbstractInsnNode>();
+ this.merged = new HashMap<AbstractInsnNode, AbstractInsnNode>();
+ this.replacements = new HashMap<AbstractInsnNode, Set<AbstractInsnNode>>();
+ }
+
+ /**
+ * Applies all specified filtering commands and calculates the resulting
+ * coverage.
+ *
+ * @param coverage
+ * the result is added to this coverage node
+ */
+ void calculate(final MethodCoverageImpl coverage) {
+ applyMerges();
+ applyReplacements();
+ ensureCapacity(coverage);
+
+ for (final Entry<AbstractInsnNode, Instruction> entry : instructions
+ .entrySet()) {
+ if (!ignored.contains(entry.getKey())) {
+ final Instruction instruction = entry.getValue();
+ coverage.increment(instruction.getInstructionCounter(),
+ instruction.getBranchCounter(), instruction.getLine());
+ }
+ }
+
+ coverage.incrementMethodCounter();
+ }
+
+ private void applyMerges() {
+ // Merge to the representative:
+ for (final Entry<AbstractInsnNode, AbstractInsnNode> entry : merged
+ .entrySet()) {
+ final AbstractInsnNode node = entry.getKey();
+ final Instruction instruction = instructions.get(node);
+ final AbstractInsnNode representativeNode = findRepresentative(
+ node);
+ ignored.add(node);
+ instructions.put(representativeNode,
+ instructions.get(representativeNode).merge(instruction));
+ entry.setValue(representativeNode);
+ }
+
+ // Get merged value back from representative
+ for (final Entry<AbstractInsnNode, AbstractInsnNode> entry : merged
+ .entrySet()) {
+ instructions.put(entry.getKey(),
+ instructions.get(entry.getValue()));
+ }
+ }
+
+ private void applyReplacements() {
+ for (final Entry<AbstractInsnNode, Set<AbstractInsnNode>> entry : replacements
+ .entrySet()) {
+ final Set<AbstractInsnNode> replacements = entry.getValue();
+ final List<Instruction> newBranches = new ArrayList<Instruction>(
+ replacements.size());
+ for (final AbstractInsnNode b : replacements) {
+ newBranches.add(instructions.get(b));
+ }
+ final AbstractInsnNode node = entry.getKey();
+ instructions.put(node,
+ instructions.get(node).replaceBranches(newBranches));
+ }
+ }
+
+ private void ensureCapacity(final MethodCoverageImpl coverage) {
+ // Determine line range:
+ int firstLine = ISourceFileCoverage.UNKNOWN_LINE;
+ int lastLine = ISourceFileCoverage.UNKNOWN_LINE;
+ for (final Entry<AbstractInsnNode, Instruction> entry : instructions
+ .entrySet()) {
+ if (!ignored.contains(entry.getKey())) {
+ final int line = entry.getValue().getLine();
+ if (line != ISourceNode.UNKNOWN_LINE) {
+ if (firstLine > line
+ || lastLine == ISourceNode.UNKNOWN_LINE) {
+ firstLine = line;
+ }
+ if (lastLine < line) {
+ lastLine = line;
+ }
+ }
+ }
+ }
+
+ // Performance optimization to avoid incremental increase of line array:
+ coverage.ensureCapacity(firstLine, lastLine);
+ }
+
+ private AbstractInsnNode findRepresentative(AbstractInsnNode i) {
+ AbstractInsnNode r;
+ while ((r = merged.get(i)) != null) {
+ i = r;
+ }
+ return i;
+ }
+
+ // === IFilterOutput API ===
+
+ public void ignore(final AbstractInsnNode fromInclusive,
+ final AbstractInsnNode toInclusive) {
+ for (AbstractInsnNode i = fromInclusive; i != toInclusive; i = i
+ .getNext()) {
+ ignored.add(i);
+ }
+ ignored.add(toInclusive);
+ }
+
+ public void merge(AbstractInsnNode i1, AbstractInsnNode i2) {
+ i1 = findRepresentative(i1);
+ i2 = findRepresentative(i2);
+ if (i1 != i2) {
+ merged.put(i2, i1);
+ }
+ }
+
+ public void replaceBranches(final AbstractInsnNode source,
+ final Set<AbstractInsnNode> newTargets) {
+ replacements.put(source, newTargets);
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java
index 1e09129a..aa7dccf0 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/MethodCoverageImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java
index 4f92fc7c..285ddd38 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/PackageCoverageImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java
index e689e5b1..dc4483f5 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceFileCoverageImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceNodeImpl.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceNodeImpl.java
index 6aa241c5..3fa3d692 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceNodeImpl.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/SourceNodeImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/StringPool.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/StringPool.java
index a2e8d700..97e25aaa 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/StringPool.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/StringPool.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java
deleted file mode 100644
index 76b6b2f9..00000000
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractAnnotatedMethodFilter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis.filter;
-
-import java.util.List;
-
-import org.objectweb.asm.tree.AnnotationNode;
-import org.objectweb.asm.tree.MethodNode;
-
-/**
- * Filters annotated methods.
- */
-abstract class AbstractAnnotatedMethodFilter implements IFilter {
- private final String descType;
-
- /**
- * Configures a new filter instance.
- *
- * @param annotationType
- * VM type of the annotation
- */
- protected AbstractAnnotatedMethodFilter(final String annotationType) {
- this.descType = "L" + annotationType + ";";
- }
-
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
- if (hasAnnotation(methodNode)) {
- output.ignore(methodNode.instructions.getFirst(),
- methodNode.instructions.getLast());
- }
- }
-
- private boolean hasAnnotation(final MethodNode methodNode) {
- final List<AnnotationNode> annotations = getAnnotations(methodNode);
- if (annotations != null) {
- for (final AnnotationNode annotation : annotations) {
- if (descType.equals(annotation.desc)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Retrieves the annotations to search from a method. Depending on the
- * retention of the annotation this is either
- * <code>visibleAnnotations</code> or <code>invisibleAnnotations</code>.
- *
- * @param methodNode
- * method to retrieve annotations from
- * @return list of annotations
- */
- abstract List<AnnotationNode> getAnnotations(final MethodNode methodNode);
-
-}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java
index b5aea723..38860a83 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AbstractMatcher.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -17,6 +17,8 @@ import java.util.Map;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
abstract class AbstractMatcher {
@@ -25,13 +27,49 @@ abstract class AbstractMatcher {
AbstractInsnNode cursor;
- final void nextIsInvokeVirtual(final String owner, final String name) {
- nextIs(Opcodes.INVOKEVIRTUAL);
+ /**
+ * Sets {@link #cursor} to first instruction of method if it is
+ * <code>ALOAD 0</code>, otherwise sets it to <code>null</code>.
+ */
+ final void firstIsALoad0(final MethodNode methodNode) {
+ cursor = methodNode.instructions.getFirst();
+ skipNonOpcodes();
+ if (cursor.getOpcode() == Opcodes.ALOAD
+ && ((VarInsnNode) cursor).var == 0) {
+ return;
+ }
+ cursor = null;
+ }
+
+ /**
+ * Moves {@link #cursor} to next instruction if it is {@link TypeInsnNode}
+ * with given opcode and operand, otherwise sets it to <code>null</code>.
+ */
+ final void nextIsType(final int opcode, final String desc) {
+ nextIs(opcode);
+ if (cursor == null) {
+ return;
+ }
+ if (((TypeInsnNode) cursor).desc.equals(desc)) {
+ return;
+ }
+ cursor = null;
+ }
+
+ /**
+ * Moves {@link #cursor} to next instruction if it is {@link MethodInsnNode}
+ * with given opcode, owner, name and descriptor, otherwise sets it to
+ * <code>null</code>.
+ */
+ final void nextIsInvoke(final int opcode, final String owner,
+ final String name, final String descriptor) {
+ nextIs(opcode);
if (cursor == null) {
return;
}
final MethodInsnNode m = (MethodInsnNode) cursor;
- if (owner.equals(m.owner) && name.equals(m.name)) {
+ if (owner.equals(m.owner) && name.equals(m.name)
+ && descriptor.equals(m.desc)) {
return;
}
cursor = null;
@@ -52,6 +90,25 @@ abstract class AbstractMatcher {
}
/**
+ * Moves {@link #cursor} to next instruction if it is
+ * <code>TABLESWITCH</code> or <code>LOOKUPSWITCH</code>, otherwise sets it
+ * to <code>null</code>.
+ */
+ final void nextIsSwitch() {
+ next();
+ if (cursor == null) {
+ return;
+ }
+ switch (cursor.getOpcode()) {
+ case Opcodes.TABLESWITCH:
+ case Opcodes.LOOKUPSWITCH:
+ return;
+ default:
+ cursor = null;
+ }
+ }
+
+ /**
* Moves {@link #cursor} to next instruction if it has given opcode,
* otherwise sets it to <code>null</code>.
*/
@@ -76,12 +133,26 @@ abstract class AbstractMatcher {
skipNonOpcodes();
}
+ /**
+ * Moves {@link #cursor} through {@link AbstractInsnNode#FRAME},
+ * {@link AbstractInsnNode#LABEL}, {@link AbstractInsnNode#LINE}.
+ */
final void skipNonOpcodes() {
+ cursor = skipNonOpcodes(cursor);
+ }
+
+ /**
+ * Returns first instruction from given and following it that is not
+ * {@link AbstractInsnNode#FRAME}, {@link AbstractInsnNode#LABEL},
+ * {@link AbstractInsnNode#LINE}.
+ */
+ static AbstractInsnNode skipNonOpcodes(AbstractInsnNode cursor) {
while (cursor != null && (cursor.getType() == AbstractInsnNode.FRAME
|| cursor.getType() == AbstractInsnNode.LABEL
|| cursor.getType() == AbstractInsnNode.LINE)) {
cursor = cursor.getNext();
}
+ return cursor;
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java
new file mode 100644
index 00000000..d78444c0
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/AnnotationGeneratedFilter.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.List;
+
+import org.objectweb.asm.tree.AnnotationNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Filters classes and methods annotated with
+ * {@link java.lang.annotation.RetentionPolicy#RUNTIME runtime visible} and
+ * {@link java.lang.annotation.RetentionPolicy#CLASS invisible} annotation whose
+ * simple name contains <code>Generated</code>.
+ */
+public final class AnnotationGeneratedFilter implements IFilter {
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+
+ for (String annotation : context.getClassAnnotations()) {
+ if (matches(annotation)) {
+ output.ignore(methodNode.instructions.getFirst(),
+ methodNode.instructions.getLast());
+ return;
+ }
+ }
+
+ if (presentIn(methodNode.invisibleAnnotations)
+ || presentIn(methodNode.visibleAnnotations)) {
+ output.ignore(methodNode.instructions.getFirst(),
+ methodNode.instructions.getLast());
+ }
+
+ }
+
+ private static boolean matches(final String annotation) {
+ final String name = annotation
+ .substring(Math.max(annotation.lastIndexOf('/'),
+ annotation.lastIndexOf('$')) + 1);
+ return name.contains("Generated");
+ }
+
+ private static boolean presentIn(final List<AnnotationNode> annotations) {
+ if (annotations != null) {
+ for (AnnotationNode annotation : annotations) {
+ if (matches(annotation.desc)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java
new file mode 100644
index 00000000..4a39d1e8
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumEmptyConstructorFilter.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Filters empty enum constructors.
+ *
+ * Constructor of enum is invoked from static initialization block to create
+ * instance of each enum constant. So it won't be executed if number of enum
+ * constants is zero. Such enums are sometimes used as alternative to classes
+ * with static utilities and private empty constructor. Implicit constructor of
+ * enum created by compiler doesn't have a synthetic flag and refers to a line
+ * of enum definition. Therefore in order to not have partial coverage of enum
+ * definition line in enums without enum constants and similarly to
+ * {@link PrivateEmptyNoArgConstructorFilter filter of private empty
+ * constructors} - empty constructor in enums without additional parameters
+ * should be filtered out even if it is not implicit.
+ */
+public final class EnumEmptyConstructorFilter implements IFilter {
+
+ private static final String CONSTRUCTOR_NAME = "<init>";
+ private static final String CONSTRUCTOR_DESC = "(Ljava/lang/String;I)V";
+
+ private static final String ENUM_TYPE = "java/lang/Enum";
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ if (ENUM_TYPE.equals(context.getSuperClassName())
+ && CONSTRUCTOR_NAME.equals(methodNode.name)
+ && CONSTRUCTOR_DESC.equals(methodNode.desc)
+ && new Matcher().match(methodNode)) {
+ output.ignore(methodNode.instructions.getFirst(),
+ methodNode.instructions.getLast());
+ }
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ private boolean match(final MethodNode methodNode) {
+ firstIsALoad0(methodNode);
+ nextIs(Opcodes.ALOAD);
+ nextIs(Opcodes.ILOAD);
+ nextIsInvoke(Opcodes.INVOKESPECIAL, ENUM_TYPE, CONSTRUCTOR_NAME,
+ CONSTRUCTOR_DESC);
+ nextIs(Opcodes.RETURN);
+ return cursor != null;
+ }
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java
index c5f1784c..0c2eef58 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/EnumFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -19,9 +19,10 @@ import org.objectweb.asm.tree.MethodNode;
*/
public final class EnumFilter implements IFilter {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
- if (isMethodFiltered(className, superClassName, methodNode.name,
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ if (isMethodFiltered(context.getClassName(),
+ context.getSuperClassName(), methodNode.name,
methodNode.desc)) {
output.ignore(methodNode.instructions.getFirst(),
methodNode.instructions.getLast());
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java
index 0f344180..7a1053b5 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/Filters.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -23,26 +23,38 @@ public final class Filters implements IFilter {
*/
public static final IFilter NONE = new Filters();
+ private final IFilter[] filters;
+
/**
- * Filter that combines all other filters.
+ * Creates filter that combines all other filters.
+ *
+ * @return filter that combines all other filters
*/
- public static final IFilter ALL = new Filters(new EnumFilter(),
- new SyntheticFilter(), new SynchronizedFilter(),
- new TryWithResourcesJavacFilter(), new TryWithResourcesEcjFilter(),
- new FinallyFilter(), new PrivateEmptyNoArgConstructorFilter(),
- new StringSwitchJavacFilter(), new LombokGeneratedFilter(),
- new GroovyGeneratedFilter());
-
- private final IFilter[] filters;
+ public static IFilter all() {
+ return new Filters(new EnumFilter(), new SyntheticFilter(),
+ new SynchronizedFilter(), new TryWithResourcesJavac11Filter(),
+ new TryWithResourcesJavacFilter(),
+ new TryWithResourcesEcjFilter(), new FinallyFilter(),
+ new PrivateEmptyNoArgConstructorFilter(),
+ new StringSwitchJavacFilter(), new StringSwitchEcjFilter(),
+ new EnumEmptyConstructorFilter(),
+ new AnnotationGeneratedFilter(), new KotlinGeneratedFilter(),
+ new KotlinLateinitFilter(), new KotlinWhenFilter(),
+ new KotlinWhenStringFilter(),
+ new KotlinUnsafeCastOperatorFilter(),
+ new KotlinNotNullOperatorFilter(),
+ new KotlinDefaultArgumentsFilter(), new KotlinInlineFilter(),
+ new KotlinCoroutineFilter());
+ }
private Filters(final IFilter... filters) {
this.filters = filters;
}
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
for (final IFilter filter : filters) {
- filter.filter(className, superClassName, methodNode, output);
+ filter.filter(methodNode, context, output);
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java
index 830d0c28..b2e0b145 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/FinallyFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -67,8 +67,8 @@ import org.objectweb.asm.tree.VarInsnNode;
*/
public final class FinallyFilter implements IFilter {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
for (final TryCatchBlockNode tryCatchBlock : methodNode.tryCatchBlocks) {
if (tryCatchBlock.type == null) {
filter(output, methodNode.tryCatchBlocks, tryCatchBlock);
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilter.java
deleted file mode 100644
index 816cc4cd..00000000
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/GroovyGeneratedFilter.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis.filter;
-
-import java.util.List;
-
-import org.objectweb.asm.tree.AnnotationNode;
-import org.objectweb.asm.tree.MethodNode;
-
-/**
- * Filters methods annotated with <code>@groovy.transform.Generated</code>.
- */
-public final class GroovyGeneratedFilter extends AbstractAnnotatedMethodFilter {
-
- /**
- * New filter.
- */
- public GroovyGeneratedFilter() {
- super("groovy/transform/Generated");
- }
-
- @Override
- List<AnnotationNode> getAnnotations(final MethodNode methodNode) {
- return methodNode.visibleAnnotations;
- }
-
-}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java
index 82b7959a..b662ba4f 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -14,8 +14,8 @@ package org.jacoco.core.internal.analysis.filter;
import org.objectweb.asm.tree.MethodNode;
/**
- * Interface for filter implementations. Instances of filters are reused and so
- * must be stateless.
+ * Interface for filter implementations. Instances of filters are created for
+ * analysis of each class and so can have per-class state.
*/
public interface IFilter {
@@ -24,16 +24,13 @@ public interface IFilter {
* expected to inspect the provided method and report its result to the
* given {@link IFilterOutput} instance.
*
- * @param className
- * class name
- * @param superClassName
- * superclass name
* @param methodNode
* method to inspect
+ * @param context
+ * context information for the method
* @param output
* callback to report filtering results to
*/
- void filter(String className, String superClassName, MethodNode methodNode,
+ void filter(MethodNode methodNode, IFilterContext context,
IFilterOutput output);
-
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java
new file mode 100644
index 00000000..8b97654d
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterContext.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Marc R. Hoffmann - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.Set;
+
+/**
+ * Context information provided to filters.
+ */
+public interface IFilterContext {
+
+ /**
+ * @return vm name of the enclosing class
+ */
+ String getClassName();
+
+ /**
+ * @return vm name of the super class of the enclosing class
+ */
+ String getSuperClassName();
+
+ /**
+ * @return vm names of the class annotations of the enclosing class
+ */
+ Set<String> getClassAnnotations();
+
+ /**
+ * @return file name of the corresponding source file or <code>null</code>
+ * if not available
+ */
+ String getSourceFileName();
+
+ /**
+ * @return value of SourceDebugExtension attribute or <code>null</code> if
+ * not available
+ */
+ String getSourceDebugExtension();
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java
index 4ca9b814..0f022201 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/IFilterOutput.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,6 +11,8 @@
*******************************************************************************/
package org.jacoco.core.internal.analysis.filter;
+import java.util.Set;
+
import org.objectweb.asm.tree.AbstractInsnNode;
/**
@@ -41,4 +43,16 @@ public interface IFilterOutput {
*/
void merge(AbstractInsnNode i1, AbstractInsnNode i2);
+ /**
+ * Marks instruction whose outgoing branches should be replaced during
+ * computation of coverage.
+ *
+ * @param source
+ * instruction which branches should be replaced
+ * @param newTargets
+ * new targets of branches
+ */
+ void replaceBranches(AbstractInsnNode source,
+ Set<AbstractInsnNode> newTargets);
+
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java
new file mode 100644
index 00000000..66d450a3
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinCoroutineFilter.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LdcInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TableSwitchInsnNode;
+
+/**
+ * Filters branches that Kotlin compiler generates for coroutines.
+ */
+public final class KotlinCoroutineFilter implements IFilter {
+
+ static boolean isLastArgumentContinuation(final MethodNode methodNode) {
+ final Type methodType = Type.getMethodType(methodNode.desc);
+ final int lastArgument = methodType.getArgumentTypes().length - 1;
+ return lastArgument >= 0 && "kotlin.coroutines.Continuation".equals(
+ methodType.getArgumentTypes()[lastArgument].getClassName());
+ }
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+
+ if (!KotlinGeneratedFilter.isKotlinClass(context)) {
+ return;
+ }
+
+ new Matcher().match(methodNode, output);
+
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ private void match(final MethodNode methodNode,
+ final IFilterOutput output) {
+ cursor = methodNode.instructions.getFirst();
+ nextIsInvoke(Opcodes.INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;");
+
+ if (cursor == null) {
+ cursor = skipNonOpcodes(methodNode.instructions.getFirst());
+
+ nextIsCreateStateInstance();
+
+ nextIsInvoke(Opcodes.INVOKESTATIC,
+ "kotlin/coroutines/intrinsics/IntrinsicsKt",
+ "getCOROUTINE_SUSPENDED", "()Ljava/lang/Object;");
+ }
+
+ nextIsVar(Opcodes.ASTORE, "COROUTINE_SUSPENDED");
+ nextIsVar(Opcodes.ALOAD, "this");
+ nextIs(Opcodes.GETFIELD);
+ nextIs(Opcodes.TABLESWITCH);
+ if (cursor == null) {
+ return;
+ }
+ final TableSwitchInsnNode s = (TableSwitchInsnNode) cursor;
+ final List<AbstractInsnNode> ignore = new ArrayList<AbstractInsnNode>(
+ s.labels.size() * 2);
+
+ nextIs(Opcodes.ALOAD);
+ nextIsThrowOnFailure();
+
+ if (cursor == null) {
+ return;
+ }
+ ignore.add(methodNode.instructions.getFirst());
+ ignore.add(cursor);
+
+ int suspensionPoint = 1;
+ for (AbstractInsnNode i = cursor; i != null
+ && suspensionPoint < s.labels.size(); i = i.getNext()) {
+ cursor = i;
+ nextIsVar(Opcodes.ALOAD, "COROUTINE_SUSPENDED");
+ nextIs(Opcodes.IF_ACMPNE);
+ if (cursor == null) {
+ continue;
+ }
+ final AbstractInsnNode continuationAfterLoadedResult = skipNonOpcodes(
+ ((JumpInsnNode) cursor).label);
+ nextIsVar(Opcodes.ALOAD, "COROUTINE_SUSPENDED");
+ nextIs(Opcodes.ARETURN);
+ if (cursor == null
+ || skipNonOpcodes(cursor.getNext()) != skipNonOpcodes(
+ s.labels.get(suspensionPoint))) {
+ continue;
+ }
+
+ for (AbstractInsnNode j = i; j != null; j = j.getNext()) {
+ cursor = j;
+ nextIs(Opcodes.ALOAD);
+ nextIsThrowOnFailure();
+
+ nextIs(Opcodes.ALOAD);
+ if (cursor != null && skipNonOpcodes(cursor
+ .getNext()) == continuationAfterLoadedResult) {
+ ignore.add(i);
+ ignore.add(cursor);
+ suspensionPoint++;
+ break;
+ }
+ }
+ }
+
+ cursor = s.dflt;
+ nextIsType(Opcodes.NEW, "java/lang/IllegalStateException");
+ nextIs(Opcodes.DUP);
+ nextIs(Opcodes.LDC);
+ if (cursor == null) {
+ return;
+ }
+ if (!((LdcInsnNode) cursor).cst.equals(
+ "call to 'resume' before 'invoke' with coroutine")) {
+ return;
+ }
+ nextIsInvoke(Opcodes.INVOKESPECIAL,
+ "java/lang/IllegalStateException", "<init>",
+ "(Ljava/lang/String;)V");
+ nextIs(Opcodes.ATHROW);
+ if (cursor == null) {
+ return;
+ }
+
+ output.ignore(s.dflt, cursor);
+ for (int i = 0; i < ignore.size(); i += 2) {
+ output.ignore(ignore.get(i), ignore.get(i + 1));
+ }
+ }
+
+ private void nextIsThrowOnFailure() {
+ final AbstractInsnNode c = cursor;
+ nextIsInvoke(Opcodes.INVOKESTATIC, "kotlin/ResultKt",
+ "throwOnFailure", "(Ljava/lang/Object;)V");
+ if (cursor == null) {
+ cursor = c;
+ // Before resolution of
+ // https://youtrack.jetbrains.com/issue/KT-28015 in
+ // Kotlin 1.3.30
+ nextIs(Opcodes.DUP);
+ nextIsType(Opcodes.INSTANCEOF, "kotlin/Result$Failure");
+ nextIs(Opcodes.IFEQ);
+ nextIsType(Opcodes.CHECKCAST, "kotlin/Result$Failure");
+ nextIs(Opcodes.GETFIELD);
+ nextIs(Opcodes.ATHROW);
+ nextIs(Opcodes.POP);
+ }
+ }
+
+ private void nextIsCreateStateInstance() {
+ nextIs(Opcodes.INSTANCEOF);
+
+ nextIs(Opcodes.IFEQ);
+ if (cursor == null) {
+ return;
+ }
+ final AbstractInsnNode createStateInstance = skipNonOpcodes(
+ ((JumpInsnNode) cursor).label);
+
+ nextIs(Opcodes.ALOAD);
+ nextIs(Opcodes.CHECKCAST);
+ nextIs(Opcodes.ASTORE);
+
+ nextIs(Opcodes.ALOAD);
+ nextIs(Opcodes.GETFIELD);
+
+ nextIs(Opcodes.LDC);
+ nextIs(Opcodes.IAND);
+ nextIs(Opcodes.IFEQ);
+ if (cursor == null || skipNonOpcodes(
+ ((JumpInsnNode) cursor).label) != createStateInstance) {
+ return;
+ }
+
+ nextIs(Opcodes.ALOAD);
+ nextIs(Opcodes.DUP);
+ nextIs(Opcodes.GETFIELD);
+
+ nextIs(Opcodes.LDC);
+ nextIs(Opcodes.ISUB);
+ nextIs(Opcodes.PUTFIELD);
+
+ nextIs(Opcodes.GOTO);
+ if (cursor == null) {
+ return;
+ }
+ final AbstractInsnNode afterCoroutineStateCreated = skipNonOpcodes(
+ ((JumpInsnNode) cursor).label);
+
+ if (skipNonOpcodes(cursor.getNext()) != createStateInstance) {
+ return;
+ }
+
+ cursor = afterCoroutineStateCreated;
+ nextIs(Opcodes.GETFIELD);
+ nextIs(Opcodes.ASTORE);
+ }
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java
new file mode 100644
index 00000000..ef198447
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinDefaultArgumentsFilter.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.VarInsnNode;
+
+/**
+ * Filters branches that Kotlin compiler generates for default arguments.
+ *
+ * For each default argument Kotlin compiler generates following bytecode to
+ * determine if it should be used or not:
+ *
+ * <pre>
+ * ILOAD maskVar
+ * ICONST_x, BIPUSH, SIPUSH, LDC or LDC_W
+ * IAND
+ * IFEQ label
+ * default argument
+ * label:
+ * </pre>
+ *
+ * Where <code>maskVar</code> is penultimate argument of synthetic method with
+ * suffix "$default". And its value can't be zero - invocation with all
+ * arguments uses original non synthetic method, thus <code>IFEQ</code>
+ * instructions should be ignored.
+ */
+public final class KotlinDefaultArgumentsFilter implements IFilter {
+
+ static boolean isDefaultArgumentsMethodName(final String methodName) {
+ return methodName.endsWith("$default");
+ }
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ if ((methodNode.access & Opcodes.ACC_SYNTHETIC) == 0) {
+ return;
+ }
+ if (!isDefaultArgumentsMethodName(methodNode.name)) {
+ return;
+ }
+ if (!KotlinGeneratedFilter.isKotlinClass(context)) {
+ return;
+ }
+
+ new Matcher().match(methodNode, output);
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ public void match(final MethodNode methodNode,
+ final IFilterOutput output) {
+ cursor = methodNode.instructions.getFirst();
+
+ final Set<AbstractInsnNode> ignore = new HashSet<AbstractInsnNode>();
+ final int maskVar = Type.getMethodType(methodNode.desc)
+ .getArgumentTypes().length - 2;
+ while (true) {
+ if (cursor.getOpcode() != Opcodes.ILOAD) {
+ break;
+ }
+ if (((VarInsnNode) cursor).var != maskVar) {
+ break;
+ }
+ next();
+ nextIs(Opcodes.IAND);
+ nextIs(Opcodes.IFEQ);
+ if (cursor == null) {
+ return;
+ }
+ ignore.add(cursor);
+ cursor = ((JumpInsnNode) cursor).label;
+ skipNonOpcodes();
+ }
+
+ for (AbstractInsnNode i : ignore) {
+ output.ignore(i, i);
+ }
+ }
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java
new file mode 100644
index 00000000..129580a9
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinGeneratedFilter.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Nikolay Krasko - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Filters methods generated by the Kotlin compiler. Kotlin classes are
+ * identified by the <code>@kotlin.Metadata</code> annotations. In such classes
+ * generated methods do not have line numbers.
+ */
+public class KotlinGeneratedFilter implements IFilter {
+
+ static final String KOTLIN_METADATA_DESC = "Lkotlin/Metadata;";
+
+ static boolean isKotlinClass(final IFilterContext context) {
+ return context.getClassAnnotations().contains(KOTLIN_METADATA_DESC);
+ }
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+
+ if (context.getSourceFileName() == null) {
+ // probably full debug information is missing
+ // disabled filtering as all methods might be erroneously skipped
+ return;
+ }
+
+ if (!isKotlinClass(context)) {
+ return;
+ }
+
+ if (hasLineNumber(methodNode)) {
+ return;
+ }
+
+ output.ignore(methodNode.instructions.getFirst(),
+ methodNode.instructions.getLast());
+ }
+
+ private boolean hasLineNumber(final MethodNode methodNode) {
+ for (AbstractInsnNode i = methodNode.instructions
+ .getFirst(); i != null; i = i.getNext()) {
+ if (AbstractInsnNode.LINE == i.getType()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java
new file mode 100644
index 00000000..5666de2d
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinInlineFilter.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.BitSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.LineNumberNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Filters out instructions that were inlined by Kotlin compiler.
+ */
+public final class KotlinInlineFilter implements IFilter {
+
+ private int firstGeneratedLineNumber = -1;
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ if (context.getSourceDebugExtension() == null) {
+ return;
+ }
+
+ if (!KotlinGeneratedFilter.isKotlinClass(context)) {
+ return;
+ }
+
+ if (firstGeneratedLineNumber == -1) {
+ firstGeneratedLineNumber = getFirstGeneratedLineNumber(
+ context.getSourceFileName(),
+ context.getSourceDebugExtension());
+ }
+
+ int line = 0;
+ for (AbstractInsnNode i = methodNode.instructions
+ .getFirst(); i != null; i = i.getNext()) {
+ if (AbstractInsnNode.LINE == i.getType()) {
+ line = ((LineNumberNode) i).line;
+ }
+ if (line >= firstGeneratedLineNumber) {
+ output.ignore(i, i);
+ }
+ }
+ }
+
+ private static int getFirstGeneratedLineNumber(final String sourceFileName,
+ final String smap) {
+ try {
+ final BufferedReader br = new BufferedReader(
+ new StringReader(smap));
+ expectLine(br, "SMAP");
+ // OutputFileName
+ expectLine(br, sourceFileName);
+ // DefaultStratumId
+ expectLine(br, "Kotlin");
+ // StratumSection
+ expectLine(br, "*S Kotlin");
+ // FileSection
+ expectLine(br, "*F");
+ final BitSet sourceFileIds = new BitSet();
+ String line;
+ while (!"*L".equals(line = br.readLine())) {
+ // AbsoluteFileName
+ br.readLine();
+
+ final Matcher m = FILE_INFO_PATTERN.matcher(line);
+ if (!m.matches()) {
+ throw new IllegalStateException(
+ "Unexpected SMAP line: " + line);
+ }
+ final String fileName = m.group(2);
+ if (fileName.equals(sourceFileName)) {
+ sourceFileIds.set(Integer.parseInt(m.group(1)));
+ }
+ }
+ if (sourceFileIds.isEmpty()) {
+ throw new IllegalStateException("Unexpected SMAP FileSection");
+ }
+ // LineSection
+ int min = Integer.MAX_VALUE;
+ while (!"*E".equals(line = br.readLine())) {
+ final Matcher m = LINE_INFO_PATTERN.matcher(line);
+ if (!m.matches()) {
+ throw new IllegalStateException(
+ "Unexpected SMAP line: " + line);
+ }
+ final int inputStartLine = Integer.parseInt(m.group(1));
+ final int lineFileID = Integer
+ .parseInt(m.group(2).substring(1));
+ final int outputStartLine = Integer.parseInt(m.group(4));
+ if (sourceFileIds.get(lineFileID)
+ && inputStartLine == outputStartLine) {
+ continue;
+ }
+ min = Math.min(outputStartLine, min);
+ }
+ return min;
+ } catch (final IOException e) {
+ // Must not happen with StringReader
+ throw new AssertionError(e);
+ }
+ }
+
+ private static void expectLine(final BufferedReader br,
+ final String expected) throws IOException {
+ final String line = br.readLine();
+ if (!expected.equals(line)) {
+ throw new IllegalStateException("Unexpected SMAP line: " + line);
+ }
+ }
+
+ private static final Pattern LINE_INFO_PATTERN = Pattern.compile("" //
+ + "([0-9]++)" // InputStartLine
+ + "(#[0-9]++)?+" // LineFileID
+ + "(,[0-9]++)?+" // RepeatCount
+ + ":([0-9]++)" // OutputStartLine
+ + "(,[0-9]++)?+" // OutputLineIncrement
+ );
+
+ private static final Pattern FILE_INFO_PATTERN = Pattern.compile("" //
+ + "\\+ ([0-9]++)" // FileID
+ + " (.++)" // FileName
+ );
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java
new file mode 100644
index 00000000..12fe926c
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinLateinitFilter.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Fabian Mastenbroek - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Filters branch in bytecode that Kotlin compiler generates for reading from
+ * <code>lateinit</code> properties.
+ */
+public class KotlinLateinitFilter implements IFilter {
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ final Matcher matcher = new Matcher();
+ for (AbstractInsnNode i = methodNode.instructions
+ .getFirst(); i != null; i = i.getNext()) {
+ matcher.match(i, output);
+ }
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ public void match(final AbstractInsnNode start,
+ final IFilterOutput output) {
+
+ if (Opcodes.IFNONNULL != start.getOpcode()) {
+ return;
+ }
+ cursor = start;
+
+ nextIs(Opcodes.LDC);
+ nextIsInvoke(Opcodes.INVOKESTATIC, "kotlin/jvm/internal/Intrinsics",
+ "throwUninitializedPropertyAccessException",
+ "(Ljava/lang/String;)V");
+
+ if (cursor != null) {
+ output.ignore(start, cursor);
+ }
+ }
+ }
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java
new file mode 100644
index 00000000..4dd223a3
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinNotNullOperatorFilter.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Filters branch in bytecode that Kotlin compiler generates for not-null
+ * assertion operator.
+ */
+public final class KotlinNotNullOperatorFilter implements IFilter {
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ final Matcher matcher = new Matcher();
+ for (AbstractInsnNode i = methodNode.instructions
+ .getFirst(); i != null; i = i.getNext()) {
+ matcher.match(i, output);
+ }
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ public void match(final AbstractInsnNode start,
+ final IFilterOutput output) {
+ if (Opcodes.IFNONNULL != start.getOpcode()) {
+ return;
+ }
+ cursor = start;
+ nextIsInvoke(Opcodes.INVOKESTATIC, "kotlin/jvm/internal/Intrinsics",
+ "throwNpe", "()V");
+ if (cursor == null) {
+ return;
+ }
+ output.ignore(start, cursor);
+ }
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java
new file mode 100644
index 00000000..c298e945
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinUnsafeCastOperatorFilter.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LdcInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+/**
+ * Filters branch in bytecode that Kotlin compiler generates for "unsafe" cast
+ * operator.
+ */
+public final class KotlinUnsafeCastOperatorFilter implements IFilter {
+
+ private static final String KOTLIN_TYPE_CAST_EXCEPTION = "kotlin/TypeCastException";
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ final Matcher matcher = new Matcher();
+ for (AbstractInsnNode i = methodNode.instructions
+ .getFirst(); i != null; i = i.getNext()) {
+ matcher.match(i, output);
+ }
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ public void match(final AbstractInsnNode start,
+ final IFilterOutput output) {
+
+ if (Opcodes.IFNONNULL != start.getOpcode()) {
+ return;
+ }
+ cursor = start;
+
+ nextIsType(Opcodes.NEW, KOTLIN_TYPE_CAST_EXCEPTION);
+ nextIs(Opcodes.DUP);
+ nextIs(Opcodes.LDC);
+ if (cursor == null) {
+ return;
+ }
+ final LdcInsnNode ldc = (LdcInsnNode) cursor;
+ if (!(ldc.cst instanceof String && ((String) ldc.cst)
+ .startsWith("null cannot be cast to non-null type"))) {
+ return;
+ }
+ nextIsInvoke(Opcodes.INVOKESPECIAL, KOTLIN_TYPE_CAST_EXCEPTION,
+ "<init>", "(Ljava/lang/String;)V");
+ nextIs(Opcodes.ATHROW);
+ if (cursor == null) {
+ return;
+ }
+ if (cursor.getNext() != ((JumpInsnNode) start).label) {
+ return;
+ }
+
+ output.ignore(start, cursor);
+ }
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java
new file mode 100644
index 00000000..a229aa04
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenFilter.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.LookupSwitchInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TableSwitchInsnNode;
+
+/**
+ * Filters bytecode that Kotlin compiler generates for <code>when</code>
+ * expressions which list all cases of <code>enum</code> or
+ * <code>sealed class</code>, i.e. which don't require explicit
+ * <code>else</code>.
+ */
+public final class KotlinWhenFilter implements IFilter {
+
+ private static final String EXCEPTION = "kotlin/NoWhenBranchMatchedException";
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ final Matcher matcher = new Matcher();
+ for (AbstractInsnNode i = methodNode.instructions
+ .getFirst(); i != null; i = i.getNext()) {
+ matcher.match(i, output);
+ }
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ void match(final AbstractInsnNode start, final IFilterOutput output) {
+ if (start.getType() != InsnNode.LABEL) {
+ return;
+ }
+ cursor = start;
+
+ nextIsType(Opcodes.NEW, EXCEPTION);
+ nextIs(Opcodes.DUP);
+ nextIsInvoke(Opcodes.INVOKESPECIAL, EXCEPTION, "<init>", "()V");
+ nextIs(Opcodes.ATHROW);
+
+ for (AbstractInsnNode i = cursor; i != null; i = i.getPrevious()) {
+ if (i.getOpcode() == Opcodes.IFEQ
+ && ((JumpInsnNode) i).label == start) {
+ output.ignore(i, i);
+ output.ignore(start, cursor);
+ return;
+
+ } else if (getDefaultLabel(i) == start) {
+ ignoreDefaultBranch(i, output);
+ output.ignore(start, cursor);
+ return;
+
+ }
+ }
+ }
+ }
+
+ private static LabelNode getDefaultLabel(final AbstractInsnNode i) {
+ switch (i.getOpcode()) {
+ case Opcodes.LOOKUPSWITCH:
+ return ((LookupSwitchInsnNode) i).dflt;
+ case Opcodes.TABLESWITCH:
+ return ((TableSwitchInsnNode) i).dflt;
+ default:
+ return null;
+ }
+ }
+
+ private static void ignoreDefaultBranch(final AbstractInsnNode switchNode,
+ final IFilterOutput output) {
+ final List<LabelNode> labels;
+ if (switchNode.getOpcode() == Opcodes.LOOKUPSWITCH) {
+ labels = ((LookupSwitchInsnNode) switchNode).labels;
+ } else {
+ labels = ((TableSwitchInsnNode) switchNode).labels;
+ }
+ final Set<AbstractInsnNode> newTargets = new HashSet<AbstractInsnNode>();
+ for (LabelNode label : labels) {
+ newTargets.add(AbstractMatcher.skipNonOpcodes(label));
+ }
+ output.replaceBranches(switchNode, newTargets);
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java
new file mode 100644
index 00000000..fcccb550
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/KotlinWhenStringFilter.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.LookupSwitchInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TableSwitchInsnNode;
+import org.objectweb.asm.tree.VarInsnNode;
+
+/**
+ * Filters bytecode that Kotlin compiler generates for <code>when</code>
+ * expressions with a <code>String</code>.
+ */
+public final class KotlinWhenStringFilter implements IFilter {
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ final Matcher matcher = new Matcher();
+ for (AbstractInsnNode i = methodNode.instructions
+ .getFirst(); i != null; i = i.getNext()) {
+ matcher.match(i, output);
+ }
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ public void match(final AbstractInsnNode start,
+ final IFilterOutput output) {
+
+ if (Opcodes.ALOAD != start.getOpcode()) {
+ return;
+ }
+ cursor = start;
+ nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode",
+ "()I");
+ nextIsSwitch();
+ if (cursor == null) {
+ return;
+ }
+ vars.put("s", (VarInsnNode) start);
+
+ final AbstractInsnNode s = cursor;
+ final int hashCodes;
+ final LabelNode defaultLabel;
+ if (s.getOpcode() == Opcodes.LOOKUPSWITCH) {
+ final LookupSwitchInsnNode lookupSwitch = (LookupSwitchInsnNode) cursor;
+ defaultLabel = lookupSwitch.dflt;
+ hashCodes = lookupSwitch.labels.size();
+ } else {
+ final TableSwitchInsnNode tableSwitch = (TableSwitchInsnNode) cursor;
+ defaultLabel = tableSwitch.dflt;
+ hashCodes = tableSwitch.labels.size();
+ }
+
+ final Set<AbstractInsnNode> replacements = new HashSet<AbstractInsnNode>();
+ replacements.add(skipNonOpcodes(defaultLabel));
+
+ for (int i = 0; i < hashCodes; i++) {
+ while (true) {
+ nextIsVar(Opcodes.ALOAD, "s");
+ nextIs(Opcodes.LDC);
+ nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String",
+ "equals", "(Ljava/lang/Object;)Z");
+ // jump to next comparison or default case
+ nextIs(Opcodes.IFEQ);
+ final JumpInsnNode jump = (JumpInsnNode) cursor;
+ // jump to case
+ nextIs(Opcodes.GOTO);
+ if (cursor == null) {
+ return;
+ }
+
+ replacements
+ .add(skipNonOpcodes(((JumpInsnNode) cursor).label));
+
+ if (jump.label == defaultLabel) {
+ // end of comparisons for same hashCode
+ break;
+ }
+ }
+ }
+
+ output.ignore(s.getNext(), cursor);
+ output.replaceBranches(s, replacements);
+ }
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java
deleted file mode 100644
index b35e741f..00000000
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/LombokGeneratedFilter.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.analysis.filter;
-
-import java.util.List;
-
-import org.objectweb.asm.tree.AnnotationNode;
-import org.objectweb.asm.tree.MethodNode;
-
-/**
- * Filters methods annotated with <code>@lombok.Generated</code>.
- */
-public final class LombokGeneratedFilter extends AbstractAnnotatedMethodFilter {
-
- /**
- * New filter.
- */
- public LombokGeneratedFilter() {
- super("lombok/Generated");
- }
-
- @Override
- List<AnnotationNode> getAnnotations(final MethodNode methodNode) {
- return methodNode.invisibleAnnotations;
- }
-
-}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java
index 08c654e3..236ef712 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/PrivateEmptyNoArgConstructorFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -12,21 +12,22 @@
package org.jacoco.core.internal.analysis.filter;
import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
-import org.objectweb.asm.tree.VarInsnNode;
/**
* Filters private empty constructors that do not have arguments.
*/
public final class PrivateEmptyNoArgConstructorFilter implements IFilter {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
+ private static final String CONSTRUCTOR_NAME = "<init>";
+ private static final String CONSTRUCTOR_DESC = "()V";
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0
- && "<init>".equals(methodNode.name)
- && "()V".equals(methodNode.desc)
- && new Matcher().match(methodNode, superClassName)) {
+ && CONSTRUCTOR_NAME.equals(methodNode.name)
+ && CONSTRUCTOR_DESC.equals(methodNode.desc) && new Matcher()
+ .match(methodNode, context.getSuperClassName())) {
output.ignore(methodNode.instructions.getFirst(),
methodNode.instructions.getLast());
}
@@ -35,20 +36,11 @@ public final class PrivateEmptyNoArgConstructorFilter implements IFilter {
private static class Matcher extends AbstractMatcher {
private boolean match(final MethodNode methodNode,
final String superClassName) {
- cursor = methodNode.instructions.getFirst();
- skipNonOpcodes();
- if (cursor.getOpcode() != Opcodes.ALOAD
- || ((VarInsnNode) cursor).var != 0) {
- return false;
- }
- nextIs(Opcodes.INVOKESPECIAL);
- MethodInsnNode m = (MethodInsnNode) cursor;
- if (m != null && superClassName.equals(m.owner)
- && "<init>".equals(m.name) && ("()V").equals(m.desc)) {
- nextIs(Opcodes.RETURN);
- return cursor != null;
- }
- return false;
+ firstIsALoad0(methodNode);
+ nextIsInvoke(Opcodes.INVOKESPECIAL, superClassName,
+ CONSTRUCTOR_NAME, CONSTRUCTOR_DESC);
+ nextIs(Opcodes.RETURN);
+ return cursor != null;
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java
new file mode 100644
index 00000000..e0aba35d
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchEcjFilter.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.JumpInsnNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.LookupSwitchInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TableSwitchInsnNode;
+import org.objectweb.asm.tree.VarInsnNode;
+
+/**
+ * Filters code that is generated by ECJ for a <code>switch</code> statement
+ * with a <code>String</code>.
+ */
+public final class StringSwitchEcjFilter implements IFilter {
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ final Matcher matcher = new Matcher();
+ for (AbstractInsnNode i = methodNode.instructions
+ .getFirst(); i != null; i = i.getNext()) {
+ matcher.match(i, output);
+ }
+ }
+
+ private static class Matcher extends AbstractMatcher {
+ public void match(final AbstractInsnNode start,
+ final IFilterOutput output) {
+
+ if (Opcodes.ASTORE != start.getOpcode()) {
+ return;
+ }
+ cursor = start;
+ nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode",
+ "()I");
+ nextIsSwitch();
+ if (cursor == null) {
+ return;
+ }
+ vars.put("s", (VarInsnNode) start);
+
+ final AbstractInsnNode s = cursor;
+ final int hashCodes;
+ final LabelNode defaultLabel;
+ if (s.getOpcode() == Opcodes.LOOKUPSWITCH) {
+ final LookupSwitchInsnNode lookupSwitch = (LookupSwitchInsnNode) cursor;
+ defaultLabel = lookupSwitch.dflt;
+ hashCodes = lookupSwitch.labels.size();
+ } else {
+ final TableSwitchInsnNode tableSwitch = (TableSwitchInsnNode) cursor;
+ defaultLabel = tableSwitch.dflt;
+ hashCodes = tableSwitch.labels.size();
+ }
+
+ final Set<AbstractInsnNode> replacements = new HashSet<AbstractInsnNode>();
+ replacements.add(skipNonOpcodes(defaultLabel));
+
+ for (int i = 0; i < hashCodes; i++) {
+ while (true) {
+ nextIsVar(Opcodes.ALOAD, "s");
+ nextIs(Opcodes.LDC);
+ nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String",
+ "equals", "(Ljava/lang/Object;)Z");
+ // jump to case
+ nextIs(Opcodes.IFNE);
+ if (cursor == null) {
+ return;
+ }
+
+ replacements
+ .add(skipNonOpcodes(((JumpInsnNode) cursor).label));
+
+ if (cursor.getNext().getOpcode() == Opcodes.GOTO) {
+ // end of comparisons for same hashCode
+ // jump to default
+ nextIs(Opcodes.GOTO);
+ break;
+ } else if (cursor.getNext() == defaultLabel) {
+ break;
+ }
+ }
+ }
+
+ output.ignore(s.getNext(), cursor);
+ output.replaceBranches(s, replacements);
+ }
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java
index e1d7a1cc..3033d9bc 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/StringSwitchJavacFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -24,8 +24,8 @@ import org.objectweb.asm.tree.TableSwitchInsnNode;
*/
public final class StringSwitchJavacFilter implements IFilter {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
AbstractInsnNode i = methodNode.instructions.getFirst();
while (i != null) {
filter(i, output);
@@ -68,12 +68,14 @@ public final class StringSwitchJavacFilter implements IFilter {
// Even if expression is not a variable, its result will be
// precomputed before the previous two instructions:
nextIsVar(Opcodes.ALOAD, "s");
- nextIsInvokeVirtual("java/lang/String", "hashCode");
+ nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String", "hashCode",
+ "()I");
next();
while (true) {
nextIsVar(Opcodes.ALOAD, "s");
nextIs(Opcodes.LDC);
- nextIsInvokeVirtual("java/lang/String", "equals");
+ nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/String",
+ "equals", "(Ljava/lang/Object;)Z");
// jump to next comparison or second switch
nextIs(Opcodes.IFEQ);
// ICONST, BIPUSH or SIPUSH
@@ -91,7 +93,8 @@ public final class StringSwitchJavacFilter implements IFilter {
}
}
nextIsVar(Opcodes.ILOAD, "c");
- nextIs(Opcodes.TABLESWITCH);
+ // Can be TABLESWITCH or LOOKUPSWITCH depending on number of cases
+ nextIsSwitch();
return cursor != null;
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java
index 71ce0cfe..6341328f 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SynchronizedFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -21,9 +21,9 @@ import org.objectweb.asm.tree.TryCatchBlockNode;
*/
public final class SynchronizedFilter implements IFilter {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
- for (TryCatchBlockNode tryCatch : methodNode.tryCatchBlocks) {
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ for (final TryCatchBlockNode tryCatch : methodNode.tryCatchBlocks) {
if (tryCatch.type != null) {
continue;
}
@@ -67,7 +67,7 @@ public final class SynchronizedFilter implements IFilter {
nextIs(Opcodes.ALOAD);
nextIs(Opcodes.MONITOREXIT);
nextIs(Opcodes.ATHROW);
- return cursor != null;
+ return cursor != null;
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java
index afba0f00..69c4092a 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/SyntheticFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -19,13 +19,29 @@ import org.objectweb.asm.tree.MethodNode;
*/
public final class SyntheticFilter implements IFilter {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
- if ((methodNode.access & Opcodes.ACC_SYNTHETIC) != 0
- && !methodNode.name.startsWith("lambda$")) {
- output.ignore(methodNode.instructions.getFirst(),
- methodNode.instructions.getLast());
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ if ((methodNode.access & Opcodes.ACC_SYNTHETIC) == 0) {
+ return;
}
+
+ if (methodNode.name.startsWith("lambda$")) {
+ return;
+ }
+
+ if (KotlinGeneratedFilter.isKotlinClass(context)) {
+ if (KotlinDefaultArgumentsFilter
+ .isDefaultArgumentsMethodName(methodNode.name)) {
+ return;
+ }
+
+ if (KotlinCoroutineFilter.isLastArgumentContinuation(methodNode)) {
+ return;
+ }
+ }
+
+ output.ignore(methodNode.instructions.getFirst(),
+ methodNode.instructions.getLast());
}
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java
index c25d61ff..94dea561 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesEcjFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -27,13 +27,13 @@ import org.objectweb.asm.tree.TryCatchBlockNode;
*/
public final class TryWithResourcesEcjFilter implements IFilter {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
if (methodNode.tryCatchBlocks.isEmpty()) {
return;
}
final Matcher matcher = new Matcher(output);
- for (TryCatchBlockNode t : methodNode.tryCatchBlocks) {
+ for (final TryCatchBlockNode t : methodNode.tryCatchBlocks) {
if (t.type == null) {
matcher.start(t.handler);
if (!matcher.matchEcj()) {
@@ -200,7 +200,8 @@ public final class TryWithResourcesEcjFilter implements IFilter {
// "primaryExc.addSuppressed(suppressedExc)"
nextIsVar(Opcodes.ALOAD, "primaryExc");
nextIsVar(Opcodes.ALOAD, suppressedExc);
- nextIsInvokeVirtual("java/lang/Throwable", "addSuppressed");
+ nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable",
+ "addSuppressed", "(Ljava/lang/Throwable;)V");
nextIsLabel(endLabel);
return cursor != null;
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java
new file mode 100644
index 00000000..7a20f74f
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavac11Filter.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.analysis.filter;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TryCatchBlockNode;
+
+/**
+ * Filters code which is generated for try-with-resources statement by javac
+ * starting from version 11.
+ */
+public final class TryWithResourcesJavac11Filter implements IFilter {
+
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
+ if (methodNode.tryCatchBlocks.isEmpty()) {
+ return;
+ }
+ final Matcher matcher = new Matcher();
+ for (TryCatchBlockNode t : methodNode.tryCatchBlocks) {
+ if ("java/lang/Throwable".equals(t.type)) {
+ matcher.match(t.handler, output, true);
+ matcher.match(t.handler, output, false);
+ }
+ }
+ }
+
+ /**
+ * <pre>
+ * r = ...;
+ * try {
+ * ...
+ * } body-only-finally {
+ * if (r != null)
+ * r.close();
+ * } catch (Throwable primaryExc) {
+ * if (r != null)
+ * try {
+ * r.close();
+ * } catch (Throwable t) {
+ * primaryExc.addSuppressed(t);
+ * }
+ * throw primaryExc;
+ * }
+ * </pre>
+ *
+ * <code>null</code> check for resource is omitted when it is initialized
+ * using <code>new</code>
+ */
+ private class Matcher extends AbstractMatcher {
+ private boolean withNullCheck;
+
+ private String expectedOwner;
+
+ void match(final AbstractInsnNode start, final IFilterOutput output,
+ final boolean withNullCheck) {
+ this.withNullCheck = withNullCheck;
+ vars.clear();
+ expectedOwner = null;
+
+ cursor = start.getPrevious();
+ nextIsVar(Opcodes.ASTORE, "primaryExc");
+ nextIsJavacClose();
+ nextIs(Opcodes.GOTO);
+ nextIsVar(Opcodes.ASTORE, "t");
+ nextIsVar(Opcodes.ALOAD, "primaryExc");
+ nextIsVar(Opcodes.ALOAD, "t");
+ nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable",
+ "addSuppressed", "(Ljava/lang/Throwable;)V"); // primaryExc.addSuppressed(t)
+ nextIsVar(Opcodes.ALOAD, "primaryExc");
+ nextIs(Opcodes.ATHROW);
+ if (cursor == null) {
+ return;
+ }
+ final AbstractInsnNode end = cursor;
+
+ AbstractInsnNode s = start.getPrevious();
+ cursor = start.getPrevious();
+ while (!nextIsJavacClose()) {
+ s = s.getPrevious();
+ cursor = s;
+ if (cursor == null) {
+ return;
+ }
+ }
+ s = s.getNext();
+
+ final AbstractInsnNode m = cursor;
+ next();
+ if (cursor.getOpcode() != Opcodes.GOTO) {
+ cursor = m;
+ }
+
+ output.ignore(s, cursor);
+ output.ignore(start, end);
+ }
+
+ private boolean nextIsJavacClose() {
+ if (withNullCheck) {
+ nextIsVar(Opcodes.ALOAD, "r");
+ nextIs(Opcodes.IFNULL);
+ }
+ nextIsClose();
+ return cursor != null;
+ }
+
+ private void nextIsClose() {
+ nextIsVar(Opcodes.ALOAD, "r");
+ next();
+ if (cursor == null) {
+ return;
+ }
+ if (cursor.getOpcode() != Opcodes.INVOKEINTERFACE
+ && cursor.getOpcode() != Opcodes.INVOKEVIRTUAL) {
+ cursor = null;
+ return;
+ }
+ final MethodInsnNode m = (MethodInsnNode) cursor;
+ if (!"close".equals(m.name) || !"()V".equals(m.desc)) {
+ cursor = null;
+ return;
+ }
+ final String actual = m.owner;
+ if (expectedOwner == null) {
+ expectedOwner = actual;
+ } else if (!expectedOwner.equals(actual)) {
+ cursor = null;
+ }
+ }
+
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java
index f3b33bc9..23ecb0e6 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/analysis/filter/TryWithResourcesJavacFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -18,19 +18,21 @@ import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
/**
- * Filters code that javac generates for try-with-resources statement.
+ * Filters code which is generated for try-with-resources statement by javac
+ * versions from 7 to 10.
*/
public final class TryWithResourcesJavacFilter implements IFilter {
- public void filter(final String className, final String superClassName,
- final MethodNode methodNode, final IFilterOutput output) {
+ public void filter(final MethodNode methodNode,
+ final IFilterContext context, final IFilterOutput output) {
if (methodNode.tryCatchBlocks.isEmpty()) {
return;
}
final Matcher matcher = new Matcher(output);
- for (TryCatchBlockNode t : methodNode.tryCatchBlocks) {
+ for (final TryCatchBlockNode t : methodNode.tryCatchBlocks) {
if ("java/lang/Throwable".equals(t.type)) {
- for (Matcher.JavacPattern p : Matcher.JavacPattern.values()) {
+ for (final Matcher.JavacPattern p : Matcher.JavacPattern
+ .values()) {
matcher.start(t.handler);
if (matcher.matchJavac(p)) {
break;
@@ -195,7 +197,7 @@ public final class TryWithResourcesJavacFilter implements IFilter {
final MethodInsnNode m = (MethodInsnNode) cursor;
if ("$closeResource".equals(m.name)
&& "(Ljava/lang/Throwable;Ljava/lang/AutoCloseable;)V"
- .equals(m.desc)) {
+ .equals(m.desc)) {
return true;
}
cursor = null;
@@ -214,7 +216,8 @@ public final class TryWithResourcesJavacFilter implements IFilter {
// "primaryExc.addSuppressed(t)"
nextIsVar(Opcodes.ALOAD, "primaryExc");
nextIsVar(Opcodes.ALOAD, ctx + "t");
- nextIsInvokeVirtual("java/lang/Throwable", "addSuppressed");
+ nextIsInvoke(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable",
+ "addSuppressed", "(Ljava/lang/Throwable;)V");
nextIs(Opcodes.GOTO);
// "r.close()"
nextIsClose();
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java b/org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java
index 974269b9..620a46f0 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/data/CRC64.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataInput.java b/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataInput.java
index 082c1790..945b2b64 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataInput.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataInput.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataOutput.java b/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataOutput.java
index 7852102a..4d230f8e 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataOutput.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/data/CompactDataOutput.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java
index 11ce434d..876a1351 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesAdapter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesVisitor.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesVisitor.java
index fc3b979b..54817e80 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesVisitor.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/ClassProbesVisitor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/FrameSnapshot.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/FrameSnapshot.java
index 94e24cc9..a0c7449f 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/FrameSnapshot.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/FrameSnapshot.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java
index 09e99064..6079f443 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/IFrame.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -24,6 +24,6 @@ public interface IFrame {
* @param mv
* method visitor to emit frame event to
*/
- void accept(final MethodVisitor mv);
+ void accept(MethodVisitor mv);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/IProbeIdGenerator.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/IProbeIdGenerator.java
index 4baa4f07..6f3f1977 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/IProbeIdGenerator.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/IProbeIdGenerator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java
deleted file mode 100644
index d1e7cbeb..00000000
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/Instruction.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Marc R. Hoffmann - initial API and implementation
- *
- *******************************************************************************/
-package org.jacoco.core.internal.flow;
-
-import org.objectweb.asm.tree.AbstractInsnNode;
-
-import java.util.BitSet;
-
-/**
- * Representation of a byte code instruction for analysis. Internally used for
- * analysis.
- */
-public class Instruction {
-
- private final AbstractInsnNode node;
-
- private final int line;
-
- private int branches;
-
- private final BitSet coveredBranches;
-
- private Instruction predecessor;
-
- private int predecessorBranch;
-
- /**
- * New instruction at the given line.
- *
- * @param node
- * corresponding node
- * @param line
- * source line this instruction belongs to
- */
- public Instruction(final AbstractInsnNode node, final int line) {
- this.node = node;
- this.line = line;
- this.branches = 0;
- this.coveredBranches = new BitSet();
- }
-
- /**
- * @return corresponding node
- */
- public AbstractInsnNode getNode() {
- return node;
- }
-
- /**
- * Adds an branch to this instruction.
- */
- public void addBranch() {
- branches++;
- }
-
- /**
- * Sets the given instruction as a predecessor of this instruction and adds
- * branch to the predecessor. Probes are inserted in a way that every
- * instruction has at most one direct predecessor.
- *
- * @see #addBranch()
- * @param predecessor
- * predecessor instruction
- * @param branch
- * branch number in predecessor that should be marked as covered
- * when this instruction marked as covered
- */
- public void setPredecessor(final Instruction predecessor,
- final int branch) {
- this.predecessor = predecessor;
- predecessor.addBranch();
- this.predecessorBranch = branch;
- }
-
- /**
- * Marks one branch of this instruction as covered. Also recursively marks
- * all predecessor instructions as covered if this is the first covered
- * branch.
- *
- * @param branch
- * branch number to mark as covered
- */
- public void setCovered(final int branch) {
- Instruction i = this;
- int b = branch;
- while (i != null) {
- if (!i.coveredBranches.isEmpty()) {
- i.coveredBranches.set(b);
- break;
- }
- i.coveredBranches.set(b);
- b = i.predecessorBranch;
- i = i.predecessor;
- }
- }
-
- /**
- * Returns the source line this instruction belongs to.
- *
- * @return corresponding source line
- */
- public int getLine() {
- return line;
- }
-
- /**
- * Returns the total number of branches starting from this instruction.
- *
- * @return total number of branches
- */
- public int getBranches() {
- return branches;
- }
-
- /**
- * Returns the number of covered branches starting from this instruction.
- *
- * @return number of covered branches
- */
- public int getCoveredBranches() {
- return coveredBranches.cardinality();
- }
-
- /**
- * Merges information about covered branches of given instruction into this
- * instruction.
- *
- * @param instruction
- * instruction from which to merge
- */
- public void merge(Instruction instruction) {
- this.coveredBranches.or(instruction.coveredBranches);
- }
-
- @Override
- public String toString() {
- return coveredBranches.toString();
- }
-
-}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java
index f5b354f5..0f0e4d33 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelFlowAnalyzer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java
index 1b65ae2a..85dc1d81 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/LabelInfo.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,6 +11,7 @@
*******************************************************************************/
package org.jacoco.core.internal.flow;
+import org.jacoco.core.internal.analysis.Instruction;
import org.objectweb.asm.Label;
/**
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java
index 867ff93a..40e20a3e 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesAdapter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java
index 7514193b..75e63555 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodProbesVisitor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodSanitizer.java b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodSanitizer.java
index f6aa2e9d..92b08947 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodSanitizer.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/flow/MethodSanitizer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassFieldProbeArrayStrategy.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassFieldProbeArrayStrategy.java
index e8051358..950be683 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassFieldProbeArrayStrategy.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassFieldProbeArrayStrategy.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
index 1117975f..7d5e9759 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ClassInstrumenter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/CondyProbeArrayStrategy.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/CondyProbeArrayStrategy.java
new file mode 100644
index 00000000..ca2fb60d
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/CondyProbeArrayStrategy.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.internal.instr;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ConstantDynamic;
+import org.jacoco.core.runtime.IExecutionDataAccessorGenerator;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * This strategy for Java 11+ class files uses {@link ConstantDynamic} to hold
+ * the probe array and adds bootstrap method requesting the probe array from the
+ * runtime.
+ */
+public class CondyProbeArrayStrategy implements IProbeArrayStrategy {
+
+ /**
+ * Descriptor of the bootstrap method.
+ */
+ public static final String B_DESC = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)[Z";
+
+ private final String className;
+
+ private final boolean isInterface;
+
+ private final long classId;
+
+ private final IExecutionDataAccessorGenerator accessorGenerator;
+
+ CondyProbeArrayStrategy(final String className, final boolean isInterface,
+ final long classId,
+ final IExecutionDataAccessorGenerator accessorGenerator) {
+ this.className = className;
+ this.isInterface = isInterface;
+ this.classId = classId;
+ this.accessorGenerator = accessorGenerator;
+ }
+
+ public int storeInstance(final MethodVisitor mv, final boolean clinit,
+ final int variable) {
+ final Handle bootstrapMethod = new Handle(Opcodes.H_INVOKESTATIC,
+ className, InstrSupport.INITMETHOD_NAME, B_DESC, isInterface);
+ // As a workaround for https://bugs.openjdk.java.net/browse/JDK-8216970
+ // constant should have type Object
+ mv.visitLdcInsn(new ConstantDynamic(InstrSupport.DATAFIELD_NAME,
+ "Ljava/lang/Object;", bootstrapMethod));
+ mv.visitTypeInsn(Opcodes.CHECKCAST, "[Z");
+ mv.visitVarInsn(Opcodes.ASTORE, variable);
+ return 1;
+ }
+
+ public void addMembers(final ClassVisitor cv, final int probeCount) {
+ final MethodVisitor mv = cv.visitMethod(InstrSupport.INITMETHOD_ACC,
+ InstrSupport.INITMETHOD_NAME, B_DESC, null, null);
+ final int maxStack = accessorGenerator.generateDataAccessor(classId,
+ className, probeCount, mv);
+ mv.visitInsn(Opcodes.ARETURN);
+ mv.visitMaxs(maxStack, 3);
+ mv.visitEnd();
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/DuplicateFrameEliminator.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/DuplicateFrameEliminator.java
index 34707752..bc3e54bf 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/DuplicateFrameEliminator.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/DuplicateFrameEliminator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java
index e9ae4b6d..5fe0cdca 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeArrayStrategy.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -39,7 +39,7 @@ public interface IProbeArrayStrategy {
* called after all original members of the class has been processed.
*
* @param cv
- * visitor to create fields and classes
+ * visitor to create fields and methods
* @param probeCount
* total number of probes required for this class
*/
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserter.java
index e6c8dc59..2f8dab61 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/IProbeInserter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -23,6 +23,6 @@ interface IProbeInserter {
* @param id
* id of the probe to insert
*/
- public void insertProbe(final int id);
+ void insertProbe(int id);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java
index b6632c62..85e83a3a 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,6 +13,7 @@ package org.jacoco.core.internal.instr;
import static java.lang.String.format;
+import org.objectweb.asm.ClassReader;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -25,7 +26,7 @@ public final class InstrSupport {
}
/** ASM API version */
- public static final int ASM_API_VERSION = Opcodes.ASM6;
+ public static final int ASM_API_VERSION = Opcodes.ASM7;
// === Data Field ===
@@ -158,6 +159,66 @@ public final class InstrSupport {
static final int CLINIT_ACC = Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC;
/**
+ * Gets major version number from given bytes of class (unsigned two bytes
+ * at offset 6).
+ *
+ * @param b
+ * bytes of class
+ * @return major version of bytecode
+ * @see <a href=
+ * "https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.1">Java
+ * Virtual Machine Specification §4 The class File Format</a>
+ * @see #setMajorVersion(int, byte[])
+ * @see #getMajorVersion(ClassReader)
+ */
+ public static int getMajorVersion(final byte[] b) {
+ return ((b[6] & 0xFF) << 8) | (b[7] & 0xFF);
+ }
+
+ /**
+ * Sets major version number in given bytes of class (unsigned two bytes at
+ * offset 6).
+ *
+ * @param majorVersion
+ * major version of bytecode to set
+ * @param b
+ * bytes of class
+ * @see #getMajorVersion(byte[])
+ */
+ public static void setMajorVersion(final int majorVersion, final byte[] b) {
+ b[6] = (byte) (majorVersion >>> 8);
+ b[7] = (byte) majorVersion;
+ }
+
+ /**
+ * Gets major version number from given {@link ClassReader}.
+ *
+ * @param reader
+ * reader to get information about the class
+ * @return major version of bytecode
+ * @see ClassReader#ClassReader(byte[], int, int)
+ * @see #getMajorVersion(byte[])
+ */
+ public static int getMajorVersion(final ClassReader reader) {
+ // relative to the beginning of constant pool because ASM provides API
+ // to construct ClassReader which reads from the middle of array
+ final int firstConstantPoolEntryOffset = reader.getItem(1) - 1;
+ return reader.readUnsignedShort(firstConstantPoolEntryOffset - 4);
+ }
+
+ /**
+ * Determines whether the given class file version requires stackmap frames.
+ *
+ * @param version
+ * class file version
+ * @return <code>true</code> if frames are required
+ */
+ public static boolean needsFrames(final int version) {
+ // consider major version only (due to 1.1 anomaly)
+ return (version & 0xFFFF) >= Opcodes.V1_6;
+ }
+
+ /**
* Ensures that the given member does not correspond to a internal member
* created by the instrumentation process. This would mean that the class is
* already instrumented.
@@ -174,7 +235,8 @@ public final class InstrSupport {
final String owner) throws IllegalStateException {
if (member.equals(DATAFIELD_NAME) || member.equals(INITMETHOD_NAME)) {
throw new IllegalStateException(format(
- "Class %s is already instrumented.", owner));
+ "Cannot process instrumented class %s. Please supply original non-instrumented classes.",
+ owner));
}
}
@@ -200,4 +262,23 @@ public final class InstrSupport {
}
}
+ /**
+ * Creates a {@link ClassReader} instance for given bytes of class even if
+ * its version not yet supported by ASM.
+ *
+ * @param b
+ * bytes of class
+ * @return {@link ClassReader}
+ */
+ public static ClassReader classReaderFor(final byte[] b) {
+ final int originalVersion = getMajorVersion(b);
+ if (originalVersion == Opcodes.V12 + 1) {
+ // temporarily downgrade version to bypass check in ASM
+ setMajorVersion(Opcodes.V12, b);
+ }
+ final ClassReader classReader = new ClassReader(b);
+ setMajorVersion(originalVersion, b);
+ return classReader;
+ }
+
}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InterfaceFieldProbeArrayStrategy.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InterfaceFieldProbeArrayStrategy.java
index 9325dddc..bf855fea 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InterfaceFieldProbeArrayStrategy.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InterfaceFieldProbeArrayStrategy.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/LocalProbeArrayStrategy.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/LocalProbeArrayStrategy.java
index f9a506ca..67068ed7 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/LocalProbeArrayStrategy.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/LocalProbeArrayStrategy.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -50,4 +50,4 @@ class LocalProbeArrayStrategy implements IProbeArrayStrategy {
// nothing to do
}
-} \ No newline at end of file
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java
index 472ffb7a..396368b5 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/MethodInstrumenter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/NoneProbeArrayStrategy.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/NoneProbeArrayStrategy.java
index 790a34a2..b3a4186f 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/NoneProbeArrayStrategy.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/NoneProbeArrayStrategy.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -29,4 +29,4 @@ class NoneProbeArrayStrategy implements IProbeArrayStrategy {
// nothing to do
}
-} \ No newline at end of file
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java
index 349840b0..d5756b7f 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeArrayStrategyFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -11,7 +11,6 @@
*******************************************************************************/
package org.jacoco.core.internal.instr;
-import org.jacoco.core.internal.data.CRC64;
import org.jacoco.core.internal.flow.ClassProbesAdapter;
import org.jacoco.core.runtime.IExecutionDataAccessorGenerator;
import org.objectweb.asm.ClassReader;
@@ -30,26 +29,31 @@ public final class ProbeArrayStrategyFactory {
* Creates a suitable strategy instance for the class described by the given
* reader. Created instance must be used only to process a class or
* interface for which it has been created and must be used only once.
- *
+ *
+ * @param classId
+ * class identifier
* @param reader
* reader to get information about the class
* @param accessorGenerator
* accessor to the coverage runtime
* @return strategy instance
*/
- public static IProbeArrayStrategy createFor(final ClassReader reader,
+ public static IProbeArrayStrategy createFor(final long classId,
+ final ClassReader reader,
final IExecutionDataAccessorGenerator accessorGenerator) {
final String className = reader.getClassName();
- final int version = getVersion(reader);
- final long classId = CRC64.classId(reader.b);
- final boolean withFrames = version >= Opcodes.V1_6;
+ final int version = InstrSupport.getMajorVersion(reader);
if (isInterfaceOrModule(reader)) {
final ProbeCounter counter = getProbeCounter(reader);
if (counter.getCount() == 0) {
return new NoneProbeArrayStrategy();
}
+ if (version >= Opcodes.V11 && counter.hasMethods()) {
+ return new CondyProbeArrayStrategy(className, true, classId,
+ accessorGenerator);
+ }
if (version >= Opcodes.V1_8 && counter.hasMethods()) {
return new InterfaceFieldProbeArrayStrategy(className, classId,
counter.getCount(), accessorGenerator);
@@ -58,8 +62,12 @@ public final class ProbeArrayStrategyFactory {
counter.getCount(), accessorGenerator);
}
} else {
+ if (version >= Opcodes.V11) {
+ return new CondyProbeArrayStrategy(className, false, classId,
+ accessorGenerator);
+ }
return new ClassFieldProbeArrayStrategy(className, classId,
- withFrames, accessorGenerator);
+ InstrSupport.needsFrames(version), accessorGenerator);
}
}
@@ -68,10 +76,6 @@ public final class ProbeArrayStrategyFactory {
& (Opcodes.ACC_INTERFACE | Opcodes.ACC_MODULE)) != 0;
}
- private static int getVersion(final ClassReader reader) {
- return reader.readShort(6);
- }
-
private static ProbeCounter getProbeCounter(final ClassReader reader) {
final ProbeCounter counter = new ProbeCounter();
reader.accept(new ClassProbesAdapter(counter, false), 0);
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeCounter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeCounter.java
index 2a323151..de223265 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeCounter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeCounter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java
index 61657141..63fbf765 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/ProbeInserter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/SignatureRemover.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/SignatureRemover.java
index 29995ee4..06994c0d 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/SignatureRemover.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/SignatureRemover.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/package-info.java b/org.jacoco.core/src/org/jacoco/core/package-info.java
index 0af292d4..84ebdf87 100644
--- a/org.jacoco.core/src/org/jacoco/core/package-info.java
+++ b/org.jacoco.core/src/org/jacoco/core/package-info.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,4 +13,4 @@
/**
* Meta information about JaCoCo.
*/
-package org.jacoco.core; \ No newline at end of file
+package org.jacoco.core;
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java
index 9c41d6cc..388e3e4f 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/AbstractRuntime.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
index 46c108e3..60f03c0a 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/AgentOptions.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java b/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java
index 1493afb7..1f7fafc2 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/CommandLineSupport.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -54,13 +54,13 @@ final class CommandLineSupport {
*/
static String quote(final List<String> args) {
final StringBuilder result = new StringBuilder();
- boolean seperate = false;
+ boolean separate = false;
for (final String arg : args) {
- if (seperate) {
+ if (separate) {
result.append(BLANK);
}
result.append(quote(arg));
- seperate = true;
+ separate = true;
}
return result.toString();
}
@@ -70,7 +70,7 @@ final class CommandLineSupport {
* present.
*
* @param commandline
- * combinded command line
+ * combined command line
* @return list of arguments
*/
static List<String> split(final String commandline) {
@@ -79,11 +79,11 @@ final class CommandLineSupport {
}
final List<String> args = new ArrayList<String>();
final StringBuilder current = new StringBuilder();
- int mode = M_STRIPWHITESPACE;
+ int mode = M_STRIP_WHITESPACE;
int endChar = BLANK;
for (final char c : commandline.toCharArray()) {
switch (mode) {
- case M_STRIPWHITESPACE:
+ case M_STRIP_WHITESPACE:
if (!Character.isWhitespace(c)) {
if (c == QUOTE) {
endChar = QUOTE;
@@ -91,13 +91,13 @@ final class CommandLineSupport {
current.append(c);
endChar = BLANK;
}
- mode = M_PARSEARGUMENT;
+ mode = M_PARSE_ARGUMENT;
}
break;
- case M_PARSEARGUMENT:
+ case M_PARSE_ARGUMENT:
if (c == endChar) {
addArgument(args, current);
- mode = M_STRIPWHITESPACE;
+ mode = M_STRIP_WHITESPACE;
} else if (c == SLASH) {
current.append(SLASH);
mode = M_ESCAPED;
@@ -110,11 +110,11 @@ final class CommandLineSupport {
current.setCharAt(current.length() - 1, c);
} else if (c == endChar) {
addArgument(args, current);
- mode = M_STRIPWHITESPACE;
+ mode = M_STRIP_WHITESPACE;
} else {
current.append(c);
}
- mode = M_PARSEARGUMENT;
+ mode = M_PARSE_ARGUMENT;
break;
}
}
@@ -130,8 +130,8 @@ final class CommandLineSupport {
}
}
- private static final int M_STRIPWHITESPACE = 0;
- private static final int M_PARSEARGUMENT = 1;
+ private static final int M_STRIP_WHITESPACE = 0;
+ private static final int M_PARSE_ARGUMENT = 1;
private static final int M_ESCAPED = 2;
private CommandLineSupport() {
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java b/org.jacoco.core/src/org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java
index 00783121..83df5744 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/IExecutionDataAccessorGenerator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -45,7 +45,7 @@ public interface IExecutionDataAccessorGenerator {
* @return additional stack size required by the implementation, including
* the instance pushed to the stack
*/
- public int generateDataAccessor(final long classid, final String classname,
- final int probecount, MethodVisitor mv);
+ int generateDataAccessor(long classid, String classname, int probecount,
+ MethodVisitor mv);
}
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/IRemoteCommandVisitor.java b/org.jacoco.core/src/org/jacoco/core/runtime/IRemoteCommandVisitor.java
index c4b12f1c..9057a4e4 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/IRemoteCommandVisitor.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/IRemoteCommandVisitor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -28,7 +28,6 @@ public interface IRemoteCommandVisitor {
* @throws IOException
* in case of problems with the remote connection
*/
- public void visitDumpCommand(final boolean dump, final boolean reset)
- throws IOException;
+ void visitDumpCommand(boolean dump, boolean reset) throws IOException;
}
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java
index 9eee8fba..ea055632 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/IRuntime.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -26,12 +26,12 @@ public interface IRuntime extends IExecutionDataAccessorGenerator {
* @throws Exception
* any internal problem during startup
*/
- public void startup(RuntimeData data) throws Exception;
+ void startup(RuntimeData data) throws Exception;
/**
* Allows the coverage runtime to cleanup internals. This class should be
* called when classes instrumented for this runtime are not used any more.
*/
- public void shutdown();
+ void shutdown();
}
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/InjectedClassRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/InjectedClassRuntime.java
new file mode 100644
index 00000000..ee7aa1ac
--- /dev/null
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/InjectedClassRuntime.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Evgeny Mandrikov - initial API and implementation
+ *
+ *******************************************************************************/
+package org.jacoco.core.runtime;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * {@link IRuntime} which defines a new class using
+ * {@code java.lang.invoke.MethodHandles.Lookup.defineClass} introduced in Java
+ * 9. Module where class will be defined must be opened to at least module of
+ * this class.
+ */
+public class InjectedClassRuntime extends AbstractRuntime {
+
+ private static final String FIELD_NAME = "data";
+
+ private static final String FIELD_TYPE = "Ljava/lang/Object;";
+
+ private final Class<?> locator;
+
+ private final String injectedClassName;
+
+ /**
+ * Creates a new runtime which will define a class to the same class loader
+ * and in the same package and protection domain as given class.
+ *
+ * @param locator
+ * class to identify the target class loader and package
+ * @param simpleClassName
+ * simple name of the class to be defined
+ */
+ public InjectedClassRuntime(final Class<?> locator,
+ final String simpleClassName) {
+ this.locator = locator;
+ this.injectedClassName = locator.getPackage().getName().replace('.',
+ '/') + '/' + simpleClassName;
+ }
+
+ @Override
+ public void startup(final RuntimeData data) throws Exception {
+ super.startup(data);
+ Lookup //
+ .privateLookupIn(locator, Lookup.lookup()) //
+ .defineClass(createClass(injectedClassName)) //
+ .getField(FIELD_NAME) //
+ .set(null, data);
+ }
+
+ public void shutdown() {
+ // nothing to do
+ }
+
+ public int generateDataAccessor(final long classid, final String classname,
+ final int probecount, final MethodVisitor mv) {
+ mv.visitFieldInsn(Opcodes.GETSTATIC, injectedClassName, FIELD_NAME,
+ FIELD_TYPE);
+
+ RuntimeData.generateAccessCall(classid, classname, probecount, mv);
+
+ return 6;
+ }
+
+ private static byte[] createClass(final String name) {
+ final ClassWriter cw = new ClassWriter(0);
+ cw.visit(Opcodes.V9, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_PUBLIC,
+ name.replace('.', '/'), null, "java/lang/Object", null);
+ cw.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, FIELD_NAME,
+ FIELD_TYPE, null, null);
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ /**
+ * Provides access to classes {@code java.lang.invoke.MethodHandles} and
+ * {@code java.lang.invoke.MethodHandles.Lookup} introduced in Java 8.
+ */
+ private static class Lookup {
+
+ private final Object instance;
+
+ private Lookup(final Object instance) {
+ this.instance = instance;
+ }
+
+ /**
+ * @return a lookup object for the caller of this method
+ */
+ static Lookup lookup() throws Exception {
+ return new Lookup(Class //
+ .forName("java.lang.invoke.MethodHandles") //
+ .getMethod("lookup") //
+ .invoke(null));
+ }
+
+ /**
+ * See corresponding method introduced in Java 9.
+ *
+ * @param targetClass
+ * the target class
+ * @param lookup
+ * the caller lookup object
+ * @return a lookup object for the target class, with private access
+ */
+ static Lookup privateLookupIn(final Class<?> targetClass,
+ final Lookup lookup) throws Exception {
+ return new Lookup(Class //
+ .forName("java.lang.invoke.MethodHandles") //
+ .getMethod("privateLookupIn", Class.class,
+ Class.forName(
+ "java.lang.invoke.MethodHandles$Lookup")) //
+ .invoke(null, targetClass, lookup.instance));
+ }
+
+ /**
+ * See corresponding method introduced in Java 9.
+ *
+ * @param bytes
+ * the class bytes
+ * @return class
+ */
+ Class<?> defineClass(final byte[] bytes) throws Exception {
+ return (Class<?>) Class //
+ .forName("java.lang.invoke.MethodHandles$Lookup")
+ .getMethod("defineClass", byte[].class)
+ .invoke(this.instance, new Object[] { bytes });
+ }
+
+ }
+
+}
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java
index 50cc7d70..72553956 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/LoggerRuntime.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java
index 6d31358f..5f2cc497 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/ModifiedSystemClassRuntime.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -114,7 +114,7 @@ public class ModifiedSystemClassRuntime extends AbstractRuntime {
* @return new runtime instance
*
* @throws ClassNotFoundException
- * id the given class can not be found
+ * if the given class can not be found
*/
public static IRuntime createFor(final Instrumentation inst,
final String className, final String accessFieldName)
@@ -153,7 +153,7 @@ public class ModifiedSystemClassRuntime extends AbstractRuntime {
*/
public static byte[] instrument(final byte[] source,
final String accessFieldName) {
- final ClassReader reader = new ClassReader(source);
+ final ClassReader reader = InstrSupport.classReaderFor(source);
final ClassWriter writer = new ClassWriter(reader, 0);
reader.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, writer) {
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java b/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java
index 4201c719..af6671ee 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/OfflineInstrumentationAccessGenerator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlReader.java b/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlReader.java
index b55c4ecd..46fb6d2c 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlReader.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlReader.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlWriter.java b/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlWriter.java
index f6a36930..8534471f 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlWriter.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/RemoteControlWriter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java b/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java
index 74a51dcb..afb5b7f3 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/RuntimeData.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/SystemPropertiesRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/SystemPropertiesRuntime.java
index 5e86c9b6..d7c338c8 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/SystemPropertiesRuntime.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/SystemPropertiesRuntime.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/URLStreamHandlerRuntime.java b/org.jacoco.core/src/org/jacoco/core/runtime/URLStreamHandlerRuntime.java
index afce7246..55f9c874 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/URLStreamHandlerRuntime.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/URLStreamHandlerRuntime.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java b/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java
index 2b52d4b8..91feaa66 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/WildcardMatcher.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -14,9 +14,10 @@ package org.jacoco.core.runtime;
import java.util.regex.Pattern;
/**
- * Matches strings against <code>?</code>/<code>*</code> wildcard expressions.
- * Multiple expressions can be separated with a colon (:). In this case the
- * expression matches if at least one part matches.
+ * Matches strings against glob like wildcard expressions where <code>?</code>
+ * matches any single character and <code>*</code> matches any number of any
+ * character. Multiple expressions can be separated with a colon (:). In this
+ * case the expression matches if at least one part matches.
*/
public class WildcardMatcher {
@@ -47,7 +48,7 @@ public class WildcardMatcher {
for (final char c : expression.toCharArray()) {
switch (c) {
case '?':
- regex.append(".?");
+ regex.append(".");
break;
case '*':
regex.append(".*");
diff --git a/org.jacoco.core/src/org/jacoco/core/runtime/package-info.java b/org.jacoco.core/src/org/jacoco/core/runtime/package-info.java
index 127b7a22..1ac7cccb 100644
--- a/org.jacoco.core/src/org/jacoco/core/runtime/package-info.java
+++ b/org.jacoco.core/src/org/jacoco/core/runtime/package-info.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -13,4 +13,4 @@
/**
* Runtime control and execution data collection.
*/
-package org.jacoco.core.runtime; \ No newline at end of file
+package org.jacoco.core.runtime;
diff --git a/org.jacoco.core/src/org/jacoco/core/tools/ExecDumpClient.java b/org.jacoco.core/src/org/jacoco/core/tools/ExecDumpClient.java
index c6a8007e..35617b49 100644
--- a/org.jacoco.core/src/org/jacoco/core/tools/ExecDumpClient.java
+++ b/org.jacoco.core/src/org/jacoco/core/tools/ExecDumpClient.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/tools/ExecFileLoader.java b/org.jacoco.core/src/org/jacoco/core/tools/ExecFileLoader.java
index c5c4555d..cf7b2e56 100644
--- a/org.jacoco.core/src/org/jacoco/core/tools/ExecFileLoader.java
+++ b/org.jacoco.core/src/org/jacoco/core/tools/ExecFileLoader.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
diff --git a/org.jacoco.core/src/org/jacoco/core/tools/package-info.java b/org.jacoco.core/src/org/jacoco/core/tools/package-info.java
index 7aa7e9f7..c35c5f9a 100644
--- a/org.jacoco.core/src/org/jacoco/core/tools/package-info.java
+++ b/org.jacoco.core/src/org/jacoco/core/tools/package-info.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
+ * Copyright (c) 2009, 2019 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -14,4 +14,4 @@
* Collection of tools build on top of the JaCoCo core APIs. The tools offer
* more high-level functionality useful for integrating JaCoCo.
*/
-package org.jacoco.core.tools; \ No newline at end of file
+package org.jacoco.core.tools;