由于某些原因,我的JvmModelInferrer
需要来搜索符合条件的特殊类型的所有元素。这些元素是完全推断模型所必需的。但是所有这些元素都可以分布在项目的所有源代码文件中。更精确:有一个元素引入了一个类和几个修改这个类的元素。这个语法看起来像这样(简化到最小深度):
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] '{'
// ...
'}';
如果我现在推断出类pkg.A
的jvm模型,我需要找到引用ModifiesUnit
的所有pkg.A
个单元来生成此类。
这或多或少是一个问题:如何找到引用pkg.A
的所有元素?我发现了一个灵魂,但我觉得它非常无用,也许有任何API可以让我更有效率。
类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
}
]
}
答案 0 :(得分:0)
谢谢,Christian Dietrich!你的想法非常好。
我的快速,专门的反向参考查找解决方案如下所示:
我扩展了XbaseResourceDescriptionStrategy
以将自定义数据添加到索引中。自定义数据是键/值对,其中'ModifiesUnit'
为键,引用类(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
}
}
我创建了一个索引包装类,它目前只提供一个方法,该方法返回修改给定类的所有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以来,任何资源的内容都不会处于相同的状态。
访问修改某个类的所有ModifiesUnit
现在非常简单:val modifiesUnits = index.allModifyUnitsForCi(cd)
。