aboutsummaryrefslogtreecommitdiffstats
path: root/org.jacoco.core/src/org/jacoco/core
diff options
context:
space:
mode:
Diffstat (limited to 'org.jacoco.core/src/org/jacoco/core')
-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
125 files changed, 2742 insertions, 877 deletions
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;