001: /*
002: * Spoon - http://spoon.gforge.inria.fr/
003: * Copyright (C) 2006 INRIA Futurs <renaud.pawlak@inria.fr>
004: *
005: * This software is governed by the CeCILL-C License under French law and
006: * abiding by the rules of distribution of free software. You can use, modify
007: * and/or redistribute the software under the terms of the CeCILL-C license as
008: * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
009: *
010: * This program is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
013: *
014: * The fact that you are presently reading this means that you have had
015: * knowledge of the CeCILL-C license and that you accept its terms.
016: */
017:
018: package spoon.support.visitor;
019:
020: import java.lang.reflect.Field;
021: import java.util.Collection;
022: import java.util.List;
023:
024: import spoon.processing.FactoryAccessor;
025: import spoon.reflect.declaration.CtElement;
026: import spoon.reflect.reference.CtReference;
027: import spoon.reflect.visitor.CtScanner;
028: import spoon.support.util.RtHelper;
029:
030: /**
031: * This scanner replaces a program element with another one in a program element
032: * hierarchy.
033: */
034: public class ElementReplacer<T extends FactoryAccessor> extends
035: CtScanner {
036:
037: T replacement;
038:
039: T toReplace;
040:
041: /**
042: * Creates a new replacer.
043: *
044: * @param toReplace
045: * the element to be replaced
046: * @param replacement
047: * the replacing element
048: */
049: public ElementReplacer(T toReplace, T replacement) {
050: super ();
051: this .replacement = replacement;
052: this .toReplace = toReplace;
053: }
054:
055: private T getReplacement(Object parent) {
056: T ret = replacement.getFactory().Core().clone(replacement);
057: if (ret instanceof CtElement && parent instanceof CtElement) {
058: ((CtElement) ret).setParent((CtElement) parent);
059: }
060: return ret;
061: }
062:
063: @SuppressWarnings("unchecked")
064: private void replaceIn(Object parent) throws Exception {
065:
066: // List<Field> fields =
067: // Arrays.asList(RtHelper.getAllFields(parent.getClass()));
068:
069: // Class current = parent.getClass();
070: // for (Field f : current.getDeclaredFields())
071: // fields.add(f);
072: //
073: // while (current.getSuperclass() != null) {
074: // current = current.getSuperclass();
075: // for (Field f : current.getDeclaredFields())
076: // fields.add(f);
077: // }
078:
079: // Field[] fields = parent.getClass().getFields();
080: for (Field f : RtHelper.getAllFields(parent.getClass())) {
081: f.setAccessible(true);
082: Object tmp = f.get(parent);
083:
084: if (tmp != null) {
085: if (tmp instanceof List) {
086: List<T> lst = (List<T>) tmp;
087:
088: for (int i = 0; i < lst.size(); i++) {
089: if (lst.get(i) != null
090: && lst.get(i).equals(toReplace)) {
091: lst.remove(i);
092: if (replacement != null)
093: lst.add(i, getReplacement(parent));
094: }
095: }
096: } else if (tmp instanceof Collection) {
097: Collection<T> collect = (Collection<T>) tmp;
098: Object[] array = collect.toArray();
099: for (Object obj : array) {
100: if (obj.equals(toReplace)) {
101: collect.remove(obj);
102: collect.add(getReplacement(parent));
103: }
104: }
105: } else if (tmp.equals(toReplace)) {
106: f.set(parent, getReplacement(parent));
107: }
108: }
109: }
110: }
111:
112: /**
113: * Do the replacement of the given element if needed.
114: */
115: @Override
116: public void enter(CtElement e) {
117: try {
118: replaceIn(e);
119: } catch (Exception e1) {
120: e1.printStackTrace();
121: }
122: super .enter(e);
123: }
124:
125: /**
126: * Do the replacement of the given element reference if needed.
127: */
128: @Override
129: public void enterReference(CtReference e) {
130: try {
131: replaceIn(e);
132: } catch (Exception e1) {
133: e1.printStackTrace();
134: }
135: super.enterReference(e);
136: }
137:
138: }
|