/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.support.reflect.declaration;
import spoon.SpoonException;
import spoon.SpoonModelBuilder.InputType;
import spoon.reflect.code.CtCodeElement;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtStatementList;
import spoon.reflect.declaration.CtAnonymousExecutable;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtExecutable;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtTypeMember;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.CtVisitor;
import spoon.support.UnsettableProperty;
import spoon.support.compiler.jdt.JDTBasedSpoonCompiler;
import spoon.support.reflect.code.CtStatementImpl;
import spoon.support.reflect.eval.VisitorPartialEvaluator;
import spoon.support.util.SignatureBasedSortedSet;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* The implementation for {@link spoon.reflect.declaration.CtClass}.
*
* @author Renaud Pawlak
*/
public class CtClassImpl<T extends Object> extends CtTypeImpl<T> implements CtClass<T> {
private static final long serialVersionUID = 1L;
CtTypeReference<?> superClass;
@Override
public void accept(CtVisitor v) {
v.visitCtClass(this);
}
@Override
public List<CtAnonymousExecutable> getAnonymousExecutables() {
List<CtAnonymousExecutable> anonymousExecutables = new ArrayList<>();
for (CtTypeMember typeMember : typeMembers) {
if (typeMember instanceof CtAnonymousExecutable) {
anonymousExecutables.add((CtAnonymousExecutable) typeMember);
}
}
return anonymousExecutables;
}
@Override
public CtConstructor<T> getConstructor(CtTypeReference<?>... parameterTypes) {
for (CtTypeMember typeMember : getTypeMembers()) {
if (!(typeMember instanceof CtConstructor)) {
continue;
}
CtConstructor<T> c = (CtConstructor<T>) typeMember;
boolean cont = c.getParameters().size() == parameterTypes.length;
for (int i = 0; cont && (i < c.getParameters().size()) && (i < parameterTypes.length); i++) {
if (!parameterTypes[i].getQualifiedName().equals(c.getParameters().get(i).getType().getQualifiedName())) {
cont = false;
}
}
if (cont) {
return c;
}
}
return null;
}
@Override
public Set<CtConstructor<T>> getConstructors() {
Set<CtConstructor<T>> constructors = new SignatureBasedSortedSet<>();
for (CtTypeMember typeMember : typeMembers) {
if (typeMember instanceof CtConstructor) {
constructors.add((CtConstructor<T>) typeMember);
}
}
return constructors;
}
@Override
public <C extends CtClass<T>> C addAnonymousExecutable(CtAnonymousExecutable e) {
return addTypeMember(e);
}
@Override
public boolean removeAnonymousExecutable(CtAnonymousExecutable e) {
return removeTypeMember(e);
}
@Override
public CtTypeReference<?> getSuperclass() {
return superClass;
}
@Override
public <C extends CtClass<T>> C setAnonymousExecutables(List<CtAnonymousExecutable> anonymousExecutables) {
if (anonymousExecutables == null || anonymousExecutables.isEmpty()) {
this.typeMembers.removeAll(getAnonymousExecutables());
return (C) this;
}
typeMembers.removeAll(getAnonymousExecutables());
for (CtAnonymousExecutable exec : anonymousExecutables) {
addAnonymousExecutable(exec);
}
return (C) this;
}
@Override
public <C extends CtClass<T>> C setConstructors(Set<CtConstructor<T>> constructors) {
if (constructors == null || constructors.isEmpty()) {
this.typeMembers.removeAll(getConstructors());
return (C) this;
}
typeMembers.removeAll(getConstructors());
for (CtConstructor<T> constructor : constructors) {
addConstructor(constructor);
}
return (C) this;
}
@Override
public <C extends CtClass<T>> C addConstructor(CtConstructor<T> constructor) {
return addTypeMember(constructor);
}
@Override
public void removeConstructor(CtConstructor<T> constructor) {
removeTypeMember(constructor);
}
@Override
public <C extends CtType<T>> C setSuperclass(CtTypeReference<?> superClass) {
if (superClass != null) {
superClass.setParent(this);
}
this.superClass = superClass;
return (C) this;
}
@Override
public boolean isAnonymous() {
try {
Integer.parseInt(getSimpleName());
} catch (NumberFormatException e) {
return false;
}
return true;
}
@Override
public boolean isSubtypeOf(CtTypeReference<?> type) {
return getReference().isSubtypeOf(type);
}
@Override
public <C extends CtStatement> C insertAfter(CtStatement statement) {
CtStatementImpl.insertAfter(this, statement);
return (C) this;
}
@Override
public <C extends CtStatement> C insertAfter(CtStatementList statements) {
CtStatementImpl.insertAfter(this, statements);
return (C) this;
}
@Override
public <C extends CtStatement> C insertBefore(CtStatement statement) {
CtStatementImpl.insertBefore(this, statement);
return (C) this;
}
@Override
public <C extends CtStatement> C insertBefore(CtStatementList statements) {
CtStatementImpl.insertBefore(this, statements);
return (C) this;
}
@Override
public String getLabel() {
return null;
}
@Override
@UnsettableProperty
public <C extends CtStatement> C setLabel(String label) {
return (C) this;
}
@SuppressWarnings("unchecked")
@Override
public <R extends CtCodeElement> R partiallyEvaluate() {
VisitorPartialEvaluator eval = new VisitorPartialEvaluator();
return eval.evaluate((R) this);
}
@Override
public Collection<CtExecutableReference<?>> getDeclaredExecutables() {
Collection<CtExecutableReference<?>> declaredExecutables = super.getDeclaredExecutables();
List<CtExecutableReference<?>> l = new ArrayList<>(declaredExecutables.size() + getConstructors().size());
l.addAll(declaredExecutables);
for (CtExecutable<?> c : getConstructors()) {
l.add(c.getReference());
}
return Collections.unmodifiableList(l);
}
@Override
public void replace(CtStatement element) {
replace((CtElement) element);
}
@Override
public CtClass<T> clone() {
return (CtClass<T>) super.clone();
}
@Override
public T newInstance() {
try {
JDTBasedSpoonCompiler spooner = new JDTBasedSpoonCompiler(getFactory());
spooner.compile(InputType.CTTYPES); // compiling the types of the factory
Class<?> klass = new NewInstanceClassloader(spooner.getBinaryOutputDirectory()).loadClass(getQualifiedName());
return (T) klass.newInstance();
} catch (Exception e) {
throw new SpoonException(e);
}
}
private class NewInstanceClassloader extends URLClassLoader {
NewInstanceClassloader(File binaryOutputDirectory) throws MalformedURLException {
super(new URL[] { binaryOutputDirectory.toURL()});
}
@Override
public Class<?> loadClass(String s) throws ClassNotFoundException {
try {
return findClass(s);
} catch (Exception e) {
return super.loadClass(s);
}
}
}
/** adding the constructors and static executables */
@Override
public Collection<CtExecutableReference<?>> getAllExecutables() {
Set<CtExecutableReference<?>> l = (Set<CtExecutableReference<?>>) super.getAllExecutables();
for (CtConstructor c : getConstructors()) {
l.add(c.getReference());
}
for (CtExecutable<?> anon : getAnonymousExecutables()) {
l.add(anon.getReference());
}
return l;
}
}