/*
* 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.GoConstants;
import com.goide.project.GoVendoringUtil;
import com.goide.psi.impl.GoPsiImplUtil;
import com.goide.sdk.GoSdkService;
import com.goide.sdk.GoSdkUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
public class GoPathScopeHelper {
@NotNull
private final Set<VirtualFile> myRoots;
@Nullable
private final VirtualFile mySdkHome;
private final boolean mySupportsInternalPackages;
private final boolean mySupportsSdkInternalPackages;
private final boolean myVendoringEnabled;
public static GoPathScopeHelper fromReferenceFile(@NotNull Project project,
@Nullable Module module,
@Nullable VirtualFile referenceFile) {
VirtualFile sdkHome = GoSdkUtil.getSdkSrcDir(project, module);
String sdkVersion = GoSdkService.getInstance(project).getSdkVersion(module);
boolean supportsInternalPackages = GoVendoringUtil.supportsInternalPackages(sdkVersion);
boolean supportsSdkInternalPackages = GoVendoringUtil.supportsSdkInternalPackages(sdkVersion);
boolean vendoringEnabled = GoVendoringUtil.isVendoringEnabled(module);
Set<VirtualFile> sourceRoots = vendoringEnabled ? GoSdkUtil.getVendoringAwareSourcesPathsToLookup(project, module, referenceFile)
: GoSdkUtil.getSourcesPathsToLookup(project, module);
return new GoPathScopeHelper(sourceRoots, sdkHome, supportsInternalPackages, supportsSdkInternalPackages, vendoringEnabled);
}
private GoPathScopeHelper(@NotNull Set<VirtualFile> roots,
@Nullable VirtualFile sdkHome,
boolean supportsInternalPackages,
boolean supportsSdkInternalPackages,
boolean vendoringEnabled) {
myRoots = roots;
mySdkHome = sdkHome;
mySupportsInternalPackages = supportsInternalPackages;
mySupportsSdkInternalPackages = supportsSdkInternalPackages;
myVendoringEnabled = vendoringEnabled;
}
public boolean couldBeReferenced(@NotNull VirtualFile declarationFile, @Nullable VirtualFile referenceFile) {
VirtualFile declarationDirectory = declarationFile.getParent();
if (declarationDirectory == null) {
return true;
}
if (ApplicationManager.getApplication().isUnitTestMode() && myRoots.contains(declarationDirectory)) {
return true;
}
String importPath = GoSdkUtil.getRelativePathToRoots(declarationDirectory, myRoots);
if (importPath == null) {
return false;
}
if (importPath.isEmpty()) {
return true;
}
VirtualFile referenceDirectory = referenceFile != null ? referenceFile.getParent() : null;
if (referenceDirectory != null) {
if (myVendoringEnabled && GoSdkUtil.isUnreachableVendoredPackage(declarationDirectory, referenceDirectory, myRoots)) {
return false;
}
boolean declarationIsInSdk = mySdkHome != null && VfsUtilCore.isAncestor(mySdkHome, declarationDirectory, false);
if (mySupportsInternalPackages || mySupportsSdkInternalPackages && declarationIsInSdk) {
if (GoSdkUtil.isUnreachableInternalPackage(declarationDirectory, referenceDirectory, myRoots)) {
return false;
}
}
if (declarationIsInSdk && GoSdkUtil.findParentDirectory(declarationDirectory, myRoots, GoConstants.TESTDATA_NAME) != null) {
return false;
}
else {
boolean referenceIsInSdk = mySdkHome != null && VfsUtilCore.isAncestor(mySdkHome, referenceDirectory, false);
if (referenceIsInSdk) {
return false;
}
}
}
return GoPsiImplUtil.allowed(declarationFile, referenceFile) && !isShadowedImportPath(declarationDirectory, importPath, myRoots);
}
private static boolean isShadowedImportPath(@NotNull VirtualFile targetDirectory,
@NotNull String targetImportPath,
@NotNull Collection<VirtualFile> roots) {
assert targetDirectory.isDirectory();
for (VirtualFile root : roots) {
VirtualFile realDirectoryToResolve = root.findFileByRelativePath(targetImportPath);
if (realDirectoryToResolve != null) {
return !targetDirectory.equals(realDirectoryToResolve);
}
}
return false;
}
@NotNull
public Set<VirtualFile> getRoots() {
return myRoots;
}
public boolean isVendoringEnabled() {
return myVendoringEnabled;
}
}