mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 08:48:55 +00:00
[generator2] provide a simpler alternative to StandaloneSetup
This commit is contained in:
parent
0d2e953795
commit
8764c05e56
10 changed files with 211 additions and 112 deletions
|
@ -19,7 +19,6 @@ import java.util.List
|
|||
import org.eclipse.emf.common.util.Diagnostic
|
||||
import org.eclipse.emf.common.util.DiagnosticChain
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.common.util.WrappedException
|
||||
import org.eclipse.emf.ecore.EValidator
|
||||
import org.eclipse.emf.ecore.resource.Resource
|
||||
import org.eclipse.emf.ecore.resource.ResourceSet
|
||||
|
@ -30,7 +29,6 @@ import org.eclipse.xtext.Grammar
|
|||
import org.eclipse.xtext.GrammarUtil
|
||||
import org.eclipse.xtext.ReferencedMetamodel
|
||||
import org.eclipse.xtext.XtextPackage
|
||||
import org.eclipse.xtext.ecore.EcoreSupportStandaloneSetup
|
||||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider
|
||||
import org.eclipse.xtext.resource.XtextResource
|
||||
|
@ -59,10 +57,10 @@ class LanguageConfig2 extends CompositeGeneratorFragment2 implements ILanguageCo
|
|||
ResourceSet resourceSet
|
||||
|
||||
@Accessors
|
||||
Module guiceModule = []
|
||||
XtextLanguageStandaloneSetup standaloneSetup = new XtextLanguageStandaloneSetup
|
||||
|
||||
@Accessors
|
||||
val List<String> loadedResources = newArrayList
|
||||
Module guiceModule = []
|
||||
|
||||
@Accessors
|
||||
val runtimeGenSetup = new StandaloneSetupAccess
|
||||
|
@ -99,65 +97,13 @@ class LanguageConfig2 extends CompositeGeneratorFragment2 implements ILanguageCo
|
|||
return fileExtensions
|
||||
}
|
||||
|
||||
def void addLoadedResource(String uri) {
|
||||
this.loadedResources.add(uri)
|
||||
}
|
||||
|
||||
override initialize(Injector injector) {
|
||||
fragments.add(0, new ImplicitFragment)
|
||||
injector.injectMembers(this)
|
||||
if (resourceSet === null)
|
||||
resourceSet = resourceSetProvider.get()
|
||||
for (String loadedResource : loadedResources) {
|
||||
val loadedResourceUri = URI.createURI(loadedResource)
|
||||
switch (loadedResourceUri.fileExtension) {
|
||||
case 'genmodel': {
|
||||
val resourceServiceProvider = IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(loadedResourceUri)
|
||||
if (resourceServiceProvider === null) {
|
||||
try {
|
||||
val genModelSupport = Class.forName('org.eclipse.emf.codegen.ecore.xtext.GenModelSupport')
|
||||
val instance = genModelSupport.newInstance()
|
||||
genModelSupport.getDeclaredMethod('createInjectorAndDoEMFRegistration').invoke(instance)
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.error("Couldn't initialize GenModel support. Is it on the classpath?")
|
||||
LOG.debug(e.getMessage(), e)
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't initialize GenModel support.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'ecore': {
|
||||
val resourceServiceProvider = IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(loadedResourceUri)
|
||||
if (resourceServiceProvider === null) {
|
||||
EcoreSupportStandaloneSetup.setup()
|
||||
}
|
||||
}
|
||||
case 'xcore': {
|
||||
val resourceServiceProvider = IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(loadedResourceUri)
|
||||
if (resourceServiceProvider === null) {
|
||||
try {
|
||||
val xcore = Class.forName('org.eclipse.emf.ecore.xcore.XcoreStandaloneSetup')
|
||||
xcore.getDeclaredMethod('doSetup', #[]).invoke(null)
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.error("Couldn't initialize Xcore support. Is it on the classpath?")
|
||||
LOG.debug(e.getMessage(), e)
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't initialize Xcore support.", e)
|
||||
}
|
||||
}
|
||||
val xcoreLangURI = URI.createPlatformResourceURI('/org.eclipse.emf.ecore.xcore.lib/model/XcoreLang.xcore', true)
|
||||
try {
|
||||
resourceSet.getResource(xcoreLangURI, true)
|
||||
} catch (WrappedException e) {
|
||||
LOG.error("Could not load XcoreLang.xcore.", e)
|
||||
val brokenResource = resourceSet.getResource(xcoreLangURI, false)
|
||||
resourceSet.resources.remove(brokenResource)
|
||||
}
|
||||
}
|
||||
}
|
||||
resourceSet.getResource(loadedResourceUri, true)
|
||||
|
||||
}
|
||||
standaloneSetup.initialize(injector)
|
||||
|
||||
if (!resourceSet.resources.isEmpty) {
|
||||
installIndex()
|
||||
for (var i = 0, var size = resourceSet.resources.size; i < size; i++) {
|
||||
|
|
|
@ -53,6 +53,9 @@ class XtextGenerator extends AbstractWorkflowComponent2 {
|
|||
@Accessors
|
||||
XtextDirectoryCleaner cleaner = new XtextDirectoryCleaner
|
||||
|
||||
@Accessors
|
||||
XtextGeneratorStandaloneSetup standaloneSetup = new XtextGeneratorStandaloneSetup
|
||||
|
||||
Injector injector
|
||||
|
||||
@Inject IXtextProjectConfig projectConfig
|
||||
|
@ -100,6 +103,7 @@ class XtextGenerator extends AbstractWorkflowComponent2 {
|
|||
injector.getInstance(CodeConfig) => [initialize(injector)]
|
||||
projectConfig.initialize(injector)
|
||||
cleaner.initialize(injector)
|
||||
standaloneSetup.initialize(injector)
|
||||
for (language : languageConfigs) {
|
||||
val languageInjector = injector.createLanguageInjector(language)
|
||||
language.initialize(languageInjector)
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*******************************************************************************
|
||||
* 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
|
||||
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.Injector
|
||||
import org.eclipse.emf.mwe.utils.ProjectMapping
|
||||
import org.eclipse.emf.mwe.utils.StandaloneSetup
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtext.util.internal.Log
|
||||
|
||||
@Log
|
||||
class XtextGeneratorStandaloneSetup implements IGuiceAwareGeneratorComponent {
|
||||
@Inject IXtextProjectConfig projectConfig
|
||||
|
||||
@Accessors boolean scanClasspath = true
|
||||
|
||||
override initialize(Injector injector) {
|
||||
injector.injectMembers(this)
|
||||
setup
|
||||
}
|
||||
|
||||
private def void setup() {
|
||||
val delegate = new StandaloneSetup
|
||||
delegate.scanClassPath = scanClasspath
|
||||
projectMappings.forEach [ mapping |
|
||||
delegate.addProjectMapping(new ProjectMapping => [
|
||||
projectName = mapping.key
|
||||
path = mapping.value.path
|
||||
])
|
||||
]
|
||||
}
|
||||
|
||||
private def getProjectMappings() {
|
||||
#[
|
||||
projectConfig.runtimeProjectName -> projectConfig.runtimeRoot,
|
||||
projectConfig.runtimeTestProjectName -> projectConfig.runtimeTestRoot,
|
||||
projectConfig.genericIdeProjectName -> projectConfig.genericIdeRoot,
|
||||
projectConfig.genericIdeTestProjectName -> projectConfig.genericIdeTestRoot,
|
||||
projectConfig.eclipsePluginProjectName -> projectConfig.eclipsePluginRoot,
|
||||
projectConfig.eclipsePluginTestProjectName -> projectConfig.eclipsePluginTestRoot,
|
||||
projectConfig.ideaPluginProjectName -> projectConfig.ideaPluginRoot,
|
||||
projectConfig.ideaPluginTestProjectName -> projectConfig.ideaPluginTestRoot,
|
||||
projectConfig.webProjectName -> projectConfig.webRoot,
|
||||
projectConfig.webTestProjectName -> projectConfig.webTestRoot
|
||||
].filter[key != null && value != null]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*******************************************************************************
|
||||
* 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
|
||||
|
||||
import com.google.inject.Injector
|
||||
import java.util.List
|
||||
import org.eclipse.emf.codegen.ecore.genmodel.GenModel
|
||||
import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.common.util.WrappedException
|
||||
import org.eclipse.emf.ecore.EPackage
|
||||
import org.eclipse.emf.ecore.resource.ResourceSet
|
||||
import org.eclipse.emf.mwe.utils.GenModelHelper
|
||||
import org.eclipse.emf.mwe.utils.StandaloneSetup
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.eclipse.xtext.ecore.EcoreSupportStandaloneSetup
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider
|
||||
import org.eclipse.xtext.util.internal.Log
|
||||
import com.google.inject.Inject
|
||||
|
||||
@Log
|
||||
class XtextLanguageStandaloneSetup implements IGuiceAwareGeneratorComponent {
|
||||
@Accessors List<String> loadedResources = newArrayList
|
||||
|
||||
@Inject ILanguageConfig language
|
||||
|
||||
def void addLoadedResource(String uri) {
|
||||
loadedResources += uri
|
||||
}
|
||||
|
||||
override initialize(Injector injector) {
|
||||
injector.injectMembers(this)
|
||||
setup(language.resourceSet)
|
||||
}
|
||||
|
||||
private def void setup(ResourceSet resourceSet) {
|
||||
val delegate = new StandaloneSetup
|
||||
delegate.resourceSet = resourceSet
|
||||
loadedResources.forEach[
|
||||
loadResource(resourceSet)
|
||||
]
|
||||
registerGenModels(resourceSet)
|
||||
registerEPackages(resourceSet)
|
||||
}
|
||||
|
||||
private def loadResource(String loadedResource, ResourceSet resourceSet) {
|
||||
val loadedResourceUri = URI.createURI(loadedResource)
|
||||
ensureResourceCanBeLoaded(loadedResourceUri, resourceSet)
|
||||
resourceSet.getResource(loadedResourceUri, true)
|
||||
}
|
||||
|
||||
private def ensureResourceCanBeLoaded(URI loadedResource, ResourceSet resourceSet) {
|
||||
switch (loadedResource.fileExtension) {
|
||||
case 'genmodel': {
|
||||
GenModelPackage.eINSTANCE.getEFactoryInstance
|
||||
val resourceServiceProvider = IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(loadedResource)
|
||||
if (resourceServiceProvider === null) {
|
||||
try {
|
||||
val genModelSupport = Class.forName('org.eclipse.emf.codegen.ecore.xtext.GenModelSupport')
|
||||
val instance = genModelSupport.newInstance()
|
||||
genModelSupport.getDeclaredMethod('createInjectorAndDoEMFRegistration').invoke(instance)
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.debug("org.eclipse.emf.codegen.ecore.xtext.GenModelSupport not found, GenModels will not be indexed")
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't initialize GenModel support.", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'ecore': {
|
||||
val resourceServiceProvider = IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(loadedResource)
|
||||
if (resourceServiceProvider === null) {
|
||||
EcoreSupportStandaloneSetup.setup()
|
||||
}
|
||||
}
|
||||
case 'xcore': {
|
||||
val resourceServiceProvider = IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(loadedResource)
|
||||
if (resourceServiceProvider === null) {
|
||||
try {
|
||||
val xcore = Class.forName('org.eclipse.emf.ecore.xcore.XcoreStandaloneSetup')
|
||||
xcore.getDeclaredMethod('doSetup', #[]).invoke(null)
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.error("Couldn't initialize Xcore support. Is it on the classpath?")
|
||||
LOG.debug(e.getMessage(), e)
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't initialize Xcore support.", e)
|
||||
}
|
||||
}
|
||||
val xcoreLangURI = URI.createPlatformResourceURI('/org.eclipse.emf.ecore.xcore.lib/model/XcoreLang.xcore', true)
|
||||
try {
|
||||
resourceSet.getResource(xcoreLangURI, true)
|
||||
} catch (WrappedException e) {
|
||||
LOG.error("Could not load XcoreLang.xcore.", e)
|
||||
val brokenResource = resourceSet.getResource(xcoreLangURI, false)
|
||||
resourceSet.resources.remove(brokenResource)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def registerEPackages(ResourceSet resourceSet) {
|
||||
resourceSet.resources.map[contents].flatten.filter(EPackage).forEach[registerEPackage]
|
||||
}
|
||||
|
||||
private def registerGenModels(ResourceSet resourceSet) {
|
||||
resourceSet.resources.map[contents].flatten.filter(GenModel).forEach[registerGenModel]
|
||||
}
|
||||
|
||||
private def registerGenModel(GenModel genModel) {
|
||||
new GenModelHelper().registerGenModel(genModel)
|
||||
}
|
||||
|
||||
private def registerEPackage(EPackage ePackage) {
|
||||
val registry = ePackage.eResource.resourceSet.packageRegistry
|
||||
if (registry.get(ePackage.nsURI) === null) {
|
||||
registry.put(ePackage.nsURI, ePackage)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -162,22 +162,6 @@ class RuntimeProjectDescriptor extends TestedProjectDescriptor {
|
|||
var fileExtensions = "«config.language.fileExtensions»"
|
||||
|
||||
Workflow {
|
||||
bean = StandaloneSetup {
|
||||
scanClassPath = true
|
||||
platformUri = rootPath
|
||||
«IF fromExistingEcoreModels»
|
||||
«FOR ePackageInfo : config.ecore2Xtext.EPackageInfos.filter[genmodelURI.fileExtension != "xcore"].map[EPackageJavaFQN].filterNull»
|
||||
registerGeneratedEPackage = "«ePackageInfo»"
|
||||
«ENDFOR»
|
||||
«FOR genmodelURI : config.ecore2Xtext.EPackageInfos.filter[genmodelURI.fileExtension != "xcore"].map[genmodelURI.toString].toSet»
|
||||
registerGenModelFile = "«genmodelURI»"
|
||||
«ENDFOR»
|
||||
«ELSE»
|
||||
// The following two lines can be removed, if Xbase is not used.
|
||||
registerGeneratedEPackage = "org.eclipse.xtext.xbase.XbasePackage"
|
||||
registerGenModelFile = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
«ENDIF»
|
||||
}
|
||||
|
||||
component = XtextGenerator auto-inject {
|
||||
configuration = {
|
||||
|
@ -209,9 +193,13 @@ class RuntimeProjectDescriptor extends TestedProjectDescriptor {
|
|||
}
|
||||
language = auto-inject {
|
||||
uri = "platform:/resource/${baseName}/«Outlet.MAIN_JAVA.sourceFolder»/«grammarFilePath»"
|
||||
«FOR genmodelURI : config.ecore2Xtext.EPackageInfos.filter[genmodelURI.fileExtension == "xcore"].map[genmodelURI.toString].toSet»
|
||||
loadedResource = "«genmodelURI»"
|
||||
«ENDFOR»
|
||||
standaloneSetup = {
|
||||
//can be removed if Xbase is not used
|
||||
loadedResource = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
«FOR genmodelURI : config.ecore2Xtext.EPackageInfos.map[genmodelURI.toString].toSet»
|
||||
loadedResource = "«genmodelURI»"
|
||||
«ENDFOR»
|
||||
}
|
||||
|
||||
// Java API to access grammar elements (required by several other fragments)
|
||||
fragment = grammarAccess.GrammarAccessFragment2 auto-inject {}
|
||||
|
|
|
@ -11,13 +11,6 @@ var rootPath = ".."
|
|||
var fileExtensions = "mydsl"
|
||||
|
||||
Workflow {
|
||||
bean = StandaloneSetup {
|
||||
scanClassPath = true
|
||||
platformUri = rootPath
|
||||
// The following two lines can be removed, if Xbase is not used.
|
||||
registerGeneratedEPackage = "org.eclipse.xtext.xbase.XbasePackage"
|
||||
registerGenModelFile = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
component = XtextGenerator auto-inject {
|
||||
configuration = {
|
||||
|
@ -33,6 +26,10 @@ Workflow {
|
|||
}
|
||||
language = auto-inject {
|
||||
uri = "platform:/resource/${baseName}/src/org/xtext/example/mydsl/MyDsl.xtext"
|
||||
standaloneSetup = {
|
||||
//can be removed if Xbase is not used
|
||||
loadedResource = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
// Java API to access grammar elements (required by several other fragments)
|
||||
fragment = grammarAccess.GrammarAccessFragment2 auto-inject {}
|
||||
|
|
|
@ -11,13 +11,6 @@ var rootPath = ".."
|
|||
var fileExtensions = "mydsl"
|
||||
|
||||
Workflow {
|
||||
bean = StandaloneSetup {
|
||||
scanClassPath = true
|
||||
platformUri = rootPath
|
||||
// The following two lines can be removed, if Xbase is not used.
|
||||
registerGeneratedEPackage = "org.eclipse.xtext.xbase.XbasePackage"
|
||||
registerGenModelFile = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
component = XtextGenerator auto-inject {
|
||||
configuration = {
|
||||
|
@ -35,6 +28,10 @@ Workflow {
|
|||
}
|
||||
language = auto-inject {
|
||||
uri = "platform:/resource/${baseName}/src/org/xtext/example/mydsl/MyDsl.xtext"
|
||||
standaloneSetup = {
|
||||
//can be removed if Xbase is not used
|
||||
loadedResource = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
// Java API to access grammar elements (required by several other fragments)
|
||||
fragment = grammarAccess.GrammarAccessFragment2 auto-inject {}
|
||||
|
|
|
@ -11,13 +11,6 @@ var rootPath = ".."
|
|||
var fileExtensions = "mydsl"
|
||||
|
||||
Workflow {
|
||||
bean = StandaloneSetup {
|
||||
scanClassPath = true
|
||||
platformUri = rootPath
|
||||
// The following two lines can be removed, if Xbase is not used.
|
||||
registerGeneratedEPackage = "org.eclipse.xtext.xbase.XbasePackage"
|
||||
registerGenModelFile = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
component = XtextGenerator auto-inject {
|
||||
configuration = {
|
||||
|
@ -37,6 +30,10 @@ Workflow {
|
|||
}
|
||||
language = auto-inject {
|
||||
uri = "platform:/resource/${baseName}/src/main/java/org/xtext/example/mydsl/MyDsl.xtext"
|
||||
standaloneSetup = {
|
||||
//can be removed if Xbase is not used
|
||||
loadedResource = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
// Java API to access grammar elements (required by several other fragments)
|
||||
fragment = grammarAccess.GrammarAccessFragment2 auto-inject {}
|
||||
|
|
|
@ -11,13 +11,6 @@ var rootPath = ".."
|
|||
var fileExtensions = "mydsl"
|
||||
|
||||
Workflow {
|
||||
bean = StandaloneSetup {
|
||||
scanClassPath = true
|
||||
platformUri = rootPath
|
||||
// The following two lines can be removed, if Xbase is not used.
|
||||
registerGeneratedEPackage = "org.eclipse.xtext.xbase.XbasePackage"
|
||||
registerGenModelFile = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
component = XtextGenerator auto-inject {
|
||||
configuration = {
|
||||
|
@ -34,6 +27,10 @@ Workflow {
|
|||
}
|
||||
language = auto-inject {
|
||||
uri = "platform:/resource/${baseName}/src/org/xtext/example/mydsl/MyDsl.xtext"
|
||||
standaloneSetup = {
|
||||
//can be removed if Xbase is not used
|
||||
loadedResource = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
// Java API to access grammar elements (required by several other fragments)
|
||||
fragment = grammarAccess.GrammarAccessFragment2 auto-inject {}
|
||||
|
|
|
@ -11,13 +11,6 @@ var rootPath = ".."
|
|||
var fileExtensions = "mydsl"
|
||||
|
||||
Workflow {
|
||||
bean = StandaloneSetup {
|
||||
scanClassPath = true
|
||||
platformUri = rootPath
|
||||
// The following two lines can be removed, if Xbase is not used.
|
||||
registerGeneratedEPackage = "org.eclipse.xtext.xbase.XbasePackage"
|
||||
registerGenModelFile = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
component = XtextGenerator auto-inject {
|
||||
configuration = {
|
||||
|
@ -36,6 +29,10 @@ Workflow {
|
|||
}
|
||||
language = auto-inject {
|
||||
uri = "platform:/resource/${baseName}/src/main/java/org/xtext/example/mydsl/MyDsl.xtext"
|
||||
standaloneSetup = {
|
||||
//can be removed if Xbase is not used
|
||||
loadedResource = "platform:/resource/org.eclipse.xtext.xbase/model/Xbase.genmodel"
|
||||
}
|
||||
|
||||
// Java API to access grammar elements (required by several other fragments)
|
||||
fragment = grammarAccess.GrammarAccessFragment2 auto-inject {}
|
||||
|
|
Loading…
Reference in a new issue