/**
* 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 java.util.Set;
import spoon.reflect.cu.SourcePosition;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtShadowable;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.ParentNotInitializedException;
import spoon.reflect.reference.CtPackageReference;
import spoon.reflect.visitor.CtVisitor;
import spoon.support.util.QualifiedNameBasedSortedSet;
/**
* The implementation for {@link spoon.reflect.declaration.CtPackage}.
*
* @author Renaud Pawlak
*/
public class CtPackageImpl extends CtNamedElementImpl implements CtPackage {
private static final long serialVersionUID = 1L;
protected Set<CtPackage> packs = orderedPackageSet();
private Set<CtType<?>> types = orderedTypeSet();
public CtPackageImpl() {
super();
}
@Override
public void accept(CtVisitor v) {
v.visitCtPackage(this);
}
@Override
public <T extends CtPackage> T addPackage(CtPackage pack) {
if (pack == null) {
return (T) this;
}
if (packs == CtElementImpl.<CtPackage>emptySet()) {
this.packs = orderedPackageSet();
}
// they are the same
if (this.getQualifiedName().equals(pack.getQualifiedName())) {
addAllTypes(pack, this);
addAllPackages(pack, this);
return (T) this;
}
// it already exists
for (CtPackage p1 : packs) {
if (p1.getQualifiedName().equals(pack.getQualifiedName())) {
addAllTypes(pack, p1);
addAllPackages(pack, p1);
return (T) this;
}
}
pack.setParent(this);
this.packs.add(pack);
return (T) this;
}
private Set<CtPackage> orderedPackageSet() {
return new QualifiedNameBasedSortedSet<>();
}
private Set<CtType<?>> orderedTypeSet() {
return new QualifiedNameBasedSortedSet<>();
}
/** add all types of "from" in "to" */
private void addAllTypes(CtPackage from, CtPackage to) {
for (CtType t : from.getTypes()) {
for (CtType t2: to.getTypes()) {
if (t2.getQualifiedName().equals(t.getQualifiedName()) && !t2.equals(t)) {
throw new IllegalStateException("types with same qualified names and different code cannot be merged");
}
}
to.addType(t);
}
}
/** add all packages of "from" in "to" */
private void addAllPackages(CtPackage from, CtPackage to) {
for (CtPackage p : from.getPackages()) {
to.addPackage(p);
}
}
@Override
public boolean removePackage(CtPackage pack) {
return packs.remove(pack);
}
@Override
public CtPackage getDeclaringPackage() {
try {
return getParent(CtPackage.class);
} catch (ParentNotInitializedException e) {
return null;
}
}
@Override
public CtPackage getPackage(String name) {
for (CtPackage p : packs) {
if (p.getSimpleName().equals(name)) {
return p;
}
}
return null;
}
@Override
public Set<CtPackage> getPackages() {
return packs;
}
@Override
public String getQualifiedName() {
if (getDeclaringPackage() == null || getDeclaringPackage().isUnnamedPackage()) {
return getSimpleName();
} else {
return getDeclaringPackage().getQualifiedName() + "." + getSimpleName();
}
}
@Override
@SuppressWarnings("unchecked")
public <T extends CtType<?>> T getType(String simpleName) {
for (CtType<?> t : types) {
if (t.getSimpleName().equals(simpleName)) {
return (T) t;
}
}
return null;
}
@Override
public Set<CtType<?>> getTypes() {
return types;
}
@Override
public <T extends CtPackage> T setPackages(Set<CtPackage> packs) {
if (packs == null || packs.isEmpty()) {
this.packs = CtElementImpl.emptySet();
return (T) this;
}
this.packs.clear();
for (CtPackage p : packs) {
addPackage(p);
}
return (T) this;
}
@Override
public <T extends CtPackage> T setTypes(Set<CtType<?>> types) {
if (types == null || types.isEmpty()) {
this.types = CtElementImpl.emptySet();
return (T) this;
}
this.types.clear();
for (CtType<?> t : types) {
addType(t);
}
return (T) this;
}
@Override
public CtPackageReference getReference() {
return getFactory().Package().createReference(this);
}
@Override
public <T extends CtPackage> T addType(CtType<?> type) {
if (type == null) {
return (T) this;
}
if (types == CtElementImpl.<CtType<?>>emptySet()) {
this.types = orderedTypeSet();
}
type.setParent(this);
types.add(type);
return (T) this;
}
@Override
public void removeType(CtType<?> type) {
types.remove(type);
}
@Override
public SourcePosition getPosition() {
/*
* The super.getPosition() method returns the own position
* or if it's null the position of the parent element,
* but that isn't possible for packages.
* A package should return the position of the package-info file
* if it exists. The parent of a package is another package which
* needs to have an own package-info file.
*/
return this.position;
}
@Override
public String toString() {
return getQualifiedName();
}
boolean isShadow;
@Override
public boolean isShadow() {
return isShadow;
}
@Override
public <E extends CtShadowable> E setShadow(boolean isShadow) {
this.isShadow = isShadow;
return (E) this;
}
@Override
public CtPackage clone() {
return (CtPackage) super.clone();
}
@Override
public boolean isUnnamedPackage() {
return TOP_LEVEL_PACKAGE_NAME.equals(getSimpleName());
}
}