Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Fixes #727 Use ByteBuddy to instrument classes instead Javassist: imp…
…lement suppress constructor Fix code style issues
- Loading branch information
Showing
with
2,192 additions
and 418 deletions.
- +1 −1 config/checkstyle/checkstyle.xml
- +1 −0 gradle/java-module.gradle
- +1 −0 gradle/release/fullJars.gradle
- +4 −0 powermock-core/src/main/java/org/powermock/core/MockGateway.java
- +78 −0 powermock-core/src/main/java/org/powermock/core/bytebuddy/ConditionalStateStackManipulation.java
- +143 −0 powermock-core/src/main/java/org/powermock/core/bytebuddy/Frame.java
- +76 −0 powermock-core/src/main/java/org/powermock/core/bytebuddy/MaxLocalsExtractor.java
- +44 −0 powermock-core/src/main/java/org/powermock/core/bytebuddy/MethodMaxLocals.java
- +146 −0 powermock-core/src/main/java/org/powermock/core/bytebuddy/MockGetawayCall.java
- +99 −0 powermock-core/src/main/java/org/powermock/core/bytebuddy/PrimitiveBoxing.java
- +60 −0 powermock-core/src/main/java/org/powermock/core/bytebuddy/Variable.java
- +26 −37 powermock-core/src/main/java/org/powermock/core/classloader/DeferSupportingClassLoader.java
- +5 −3 powermock-core/src/main/java/org/powermock/core/classloader/MockClassLoader.java
- +19 −0 powermock-core/src/main/java/org/powermock/core/classloader/MockClassLoaderConfiguration.java
- +17 −7 powermock-core/src/main/java/org/powermock/core/classloader/bytebuddy/ByteBuddyMockClassLoader.java
- +5 −7 powermock-core/src/main/java/org/powermock/core/classloader/javassist/JavassistMockClassLoader.java
- +34 −0 powermock-core/src/main/java/org/powermock/core/transformers/ForTestClass.java
- +128 −0 powermock-core/src/main/java/org/powermock/core/transformers/TestClassTransformer.java
- +39 −3 powermock-core/src/main/java/org/powermock/core/transformers/TransformStrategy.java
- +65 −0 ...src/main/java/org/powermock/core/transformers/bytebuddy/ByteBuddyMockTransformerChainFactory.java
- +50 −0 ...re/src/main/java/org/powermock/core/transformers/bytebuddy/ClassFinalModifierMockTransformer.java
- +187 −0 ...-core/src/main/java/org/powermock/core/transformers/bytebuddy/ConstructorCallMockTransformer.java
- +4 −52 .../src/main/java/org/powermock/core/transformers/bytebuddy/ConstructorModifiersMockTransformer.java
- +0 −122 ...k-core/src/main/java/org/powermock/core/transformers/bytebuddy/FinalModifiersMockTransformer.java
- +44 −0 ...ore/src/main/java/org/powermock/core/transformers/bytebuddy/StaticFinalFieldsMockTransformer.java
- +0 −2 ...ore/src/main/java/org/powermock/core/transformers/bytebuddy/StaticInitializerMockTransformer.java
- +257 −0 ...va/org/powermock/core/transformers/bytebuddy/constructor/ConstructorCallMethodVisitorWrapper.java
- +1 −2 powermock-core/src/main/java/org/powermock/core/transformers/bytebuddy/support/ByteBuddyClass.java
- +6 −4 ...re/src/main/java/org/powermock/core/transformers/javassist/AbstractJavaAssistMockTransformer.java
- +7 −4 ...rmock-core/src/main/java/org/powermock/core/transformers/javassist/InstrumentMockTransformer.java
- +15 −101 ...ock/core/transformers/javassist/{TestClassTransformer.java → JavaAssistTestClassTransformer.java}
- +0 −3 ...c/main/java/org/powermock/core/transformers/javassist/StaticFinalNativeMethodMockTransformer.java
- +5 −3 ...re/src/main/java/org/powermock/core/transformers/javassist/support/PowerMockExpressionEditor.java
- +4 −4 powermock-core/src/main/java/org/powermock/tests/utils/impl/AbstractCommonTestSuiteChunkerImpl.java
- +1 −1 powermock-core/src/main/java/org/powermock/tests/utils/impl/MockClassLoaderFactory.java
- +2 −1 powermock-core/src/test/java/org/powermock/core/classloader/MockClassLoaderTest.java
- +27 −2 powermock-core/src/test/java/org/powermock/core/test/ClassLoaderTestHelper.java
- +5 −0 powermock-core/src/test/java/org/powermock/core/test/MockClassLoaderFactory.java
- +7 −1 powermock-core/src/test/java/org/powermock/core/transformers/AbstractBaseMockTransformerTest.java
- +3 −4 ...ock-core/src/test/java/org/powermock/core/transformers/ClassFinalModifierMockTransformerTest.java
- +327 −0 powermock-core/src/test/java/org/powermock/core/transformers/ConstructorCallMockTransformerTest.java
- +2 −4 powermock-core/src/test/java/org/powermock/core/transformers/ConstructorsMockTransformerTest.java
- +1 −22 powermock-core/src/test/java/org/powermock/core/transformers/InstrumentMockTransformerTest.java
- +27 −7 powermock-core/src/test/java/org/powermock/core/transformers/MockTransformerTestHelper.java
- +116 −0 ...mock-core/src/test/java/org/powermock/core/transformers/StaticFinalFieldsMockTransformerTest.java
- +0 −4 ...ore/src/test/java/org/powermock/core/transformers/StaticFinalNativeMethodMockTransformerTest.java
- +1 −2 ...e/src/test/java/org/powermock/core/transformers/SuppressStaticInitializerMockTransformerTest.java
- +2 −1 .../transformers/javassist/{TestClassTransformerTest.java → TestClassTransformerJavaAssistTest.java}
- +100 −14 powermock-core/src/test/java/powermock/test/support/MainMockTransformerTestSupport.java
@@ -0,0 +1,78 @@ | ||
/* | ||
* | ||
* Copyright 2017 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package org.powermock.core.bytebuddy; | ||
|
||
import net.bytebuddy.implementation.Implementation.Context; | ||
import net.bytebuddy.implementation.bytecode.StackManipulation; | ||
import net.bytebuddy.jar.asm.Label; | ||
import net.bytebuddy.jar.asm.MethodVisitor; | ||
import net.bytebuddy.jar.asm.Opcodes; | ||
|
||
public class ConditionalStateStackManipulation implements StackManipulation { | ||
|
||
|
||
private final StackManipulation condition; | ||
private final StackManipulation action; | ||
private final StackManipulation otherwise; | ||
private final Frame frame; | ||
|
||
public ConditionalStateStackManipulation(final StackManipulation condition, | ||
final StackManipulation action, | ||
final StackManipulation otherwise, | ||
final Frame frame) { | ||
|
||
this.condition = condition; | ||
this.action = action; | ||
this.otherwise = otherwise; | ||
this.frame = frame; | ||
} | ||
|
||
@Override | ||
public boolean isValid() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public Size apply(final MethodVisitor mv, final Context implementationContext) { | ||
|
||
Size size = new Size(0, 0); | ||
|
||
Label proceed = new Label(); | ||
Label exit = new Label(); | ||
|
||
size = size.aggregate(condition.apply(mv, implementationContext)); | ||
|
||
mv.visitJumpInsn(Opcodes.IFEQ, proceed); | ||
|
||
size = size.aggregate(action.apply(mv, implementationContext)); | ||
|
||
mv.visitJumpInsn(Opcodes.GOTO, exit); | ||
|
||
mv.visitLabel(proceed); | ||
mv.visitFrame(Opcodes.F_FULL, frame.localSize(), frame.locals(), 0, null); | ||
|
||
size = size.aggregate(otherwise.apply(mv, implementationContext)); | ||
|
||
mv.visitLabel(exit); | ||
|
||
mv.visitFrame(Opcodes.F_FULL, 0, null, 0, null); | ||
|
||
return size; | ||
} | ||
} |
@@ -0,0 +1,143 @@ | ||
/* | ||
* | ||
* Copyright 2017 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package org.powermock.core.bytebuddy; | ||
|
||
|
||
import net.bytebuddy.description.method.ParameterDescription; | ||
import net.bytebuddy.description.method.ParameterDescription.InDefinedShape; | ||
import net.bytebuddy.description.method.ParameterList; | ||
import net.bytebuddy.description.type.TypeDescription.Generic; | ||
import net.bytebuddy.implementation.bytecode.StackSize; | ||
import net.bytebuddy.jar.asm.Opcodes; | ||
import net.bytebuddy.utility.CompoundList; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.Deque; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
|
||
public class Frame { | ||
|
||
public static Frame beforeConstructorCall(final Iterable<? extends ParameterDescription> constructorParameters) { | ||
List<LocalVariable> locals = new ArrayList<LocalVariable>(); | ||
|
||
locals.add(LocalVariable.UNINITIALIZED_THIS); | ||
|
||
int maxLocals = 1; | ||
|
||
for (ParameterDescription sourceParameter : constructorParameters) { | ||
Generic type = sourceParameter.getType(); | ||
locals.add(LocalVariable.from(type)); | ||
maxLocals += type.getStackSize().getSize(); | ||
} | ||
|
||
return new Frame(locals); | ||
} | ||
|
||
private Deque<Object> stack; | ||
private List<LocalVariable> locals; | ||
|
||
public Frame(final List<LocalVariable> locals) { | ||
this.locals = Collections.unmodifiableList(locals); | ||
this.stack = new LinkedList<Object>(); | ||
} | ||
|
||
public Frame addTopToLocals(final int count) { | ||
List<LocalVariable> locals = new ArrayList<LocalVariable>(); | ||
for (int i = 0; i < count; i++) { | ||
locals.add(LocalVariable.TOP); | ||
} | ||
|
||
return new Frame( | ||
CompoundList.of(this.locals, locals) | ||
); | ||
} | ||
|
||
public Frame addLocalVariable(final LocalVariable localVariable) { | ||
return new Frame( | ||
CompoundList.of(this.locals, localVariable) | ||
); | ||
} | ||
|
||
public Frame addLocalVariables(final ParameterList<InDefinedShape> types) { | ||
|
||
List<LocalVariable> frameLocals = new ArrayList<LocalVariable>(); | ||
|
||
for (ParameterDescription parameter : types) { | ||
Generic type = parameter.getType(); | ||
frameLocals.add(LocalVariable.from(type)); | ||
} | ||
|
||
return new Frame(CompoundList.of(this.locals, frameLocals)); | ||
} | ||
|
||
public Object[] locals() { | ||
Object[] frameLocals = new Object[this.locals.size()]; | ||
for (int i = 0; i < this.locals.size(); i++) { | ||
frameLocals[i] = this.locals.get(i).getType(); | ||
} | ||
return frameLocals; | ||
} | ||
|
||
public int localSize() { | ||
return locals.size(); | ||
} | ||
|
||
public int maxLocalVariableIndex() { | ||
int localStackSize = 0; | ||
for (LocalVariable localVariable : locals) { | ||
localStackSize += localVariable.getStackSize().getSize(); | ||
} | ||
return localStackSize; | ||
} | ||
|
||
public static class LocalVariable { | ||
public static LocalVariable from(final Generic type) { | ||
if (type.represents(double.class)) { | ||
return DOUBLE; | ||
} else { | ||
return new LocalVariable( | ||
type.getTypeName().replace('.', '/'), | ||
type.getStackSize() | ||
); | ||
} | ||
} | ||
|
||
public static final LocalVariable UNINITIALIZED_THIS = new LocalVariable(Opcodes.UNINITIALIZED_THIS, StackSize.SINGLE); | ||
public static final LocalVariable TOP = new LocalVariable(Opcodes.TOP, StackSize.SINGLE); | ||
public static final LocalVariable DOUBLE = new LocalVariable(Opcodes.DOUBLE, StackSize.DOUBLE); | ||
|
||
private final Object type; | ||
private final StackSize stackSize; | ||
|
||
private LocalVariable(final Object type, StackSize size) { | ||
this.type = type; | ||
this.stackSize = size; | ||
} | ||
|
||
public Object getType() { | ||
return type; | ||
} | ||
|
||
public StackSize getStackSize() { | ||
return stackSize; | ||
} | ||
} | ||
} |
@@ -0,0 +1,76 @@ | ||
/* | ||
* | ||
* Copyright 2017 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package org.powermock.core.bytebuddy; | ||
|
||
import net.bytebuddy.description.method.MethodDescription; | ||
import net.bytebuddy.jar.asm.ClassVisitor; | ||
import net.bytebuddy.jar.asm.MethodVisitor; | ||
import net.bytebuddy.jar.asm.Opcodes; | ||
|
||
public class MaxLocalsExtractor extends ClassVisitor { | ||
|
||
private MethodMaxLocals methodMaxLocals; | ||
|
||
public MaxLocalsExtractor() { | ||
super(Opcodes.ASM5); | ||
} | ||
|
||
@Override | ||
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, | ||
final String[] exceptions) { | ||
if (MethodDescription.CONSTRUCTOR_INTERNAL_NAME.equals(name)) { | ||
methodMaxLocals = new MethodMaxLocals(); | ||
return new MaxLocalsMethodVisitor(name, desc, methodMaxLocals); | ||
} | ||
return super.visitMethod(access, name, desc, signature, exceptions); | ||
} | ||
|
||
public MethodMaxLocals getMethods() { | ||
return methodMaxLocals; | ||
} | ||
|
||
private static class MaxLocalsMethodVisitor extends MethodVisitor { | ||
|
||
private final String name; | ||
private final String signature; | ||
private final MethodMaxLocals methodMaxLocals; | ||
private int maxLocals; | ||
|
||
private MaxLocalsMethodVisitor(final String name, final String signature, | ||
final MethodMaxLocals methodMaxLocals) { | ||
super(Opcodes.ASM5); | ||
this.name = name; | ||
this.signature = signature; | ||
this.methodMaxLocals = methodMaxLocals; | ||
} | ||
|
||
@Override | ||
public void visitMaxs(final int maxStack, final int maxLocals) { | ||
this.maxLocals = maxLocals; | ||
super.visitMaxs(maxStack, maxLocals); | ||
} | ||
|
||
@Override | ||
public void visitEnd() { | ||
methodMaxLocals.add(name, signature, maxLocals); | ||
super.visitEnd(); | ||
} | ||
} | ||
|
||
} |
@@ -0,0 +1,44 @@ | ||
/* | ||
* | ||
* Copyright 2017 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package org.powermock.core.bytebuddy; | ||
|
||
import net.bytebuddy.description.method.MethodDescription; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
|
||
public class MethodMaxLocals { | ||
|
||
private final Map<String, Integer> methodMaxLocals; | ||
|
||
MethodMaxLocals() { | ||
methodMaxLocals = new HashMap<String, Integer>(); | ||
} | ||
|
||
public void add(String name, String signature, int maxLocals) { | ||
methodMaxLocals.put(name + signature, maxLocals); | ||
} | ||
|
||
public int getMethodMaxLocal(final MethodDescription instrumentedMethod) { | ||
final String key = instrumentedMethod.getInternalName() + instrumentedMethod.getDescriptor(); | ||
final Integer maxLocals = methodMaxLocals.get(key); | ||
return maxLocals == null ? 0 : maxLocals; | ||
} | ||
} |
Oops, something went wrong.