Package: XPathServices

XPathServices

nameinstructionbranchcomplexitylinemethod
XPathServices(IReadOnlyQueryEnvironment)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
addEObjectEClass(Set, IReadOnlyQueryEnvironment)
M: 24 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
ancestors(EObject)
M: 19 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
ancestors(EObject, EClass)
M: 11 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
ancestors(EObject, Set)
M: 24 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
eIsInstanceOf(EObject, Set)
M: 24 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
followingSiblings(EObject)
M: 16 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
followingSiblings(EObject, EClass)
M: 11 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
followingSiblings(EObject, Set)
M: 145 C: 0
0%
M: 34 C: 0
0%
M: 18 C: 0
0%
M: 28 C: 0
0%
M: 1 C: 0
0%
getContainer(EObject)
M: 14 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getContentsExcluding(EObject, EObject)
M: 69 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 12 C: 0
0%
M: 1 C: 0
0%
getContentsExcluding(Object, EObject)
M: 24 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getContentsFrom(EObject, EObject)
M: 81 C: 0
0%
M: 18 C: 0
0%
M: 10 C: 0
0%
M: 17 C: 0
0%
M: 1 C: 0
0%
getContentsFrom(Object, EObject)
M: 24 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getContentsUntil(EObject, EObject)
M: 71 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 16 C: 0
0%
M: 1 C: 0
0%
getContentsUntil(Object, EObject)
M: 24 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getFeatures(EObject, EStructuralFeature, Set)
M: 59 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
getFollowingFeatures(EObject, EStructuralFeature, Set)
M: 68 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
getPrecedingFeatures(EObject, EStructuralFeature, Set)
M: 63 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 13 C: 0
0%
M: 1 C: 0
0%
getRootsExcluding(Resource, EObject)
M: 28 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
getRootsFrom(Resource, EObject)
M: 35 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
getRootsUntil(Resource, EObject)
M: 29 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getService(Method)
M: 60 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
precedingSiblings(EObject)
M: 16 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
precedingSiblings(EObject, EClass)
M: 11 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
precedingSiblings(EObject, Set)
M: 125 C: 0
0%
M: 26 C: 0
0%
M: 14 C: 0
0%
M: 26 C: 0
0%
M: 1 C: 0
0%
siblings(EObject)
M: 16 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
siblings(EObject, EClass)
M: 11 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
siblings(EObject, Set)
M: 123 C: 0
0%
M: 26 C: 0
0%
M: 14 C: 0
0%
M: 24 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2015 Obeo.
3: * All rights reserved. This program and the accompanying materials
4: * are made available under the terms of the Eclipse Public License v1.0
5: * which accompanies this distribution, and is available at
6: * http://www.eclipse.org/legal/epl-v10.html
7: *
8: * Contributors:
9: * Obeo - initial API and implementation
10: *******************************************************************************/
11: package org.eclipse.acceleo.query.services;
12:
13: import com.google.common.collect.Sets;
14:
15: import java.lang.reflect.Method;
16: import java.util.ArrayList;
17: import java.util.Collection;
18: import java.util.Collections;
19: import java.util.LinkedHashSet;
20: import java.util.List;
21: import java.util.Set;
22:
23: import org.eclipse.acceleo.annotations.api.documentation.Documentation;
24: import org.eclipse.acceleo.annotations.api.documentation.Example;
25: import org.eclipse.acceleo.annotations.api.documentation.Param;
26: import org.eclipse.acceleo.query.ast.Call;
27: import org.eclipse.acceleo.query.runtime.IReadOnlyQueryEnvironment;
28: import org.eclipse.acceleo.query.runtime.IService;
29: import org.eclipse.acceleo.query.runtime.IValidationResult;
30: import org.eclipse.acceleo.query.runtime.impl.AbstractServiceProvider;
31: import org.eclipse.acceleo.query.runtime.impl.JavaMethodService;
32: import org.eclipse.acceleo.query.runtime.impl.ValidationServices;
33: import org.eclipse.acceleo.query.validation.type.EClassifierLiteralType;
34: import org.eclipse.acceleo.query.validation.type.EClassifierSetLiteralType;
35: import org.eclipse.acceleo.query.validation.type.EClassifierType;
36: import org.eclipse.acceleo.query.validation.type.IType;
37: import org.eclipse.acceleo.query.validation.type.SequenceType;
38: import org.eclipse.emf.ecore.EClass;
39: import org.eclipse.emf.ecore.EClassifier;
40: import org.eclipse.emf.ecore.EObject;
41: import org.eclipse.emf.ecore.EStructuralFeature;
42: import org.eclipse.emf.ecore.EcorePackage;
43: import org.eclipse.emf.ecore.InternalEObject;
44: import org.eclipse.emf.ecore.impl.EClassImpl.FeatureSubsetSupplier;
45: import org.eclipse.emf.ecore.resource.Resource;
46:
47: /**
48: * Services on {@link EObject}.
49: *
50: * @author <a href="mailto:romain.guider@obeo.fr">Romain Guider</a>
51: */
52: @SuppressWarnings({"checkstyle:javadocmethod", "checkstyle:javadoctype" })
53: public class XPathServices extends AbstractServiceProvider {
54:
55:         /**
56:          * {@link EClass} containment message.
57:          */
58:         private static final String ONLY_E_CLASS_CAN_BE_CONTAINED_INTO_OTHER_E_CLASSES_NOT_S = "Only EClass can be contained into other EClasses not %s";
59:
60:         /**
61:          * Can't contain directly or indirectly message.
62:          */
63:         private static final String S_CAN_T_CONTAIN_DIRECTLY_OR_INDIRECTLY_S = "%s can't contain directly or indirectly %s";
64:
65:         /**
66:          * Ancestors {@link IService}.
67:          *
68:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
69:          */
70:         private static final class AncestorsService extends FilterService {
71:
72:                 /**
73:                  * Creates a new service instance given a method and an instance.
74:                  *
75:                  * @param serviceMethod
76:                  * the method that realizes the service
77:                  * @param serviceInstance
78:                  * the instance on which the service must be called
79:                  */
80:                 private AncestorsService(Method serviceMethod, Object serviceInstance) {
81:                         super(serviceMethod, serviceInstance);
82:                 }
83:
84:                 @Override
85:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
86:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
87:                         final Set<IType> result = new LinkedHashSet<IType>();
88:
89:                         if (argTypes.get(0).getType() instanceof EClass) {
90:                                 final EClass eCls = (EClass)argTypes.get(0).getType();
91:                                 if (eCls == EcorePackage.eINSTANCE.getEObject()) {
92:                                         if (argTypes.size() == 1) {
93:                                                 result.add(new SequenceType(queryEnvironment, argTypes.get(0)));
94:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierLiteralType) {
95:                                                 result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
96:                                                                 ((EClassifierLiteralType)argTypes.get(1)).getType())));
97:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierSetLiteralType) {
98:                                                 for (EClassifier eClassifier : ((EClassifierSetLiteralType)argTypes.get(1))
99:                                                                 .getEClassifiers()) {
100:                                                         result.add(new SequenceType(queryEnvironment, new EClassifierType(
101:                                                                         queryEnvironment, eClassifier)));
102:                                                 }
103:                                         } else if (argTypes.size() == 2) {
104:                                                 result.addAll(super.getType(call, services, validationResult, queryEnvironment,
105:                                                                 argTypes));
106:                                         }
107:                                 } else {
108:                                         result.addAll(getTypeForSpecificType(services, queryEnvironment, argTypes, eCls));
109:                                 }
110:                         } else {
111:                                 result.add(new SequenceType(queryEnvironment, services.nothing(
112:                                                 ONLY_E_CLASS_CAN_BE_CONTAINED_INTO_OTHER_E_CLASSES_NOT_S, argTypes.get(0))));
113:                         }
114:
115:                         return result;
116:                 }
117:
118:                 /**
119:                  * Gets the {@link IType} of elements returned by the service when the receiver type is not the
120:                  * {@link EObject} {@link EClass}.
121:                  *
122:                  * @param services
123:                  * the {@link ValidationServices}
124:                  * @param queryEnvironment
125:                  * the {@link IReadOnlyQueryEnvironment}
126:                  * @param argTypes
127:                  * arguments {@link IType}
128:                  * @param receiverEClass
129:                  * the receiver type can't be {@link EObject} {@link EClass}
130:                  * @return the {@link IType} of elements returned by the service when the receiver type is not the
131:                  * {@link EObject} {@link EClass}
132:                  */
133:                 private Set<IType> getTypeForSpecificType(ValidationServices services,
134:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes, final EClass receiverEClass) {
135:                         final Set<IType> result = new LinkedHashSet<IType>();
136:
137:                         if (argTypes.size() == 1) {
138:                                 for (EClass containingEClass : queryEnvironment.getEPackageProvider()
139:                                                 .getAllContainingEClasses(receiverEClass)) {
140:                                         result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
141:                                                         containingEClass)));
142:                                 }
143:                                 if (result.isEmpty()) {
144:                                         result.add(new SequenceType(queryEnvironment, services.nothing("%s can't be contained",
145:                                                         argTypes.get(0))));
146:                                 }
147:                         } else if (argTypes.size() == 2) {
148:                                 final Set<IType> filterTypes = Sets.newLinkedHashSet();
149:                                 if (argTypes.get(1) instanceof EClassifierSetLiteralType) {
150:                                         for (EClassifier eClassifier : ((EClassifierSetLiteralType)argTypes.get(1))
151:                                                         .getEClassifiers()) {
152:                                                 filterTypes.add(new EClassifierType(queryEnvironment, eClassifier));
153:                                         }
154:                                 } else if (argTypes.get(1) instanceof EClassifierLiteralType) {
155:                                         filterTypes.add(argTypes.get(1));
156:                                 } else {
157:                                         addEObjectEClass(filterTypes, queryEnvironment);
158:                                 }
159:                                 for (IType filterType : filterTypes) {
160:                                         for (EClass containingEClass : queryEnvironment.getEPackageProvider()
161:                                                         .getAllContainingEClasses(receiverEClass)) {
162:                                                 final IType lowerType = services.lower(new EClassifierType(queryEnvironment,
163:                                                                 containingEClass), filterType);
164:                                                 if (lowerType != null) {
165:                                                         result.add(new SequenceType(queryEnvironment, lowerType));
166:                                                 }
167:                                         }
168:                                 }
169:                                 if (result.isEmpty()) {
170:                                         result.add(new SequenceType(queryEnvironment, services.nothing(
171:                                                         S_CAN_T_CONTAIN_DIRECTLY_OR_INDIRECTLY_S, argTypes.get(1), argTypes.get(0))));
172:                                 }
173:                         }
174:
175:                         return result;
176:                 }
177:
178:         }
179:
180:         /**
181:          * FollowingSiblings {@link IService}.
182:          *
183:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
184:          */
185:         private static final class FollowingSiblingsService extends FilterService {
186:
187:                 /**
188:                  * Creates a new service instance given a method and an instance.
189:                  *
190:                  * @param serviceMethod
191:                  * the method that realizes the service
192:                  * @param serviceInstance
193:                  * the instance on which the service must be called
194:                  */
195:                 private FollowingSiblingsService(Method serviceMethod, Object serviceInstance) {
196:                         super(serviceMethod, serviceInstance);
197:                 }
198:
199:                 @Override
200:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
201:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
202:                         final Set<IType> result = new LinkedHashSet<IType>();
203:
204:                         if (argTypes.get(0).getType() instanceof EClass) {
205:                                 final EClass eCls = (EClass)argTypes.get(0).getType();
206:                                 if (eCls == EcorePackage.eINSTANCE.getEObject()) {
207:                                         if (argTypes.size() == 1) {
208:                                                 result.add(new SequenceType(queryEnvironment, argTypes.get(0)));
209:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierLiteralType) {
210:                                                 result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
211:                                                                 ((EClassifierLiteralType)argTypes.get(1)).getType())));
212:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierSetLiteralType) {
213:                                                 for (EClassifier eClassifier : ((EClassifierSetLiteralType)argTypes.get(1))
214:                                                                 .getEClassifiers()) {
215:                                                         result.add(new SequenceType(queryEnvironment, new EClassifierType(
216:                                                                         queryEnvironment, eClassifier)));
217:                                                 }
218:                                         } else if (argTypes.size() == 2) {
219:                                                 result.addAll(super.getType(call, services, validationResult, queryEnvironment,
220:                                                                 argTypes));
221:                                         }
222:                                 } else {
223:                                         result.addAll(getTypeForSpecificType(services, queryEnvironment, argTypes, eCls));
224:                                 }
225:                         } else {
226:                                 result.add(new SequenceType(queryEnvironment, services.nothing(
227:                                                 "Only EClass can have following siblings not %s", argTypes.get(0))));
228:                         }
229:
230:                         return result;
231:                 }
232:
233:                 /**
234:                  * Gets the {@link IType} of elements returned by the service when the receiver type is not the
235:                  * {@link EObject} {@link EClass}.
236:                  *
237:                  * @param services
238:                  * the {@link ValidationServices}
239:                  * @param queryEnvironment
240:                  * the {@link IReadOnlyQueryEnvironment}
241:                  * @param argTypes
242:                  * arguments {@link IType}
243:                  * @param receiverEClass
244:                  * the receiver type can't be {@link EObject} {@link EClass}
245:                  * @return the {@link IType} of elements returned by the service when the receiver type is not the
246:                  * {@link EObject} {@link EClass}
247:                  */
248:                 private Set<IType> getTypeForSpecificType(ValidationServices services,
249:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes, final EClass receiverEClass) {
250:                         final Set<IType> result = new LinkedHashSet<IType>();
251:
252:                         if (argTypes.size() == 1) {
253:                                 for (EClass followingEClass : queryEnvironment.getEPackageProvider()
254:                                                 .getFollowingSiblingsEClasses(receiverEClass)) {
255:                                         result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
256:                                                         followingEClass)));
257:                                 }
258:                                 // for siblings root of a resource (any EObject)
259:                                 result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
260:                                                 EcorePackage.eINSTANCE.getEObject())));
261:                         } else if (argTypes.size() == 2) {
262:                                 final Set<IType> filterTypes = Sets.newLinkedHashSet();
263:                                 if (argTypes.get(1) instanceof EClassifierSetLiteralType) {
264:                                         for (EClassifier eClassifier : ((EClassifierSetLiteralType)argTypes.get(1))
265:                                                         .getEClassifiers()) {
266:                                                 filterTypes.add(new EClassifierType(queryEnvironment, eClassifier));
267:                                         }
268:                                 } else if (argTypes.get(1) instanceof EClassifierLiteralType) {
269:                                         filterTypes.add(argTypes.get(1));
270:                                 } else {
271:                                         addEObjectEClass(filterTypes, queryEnvironment);
272:                                 }
273:                                 for (IType filterType : filterTypes) {
274:                                         for (EClass followingEClass : queryEnvironment.getEPackageProvider()
275:                                                         .getFollowingSiblingsEClasses(receiverEClass)) {
276:                                                 final IType lowerType = services.lower(new EClassifierType(queryEnvironment,
277:                                                                 followingEClass), filterType);
278:                                                 if (lowerType != null) {
279:                                                         result.add(new SequenceType(queryEnvironment, lowerType));
280:                                                 }
281:                                         }
282:                                         // for siblings root of a resource (filtered EObject)
283:                                         result.add(new SequenceType(queryEnvironment, services.lower(filterType, filterType)));
284:                                 }
285:                         }
286:
287:                         return result;
288:                 }
289:
290:         }
291:
292:         /**
293:          * PrecedingSiblings {@link IService}.
294:          *
295:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
296:          */
297:         private static final class PrecedingSiblingsService extends FilterService {
298:
299:                 /**
300:                  * Creates a new service instance given a method and an instance.
301:                  *
302:                  * @param serviceMethod
303:                  * the method that realizes the service
304:                  * @param serviceInstance
305:                  * the instance on which the service must be called
306:                  */
307:                 private PrecedingSiblingsService(Method serviceMethod, Object serviceInstance) {
308:                         super(serviceMethod, serviceInstance);
309:                 }
310:
311:                 @Override
312:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
313:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
314:                         final Set<IType> result = new LinkedHashSet<IType>();
315:
316:                         if (argTypes.get(0).getType() instanceof EClass) {
317:                                 final EClass eCls = (EClass)argTypes.get(0).getType();
318:                                 if (eCls == EcorePackage.eINSTANCE.getEObject()) {
319:                                         if (argTypes.size() == 1) {
320:                                                 result.add(new SequenceType(queryEnvironment, argTypes.get(0)));
321:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierLiteralType) {
322:                                                 result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
323:                                                                 ((EClassifierLiteralType)argTypes.get(1)).getType())));
324:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierSetLiteralType) {
325:                                                 for (EClassifier eClassifier : ((EClassifierSetLiteralType)argTypes.get(1))
326:                                                                 .getEClassifiers()) {
327:                                                         result.add(new SequenceType(queryEnvironment, new EClassifierType(
328:                                                                         queryEnvironment, eClassifier)));
329:                                                 }
330:                                         } else if (argTypes.size() == 2) {
331:                                                 result.addAll(super.getType(call, services, validationResult, queryEnvironment,
332:                                                                 argTypes));
333:                                         }
334:                                 } else {
335:                                         result.addAll(getTypeForSpecificType(services, queryEnvironment, argTypes, eCls));
336:                                 }
337:                         } else {
338:                                 result.add(new SequenceType(queryEnvironment, services.nothing(
339:                                                 "Only EClass can have preceding siblings not %s", argTypes.get(0))));
340:                         }
341:
342:                         return result;
343:                 }
344:
345:                 /**
346:                  * Gets the {@link IType} of elements returned by the service when the receiver type is not the
347:                  * {@link EObject} {@link EClass}.
348:                  *
349:                  * @param services
350:                  * the {@link ValidationServices}
351:                  * @param queryEnvironment
352:                  * the {@link IReadOnlyQueryEnvironment}
353:                  * @param argTypes
354:                  * arguments {@link IType}
355:                  * @param receiverEClass
356:                  * the receiver type can't be {@link EObject} {@link EClass}
357:                  * @return the {@link IType} of elements returned by the service when the receiver type is not the
358:                  * {@link EObject} {@link EClass}
359:                  */
360:                 private Set<IType> getTypeForSpecificType(ValidationServices services,
361:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes, final EClass receiverEClass) {
362:                         final Set<IType> result = new LinkedHashSet<IType>();
363:
364:                         if (argTypes.size() == 1) {
365:                                 for (EClass precedingEClass : queryEnvironment.getEPackageProvider()
366:                                                 .getPrecedingSiblingsEClasses(receiverEClass)) {
367:                                         result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
368:                                                         precedingEClass)));
369:                                 }
370:                                 // for siblings root of a resource (any EObject)
371:                                 result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
372:                                                 EcorePackage.eINSTANCE.getEObject())));
373:                         } else if (argTypes.size() == 2) {
374:                                 final Set<IType> filterTypes = Sets.newLinkedHashSet();
375:                                 if (argTypes.get(1) instanceof EClassifierSetLiteralType) {
376:                                         for (EClassifier eClassifier : ((EClassifierSetLiteralType)argTypes.get(1))
377:                                                         .getEClassifiers()) {
378:                                                 filterTypes.add(new EClassifierType(queryEnvironment, eClassifier));
379:                                         }
380:                                 } else if (argTypes.get(1) instanceof EClassifierLiteralType) {
381:                                         filterTypes.add(argTypes.get(1));
382:                                 } else {
383:                                         addEObjectEClass(filterTypes, queryEnvironment);
384:                                 }
385:                                 for (IType filterType : filterTypes) {
386:                                         for (EClass precedingEClass : queryEnvironment.getEPackageProvider()
387:                                                         .getPrecedingSiblingsEClasses(receiverEClass)) {
388:                                                 final IType lowerType = services.lower(new EClassifierType(queryEnvironment,
389:                                                                 precedingEClass), filterType);
390:                                                 if (lowerType != null) {
391:                                                         result.add(new SequenceType(queryEnvironment, lowerType));
392:                                                 }
393:                                         }
394:                                         // for siblings root of a resource (filtered EObject)
395:                                         result.add(new SequenceType(queryEnvironment, services.lower(filterType, filterType)));
396:                                 }
397:                         }
398:
399:                         return result;
400:                 }
401:
402:         }
403:
404:         /**
405:          * Siblings {@link IService}.
406:          *
407:          * @author <a href="mailto:yvan.lussaud@obeo.fr">Yvan Lussaud</a>
408:          */
409:         private static final class SiblingsService extends FilterService {
410:
411:                 /**
412:                  * Creates a new service instance given a method and an instance.
413:                  *
414:                  * @param serviceMethod
415:                  * the method that realizes the service
416:                  * @param serviceInstance
417:                  * the instance on which the service must be called
418:                  */
419:                 private SiblingsService(Method serviceMethod, Object serviceInstance) {
420:                         super(serviceMethod, serviceInstance);
421:                 }
422:
423:                 @Override
424:                 public Set<IType> getType(Call call, ValidationServices services, IValidationResult validationResult,
425:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes) {
426:                         final Set<IType> result = new LinkedHashSet<IType>();
427:
428:                         if (argTypes.get(0).getType() instanceof EClass) {
429:                                 final EClass eCls = (EClass)argTypes.get(0).getType();
430:                                 if (eCls == EcorePackage.eINSTANCE.getEObject()) {
431:                                         if (argTypes.size() == 1) {
432:                                                 result.add(new SequenceType(queryEnvironment, argTypes.get(0)));
433:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierLiteralType) {
434:                                                 result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
435:                                                                 ((EClassifierLiteralType)argTypes.get(1)).getType())));
436:                                         } else if (argTypes.size() == 2 && argTypes.get(1) instanceof EClassifierSetLiteralType) {
437:                                                 for (EClassifier eClassifier : ((EClassifierSetLiteralType)argTypes.get(1))
438:                                                                 .getEClassifiers()) {
439:                                                         result.add(new SequenceType(queryEnvironment, new EClassifierType(
440:                                                                         queryEnvironment, eClassifier)));
441:                                                 }
442:                                         } else if (argTypes.size() == 2) {
443:                                                 result.addAll(super.getType(call, services, validationResult, queryEnvironment,
444:                                                                 argTypes));
445:                                         }
446:                                 } else {
447:                                         result.addAll(getTypeForSpecificType(services, queryEnvironment, argTypes, eCls));
448:                                 }
449:                         } else {
450:                                 result.add(new SequenceType(queryEnvironment, services.nothing(
451:                                                 "Only EClass can have siblings not %s", argTypes.get(0))));
452:                         }
453:
454:                         return result;
455:                 }
456:
457:                 /**
458:                  * Gets the {@link IType} of elements returned by the service when the receiver type is not the
459:                  * {@link EObject} {@link EClass}.
460:                  *
461:                  * @param services
462:                  * the {@link ValidationServices}
463:                  * @param queryEnvironment
464:                  * the {@link IReadOnlyQueryEnvironment}
465:                  * @param argTypes
466:                  * arguments {@link IType}
467:                  * @param receiverEClass
468:                  * the receiver type can't be {@link EObject} {@link EClass}
469:                  * @return the {@link IType} of elements returned by the service when the receiver type is not the
470:                  * {@link EObject} {@link EClass}
471:                  */
472:                 private Set<IType> getTypeForSpecificType(ValidationServices services,
473:                                 IReadOnlyQueryEnvironment queryEnvironment, List<IType> argTypes, final EClass receiverEClass) {
474:                         final Set<IType> result = new LinkedHashSet<IType>();
475:
476:                         if (argTypes.size() == 1) {
477:                                 for (EClass siblingEClass : queryEnvironment.getEPackageProvider().getSiblingsEClasses(
478:                                                 receiverEClass)) {
479:                                         result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
480:                                                         siblingEClass)));
481:                                 }
482:                                 // for siblings root of a resource (any EObject)
483:                                 result.add(new SequenceType(queryEnvironment, new EClassifierType(queryEnvironment,
484:                                                 EcorePackage.eINSTANCE.getEObject())));
485:                         } else if (argTypes.size() == 2) {
486:                                 final Set<IType> filterTypes = Sets.newLinkedHashSet();
487:                                 if (argTypes.get(1) instanceof EClassifierSetLiteralType) {
488:                                         for (EClassifier eClassifier : ((EClassifierSetLiteralType)argTypes.get(1))
489:                                                         .getEClassifiers()) {
490:                                                 filterTypes.add(new EClassifierType(queryEnvironment, eClassifier));
491:                                         }
492:                                 } else if (argTypes.get(1) instanceof EClassifierLiteralType) {
493:                                         filterTypes.add(argTypes.get(1));
494:                                 } else {
495:                                         addEObjectEClass(filterTypes, queryEnvironment);
496:                                 }
497:                                 for (IType filterType : filterTypes) {
498:                                         for (EClass siblingEClass : queryEnvironment.getEPackageProvider().getSiblingsEClasses(
499:                                                         receiverEClass)) {
500:                                                 final IType lowerType = services.lower(new EClassifierType(queryEnvironment,
501:                                                                 siblingEClass), filterType);
502:                                                 if (lowerType != null) {
503:                                                         result.add(new SequenceType(queryEnvironment, lowerType));
504:                                                 }
505:                                         }
506:                                         // for siblings root of a resource (filtered EObject)
507:                                         result.add(new SequenceType(queryEnvironment, services.lower(filterType, filterType)));
508:                                 }
509:                         }
510:
511:                         return result;
512:                 }
513:         }
514:
515:         /**
516:          * The {@link IReadOnlyQueryEnvironment}.
517:          */
518:         private final IReadOnlyQueryEnvironment queryEnvironment;
519:
520:         /**
521:          * Constructor.
522:          *
523:          * @param queryEnvironment
524:          * the {@link IReadOnlyQueryEnvironment}
525:          */
526:         public XPathServices(IReadOnlyQueryEnvironment queryEnvironment) {
527:                 this.queryEnvironment = queryEnvironment;
528:         }
529:
530:         /**
531:          * {@inheritDoc}
532:          *
533:          * @see org.eclipse.acceleo.query.runtime.impl.AbstractServiceProvider#getService(java.lang.reflect.Method)
534:          */
535:         @Override
536:         protected IService getService(Method publicMethod) {
537:                 final IService result;
538:•                if ("ancestors".equals(publicMethod.getName())) {
539:                         result = new AncestorsService(publicMethod, this);
540:•                } else if ("followingSiblings".equals(publicMethod.getName())) {
541:                         result = new FollowingSiblingsService(publicMethod, this);
542:•                } else if ("precedingSiblings".equals(publicMethod.getName())) {
543:                         result = new PrecedingSiblingsService(publicMethod, this);
544:•                } else if ("siblings".equals(publicMethod.getName())) {
545:                         result = new SiblingsService(publicMethod, this);
546:                 } else {
547:                         result = new JavaMethodService(publicMethod, this);
548:                 }
549:
550:                 return result;
551:         }
552:
553:         // @formatter:off
554:         @Documentation(
555:                 value = "Returns a Sequence containing the full set of object's ancestors.",
556:                 params = {
557:                         @Param(name = "self", value = "The EObject we seek the ancestors of")
558:                 },
559:                 result = "Sequence containing the full set of the receiver's ancestors",
560:                 examples = {
561:                         @Example(expression = "eClass.ancestors()", result = "Sequence{parentEPackage, grandParentEPackage}")
562:                 }
563:         )
564:         // @formatter:on
565:         public List<EObject> ancestors(EObject self) {
566:                 // TODO lazy collection + predicate
567:                 final List<EObject> result = new ArrayList<EObject>();
568:
569:                 EObject container = self.eContainer();
570:•                while (container != null) {
571:                         result.add(container);
572:                         container = container.eContainer();
573:                 }
574:
575:                 return result;
576:         }
577:
578:         // @formatter:off
579:         @Documentation(
580:                 value = "Returns a Sequence containing the set of object's ancestors of the given type.",
581:                 params = {
582:                         @Param(name = "self", value = "The EObject we seek the ancestors of"),
583:                         @Param(name = "filter", value = "The filtering EClass")
584:                 },
585:                 result = "Sequence containing the set of the receiver's ancestors of the given type",
586:                 examples = {
587:                         @Example(expression = "eClass.ancestors(ecore::EPackage)", result = "Sequence{parentEPackage, grandParentEPackage}")
588:                 }
589:         )
590:         // @formatter:on
591:         public List<EObject> ancestors(EObject self, EClass filter) {
592:                 final Set<EClass> filters = Sets.newLinkedHashSet();
593:                 filters.add(filter);
594:
595:                 return ancestors(self, filters);
596:         }
597:
598:         // @formatter:off
599:         @Documentation(
600:                 value = "Returns a Sequence containing the set of object's ancestors of any given types.",
601:                 params = {
602:                         @Param(name = "self", value = "The EObject we seek the ancestors of"),
603:                         @Param(name = "filters", value = "The set of filtering EClasses")
604:                 },
605:                 result = "Sequence containing the set of the receiver's ancestors of any given types",
606:                 examples = {
607:                         @Example(expression = "eClass.ancestors({ecore::EPackage | ecore::EClass})", result = "Sequence{parentEPackage, grandParentEPackage}")
608:                 }
609:         )
610:         // @formatter:on
611:         public List<EObject> ancestors(EObject self, Set<EClass> filters) {
612:                 // TODO lazy collection + predicate
613:                 final List<EObject> result = new ArrayList<EObject>();
614:
615:                 EObject container = self.eContainer();
616:•                while (container != null) {
617:•                        if (eIsInstanceOf(container, filters)) {
618:                                 result.add(container);
619:                         }
620:                         container = container.eContainer();
621:                 }
622:
623:                 return result;
624:         }
625:
626:         // @formatter:off
627:         @Documentation(
628:                 value = "Returns a Sequence containing the full set of object's following siblings.",
629:                 params = {
630:                         @Param(name = "self", value = "The EObject we seek the following siblings of")
631:                 },
632:                 result = "Sequence containing the full set of the receiver's following siblings",
633:                 examples = {
634:                         @Example(expression = "eClass3.followingSiblings()", result = "Sequence{eClass4, eClass5}")
635:                 }
636:         )
637:         // @formatter:on
638:         public List<EObject> followingSiblings(EObject self) {
639:                 // TODO lazy collection
640:                 final List<EObject> result;
641:
642:                 Object container = getContainer(self);
643:•                if (container != null) {
644:                         result = getContentsFrom(container, self);
645:                 } else {
646:                         result = Collections.emptyList();
647:                 }
648:
649:                 return result;
650:         }
651:
652:         // @formatter:off
653:         @Documentation(
654:                 value = "Returns a Sequence containing the set of object's following siblings of the given type.",
655:                 params = {
656:                         @Param(name = "self", value = "The EObject we seek the following siblings of"),
657:                         @Param(name = "filter", value = "The filtering EClass")
658:                 },
659:                 result = "Sequence containing the set of the receiver's following siblings of the given type",
660:                 examples = {
661:                         @Example(expression = "eClass3.followingSiblings(ecore::EClass)", result = "Sequence{eClass4, eClass5}")
662:                 }
663:         )
664:         // @formatter:on
665:         public List<EObject> followingSiblings(EObject self, EClass filter) {
666:                 final Set<EClass> filters = Sets.newLinkedHashSet();
667:                 filters.add(filter);
668:
669:                 return followingSiblings(self, filters);
670:         }
671:
672:         // @formatter:off
673:         @Documentation(
674:                 value = "Returns a Sequence containing the set of object's following siblings of any given types.",
675:                 params = {
676:                         @Param(name = "self", value = "The EObject we seek the following siblings of"),
677:                         @Param(name = "filters", value = "The set of filtering EClasses")
678:                 },
679:                 result = "Sequence containing the set of the receiver's following siblings of any given types",
680:                 examples = {
681:                         @Example(expression = "eClass3.followingSiblings({ecore::EPackage | ecore::EClass})", result = "Sequence{eClass4, eClass5}")
682:                 }
683:         )
684:         // @formatter:on
685:         public List<EObject> followingSiblings(EObject eObject, Set<EClass> filters) {
686:                 // TODO lazy collection
687:                 final List<EObject> result;
688:
689:                 Object container = getContainer(eObject);
690:•                if (container instanceof EObject) {
691:                         result = new ArrayList<EObject>();
692:                         final EStructuralFeature containingFeature = eObject.eContainingFeature();
693:                         final List<EStructuralFeature> followingFeatures = getFollowingFeatures((EObject)container,
694:                                         containingFeature, filters);
695:•                        boolean collect = followingFeatures.size() > 0 && followingFeatures.get(0) != containingFeature;
696:•                        for (EStructuralFeature feature : followingFeatures) {
697:                                 final Object value = ((EObject)container).eGet(feature);
698:•                                if (value instanceof Collection<?>) {
699:•                                        for (Object child : (Collection<?>)value) {
700:•                                                if (child == eObject) {
701:                                                         collect = true;
702:•                                                } else if (collect && child instanceof EObject
703:•                                                                && eIsInstanceOf((EObject)child, filters)) {
704:                                                         result.add((EObject)child);
705:                                                 }
706:                                         }
707:•                                } else if (value == eObject) {
708:                                         collect = true;
709:•                                } else if (collect && value instanceof EObject && eIsInstanceOf((EObject)value, filters)) {
710:                                         result.add((EObject)value);
711:                                 }
712:                         }
713:•                } else if (container instanceof Resource) {
714:                         result = new ArrayList<EObject>();
715:•                        for (EObject eObj : getRootsFrom((Resource)container, eObject)) {
716:•                                if (eIsInstanceOf(eObj, filters)) {
717:                                         result.add(eObj);
718:                                 }
719:                         }
720:                 } else {
721:                         result = Collections.emptyList();
722:                 }
723:
724:                 return result;
725:         }
726:
727:         /**
728:          * Gets the following {@link EStructuralFeature} for the given container and containing feature.
729:          *
730:          * @param container
731:          * the {@link EObject} container
732:          * @param containingFeature
733:          * the containing {@link EStructuralFeature}
734:          * @param filters
735:          * the {@link EClass} filters
736:          * @return the following {@link EStructuralFeature} for the given container and containing feature
737:          */
738:         private List<EStructuralFeature> getFollowingFeatures(EObject container,
739:                         EStructuralFeature containingFeature, Set<EClass> filters) {
740:                 final List<EStructuralFeature> result = new ArrayList<EStructuralFeature>();
741:
742:                 final Set<EStructuralFeature> filteredFeatures = new LinkedHashSet<EStructuralFeature>();
743:•                for (EClass eCls : filters) {
744:                         filteredFeatures.addAll(queryEnvironment.getEPackageProvider().getContainingEStructuralFeatures(
745:                                         eCls));
746:                 }
747:                 final EStructuralFeature[] containmentFeatures = ((FeatureSubsetSupplier)((EObject)container)
748:                                 .eClass().getEAllStructuralFeatures()).containments();
749:                 boolean collect = false;
750:•                for (EStructuralFeature containmentFeature : containmentFeatures) {
751:•                        if (containmentFeature == containingFeature) {
752:                                 collect = true;
753:                         }
754:•                        if (collect && filteredFeatures.contains(containmentFeature)) {
755:                                 result.add(containmentFeature);
756:                         }
757:                 }
758:
759:                 return result;
760:         }
761:
762:         // @formatter:off
763:         @Documentation(
764:                 value = "Returns a Sequence containing the full set of object's preceding siblings.",
765:                 params = {
766:                         @Param(name = "self", value = "The EObject we seek the preceding siblings of")
767:                 },
768:                 result = "Sequence containing the full set of the receiver's preceding siblings",
769:                 examples = {
770:                         @Example(expression = "eClass3.precedingSiblings()", result = "Sequence{eClass1, eClass2}")
771:                 }
772:         )
773:         // @formatter:on
774:         public List<EObject> precedingSiblings(EObject self) {
775:                 // TODO lazy collection
776:                 final List<EObject> result;
777:
778:                 Object container = getContainer(self);
779:•                if (container != null) {
780:                         result = getContentsUntil(container, self);
781:                 } else {
782:                         result = Collections.emptyList();
783:                 }
784:
785:                 return result;
786:         }
787:
788:         // @formatter:off
789:         @Documentation(
790:                 value = "Returns a Sequence containing the set of object's preceding siblings of the given type.",
791:                 params = {
792:                         @Param(name = "self", value = "The EObject we seek the preceding siblings of"),
793:                         @Param(name = "filter", value = "The filtering EClass")
794:                 },
795:                 result = "Sequence containing the set of the receiver's preceding siblings of the given type",
796:                 examples = {
797:                         @Example(expression = "eClass3.precedingSiblings(ecore::EClass)", result = "Sequence{eClass1, eClass2}")
798:                 }
799:         )
800:         // @formatter:on
801:         public List<EObject> precedingSiblings(EObject self, EClass filter) {
802:                 final Set<EClass> filters = Sets.newLinkedHashSet();
803:                 filters.add(filter);
804:
805:                 return precedingSiblings(self, filters);
806:         }
807:
808:         // @formatter:off
809:         @Documentation(
810:                 value = "Returns a Sequence containing the set of object's preceding siblings of any given types.",
811:                 params = {
812:                         @Param(name = "self", value = "The EObject we seek the preceding siblings of"),
813:                         @Param(name = "filters", value = "The set of filtering EClasses")
814:                 },
815:                 result = "Sequence containing the set of the receiver's preceding siblings of any given types",
816:                 examples = {
817:                         @Example(expression = "eClass3.precedingSiblings({ecore::EPackage | ecore::EClass})", result = "Sequence{eClass1, eClass2}")
818:                 }
819:         )
820:         // @formatter:on
821:         public List<EObject> precedingSiblings(EObject eObject, Set<EClass> filters) {
822:                 // TODO lazy collection
823:                 final List<EObject> result;
824:
825:                 Object container = getContainer(eObject);
826:•                if (container instanceof EObject) {
827:                         result = new ArrayList<EObject>();
828:                         final EStructuralFeature containingFeature = eObject.eContainingFeature();
829:                         final List<EStructuralFeature> precedingFeatures = getPrecedingFeatures((EObject)container,
830:                                         containingFeature, filters);
831:•                        finish: for (EStructuralFeature feature : precedingFeatures) {
832:                                 final Object value = ((EObject)container).eGet(feature);
833:•                                if (value instanceof Collection<?>) {
834:•                                        for (Object child : (Collection<?>)value) {
835:•                                                if (child == eObject) {
836:                                                         break finish;
837:•                                                } else if (child instanceof EObject && eIsInstanceOf((EObject)child, filters)) {
838:                                                         result.add((EObject)child);
839:                                                 }
840:                                         }
841:•                                } else if (value == eObject) {
842:                                         break finish;
843:•                                } else if (value instanceof EObject && eIsInstanceOf((EObject)value, filters)) {
844:                                         result.add((EObject)value);
845:                                 }
846:                         }
847:•                } else if (container instanceof Resource) {
848:                         result = new ArrayList<EObject>();
849:•                        for (EObject eObj : getRootsUntil((Resource)container, eObject)) {
850:•                                if (eIsInstanceOf(eObj, filters)) {
851:                                         result.add(eObj);
852:                                 }
853:                         }
854:                 } else {
855:                         result = Collections.emptyList();
856:                 }
857:
858:                 return result;
859:         }
860:
861:         /**
862:          * Gets the preceding {@link EStructuralFeature} for the given container and containing feature.
863:          *
864:          * @param container
865:          * the {@link EObject} container
866:          * @param containingFeature
867:          * the containing {@link EStructuralFeature}
868:          * @param filters
869:          * the {@link EClass} filters
870:          * @return the preceding {@link EStructuralFeature} for the given container and containing feature
871:          */
872:         private List<EStructuralFeature> getPrecedingFeatures(EObject container,
873:                         EStructuralFeature containingFeature, Set<EClass> filters) {
874:                 final List<EStructuralFeature> result = new ArrayList<EStructuralFeature>();
875:
876:                 final Set<EStructuralFeature> filteredFeatures = new LinkedHashSet<EStructuralFeature>();
877:•                for (EClass eCls : filters) {
878:                         filteredFeatures.addAll(queryEnvironment.getEPackageProvider().getContainingEStructuralFeatures(
879:                                         eCls));
880:                 }
881:                 final EStructuralFeature[] containmentFeatures = ((FeatureSubsetSupplier)((EObject)container)
882:                                 .eClass().getEAllStructuralFeatures()).containments();
883:•                for (EStructuralFeature containmentFeature : containmentFeatures) {
884:•                        if (filteredFeatures.contains(containmentFeature)) {
885:                                 result.add(containmentFeature);
886:                         }
887:•                        if (containmentFeature == containingFeature) {
888:                                 break;
889:                         }
890:                 }
891:
892:                 return result;
893:         }
894:
895:         // @formatter:off
896:         @Documentation(
897:                 value = "Returns a Sequence containing the full set of object's siblings.",
898:                 params = {
899:                         @Param(name = "self", value = "The EObject we seek the siblings of")
900:                 },
901:                 result = "Sequence containing the full set of the receiver's siblings",
902:                 examples = {
903:                         @Example(expression = "eClass3.siblings()", result = "Sequence{eClass1, eClass2, eClass4, eClass5}")
904:                 }
905:         )
906:         // @formatter:on
907:         public List<EObject> siblings(EObject self) {
908:                 // TODO lazy collection
909:                 final List<EObject> result;
910:
911:                 Object container = getContainer(self);
912:•                if (container != null) {
913:                         result = getContentsExcluding(container, self);
914:                 } else {
915:                         result = Collections.emptyList();
916:                 }
917:
918:                 return result;
919:         }
920:
921:         // @formatter:off
922:         @Documentation(
923:                 value = "Returns a Sequence containing the set of object's siblings of the given type.",
924:                 params = {
925:                         @Param(name = "self", value = "The EObject we seek the siblings of"),
926:                         @Param(name = "filter", value = "The filtering EClass")
927:                 },
928:                 result = "Sequence containing the set of the receiver's siblings of the given type",
929:                 examples = {
930:                         @Example(expression = "eClass3.siblings(ecore::EClass)", result = "Sequence{eClass1, eClass2, eClass4, eClass5}")
931:                 }
932:         )
933:         // @formatter:on
934:         public List<EObject> siblings(final EObject self, final EClass filter) {
935:                 final Set<EClass> filters = Sets.newLinkedHashSet();
936:                 filters.add(filter);
937:
938:                 return siblings(self, filters);
939:         }
940:
941:         // @formatter:off
942:         @Documentation(
943:                 value = "Returns a Sequence containing the set of object's siblings of any given types.",
944:                 params = {
945:                         @Param(name = "self", value = "The EObject we seek the siblings of"),
946:                         @Param(name = "filters", value = "The set of filtering EClasses")
947:                 },
948:                 result = "Sequence containing the set of the receiver's siblings of any given types",
949:                 examples = {
950:                         @Example(expression = "eClass3.siblings({ecore::EPackage | ecore::EClass})", result = "Sequence{eClass1, eClass2, eClass1, eClass2}")
951:                 }
952:         )
953:         // @formatter:on
954:         public List<EObject> siblings(final EObject eObject, final Set<EClass> filters) {
955:                 // TODO lazy collection
956:                 final List<EObject> result;
957:
958:                 Object container = getContainer(eObject);
959:•                if (container instanceof EObject) {
960:                         result = new ArrayList<EObject>();
961:                         final EStructuralFeature containingFeature = eObject.eContainingFeature();
962:                         final List<EStructuralFeature> features = getFeatures((EObject)container, containingFeature,
963:                                         filters);
964:•                        for (EStructuralFeature containmentFeature : features) {
965:                                 final Object value = ((EObject)container).eGet(containmentFeature);
966:•                                if (value instanceof Collection<?>) {
967:•                                        for (Object child : (Collection<?>)value) {
968:•                                                if (child != eObject && child instanceof EObject
969:•                                                                && eIsInstanceOf((EObject)child, filters)) {
970:                                                         result.add((EObject)child);
971:                                                 }
972:                                         }
973:•                                } else if (value != eObject && value instanceof EObject
974:•                                                && eIsInstanceOf((EObject)value, filters)) {
975:                                         result.add((EObject)value);
976:                                 }
977:                         }
978:•                } else if (container instanceof Resource) {
979:                         result = new ArrayList<EObject>();
980:•                        for (EObject eObj : getRootsExcluding((Resource)container, eObject)) {
981:•                                if (eIsInstanceOf(eObj, filters)) {
982:                                         result.add(eObj);
983:                                 }
984:                         }
985:                 } else {
986:                         result = Collections.emptyList();
987:                 }
988:
989:                 return result;
990:         }
991:
992:         /**
993:          * Gets {@link EStructuralFeature} for the given container and containing feature.
994:          *
995:          * @param container
996:          * the {@link EObject} container
997:          * @param containingFeature
998:          * the containing {@link EStructuralFeature}
999:          * @param filters
1000:          * the {@link EClass} filters
1001:          * @return {@link EStructuralFeature} for the given container and containing feature
1002:          */
1003:         private List<EStructuralFeature> getFeatures(EObject container, EStructuralFeature containingFeature,
1004:                         Set<EClass> filters) {
1005:                 final List<EStructuralFeature> result = new ArrayList<EStructuralFeature>();
1006:
1007:                 final Set<EStructuralFeature> filteredFeatures = new LinkedHashSet<EStructuralFeature>();
1008:•                for (EClass eCls : filters) {
1009:                         filteredFeatures.addAll(queryEnvironment.getEPackageProvider().getContainingEStructuralFeatures(
1010:                                         eCls));
1011:                 }
1012:                 final EStructuralFeature[] containmentFeatures = ((FeatureSubsetSupplier)((EObject)container)
1013:                                 .eClass().getEAllStructuralFeatures()).containments();
1014:•                for (EStructuralFeature containmentFeature : containmentFeatures) {
1015:•                        if (filteredFeatures.contains(containmentFeature)) {
1016:                                 result.add(containmentFeature);
1017:                         }
1018:                 }
1019:
1020:                 return result;
1021:         }
1022:
1023:         /**
1024:          * Obtains the container of an object for the purpose of accessing its siblings. This is often the
1025:          * {@link EObject#eContainer() eContainer}, but for top-level objects it may be the
1026:          * {@link EObject#eResource() eResource}.
1027:          *
1028:          * @param object
1029:          * an object
1030:          * @return its logical container
1031:          */
1032:         private Object getContainer(EObject object) {
1033:                 Object result = object.eContainer();
1034:
1035:•                if (result == null && object instanceof InternalEObject) {
1036:                         // maybe it's a resource root
1037:                         result = ((InternalEObject)object).eDirectResource();
1038:                 }
1039:
1040:                 return result;
1041:         }
1042:
1043:         /**
1044:          * Gets the contents of the given {@link #getContainer(EObject) container} except the given
1045:          * {@link EObject} to exclude.
1046:          *
1047:          * @param container
1048:          * a container of objects
1049:          * @param toExclude
1050:          * the {@link EObject} to exclude
1051:          * @return the contents of the given {@link #getContainer(EObject) container} except the given
1052:          * {@link EObject} to exclude
1053:          */
1054:         private List<EObject> getContentsExcluding(Object container, EObject toExclude) {
1055:                 final List<EObject> contents;
1056:
1057:•                if (container instanceof EObject) {
1058:                         contents = getContentsExcluding((EObject)container, toExclude);
1059:•                } else if (container instanceof Resource) {
1060:                         contents = getRootsExcluding((Resource)container, toExclude);
1061:                 } else {
1062:                         contents = Collections.emptyList();
1063:                 }
1064:
1065:                 return contents;
1066:         }
1067:
1068:         /**
1069:          * Gets the contents of the given {@link #getContainer(EObject) container} until the given {@link EObject}
1070:          * excluded.
1071:          *
1072:          * @param container
1073:          * a container of objects
1074:          * @param until
1075:          * the {@link EObject} to exclude
1076:          * @return the contents of the given {@link #getContainer(EObject) container} until the given
1077:          * {@link EObject} excluded
1078:          */
1079:         private List<EObject> getContentsUntil(Object container, EObject until) {
1080:                 final List<EObject> contents;
1081:
1082:•                if (container instanceof EObject) {
1083:                         contents = getContentsUntil((EObject)container, until);
1084:•                } else if (container instanceof Resource) {
1085:                         contents = getRootsUntil((Resource)container, until);
1086:                 } else {
1087:                         contents = Collections.emptyList();
1088:                 }
1089:
1090:                 return contents;
1091:         }
1092:
1093:         /**
1094:          * Gets the contents of the given {@link #getContainer(EObject) container} from the given {@link EObject}
1095:          * excluded to the end.
1096:          *
1097:          * @param container
1098:          * a container of objects
1099:          * @param from
1100:          * the {@link EObject} to start from excluded
1101:          * @return the contents of the given {@link #getContainer(EObject) container} from the given
1102:          * {@link EObject} excluded to the end
1103:          */
1104:         private List<EObject> getContentsFrom(Object container, EObject from) {
1105:                 final List<EObject> contents;
1106:
1107:•                if (container instanceof EObject) {
1108:                         contents = getContentsFrom((EObject)container, from);
1109:•                } else if (container instanceof Resource) {
1110:                         contents = getRootsFrom((Resource)container, from);
1111:                 } else {
1112:                         contents = Collections.emptyList();
1113:                 }
1114:
1115:                 return contents;
1116:         }
1117:
1118:         /**
1119:          * Elements held by a reference with containment=true and derived=true are not returned by
1120:          * {@link EObject#eContents()}. This allows us to return the list of all contents from an EObject
1121:          * <b>including</b> those references.
1122:          *
1123:          * @param container
1124:          * the containing {@link EObject}
1125:          * @param toExcluse
1126:          * the {@link EObject} to exclude
1127:          * @return The list of all the content of a given EObject, derived containment references included
1128:          */
1129:         private List<EObject> getContentsExcluding(EObject container, EObject toExcluse) {
1130:                 // TODO lazy collection
1131:                 final List<EObject> result = new ArrayList<EObject>();
1132:
1133:                 final EStructuralFeature[] containmentFeatures = ((FeatureSubsetSupplier)container.eClass()
1134:                                 .getEAllStructuralFeatures()).containments();
1135:•                for (final EStructuralFeature feature : containmentFeatures) {
1136:                         final Object value = container.eGet(feature);
1137:•                        if (value instanceof Collection<?>) {
1138:•                                for (Object child : (Collection<?>)value) {
1139:•                                        if (child != toExcluse && child instanceof EObject) {
1140:                                                 result.add((EObject)child);
1141:                                         }
1142:                                 }
1143:•                        } else if (value != toExcluse && value instanceof EObject) {
1144:                                 result.add((EObject)value);
1145:                         }
1146:                 }
1147:
1148:                 return result;
1149:         }
1150:
1151:         /**
1152:          * Gets the content of the given {@link EObject} until the given contained {@link EObject}.
1153:          *
1154:          * @param container
1155:          * the {@link EObject} we seek the content of
1156:          * @param until
1157:          * the {@link EObject} to exclude
1158:          * @return the content of the given {@link EObject} until the given contained {@link EObject}
1159:          */
1160:         private List<EObject> getContentsUntil(EObject container, EObject until) {
1161:                 // TODO lazy collection
1162:                 final List<EObject> result = new ArrayList<EObject>();
1163:
1164:                 final EStructuralFeature[] containmentFeatures = ((FeatureSubsetSupplier)container.eClass()
1165:                                 .getEAllStructuralFeatures()).containments();
1166:•                finish: for (final EStructuralFeature feature : containmentFeatures) {
1167:                         final Object value = container.eGet(feature);
1168:•                        if (value instanceof Collection<?>) {
1169:•                                for (Object child : (Collection<?>)value) {
1170:•                                        if (child == until) {
1171:                                                 break finish;
1172:•                                        } else if (child instanceof EObject) {
1173:                                                 result.add((EObject)child);
1174:                                         }
1175:                                 }
1176:•                        } else if (value == until) {
1177:                                 break finish;
1178:•                        } else if (value instanceof EObject) {
1179:                                 result.add((EObject)value);
1180:                         }
1181:                 }
1182:
1183:                 return result;
1184:         }
1185:
1186:         /**
1187:          * Gets the content of the given {@link EObject} from the given contained {@link EObject} until the end.
1188:          *
1189:          * @param container
1190:          * the {@link EObject} we seek the content of
1191:          * @param until
1192:          * the {@link EObject} start excluded
1193:          * @return the content of the given {@link EObject} from the given contained {@link EObject} until the end
1194:          */
1195:         private List<EObject> getContentsFrom(EObject container, EObject until) {
1196:                 // TODO lazy collection
1197:                 final List<EObject> result = new ArrayList<EObject>();
1198:
1199:                 boolean collect = false;
1200:                 final EStructuralFeature[] containmentFeatures = ((FeatureSubsetSupplier)container.eClass()
1201:                                 .getEAllStructuralFeatures()).containments();
1202:•                for (final EStructuralFeature feature : containmentFeatures) {
1203:                         final Object value = container.eGet(feature);
1204:•                        if (value instanceof Collection<?>) {
1205:•                                for (Object child : (Collection<?>)value) {
1206:•                                        if (child == until) {
1207:                                                 collect = true;
1208:•                                        } else if (collect && child instanceof EObject) {
1209:                                                 result.add((EObject)child);
1210:                                         }
1211:                                 }
1212:•                        } else if (value == until) {
1213:                                 collect = true;
1214:•                        } else if (collect && value instanceof EObject) {
1215:                                 result.add((EObject)value);
1216:                         }
1217:                 }
1218:
1219:                 return result;
1220:         }
1221:
1222:         /**
1223:          * Like the standard {@link Resource#getContents()} method except that we retrieve only objects that do
1224:          * not have containers (i.e., they are not cross-resource-contained). This is an important distinction
1225:          * because we want only peers (or "siblings") of an object that is a root (having no container), and those
1226:          * are defined as the other objects that are also roots.
1227:          *
1228:          * @param resource
1229:          * a resource from which to get root objects
1230:          * @param toExclude
1231:          * the {@link EObject} to exclude
1232:          * @return the root objects. <b>Note</b> that, for efficiency, the resulting list may be the
1233:          * {@code resource}'s actual contents list. Callers must treat the result as unmodifiable
1234:          */
1235:         private List<EObject> getRootsExcluding(Resource resource, EObject toExclude) {
1236:                 // TODO use lazy collection
1237:                 final List<EObject> result = new ArrayList<EObject>();
1238:
1239:•                for (EObject eObj : resource.getContents()) {
1240:•                        if (eObj != toExclude && eObj.eContainer() == null) {
1241:                                 result.add(eObj);
1242:                         }
1243:                 }
1244:
1245:                 return result;
1246:         }
1247:
1248:         /**
1249:          * Gets the content root of the given resource until the given {@link EObject}.
1250:          *
1251:          * @param resource
1252:          * a resource from which to get root objects
1253:          * @param until
1254:          * the {@link EObject} to exclude
1255:          * @return the content root of the given resource until the given {@link EObject}
1256:          */
1257:         private List<EObject> getRootsUntil(Resource resource, EObject until) {
1258:                 // TODO use lazy collection
1259:                 final List<EObject> result = new ArrayList<EObject>();
1260:
1261:•                for (EObject eObj : resource.getContents()) {
1262:•                        if (eObj == until) {
1263:                                 break;
1264:•                        } else if (eObj.eContainer() == null) {
1265:                                 result.add(eObj);
1266:                         }
1267:                 }
1268:
1269:                 return result;
1270:         }
1271:
1272:         /**
1273:          * Gets the content root of the given resource from the given {@link EObject} until the end.
1274:          *
1275:          * @param resource
1276:          * a resource from which to get root objects
1277:          * @param from
1278:          * the {@link EObject} to start excluded
1279:          * @return the content root of the given resource from the given {@link EObject} until the end
1280:          */
1281:         private List<EObject> getRootsFrom(Resource resource, EObject from) {
1282:                 // TODO use lazy collection
1283:                 final List<EObject> result = new ArrayList<EObject>();
1284:
1285:                 boolean collect = false;
1286:•                for (EObject eObj : resource.getContents()) {
1287:•                        if (eObj == from) {
1288:                                 collect = true;
1289:•                        } else if (collect && eObj.eContainer() == null) {
1290:                                 result.add(eObj);
1291:                         }
1292:                 }
1293:
1294:                 return result;
1295:         }
1296:
1297:         /**
1298:          * Add the IType instance corresponding to ecore::EObject to the set using the given
1299:          * {@link IReadOnlyQueryEnvironment} to resolve it.
1300:          *
1301:          * @param queryEnvironment
1302:          * types the Set to update.
1303:          * @param queryEnvironment
1304:          * the {@link IReadOnlyQueryEnvironment}
1305:          * @return the {@link EObject} {@link EClassifier} for the given {@link IReadOnlyQueryEnvironment} if any,
1306:          * <code>null</code> otherwise
1307:          */
1308:         private static void addEObjectEClass(Set<IType> types, IReadOnlyQueryEnvironment queryEnvironment) {
1309:•                for (EClassifier classifier : queryEnvironment.getEPackageProvider().getTypes("ecore", "EObject")) {
1310:                         types.add(new EClassifierType(queryEnvironment, classifier));
1311:                 }
1312:         }
1313:
1314:         /**
1315:          * Tells if the given {@link EObject} is an instance of one of the given {@link EClass}.
1316:          *
1317:          * @param value
1318:          * the {@link EObject} to check
1319:          * @param types
1320:          * the {@link Set} of {@link EClass}
1321:          * @return <code>true</code> if the given {@link EObject} is an instance of one of the given
1322:          * {@link EClass}, <code>false</code> otherwise
1323:          */
1324:         private boolean eIsInstanceOf(EObject value, Set<EClass> types) {
1325:•                for (EClass type : types) {
1326:•                        if (type.isSuperTypeOf(((EObject)value).eClass()) || type.isInstance(value)) {
1327:                                 return true;
1328:                         }
1329:                 }
1330:                 return false;
1331:         }
1332:
1333: }