反向引用查找
Inverse reference lookup
出于某些原因,我的 JvmModelInferrer
需要 搜索满足条件的特殊类型的所有元素。这些元素是完整推断模型所必需的。但是所有这些元素都可以分布在项目的所有源代码文件中。更准确地说:有一个引入 class 的元素和修改此 class 的几个元素。这个语法看起来像这样(简化到最小深度):
DeltaAction:
AddsUnit | ModifiesUnit | RemovesUnit;
AddsUnit:
{AddsUnit} 'adds' '{' unit=JavaCompilationUnit? '}';
JavaCompilationUnit:
('package' name=QualifiedName EOL)?
importSection=XImportSection?
// ...
typeDeclarations=ClassOrInterface;
ClassOrInterface:
ClassDeclaration /* | ... */;
ClassDeclaration:
'class' name=QualifiedName
// ...
;
ModifiesUnit:
'modifies' unit=[ClassOrInterface|QualifiedName] '{'
// ...
'}';
如果我现在推断 class pkg.A
的 jvm 模型,我需要找到所有引用 pkg.A
的 ModifiesUnit
单元来生成这个 class.
这或多或少是个问题:如何找到所有引用 pkg.A
的元素?我找到了一个 soultion,但我认为它非常低效,也许有任何 API 对我来说效率更高。
class DeltaJJvmModelInferrer 扩展了 AbstractModelInferrer {
@Inject ResourceDescriptionsProvider descsProvider
@Inject ResourceSet set
@Inject IQualifiedNameProvider qnameProvider
def dispatch void infer(DeltaJUnit unit, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
descsProvider.createResourceDescriptions.allResourceDescriptions.forEach [ rd |
val res = set.getResource(rd.URI, true)
res.unload
res.load(null)
EcoreUtil2.resolveAll(res)
]
try {
set.allContents.filter(typeof(ModifiesUnit)).filter [ mu |
qnameProvider.getFullyQualifiedName(mu.unit).equals(qnameProvider.getFullyQualifiedName(cd))
].forEach [ mu |
// Do the stuff I need to do!
]
} catch (Exception e) {
return
}
]
}
谢谢,克里斯蒂安·迪特里希!你的想法很好。
我的快速专用反向引用查找解决方案如下所示:
我扩展了 XbaseResourceDescriptionStrategy
以将自定义数据添加到索引中。自定义数据是一个 key/value 对,其中 'ModifiesUnit'
作为键,引用的 class (qnp.getFullyQualifiedName(mu.unit)
) 的限定名称作为值:
class DeltaJResourceDescriptionStrategy extends XbaseResourceDescriptionStrategy {
public static val TYPE = 'ModifiesUnit'
override def createEObjectDescriptions(EObject eObject, IAcceptor<IEObjectDescription> acceptor) {
var custom = true
try {
if (eObject instanceof ModifiesUnit) {
if (!eObject.eIsProxy) {
val qname = qnp.getFullyQualifiedName(eObject.unit)
acceptor.accept(EObjectDescription.create(qname, eObject, eObject.createModifiesUnitUserData))
}
}
} catch (Exception e) {
custom = false
}
super.createEObjectDescriptions(eObject, acceptor) && custom
}
def createModifiesUnitUserData(ModifiesUnit mu) {
val map = newHashMap
map.put(TYPE, qualifiedNameProvider.getFullyQualifiedName(mu.unit).toString)
map
}
}
我创建了一个索引包装器 class,它目前只提供一种方法,该方法 returns 修改给定 [=39= 的所有 ModifiesUnit
的列表].它使用限定名称来标识我想要的修改单位:
class DeltaJIndex {
@Inject extension ResourceDescriptionsProvider
@Inject extension QualifiedNameProvider
@Inject extension ResourceSet
def getAllResourceDescriptions() {
createResourceDescriptions.allResourceDescriptions
}
def getAllModifyUnitsOf(ClassOrInterface ci) {
val Set<ModifiesUnit> units = newHashSet
val Set<Resource> resources = newHashSet
val ciQn = qnProvider.getFullyQualifiedName(ci).toString
rdProvider.getResourceDescriptions(ci.eResource).allResourceDescriptions.forEach [ list |
list.exportedObjects.forEach [ object |
if (object.userDataKeys.contains(TYPE) && object.getUserData(TYPE) == ciQn) {
val res = set.getResource(object.EObjectURI, true)
if (!resources.contains(res)) {
res.unload
res.load(null)
resources.add(res)
}
units.add(res.getEObject(object.EObjectURI.fragment) as ModifiesUnit)
}
]
]
units
}
}
唯一的问题是,我必须卸载所有资源并重新加载。否则,自上次 Eclipse 启动以来编辑过的任何资源的内容都不会处于相同状态。
访问所有修改某个 class 的 ModifiesUnit
现在就这么简单:val modifiesUnits = index.allModifyUnitsForCi(cd)
.
出于某些原因,我的 JvmModelInferrer
需要 搜索满足条件的特殊类型的所有元素。这些元素是完整推断模型所必需的。但是所有这些元素都可以分布在项目的所有源代码文件中。更准确地说:有一个引入 class 的元素和修改此 class 的几个元素。这个语法看起来像这样(简化到最小深度):
DeltaAction:
AddsUnit | ModifiesUnit | RemovesUnit;
AddsUnit:
{AddsUnit} 'adds' '{' unit=JavaCompilationUnit? '}';
JavaCompilationUnit:
('package' name=QualifiedName EOL)?
importSection=XImportSection?
// ...
typeDeclarations=ClassOrInterface;
ClassOrInterface:
ClassDeclaration /* | ... */;
ClassDeclaration:
'class' name=QualifiedName
// ...
;
ModifiesUnit:
'modifies' unit=[ClassOrInterface|QualifiedName] '{'
// ...
'}';
如果我现在推断 class pkg.A
的 jvm 模型,我需要找到所有引用 pkg.A
的 ModifiesUnit
单元来生成这个 class.
这或多或少是个问题:如何找到所有引用 pkg.A
的元素?我找到了一个 soultion,但我认为它非常低效,也许有任何 API 对我来说效率更高。
class DeltaJJvmModelInferrer 扩展了 AbstractModelInferrer {
@Inject ResourceDescriptionsProvider descsProvider
@Inject ResourceSet set
@Inject IQualifiedNameProvider qnameProvider
def dispatch void infer(DeltaJUnit unit, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
descsProvider.createResourceDescriptions.allResourceDescriptions.forEach [ rd |
val res = set.getResource(rd.URI, true)
res.unload
res.load(null)
EcoreUtil2.resolveAll(res)
]
try {
set.allContents.filter(typeof(ModifiesUnit)).filter [ mu |
qnameProvider.getFullyQualifiedName(mu.unit).equals(qnameProvider.getFullyQualifiedName(cd))
].forEach [ mu |
// Do the stuff I need to do!
]
} catch (Exception e) {
return
}
]
}
谢谢,克里斯蒂安·迪特里希!你的想法很好。
我的快速专用反向引用查找解决方案如下所示:
我扩展了
XbaseResourceDescriptionStrategy
以将自定义数据添加到索引中。自定义数据是一个 key/value 对,其中'ModifiesUnit'
作为键,引用的 class (qnp.getFullyQualifiedName(mu.unit)
) 的限定名称作为值:class DeltaJResourceDescriptionStrategy extends XbaseResourceDescriptionStrategy { public static val TYPE = 'ModifiesUnit' override def createEObjectDescriptions(EObject eObject, IAcceptor<IEObjectDescription> acceptor) { var custom = true try { if (eObject instanceof ModifiesUnit) { if (!eObject.eIsProxy) { val qname = qnp.getFullyQualifiedName(eObject.unit) acceptor.accept(EObjectDescription.create(qname, eObject, eObject.createModifiesUnitUserData)) } } } catch (Exception e) { custom = false } super.createEObjectDescriptions(eObject, acceptor) && custom } def createModifiesUnitUserData(ModifiesUnit mu) { val map = newHashMap map.put(TYPE, qualifiedNameProvider.getFullyQualifiedName(mu.unit).toString) map } }
我创建了一个索引包装器 class,它目前只提供一种方法,该方法 returns 修改给定 [=39= 的所有
ModifiesUnit
的列表].它使用限定名称来标识我想要的修改单位:class DeltaJIndex { @Inject extension ResourceDescriptionsProvider @Inject extension QualifiedNameProvider @Inject extension ResourceSet def getAllResourceDescriptions() { createResourceDescriptions.allResourceDescriptions } def getAllModifyUnitsOf(ClassOrInterface ci) { val Set<ModifiesUnit> units = newHashSet val Set<Resource> resources = newHashSet val ciQn = qnProvider.getFullyQualifiedName(ci).toString rdProvider.getResourceDescriptions(ci.eResource).allResourceDescriptions.forEach [ list | list.exportedObjects.forEach [ object | if (object.userDataKeys.contains(TYPE) && object.getUserData(TYPE) == ciQn) { val res = set.getResource(object.EObjectURI, true) if (!resources.contains(res)) { res.unload res.load(null) resources.add(res) } units.add(res.getEObject(object.EObjectURI.fragment) as ModifiesUnit) } ] ] units } }
唯一的问题是,我必须卸载所有资源并重新加载。否则,自上次 Eclipse 启动以来编辑过的任何资源的内容都不会处于相同状态。
访问所有修改某个 class 的
ModifiesUnit
现在就这么简单:val modifiesUnits = index.allModifyUnitsForCi(cd)
.