mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+1
@@ -151,6 +151,7 @@
|
||||
<scope name="runtime.classes" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="BadExpressionStatementJS" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="BashSimpleVarUsage" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="BeforeClassOrAfterClassIsPublicStaticVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="BeforeOrAfterIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="BindingAnnotationWithoutInject" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
|
||||
@@ -199,9 +199,13 @@ LD_LIBRARY_PATH="$IDE_BIN_HOME:$LD_LIBRARY_PATH" "$JAVA_BIN" \
|
||||
com.intellij.idea.Main \
|
||||
"$@"
|
||||
EC=$?
|
||||
|
||||
test $EC -ne 88 && exit $EC
|
||||
if [ -x "$HOME/.@@system_selector@@/restart/restarter.sh" ]; then
|
||||
"$HOME/.@@system_selector@@/restart/restarter.sh"
|
||||
"$RM" -f "$HOME/.@@system_selector@@/restart/restarter.sh"
|
||||
|
||||
RESTARTER="$HOME/.@@system_selector@@/restart/restarter.sh"
|
||||
if [ -x "$RESTARTER" ]; then
|
||||
"$RESTARTER"
|
||||
"$RM" -f "$RESTARTER"
|
||||
fi
|
||||
|
||||
exec "$0" "$@"
|
||||
|
||||
+86
-23
@@ -15,22 +15,27 @@
|
||||
*/
|
||||
package com.intellij.execution.scratch;
|
||||
|
||||
import com.intellij.execution.application.ApplicationConfigurable;
|
||||
import com.intellij.execution.application.ApplicationConfiguration;
|
||||
import com.intellij.application.options.ModulesComboBox;
|
||||
import com.intellij.execution.ui.CommonJavaParametersPanel;
|
||||
import com.intellij.execution.ui.ConfigurationModuleSelector;
|
||||
import com.intellij.execution.ui.DefaultJreSelector;
|
||||
import com.intellij.execution.ui.JrePathEditor;
|
||||
import com.intellij.ide.scratch.ScratchFileService;
|
||||
import com.intellij.ide.scratch.ScratchRootType;
|
||||
import com.intellij.openapi.fileChooser.FileChooser;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.LabeledComponent;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileWithId;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel;
|
||||
import com.intellij.ui.PanelWithAnchor;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -43,13 +48,28 @@ import java.awt.event.ActionListener;
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 30-Sep-15
|
||||
*/
|
||||
public class JavaScratchConfigurable extends ApplicationConfigurable{
|
||||
public class JavaScratchConfigurable extends SettingsEditor<JavaScratchConfiguration> implements PanelWithAnchor {
|
||||
|
||||
private final TextFieldWithBrowseButton myScratchPathField;
|
||||
private final CommonJavaParametersPanel myCommonProgramParameters;
|
||||
private final LabeledComponent<JTextField> myMainClass;
|
||||
private final LabeledComponent<TextFieldWithBrowseButton> myScratchPathField;
|
||||
private final LabeledComponent<ModulesComboBox> myModule;
|
||||
private JPanel myWholePanel;
|
||||
|
||||
private final ConfigurationModuleSelector myModuleSelector;
|
||||
private JrePathEditor myJrePathEditor;
|
||||
private JComponent myAnchor;
|
||||
|
||||
public JavaScratchConfigurable(final Project project) {
|
||||
super(project);
|
||||
myScratchPathField = new TextFieldWithBrowseButton(new ActionListener() {
|
||||
myMainClass = new LabeledComponent<JTextField>();
|
||||
myMainClass.setLabelLocation(BorderLayout.WEST);
|
||||
myMainClass.setText("Main &class:");
|
||||
myMainClass.setComponent(new JTextField());
|
||||
|
||||
myScratchPathField = new LabeledComponent<TextFieldWithBrowseButton>();
|
||||
myScratchPathField.setLabelLocation(BorderLayout.WEST);
|
||||
myScratchPathField.setText("&Path to scratch file:");
|
||||
myScratchPathField.setComponent(new TextFieldWithBrowseButton(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
VirtualFile toSelect = getVFileFromEditor();
|
||||
@@ -63,33 +83,64 @@ public class JavaScratchConfigurable extends ApplicationConfigurable{
|
||||
setVFileToEditor(file);
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
}, this));
|
||||
|
||||
myModule = new LabeledComponent<ModulesComboBox>();
|
||||
myModule.setLabelLocation(BorderLayout.WEST);
|
||||
myModule.setComponent(new ModulesComboBox());
|
||||
myModule.setText("Use classpath of &module:");
|
||||
myModuleSelector = new ConfigurationModuleSelector(project, myModule.getComponent());
|
||||
|
||||
myCommonProgramParameters = new CommonJavaParametersPanel();
|
||||
myCommonProgramParameters.setModuleContext(myModuleSelector.getModule());
|
||||
myModule.getComponent().addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myCommonProgramParameters.setModuleContext(myModuleSelector.getModule());
|
||||
}
|
||||
});
|
||||
myJrePathEditor = new JrePathEditor();
|
||||
myJrePathEditor.setDefaultJreSelector(DefaultJreSelector.projectSdk(project));
|
||||
|
||||
myWholePanel = new JPanel(new GridBagLayout());
|
||||
myWholePanel.add(myMainClass, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0),0, 0 ));
|
||||
myWholePanel.add(myScratchPathField, new GridBagConstraints(GridBagConstraints.RELATIVE, 1, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0),0, 0 ));
|
||||
myWholePanel.add(myCommonProgramParameters, new GridBagConstraints(GridBagConstraints.RELATIVE, 2, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(12, 0, 12, 0),0, 0 ));
|
||||
myWholePanel.add(myModule, new GridBagConstraints(GridBagConstraints.RELATIVE, 3, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0),0, 0 ));
|
||||
myWholePanel.add(myJrePathEditor, new GridBagConstraints(GridBagConstraints.RELATIVE, 4, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0),0, 0 ));
|
||||
|
||||
myAnchor = UIUtil.mergeComponentsWithAnchor(myMainClass, myScratchPathField, myCommonProgramParameters, myJrePathEditor, myModule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyEditorTo(ApplicationConfiguration configuration) throws ConfigurationException {
|
||||
super.applyEditorTo(configuration);
|
||||
public void applyEditorTo(JavaScratchConfiguration configuration) throws ConfigurationException {
|
||||
myCommonProgramParameters.applyTo(configuration);
|
||||
myModuleSelector.applyTo(configuration);
|
||||
configuration.MAIN_CLASS_NAME = myMainClass.getComponent().getText().trim();
|
||||
configuration.ALTERNATIVE_JRE_PATH = myJrePathEditor.getJrePathOrName();
|
||||
configuration.ALTERNATIVE_JRE_PATH_ENABLED = myJrePathEditor.isAlternativeJreSelected();
|
||||
|
||||
final VirtualFile vFile = getVFileFromEditor();
|
||||
((JavaScratchConfiguration)configuration).SCRATCH_FILE_ID = vFile instanceof VirtualFileWithId ? ((VirtualFileWithId)vFile).getId() : 0;
|
||||
configuration.SCRATCH_FILE_ID = vFile instanceof VirtualFileWithId ? ((VirtualFileWithId)vFile).getId() : 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VirtualFile getVFileFromEditor() {
|
||||
final String path = FileUtil.toSystemIndependentName(myScratchPathField.getText());
|
||||
final String path = FileUtil.toSystemIndependentName(myScratchPathField.getComponent().getText().trim());
|
||||
return !StringUtil.isEmpty(path) ? LocalFileSystem.getInstance().findFileByPath(path) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetEditorFrom(ApplicationConfiguration configuration) {
|
||||
super.resetEditorFrom(configuration);
|
||||
final JavaScratchConfiguration scratchConfig = (JavaScratchConfiguration)configuration;
|
||||
final VirtualFile file = scratchConfig.getScratchVirtualFile();
|
||||
setVFileToEditor(file);
|
||||
public void resetEditorFrom(JavaScratchConfiguration configuration) {
|
||||
myCommonProgramParameters.reset(configuration);
|
||||
myModuleSelector.reset(configuration);
|
||||
myMainClass.getComponent().setText(configuration.MAIN_CLASS_NAME != null ? configuration.MAIN_CLASS_NAME.replaceAll("\\$", "\\.") : "");
|
||||
myJrePathEditor.setPathOrName(configuration.ALTERNATIVE_JRE_PATH, configuration.ALTERNATIVE_JRE_PATH_ENABLED);
|
||||
setVFileToEditor(configuration.getScratchVirtualFile());
|
||||
}
|
||||
|
||||
private void setVFileToEditor(VirtualFile file) {
|
||||
if (file != null) {
|
||||
myScratchPathField.setText(FileUtil.toSystemDependentName(file.getPath()));
|
||||
myScratchPathField.getComponent().setText(FileUtil.toSystemDependentName(file.getPath()));
|
||||
}
|
||||
else {
|
||||
myScratchPathField.setText("");
|
||||
@@ -99,9 +150,21 @@ public class JavaScratchConfigurable extends ApplicationConfigurable{
|
||||
@NotNull
|
||||
@Override
|
||||
public JComponent createEditor() {
|
||||
final JPanel panel = new JPanel(new GridBagLayout());
|
||||
panel.add(new JBLabel("Path to scratch file: "), new GridBagConstraints(0, 0, 1, 1, 0.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(20,0,0,10), 0, 0));
|
||||
panel.add(myScratchPathField, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(20, 0, 0, 0), 0, 0));
|
||||
return new BorderLayoutPanel().addToCenter(super.createEditor()).addToBottom(panel);
|
||||
return myWholePanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getAnchor() {
|
||||
return myAnchor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnchor(@Nullable JComponent anchor) {
|
||||
myAnchor = anchor;
|
||||
myMainClass.setAnchor(anchor);
|
||||
myScratchPathField.setAnchor(anchor);
|
||||
myCommonProgramParameters.setAnchor(anchor);
|
||||
myJrePathEditor.setAnchor(anchor);
|
||||
myModule.setAnchor(anchor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +84,8 @@ public class JavaResolveCache {
|
||||
PsiType type = isOverloadCheck ? null : myCalculatedTypes.get(expr);
|
||||
if (type == null) {
|
||||
final RecursionGuard.StackStamp dStackStamp = PsiDiamondType.ourDiamondGuard.markStack();
|
||||
final RecursionGuard.StackStamp gStackStamp = PsiResolveHelper.ourGraphGuard.markStack();
|
||||
type = f.fun(expr);
|
||||
if (!dStackStamp.mayCacheNow() || !gStackStamp.mayCacheNow() || isOverloadCheck) {
|
||||
if (!dStackStamp.mayCacheNow() || isOverloadCheck) {
|
||||
return type;
|
||||
}
|
||||
if (type == null) type = TypeConversionUtil.NULL_TYPE;
|
||||
|
||||
+3
-1
@@ -1195,7 +1195,9 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
LambdaUtil.ourFunctionTypes.set(null);
|
||||
if (formula instanceof InputOutputConstraintFormula) {
|
||||
LambdaUtil.getFunctionalTypeMap().remove(((InputOutputConstraintFormula)formula).getExpression());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+1
-1
@@ -157,7 +157,7 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiExpression getExpression() {
|
||||
public PsiExpression getExpression() {
|
||||
return myExpression;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import java.util.*;
|
||||
*/
|
||||
public abstract class InputOutputConstraintFormula implements ConstraintFormula {
|
||||
|
||||
protected abstract PsiExpression getExpression();
|
||||
public abstract PsiExpression getExpression();
|
||||
protected abstract PsiType getT();
|
||||
protected abstract void setT(PsiType t);
|
||||
protected abstract InputOutputConstraintFormula createSelfConstraint(PsiType type, PsiExpression expression);
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package nise;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
|
||||
class TypeTest {
|
||||
public static void main(String[] args) {
|
||||
assertThat(id(new Combiner<>(echo("A"), echo("B"), (str1, str2) ->
|
||||
new StringBuilder(str1.length() + str2.length())
|
||||
.append(str1)
|
||||
.append(str2))).get(),
|
||||
hasSameContentAs("AB"));
|
||||
}
|
||||
|
||||
private static <R> Supplier<R> id(Supplier<R> s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
private static <T> Supplier<T> echo(T s) {
|
||||
return () -> s;
|
||||
}
|
||||
|
||||
private static Predicate<CharSequence> hasSameContentAs(CharSequence seq) {
|
||||
return charSequence -> charSequence.toString().equals(seq.toString());
|
||||
}
|
||||
|
||||
private static <T> void assertThat(T actual, Predicate<? super T> matcher) {
|
||||
if (!matcher.test(actual)) throw new AssertionError();
|
||||
}
|
||||
|
||||
private static class Combiner<T1, T2, R> implements Supplier<R> {
|
||||
private final Supplier<T1> s1;
|
||||
private final Supplier<T2> s2;
|
||||
private final BiFunction<T1, T2, R> f;
|
||||
|
||||
public Combiner(Supplier<T1> s1, Supplier<T2> s2, BiFunction<T1, T2, R> f) {
|
||||
this.s1 = s1;
|
||||
this.s2 = s2;
|
||||
this.f = f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R get() {
|
||||
return f.apply(s1.get(), s2.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class Test {
|
||||
void f(Stream<ReviewDiffRecord> stream1) {
|
||||
final Supplier<List<String>> revisionDiffItemDTOs = () -> stream1.map(record -> {
|
||||
foo(null);
|
||||
final Object stream = record.getAllNodes().stream();
|
||||
return "";
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
private <T> void foo(T t) throws RuntimeException {}
|
||||
|
||||
private class ReviewDiffRecord {
|
||||
List<String> getAllNodes() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+4
@@ -46,6 +46,10 @@ public class Diamond8HighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testWithConstructorRefInside() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIDEA140686() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
||||
|
||||
+4
-4
@@ -16,17 +16,13 @@
|
||||
package com.intellij.codeInsight.daemon.lambda;
|
||||
|
||||
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
|
||||
@NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/expressions";
|
||||
@@ -47,6 +43,10 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
|
||||
doTestAllMethodCallExpressions();
|
||||
}
|
||||
|
||||
public void testProoveThatInferenceInsideLambdaBodyDontInfluenceOuterCallInference() throws Exception {
|
||||
doTestAllMethodCallExpressions();
|
||||
}
|
||||
|
||||
public void testCachedUnresolvedMethods() throws Exception {
|
||||
doTestCachedUnresolved();
|
||||
}
|
||||
|
||||
@@ -274,7 +274,6 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep
|
||||
public void dispose() {
|
||||
if (myDisposed) return;
|
||||
|
||||
myLivePreview.cleanUp();
|
||||
off();
|
||||
|
||||
mySearchResults.dispose();
|
||||
|
||||
@@ -46,4 +46,8 @@ public abstract class ScratchFileService {
|
||||
|
||||
@NotNull
|
||||
public abstract PerFileMappings<Language> getScratchesMapping();
|
||||
|
||||
public static boolean isInScratchRoot(@Nullable VirtualFile file) {
|
||||
return getInstance().getRootType(file) != null;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-8
@@ -22,9 +22,9 @@ import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.refactoring.move.MoveCallback;
|
||||
import com.intellij.refactoring.move.MoveHandlerDelegate;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -62,13 +62,7 @@ public class MoveFilesOrDirectoriesHandler extends MoveHandlerDelegate {
|
||||
|
||||
public static boolean isValidTarget(PsiElement psiElement) {
|
||||
if (!(psiElement instanceof PsiDirectory || psiElement instanceof PsiDirectoryContainer)) return false;
|
||||
return psiElement.getManager().isInProject(psiElement) || isInScratches(psiElement);
|
||||
}
|
||||
|
||||
protected static boolean isInScratches(PsiElement psiElement) {
|
||||
VirtualFile virtualFile = psiElement instanceof PsiFileSystemItem ? ((PsiFileSystemItem)psiElement).getVirtualFile() : null;
|
||||
if (virtualFile != null && ScratchFileService.getInstance().getRootType(virtualFile) != null) return true;
|
||||
return false;
|
||||
return psiElement.getManager().isInProject(psiElement) || ScratchFileService.isInScratchRoot(PsiUtilCore.getVirtualFile(psiElement));
|
||||
}
|
||||
|
||||
public void doMove(final PsiElement[] elements, final PsiElement targetContainer) {
|
||||
|
||||
@@ -300,7 +300,10 @@ public class RenameProcessor extends BaseRefactoringProcessor {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
PsiElement element = elements.get(i);
|
||||
LOG.assertTrue(element != null);
|
||||
if (element == null) {
|
||||
LOG.error("primary: " + myPrimaryElement + "; renamers: " + myRenamers);
|
||||
continue;
|
||||
}
|
||||
final String newName = myAllRenames.get(element);
|
||||
final UsageInfo[] usages = RenameUtil.findUsages(element, newName, mySearchInComments, mySearchTextOccurrences, myAllRenames);
|
||||
final List<UsageInfo> usagesList = Arrays.asList(usages);
|
||||
|
||||
@@ -107,7 +107,7 @@ class LineLayout {
|
||||
List<BidiRun> runs = createRuns(editor, chars, -1);
|
||||
for (BidiRun run : runs) {
|
||||
for (Chunk chunk : run.getChunks()) {
|
||||
addFragments(chunk, run.isRtl(), chars, chunk.startOffset, chunk.endOffset, fontStyle, fontPreferences, fontRenderContext, null);
|
||||
addFragments(run, chunk, chars, chunk.startOffset, chunk.endOffset, fontStyle, fontPreferences, fontRenderContext, null);
|
||||
}
|
||||
}
|
||||
return runs;
|
||||
@@ -150,6 +150,18 @@ class LineLayout {
|
||||
}
|
||||
|
||||
private static void addRuns(List<BidiRun> runs, char[] text, int start, int end) {
|
||||
int afterLastTabPosition = start;
|
||||
for (int i = start; i < end; i++) {
|
||||
if (text[i] == '\t') {
|
||||
addRunsNoTabs(runs, text, afterLastTabPosition, i);
|
||||
afterLastTabPosition = i + 1;
|
||||
addOrMergeRun(runs, new BidiRun((byte)0, i, i + 1));
|
||||
}
|
||||
}
|
||||
addRunsNoTabs(runs, text, afterLastTabPosition, end);
|
||||
}
|
||||
|
||||
private static void addRunsNoTabs(List<BidiRun> runs, char[] text, int start, int end) {
|
||||
if (start >= end) return;
|
||||
Bidi bidi = new Bidi(text, start, null, 0, end - start, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
|
||||
int runCount = bidi.getRunCount();
|
||||
@@ -170,7 +182,7 @@ class LineLayout {
|
||||
}
|
||||
}
|
||||
|
||||
private static void addFragments(Chunk chunk, boolean isRtl, char[] text, int start, int end, int fontStyle,
|
||||
private static void addFragments(BidiRun run, Chunk chunk, char[] text, int start, int end, int fontStyle,
|
||||
FontPreferences fontPreferences, FontRenderContext fontRenderContext,
|
||||
@Nullable TabFragment tabFragment) {
|
||||
assert start < end;
|
||||
@@ -179,7 +191,7 @@ class LineLayout {
|
||||
for(int i = start; i < end; i++) {
|
||||
char c = text[i];
|
||||
if (c == '\t' && tabFragment != null) {
|
||||
assert !isRtl;
|
||||
assert run.level == 0;
|
||||
addTextFragmentIfNeeded(chunk, text, currentIndex, i, currentFont, fontRenderContext, false);
|
||||
chunk.fragments.add(tabFragment);
|
||||
currentFont = null;
|
||||
@@ -188,13 +200,13 @@ class LineLayout {
|
||||
else {
|
||||
Font font = ComplementaryFontsRegistry.getFontAbleToDisplay(c, fontStyle, fontPreferences).getFont();
|
||||
if (!font.equals(currentFont)) {
|
||||
addTextFragmentIfNeeded(chunk, text, currentIndex, i, currentFont, fontRenderContext, isRtl);
|
||||
addTextFragmentIfNeeded(chunk, text, currentIndex, i, currentFont, fontRenderContext, run.isRtl());
|
||||
currentFont = font;
|
||||
currentIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
addTextFragmentIfNeeded(chunk, text, currentIndex, end, currentFont, fontRenderContext, isRtl);
|
||||
addTextFragmentIfNeeded(chunk, text, currentIndex, end, currentFont, fontRenderContext, run.isRtl());
|
||||
assert !chunk.fragments.isEmpty();
|
||||
}
|
||||
|
||||
@@ -342,7 +354,7 @@ class LineLayout {
|
||||
for (Chunk chunk : getChunks()) {
|
||||
if (chunk.endOffset <= start) continue;
|
||||
if (chunk.startOffset >= end) break;
|
||||
subChunks.add(chunk.subChunk(view, lineStartOffset, isRtl(), start, end, quick));
|
||||
subChunks.add(chunk.subChunk(view, this, lineStartOffset, start, end, quick));
|
||||
}
|
||||
subRun.chunks = subChunks.toArray(new Chunk[subChunks.size()]);
|
||||
return subRun;
|
||||
@@ -359,7 +371,7 @@ class LineLayout {
|
||||
this.endOffset = endOffset;
|
||||
}
|
||||
|
||||
private void ensureLayout(@NotNull EditorView view, int lineStartOffset, boolean isRtl) {
|
||||
private void ensureLayout(@NotNull EditorView view, BidiRun run, int lineStartOffset) {
|
||||
if (!fragments.isEmpty()) return;
|
||||
int start = lineStartOffset + startOffset;
|
||||
int end = lineStartOffset + endOffset;
|
||||
@@ -367,7 +379,7 @@ class LineLayout {
|
||||
FontPreferences fontPreferences = view.getEditor().getColorsScheme().getFontPreferences();
|
||||
char[] chars = CharArrayUtil.fromSequence(view.getEditor().getDocument().getImmutableCharSequence(), start, end);
|
||||
while (!it.atEnd()) {
|
||||
addFragments(this, isRtl, chars, it.getStartOffset() - start, it.getEndOffset() - start,
|
||||
addFragments(run, this, chars, it.getStartOffset() - start, it.getEndOffset() - start,
|
||||
it.getMergedAttributes().getFontType(), fontPreferences, view.getFontRenderContext(), view.getTabFragment());
|
||||
it.advance();
|
||||
}
|
||||
@@ -375,7 +387,7 @@ class LineLayout {
|
||||
assert !fragments.isEmpty();
|
||||
}
|
||||
|
||||
private Chunk subChunk(EditorView view, int lineStartOffset, boolean isRtl, int targetStartOffset, int targetEndOffset, boolean quick) {
|
||||
private Chunk subChunk(EditorView view, BidiRun run, int lineStartOffset, int targetStartOffset, int targetEndOffset, boolean quick) {
|
||||
assert targetStartOffset < endOffset;
|
||||
assert targetEndOffset > startOffset;
|
||||
int start = Math.max(startOffset, targetStartOffset);
|
||||
@@ -390,7 +402,7 @@ class LineLayout {
|
||||
if (start == startOffset && end == this.endOffset) {
|
||||
return this;
|
||||
}
|
||||
ensureLayout(view, lineStartOffset, isRtl);
|
||||
ensureLayout(view, run, lineStartOffset);
|
||||
Chunk chunk = new Chunk(start, end);
|
||||
int offset = startOffset;
|
||||
for (LineFragment fragment : fragments) {
|
||||
@@ -434,7 +446,7 @@ class LineLayout {
|
||||
if (myChunkIndex >= chunks.length) return false;
|
||||
Chunk chunk = chunks[run.isRtl() ? chunks.length - 1 - myChunkIndex : myChunkIndex];
|
||||
if (myView != null) {
|
||||
chunk.ensureLayout(myView, myLineStartOffset, run.isRtl());
|
||||
chunk.ensureLayout(myView, run, myLineStartOffset);
|
||||
}
|
||||
return myFragmentIndex < chunk.fragments.size();
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.intellij.ui.HyperlinkLabel;
|
||||
import com.intellij.ui.TextFieldWithHistory;
|
||||
import com.intellij.ui.TextFieldWithHistoryWithBrowseButton;
|
||||
import com.intellij.util.NotNullProducer;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import com.intellij.util.containers.ComparatorUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -295,7 +296,7 @@ public class SwingHelper {
|
||||
boolean mergeWithPrevHistory) {
|
||||
Set<String> newHistorySet = ContainerUtil.newHashSet(history);
|
||||
List<String> prevHistory = textFieldWithHistory.getHistory();
|
||||
List<String> mergedHistory = ContainerUtil.newArrayList();
|
||||
List<String> mergedHistory = ContainerUtil.newArrayListWithCapacity(history.size());
|
||||
if (mergeWithPrevHistory) {
|
||||
for (String item : prevHistory) {
|
||||
if (!newHistorySet.contains(item)) {
|
||||
@@ -303,15 +304,20 @@ public class SwingHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
String currentText = textFieldWithHistory.getText();
|
||||
if (StringUtil.isNotEmpty(currentText) && !newHistorySet.contains(currentText)) {
|
||||
mergedHistory.add(currentText);
|
||||
}
|
||||
}
|
||||
mergedHistory.addAll(history);
|
||||
String oldText = StringUtil.notNullize(textFieldWithHistory.getText());
|
||||
String oldSelectedItem = ObjectUtils.tryCast(textFieldWithHistory.getSelectedItem(), String.class);
|
||||
if (!mergedHistory.contains(oldSelectedItem)) {
|
||||
oldSelectedItem = null;
|
||||
}
|
||||
textFieldWithHistory.setHistory(mergedHistory);
|
||||
setLongestAsPrototype(textFieldWithHistory, mergedHistory);
|
||||
if (oldSelectedItem != null) {
|
||||
textFieldWithHistory.setSelectedItem(oldSelectedItem);
|
||||
}
|
||||
if (!oldText.equals(oldSelectedItem)) {
|
||||
textFieldWithHistory.setText(oldText);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setLongestAsPrototype(@NotNull JComboBox comboBox, @NotNull List<String> variants) {
|
||||
|
||||
@@ -563,6 +563,26 @@ public class EditorRtlTest extends AbstractEditorTest {
|
||||
checkResult("RLR<caret>");
|
||||
}
|
||||
|
||||
public void testTabInsideRtlText() throws Exception {
|
||||
prepareText("<caret>R\tRR");
|
||||
right();
|
||||
checkResult("R<caret>\tRR");
|
||||
right();
|
||||
checkResult("<caret>R\tRR");
|
||||
right();
|
||||
checkResult("R<caret>\tRR");
|
||||
right();
|
||||
checkResult("R\t<caret>RR");
|
||||
right();
|
||||
checkResult("R\tRR<caret>");
|
||||
right();
|
||||
checkResult("R\tR<caret>R");
|
||||
right();
|
||||
checkResult("R\t<caret>RR");
|
||||
right();
|
||||
checkResult("R\tRR<caret>");
|
||||
}
|
||||
|
||||
private void prepareText(String text) throws IOException {
|
||||
prepare(text, TestFileType.TEXT);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiPolyVariantReference;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyExpressionCodeFragmentImpl;
|
||||
@@ -221,7 +220,8 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
if (expr instanceof PySubscriptionExpression) {
|
||||
final PyExpression indexExpr = ((PySubscriptionExpression)expr).getIndexExpression();
|
||||
if (indexExpr != null) {
|
||||
final PyGenericType genericType = getGenericType(indexExpr, context);
|
||||
final PsiElement resolved = tryResolving(indexExpr, context);
|
||||
final PyGenericType genericType = getGenericType(resolved, context);
|
||||
if (genericType != null) {
|
||||
results.add(genericType);
|
||||
}
|
||||
@@ -235,35 +235,36 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
|
||||
@Nullable
|
||||
private static PyType getType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
final PyType unionType = getUnionType(expression, context);
|
||||
final PsiElement resolved = tryResolving(expression, context);
|
||||
final PyType unionType = getUnionType(resolved, context);
|
||||
if (unionType != null) {
|
||||
return unionType;
|
||||
}
|
||||
final Ref<PyType> optionalType = getOptionalTypeFromDefaultNone(expression, context);
|
||||
final Ref<PyType> optionalType = getOptionalTypeFromDefaultNone(resolved, context);
|
||||
if (optionalType != null) {
|
||||
return optionalType.get();
|
||||
}
|
||||
final PyType callableType = getCallableType(expression, context);
|
||||
final PyType callableType = getCallableType(resolved, context);
|
||||
if (callableType != null) {
|
||||
return callableType;
|
||||
}
|
||||
final PyType parameterizedType = getParameterizedType(expression, context);
|
||||
final PyType parameterizedType = getParameterizedType(resolved, context);
|
||||
if (parameterizedType != null) {
|
||||
return parameterizedType;
|
||||
}
|
||||
final PyType builtinCollection = getBuiltinCollection(expression, context);
|
||||
final PyType builtinCollection = getBuiltinCollection(resolved);
|
||||
if (builtinCollection != null) {
|
||||
return builtinCollection;
|
||||
}
|
||||
final PyType genericType = getGenericType(expression, context);
|
||||
final PyType genericType = getGenericType(resolved, context);
|
||||
if (genericType != null) {
|
||||
return genericType;
|
||||
}
|
||||
final Ref<PyType> classType = getClassType(expression, context);
|
||||
final Ref<PyType> classType = getClassType(resolved, context);
|
||||
if (classType != null) {
|
||||
return classType.get();
|
||||
}
|
||||
final PyType stringBasedType = getStringBasedType(expression, context);
|
||||
final PyType stringBasedType = getStringBasedType(resolved, context);
|
||||
if (stringBasedType != null) {
|
||||
return stringBasedType;
|
||||
}
|
||||
@@ -271,28 +272,30 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Ref<PyType> getClassType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
final PyType type = context.getType(expression);
|
||||
if (type != null && isAny(type)) {
|
||||
return Ref.create();
|
||||
}
|
||||
if (type instanceof PyClassLikeType) {
|
||||
final PyClassLikeType classType = (PyClassLikeType)type;
|
||||
if (classType.isDefinition()) {
|
||||
final PyType instanceType = classType.toInstance();
|
||||
return Ref.create(instanceType);
|
||||
private static Ref<PyType> getClassType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
if (element instanceof PyTypedElement) {
|
||||
final PyType type = context.getType((PyTypedElement)element);
|
||||
if (type != null && isAny(type)) {
|
||||
return Ref.create();
|
||||
}
|
||||
if (type instanceof PyClassLikeType) {
|
||||
final PyClassLikeType classType = (PyClassLikeType)type;
|
||||
if (classType.isDefinition()) {
|
||||
final PyType instanceType = classType.toInstance();
|
||||
return Ref.create(instanceType);
|
||||
}
|
||||
}
|
||||
else if (type instanceof PyNoneType) {
|
||||
return Ref.create(type);
|
||||
}
|
||||
}
|
||||
else if (type instanceof PyNoneType) {
|
||||
return Ref.create(type);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Ref<PyType> getOptionalTypeFromDefaultNone(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
if (expression instanceof PySubscriptionExpression) {
|
||||
final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression;
|
||||
private static Ref<PyType> getOptionalTypeFromDefaultNone(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
if (element instanceof PySubscriptionExpression) {
|
||||
final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)element;
|
||||
final PyExpression operand = subscriptionExpr.getOperand();
|
||||
final String operandName = resolveToQualifiedName(operand, context);
|
||||
if ("typing.Optional".equals(operandName)) {
|
||||
@@ -310,11 +313,11 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getStringBasedType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
if (expression instanceof PyStringLiteralExpression) {
|
||||
private static PyType getStringBasedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
if (element instanceof PyStringLiteralExpression) {
|
||||
// XXX: Requires switching from stub to AST
|
||||
final String contents = ((PyStringLiteralExpression)expression).getStringValue();
|
||||
return getStringBasedType(contents, expression, context);
|
||||
final String contents = ((PyStringLiteralExpression)element).getStringValue();
|
||||
return getStringBasedType(contents, element, context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -341,9 +344,9 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getCallableType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
if (expression instanceof PySubscriptionExpression) {
|
||||
final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression;
|
||||
private static PyType getCallableType(@NotNull PsiElement resolved, @NotNull TypeEvalContext context) {
|
||||
if (resolved instanceof PySubscriptionExpression) {
|
||||
final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)resolved;
|
||||
final PyExpression operand = subscriptionExpr.getOperand();
|
||||
final String operandName = resolveToQualifiedName(operand, context);
|
||||
if ("typing.Callable".equals(operandName)) {
|
||||
@@ -371,9 +374,9 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getUnionType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
if (expression instanceof PySubscriptionExpression) {
|
||||
final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression;
|
||||
private static PyType getUnionType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
if (element instanceof PySubscriptionExpression) {
|
||||
final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)element;
|
||||
final PyExpression operand = subscriptionExpr.getOperand();
|
||||
final String operandName = resolveToQualifiedName(operand, context);
|
||||
if ("typing.Union".equals(operandName)) {
|
||||
@@ -384,32 +387,22 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyGenericType getGenericType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
final PsiElement resolved = resolve(expression, context);
|
||||
if (resolved instanceof PyTargetExpression) {
|
||||
final PyTargetExpression targetExpr = (PyTargetExpression)resolved;
|
||||
final QualifiedName calleeName = targetExpr.getCalleeName();
|
||||
if (calleeName != null && "TypeVar".equals(calleeName.toString())) {
|
||||
// XXX: Requires switching from stub to AST
|
||||
final PyExpression assigned = targetExpr.findAssignedValue();
|
||||
if (assigned instanceof PyCallExpression) {
|
||||
final PyCallExpression assignedCall = (PyCallExpression)assigned;
|
||||
final PyExpression callee = assignedCall.getCallee();
|
||||
if (callee != null) {
|
||||
final String calleeQName = resolveToQualifiedName(callee, context);
|
||||
if ("typing.TypeVar".equals(calleeQName)) {
|
||||
final PyExpression[] arguments = assignedCall.getArguments();
|
||||
if (arguments.length > 0) {
|
||||
final PyExpression firstArgument = arguments[0];
|
||||
if (firstArgument instanceof PyStringLiteralExpression) {
|
||||
final String name = ((PyStringLiteralExpression)firstArgument).getStringValue();
|
||||
if (name != null) {
|
||||
return new PyGenericType(name, getGenericTypeBound(arguments, context));
|
||||
}
|
||||
}
|
||||
private static PyGenericType getGenericType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
if (element instanceof PyCallExpression) {
|
||||
final PyCallExpression assignedCall = (PyCallExpression)element;
|
||||
final PyExpression callee = assignedCall.getCallee();
|
||||
if (callee != null) {
|
||||
final String calleeQName = resolveToQualifiedName(callee, context);
|
||||
if ("typing.TypeVar".equals(calleeQName)) {
|
||||
final PyExpression[] arguments = assignedCall.getArguments();
|
||||
if (arguments.length > 0) {
|
||||
final PyExpression firstArgument = arguments[0];
|
||||
if (firstArgument instanceof PyStringLiteralExpression) {
|
||||
final String name = ((PyStringLiteralExpression)firstArgument).getStringValue();
|
||||
if (name != null) {
|
||||
return new PyGenericType(name, getGenericTypeBound(arguments, context));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,9 +436,9 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getParameterizedType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
if (expression instanceof PySubscriptionExpression) {
|
||||
final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)expression;
|
||||
private static PyType getParameterizedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
if (element instanceof PySubscriptionExpression) {
|
||||
final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)element;
|
||||
final PyExpression operand = subscriptionExpr.getOperand();
|
||||
final PyExpression indexExpr = subscriptionExpr.getIndexExpression();
|
||||
final PyType operandType = getType(operand, context);
|
||||
@@ -453,7 +446,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
final PyClass cls = ((PyClassType)operandType).getPyClass();
|
||||
final List<PyType> indexTypes = getIndexTypes(subscriptionExpr, context);
|
||||
if (PyNames.TUPLE.equals(cls.getQualifiedName())) {
|
||||
return PyTupleType.create(expression, indexTypes.toArray(new PyType[indexTypes.size()]));
|
||||
return PyTupleType.create(element, indexTypes.toArray(new PyType[indexTypes.size()]));
|
||||
}
|
||||
else if (indexExpr != null) {
|
||||
return new PyCollectionTypeImpl(cls, false, indexTypes);
|
||||
@@ -464,18 +457,18 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PyType getBuiltinCollection(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
final String collectionName = resolveToQualifiedName(expression, context);
|
||||
private static PyType getBuiltinCollection(@NotNull PsiElement element) {
|
||||
final String collectionName = getQualifiedName(element);
|
||||
final String builtinName = COLLECTION_CLASSES.get(collectionName);
|
||||
return builtinName != null ? PyTypeParser.getTypeByName(expression, builtinName) : null;
|
||||
return builtinName != null ? PyTypeParser.getTypeByName(element, builtinName) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement resolve(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
if (expression instanceof PyReferenceOwner) {
|
||||
final PyReferenceOwner referenceOwner = (PyReferenceOwner)expression;
|
||||
@NotNull
|
||||
private static PsiElement tryResolving(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
if (expression instanceof PyReferenceExpression) {
|
||||
final PyReferenceExpression referenceExpr = (PyReferenceExpression)expression;
|
||||
final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context);
|
||||
final PsiPolyVariantReference reference = referenceOwner.getReference(resolveContext);
|
||||
final PsiPolyVariantReference reference = referenceExpr.getReference(resolveContext);
|
||||
final PsiElement element = reference.resolve();
|
||||
if (element instanceof PyFunction) {
|
||||
final PyFunction function = (PyFunction)element;
|
||||
@@ -486,14 +479,28 @@ public class PyTypingTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
return element;
|
||||
else if (element instanceof PyTargetExpression) {
|
||||
final PyTargetExpression targetExpr = (PyTargetExpression)element;
|
||||
// XXX: Requires switching from stub to AST
|
||||
final PyExpression assignedValue = targetExpr.findAssignedValue();
|
||||
if (assignedValue != null) {
|
||||
return assignedValue;
|
||||
}
|
||||
}
|
||||
if (element != null) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return expression;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String resolveToQualifiedName(@NotNull PyExpression expression, @NotNull TypeEvalContext context) {
|
||||
final PsiElement element = resolve(expression, context);
|
||||
return getQualifiedName(tryResolving(expression, context));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getQualifiedName(@NotNull PsiElement element) {
|
||||
if (element instanceof PyQualifiedNameOwner) {
|
||||
final PyQualifiedNameOwner qualifiedNameOwner = (PyQualifiedNameOwner)element;
|
||||
return qualifiedNameOwner.getQualifiedName();
|
||||
|
||||
@@ -23,7 +23,7 @@ import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.ide.fileTemplates.FileTemplate;
|
||||
import com.intellij.ide.fileTemplates.FileTemplateManager;
|
||||
import com.intellij.ide.scratch.ScratchRootType;
|
||||
import com.intellij.ide.scratch.ScratchFileService;
|
||||
import com.intellij.injected.editor.VirtualFileWindow;
|
||||
import com.intellij.lang.ASTFactory;
|
||||
import com.intellij.lang.ASTNode;
|
||||
@@ -55,6 +55,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.*;
|
||||
@@ -1832,8 +1833,7 @@ public class PyUtil {
|
||||
}
|
||||
|
||||
public static boolean isInScratchFile(@NotNull PsiElement element) {
|
||||
PsiFile file = element.getContainingFile();
|
||||
return file != null && ScratchRootType.getInstance().isScratchFile(file.getVirtualFile());
|
||||
return ScratchFileService.isInScratchRoot(PsiUtilCore.getVirtualFile(element));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
*/
|
||||
package com.jetbrains.python.psi.types;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.AccessDirection;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
@@ -55,7 +58,19 @@ public class PyGenericType implements PyType {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myBound != null ? myName + " <= " + myBound.getName() : myName;
|
||||
if (myBound instanceof PyUnionType) {
|
||||
final PyUnionType bounds = (PyUnionType)myBound;
|
||||
final String boundsString = StringUtil.join(bounds.getMembers(), new Function<PyType, String>() {
|
||||
@Override
|
||||
public String fun(PyType type) {
|
||||
return type != null ? type.getName() : PyNames.UNKNOWN_TYPE;
|
||||
}
|
||||
}, ", ");
|
||||
return "TypeVar('" + myName + "', " + boundsString + ")";
|
||||
}
|
||||
else {
|
||||
return "TypeVar('" + myName + "')";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,5 +8,5 @@ def test():
|
||||
|
||||
x = f(10)
|
||||
y = f('foo')
|
||||
z = f(<warning descr="Expected type 'T <= int | str', got 'list' instead">[]</warning>)
|
||||
z = f(<warning descr="Expected type 'TypeVar('T', int, str)', got 'list' instead">[]</warning>)
|
||||
return x + <warning descr="Expected type 'Number', got 'str' instead">y</warning>
|
||||
|
||||
@@ -21,4 +21,4 @@ class User1(object):
|
||||
c = User1(10)
|
||||
print(c.get() + <warning descr="Expected type 'Number', got 'str' instead">'foo'</warning>)
|
||||
c.put(14)
|
||||
c.put(<weak_warning descr="Expected type 'int' (matched generic type 'T'), got 'str' instead">'foo'</weak_warning>)
|
||||
c.put(<weak_warning descr="Expected type 'int' (matched generic type 'TypeVar('T')'), got 'str' instead">'foo'</weak_warning>)
|
||||
|
||||
@@ -40,7 +40,7 @@ def test():
|
||||
print(result)
|
||||
print(result + <warning descr="Expected type 'Number', got 'str' instead">'foo'</warning>)
|
||||
|
||||
f2(1, <weak_warning descr="Expected type 'list[int]' (matched generic type 'list[T]'), got 'list[str]' instead">['foo']</weak_warning>, 'bar')
|
||||
f2(1, <weak_warning descr="Expected type 'list[int]' (matched generic type 'list[TypeVar('T')]'), got 'list[str]' instead">['foo']</weak_warning>, 'bar')
|
||||
|
||||
result = f3(1, 'foo', True)
|
||||
f4(<warning descr="Expected type 'Tuple[bool, int, str]', got 'Tuple[int, str, bool]' instead">result</warning>)
|
||||
|
||||
@@ -7,7 +7,7 @@ def test_second_form():
|
||||
|
||||
|
||||
def test_second_form_fail():
|
||||
for chunk in iter(<weak_warning descr="Expected type 'Union[Iterable, () -> object]' (matched generic type 'Union[Iterable[T], () -> object]'), got 'int' instead">10</weak_warning>, ''):
|
||||
for chunk in iter(<weak_warning descr="Expected type 'Union[Iterable, () -> object]' (matched generic type 'Union[Iterable[TypeVar('T')], () -> object]'), got 'int' instead">10</weak_warning>, ''):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
from typing import TypeVar
|
||||
|
||||
|
||||
T = TypeVar('T', int, unresolved)
|
||||
|
||||
|
||||
def calc(a: T, b: T):
|
||||
pass
|
||||
|
||||
|
||||
calc('a', <weak_warning descr="Expected type 'str' (matched generic type 'TypeVar('T', int, Any)'), got 'int' instead">0</weak_warning>)
|
||||
@@ -31,6 +31,6 @@ def test_stub_only_function(x):
|
||||
|
||||
def tset_overloaded_generics(x):
|
||||
g(<warning descr="Expected type 'dict', got 'int' instead">Gen(10).get(10, 10)</warning>)
|
||||
g(Gen(10).get(10, <weak_warning descr="Expected type 'int' (matched generic type 'T'), got 'str' instead">'foo'</weak_warning>))
|
||||
g(Gen('foo').get(10, <weak_warning descr="Expected type 'str' (matched generic type 'T'), got 'int' instead">10</weak_warning>))
|
||||
g(Gen(10).get(10, <weak_warning descr="Expected type 'int' (matched generic type 'TypeVar('T')'), got 'str' instead">'foo'</weak_warning>))
|
||||
g(Gen('foo').get(10, <weak_warning descr="Expected type 'str' (matched generic type 'TypeVar('T')'), got 'int' instead">10</weak_warning>))
|
||||
g(<warning descr="Expected type 'dict', got 'str' instead">Gen('foo').get(10, 'foo')</warning>)
|
||||
|
||||
@@ -137,7 +137,7 @@ public class PyTypeParserTest extends PyTestCase {
|
||||
final PyType type = PyTypeParser.getTypeByName(myFixture.getFile(), "T");
|
||||
assertNotNull(type);
|
||||
assertInstanceOf(type, PyGenericType.class);
|
||||
assertEquals("T", type.getName());
|
||||
assertEquals("TypeVar('T')", type.getName());
|
||||
}
|
||||
|
||||
// PY-4223
|
||||
@@ -251,7 +251,7 @@ public class PyTypeParserTest extends PyTestCase {
|
||||
assertEquals("int", type0.getName());
|
||||
final PyType type1 = parameterTypes.get(1).getType(context);
|
||||
assertNotNull(type1);
|
||||
assertEquals("T", type1.getName());
|
||||
assertEquals("TypeVar('T')", type1.getName());
|
||||
}
|
||||
|
||||
public void testCallableWithoutArgs() {
|
||||
|
||||
@@ -151,7 +151,7 @@ public class PyTypingTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testGenericType() {
|
||||
doTest("A",
|
||||
doTest("TypeVar('A')",
|
||||
"from typing import TypeVar\n" +
|
||||
"\n" +
|
||||
"T = TypeVar('A')\n" +
|
||||
@@ -161,7 +161,7 @@ public class PyTypingTest extends PyTestCase {
|
||||
}
|
||||
|
||||
public void testGenericBoundedType() {
|
||||
doTest("T <= int | str",
|
||||
doTest("TypeVar('T', int, str)",
|
||||
"from typing import TypeVar\n" +
|
||||
"\n" +
|
||||
"T = TypeVar('T', int, str)\n" +
|
||||
@@ -346,12 +346,25 @@ public class PyTypingTest extends PyTestCase {
|
||||
"from typing import Iterable\n" +
|
||||
"\n" +
|
||||
"def foo() -> Iterable[int]:\n" +
|
||||
" passs\n" +
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"for expr in foo():\n" +
|
||||
" pass\n");
|
||||
}
|
||||
|
||||
// PY-16353
|
||||
public void testAssignedType() {
|
||||
doTest("Iterable[int]",
|
||||
"from typing import Iterable\n" +
|
||||
"\n" +
|
||||
"IntIterable = Iterable[int]\n" +
|
||||
"\n" +
|
||||
"def foo() -> IntIterable:\n" +
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"expr = foo()\n");
|
||||
}
|
||||
|
||||
private void doTestNoInjectedText(@NotNull String text) {
|
||||
myFixture.configureByText(PythonFileType.INSTANCE, text);
|
||||
final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject());
|
||||
|
||||
@@ -78,4 +78,9 @@ public class Py3TypeCheckerInspectionTest extends PyTestCase {
|
||||
public void testTypingListSubscriptionExpression() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// PY-16855
|
||||
public void testTypingTypeVarWithUnresolvedBound() {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user