/* * Copyright 2003-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.ide.findusages.model; import jetbrains.mps.ide.findusages.model.holders.IHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.model.SModelReference; import org.jetbrains.mps.openapi.model.SNode; import org.jetbrains.mps.openapi.model.SNodeReference; import org.jetbrains.mps.openapi.module.SModule; import org.jetbrains.mps.openapi.module.SModuleReference; import org.jetbrains.mps.openapi.module.SRepository; import org.jetbrains.mps.openapi.module.SearchScope; import org.jetbrains.mps.openapi.util.ProgressMonitor; /** * Abstracts revival of searched objects from their {@link jetbrains.mps.ide.findusages.model.holders.IHolder} persistence into something * MPS could search for. Unlike {@link org.jetbrains.mps.openapi.module.SearchScope}, this interface helps to answer 'What is being looked up', * not 'Where it's to be looked up'. * <p/> * Distinction between {@link org.jetbrains.mps.openapi.module.SearchScope} and {@link SearchObjectResolver} is apparent if you think about scenario, when * one looks for instances of a concept declaration in a set of modules. Concept declaration originates in a model/module that is not necessarily among the * modules/models we search through. In fact, quite the opposite, it's unlikely to be among them. * <p/> * Use this interface to translate search objects obtained through {@link IHolder#getObject()}. * <p/> * Find Usages client is responsible to ensure proper model access so that these methods, invoked during * {@link jetbrains.mps.ide.findusages.findalgorithm.finders.Finder#find(SearchQuery, ProgressMonitor)}, do not fail. * * @author Artem Tikhomirov * @since 2017.1 */ public interface SearchObjectResolver { /** * Finder may use this method to go from model reference as a search value to SModel object. * Find Usages client may use this method to limit what's visible/accessible to a Finder. * * @param reference model to resolve * @return model instance, or <code>null</code> if model with specified reference is not available */ @Nullable SModel resolve(@NotNull SModelReference reference); /** * Finder may use this method to go from module reference as a seatch value to SModule object. * Find Usages client may use this method to limit what's visible/accessible to a Finder. * * @param reference module to resolve * @return module instance, or <code>null</code> if there's no such module */ @Nullable SModule resolve(@NotNull SModuleReference reference); /** * Finder may use this method to go from model reference as a search value to SNode object. * Find Usages client may use this method to limit what's visible/accessible to a Finder. * * @param reference node to resolve * @return node instance of {@code null} if the node is unknown */ @Nullable default SNode resolve(@NotNull SNodeReference reference) { SModelReference mr = reference.getModelReference(); SModel m = mr == null || reference.getNodeId() == null ? null : resolve(mr); return m == null ? null : m.getNode(reference.getNodeId()); } static SearchObjectResolver forNode(@NotNull SNode node) { return new BasicResolver(node.getModel().getRepository()); } static SearchObjectResolver forModule(@NotNull SModule module) { return new BasicResolver(module.getRepository()); } /** * All-purpose, unrestricted implementation of the resolver. * Generally, we shall strive to limit resolver to searched model/module/node only, however, with 2017.1 on my neck, I don't want to bother * with limitations nobody cares about anyway. */ final class BasicResolver implements SearchObjectResolver { private final SRepository myRepository; public BasicResolver(@NotNull SRepository repository) { myRepository = repository; } @Nullable @Override public SModel resolve(@NotNull SModelReference reference) { return reference.resolve(myRepository); } @Nullable @Override public SModule resolve(@NotNull SModuleReference reference) { return reference.resolve(myRepository); } @Nullable @Override public SNode resolve(@NotNull SNodeReference reference) { return reference.resolve(myRepository); } } /** * DO NOT USE THIS CLASS FOR ANY PURPOSE EXCEPT THE ONE IT HAS BEEN WRITTEN FOR, THE CLASS SHALL CEASE ONCE PROPER API IS IN PLACE. * <p/> * Provisional bridge between {@link SearchScope} and {@link SearchObjectResolver}. {@code resolve()} methods in {@link SearchScope} are * ill-placed, and now are extracted into {@link SearchObjectResolver}. */ final class CompatibilityResolver implements SearchObjectResolver { private final SearchScope myScope; public CompatibilityResolver(SearchScope scope) { myScope = scope; } @Nullable @Override public SModel resolve(@NotNull SModelReference reference) { return myScope.resolve(reference); } @Nullable @Override public SModule resolve(@NotNull SModuleReference reference) { return myScope.resolve(reference); } @Nullable @Override public SNode resolve(@NotNull SNodeReference reference) { return myScope.resolve(reference); } } }