反向参考查找

时间:2015-01-20 17:04:22

标签: java xtext emf xtend

由于某些原因,我的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
        }
    ]
}

1 个答案:

答案 0 :(得分:0)

谢谢,Christian Dietrich!你的想法非常好。

我的快速,专门的反向参考查找解决方案如下所示:

  1. 我扩展了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
        }
    }
    
  2. 我创建了一个索引包装类,它目前只提供一个方法,该方法返回修改给定类的所有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以来,任何资源的内容都不会处于相同的状态。

  3. 访问修改某个类的所有ModifiesUnit现在非常简单:val modifiesUnits = index.allModifyUnitsForCi(cd)

相关问题