private ITypeModel processTypeReference(CtTypeReference<?> typeReference) { String qualifiedName = typeReference.getQualifiedName(); ITypeModel existingType = registry.getType(qualifiedName); if (existingType != null) { return new ProxyType(registry, qualifiedName); } CtClass<Object> ctClass = factory.Class().get(qualifiedName); if (ctClass != null) { return processType(ctClass); } CtType<Object> ctType = factory.Type().get(qualifiedName); if (ctType != null) { return processType(ctType); } TypeModel type = new TypeModel(); type.setFullyQualifiedName(qualifiedName); registry.registerType(type); fillReference(type, typeReference); Collection<CtExecutableReference<?>> methods = typeReference.getDeclaredExecutables(); for (CtExecutableReference<?> m : methods) { IMethodModel methodModel = processMethodReference(m); type.addMethod(methodModel); } Collection<CtFieldReference<?>> fields = typeReference.getDeclaredFields(); for (CtFieldReference<?> m : fields) { IFieldModel methodModel = processFieldReference(m); type.addField(methodModel); } return new ProxyType(registry, qualifiedName); }
private void fillJAXBType(BasicModel fm, CtTypeReference<?> type) { if (type == null) { return; } List<CtTypeReference<?>> actualTypes = new ArrayList<CtTypeReference<?>>(); Class<?> actualClass = type.getActualClass(); fm.setJavaClass(actualClass); if (actualClass != null && Collection.class.isAssignableFrom(actualClass)) { fm.setCollection(true); List<CtTypeReference<?>> actualTypeArguments = type.getActualTypeArguments(); if (actualTypeArguments.size() > 0) { actualTypes.add(actualTypeArguments.get(0)); } } else if (actualClass != null && Map.class.isAssignableFrom(actualClass)) { fm.setMap(true); List<CtTypeReference<?>> actualTypeArguments = type.getActualTypeArguments(); if (actualTypeArguments.size() == 2) { actualTypes = actualTypeArguments; } } else { actualTypes.add(type); } for (CtTypeReference<?> t : actualTypes) { ITypeModel processTypeReference = processTypeReference(t); fm.addJaxbType(processTypeReference); } }
@Test public void testPrintAMethodWithGeneric() throws Exception { final Launcher launcher = new Launcher(); final Factory factory = launcher.getFactory(); factory.getEnvironment().setAutoImports(true); final SpoonCompiler compiler = launcher.createCompiler(); compiler.addInputSource(new File("./src/test/java/spoon/test/prettyprinter/testclasses/")); compiler.build(); final CtClass<?> aClass = (CtClass<?>) factory.Type().get(AClass.class); final String expected = "public List<? extends ArrayList> aMethodWithGeneric() {" + System.lineSeparator() + " return new ArrayList<>();" + System.lineSeparator() + "}"; assertEquals(expected, aClass.getMethodsByName("aMethodWithGeneric").get(0).toString()); final CtConstructorCall<?> constructorCall = aClass.getElements(new TypeFilter<CtConstructorCall<?>>(CtConstructorCall.class)).get(0); final CtTypeReference<?> ctTypeReference = constructorCall.getType().getActualTypeArguments().get(0); assertTrue(ctTypeReference instanceof CtImplicitTypeReference); assertEquals("Object", ctTypeReference.getSimpleName()); }
public static CtMethod cloneMethodTest(CtMethod method, String suffix, int timeOut) { CtMethod cloned_method = cloneMethod(method, suffix); CtAnnotation testAnnotation = cloned_method .getAnnotations() .stream() .filter(annotation -> annotation.toString().contains("Test")) .findFirst() .orElse(null); if (testAnnotation != null) { cloned_method.removeAnnotation(testAnnotation); } testAnnotation = method.getFactory().Core().createAnnotation(); CtTypeReference<Object> ref = method.getFactory().Core().createTypeReference(); ref.setSimpleName("Test"); CtPackageReference refPackage = method.getFactory().Core().createPackageReference(); refPackage.setSimpleName("org.junit"); ref.setPackage(refPackage); testAnnotation.setAnnotationType(ref); Map<String, Object> elementValue = new HashMap<>(); elementValue.put("timeout", timeOut); testAnnotation.setElementValues(elementValue); cloned_method.addAnnotation(testAnnotation); return cloned_method; }
private IMethodModel processMethod(CtMethod<?> m, TypeModel ownerType) { MethodModel methodModel = new MethodModel(); fillBasic(methodModel, m); fillTypeParameters(methodModel, m); CtTypeReference<?> returnedType = m.getType(); ITypeModel returnedTypeModel = processTypeReference(returnedType); methodModel.setReturnedType(returnedTypeModel); fillJAXBType(methodModel, returnedType); List<CtParameter<?>> parameters = m.getParameters(); for (CtParameter<?> p : parameters) { IParameterModel parameterModel = processParameter(p); methodModel.addParameter(parameterModel); } String returnedTypeSimpleName = returnedType.getSimpleName(); String returnedTypeQualifiedname = returnedType.getQualifiedName(); if (returnedTypeSimpleName.equalsIgnoreCase(returnedTypeQualifiedname)) { for (ITypeParameter tp : ownerType.getTypeParameters()) { if (returnedType.getSimpleName().equals(tp.getName())) { methodModel.setHasGenericReturnType(true); } } for (ITypeParameter tp : methodModel.getTypeParameters()) { if (returnedType.getSimpleName().equals(tp.getName())) { methodModel.setHasGenericReturnType(true); } } } return methodModel; }
private void fillTypeParameters(GenericElementModel model, CtGenericElement element) { List<CtTypeReference<?>> ftp = element.getFormalTypeParameters(); if (ftp == null || ftp.isEmpty()) { return; } for (CtTypeReference<?> param : ftp) { String name = param.getSimpleName(); TypeParameterModel paramModel = new TypeParameterModel(); paramModel.setName(name); model.getTypeParameters().add(paramModel); } }
private IParameterModel processParameter(CtParameter<?> paramElement) { ParameterModel parameterModel = new ParameterModel(); CtTypeReference<?> paramType = paramElement.getType(); String qualifiedName = paramType.getQualifiedName(); parameterModel.setType(qualifiedName); parameterModel.setRequired(paramType.isPrimitive()); fillBasic(parameterModel, paramElement); fillJAXBType(parameterModel, paramType); processTypeReference(paramType); return parameterModel; }
/** * Type of the benchmarks method for this snippet. This is 'void' by default. * * <p>The benchmark method type must be the same that the one */ public String getBenchMethodReturnType() { if (benchMethodReturnType == null) { if (astElement != null) { List<CtReturn> rets = astElement.getElements(new TypeFilter<CtReturn>(CtReturn.class)); if (rets != null && rets.size() > 0 && rets.get(0).getReturnedExpression() != null) { CtTypeReference t = rets.get(0).getReturnedExpression().getType(); if (t.isAnonymous() || t.getQualifiedName().equals("<nulltype>")) benchMethodReturnType = "Object"; else benchMethodReturnType = t.getQualifiedName(); } } } return benchMethodReturnType == null ? "void" : benchMethodReturnType; }
private IParameterModel processParameterReference(CtTypeReference<?> paramTypeReference) { ParameterModel parameterModel = new ParameterModel(); parameterModel.setType(paramTypeReference.getQualifiedName()); parameterModel.setName(paramTypeReference.getSimpleName()); parameterModel.setRequired(paramTypeReference.isPrimitive()); List<Annotation> annotations = paramTypeReference.getAnnotations(); for (Annotation a : annotations) { IAnnotationModel annotationModel = processJavaLangAnnotation(a); parameterModel.addAnnotation(annotationModel); } return parameterModel; }
@Override public <C extends CtTypedElement> C setType(CtTypeReference<T> type) { if (type != null) { type.setParent(this); } this.type = type; return (C) this; }
/** Actually invokes from a compile-time invocation (by using runtime reflection). */ @SuppressWarnings("unchecked") public static <T> T invoke(CtInvocation<T> i) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Object target = i.getTarget() == null ? null : ((CtLiteral<?>) i.getTarget()).getValue(); List<Object> args = new ArrayList<Object>(); for (CtExpression<?> e : i.getArguments()) { args.add(((CtLiteral<?>) e).getValue()); } Class<?> c = i.getExecutable().getDeclaringType().getActualClass(); ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(); for (CtTypeReference<?> type : i.getExecutable().getActualTypeArguments()) { argTypes.add(type.getActualClass()); } return (T) c.getMethod(i.getExecutable().getSimpleName(), argTypes.toArray(new Class[argTypes.size()])) .invoke(target, args.toArray()); }
private IFieldModel processField(CtField<?> m, TypeModel ownerType) { FieldModel fm = new FieldModel(); fillBasic(fm, m); CtTypeReference<?> type = m.getType(); fillJAXBType(fm, type); String typeSimpleName = type.getSimpleName(); String typeQualifiedname = type.getQualifiedName(); if (typeSimpleName.equalsIgnoreCase(typeQualifiedname)) { for (ITypeParameter tp : ownerType.getTypeParameters()) { if (typeSimpleName.equals(tp.getName())) { fm.setGeneric(true); } } } return fm; }
@Override public <C extends CtExpression<T>> C addTypeCast(CtTypeReference<?> type) { if (typeCasts == CtElementImpl.<CtTypeReference<?>>emptyList()) { typeCasts = new ArrayList<CtTypeReference<?>>(CASTS_CONTAINER_DEFAULT_CAPACITY); } type.setParent(this); typeCasts.add(type); return (C) this; }
protected CtVariableRead buildVarRef(CtTypeReference type, Factory factory) { CtTypeReference<Object> typeRef = factory.Core().clone(type); CtLocalVariable<Object> localVar = factory.Core().createLocalVariable(); localVar.setType(typeRef); localVar.setSimpleName("var_" + type.getSimpleName() + "_" + System.currentTimeMillis()); CtVariableReadImpl varRead = new CtVariableReadImpl(); varRead.setVariable(factory.Code().createLocalVariableReference(localVar)); return varRead; }
private void createAssignment(CtConditional ctConditional, CtIf anIf, CtAssignment assignment) { CtAssignment assignmentThen = assignment.clone(); assignmentThen.setAssignment(ctConditional.getThenExpression()); assignmentThen.setParent(anIf); anIf.setThenStatement(assignmentThen); CtAssignment assignmentElse = assignment.clone(); assignmentElse.setAssignment(ctConditional.getElseExpression()); assignmentElse.setParent(anIf); anIf.setThenStatement(assignmentElse); List<CtTypeReference> typeCasts = ctConditional.getTypeCasts(); for (int i = 0; i < typeCasts.size(); i++) { CtTypeReference ctTypeReference = typeCasts.get(i); assignmentThen.getAssignment().addTypeCast(ctTypeReference.clone()); assignmentElse.getAssignment().addTypeCast(ctTypeReference.clone()); } anIf.setElseStatement(getFactory().Code().createCtBlock(assignmentElse)); anIf.setThenStatement(getFactory().Code().createCtBlock(assignmentThen)); }
protected CtLocalVariable createLocalVarFromMethodLiterals( CtMethod method, CtTypeReference type) { List<CtLiteral> literals = getLiterals(method) .stream() .filter(lit -> lit.getType() != null) .filter(lit -> lit.getType().equals(type)) .collect(Collectors.toList()); if (literals.isEmpty()) { return null; } CtLiteral lit = literals.get(AmplificationHelper.getRandom().nextInt(literals.size())); return type.getFactory().Code().createLocalVariable(type, "vc_" + count++, lit); }
protected Statement getLocalVar(CtTypeReference type, InputContext inputContext) { List<Statement> list = localVars .stream() .filter(var -> var.getCtCodeFragment() != null) .filter(var -> type.equals(((CtLocalVariable) var.getCtCodeFragment()).getType())) .filter( var -> inputContext.getVariableOrFieldNamed( ((CtLocalVariable) var.getCtCodeFragment()).getSimpleName()) == null) .collect(Collectors.toList()); if (list.isEmpty()) { return null; } else { boolean localVarFind; while (!list.isEmpty()) { Statement localVar = list.remove(AmplificationHelper.getRandom().nextInt(list.size())); localVarFind = true; for (CtVariableReference var : localVar.getInputContext().getVar()) { CtVariableReference<?> candidate = inputContext.candidate(var.getType(), true); if (candidate == null) { localVarFind = false; break; } } if (localVarFind) { Statement cloneLocalVar = localVar.clone(); for (CtVariableReference var : localVar.getInputContext().getVar()) { try { CtVariableReference variable = cloneLocalVar.getInputContext().getVariableOrFieldNamed(var.getSimpleName()); cloneLocalVar .getInputContext() .getVariableOrFieldNamed(var.getSimpleName()) .replace(variable); } catch (Exception e) { continue; } return cloneLocalVar; } } } return null; } }
@Override public void process(CtConditional ctConditional) { CtStatement parent = ctConditional.getParent(CtStatement.class); while (!(parent.getParent() instanceof CtStatementList)) { parent = parent.getParent(CtStatement.class); } CtExpression condition = ctConditional.getCondition(); CtIf anIf = getFactory().Core().createIf(); anIf.setPosition(ctConditional.getPosition()); if (parent instanceof CtReturn) { if (!((CtReturn) parent).getReturnedExpression().equals(ctConditional)) { return; } CtReturn returnThen = (CtReturn) parent.clone(); CtReturn returnElse = (CtReturn) parent.clone(); returnThen.setReturnedExpression(ctConditional.getThenExpression()); returnElse.setReturnedExpression(ctConditional.getElseExpression()); List<CtTypeReference> typeCasts = ctConditional.getTypeCasts(); for (int i = 0; i < typeCasts.size(); i++) { CtTypeReference ctTypeReference = typeCasts.get(i); returnThen.getReturnedExpression().addTypeCast(ctTypeReference.clone()); returnElse.getReturnedExpression().addTypeCast(ctTypeReference.clone()); } anIf.setElseStatement(getFactory().Code().createCtBlock(returnElse)); anIf.setThenStatement(getFactory().Code().createCtBlock(returnThen)); } else if (parent instanceof CtAssignment) { CtAssignment assignment = (CtAssignment) parent; CtExpression ctExpression = assignment.getAssignment(); if (!ctExpression.equals(ctConditional)) { if (ctExpression instanceof CtBinaryOperator) { CtBinaryOperator ctBinaryOperator = (CtBinaryOperator) ctExpression; createAssignment(ctConditional, anIf, assignment); CtBinaryOperator cloneThen = ctBinaryOperator.clone(); CtBinaryOperator cloneElse = ctBinaryOperator.clone(); if (ctBinaryOperator.getLeftHandOperand().equals(ctConditional)) { cloneThen.setLeftHandOperand(ctConditional.getThenExpression()); ctConditional.getThenExpression().setParent(cloneThen); cloneElse.setLeftHandOperand(ctConditional.getElseExpression()); } else if (ctBinaryOperator.getRightHandOperand().equals(ctConditional)) { cloneThen.setRightHandOperand(ctConditional.getThenExpression()); cloneElse.setRightHandOperand(ctConditional.getElseExpression()); } cloneThen.getLeftHandOperand().setParent(cloneThen); cloneElse.getLeftHandOperand().setParent(cloneElse); ((CtAssignment) ((CtBlock) anIf.getThenStatement()).getStatement(0)) .setAssignment(cloneThen); ((CtAssignment) ((CtBlock) anIf.getElseStatement()).getStatement(0)) .setAssignment(cloneElse); } else { return; } } else { createAssignment(ctConditional, anIf, assignment); } } else if (parent instanceof CtLocalVariable) { CtLocalVariable localVariable = (CtLocalVariable) parent; if (!localVariable.getDefaultExpression().equals(ctConditional)) { return; } CtLocalVariable clone = localVariable.clone(); clone.setDefaultExpression(null); localVariable.insertBefore(clone); CtAssignment variableAssignment = getFactory() .Code() .createVariableAssignment(localVariable.getReference(), false, ctConditional); variableAssignment.setType(localVariable.getType().clone()); variableAssignment.setPosition(ctConditional.getPosition()); createAssignment(ctConditional, anIf, variableAssignment); } else if (parent instanceof CtInvocation) { CtInvocation invocation = (CtInvocation) parent; CtInvocation cloneThen = invocation.clone(); CtInvocation cloneElse = invocation.clone(); List arguments = cloneThen.getArguments(); boolean found = false; for (int i = 0; i < arguments.size(); i++) { Object o = arguments.get(i); if (o.equals(ctConditional)) { ctConditional.getThenExpression().setParent(invocation); arguments.set(i, ctConditional.getThenExpression()); ctConditional.getElseExpression().setParent(invocation); cloneElse.getArguments().set(i, ctConditional.getElseExpression()); found = true; break; } } if (!found) { return; } cloneThen.setParent(anIf); cloneElse.setParent(anIf); anIf.setElseStatement(getFactory().Code().createCtBlock(cloneElse)); anIf.setThenStatement(getFactory().Code().createCtBlock(cloneThen)); } else if (parent instanceof CtConstructorCall) { CtConstructorCall invocation = (CtConstructorCall) parent; CtConstructorCall cloneThen = invocation.clone(); CtConstructorCall cloneElse = invocation.clone(); List arguments = cloneThen.getArguments(); boolean found = false; for (int i = 0; i < arguments.size(); i++) { Object o = arguments.get(i); if (o.equals(ctConditional)) { arguments.set(i, ctConditional.getThenExpression()); cloneElse.getArguments().set(i, ctConditional.getElseExpression()); found = true; break; } } if (!found) { return; } cloneThen.setParent(anIf); cloneElse.setParent(anIf); anIf.setElseStatement(getFactory().Code().createCtBlock(cloneElse)); anIf.setThenStatement(getFactory().Code().createCtBlock(cloneThen)); } else if (parent instanceof CtIf) { CtIf elem = (CtIf) parent; if (!elem.getCondition().equals(ctConditional)) { return; } CtIf cloneThen = elem.clone(); cloneThen.setParent(anIf); CtIf cloneElse = elem.clone(); cloneElse.setParent(anIf); cloneThen.setCondition(ctConditional.getThenExpression()); ctConditional.getThenExpression().setParent(cloneThen); cloneElse.setCondition(ctConditional.getElseExpression()); ctConditional.getElseExpression().setParent(cloneElse); anIf.setElseStatement(getFactory().Code().createCtBlock(cloneElse)); anIf.setThenStatement(getFactory().Code().createCtBlock(cloneThen)); } else if (parent instanceof CtThrow) { return; } else if (parent instanceof CtLoop) { return; } else if (parent instanceof CtUnaryOperator) { return; } else { System.err.println(parent); throw new RuntimeException("Other " + parent.getClass()); } /*if(ctConditional.getThenExpression().getTypeCasts() == null || ctConditional.getThenExpression().getTypeCasts().isEmpty()) { ((CtExpression)anIf.getThenStatement()).setTypeCasts(ctConditional.getTypeCasts()); } if(ctConditional.getElseExpression().getTypeCasts() == null || ctConditional.getElseExpression().getTypeCasts().isEmpty()) { ((CtExpression) anIf.getElseStatement()) .setTypeCasts(ctConditional.getTypeCasts()); }*/ anIf.setCondition(condition); condition.setParent(anIf); parent.replace(anIf); }
@SuppressWarnings("unchecked") private <T, U extends CtVariable<T>> U getVariableDeclaration( final String name, final Class<U> clazz) { final CoreFactory coreFactory = jdtTreeBuilder.getFactory().Core(); final TypeFactory typeFactory = jdtTreeBuilder.getFactory().Type(); final ClassFactory classFactory = jdtTreeBuilder.getFactory().Class(); final InterfaceFactory interfaceFactory = jdtTreeBuilder.getFactory().Interface(); final FieldFactory fieldFactory = jdtTreeBuilder.getFactory().Field(); final ReferenceBuilder referenceBuilder = jdtTreeBuilder.getReferencesBuilder(); final Environment environment = jdtTreeBuilder.getFactory().getEnvironment(); // there is some extra work to do if we are looking for CtFields (and subclasses) final boolean lookingForFields = clazz == null || coreFactory.createField().getClass().isAssignableFrom(clazz); // try to find the variable on stack beginning with the most recent element for (final ASTPair astPair : stack) { // the variable may have been declared directly by one of these elements final ScopeRespectingVariableScanner<U> scanner = new ScopeRespectingVariableScanner(name, clazz); astPair.element.accept(scanner); if (scanner.getResult() != null) { return scanner.getResult(); } // the variable may have been declared in a super class/interface if (lookingForFields && astPair.node instanceof TypeDeclaration) { final TypeDeclaration nodeDeclaration = (TypeDeclaration) astPair.node; final Deque<ReferenceBinding> referenceBindings = new ArrayDeque<>(); // add super class if any if (nodeDeclaration.superclass != null && nodeDeclaration.superclass.resolvedType instanceof ReferenceBinding) { referenceBindings.push((ReferenceBinding) nodeDeclaration.superclass.resolvedType); } // add interfaces if any if (nodeDeclaration.superInterfaces != null) { for (final TypeReference tr : nodeDeclaration.superInterfaces) { if (tr.resolvedType instanceof ReferenceBinding) { referenceBindings.push((ReferenceBinding) tr.resolvedType); } } } while (!referenceBindings.isEmpty()) { final ReferenceBinding referenceBinding = referenceBindings.pop(); for (final FieldBinding fieldBinding : referenceBinding.fields()) { if (name.equals(new String(fieldBinding.readableName()))) { final String qualifiedNameOfParent = new String(referenceBinding.readableName()); final CtType parentOfField = referenceBinding.isClass() ? classFactory.create(qualifiedNameOfParent) : interfaceFactory.create(qualifiedNameOfParent); return (U) fieldFactory.create( parentOfField, JDTTreeBuilderQuery.getModifiers(fieldBinding.modifiers), referenceBuilder.getTypeReference(fieldBinding.type), name); } } // add super class if any final ReferenceBinding superclass = referenceBinding.superclass(); if (superclass != null) { referenceBindings.push(superclass); } // add interfaces if any final ReferenceBinding[] interfaces = referenceBinding.superInterfaces(); if (interfaces != null) { for (ReferenceBinding rb : interfaces) { referenceBindings.push(rb); } } } } } // the variable may have been imported statically from another class/interface if (lookingForFields) { final CtReference potentialReferenceToField = referenceBuilder.getDeclaringReferenceFromImports(name.toCharArray()); if (potentialReferenceToField != null && potentialReferenceToField instanceof CtTypeReference) { final CtTypeReference typeReference = (CtTypeReference) potentialReferenceToField; try { final Class classOfType = typeReference.getActualClass(); if (classOfType != null) { final CtType declaringTypeOfField = typeReference.isInterface() ? interfaceFactory.get(classOfType) : classFactory.get(classOfType); final CtField field = declaringTypeOfField.getField(name); if (field != null) { return (U) field; } } } catch (final SpoonClassNotFoundException scnfe) { // in noclasspath mode we do some heuristics to determine if `name` could be a // field that has been imported statically from another class (or interface). if (environment.getNoClasspath()) { // if `potentialReferenceToField` is a `CtTypeReference` then `name` must // have been imported statically. Otherwise, `potentialReferenceToField` // would be a CtPackageReference! // if `name` consists only of upper case characters separated by '_', we // assume a constant value according to JLS. if (name.toUpperCase().equals(name)) { final CtType parentOfField = classFactory.create(typeReference.getQualifiedName()); // it is the best thing we can do final CtField field = coreFactory.createField(); field.setParent(parentOfField); field.setSimpleName(name); // it is the best thing we can do field.setType(typeFactory.nullType()); return (U) field; } } } } } return null; }