[generator] Added new Xbase and Xtype fragments

Signed-off-by: Miro Spönemann <miro.spoenemann@itemis.de>
This commit is contained in:
Miro Spönemann 2015-07-09 14:17:00 +02:00
parent cbae054be0
commit e3bd95a4f6
11 changed files with 797 additions and 14 deletions

View file

@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2014 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext.xtext.generator
import org.eclipse.xtext.xtext.generator.IGeneratorFragment2
import org.eclipse.emf.mwe.core.issues.Issues
import com.google.inject.Injector
abstract class AbstractGeneratorFragment2 implements IGeneratorFragment2 {
override checkConfiguration(XtextGenerator generator, Issues issues) {
// Override this method to check the configured properties of this fragment
}
override initialize(Injector injector) {
injector.injectMembers(this)
}
}

View file

@ -0,0 +1,170 @@
/**
* Copyright (c) 2011 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.xtext.xtext.generator
import org.eclipse.emf.codegen.ecore.genmodel.GenClass
import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier
import org.eclipse.emf.codegen.ecore.genmodel.GenDataType
import org.eclipse.emf.codegen.ecore.genmodel.GenEnum
import org.eclipse.emf.codegen.ecore.genmodel.GenFeature
import org.eclipse.emf.codegen.ecore.genmodel.GenModel
import org.eclipse.emf.codegen.ecore.genmodel.GenPackage
import org.eclipse.emf.ecore.EClass
import org.eclipse.emf.ecore.EClassifier
import org.eclipse.emf.ecore.EDataType
import org.eclipse.emf.ecore.EEnum
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.EPackage
import org.eclipse.emf.ecore.EStructuralFeature
import org.eclipse.emf.ecore.EcorePackage
import org.eclipse.emf.ecore.plugin.EcorePlugin
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.emf.ecore.resource.ResourceSet
class GenModelUtil {
def static GenClass getGenClass(EClass cls, ResourceSet resourceSet) {
return getGenClassifier(cls, resourceSet) as GenClass
}
def static GenClassifier getGenClassifier(EClassifier cls, ResourceSet resourceSet) {
val genPackage = getGenPackage(cls.EPackage, resourceSet)
for (genCls : genPackage.genClassifiers) {
if (cls.name == genCls.ecoreClassifier.name) {
return genCls
}
}
throw new RuntimeException('''No GenClassifier named '«cls.name»' found in GenModel «genPackage.eResource.URI»''')
}
def static GenDataType getGenDataType(EDataType dt, ResourceSet resourceSet) {
return getGenClassifier(dt, resourceSet) as GenDataType
}
def static GenEnum getGenEnum(EEnum en, ResourceSet resourceSet) {
return getGenClassifier(en, resourceSet) as GenEnum
}
def static GenFeature getGenFeature(EStructuralFeature feature, ResourceSet resourceSet) {
val genCls = getGenClassifier(feature.EContainingClass, resourceSet) as GenClass
for (genFeat : genCls.genFeatures) {
if (feature.name == genFeat.ecoreFeature.name) {
return genFeat
}
}
throw new RuntimeException('''No GenFeature named '«feature.name»' found in GenClass '«genCls»' from GenModel«genCls.eResource.URI»''')
}
def static String getGenIntLiteral(EClass clazz, EStructuralFeature feature, ResourceSet resourceSet) {
val genFeature = getGenFeature(feature, resourceSet)
val genClass = getGenClass(clazz, resourceSet)
return genClass.genPackage.packageInterfaceName + '.' + genClass.getFeatureID(genFeature)
}
def static String getGenIntLiteral(EClassifier classifier, ResourceSet resourceSet) {
val genClassifier = getGenClassifier(classifier, resourceSet)
return genClassifier.genPackage.packageInterfaceName + '.' + genClassifier.classifierID
}
def static GenPackage getGenPackage(EPackage pkg, ResourceSet resourceSet) {
val nsURI = pkg.nsURI
var String location
if (pkg.eResource?.URI !== null)
location = pkg.eResource.URI.toString
val genModelResource = getGenModelResource(location, nsURI, resourceSet)
if (genModelResource !== null) {
for (model : genModelResource.contents) {
if (model instanceof GenModel) {
val genPkg = model.findGenPackage(pkg)
if (genPkg !== null) {
genPkg.getEcorePackage.getEClassifiers()
return genPkg
}
}
}
throw new RuntimeException('''No GenPackage for NsURI «nsURI» found in «genModelResource.URI»''')
}
throw new RuntimeException('''No GenPackage for NsURI «nsURI».''')
}
def static Resource getGenModelResource(String locationInfo, String nsURI, ResourceSet resourceSet) {
val genModelURI = EcorePlugin.getEPackageNsURIToGenModelLocationMap(false).get(nsURI)
if (genModelURI === null) {
if (EcorePackage.eNS_URI.equals(nsURI)) // If we really want to use the registered ecore ...
return null // look into the resource set to find a genpackage for the given URI
for (res : resourceSet.resources) {
// We only look into the first level, as genmodels are usually among the top level elements.
// This is just to avoid traversing all eobjects in the resource set.
for (obj : res.contents) {
if (obj instanceof GenModel) {
for (genPackage : obj.genPackages) {
if (genPackage.NSURI.equals(nsURI)) {
return genPackage.eResource
}
}
}
}
}
val buf = new StringBuilder
var loc = locationInfo
if (loc !== null && loc.length > 0)
loc = ' from ' + loc
else
loc = ''
buf.append("Could not find a GenModel for EPackage '").append(nsURI).append("'").append(loc).append("\n")
// TODO replace with references to new fragments
buf.append('''If the missing GenModel has been generated via EMFGeneratorFragment.class.getSimpleName() or org.eclipse.xtext.generator.ecore.EcoreGeneratorFragment.class.getSimpleName()''')
buf.append(" make sure to run it first in the workflow.\n")
buf.append('''If you have a *.genmodel-file, make sure to register it via StandaloneSetup.registerGenModelFile(String)''')
throw new RuntimeException(buf.toString)
}
if (resourceSet === null)
throw new RuntimeException('''There is no ResourceSet for EPackage '«nsURI»'. Please make sure the EPackage has been loaded from a .ecore file and not from the generated Java file.''')
val genModelResource = resourceSet.getResource(genModelURI, true)
if (genModelResource === null)
throw new RuntimeException('''Error loading GenModel «genModelURI»''')
for (EObject content : genModelResource.contents) {
if (content instanceof GenModel)
content.reconcile()
}
return genModelResource
}
def static String getGenTypeLiteral(EClassifier classifier, ResourceSet resourceSet) {
// inspired by org.eclipse.emf.codegen.ecore.genmodel.impl.GenClassifierImpl.getQualifiedClassifierAccessor()
val genClassifier = getGenClassifier(classifier, resourceSet)
var String pkg = genClassifier.genPackage.packageInterfaceName
if (genClassifier.genPackage.isLiteralsInterface)
return pkg + '.Literals.' + genClassifier.classifierID
else
return pkg + '.eINSTANCE.get' + genClassifier.classifierAccessorName + '()'
}
def static String getGenTypeLiteral(EPackage pkg, ResourceSet resourceSet) {
return getGenPackage(pkg, resourceSet).packageInterfaceName + '.eINSTANCE'
}
def static String getGenTypeLiteral(EStructuralFeature feature, ResourceSet resourceSet) {
// inspired by org.eclipse.emf.codegen.ecore.genmodel.impl.GenFeatureImpl.getQualifiedFeatureAccessor()
val genFeature = getGenFeature(feature, resourceSet)
val pkg = genFeature.genPackage.packageInterfaceName
if (genFeature.genPackage.isLiteralsInterface)
return pkg + '.Literals.' + genFeature.genClass.getFeatureID(genFeature)
else
return pkg + '.eINSTANCE.get' + genFeature.featureAccessorName + '()'
}
def static String getJavaTypeName(EClassifier classifier, ResourceSet resourceSet) {
val genClassifier = getGenClassifier(classifier, resourceSet)
if (genClassifier instanceof GenClass)
return genClassifier.qualifiedInterfaceName
else
return (genClassifier as GenDataType).qualifiedInstanceClassName
}
}

View file

@ -39,7 +39,7 @@ import org.eclipse.xtext.resource.impl.ResourceDescriptionsData
import org.eclipse.xtext.util.internal.Log
import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess
import org.eclipse.xtext.xtext.generator.model.StandaloneSetupAccess
import org.eclipse.xtext.xtext.generator.model.TypeReference
import org.eclipse.xtext.xtext.generator.xbase.XbaseGeneratorFragment2
import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.*
@ -83,7 +83,7 @@ class LanguageConfig2 extends CompositeGeneratorFragment2 {
}
def void setFileExtensions(String fileExtensions) {
this.fileExtensions = fileExtensions.trim.split("\\s*,\\s*").toList
this.fileExtensions = fileExtensions.trim.split('\\s*,\\s*').toList
}
def List<String> getFileExtensions() {
@ -254,11 +254,11 @@ class LanguageConfig2 extends CompositeGeneratorFragment2 {
}
override generate(LanguageConfig2 language) {
addImplicitContributions()
addImplicitContributions(language)
super.generate(language)
}
protected def void addImplicitContributions() {
protected def void addImplicitContributions(LanguageConfig2 language) {
if (projectConfig.runtimeManifest !== null) {
projectConfig.runtimeManifest.requiredBundles.addAll(#[
'org.eclipse.xtext', 'org.eclipse.xtext.util'
@ -270,10 +270,19 @@ class LanguageConfig2 extends CompositeGeneratorFragment2 {
'org.eclipse.xtext.ui', 'org.eclipse.xtext.ui.shared', 'org.eclipse.ui.editors', 'org.eclipse.ui'
])
}
val StringConcatenationClient expression = '''«'org.eclipse.xtext.ui.shared.Access'.typeRef».getJavaProjectsState()'''
new GuiceModuleAccess.BindingFactory()
.addTypeToProviderInstance(new TypeReference(IAllContainersState), expression)
.contributeTo(eclipsePluginGenModule)
val bindingFactory = new GuiceModuleAccess.BindingFactory()
.addTypeToProviderInstance(IAllContainersState.typeRef, expression)
if (XbaseGeneratorFragment2.inheritsXbase(language.grammar)) {
bindingFactory.addTypeToType('org.eclipse.xtext.ui.editor.XtextEditor'.typeRef,
'org.eclipse.xtext.xbase.ui.editor.XbaseEditor'.typeRef)
.addTypeToType('org.eclipse.xtext.ui.editor.model.XtextDocumentProvider'.typeRef,
'org.eclipse.xtext.xbase.ui.editor.XbaseDocumentProvider'.typeRef)
.addTypeToType('org.eclipse.xtext.ui.generator.trace.OpenGeneratedFileHandler'.typeRef,
'org.eclipse.xtext.xbase.ui.generator.trace.XbaseOpenGeneratedFileHandler'.typeRef)
}
bindingFactory.contributeTo(eclipsePluginGenModule)
}
}

View file

@ -29,6 +29,7 @@ import org.eclipse.xtext.Grammar
import org.eclipse.xtext.XtextStandaloneSetup
import org.eclipse.xtext.util.MergeableManifest
import org.eclipse.xtext.util.internal.Log
import org.eclipse.xtext.xtext.generator.model.FileSystemAccess
import org.eclipse.xtext.xtext.generator.model.ManifestAccess
import org.eclipse.xtext.xtext.generator.model.TypeReference
@ -53,6 +54,8 @@ class XtextGenerator extends AbstractWorkflowComponent2 implements IGuiceAwareGe
@Inject XtextGeneratorTemplates templates
@Inject extension FileSystemAccess.Extensions
new() {
new XtextStandaloneSetup().createInjectorAndDoEMFRegistration()
}
@ -123,17 +126,17 @@ class XtextGenerator extends AbstractWorkflowComponent2 implements IGuiceAwareGe
protected def generateRuntimeSetup(LanguageConfig2 language) {
templates.createRuntimeGenSetup(language).writeTo(projectConfig.runtimeSrcGen)
if (!projectConfig.runtimeSrc.isFile(language.naming.runtimeSetup.path))
if (!projectConfig.runtimeSrc.containsJavaFile(language.naming.runtimeSetup))
templates.createRuntimeSetup(language).writeTo(projectConfig.runtimeSrc)
}
protected def generateModules(LanguageConfig2 language) {
templates.createRuntimeGenModule(language).writeTo(projectConfig.runtimeSrcGen)
if (!projectConfig.runtimeSrc.isFile(language.naming.runtimeModule.path))
if (!projectConfig.runtimeSrc.containsJavaFile(language.naming.runtimeModule))
templates.createRuntimeModule(language).writeTo(projectConfig.runtimeSrc)
if (projectConfig.eclipsePluginSrcGen !== null)
templates.createEclipsePluginGenModule(language).writeTo(projectConfig.eclipsePluginSrcGen)
if (projectConfig.eclipsePluginSrc !== null && !projectConfig.eclipsePluginSrc.isFile(language.naming.eclipsePluginModule.path))
if (projectConfig.eclipsePluginSrc !== null && !projectConfig.eclipsePluginSrc.containsJavaFile(language.naming.eclipsePluginModule))
templates.createEclipsePluginModule(language).writeTo(projectConfig.eclipsePluginSrc)
}

View file

@ -22,6 +22,18 @@ import org.eclipse.xtext.xtext.generator.IGuiceAwareGeneratorComponent
class FileSystemAccess implements IFileSystemAccess2, IGuiceAwareGeneratorComponent {
static class Extensions {
def boolean containsJavaFile(IFileSystemAccess2 fsa, TypeReference typeRef) {
fsa.isFile(typeRef.path + '.java')
}
def boolean containsXtendFile(IFileSystemAccess2 fsa, TypeReference typeRef) {
fsa.isFile(typeRef.path + '.xtend')
}
}
@Inject IEncodingProvider encodingProvider
val URI baseUri

View file

@ -43,7 +43,11 @@ class JavaFileAccess extends TextFileAccess {
throw new IllegalArgumentException('Nested type cannot be serialized: ' + typeRef)
this.javaType = typeRef
this.codeConfig = codeConfig
setPath(typeRef.path)
setPath(typeRef.path + '.' + fileExtension)
}
protected def String getFileExtension() {
'java'
}
def String importType(TypeReference typeRef) {
@ -83,6 +87,10 @@ class JavaFileAccess extends TextFileAccess {
setContent(javaStringConcat)
}
protected def boolean appendSemicolons() {
true
}
override generate() {
val classAnnotations = annotations + codeConfig.classAnnotations.filter[appliesTo(this)]
classAnnotations.forEach[importType(annotationImport)]
@ -90,10 +98,10 @@ class JavaFileAccess extends TextFileAccess {
Collections.sort(sortedImports)
return '''
«codeConfig.fileHeader»
package «javaType.packageName»;
package «javaType.packageName»«IF appendSemicolons»;«ENDIF»
«FOR importName : sortedImports»
import «importName»;
import «importName»«IF appendSemicolons»;«ENDIF»
«ENDFOR»
«typeComment»

View file

@ -118,7 +118,7 @@ class TypeReference {
}
def String getPath() {
return packageName.replace('.', '/') + '/' + simpleNames.head + '.java'
return packageName.replace('.', '/') + '/' + simpleNames.head
}
}

View file

@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext.xtext.generator.model
import org.eclipse.xtext.xtext.generator.CodeConfig
class XtendFileAccess extends JavaFileAccess {
new(String qualifiedName, CodeConfig codeConfig) {
super(qualifiedName, codeConfig)
}
new(TypeReference typeRef, CodeConfig codeConfig) {
super(typeRef, codeConfig)
}
override protected getFileExtension() {
'xtend'
}
override protected appendSemicolons() {
false
}
}

View file

@ -0,0 +1,483 @@
/*******************************************************************************
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext.xtext.generator.xbase
import com.google.inject.Inject
import com.google.inject.name.Names
import java.util.Set
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend2.lib.StringConcatenationClient
import org.eclipse.xtext.AbstractRule
import org.eclipse.xtext.Grammar
import org.eclipse.xtext.GrammarUtil
import org.eclipse.xtext.naming.IQualifiedNameProvider
import org.eclipse.xtext.parser.IEncodingProvider
import org.eclipse.xtext.resource.ILocationInFileProvider
import org.eclipse.xtext.scoping.IGlobalScopeProvider
import org.eclipse.xtext.scoping.IScopeProvider
import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider
import org.eclipse.xtext.validation.IResourceValidator
import org.eclipse.xtext.xtext.UsedRulesFinder
import org.eclipse.xtext.xtext.generator.AbstractGeneratorFragment2
import org.eclipse.xtext.xtext.generator.CodeConfig
import org.eclipse.xtext.xtext.generator.IXtextProjectConfig
import org.eclipse.xtext.xtext.generator.LanguageConfig2
import org.eclipse.xtext.xtext.generator.model.FileSystemAccess
import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess
import org.eclipse.xtext.xtext.generator.model.TypeReference
import org.eclipse.xtext.xtext.generator.model.XtendFileAccess
import static extension org.eclipse.xtext.xtext.generator.GenModelUtil.*
import static extension org.eclipse.xtext.xtext.generator.model.TypeReference.*
@Accessors(PUBLIC_SETTER)
class XbaseGeneratorFragment2 extends AbstractGeneratorFragment2 {
static def boolean inheritsXbase(Grammar grammar) {
GrammarUtil.inherits(grammar, 'org.eclipse.xtext.xbase.Xbase')
}
static def boolean inheritsXbaseWithAnnotations(Grammar grammar) {
GrammarUtil.inherits(grammar, 'org.eclipse.xtext.xbase.annotations.XbaseWithAnnotations')
}
static def boolean usesXImportSection(Grammar grammar) {
val Set<AbstractRule> usedRules = newHashSet
new UsedRulesFinder(usedRules).compute(grammar)
return usedRules.exists[name == 'XImportSection' && GrammarUtil.getGrammar(it).name == 'org.eclipse.xtext.xbase.Xtype']
}
boolean generateXtendInferrer = true
boolean useInferredJvmModel = true
boolean jdtTypeHierarchy = true
boolean jdtCallHierarchy = true
boolean skipExportedPackage = false
@Inject IXtextProjectConfig projectConfig
@Inject CodeConfig codeConfig
@Inject IEncodingProvider encodingProvider
@Inject extension FileSystemAccess.Extensions
def TypeReference getJvmModelInferrer(LanguageConfig2 langConfig) {
new TypeReference(langConfig.naming.runtimeBasePackage + '.jvmmodel.' + GrammarUtil.getName(langConfig.grammar) + 'JvmModelInferrer')
}
def TypeReference getImportScopeProvider(LanguageConfig2 langConfig) {
if (langConfig.grammar.usesXImportSection)
'org.eclipse.xtext.xbase.scoping.XImportSectionNamespaceScopeProvider'.typeRef
else
'org.eclipse.xtext.xbase.scoping.XbaseImportedNamespaceScopeProvider'.typeRef
}
override generate(LanguageConfig2 language) {
if (!language.grammar.inheritsXbase)
return;
addRuntimeGuiceBindings(language)
addEclipsePluginGuiceBindings(language)
if (projectConfig.eclipsePluginPluginXml !== null)
addEclipsePluginExtensions(language)
if (!projectConfig.runtimeSrc.containsXtendFile(language.jvmModelInferrer))
doGenerateXtendInferrer(language)
if (projectConfig.runtimeManifest !== null) {
projectConfig.runtimeManifest.requiredBundles.addAll(#[
'org.eclipse.xtext.xbase', 'org.eclipse.xtext.xbase.lib'
])
if ((generateXtendInferrer || useInferredJvmModel) && !skipExportedPackage) {
projectConfig.runtimeManifest.exportedPackages += language.jvmModelInferrer.packageName
}
}
if (projectConfig.eclipsePluginManifest !== null) {
projectConfig.eclipsePluginManifest.requiredBundles.addAll(#[
'org.eclipse.xtext.xbase.ui', 'org.eclipse.jdt.debug.ui'
])
}
}
protected def addRuntimeGuiceBindings(LanguageConfig2 language) {
val bindingFactory = new GuiceModuleAccess.BindingFactory()
// overrides binding from org.eclipse.xtext.generator.exporting.QualifiedNamesFragment
.addTypeToType(IQualifiedNameProvider.typeRef,
'org.eclipse.xtext.xbase.scoping.XbaseQualifiedNameProvider'.typeRef)
if (useInferredJvmModel) {
bindingFactory
.addTypeToType(ILocationInFileProvider.typeRef,
'org.eclipse.xtext.xbase.jvmmodel.JvmLocationInFileProvider'.typeRef)
.addTypeToType(IGlobalScopeProvider.typeRef,
'org.eclipse.xtext.common.types.xtext.TypesAwareDefaultGlobalScopeProvider'.typeRef)
.addTypeToType('org.eclipse.xtext.xbase.validation.FeatureNameValidator'.typeRef,
'org.eclipse.xtext.xbase.validation.LogicalContainerAwareFeatureNameValidator'.typeRef)
.addTypeToType('org.eclipse.xtext.xbase.typesystem.internal.DefaultBatchTypeResolver'.typeRef,
'org.eclipse.xtext.xbase.typesystem.internal.LogicalContainerAwareBatchTypeResolver'.typeRef)
.addTypeToType('org.eclipse.xtext.xbase.typesystem.internal.DefaultReentrantTypeResolver'.typeRef,
'org.eclipse.xtext.xbase.typesystem.internal.LogicalContainerAwareReentrantTypeResolver'.typeRef)
.addTypeToType(IResourceValidator.typeRef,
'org.eclipse.xtext.xbase.annotations.validation.DerivedStateAwareResourceValidator'.typeRef)
if (generateXtendInferrer) {
bindingFactory
.addTypeToType('org.eclipse.xtext.xbase.jvmmodel.IJvmModelInferrer'.typeRef, language.jvmModelInferrer)
}
} else {
bindingFactory
.addTypeToType(ILocationInFileProvider.typeRef,
'org.eclipse.xtext.xbase.resource.XbaseLocationInFileProvider'.typeRef)
}
if (language.grammar.usesXImportSection) {
val StringConcatenationClient statement = '''
binder.bind(«IScopeProvider».class).annotatedWith(«Names».named(«AbstractDeclarativeScopeProvider».NAMED_DELEGATE)).to(«language.importScopeProvider».class);
'''
bindingFactory
.addConfiguredBinding(IScopeProvider.simpleName + 'Delegate', statement);
}
bindingFactory.contributeTo(language.runtimeGenModule)
if (language.grammar.inheritsXbaseWithAnnotations)
language.runtimeGenModule.superClass = 'org.eclipse.xtext.xbase.annotations.DefaultXbaseWithAnnotationsRuntimeModule'.typeRef
else
language.runtimeGenModule.superClass = 'org.eclipse.xtext.xbase.DefaultXbaseRuntimeModule'.typeRef
}
protected def addEclipsePluginGuiceBindings(LanguageConfig2 language) {
val bindingFactory = new GuiceModuleAccess.BindingFactory()
if (useInferredJvmModel) {
val StringConcatenationClient statement = '''
if («'org.eclipse.ui.PlatformUI'.typeRef».isWorkbenchRunning()) {
binder.bind(«'org.eclipse.xtext.ui.editor.IURIEditorOpener'.typeRef».class).annotatedWith(«'org.eclipse.xtext.ui.LanguageSpecific'.typeRef».class).to(«'org.eclipse.xtext.xbase.ui.jvmmodel.navigation.DerivedMemberAwareEditorOpener'.typeRef».class);
binder.bind(«'org.eclipse.xtext.common.types.ui.navigation.IDerivedMemberAwareEditorOpener'.typeRef».class).to(«'org.eclipse.xtext.xbase.ui.jvmmodel.navigation.DerivedMemberAwareEditorOpener'.typeRef».class);
}
'''
// Rename refactoring
bindingFactory
.addTypeToType('org.eclipse.xtext.ui.editor.findrefs.FindReferencesHandler'.typeRef,
'org.eclipse.xtext.xbase.ui.jvmmodel.findrefs.JvmModelFindReferenceHandler'.typeRef)
.addTypeToType('org.eclipse.xtext.ui.editor.findrefs.ReferenceQueryExecutor'.typeRef,
'org.eclipse.xtext.xbase.ui.jvmmodel.findrefs.JvmModelReferenceQueryExecutor'.typeRef)
// overrides binding from org.eclipse.xtext.generator.exporting.QualifiedNamesFragment
.addTypeToType('org.eclipse.xtext.ui.refactoring.IDependentElementsCalculator'.typeRef,
'org.eclipse.xtext.xbase.ui.jvmmodel.refactoring.JvmModelDependentElementsCalculator'.typeRef)
// overrides binding from RefactorElementNameFragment
.addTypeToType('org.eclipse.xtext.ui.refactoring.IRenameRefactoringProvider'.typeRef,
'org.eclipse.xtext.xbase.ui.jvmmodel.refactoring.jdt.CombinedJvmJdtRenameRefactoringProvider'.typeRef)
// overrides binding from RefactorElementNameFragment
.addTypeToType('org.eclipse.xtext.ui.refactoring.IReferenceUpdater'.typeRef,
'org.eclipse.xtext.xbase.ui.refactoring.XbaseReferenceUpdater'.typeRef)
// overrides binding from RefactorElementNameFragment
.addfinalTypeToType('org.eclipse.xtext.ui.refactoring.ui.IRenameContextFactory'.typeRef,
'org.eclipse.xtext.xbase.ui.jvmmodel.refactoring.jdt.CombinedJvmJdtRenameContextFactory'.typeRef)
// overrides binding from RefactorElementNameFragment
.addTypeToType('org.eclipse.xtext.ui.refactoring.IRenameStrategy'.typeRef,
'org.eclipse.xtext.xbase.ui.jvmmodel.refactoring.DefaultJvmModelRenameStrategy'.typeRef)
.addTypeToType('org.eclipse.xtext.common.types.ui.refactoring.participant.JdtRenameParticipant.ContextFactory'.typeRef,
'org.eclipse.xtext.xbase.ui.jvmmodel.refactoring.JvmModelJdtRenameParticipantContext.ContextFactory'.typeRef)
.addTypeToType('org.eclipse.xtext.ui.editor.outline.impl.OutlineNodeElementOpener'.typeRef,
'org.eclipse.xtext.xbase.ui.jvmmodel.outline.JvmOutlineNodeElementOpener'.typeRef)
.addTypeToType('org.eclipse.xtext.ui.editor.GlobalURIEditorOpener'.typeRef,
'org.eclipse.xtext.common.types.ui.navigation.GlobalDerivedMemberAwareURIEditorOpener'.typeRef)
.addTypeToType('org.eclipse.xtext.ui.editor.occurrences.IOccurrenceComputer'.typeRef,
'org.eclipse.xtext.xbase.ui.jvmmodel.occurrence.JvmModelOccurrenceComputer'.typeRef)
.addTypeToType('org.eclipse.xtext.common.types.ui.query.IJavaSearchParticipation'.typeRef,
'org.eclipse.xtext.common.types.ui.query.IJavaSearchParticipation.No'.typeRef)
// DerivedMemberAwareEditorOpener
.addConfiguredBinding('LanguageSpecificURIEditorOpener', statement)
} else {
bindingFactory
.addTypeToType('org.eclipse.xtext.ui.refactoring.IRenameStrategy'.typeRef,
'org.eclipse.xtext.xbase.ui.refactoring.XbaseRenameStrategy'.typeRef)
}
if (language.grammar.usesXImportSection) {
bindingFactory
.addTypeToType('org.eclipse.xtext.xbase.imports.IUnresolvedTypeResolver'.typeRef,
'org.eclipse.xtext.xbase.ui.imports.InteractiveUnresolvedTypeResolver'.typeRef)
.addTypeToType('org.eclipse.xtext.common.types.xtext.ui.ITypesProposalProvider'.typeRef,
'org.eclipse.xtext.xbase.ui.contentassist.ImportingTypesProposalProvider'.typeRef)
.addTypeToType(' org.eclipse.xtext.ui.editor.templates.XtextTemplateContextType'.typeRef,
'org.eclipse.xtext.xbase.ui.templates.XbaseTemplateContextType'.typeRef)
} else {
bindingFactory
.addTypeToType('org.eclipse.xtext.xbase.ui.quickfix.JavaTypeQuickfixes'.typeRef,
'org.eclipse.xtext.xbase.ui.quickfix.JavaTypeQuickfixesNoImportSection'.typeRef)
}
bindingFactory.contributeTo(language.eclipsePluginGenModule)
if (language.grammar.inheritsXbaseWithAnnotations)
language.eclipsePluginGenModule.superClass = 'org.eclipse.xtext.xbase.annotations.ui.DefaultXbaseWithAnnotationsUiModule'.typeRef
else
language.eclipsePluginGenModule.superClass = 'org.eclipse.xtext.xbase.ui.DefaultXbaseUiModule'.typeRef
}
protected def doGenerateXtendInferrer(LanguageConfig2 language) {
val xtendFile = new XtendFileAccess(language.jvmModelInferrer, codeConfig)
xtendFile.encodingProvider = encodingProvider
xtendFile.typeComment = '''
/**
* <p>Infers a JVM model from the source model.</p>
*
* <p>The JVM model should contain all elements that would appear in the Java code
* which is generated from the source model. Other models link against the JVM model rather than the source model.</p>
*/
'''
val firstRuleType = language.grammar.rules.head.type.classifier.getJavaTypeName(language.grammar.eResource.resourceSet).typeRef
xtendFile.javaContent = '''
class «language.jvmModelInferrer.simpleName» extends «'org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer'.typeRef» {
/**
* convenience API to build and initialize JVM types and their members.
*/
@«Inject» extension «'org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder'.typeRef»
/**
* The dispatch method {@code infer} is called for each instance of the
* given element's type that is contained in a resource.
*
* @param element
* the model to create one or more
* {@link org.eclipse.xtext.common.types.JvmDeclaredType declared
* types} from.
* @param acceptor
* each created
* {@link org.eclipse.xtext.common.types.JvmDeclaredType type}
* without a container should be passed to the acceptor in order
* get attached to the current resource. The acceptor's
* {@link IJvmDeclaredTypeAcceptor#accept(org.eclipse.xtext.common.types.JvmDeclaredType)
* accept(..)} method takes the constructed empty type for the
* pre-indexing phase. This one is further initialized in the
* indexing phase using the closure you pass to the returned
* {@link org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor.IPostIndexingInitializing#initializeLater(org.eclipse.xtext.xbase.lib.Procedures.Procedure1)
* initializeLater(..)}.
* @param isPreIndexingPhase
* whether the method is called in a pre-indexing phase, i.e.
* when the global index is not yet fully updated. You must not
* rely on linking using the index if isPreIndexingPhase is
* <code>true</code>.
*/
def dispatch void infer(«firstRuleType» element, «'org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor'.typeRef» acceptor, boolean isPreIndexingPhase) {
// Here you explain how your model is mapped to Java elements, by writing the actual translation code.
// An implementation for the initial hello world example could look like this:
// acceptor.accept(element.toClass("my.company.greeting.MyGreetings")) [
// for (greeting : element.greetings) {
// members += greeting.toMethod("hello" + greeting.name, typeRef(String)) [
// body = «"'''"»
// return "Hello «'«'»greeting.name«'»'»";
// «"'''"»
// ]
// }
// ]
}
}
'''
xtendFile.writeTo(projectConfig.runtimeSrc)
}
protected def addEclipsePluginExtensions(LanguageConfig2 language) {
val name = language.grammar.name
if (jdtTypeHierarchy) {
projectConfig.eclipsePluginPluginXml.entries += '''
<!-- Type Hierarchy -->
<extension point="org.eclipse.ui.handlers">
<handler
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.xtext.xbase.ui.hierarchy.OpenTypeHierarchyHandler"
commandId="org.eclipse.xtext.xbase.ui.hierarchy.OpenTypeHierarchy">
<activeWhen>
<reference
definitionId="«name».Editor.opened">
</reference>
</activeWhen>
</handler>
<handler
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.xtext.xbase.ui.hierarchy.QuickTypeHierarchyHandler"
commandId="org.eclipse.jdt.ui.edit.text.java.open.hierarchy">
<activeWhen>
<reference
definitionId="«name».Editor.opened">
</reference>
</activeWhen>
</handler>
«IF language.grammar.usesXImportSection»
<handler
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.xtext.xbase.ui.imports.OrganizeImportsHandler"
commandId="org.eclipse.xtext.xbase.ui.organizeImports">
<activeWhen>
<reference
definitionId="«name».Editor.opened">
</reference>
</activeWhen>
</handler>
«ENDIF»
</extension>
<extension point="org.eclipse.ui.menus">
«IF language.grammar.usesXImportSection»
<menuContribution
locationURI="popup:#TextEditorContext?after=group.edit">
<command
commandId="org.eclipse.xtext.xbase.ui.organizeImports"
style="push"
tooltip="Organize Imports">
<visibleWhen checkEnabled="false">
<reference
definitionId="«name».Editor.opened">
</reference>
</visibleWhen>
</command>
</menuContribution>
«ENDIF»
<menuContribution
locationURI="popup:#TextEditorContext?after=group.open">
<command commandId="org.eclipse.xtext.xbase.ui.hierarchy.OpenTypeHierarchy"
style="push"
tooltip="Open Type Hierarchy">
<visibleWhen checkEnabled="false">
<reference definitionId="«name».Editor.opened"/>
</visibleWhen>
</command>
</menuContribution>
<menuContribution
locationURI="popup:#TextEditorContext?after=group.open">
<command commandId="org.eclipse.jdt.ui.edit.text.java.open.hierarchy"
style="push"
tooltip="Quick Type Hierarchy">
<visibleWhen checkEnabled="false">
<reference definitionId="«name».Editor.opened"/>
</visibleWhen>
</command>
</menuContribution>
</extension>
'''
}
if (jdtCallHierarchy) {
projectConfig.eclipsePluginPluginXml.entries += '''
<!-- Call Hierachy -->
<extension point="org.eclipse.ui.handlers">
<handler
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.xtext.xbase.ui.hierarchy.OpenCallHierachyHandler"
commandId="org.eclipse.xtext.xbase.ui.hierarchy.OpenCallHierarchy">
<activeWhen>
<reference
definitionId="«name».Editor.opened">
</reference>
</activeWhen>
</handler>
</extension>
<extension point="org.eclipse.ui.menus">
<menuContribution
locationURI="popup:#TextEditorContext?after=group.open">
<command commandId="org.eclipse.xtext.xbase.ui.hierarchy.OpenCallHierarchy"
style="push"
tooltip="Open Call Hierarchy">
<visibleWhen checkEnabled="false">
<reference definitionId="«name».Editor.opened"/>
</visibleWhen>
</command>
</menuContribution>
</extension>
'''
}
projectConfig.eclipsePluginPluginXml.entries += '''
<extension point="org.eclipse.core.runtime.adapters">
<factory class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.xtext.builder.smap.StratumBreakpointAdapterFactory"
adaptableType="org.eclipse.xtext.ui.editor.XtextEditor">
<adapter type="org.eclipse.debug.ui.actions.IToggleBreakpointsTarget"/>
</factory>
</extension>
<extension point="org.eclipse.ui.editorActions">
<editorContribution targetID="«name»"
id="«name».rulerActions">
<action
label="Not Used"
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.debug.ui.actions.RulerToggleBreakpointActionDelegate"
style="push"
actionID="RulerDoubleClick"
id="«name».doubleClickBreakpointAction"/>
</editorContribution>
</extension>
<extension point="org.eclipse.ui.popupMenus">
<viewerContribution
targetID="«name».RulerContext"
id="«name».RulerPopupActions">
<action
label="Toggle Breakpoint"
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.debug.ui.actions.RulerToggleBreakpointActionDelegate"
menubarPath="debug"
id="«name».rulerContextMenu.toggleBreakpointAction">
</action>
<action
label="Not used"
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.debug.ui.actions.RulerEnableDisableBreakpointActionDelegate"
menubarPath="debug"
id="«name».rulerContextMenu.enableDisableBreakpointAction">
</action>
<action
label="Breakpoint Properties"
helpContextId="breakpoint_properties_action_context"
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.jdt.debug.ui.actions.JavaBreakpointPropertiesRulerActionDelegate"
menubarPath="group.properties"
id="«name».rulerContextMenu.openBreapointPropertiesAction">
</action>
</viewerContribution>
</extension>
<!-- Introduce Local Variable Refactoring -->
<extension point="org.eclipse.ui.handlers">
<handler
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.xtext.xbase.ui.refactoring.ExtractVariableHandler"
commandId="org.eclipse.xtext.xbase.ui.refactoring.ExtractLocalVariable">
<activeWhen>
<reference
definitionId="«name».Editor.opened">
</reference>
</activeWhen>
</handler>
</extension>
<extension point="org.eclipse.ui.menus">
<menuContribution
locationURI="popup:#TextEditorContext?after=group.edit">
<command commandId="org.eclipse.xtext.xbase.ui.refactoring.ExtractLocalVariable"
style="push">
<visibleWhen checkEnabled="false">
<reference
definitionId="«name».Editor.opened">
</reference>
</visibleWhen>
</command>
</menuContribution>
</extension>
<!-- Open implementation -->
<extension point="org.eclipse.ui.handlers">
<handler
class="«language.naming.eclipsePluginExecutableExtensionFactory»:org.eclipse.xtext.xbase.ui.navigation.OpenImplementationHandler"
commandId="org.eclipse.xtext.xbase.ui.OpenImplementationCommand">
<activeWhen>
<reference
definitionId="«name».Editor.opened">
</reference>
</activeWhen>
</handler>
</extension>
<extension point="org.eclipse.ui.menus">
<menuContribution
locationURI="menu:navigate?after=open.ext4">
<command commandId="org.eclipse.xtext.xbase.ui.OpenImplementationCommand">
<visibleWhen checkEnabled="false">
<reference
definitionId="«name».Editor.opened">
</reference>
</visibleWhen>
</command>
</menuContribution>
</extension>
'''
}
}

View file

@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext.xtext.generator.xbase
import com.google.inject.Inject
import org.eclipse.xtext.Grammar
import org.eclipse.xtext.GrammarUtil
import org.eclipse.xtext.xtext.generator.AbstractGeneratorFragment2
import org.eclipse.xtext.xtext.generator.IXtextProjectConfig
import org.eclipse.xtext.xtext.generator.LanguageConfig2
class XtypeGeneratorFragment2 extends AbstractGeneratorFragment2 {
static def boolean inheritsXtype(Grammar grammar) {
GrammarUtil.inherits(grammar, 'org.eclipse.xtext.xbase.Xtype')
}
@Inject IXtextProjectConfig projectConfig
override generate(LanguageConfig2 language) {
if (language.grammar.inheritsXtype && projectConfig.eclipsePluginManifest !== null)
projectConfig.eclipsePluginManifest.requiredBundles += 'org.eclipse.xtext.xbase.ui'
}
}

View file

@ -270,6 +270,20 @@ public class GrammarUtil {
collectAllUsedGrammars(grammars, grammar);
return grammars;
}
/**
* @since 2.9
*/
public static boolean inherits(Grammar grammar, String languageID) {
if (grammar.getName().equals(languageID))
return true;
for (Grammar grammar2 : grammar.getUsedGrammars()) {
if (inherits(grammar2, languageID)) {
return true;
}
}
return false;
}
private static void collectAllUsedGrammars(List<Grammar> grammars, Grammar grammar) {
grammars.addAll(grammar.getUsedGrammars());