mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
initial version of quickfix to trigger generation of IronPython binary stubs
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
package com.jetbrains.python.actions;
|
||||
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyImportReferenceImpl;
|
||||
import com.jetbrains.python.sdk.IronPythonSdkFlavor;
|
||||
import com.jetbrains.python.sdk.PythonSdkFlavor;
|
||||
import com.jetbrains.python.sdk.PythonSdkType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class GenerateBinaryStubsFix implements LocalQuickFix {
|
||||
private String myQualifiedName;
|
||||
private Sdk mySdk;
|
||||
|
||||
public GenerateBinaryStubsFix(PsiReference reference) {
|
||||
myQualifiedName = getReferenceText(reference);
|
||||
mySdk = getPythonSdk(reference);
|
||||
}
|
||||
|
||||
private static String getReferenceText(PsiReference reference) {
|
||||
PsiElement element = reference.getElement();
|
||||
while (element.getParent() instanceof PyReferenceExpression) {
|
||||
element = element.getParent();
|
||||
}
|
||||
return element.getText();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "Generate stubs for binary module " + myQualifiedName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return "GenerateBinaryStubs";
|
||||
}
|
||||
|
||||
public void applyFix(@NotNull Project project, @NotNull final ProblemDescriptor descriptor) {
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
public void run() {
|
||||
List<String> assemblyRefs = collectAssemblyReferences(descriptor.getPsiElement().getContainingFile());
|
||||
final String skeletonPath = PythonSdkType.findSkeletonsPath(mySdk);
|
||||
PythonSdkType.generateSkeleton(mySdk.getHomePath(), skeletonPath, myQualifiedName, assemblyRefs);
|
||||
final VirtualFile skeletonDir = LocalFileSystem.getInstance().findFileByPath(skeletonPath);
|
||||
if (skeletonDir != null) {
|
||||
skeletonDir.refresh(true, true);
|
||||
}
|
||||
}
|
||||
}, "Generating stubs for binary module", false, project);
|
||||
}
|
||||
|
||||
private List<String> collectAssemblyReferences(PsiFile file) {
|
||||
if (!(PythonSdkFlavor.getFlavor(mySdk.getHomePath()) instanceof IronPythonSdkFlavor)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final List<String> result = new ArrayList<String>();
|
||||
file.accept(new PyRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitPyCallExpression(PyCallExpression node) {
|
||||
super.visitPyCallExpression(node);
|
||||
if (node.isCalleeText("AddReference") || node.isCalleeText("AddReferenceByPartialName")) {
|
||||
final PyExpression[] args = node.getArguments();
|
||||
if (args.length == 1 && args [0] instanceof PyStringLiteralExpression) {
|
||||
result.add(((PyStringLiteralExpression) args [0]).getStringValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean isApplicable(PsiReference ref) {
|
||||
if (!(ref instanceof PyImportReferenceImpl)) {
|
||||
return false;
|
||||
}
|
||||
final Sdk sdk = getPythonSdk(ref);
|
||||
if (sdk == null) {
|
||||
return false;
|
||||
}
|
||||
final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk.getHomePath());
|
||||
if (flavor instanceof IronPythonSdkFlavor) {
|
||||
return getReferenceText(ref).contains("System");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Sdk getPythonSdk(PsiReference ref) {
|
||||
final Module module = ModuleUtil.findModuleForPsiElement(ref.getElement());
|
||||
return module == null ? null : PythonSdkType.findPythonSdk(module);
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.actions.AddFieldQuickFix;
|
||||
import com.jetbrains.python.actions.AddImportAction;
|
||||
import com.jetbrains.python.actions.AddMethodQuickFix;
|
||||
import com.jetbrains.python.actions.ImportFromExistingFix;
|
||||
import com.jetbrains.python.actions.*;
|
||||
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyBuiltinCache;
|
||||
@@ -373,6 +370,9 @@ public class PyUnresolvedReferencesInspection extends LocalInspectionTool {
|
||||
hl_type = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL;
|
||||
}
|
||||
|
||||
if (GenerateBinaryStubsFix.isApplicable(reference)) {
|
||||
actions.add(new GenerateBinaryStubsFix(reference));
|
||||
}
|
||||
addPluginQuickFixes(reference, actions);
|
||||
|
||||
PsiElement point = node.getLastChild(); // usually the identifier at the end of qual ref
|
||||
|
||||
@@ -38,6 +38,13 @@ public interface PyCallExpression extends PyExpression {
|
||||
@Nullable
|
||||
PyMarkedFunction resolveCallee();
|
||||
|
||||
/**
|
||||
* Checks if the unqualified name of the callee matches the specified text.
|
||||
*
|
||||
* @param name the text to check
|
||||
* @return true if matches, false otherwise
|
||||
*/
|
||||
boolean isCalleeText(@NotNull String name);
|
||||
|
||||
/**
|
||||
* Couples function with a flag describing the way it is called.
|
||||
|
||||
@@ -49,6 +49,14 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress
|
||||
return PyCallExpressionHelper.resolveCallee(this);
|
||||
}
|
||||
|
||||
public boolean isCalleeText(@NotNull String name) {
|
||||
final PyExpression callee = getCallee();
|
||||
if (!(callee instanceof PyReferenceExpression)) {
|
||||
return false;
|
||||
}
|
||||
return name.equals(((PyReferenceExpression)callee).getReferencedName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PyCallExpression: " + PyUtil.getReadableRepr(getCallee(), true); //or: getCalledFunctionReference().getReferencedName();
|
||||
|
||||
@@ -102,6 +102,14 @@ public class PyDecoratorImpl extends PyPresentableElementImpl<PyDecoratorStub> i
|
||||
return callee;
|
||||
}
|
||||
|
||||
public boolean isCalleeText(@NotNull String name) {
|
||||
final PyExpression callee = getCallee();
|
||||
if (!(callee instanceof PyReferenceExpression)) {
|
||||
return false;
|
||||
}
|
||||
return name.equals(((PyReferenceExpression)callee).getReferencedName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PyDecorator: @" + PyUtil.getReadableRepr(getCallee(), true); //getCalledFunctionReference().getReferencedName();
|
||||
|
||||
@@ -48,10 +48,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.TreeSet;
|
||||
import java.util.*;
|
||||
|
||||
import static com.jetbrains.python.psi.PyUtil.sure;
|
||||
|
||||
@@ -98,8 +95,6 @@ public class PythonSdkType extends SdkType {
|
||||
return PyBuiltinCache.BUILTIN_FILE;
|
||||
}
|
||||
|
||||
@NonNls static final private String PYTHON_STR = "python";
|
||||
|
||||
@NonNls
|
||||
@Nullable
|
||||
public String suggestHomePath() {
|
||||
@@ -352,9 +347,8 @@ public class PythonSdkType extends SdkType {
|
||||
}
|
||||
}
|
||||
// fix skeletons as needed
|
||||
String url = findSkeletonsUrl(currentSdk);
|
||||
if (url != null) {
|
||||
final String path = VfsUtil.urlToPath(url);
|
||||
final String path = findSkeletonsPath(currentSdk);
|
||||
if (path != null) {
|
||||
File stubs_dir = new File(path);
|
||||
if (!stubs_dir.exists()) {
|
||||
final ProgressManager progman = ProgressManager.getInstance();
|
||||
@@ -364,7 +358,7 @@ public class PythonSdkType extends SdkType {
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
try {
|
||||
generateBuiltinStubs(currentSdk.getHomePath(), path);
|
||||
generateBinaryStubs(currentSdk.getHomePath(), path, indicator);
|
||||
generateBinarySkeletons(currentSdk.getHomePath(), path, indicator);
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
@@ -410,11 +404,11 @@ public class PythonSdkType extends SdkType {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String findSkeletonsUrl(Sdk sdk) {
|
||||
public static String findSkeletonsPath(Sdk sdk) {
|
||||
final String[] urls = sdk.getRootProvider().getUrls(BUILTIN_ROOT_TYPE);
|
||||
for (String url : urls) {
|
||||
if (url.contains(SKELETON_DIR_NAME)) {
|
||||
return url;
|
||||
return VfsUtil.urlToPath(url);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -528,7 +522,7 @@ public class PythonSdkType extends SdkType {
|
||||
// regenerate stubs, existing or not
|
||||
final File stubs_dir = new File(stubs_path);
|
||||
if (!stubs_dir.exists()) stubs_dir.mkdirs();
|
||||
generateBinaryStubs(bin_path, stubs_path, indicator);
|
||||
generateBinarySkeletons(bin_path, stubs_path, indicator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,8 +597,7 @@ public class PythonSdkType extends SdkType {
|
||||
* @param stubsRoot where to put results (expected to exist).
|
||||
* @param indicator ProgressIndicator to update, or null.
|
||||
*/
|
||||
public static void generateBinaryStubs(final String binaryPath, final String stubsRoot, ProgressIndicator indicator)
|
||||
{
|
||||
public static void generateBinarySkeletons(final String binaryPath, final String stubsRoot, ProgressIndicator indicator) {
|
||||
if (indicator != null) {
|
||||
indicator.setText("Generating skeletons of binary libs");
|
||||
}
|
||||
@@ -635,19 +628,7 @@ public class PythonSdkType extends SdkType {
|
||||
indicator.setText2(modname);
|
||||
}
|
||||
LOG.info("Skeleton for " + modname);
|
||||
final ProcessOutput gen_result = SdkUtil.getProcessOutput(
|
||||
parent_dir,
|
||||
new String[]{binaryPath, PythonHelpersLocator.getHelperPath(GENERATOR3), "-d", stubsRoot, modname},
|
||||
getVirtualEnvAdditionalEnv(binaryPath),
|
||||
RUN_TIMEOUT
|
||||
);
|
||||
if (gen_result.getExitCode() != 0) {
|
||||
StringBuffer sb = new StringBuffer("Skeleton for ");
|
||||
sb.append(modname).append(" failed. stderr: --");
|
||||
for (String err_line : gen_result.getStderrLines()) sb.append(err_line).append("\n");
|
||||
sb.append("--");
|
||||
LOG.warn(sb.toString());
|
||||
}
|
||||
generateSkeleton(binaryPath, stubsRoot, modname, Collections.<String>emptyList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -661,6 +642,34 @@ public class PythonSdkType extends SdkType {
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateSkeleton(String binaryPath, String stubsRoot, String modname, List<String> assemblyRefs) {
|
||||
final String parent_dir = new File(binaryPath).getParent();
|
||||
List<String> commandLine = new ArrayList<String>();
|
||||
commandLine.add(binaryPath);
|
||||
commandLine.add(PythonHelpersLocator.getHelperPath(GENERATOR3));
|
||||
commandLine.add("-d");
|
||||
commandLine.add(stubsRoot);
|
||||
if (!assemblyRefs.isEmpty()) {
|
||||
commandLine.add("-c");
|
||||
commandLine.add(StringUtil.join(assemblyRefs, ";"));
|
||||
}
|
||||
commandLine.add(modname);
|
||||
|
||||
final ProcessOutput gen_result = SdkUtil.getProcessOutput(
|
||||
parent_dir,
|
||||
commandLine.toArray(new String[commandLine.size()]),
|
||||
getVirtualEnvAdditionalEnv(binaryPath),
|
||||
RUN_TIMEOUT*10
|
||||
);
|
||||
if (gen_result.getExitCode() != 0) {
|
||||
StringBuffer sb = new StringBuffer("Skeleton for ");
|
||||
sb.append(modname).append(" failed. stderr: --");
|
||||
for (String err_line : gen_result.getStderrLines()) sb.append(err_line).append("\n");
|
||||
sb.append("--");
|
||||
LOG.warn(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Sdk> getAllSdks() {
|
||||
return ProjectJdkTable.getInstance().getSdksOfType(getInstance());
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.*;
|
||||
@@ -30,10 +30,9 @@ public class SkeletonVersionUpdater implements ProjectComponent {
|
||||
writeVersion(versionFile, SKELETONS_VERSION);
|
||||
final List<Sdk> sdkList = PythonSdkType.getAllSdks();
|
||||
for (Sdk sdk : sdkList) {
|
||||
final String url = PythonSdkType.findSkeletonsUrl(sdk);
|
||||
final String path = VfsUtil.urlToPath(url);
|
||||
final String path = PythonSdkType.findSkeletonsPath(sdk);
|
||||
PythonSdkType.generateBuiltinStubs(sdk.getHomePath(), path);
|
||||
PythonSdkType.generateBinaryStubs(sdk.getHomePath(), path, ProgressManager.getInstance().getProgressIndicator());
|
||||
PythonSdkType.generateBinarySkeletons(sdk.getHomePath(), path, ProgressManager.getInstance().getProgressIndicator());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user