/* * Copyright 2013-2016 Sergey Ignatov, Alexander Zolotov, Florin Patan * * 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 com.goide.util; import com.goide.psi.GoFile; import com.goide.psi.GoImportSpec; import com.goide.psi.GoNamedElement; import com.goide.psi.impl.GoPsiImplUtil; import com.goide.psi.impl.imports.GoImportReferenceSet; import com.goide.sdk.GoPackageUtil; import com.goide.sdk.GoSdkService; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import java.util.Map; import java.util.Set; public class GoPathUseScope extends GlobalSearchScope { public static GlobalSearchScope create(@NotNull PsiElement declarationContext, boolean filterByImportList) { if (declarationContext instanceof GoNamedElement && ((GoNamedElement)declarationContext).isBlank()) { return GlobalSearchScope.EMPTY_SCOPE; } PsiFile declarationPsiFile = declarationContext.getContainingFile(); if (!(declarationPsiFile instanceof GoFile)) { return GlobalSearchScope.fileScope(declarationPsiFile); } if (GoPsiImplUtil.isBuiltinFile(declarationPsiFile)) { return GlobalSearchScope.allScope(declarationContext.getProject()); } VirtualFile declarationFile = declarationPsiFile.getVirtualFile(); if (declarationFile == null || declarationFile.getParent() == null) { return GlobalSearchScope.fileScope(declarationPsiFile); } return new GoPathUseScope(declarationPsiFile.getProject(), declarationFile, filterByImportList); } @NotNull private final VirtualFile myDeclarationFile; private final boolean myFilterByImportList; private GoPathUseScope(@NotNull Project project, @NotNull VirtualFile declarationFile, boolean filterByImportList) { super(project); myDeclarationFile = declarationFile; myFilterByImportList = filterByImportList; } @Override public boolean contains(@NotNull VirtualFile referenceFile) { VirtualFile referenceDirectory = referenceFile.isDirectory() ? referenceFile : referenceFile.getParent(); if (referenceDirectory == null) { return false; } VirtualFile declarationDirectory = myDeclarationFile.getParent(); if (referenceDirectory.equals(declarationDirectory)) { return true; } Project project = ObjectUtils.assertNotNull(getProject()); PsiManager psiManager = PsiManager.getInstance(project); PsiFile referencePsiFile = psiManager.findFile(referenceFile); Module module = referencePsiFile != null ? ModuleUtilCore.findModuleForPsiElement(referencePsiFile) : null; GoPathScopeHelper scopeHelper = GoPathScopeHelper.fromReferenceFile(project, module, referenceFile); if (!scopeHelper.couldBeReferenced(myDeclarationFile, referenceFile)) { return false; } if (!myFilterByImportList) { return true; } if (!(referencePsiFile instanceof GoFile)) { // it's some injection or cross-reference, so we cannot check its imports return true; } PsiFile declarationPsiFile = psiManager.findFile(myDeclarationFile); if (declarationPsiFile instanceof GoFile) { String importPath = ((GoFile)declarationPsiFile).getImportPath(scopeHelper.isVendoringEnabled()); Map<String, GoImportSpec> importedPackagesMap = ((GoFile)referencePsiFile).getImportedPackagesMap(); if (importedPackagesMap.containsKey(importPath)) { return true; } if (hasRelativeImportOfTargetPackage(importedPackagesMap.keySet(), referenceDirectory, declarationDirectory)) { return true; } for (GoFile packageFile : GoPackageUtil.getAllPackageFiles(referencePsiFile.getContainingDirectory(), null)) { if (packageFile != referencePsiFile && referencePsiFile.getOriginalFile() != packageFile) { Map<String, GoImportSpec> packagesMap = packageFile.getImportedPackagesMap(); if (packagesMap.containsKey(importPath)) { return true; } if (hasRelativeImportOfTargetPackage(packagesMap.keySet(), referenceDirectory, declarationDirectory)) { return true; } } } } return false; } private static boolean hasRelativeImportOfTargetPackage(@NotNull Set<String> paths, @NotNull VirtualFile referenceDirectory, @NotNull VirtualFile declarationDirectory) { for (String pathString : paths) { if (GoImportReferenceSet.isRelativeImport(pathString)) { VirtualFile file = referenceDirectory.findFileByRelativePath(pathString); if (declarationDirectory.equals(file)) { return true; } } } return false; } @Override public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) { return 0; } @Override public boolean isSearchInModuleContent(@NotNull Module aModule) { return GoSdkService.getInstance(ObjectUtils.assertNotNull(getProject())).isGoModule(aModule); } @Override public boolean isSearchInLibraries() { return false; } }