/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.dsl.processor.java.model;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import com.oracle.truffle.dsl.processor.java.transform.AbstractCodeWriter;
public abstract class CodeElement<E extends Element> implements Element, GeneratedElement {
private final Set<Modifier> modifiers;
private List<AnnotationMirror> annotations;
private List<E> enclosedElements;
private Element enclosingElement;
private Element generatorElement;
private AnnotationMirror generatorAnnotationMirror;
public CodeElement(Set<Modifier> modifiers) {
this.modifiers = new LinkedHashSet<>(modifiers);
}
@Override
public void setGeneratorAnnotationMirror(AnnotationMirror mirror) {
this.generatorAnnotationMirror = mirror;
}
@Override
public void setGeneratorElement(Element element) {
this.generatorElement = element;
}
@Override
public AnnotationMirror getGeneratorAnnotationMirror() {
return generatorAnnotationMirror;
}
@Override
public Element getGeneratorElement() {
return generatorElement;
}
public <T extends E> T add(T element) {
if (element == null) {
throw new NullPointerException();
}
getEnclosedElements().add(element);
return element;
}
public <T extends E> T addOptional(T element) {
if (element != null) {
add(element);
}
return element;
}
public void remove(E element) {
getEnclosedElements().remove(element);
}
@Override
public Set<Modifier> getModifiers() {
return modifiers;
}
@Override
public List<E> getEnclosedElements() {
if (enclosedElements == null) {
enclosedElements = parentableList(this, new ArrayList<E>());
}
return enclosedElements;
}
@Override
public List<AnnotationMirror> getAnnotationMirrors() {
if (annotations == null) {
annotations = parentableList(this, new ArrayList<AnnotationMirror>());
}
return annotations;
}
/**
* Support JDK8 langtools.
*
* @param annotationType
*/
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
throw new UnsupportedOperationException();
}
/**
* Support for some JDK8 builds. (remove after jdk8 is released)
*
* @param annotationType
*/
public <A extends Annotation> A[] getAnnotations(Class<A> annotationType) {
throw new UnsupportedOperationException();
}
/**
* Support for some JDK8 builds. (remove after jdk8 is released)
*
* @param annotationType
*/
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
throw new UnsupportedOperationException();
}
public void addAnnotationMirror(AnnotationMirror annotationMirror) {
getAnnotationMirrors().add(annotationMirror);
}
public void setEnclosingElement(Element parent) {
this.enclosingElement = parent;
}
public Element getEnclosingElement() {
return enclosingElement;
}
public CodeTypeElement getEnclosingClass() {
Element p = enclosingElement;
while (p != null && p.getKind() != ElementKind.CLASS && p.getKind() != ElementKind.ENUM) {
p = p.getEnclosingElement();
}
return (CodeTypeElement) p;
}
<T> List<T> parentableList(Element parent, List<T> list) {
return new ParentableList<>(parent, list);
}
@Override
public String toString() {
StringBuilderCodeWriter codeWriter = new StringBuilderCodeWriter();
accept(codeWriter, null);
return codeWriter.getString();
}
private static class StringBuilderCodeWriter extends AbstractCodeWriter {
StringBuilderCodeWriter() {
this.writer = new CharArrayWriter();
}
@Override
protected Writer createWriter(CodeTypeElement clazz) throws IOException {
return writer;
}
public String getString() {
return new String(((CharArrayWriter) writer).toCharArray()).trim();
}
}
private static class ParentableList<T> implements List<T> {
private final Element parent;
private final List<T> delegate;
ParentableList(Element parent, List<T> delegate) {
this.parent = parent;
this.delegate = delegate;
}
private void addImpl(T element) {
if (element != null) {
if (element instanceof CodeElement<?>) {
((CodeElement<?>) element).setEnclosingElement(parent);
}
}
}
private static void removeImpl(Object element) {
if (element instanceof CodeElement<?>) {
((CodeElement<?>) element).setEnclosingElement(null);
}
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean contains(Object o) {
return delegate.contains(o);
}
@Override
public Iterator<T> iterator() {
return delegate.iterator();
}
@Override
public Object[] toArray() {
return delegate.toArray();
}
@Override
public <E> E[] toArray(E[] a) {
return delegate.toArray(a);
}
@Override
public boolean add(T e) {
addImpl(e);
return delegate.add(e);
}
@Override
public boolean remove(Object o) {
boolean removed = delegate.remove(o);
if (removed) {
removeImpl(o);
}
return removed;
}
@Override
public boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends T> c) {
if (c != null) {
for (T t : c) {
addImpl(t);
}
}
return delegate.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
if (c != null) {
for (T t : c) {
addImpl(t);
}
}
return delegate.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
if (c != null) {
for (Object t : c) {
removeImpl(t);
}
}
return delegate.removeAll(c);
}
@Override
public String toString() {
return delegate.toString();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException("Not supported by parentable list");
}
@Override
public void clear() {
for (Object e : this) {
removeImpl(e);
}
delegate.clear();
}
@Override
public T get(int index) {
return delegate.get(index);
}
@Override
public T set(int index, T element) {
removeImpl(delegate.get(index));
addImpl(element);
return delegate.set(index, element);
}
@Override
public void add(int index, T element) {
addImpl(element);
delegate.add(index, element);
}
@Override
public T remove(int index) {
T element = delegate.remove(index);
removeImpl(element);
return element;
}
@Override
public int indexOf(Object o) {
return delegate.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return delegate.lastIndexOf(o);
}
@Override
public ListIterator<T> listIterator() {
return delegate.listIterator();
}
@Override
public ListIterator<T> listIterator(int index) {
return delegate.listIterator(index);
}
@Override
public List<T> subList(int fromIndex, int toIndex) {
return new ParentableList<>(parent, delegate.subList(fromIndex, toIndex));
}
}
}