/* * 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.GoExcludedPathsSettings; import com.goide.psi.*; import com.goide.psi.impl.GoPsiImplUtil; import com.goide.runconfig.testing.GoTestFinder; import com.goide.sdk.GoPackageUtil; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManager; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.search.DelegatingGlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.ThreeState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class GoUtil { private static final String PLUGIN_ID = "ro.redeul.google.go"; private GoUtil() {} public static boolean matchedForModuleBuildTarget(@NotNull PsiFile file, @Nullable Module module) { return module == null || new GoBuildMatcher(GoTargetSystem.forModule(module)).matchFile(file); } public static boolean isExcludedFile(@NotNull GoFile file) { return CachedValuesManager.getCachedValue(file, () -> { String importPath = file.getImportPath(false); GoExcludedPathsSettings excludedSettings = GoExcludedPathsSettings.getInstance(file.getProject()); return CachedValueProvider.Result.create(importPath != null && excludedSettings.isExcluded(importPath), file, excludedSettings); }); } @NotNull public static String systemOS() { // TODO android? dragonfly nacl? netbsd openbsd plan9 if (SystemInfo.isMac) { return "darwin"; } if (SystemInfo.isFreeBSD) { return "freebsd"; } if (SystemInfo.isLinux) { return GoConstants.LINUX_OS; } if (SystemInfo.isSolaris) { return "solaris"; } if (SystemInfo.isWindows) { return "windows"; } return "unknown"; } @NotNull public static String systemArch() { if (SystemInfo.is64Bit) { return GoConstants.AMD64; } if (SystemInfo.isWindows) { String arch = System.getenv("PROCESSOR_ARCHITECTURE"); String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432"); return arch.endsWith("64") || wow64Arch != null && wow64Arch.endsWith("64") ? GoConstants.AMD64 : "386"; } if (SystemInfo.is32Bit) { return "386"; } return "unknown"; } @NotNull public static ThreeState systemCgo(@NotNull String os, @NotNull String arch) { return GoConstants.KNOWN_CGO.contains(os + "/" + arch) ? ThreeState.YES : ThreeState.NO; } public static boolean fileToIgnore(@NotNull String fileName) { return StringUtil.startsWithChar(fileName, '_') || StringUtil.startsWithChar(fileName, '.'); } public static GlobalSearchScope goPathUseScope(@NotNull PsiElement context, boolean filterByImportList) { return GoPathUseScope.create(context, filterByImportList); } public static GlobalSearchScope goPathResolveScope(@NotNull PsiElement context) { // it's important to ask module on file, otherwise module won't be found for elements in libraries files [zolotov] Module module = ModuleUtilCore.findModuleForPsiElement(context.getContainingFile()); return GoPathResolveScope.create(context.getProject(), module, context); } public static GlobalSearchScope goPathResolveScope(@NotNull Module module, @Nullable PsiElement context) { return GoPathResolveScope.create(module.getProject(), module, context); } @NotNull public static GlobalSearchScope moduleScope(@NotNull Module module) { return GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module).uniteWith(module.getModuleContentWithDependenciesScope()); } @NotNull public static GlobalSearchScope moduleScopeWithoutLibraries(@NotNull Project project, @Nullable Module module) { return module != null ? GlobalSearchScope.moduleWithDependenciesScope(module).uniteWith(module.getModuleContentWithDependenciesScope()) : GlobalSearchScope.projectScope(project); } @NotNull @SuppressWarnings("ConstantConditions") public static IdeaPluginDescriptor getPlugin() { return PluginManager.getPlugin(PluginId.getId(PLUGIN_ID)); } /** * isReferenceTo optimization. Before complex checking via resolve we can say for sure that element * can't be a reference to given declaration in following cases:<br/> * – Blank definitions can't be used as value, so this method return false for all named elements with '_' name<br/> * – GoLabelRef can't be resolved to anything but GoLabelDefinition<br/> * – GoTypeReferenceExpression (not from receiver type) can't be resolved to anything but GoTypeSpec or GoImportSpec<br/> * – Definition is private and reference in different package<br/> */ public static boolean couldBeReferenceTo(@NotNull PsiElement definition, @NotNull PsiElement reference) { if (definition instanceof PsiDirectory && reference instanceof GoReferenceExpressionBase) return true; if (reference instanceof GoLabelRef && !(definition instanceof GoLabelDefinition)) return false; if (reference instanceof GoTypeReferenceExpression && !(definition instanceof GoTypeSpec || definition instanceof GoImportSpec)) { return false; } PsiFile definitionFile = definition.getContainingFile(); PsiFile referenceFile = reference.getContainingFile(); // todo: zolotov, are you sure? cross refs, for instance? if (!(definitionFile instanceof GoFile) || !(referenceFile instanceof GoFile)) return false; boolean inSameFile = definitionFile.isEquivalentTo(referenceFile); if (inSameFile) return true; if (inSamePackage(referenceFile, definitionFile)) return true; return !(reference instanceof GoNamedElement && !((GoNamedElement)reference).isPublic()); } public static boolean inSamePackage(@NotNull PsiFile firstFile, @NotNull PsiFile secondFile) { PsiDirectory containingDirectory = firstFile.getContainingDirectory(); if (containingDirectory == null || !containingDirectory.equals(secondFile.getContainingDirectory())) { return false; } if (firstFile instanceof GoFile && secondFile instanceof GoFile) { String referencePackage = ((GoFile)firstFile).getPackageName(); String definitionPackage = ((GoFile)secondFile).getPackageName(); return referencePackage != null && referencePackage.equals(definitionPackage); } return true; } @NotNull public static String suggestPackageForDirectory(@Nullable PsiDirectory directory) { String packageName = GoPsiImplUtil.getLocalPackageName(directory != null ? directory.getName() : ""); for (String p : GoPackageUtil.getAllPackagesInDirectory(directory, null, true)) { if (!GoConstants.MAIN.equals(p)) { return p; } } return packageName; } public static class ExceptTestsScope extends DelegatingGlobalSearchScope { public ExceptTestsScope(@NotNull GlobalSearchScope baseScope) { super(baseScope); } @Override public boolean contains(@NotNull VirtualFile file) { return !GoTestFinder.isTestFile(file) && super.contains(file); } } public static class TestsScope extends DelegatingGlobalSearchScope { public TestsScope(@NotNull GlobalSearchScope baseScope) { super(baseScope); } @Override public boolean contains(@NotNull VirtualFile file) { return GoTestFinder.isTestFile(file) && super.contains(file); } } public static class ExceptChildOfDirectory extends DelegatingGlobalSearchScope { @NotNull private final VirtualFile myParent; @Nullable private final String myAllowedPackageInExcludedDirectory; public ExceptChildOfDirectory(@NotNull VirtualFile parent, @NotNull GlobalSearchScope baseScope, @Nullable String allowedPackageInExcludedDirectory) { super(baseScope); myParent = parent; myAllowedPackageInExcludedDirectory = allowedPackageInExcludedDirectory; } @Override public boolean contains(@NotNull VirtualFile file) { if (myParent.equals(file.getParent())) { if (myAllowedPackageInExcludedDirectory == null) { return false; } Project project = getProject(); PsiFile psiFile = project != null ? PsiManager.getInstance(project).findFile(file) : null; if (!(psiFile instanceof GoFile)) { return false; } if (!myAllowedPackageInExcludedDirectory.equals(((GoFile)psiFile).getPackageName())) { return false; } } return super.contains(file); } } }