eclipse / Xpect

This repository has been rewritten to move to the Eclipse Foundation. Find the old history here: https://github.com/TypeFox/Xpect
http://www.xpect-tests.org/
Eclipse Public License 2.0
30 stars 28 forks source link

Xpect creates two language injectors which can lead to singleton violations wrt. injected instances #233

Open lbeurerkellner opened 6 years ago

lbeurerkellner commented 6 years ago

In the getInjector method of AbstractLanguageInfo Xpect first creates a default injector in order to obtain instances of the moduleClasses. However, later on it goes on and creates another injector, which is used to inject the actual instance components using a slightly modified runtime module.

I suppose the original intention behind this code is that the first "default" injector is only used briefly and then dismissed. However, this assumption does not hold true when used in combination with eager singletons (cf. Guice Eager Singletons).

When creating a new Xtext language (using the wizard), the generated abstract runtime module Abstract<language name>RuntimeModule declares an eager-singleton binding for the main validator of the language:

(...)
// contributed by org.eclipse.xtext.xtext.generator.validation.ValidatorFragment2
@SingletonBinding(eager=true)
public Class<? extends <language name>Validator> bind<language name>Validator() {
    return <language name>Validator.class;
}
(...)

In Guice terms this means that whenever a new injector is created based on such a module, the validator instance is created immediately and all its fields and methods are injected. As a consequence, an AbstractInjectableValidator, as it is common in Xtext, is registered with the global EMF EValidatorRegistrar (cf. AbstractInjectableValidator.java:45 in eclipse/xtext-core).

In the abovementioned code, this registration is performed twice, first for the validator instance of the default injector, and later for the validator instance of the actual injector. However, since the EValidatorRegistrar maintains uniqueness among validators based on class name / FQN, this second registration is ignored. Thus, when running validation in an Xpect test, the validator instances in use were actually injected by the default injector and therefore depend on their own set of singletons. In particular, this provokes an inconsistency between other components (e.g. the parser) and the validators with regard to singleton assumptions (e.g. the identities of grammar rule elements via grammar access do not match).

I would suspect that this situation is generally unintended and invalid, but please let me know if I understand anything incorrectly. Furthermore, I mostly came here to start a discussion, as I am not sure how to solve the issue described here. I am looking forward to hear from you about this.