2015-01-20 2 views
0

По каким-то причинам моим 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] '{' 
    // ... 
    '}'; 

Если я теперь вывести модель Jvm для класса pkg.A, мне нужно найти все 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

Что такое avout с запросом индекса для всех ModificationsUnit с нужным именем, а затем посмотреть? –

+0

и посмотрите ссылочные описания в индексе –

+0

Я еще не использовал индекс. Я посмотрю на это завтра. Есть ли какая-либо документация об ее использовании? – Joko

ответ

0

Спасибо, Кристиан Дитрих! Ваша идея работает очень хорошо.

Моего решения для быстрого, специализированного обратного эталонным поиска выглядит следующим образом:

  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 s, которые изменяют данный класс. Он использует квалифицированное имя для идентификации модифицирует единиц, которые я хочу иметь:

    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 s, которые изменяют определенный класс, теперь прост: val modifiesUnits = index.allModifyUnitsForCi(cd).

+0

Mh, у меня есть новая проблема ... Загруженные ресурсы не будут синхронизироваться с изменениями, которые я выполняю на 'ModfifiesUnit' ... Список содержит все ресурсы с состоянием, которое они имели непосредственно после Eclipse. – Joko

+0

Что вы подразумеваете под «Загруженные ресурсы» –

+0

Кстати, вы должны использовать org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider.getResourceDescriptions (Resource) –

Смежные вопросы