diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index 6842e6379d6d..c1aaa37f871d 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -145,7 +145,7 @@ def layoutFull(String home, String targetDirectory, String patchedDescriptorDir } jar("bootstrap.jar") { module("bootstrap") } - + jar("jps-launcher.jar") { module("jps-launcher") } jar("resources.jar") { @@ -557,7 +557,14 @@ public def layoutCommunityPlugins(String home) { } } - layoutPlugin("java-decompiler") + pluginDir("java-decompiler") { + dir("lib") { + jar("java-decompiler.jar") { + module("java-decompiler-engine") + module("java-decompiler-plugin") + } + } + } } } diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant index 66ac8a061d85..dfd53103ceca 100644 --- a/build/scripts/libLicenses.gant +++ b/build/scripts/libLicenses.gant @@ -189,7 +189,7 @@ libraryLicense(name: "JavaCVS", attachedTo: "javacvs-src", version: "no version libraryLicense(name: "JAXB", libraryName: "JAXB", version: "2.2.4-1", license: "CDDL 1.1", url: "http://jaxb.java.net/", licenseUrl: "http://glassfish.java.net/public/CDDL+GPL_1_1.html") libraryLicense(name: "Jaxen", version: "", license: "modified Apache", url: "http://www.jaxen.org/", licenseUrl: "http://www.jaxen.org/license.html") libraryLicense(name: "JavaHelp", version: "2.0_02", license: "included as license/javahelp_license.html in IntelliJ IDEA distribution", url: "http://java.sun.com/products/javahelp/") -libraryLicense(name: "Java-WebSocket", version: "1.3.0", license: "MIT", url: "https://github.com/TooTallNate/Java-WebSocket", licenseUrl:"https://github.com/TooTallNate/Java-WebSocket/blob/master/LICENSE") +libraryLicense(name: "Java-WebSocket", libraryName: "java_websocket.jar", version: "1.3.0", license: "MIT", url: "https://github.com/TooTallNate/Java-WebSocket", licenseUrl:"https://github.com/TooTallNate/Java-WebSocket/blob/master/LICENSE") libraryLicense(name: "JCIP Annotations", libraryName: "jcip", license: "Creative Commons Attribution License", url: "http://www.jcip.net", licenseUrl: "http://creativecommons.org/licenses/by/2.5") libraryLicense(name: "JDOM", version: "1.1 (with patches by JetBrains)", license: "modified Apache", url: "http://www.jdom.org/", licenseUrl: "http://www.jdom.org/docs/faq.html#a0030") libraryLicense(name: "javawriter", libraryName: "javawriter", license: "Apache 2.0", url: "https://github.com/square/javawriter") diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java index 5dc61a146a0b..a7f5b352c5ff 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java @@ -138,9 +138,13 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV presentation = new TypedStringValuePresentation(value, type); } else { + @SuppressWarnings("ThrowableResultOfMethodCallIgnored") EvaluateException exception = myValueDescriptor.getEvaluateException(); if (myValueDescriptor.getLastRenderer() instanceof ToStringRenderer && exception == null) { - presentation = new XRegularValuePresentation(StringUtil.wrapWithDoubleQuote(value.substring(0,Math.min(value.length(), XValueNode.MAX_VALUE_LENGTH))), type); + presentation = new XRegularValuePresentation(StringUtil.wrapWithDoubleQuote(truncateToMaxLength(value)), type); + } + else if (myValueDescriptor.getLastRenderer() instanceof CompoundReferenceRenderer && exception == null) { + presentation = new XRegularValuePresentation(truncateToMaxLength(value), type); } else { presentation = new JavaValuePresentation(value, type, exception != null ? exception.getMessage() : null); @@ -180,6 +184,10 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV }); } + private static String truncateToMaxLength(String value) { + return value.substring(0, Math.min(value.length(), XValueNode.MAX_VALUE_LENGTH)); + } + private static class JavaValuePresentation extends XValuePresentation implements XValueCompactPresentation { private final String myValue; private final String myType; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java index 31a457a260af..2f40df45cd7c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/LabelRenderer.java @@ -83,7 +83,7 @@ public class LabelRenderer extends com.intellij.debugger.ui.tree.render.Referenc } EvaluationContext thisEvaluationContext = evaluationContext.createEvaluationContext(value); Value labelValue = evaluator.evaluate(thisEvaluationContext); - result = DebuggerUtils.convertToPresentationString(DebuggerUtils.getValueAsString(thisEvaluationContext, labelValue)); + result = DebuggerUtils.getValueAsString(thisEvaluationContext, labelValue); } catch (final EvaluateException ex) { throw new EvaluateException(DebuggerBundle.message("error.unable.to.evaluate.expression") + " " + ex.getMessage(), ex); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java index 4016289147a7..eb9bf6f5f284 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ToStringRenderer.java @@ -28,6 +28,7 @@ import com.intellij.debugger.ui.tree.ValueDescriptor; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizerUtil; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiExpression; import com.intellij.ui.classFilter.ClassFilter; @@ -78,8 +79,7 @@ public class ToStringRenderer extends NodeRendererImpl { BatchEvaluator.getBatchEvaluator(evaluationContext.getDebugProcess()).invoke(new ToStringCommand(evaluationContext, value) { public void evaluationResult(String message) { valueDescriptor.setValueLabel( - // no need to add quotes and escape characters here, XValueTextRendererImpl handles the presentation - message == null? "" : /*"\"" + DebuggerUtils.convertToPresentationString(*/DebuggerUtilsEx.truncateString(message)/*) + "\""*/ + StringUtil.notNullize(message) ); labelListener.labelChanged(); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java index 63df26ff3e17..a23da345e7cb 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java @@ -84,10 +84,14 @@ class ContractInferenceInterpreter { } List inferContracts() { - final boolean notNull = NullableNotNullManager.isNotNull(myMethod); + List contracts = doInferContracts(); + if (contracts.isEmpty()) return contracts; + PsiTypeElement typeElement = myMethod.getReturnTypeElement(); final PsiType returnType = typeElement == null ? null : typeElement.getType(); - return ContainerUtil.filter(doInferContracts(), new Condition() { + final boolean notNull = !(returnType instanceof PsiPrimitiveType) && + NullableNotNullManager.getInstance(myMethod.getProject()).isNotNull(myMethod, false); + return ContainerUtil.filter(contracts, new Condition() { @Override public boolean value(MethodContract contract) { if (notNull && contract.returnValue == NOT_NULL_VALUE) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 93a75f3c9c47..17cb8724dc56 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -448,12 +448,15 @@ public class JavaCompletionUtil { PsiSubstitutor plainSub = plainResult.getSubstitutor(); PsiSubstitutor castSub = TypeConversionUtil.getSuperClassSubstitutor(plainClass, (PsiClassType)castType); PsiType returnType = method.getReturnType(); - if (method.getSignature(plainSub).equals(method.getSignature(castSub)) && - returnType != null && - toRaw(castSub.substitute(returnType)).isAssignableFrom(toRaw(plainSub.substitute(returnType))) && - processor.isAccessible(plainClass.findMethodBySignature(method, true)) - ) { - return item; + if (method.getSignature(plainSub).equals(method.getSignature(castSub))) { + PsiType typeAfterCast = toRaw(castSub.substitute(returnType)); + PsiType typeDeclared = toRaw(plainSub.substitute(returnType)); + if (typeAfterCast != null && typeDeclared != null && + typeAfterCast.isAssignableFrom(typeDeclared) && + processor.isAccessible(plainClass.findMethodBySignature(method, true)) + ) { + return item; + } } } } @@ -495,7 +498,8 @@ public class JavaCompletionUtil { }); } - private static PsiType toRaw(@NotNull PsiType type) { + @Nullable + private static PsiType toRaw(@Nullable PsiType type) { return type instanceof PsiClassType ? ((PsiClassType)type).rawType() : type; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java index a5347f2e9767..b2952f369275 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java @@ -565,8 +565,14 @@ public class ClsFileImpl extends ClsRepositoryPsiElement @NotNull public static CharSequence decompile(@NotNull VirtualFile file) { PsiManager manager = PsiManager.getInstance(DefaultProjectFactory.getInstance().getDefaultProject()); - StringBuilder buffer = new StringBuilder(); - new ClsFileImpl(new ClassFileViewProvider(manager, file), true).appendMirrorText(0, buffer); + final ClsFileImpl clsFile = new ClsFileImpl(new ClassFileViewProvider(manager, file), true); + final StringBuilder buffer = new StringBuilder(); + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + clsFile.appendMirrorText(0, buffer); + } + }); return buffer; } diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarkerUtil.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarkerUtil.java index 5a8b633ff95b..2e78c2cc067b 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarkerUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/PersistentRangeMarkerUtil.java @@ -48,11 +48,6 @@ public class PersistentRangeMarkerUtil { return false; } - if (rangeMarker.getStartOffset() == rangeMarker.getEndOffset() && e.getOffset() == rangeMarker.getStartOffset() && e.getOldLength() == 0) { - //One-point range marker - return true; - } - if (e.getOffset() >= rangeMarker.getEndOffset() || e.getOffset() + e.getOldLength() <= rangeMarker.getStartOffset()) { // Don't perform complex processing if the change doesn't affect target range. return false; diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java index da25c7da8663..d639a9c74b34 100644 --- a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java +++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java @@ -376,7 +376,10 @@ public class PushController implements Disposable { boolean force) { VcsPushOptionValue options = myDialog.getAdditionalOptionValue(support); Pusher pusher = support.getPusher(); - pusher.push(collectPushSpecsForVcs(support), options, force); + Map> specs = collectPushSpecsForVcs(support); + if (!specs.isEmpty()) { + pusher.push(specs, options, force); + } } @NotNull diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java index 4891d703b6db..a1b15c6bf33f 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/component/ArrangementAtomMatchConditionComponent.java @@ -237,7 +237,7 @@ public class ArrangementAtomMatchConditionComponent implements ArrangementUiComp @NotNull @Override public ArrangementAtomMatchCondition getMatchCondition() { - if (myInverted == myCondition.getValue()) { + if (Boolean.valueOf(myInverted) == myCondition.getValue()) { if (myOppositeCondition == null) { myOppositeCondition = new ArrangementAtomMatchCondition(myCondition.getType(), !myInverted); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java index 5e4f9b315042..0a31503e9a99 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditAction.java @@ -107,7 +107,7 @@ public class QuickEditAction implements IntentionAction, LowPriorityAction { if (!ApplicationManager.getApplication().isUnitTestMode()) { DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injectedFile); if (documentWindow != null) { - handler.navigate(((DocumentWindowImpl)documentWindow).hostToUnescaped(offset)); + handler.navigate(((DocumentWindowImpl)documentWindow).hostToInjectedUnescaped(offset)); } } return handler; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateSettingsEditor.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateSettingsEditor.java index 46f51dd2a52a..8ce2b7428c6a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateSettingsEditor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/LiveTemplateSettingsEditor.java @@ -340,7 +340,8 @@ public class LiveTemplateSettingsEditor extends JPanel { sb.append(ownName); } final boolean noContexts = sb.length() == 0; - ctxLabel.setText((noContexts ? "No applicable contexts" + (allowNoContexts ? "" : " yet") : "Applicable in " + sb.toString()) + ". "); + String contexts = (noContexts ? "No applicable contexts" + (allowNoContexts ? "" : " yet") : "Applicable in " + sb.toString()) + ". "; + ctxLabel.setText(StringUtil.first(contexts, 100, true)); ctxLabel.setForeground(noContexts ? allowNoContexts ? JBColor.GRAY : JBColor.RED : UIUtil.getLabelForeground()); change.setText(noContexts ? "Define" : "Change"); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java index a1a60ad9d39e..4505c5b1ed49 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java @@ -31,6 +31,7 @@ import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.keymap.impl.ui.KeymapPanel; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SchemesManager; +import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.options.ex.Settings; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.ui.*; @@ -398,23 +399,25 @@ public class TemplateListPanel extends JPanel implements Disposable { return evt.getPropertyName().equals("ancestor") && evt.getNewValue() != null && evt.getOldValue() == null; } - private void resizeComboToFitCustomShortcut() { - myExpandByCombo.setPrototypeDisplayValue(null); - myExpandByCombo.setPrototypeDisplayValue(CUSTOM); - } }); myOpenKeymapLabel.addHyperlinkListener(new HyperlinkAdapter() { @Override protected void hyperlinkActivated(HyperlinkEvent e) { Settings allSettings = Settings.KEY.getData(DataManager.getInstance().getDataContext(myOpenKeymapLabel)); - final KeymapPanel keymapPanel = allSettings == null ? null : allSettings.find(KeymapPanel.class); - if (keymapPanel != null) { - allSettings.select(keymapPanel).doWhenDone(new Runnable() { - public void run() { - keymapPanel.selectAction(IdeActions.ACTION_EXPAND_LIVE_TEMPLATE_CUSTOM); - } - }); + final KeymapPanel keymapPanel = allSettings == null ? new KeymapPanel() : allSettings.find(KeymapPanel.class); + if (keymapPanel == null) return; + + Runnable selectAction = new Runnable() { + public void run() { + keymapPanel.selectAction(IdeActions.ACTION_EXPAND_LIVE_TEMPLATE_CUSTOM); + } + }; + if (allSettings != null) { + allSettings.select(keymapPanel).doWhenDone(selectAction); + } else { + ShowSettingsUtil.getInstance().editConfigurable(myOpenKeymapLabel, keymapPanel, selectAction); + resizeComboToFitCustomShortcut(); } } }); @@ -422,6 +425,14 @@ public class TemplateListPanel extends JPanel implements Disposable { return panel; } + @SuppressWarnings("unchecked") + private void resizeComboToFitCustomShortcut() { + myExpandByCombo.setPrototypeDisplayValue(null); + myExpandByCombo.setPrototypeDisplayValue(CUSTOM); + myExpandByCombo.revalidate(); + myExpandByCombo.repaint(); + } + @Nullable private TemplateImpl getTemplate(int row) { JTree tree = myTree; diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index b130b3cd420d..a82d5ba1f69d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -701,14 +701,17 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp }); if (results.isEmpty()) { - if (commandName != null) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + if (commandName != null) { NOTIFICATION_GROUP.createNotification(InspectionsBundle.message("inspection.no.problems.message"), MessageType.INFO).notify(getProject()); } - }); - } + if (postRunnable != null) { + postRunnable.run(); + } + } + }); return; } Runnable runnable = new Runnable() { diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/NewScratchFileAction.java b/platform/lang-impl/src/com/intellij/ide/scratch/NewScratchFileAction.java index 29320e24f9a4..790b36b414cb 100644 --- a/platform/lang-impl/src/com/intellij/ide/scratch/NewScratchFileAction.java +++ b/platform/lang-impl/src/com/intellij/ide/scratch/NewScratchFileAction.java @@ -21,6 +21,7 @@ import com.intellij.lang.LanguageUtil; import com.intellij.lang.StdLanguages; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.DumbAware; @@ -33,6 +34,7 @@ import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; import com.intellij.util.Consumer; import com.intellij.util.ObjectUtils; import com.intellij.util.ui.EmptyIcon; @@ -63,6 +65,12 @@ public class NewScratchFileAction extends AnAction implements DumbAware { final Project project = e.getProject(); if (project == null) return; Language previous = ScratchpadManager.getInstance(project).getLatestLanguage(); + if (previous == null) { + PsiFile file = e.getData(CommonDataKeys.PSI_FILE); + if (file != null) { + previous = file.getLanguage(); + } + } ListPopup popup = buildLanguagePopup(previous, new Consumer() { @Override public void consume(Language language) { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java index 66b590aa9b96..309b400b8c47 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ChooseByNameBase.java @@ -950,6 +950,17 @@ public abstract class ChooseByNameBase { } myAlarm.cancelAllRequests(); + + if (delay > 0) { + myAlarm.addRequest(new Runnable() { + @Override + public void run() { + rebuildList(pos, 0, modalityState, postRunnable); + } + }, delay, ModalityState.stateForComponent(myTextField)); + return; + } + myListUpdater.cancelAll(); final CalcElementsThread calcElementsThread = myCalcElementsThread; @@ -977,32 +988,20 @@ public abstract class ChooseByNameBase { ((MatcherHolder)cellRenderer).setPatternMatcher(matcher); } - final Runnable request = new Runnable() { + scheduleCalcElements(text, myCheckBox.isSelected(), modalityState, new Consumer>() { @Override - public void run() { - scheduleCalcElements(text, myCheckBox.isSelected(), modalityState, new Consumer>() { - @Override - public void consume(Set elements) { - ApplicationManager.getApplication().assertIsDispatchThread(); - if (checkDisposed()) { - return; - } - backgroundCalculationFinished(elements, pos); + public void consume(Set elements) { + ApplicationManager.getApplication().assertIsDispatchThread(); + if (checkDisposed()) { + return; + } + backgroundCalculationFinished(elements, pos); - if (postRunnable != null) { - postRunnable.run(); - } - } - }); + if (postRunnable != null) { + postRunnable.run(); + } } - }; - - if (delay > 0) { - myAlarm.addRequest(request, delay, ModalityState.stateForComponent(myTextField)); - } - else { - request.run(); - } + }); } private void backgroundCalculationFinished(Collection result, int toSelect) { diff --git a/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java b/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java index 3ed4e0a16022..7c67fe95a71f 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/DocumentWindowImpl.java @@ -668,7 +668,7 @@ public class DocumentWindowImpl extends UserDataHolderBase implements Disposable } } - public int hostToUnescaped(int hostOffset) { + public int hostToInjectedUnescaped(int hostOffset) { synchronized (myLock) { Segment hostRangeMarker = myShreds.get(0).getHostRangeMarker(); if (hostRangeMarker == null || hostOffset < hostRangeMarker.getStartOffset()) return myShreds.get(0).getPrefix().length(); diff --git a/platform/platform-impl/src/com/intellij/ide/passwordSafe/config/PasswordSafeSettings.java b/platform/platform-impl/src/com/intellij/ide/passwordSafe/config/PasswordSafeSettings.java index 10c5c933c41d..ab8fac21dd3a 100644 --- a/platform/platform-impl/src/com/intellij/ide/passwordSafe/config/PasswordSafeSettings.java +++ b/platform/platform-impl/src/com/intellij/ide/passwordSafe/config/PasswordSafeSettings.java @@ -15,10 +15,7 @@ */ package com.intellij.ide.passwordSafe.config; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.components.StoragePathMacros; +import com.intellij.openapi.components.*; /** * The password safe settings @@ -28,8 +25,8 @@ import com.intellij.openapi.components.StoragePathMacros; */ @State( name = "PasswordSafe", - storages = {@Storage( - file = StoragePathMacros.APP_CONFIG + "/security.xml")}) + storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/security.xml", roamingType = RoamingType.DISABLED)} +) public class PasswordSafeSettings implements PersistentStateComponent { /** * The selected provider type diff --git a/platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/PasswordDatabase.java b/platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/PasswordDatabase.java index 4bb0eaefae53..ee2b3a8d7a98 100644 --- a/platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/PasswordDatabase.java +++ b/platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/PasswordDatabase.java @@ -17,10 +17,7 @@ package com.intellij.ide.passwordSafe.impl.providers.masterKey; import com.intellij.ide.passwordSafe.impl.providers.ByteArrayWrapper; -import com.intellij.openapi.components.PersistentStateComponent; -import com.intellij.openapi.components.State; -import com.intellij.openapi.components.Storage; -import com.intellij.openapi.components.StoragePathMacros; +import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Hex; @@ -35,8 +32,8 @@ import java.util.TreeMap; */ @State( name = "PasswordDatabase", - storages = {@Storage( - file = StoragePathMacros.APP_CONFIG + "/security.xml")}) + storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/security.xml", roamingType = RoamingType.DISABLED)} +) public class PasswordDatabase implements PersistentStateComponent { /** * The name of logger diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java index 6d5bb3b40c43..7cffd25ae46c 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaTextFieldUI.java @@ -18,6 +18,7 @@ package com.intellij.ide.ui.laf.darcula.ui; import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; import com.intellij.openapi.ui.GraphicsConfig; import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.Gray; import com.intellij.util.ui.JBInsets; @@ -103,15 +104,18 @@ public class DarculaTextFieldUI extends BasicTextFieldUI { } } + private boolean hasText() { + JTextComponent component = getComponent(); + return (component != null) && !StringUtil.isEmpty(component.getText()); + } + private SearchAction getActionUnder(MouseEvent e) { - final Point cPoint = getClearIconCoord(); - final Point sPoint = getSearchIconCoord(); - cPoint.x+=8; - cPoint.y+=8; - sPoint.x+=8; - sPoint.y+=8; - final Point ePoint = e.getPoint(); - return cPoint.distance(ePoint) <= 8 ? SearchAction.CLEAR : sPoint.distance(ePoint) <= 8 ? SearchAction.POPUP : null; + Point point = new Point(e.getX() - 8, e.getY() - 8); + return point.distance(getSearchIconCoord()) <= 8 + ? SearchAction.POPUP + : hasText() && point.distance(getClearIconCoord()) <= 8 + ? SearchAction.CLEAR + : null; } protected Rectangle getDrawingRect() { @@ -169,7 +173,7 @@ public class DarculaTextFieldUI extends BasicTextFieldUI { searchIcon = IconLoader.findIcon("/com/intellij/ide/ui/laf/icons/search.png", DarculaTextFieldUI.class, true); } searchIcon.paintIcon(null, g, p.x, p.y); - if (getComponent().hasFocus() && getComponent().getText().length() > 0) { + if (hasText()) { p = getClearIconCoord(); Icon clearIcon = UIManager.getIcon("TextField.darcula.clear.icon"); if (clearIcon == null) { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/Rediffers.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/Rediffers.java index 3a1f8b055ab5..95afab208a13 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/Rediffers.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/Rediffers.java @@ -87,9 +87,7 @@ public class Rediffers { public void beforeDocumentChange(DocumentEvent event) {} public void documentChanged(DocumentEvent event) { - int newLines = StringUtil.getLineBreakCount(event.getNewFragment()); - int oldLines = StringUtil.getLineBreakCount(event.getOldFragment()); - if (newLines != oldLines) myPanel.invalidateDiff(); + if (event.getOldLength() != event.getNewLength()) myPanel.invalidateDiff(); requestRediff(); } diff --git a/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java b/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java index ed3c995edf48..e7503afea1a6 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/ide/bookmarks/BookmarkManagerTest.java @@ -15,9 +15,7 @@ */ package com.intellij.ide.bookmarks; -import com.intellij.openapi.editor.CaretModel; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.LogicalPosition; +import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.impl.AbstractEditorTest; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.OpenFileDescriptor; @@ -30,6 +28,7 @@ import org.picocontainer.ComponentAdapter; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -91,6 +90,62 @@ public class BookmarkManagerTest extends AbstractEditorTest { delete(); assertTrue(getManager().getValidBookmarks().isEmpty()); } + + public void testTwoBookmarksOnSameLine1() throws IOException { + @NonNls String text = + "public class Test {\n" + + " public void test() {\n" + + " int i = 1;\n" + + " int j = 1;\n" + + " }\n" + + "}"; + init(text, TestFileType.TEXT); + + addBookmark(2); + addBookmark(3); + List bookmarksBefore = getManager().getValidBookmarks(); + assertEquals(2, bookmarksBefore.size()); + + myEditor.getCaretModel().setCaretsAndSelections( + Collections.singletonList(new CaretState(myEditor.visualToLogicalPosition(new VisualPosition(3, 0)), null, null))); + backspace(); + + List bookmarksAfter = getManager().getValidBookmarks(); + assertEquals(1, bookmarksAfter.size()); + for (Bookmark bookmark : bookmarksAfter) { + checkBookmarkNavigation(bookmark); + } + } + public void testTwoBookmarksOnSameLine2() throws IOException { + @NonNls String text = + "public class Test {\n" + + " public void test() {\n" + + " int i = 1;\n" + + " int j = 1;\n" + + " }\n" + + "}"; + init(text, TestFileType.TEXT); + + addBookmark(2); + addBookmark(3); + List bookmarksBefore = getManager().getValidBookmarks(); + assertEquals(2, bookmarksBefore.size()); + + myEditor.getCaretModel().setCaretsAndSelections( + Collections.singletonList(new CaretState(myEditor.visualToLogicalPosition(new VisualPosition(2, myEditor.getDocument().getLineEndOffset(2)+1)), null, null))); + delete(); + + List bookmarksAfter = getManager().getValidBookmarks(); + assertEquals(1, bookmarksAfter.size()); + for (Bookmark bookmark : bookmarksAfter) { + checkBookmarkNavigation(bookmark); + } + init(text, TestFileType.TEXT); + myEditor.getCaretModel().setCaretsAndSelections( + Collections.singletonList( + new CaretState(myEditor.visualToLogicalPosition(new VisualPosition(2, myEditor.getDocument().getLineEndOffset(2))), null, null))); + delete(); + } public void testBookmarkIsSavedAfterRemoteChange() throws IOException { @NonNls String text = diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index e8132521cf6e..ba8554c08e28 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -2683,7 +2683,15 @@ public class StringUtil extends StringUtilRt { } @Contract(pure = true) - public static boolean equalsIgnoreWhitespaces(@NotNull CharSequence s1, @NotNull CharSequence s2) { + public static boolean equalsIgnoreWhitespaces(@Nullable CharSequence s1, @Nullable CharSequence s2) { + if (s1 == null ^ s2 == null) { + return false; + } + + if (s1 == null) { + return true; + } + int len1 = s1.length(); int len2 = s2.length(); diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index d7b5534979fe..66adb1ed0952 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -1939,7 +1939,7 @@ public class UIUtil { public static Font getTitledBorderFont() { Font defFont = getLabelFont(); - return defFont.deriveFont(Math.max(defFont.getSize() - 2f, 11f)); + return defFont.deriveFont(defFont.getSize() - 1f); } /** @@ -3025,7 +3025,7 @@ public class UIUtil { } public static Color getSidePanelColor() { - return new JBColor(new Color(0xD2D6DD), new Color(60, 68, 71)); + return new JBColor(0xD2D6DD, 0x3C4447); } /** diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java index 93ebb038cae1..8b11f1f33db6 100644 --- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java +++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java @@ -15,6 +15,7 @@ */ package com.intellij.util.text; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import junit.framework.TestCase; @@ -233,4 +234,51 @@ public class StringUtilTest extends TestCase { public void testReplace() { assertEquals(StringUtil.replace("$PROJECT_FILE$/filename", "$PROJECT_FILE$", "/tmp"), "/tmp/filename"); } + + public void testEqualsIgnoreWhitespaces() { + assertTrue(StringUtil.equalsIgnoreWhitespaces(null, null)); + assertFalse(StringUtil.equalsIgnoreWhitespaces("", null)); + + assertTrue(StringUtil.equalsIgnoreWhitespaces("", "")); + assertTrue(StringUtil.equalsIgnoreWhitespaces("\n\t ", "")); + assertTrue(StringUtil.equalsIgnoreWhitespaces("", "\t\n \n\t")); + assertTrue(StringUtil.equalsIgnoreWhitespaces("\t", "\n")); + + assertTrue(StringUtil.equalsIgnoreWhitespaces("x", " x")); + assertTrue(StringUtil.equalsIgnoreWhitespaces("x", "x ")); + assertTrue(StringUtil.equalsIgnoreWhitespaces("x\n", "x")); + + assertTrue(StringUtil.equalsIgnoreWhitespaces("abcd", "a\nb\nc\nd\n")); + assertTrue(StringUtil.equalsIgnoreWhitespaces("x y x", "x y x")); + assertTrue(StringUtil.equalsIgnoreWhitespaces("xyx", "x y x")); + + assertFalse(StringUtil.equalsIgnoreWhitespaces("x", "\t\n ")); + assertFalse(StringUtil.equalsIgnoreWhitespaces("", " x ")); + assertFalse(StringUtil.equalsIgnoreWhitespaces("", "x ")); + assertFalse(StringUtil.equalsIgnoreWhitespaces("", " x")); + assertFalse(StringUtil.equalsIgnoreWhitespaces("xyx", "xxx")); + assertFalse(StringUtil.equalsIgnoreWhitespaces("xyx", "xYx")); + } + + public void testStringHashCodeIgnoreWhitespaces() { + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces(""), StringUtil.stringHashCodeIgnoreWhitespaces(""))); + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("\n\t "), StringUtil.stringHashCodeIgnoreWhitespaces(""))); + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces(""), StringUtil.stringHashCodeIgnoreWhitespaces("\t\n \n\t"))); + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("\t"), StringUtil.stringHashCodeIgnoreWhitespaces("\n"))); + + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("x"), StringUtil.stringHashCodeIgnoreWhitespaces(" x"))); + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("x"), StringUtil.stringHashCodeIgnoreWhitespaces("x "))); + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("x\n"), StringUtil.stringHashCodeIgnoreWhitespaces("x"))); + + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("abcd"), StringUtil.stringHashCodeIgnoreWhitespaces("a\nb\nc\nd\n"))); + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("x y x"), StringUtil.stringHashCodeIgnoreWhitespaces("x y x"))); + assertTrue(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("xyx"), StringUtil.stringHashCodeIgnoreWhitespaces("x y x"))); + + assertFalse(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("x"), StringUtil.stringHashCodeIgnoreWhitespaces("\t\n "))); + assertFalse(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces(""), StringUtil.stringHashCodeIgnoreWhitespaces(" x "))); + assertFalse(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces(""), StringUtil.stringHashCodeIgnoreWhitespaces("x "))); + assertFalse(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces(""), StringUtil.stringHashCodeIgnoreWhitespaces(" x"))); + assertFalse(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("xyx"), StringUtil.stringHashCodeIgnoreWhitespaces("xxx"))); + assertFalse(Comparing.equal(StringUtil.stringHashCodeIgnoreWhitespaces("xyx"), StringUtil.stringHashCodeIgnoreWhitespaces("xYx"))); + } } diff --git a/platform/vcs-impl/vcs-impl.iml b/platform/vcs-impl/vcs-impl.iml index 9492e1b4205c..364c9db4d10a 100644 --- a/platform/vcs-impl/vcs-impl.iml +++ b/platform/vcs-impl/vcs-impl.iml @@ -17,8 +17,7 @@ - + - - + \ No newline at end of file diff --git a/plugins/git4idea/src/git4idea/config/SSHConnectionSettings.java b/plugins/git4idea/src/git4idea/config/SSHConnectionSettings.java index 72de867803e5..c48b352ac1e2 100644 --- a/plugins/git4idea/src/git4idea/config/SSHConnectionSettings.java +++ b/plugins/git4idea/src/git4idea/config/SSHConnectionSettings.java @@ -28,8 +28,8 @@ import java.util.TreeMap; */ @State( name = "SSHConnectionSettings", - storages = {@Storage( - file = StoragePathMacros.APP_CONFIG + "/security.xml")}) + storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/security.xml", roamingType = RoamingType.DISABLED)} +) public class SSHConnectionSettings implements PersistentStateComponent { /** * The last successful hosts, the entries are sorted to save on efforts on sorting during saving and loading diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 830e6683e5f3..0383dd410e47 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -182,8 +182,8 @@ public class ClassWriter { int start_class_def = buffer.length(); writeClassDefinition(node, buffer, indent); - // count lines in class definition the easiest way - total_offset_lines = buffer.substring(start_class_def).toString().split(lineSeparator, -1).length - 1; +// // count lines in class definition the easiest way +// total_offset_lines = buffer.substring(start_class_def).toString().split(lineSeparator, -1).length - 1; boolean hasContent = false; @@ -220,6 +220,9 @@ public class ClassWriter { buffer.append(lineSeparator); } + // FIXME: fields don't matter at the moment + total_offset_lines = buffer.substring(start_class_def).toString().split(lineSeparator, -1).length - 1; + // methods for (StructMethod mt : cl.getMethods()) { boolean hide = mt.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) || @@ -237,7 +240,7 @@ public class ClassWriter { hasContent = true; DecompilerContext.getBytecodeSourceMapper().addTracer(cl.qualifiedName, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()), method_tracer); - total_offset_lines = method_tracer.getCurrentSourceline(); + total_offset_lines = (method_tracer.getCurrentSourceLine() + 1); // zero-based line index } else { buffer.setLength(position); @@ -805,7 +808,7 @@ public class ClassWriter { if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence try { - tracer.setCurrentSourceline(buffer.substring(start_index_method).split(lineSeparator, -1).length - 1); + tracer.incrementCurrentSourceLine(buffer.substring(start_index_method).split(lineSeparator, -1).length - 1); String code = root.toJava(indent + 1, tracer); @@ -836,7 +839,7 @@ public class ClassWriter { // save total lines // TODO: optimize - tracer.setCurrentSourceline(buffer.substring(start_index_method).split(lineSeparator, -1).length - 1); + tracer.setCurrentSourceLine(buffer.substring(start_index_method).split(lineSeparator, -1).length - 1); return !hideMethod; } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java index bab697643e45..c79e3555daba 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -268,7 +268,7 @@ public class ClassesProcessor { int index = cl.qualifiedName.lastIndexOf("/"); if (index >= 0) { - total_offset_lines++; + total_offset_lines+=2; String packageName = cl.qualifiedName.substring(0, index).replace('/', '.'); buffer.append("package "); @@ -283,6 +283,7 @@ public class ClassesProcessor { buffer.append(lineSeparator); total_offset_lines += import_lines_written + 1; } + //buffer.append(lineSeparator); buffer.append(classBuffer); diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java index 95321e5d7537..20af4272e6ec 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java @@ -1,6 +1,7 @@ package org.jetbrains.java.decompiler.main.collectors; import java.util.HashMap; +import java.util.Map.Entry; import java.util.Set; public class BytecodeMappingTracer { @@ -16,14 +17,20 @@ public class BytecodeMappingTracer { current_sourceline = initial_source_line; } - public void incrementSourceLine() { + public void incrementCurrentSourceLine() { current_sourceline++; } - public void incrementSourceLine(int number_lines) { + public void incrementCurrentSourceLine(int number_lines) { current_sourceline += number_lines; } + public void shiftSourceLines(int shift) { + for(Entry entry : mapping.entrySet()) { + entry.setValue(entry.getValue() + shift); + } + } + public void addMapping(int bytecode_offset) { if(!mapping.containsKey(bytecode_offset)) { mapping.put(bytecode_offset, current_sourceline); @@ -38,15 +45,25 @@ public class BytecodeMappingTracer { } } + public void addTracer(BytecodeMappingTracer tracer) { + if(tracer != null) { + for(Entry entry : tracer.mapping.entrySet()) { + if(!mapping.containsKey(entry.getKey())) { + mapping.put(entry.getKey(), entry.getValue()); + } + } + } + } + public HashMap getMapping() { return mapping; } - public int getCurrentSourceline() { + public int getCurrentSourceLine() { return current_sourceline; } - public void setCurrentSourceline(int current_sourceline) { + public void setCurrentSourceLine(int current_sourceline) { this.current_sourceline = current_sourceline; } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/BytecodeSourceMapper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/BytecodeSourceMapper.java index f31394b0a285..53f92b2bb2e8 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/BytecodeSourceMapper.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/BytecodeSourceMapper.java @@ -59,7 +59,7 @@ public class BytecodeSourceMapper { buffer.append(indentstr1 + "method " + method_entry.getKey() + "{" + lineSeparator); for(Entry line : method_mapping.entrySet()) { - buffer.append(indentstr2 + line.getKey() + indentstr2 + line.getValue() + lineSeparator); + buffer.append(indentstr2 + line.getKey() + indentstr2 + (line.getValue() +offset_total) + lineSeparator); } buffer.append(indentstr1 + "}" + lineSeparator); is_first_method = false; diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java index f4b7aa271aea..dc284856a475 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java @@ -778,13 +778,13 @@ public class ExprProcessor implements CodeConstants { buf.append(" label").append(edge.closure.id); } buf.append(";").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } } if (buf.length() == 0 && semicolon) { buf.append(InterpreterUtil.getIndentString(indent)).append(";").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } return buf.toString(); @@ -828,7 +828,7 @@ public class ExprProcessor implements CodeConstants { buf.append(";"); } buf.append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java index 9ab7ec235c3f..f22d1b17eded 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java @@ -124,7 +124,7 @@ public class CatchAllStatement extends Statement { boolean labeled = isLabeled(); if (labeled) { buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } List lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL); @@ -137,30 +137,30 @@ public class CatchAllStatement extends Statement { } else { buf.append(indstr).append("try {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); buf.append(indstr).append("}"); } buf.append(isFinally ? " finally" : " catch (" + vars.get(0).toJava(indent, tracer) + ")").append(" {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); if (monitor != null) { indstr1 = InterpreterUtil.getIndentString(indent + 1); buf.append(indstr1).append("if(").append(monitor.toJava(indent, tracer)).append(") {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } buf.append(ExprProcessor.jmpWrapper(handler, indent + 1 + (monitor != null ? 1 : 0), true, tracer)); if (monitor != null) { buf.append(indstr1).append("}").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } buf.append(indstr).append("}").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); return buf.toString(); } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java index 7162f15eb072..a09625851d73 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java @@ -160,11 +160,11 @@ public class CatchStatement extends Statement { if (isLabeled()) { buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } buf.append(indstr).append("try {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); buf.append(indstr).append("}"); @@ -183,14 +183,14 @@ public class CatchStatement extends Statement { } buf.append(vars.get(i - 1).toJava(indent, tracer)); buf.append(") {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); buf.append(ExprProcessor.jmpWrapper(stats.get(i), indent + 1, true, tracer)).append(indstr) .append("}"); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } buf.append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); return buf.toString(); } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java index 299659a0bb06..1ddce1b80637 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java @@ -102,39 +102,39 @@ public class DoStatement extends Statement { if (isLabeled()) { buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } switch (looptype) { case LOOP_DO: buf.append(indstr).append("while(true) {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); buf.append(indstr).append("}").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); break; case LOOP_DOWHILE: buf.append(indstr).append("do {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); buf.append(indstr).append("} while(").append(conditionExprent.get(0).toJava(indent, tracer)).append(");").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); break; case LOOP_WHILE: buf.append(indstr).append("while(").append(conditionExprent.get(0).toJava(indent, tracer)).append(") {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); buf.append(indstr).append("}").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); break; case LOOP_FOR: buf.append(indstr).append("for(").append(initExprent.get(0) == null ? "" : initExprent.get(0).toJava(indent, tracer)).append("; ") .append(conditionExprent.get(0).toJava(indent, tracer)).append("; ").append(incExprent.get(0).toJava(indent, tracer)).append(") {") .append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true, tracer)); buf.append(indstr).append("}").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } return buf.toString(); diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java index 343d99ec38c3..ebe2bd793b11 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java @@ -211,11 +211,11 @@ public class IfStatement extends Statement { if (isLabeled()) { buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } buf.append(indstr).append(headexprent.get(0).toJava(indent, tracer)).append(" {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); if (ifstat == null) { buf.append(InterpreterUtil.getIndentString(indent + 1)); @@ -235,7 +235,7 @@ public class IfStatement extends Statement { } } buf.append(";").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } else { buf.append(ExprProcessor.jmpWrapper(ifstat, indent + 1, true, tracer)); @@ -258,11 +258,15 @@ public class IfStatement extends Statement { elseif = true; } else { - String content = ExprProcessor.jmpWrapper(elsestat, indent + 1, false, tracer); + BytecodeMappingTracer else_tracer = new BytecodeMappingTracer(tracer.getCurrentSourceLine()); + String content = ExprProcessor.jmpWrapper(elsestat, indent + 1, false, else_tracer); if (content.length() > 0) { buf.append(indstr).append("} else {").append(new_line_separator); - tracer.incrementSourceLine(); // FIXME: wrong order + + else_tracer.shiftSourceLines(1); + tracer.setCurrentSourceLine(else_tracer.getCurrentSourceLine() + 1); + tracer.addTracer(else_tracer); buf.append(content); } @@ -271,7 +275,7 @@ public class IfStatement extends Statement { if (!elseif) { buf.append(indstr).append("}").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } return buf.toString(); diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java index 24152f363d93..38420e0c2bc4 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java @@ -114,7 +114,7 @@ public class SequenceStatement extends Statement { indstr = InterpreterUtil.getIndentString(indent); indent++; buf.append(indstr).append("label").append(this.id).append(": {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } boolean notempty = false; @@ -125,7 +125,7 @@ public class SequenceStatement extends Statement { if (i > 0 && notempty) { buf.append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } String str = ExprProcessor.jmpWrapper(st, indent, false, tracer); @@ -136,7 +136,7 @@ public class SequenceStatement extends Statement { if (islabeled) { buf.append(indstr).append("}").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } return buf.toString(); diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java index 3b75fdce792b..aea44de948cc 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java @@ -119,11 +119,11 @@ public class SwitchStatement extends Statement { if (isLabeled()) { buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } buf.append(indstr).append(headexprent.get(0).toJava(indent, tracer)).append(" {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); VarType switch_type = headexprent.get(0).getExprType(); @@ -136,14 +136,14 @@ public class SwitchStatement extends Statement { for (int j = 0; j < edges.size(); j++) { if (edges.get(j) == default_edge) { buf.append(indstr).append("default:").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } else { ConstExprent value = (ConstExprent)values.get(j).copy(); value.setConsttype(switch_type); buf.append(indstr).append("case ").append(value.toJava(indent, tracer)).append(":").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } } @@ -151,7 +151,7 @@ public class SwitchStatement extends Statement { } buf.append(indstr).append("}").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); return buf.toString(); } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java index 3d61198130ee..eb94ddc97265 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java @@ -80,17 +80,17 @@ public class SynchronizedStatement extends Statement { if (isLabeled()) { buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); } buf.append(indstr).append(headexprent.get(0).toJava(indent, tracer)).append(" {").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); buf.append(ExprProcessor.jmpWrapper(body, indent + 1, true, tracer)); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); buf.append(indstr).append("}").append(new_line_separator); - tracer.incrementSourceLine(); + tracer.incrementCurrentSourceLine(); return buf.toString(); } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java index 695d6598869d..f35d3d95cf4f 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java @@ -17,6 +17,7 @@ package org.jetbrains.java.decompiler.struct.attr; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; +import org.jetbrains.java.decompiler.util.InterpreterUtil; import java.io.IOException; @@ -29,7 +30,7 @@ import java.io.IOException; * Created by Egor on 05.10.2014. */ public class StructLineNumberTableAttribute extends StructGeneralAttribute { - private int[] myLineInfo = new int[0]; + private int[] myLineInfo = InterpreterUtil.EMPTY_INT_ARRAY; @Override public void initContent(ConstantPool pool) throws IOException { @@ -44,7 +45,7 @@ public class StructLineNumberTableAttribute extends StructGeneralAttribute { } } else if (myLineInfo.length > 0) { - myLineInfo = new int[0]; + myLineInfo = InterpreterUtil.EMPTY_INT_ARRAY; } } diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java index bf01035616a4..64e98a04388b 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java @@ -88,6 +88,7 @@ public class FastSparseSetFactory { public static class FastSparseSet implements Iterable { + public static final FastSparseSet[] EMPTY_ARRAY = new FastSparseSet[0]; private FastSparseSetFactory factory; diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java index 09e7bad5ccbb..eaada902b03d 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java @@ -29,6 +29,8 @@ import java.util.zip.ZipFile; public class InterpreterUtil { public static final boolean IS_WINDOWS = System.getProperty("os.name", "").startsWith("Windows"); + public static final int[] EMPTY_INT_ARRAY = new int[0]; + private static final int CHANNEL_WINDOW_SIZE = IS_WINDOWS ? 64 * 1024 * 1024 - (32 * 1024) : 64 * 1024 * 1024; // magic number for Windows private static final int BUFFER_SIZE = 16 * 1024; diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java index 996607a2bdbc..b70dedea6a78 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java @@ -38,9 +38,9 @@ public class SFormsFastMapDirect { private SFormsFastMapDirect(boolean initialize) { if (initialize) { for (int i = 2; i >= 0; i--) { - @SuppressWarnings("unchecked") FastSparseSet[] empty = new FastSparseSet[0]; + @SuppressWarnings("unchecked") FastSparseSet[] empty = FastSparseSet.EMPTY_ARRAY; elements[i] = empty; - next[i] = new int[0]; + next[i] = InterpreterUtil.EMPTY_INT_ARRAY; } } } @@ -99,8 +99,8 @@ public class SFormsFastMapDirect { while (pointer != 0); } else { - mapelements[i] = new FastSparseSet[0]; - mapnext[i] = new int[0]; + mapelements[i] = FastSparseSet.EMPTY_ARRAY; + mapnext[i] = InterpreterUtil.EMPTY_INT_ARRAY; } } diff --git a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java index c584bae2daa7..f99510e6625b 100644 --- a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java +++ b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java @@ -91,9 +91,7 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase { } public void testNavigation() { - String path = PluginPathManager.getPluginHomePath("java-decompiler") + "/testData/Navigation.class"; - VirtualFile file = StandardFileSystems.local().findFileByPath(path); - assertNotNull(path, file); + VirtualFile file = getTestFile("Navigation.class"); myFixture.openFileInEditor(file); doTestNavigation(11, 14, 14, 10); // to "m2()" @@ -101,22 +99,8 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase { doTestNavigation(16, 28, 15, 13); // to "int r" } - private void doTestNavigation(int line, int column, int expectedLine, int expectedColumn) { - PsiElement target = GotoDeclarationAction.findTargetElement(getProject(), myFixture.getEditor(), offset(line, column)); - assertTrue(String.valueOf(target), target instanceof Navigatable); - ((Navigatable)target).navigate(true); - int expected = offset(expectedLine, expectedColumn); - assertEquals(expected, myFixture.getCaretOffset()); - } - - private int offset(int line, int column) { - return myFixture.getEditor().getDocument().getLineStartOffset(line - 1) + column - 1; - } - public void testHighlighting() { - String path = PluginPathManager.getPluginHomePath("java-decompiler") + "/testData/Navigation.class"; - VirtualFile file = StandardFileSystems.local().findFileByPath(path); - assertNotNull(path, file); + VirtualFile file = getTestFile("Navigation.class"); myFixture.openFileInEditor(file); IdentifierHighlighterPassFactory.doWithHighlightingEnabled(new Runnable() { @@ -130,4 +114,23 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase { } }); } + + private static VirtualFile getTestFile(String name) { + String path = PluginPathManager.getPluginHomePath("java-decompiler") + "/plugin/testData/" + name; + VirtualFile file = StandardFileSystems.local().findFileByPath(path); + assertNotNull(path, file); + return file; + } + + private void doTestNavigation(int line, int column, int expectedLine, int expectedColumn) { + PsiElement target = GotoDeclarationAction.findTargetElement(getProject(), myFixture.getEditor(), offset(line, column)); + assertTrue(String.valueOf(target), target instanceof Navigatable); + ((Navigatable)target).navigate(true); + int expected = offset(expectedLine, expectedColumn); + assertEquals(expected, myFixture.getCaretOffset()); + } + + private int offset(int line, int column) { + return myFixture.getEditor().getDocument().getLineStartOffset(line - 1) + column - 1; + } } diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java index b85da167f45d..b95b12497e7b 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java @@ -18,8 +18,6 @@ package org.jetbrains.plugins.javaFX.fxml; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.openapi.application.PluginPathManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl; import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.testFramework.LightProjectDescriptor; diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/intentions/JavaFxInjectPageLanguageIntention.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/intentions/JavaFxInjectPageLanguageIntention.java index 01dc2e06e364..0cbd61f765a9 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/intentions/JavaFxInjectPageLanguageIntention.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/intentions/JavaFxInjectPageLanguageIntention.java @@ -17,14 +17,13 @@ package org.jetbrains.plugins.javaFX.fxml.codeInsight.intentions; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.OrderEnumerator; import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFileFactory; import com.intellij.psi.PsiParserFacade; @@ -36,16 +35,15 @@ import com.intellij.psi.xml.XmlProlog; import com.intellij.ui.components.JBList; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.lang.UrlClassLoader; import org.jetbrains.annotations.NotNull; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; /** * User: anna @@ -55,33 +53,14 @@ public class JavaFxInjectPageLanguageIntention extends PsiElementBaseIntentionAc public static final Logger LOG = Logger.getInstance("#" + JavaFxInjectPageLanguageIntention.class.getName()); private static Set getAvailableLanguages(Project project) { - final List engineFactories = new ScriptEngineManager(composeUserClassLoader(project)).getEngineFactories(); + final List engineFactories = new ScriptEngineManager().getEngineFactories(); - if (engineFactories != null) { - final Set availableNames = new TreeSet(); - for (ScriptEngineFactory factory : engineFactories) { - final String engineName = (String)factory.getParameter(ScriptEngine.NAME); - availableNames.add(engineName); - } - return availableNames; + final Set availableNames = new TreeSet(); + for (ScriptEngineFactory factory : engineFactories) { + final String engineName = (String)factory.getParameter(ScriptEngine.NAME); + availableNames.add(engineName); } - - return null; - } - - private static UrlClassLoader composeUserClassLoader(Project project) { - final List urls = new ArrayList(); - final List list = OrderEnumerator.orderEntries(project).recursively().runtimeOnly().getPathsList().getPathList(); - for (String path : list) { - try { - urls.add(new File(FileUtil.toSystemIndependentName(path)).toURI().toURL()); - } - catch (MalformedURLException e1) { - LOG.info(e1); - } - } - - return UrlClassLoader.build().urls(urls).get(); + return availableNames; } @Override @@ -90,7 +69,7 @@ public class JavaFxInjectPageLanguageIntention extends PsiElementBaseIntentionAc final XmlFile containingFile = (XmlFile)element.getContainingFile(); final Set availableLanguages = getAvailableLanguages(project); - if (availableLanguages.size() == 1) { + if (availableLanguages.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) { registerPageLanguage(project, containingFile, availableLanguages.iterator().next()); } else { final JBList list = new JBList(availableLanguages); diff --git a/plugins/javaFX/testData/quickfix/registerPageLanguage_after.fxml b/plugins/javaFX/testData/quickfix/registerPageLanguage_after.fxml index eeac829d7175..f794f91d61ba 100644 --- a/plugins/javaFX/testData/quickfix/registerPageLanguage_after.fxml +++ b/plugins/javaFX/testData/quickfix/registerPageLanguage_after.fxml @@ -1,4 +1,4 @@ - + diff --git a/python/edu/learn-python/learn-python.iml b/python/edu/learn-python/learn-python.iml index 613d67594a7a..db91c2ed7f66 100644 --- a/python/edu/learn-python/learn-python.iml +++ b/python/edu/learn-python/learn-python.iml @@ -14,8 +14,7 @@ - + - - + \ No newline at end of file diff --git a/python/ipnb/ipnb.iml b/python/ipnb/ipnb.iml index fe287d2fafbd..4fd2c2691fe1 100644 --- a/python/ipnb/ipnb.iml +++ b/python/ipnb/ipnb.iml @@ -15,7 +15,7 @@ - + @@ -26,5 +26,4 @@ - - + \ No newline at end of file diff --git a/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java b/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java similarity index 80% rename from python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java rename to python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java index a344e892588c..ffc846796806 100644 --- a/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java +++ b/python/psi-api/src/com/jetbrains/python/codeInsight/PyCustomMember.java @@ -33,7 +33,7 @@ import javax.swing.*; /** * @author Dennis.Ushakov */ -public class PyDynamicMember { +public class PyCustomMember { private String myName; private final boolean myResolveToInstance; private final Function myTypeCallback; @@ -45,7 +45,7 @@ public class PyDynamicMember { boolean myFunction = false; - public PyDynamicMember(@NotNull final String name, @Nullable final String type, final boolean resolveToInstance) { + public PyCustomMember(@NotNull final String name, @Nullable final String type, final boolean resolveToInstance) { myName = name; myResolveToInstance = resolveToInstance; myTypeName = type; @@ -54,7 +54,7 @@ public class PyDynamicMember { myTypeCallback = null; } - public PyDynamicMember(@NotNull final String name) { + public PyCustomMember(@NotNull final String name) { myName = name; myResolveToInstance = false; myTypeName = null; @@ -63,9 +63,9 @@ public class PyDynamicMember { myTypeCallback = null; } - public PyDynamicMember(@NotNull final String name, - @Nullable final String type, - final Function typeCallback) { + public PyCustomMember(@NotNull final String name, + @Nullable final String type, + final Function typeCallback) { myName = name; myResolveToInstance = false; @@ -75,55 +75,58 @@ public class PyDynamicMember { myTypeCallback = typeCallback; } - public PyDynamicMember(@NotNull final String name, @Nullable final PsiElement target) { + public PyCustomMember(@NotNull final String name, @Nullable final PsiElement target, @Nullable String typeName) { myName = name; myTarget = target; myResolveToInstance = false; - myTypeName = null; + myTypeName = typeName; myTypeCallback = null; } + public PyCustomMember(@NotNull final String name, @Nullable final PsiElement target) { + this(name, target, null); + } - public PyDynamicMember resolvesTo(String moduleQName) { + public PyCustomMember resolvesTo(String moduleQName) { myPsiPath = new PyPsiPath.ToFile(moduleQName); return this; } - public PyDynamicMember resolvesToClass(String classQName) { + public PyCustomMember resolvesToClass(String classQName) { myPsiPath = new PyPsiPath.ToClassQName(classQName); return this; } - public PyDynamicMember toClass(String name) { + public PyCustomMember toClass(String name) { myPsiPath = new PyPsiPath.ToClass(myPsiPath, name); return this; } - public PyDynamicMember toFunction(String name) { + public PyCustomMember toFunction(String name) { myPsiPath = new PyPsiPath.ToFunction(myPsiPath, name); return this; } - public PyDynamicMember toFunctionRecursive(String name) { + public PyCustomMember toFunctionRecursive(String name) { myPsiPath = new PyPsiPath.ToFunctionRecursive(myPsiPath, name); return this; } - public PyDynamicMember toClassAttribute(String name) { + public PyCustomMember toClassAttribute(String name) { myPsiPath = new PyPsiPath.ToClassAttribute(myPsiPath, name); return this; } - public PyDynamicMember toCall(String name, String... args) { + public PyCustomMember toCall(String name, String... args) { myPsiPath = new PyPsiPath.ToCall(myPsiPath, name, args); return this; } - public PyDynamicMember toAssignment(String assignee) { + public PyCustomMember toAssignment(String assignee) { myPsiPath = new PyPsiPath.ToAssignment(myPsiPath, assignee); return this; } - public PyDynamicMember toPsiElement(final PsiElement psiElement) { + public PyCustomMember toPsiElement(final PsiElement psiElement) { myPsiPath = new PyPsiPath() { @Override @@ -179,7 +182,7 @@ public class PyDynamicMember { return myTypeName.substring(pos + 1); } - public PyDynamicMember asFunction() { + public PyCustomMember asFunction() { myFunction = true; return this; } diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java index a988714c144a..b6a26fc35539 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java @@ -110,8 +110,12 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine @NotNull PyExpression[] getSuperClassExpressions(); + /** + * @param inherited return inherited (parent) methods as well + * @return class methods + */ @NotNull - PyFunction[] getMethods(); + PyFunction[] getMethods(boolean inherited); /** * Get class properties. @@ -243,4 +247,12 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine */ @Nullable PyExpression getMetaClassExpression(); + + /** + * + * @param context eval context + * @return {@link com.jetbrains.python.psi.types.PyType} casted if it has right type + */ + @Nullable + PyClassLikeType getType(@NotNull TypeEvalContext context); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyFunction.java b/python/psi-api/src/com/jetbrains/python/psi/PyFunction.java index e70a7ad12a51..0f7031b85dc2 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyFunction.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyFunction.java @@ -26,6 +26,8 @@ import com.jetbrains.python.psi.types.PyType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * Function declaration in source (the def and everything within). * @@ -101,4 +103,48 @@ extends @Nullable PyAnnotation getAnnotation(); + + // TODO: Doc + // + + /** + * Searches for function attributes. + * See PEP-0232 + * @return assignment statements for function attributes + */ + @NotNull + List findAttributes(); + + /** + * @return function protection level (underscore based) + */ + @NotNull + ProtectionLevel getProtectionLevel(); + + enum ProtectionLevel { + /** + * public members + */ + PUBLIC(0), + /** + * _protected_memebers + */ + PROTECTED(1), + /** + * __private_memebrs + */ + PRIVATE(2); + private final int myUnderscoreLevel; + + ProtectionLevel(final int underscoreLevel) { + myUnderscoreLevel = underscoreLevel; + } + + /** + * @return number of underscores + */ + public int getUnderscoreLevel() { + return myUnderscoreLevel; + } + } } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProvider.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProvider.java index e051b48fbfaa..6a61de999abc 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProvider.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProvider.java @@ -17,7 +17,7 @@ package com.jetbrains.python.psi.types; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.psi.PsiElement; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,7 +30,7 @@ public interface PyClassMembersProvider { ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyClassMembersProvider"); @NotNull - Collection getMembers(PyClassType clazz, @Nullable PsiElement location); + Collection getMembers(PyClassType clazz, @Nullable PsiElement location); @Nullable PsiElement resolveMember(PyClassType clazz, String name, @Nullable PsiElement location); diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java index a7d66499cf52..6ec96559911a 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassMembersProviderBase.java @@ -16,7 +16,7 @@ package com.jetbrains.python.psi.types; import com.intellij.psi.PsiElement; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.PyClass; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,22 +30,22 @@ import java.util.Collections; public class PyClassMembersProviderBase implements PyClassMembersProvider { @NotNull @Override - public Collection getMembers(PyClassType clazz, PsiElement location) { + public Collection getMembers(PyClassType clazz, PsiElement location) { return Collections.emptyList(); } @Override public PsiElement resolveMember(PyClassType clazz, String name, PsiElement location) { - final Collection members = getMembers(clazz, location); + final Collection members = getMembers(clazz, location); return resolveMemberByName(members, clazz, name); } @Nullable - public static PsiElement resolveMemberByName(Collection members, + public static PsiElement resolveMemberByName(Collection members, PyClassType clazz, String name) { final PyClass pyClass = clazz.getPyClass(); - for (PyDynamicMember member : members) { + for (PyCustomMember member : members) { if (member.getName().equals(name)) { return member.resolve(pyClass); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyModuleMembersProvider.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyModuleMembersProvider.java index 696dcaee6623..60d13fde976e 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyModuleMembersProvider.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyModuleMembersProvider.java @@ -18,7 +18,7 @@ package com.jetbrains.python.psi.types; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyPsiFacade; import com.jetbrains.python.psi.resolve.PointInImport; @@ -33,7 +33,7 @@ import java.util.Collections; public abstract class PyModuleMembersProvider { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("Pythonid.pyModuleMembersProvider"); - public Collection getMembers(PyFile module, PointInImport point) { + public Collection getMembers(PyFile module, PointInImport point) { final VirtualFile vFile = module.getVirtualFile(); if (vFile != null) { final String qName = PyPsiFacade.getInstance(module.getProject()).findShortestImportableName(vFile, module); @@ -46,7 +46,7 @@ public abstract class PyModuleMembersProvider { @Nullable public PsiElement resolveMember(PyFile module, String name) { - for (PyDynamicMember o : getMembers(module, PointInImport.NONE)) { + for (PyCustomMember o : getMembers(module, PointInImport.NONE)) { if (o.getName().equals(name)) { return o.resolve(module); } @@ -54,5 +54,5 @@ public abstract class PyModuleMembersProvider { return null; } - protected abstract Collection getMembersByQName(PyFile module, String qName); + protected abstract Collection getMembersByQName(PyFile module, String qName); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java index 67ba765bbf81..4640fceb324d 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java @@ -47,8 +47,8 @@ public interface PyType { * or a list of elements that define the name, a la multiResolve(). */ @Nullable - List resolveMember(@NotNull final String name, @Nullable PyExpression location, - @NotNull AccessDirection direction, @NotNull PyResolveContext resolveContext); + List resolveMember(@NotNull String name, @Nullable final PyExpression location, + @NotNull final AccessDirection direction, @NotNull final PyResolveContext resolveContext); /** * Proposes completion variants from type's attributes. diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java index 0c60e6555b59..320397c4c12a 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java @@ -80,6 +80,7 @@ public class PyTypeProviderBase implements PyTypeProvider { } }; + @Nullable @Override public PyType getReferenceExpressionType(@NotNull PyReferenceExpression referenceExpression, @NotNull TypeEvalContext context) { return null; diff --git a/python/src/com/jetbrains/numpy/codeInsight/NumpyModuleMembersProvider.java b/python/src/com/jetbrains/numpy/codeInsight/NumpyModuleMembersProvider.java index 1fd2e3afd58f..fadf38916d0b 100644 --- a/python/src/com/jetbrains/numpy/codeInsight/NumpyModuleMembersProvider.java +++ b/python/src/com/jetbrains/numpy/codeInsight/NumpyModuleMembersProvider.java @@ -15,7 +15,7 @@ */ package com.jetbrains.numpy.codeInsight; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.types.PyModuleMembersProvider; @@ -39,11 +39,11 @@ public class NumpyModuleMembersProvider extends PyModuleMembersProvider { }; @Override - protected Collection getMembersByQName(PyFile module, String qName) { + protected Collection getMembersByQName(PyFile module, String qName) { if ("numpy".equals(qName)) { - final List members = new ArrayList(); + final List members = new ArrayList(); for (String type : NUMERIC_TYPES) { - members.add(new PyDynamicMember(type, "numpy.core.multiarray.dtype", false)); + members.add(new PyCustomMember(type, "numpy.core.multiarray.dtype", false)); } return members; } diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index d82e9a6fde62..9e9c68f64a69 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -846,4 +846,8 @@ remote.interpreter.default.interpreter.path=/usr/bin/python remote.interpreter.unspecified.interpreter.path=Specify Python interpreter path remote.interpreter.unspecified.temp.files.path=Specify path for PyCharm helpers remote.interpreter.configure.path.label=Python interpreter path: -remote.interpreter.configure.temp.files.path.label=PyCharm helpers path: \ No newline at end of file +remote.interpreter.configure.temp.files.path.label=PyCharm helpers path: + +# Message we display for inspection if user uses custom class type members that do not exist +custom.type.name=Dynamic class +custom.type.mimic.name=Dynamic class based on {0} \ No newline at end of file diff --git a/python/src/com/jetbrains/python/PyCustomMembersType.java b/python/src/com/jetbrains/python/PyCustomMembersType.java new file mode 100644 index 000000000000..7e6b3b07f727 --- /dev/null +++ b/python/src/com/jetbrains/python/PyCustomMembersType.java @@ -0,0 +1,189 @@ +package com.jetbrains.python; + +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.psi.PsiElement; +import com.intellij.util.ArrayUtil; +import com.intellij.util.ProcessingContext; +import com.jetbrains.python.codeInsight.PyCustomMember; +import com.jetbrains.python.codeInsight.PyCustomMemberUtils; +import com.jetbrains.python.psi.AccessDirection; +import com.jetbrains.python.psi.PyCallSiteExpression; +import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.resolve.RatedResolveResult; +import com.jetbrains.python.psi.types.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * Custom (aka dynamic) type that has some members you pass to it. To be used for cases like "type()" + * This class can also mimic any other class (optionally). When mimics, it has all methods from this class and its own. + * @author Ilya.Kazakevich + */ +public class PyCustomMembersType implements PyClassLikeType { + @NotNull + private final Map myMembers; + @Nullable + private final PyClassType myTypeToMimic; + + /** + * @param typeToMimic this type may mimic some other class-based type. Pass it to have all members from this class + custom. + * Check class manual for more info. + * @param members custom members + */ + public PyCustomMembersType(@Nullable final PyClassType typeToMimic, @NotNull final PyCustomMember... members) { + myTypeToMimic = typeToMimic; + + myMembers = new HashMap(members.length); + for (final PyCustomMember member : members) { + myMembers.put(member.getName(), member); + } + } + + /** + * @return class we mimic (if any). Check class manual for more info. + */ + @Nullable + public PyClassType getTypeToMimic() { + return myTypeToMimic; + } + + @Override + public boolean isDefinition() { + return false; + } + + @Override + public PyClassLikeType toInstance() { + return this; + } + + @Nullable + @Override + public String getClassQName() { + return null; + } + + @NotNull + @Override + public List getSuperClassTypes(@NotNull TypeEvalContext context) { + return Collections.emptyList(); + } + + @Nullable + @Override + public List resolveMember(@NotNull final String name, + @Nullable final PyExpression location, + @NotNull final AccessDirection direction, + @NotNull final PyResolveContext resolveContext, + final boolean inherited) { + if (myMembers.containsKey(name)) { + PsiElement context = null; + if (location != null) { + context = location; + } + if (context == null) { + context = resolveContext.getTypeEvalContext().getOrigin(); + } + if (context != null) { + final PsiElement resolveResult = myMembers.get(name).resolve(context); + if (resolveResult != null) { + return Collections.singletonList(new RatedResolveResult(0, resolveResult)); + } + } + } + if (myTypeToMimic != null) { + return myTypeToMimic.resolveMember(name, location, direction, resolveContext, inherited); + } + return null; + } + + @Override + public boolean isValid() { + return true; + } + + @Nullable + @Override + public PyClassLikeType getMetaClassType(@NotNull TypeEvalContext context, boolean inherited) { + return null; + } + + @Override + public boolean isCallable() { + return true; + } + + @Nullable + @Override + public PyType getReturnType(@NotNull TypeEvalContext context) { + return null; + } + + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { + return this; + } + + @Nullable + @Override + public List getParameters(@NotNull TypeEvalContext context) { + return null; + } + + @Nullable + @Override + public List resolveMember(@NotNull final String name, + @Nullable final PyExpression location, + @NotNull final AccessDirection direction, + @NotNull final PyResolveContext resolveContext) { + return resolveMember(name, location, direction, resolveContext, true); + } + + @Override + public Object[] getCompletionVariants(final String completionPrefix, final PsiElement location, final ProcessingContext context) { + final Collection lookupElements = new ArrayList(myMembers.size()); + for (final PyCustomMember member : myMembers.values()) { + lookupElements.add(PyCustomMemberUtils.toLookUpElement(member, member.getShortType())); + } + return ArrayUtil.mergeArrays(ArrayUtil.toObjectArray(lookupElements), + ((myTypeToMimic != null) + ? myTypeToMimic.getCompletionVariants(completionPrefix, location, context) + : PsiElement.EMPTY_ARRAY)); + } + + + @Nullable + @Override + public String getName() { + String mimicName = null; + if (myTypeToMimic != null) { + mimicName = myTypeToMimic.getName(); + } + if (mimicName != null) { + return PyBundle.message("custom.type.mimic.name", mimicName); + } + return PyBundle.message("custom.type.name"); + } + + @Override + public boolean isBuiltin() { + return false; + } + + @Override + public void assertValid(final String message) { + + } + + /** + * @param name name to check + * @return True if this class (not the one it mimics!) has member with passed name + */ + public boolean hasMember(@NotNull final String name) { + return myMembers.containsKey(name); + } +} diff --git a/python/src/com/jetbrains/python/codeInsight/PyCustomMemberUtils.java b/python/src/com/jetbrains/python/codeInsight/PyCustomMemberUtils.java new file mode 100644 index 000000000000..86da6a9326f5 --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/PyCustomMemberUtils.java @@ -0,0 +1,34 @@ +package com.jetbrains.python.codeInsight; + +import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * TODO: Move methods to {@link com.jetbrains.python.codeInsight.PyCustomMember}. Only dependency hell prevents me from doing it + */ +public final class PyCustomMemberUtils { + private PyCustomMemberUtils() { + } + + /** + * Creates {@link com.intellij.codeInsight.lookup.LookupElement} to be used in cases like {@link com.jetbrains.python.psi.types.PyType#getCompletionVariants(String, com.intellij.psi.PsiElement, com.intellij.util.ProcessingContext)} + * This method should be in {@link com.jetbrains.python.codeInsight.PyCustomMember} but it does not. We need to move it. + * + * @param member custom member + * @param typeText type text (if any) + * @return lookup element + */ + @NotNull + public static LookupElementBuilder toLookUpElement(@NotNull final PyCustomMember member, @Nullable final String typeText) { + + LookupElementBuilder lookupElementBuilder = LookupElementBuilder.create(member.getName()) + .withIcon(member.getIcon()) + .withTypeText(typeText); + if (member.isFunction()) { + lookupElementBuilder = lookupElementBuilder.withInsertHandler(ParenthesesInsertHandler.NO_PARAMETERS).withLookupString("()"); + } + return lookupElementBuilder; + } +} diff --git a/python/src/com/jetbrains/python/codeInsight/PyMethodNavigationOffsetProvider.java b/python/src/com/jetbrains/python/codeInsight/PyMethodNavigationOffsetProvider.java index 045bdc1307b3..a00366ab5d7d 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyMethodNavigationOffsetProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/PyMethodNavigationOffsetProvider.java @@ -54,7 +54,7 @@ public class PyMethodNavigationOffsetProvider implements MethodNavigationOffsetP array.add(psiElement); } else if (psiElement instanceof PyClass) { - Collections.addAll(array, ((PyClass)psiElement).getMethods()); + Collections.addAll(array, ((PyClass)psiElement).getMethods(false)); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PySuperMethodCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PySuperMethodCompletionContributor.java index 04ad5ae8e958..4778c6db1ccc 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PySuperMethodCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PySuperMethodCompletionContributor.java @@ -57,13 +57,13 @@ public class PySuperMethodCompletionContributor extends CompletionContributor { return; } Set seenNames = new HashSet(); - for (PyFunction function : containingClass.getMethods()) { + for (PyFunction function : containingClass.getMethods(false)) { seenNames.add(function.getName()); } LanguageLevel languageLevel = LanguageLevel.forElement(parameters.getOriginalFile()); seenNames.addAll(PyNames.getBuiltinMethods(languageLevel).keySet()); for (PyClass ancestor : containingClass.getAncestorClasses()) { - for (PyFunction superMethod : ancestor.getMethods()) { + for (PyFunction superMethod : ancestor.getMethods(false)) { if (!seenNames.contains(superMethod.getName())) { String text = superMethod.getName() + superMethod.getParameterList().getText(); LookupElementBuilder element = LookupElementBuilder.create(text); diff --git a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java index 5a6caf0a8941..634eaf9a59c9 100644 --- a/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/override/PyOverrideImplementUtil.java @@ -281,7 +281,7 @@ public class PyOverrideImplementUtil { public static Collection getAllSuperFunctions(@NotNull final PyClass pyClass) { final Map superFunctions = new HashMap(); for (PyClass aClass : pyClass.getAncestorClasses()) { - for (PyFunction function : aClass.getMethods()) { + for (PyFunction function : aClass.getMethods(false)) { if (!superFunctions.containsKey(function.getName())) { superFunctions.put(function.getName(), function); } diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibClassMembersProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibClassMembersProvider.java index b0b8c06c92de..334552aaf8c0 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibClassMembersProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibClassMembersProvider.java @@ -17,7 +17,7 @@ package com.jetbrains.python.codeInsight.stdlib; import com.intellij.openapi.util.Key; import com.intellij.psi.PsiElement; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyTargetExpression; @@ -35,16 +35,16 @@ import java.util.List; * @author yole */ public class PyStdlibClassMembersProvider extends PyClassMembersProviderBase { - private Key> mySocketMembersKey = Key.create("socket.members"); + private Key> mySocketMembersKey = Key.create("socket.members"); @NotNull @Override - public Collection getMembers(PyClassType classType, PsiElement location) { + public Collection getMembers(PyClassType classType, PsiElement location) { PyClass clazz = classType.getPyClass(); final String qualifiedName = clazz.getQualifiedName(); if ("socket._socketobject".equals(qualifiedName)) { final PyFile socketFile = (PyFile)clazz.getContainingFile(); - List socketMembers = socketFile.getUserData(mySocketMembersKey); + List socketMembers = socketFile.getUserData(mySocketMembersKey); if (socketMembers == null) { socketMembers = calcSocketMembers(socketFile); socketFile.putUserData(mySocketMembersKey, socketMembers); @@ -54,20 +54,20 @@ public class PyStdlibClassMembersProvider extends PyClassMembersProviderBase { return Collections.emptyList(); } - private static List calcSocketMembers(PyFile socketFile) { - List result = new ArrayList(); + private static List calcSocketMembers(PyFile socketFile) { + List result = new ArrayList(); addMethodsFromAttr(socketFile, result, "_socketmethods"); addMethodsFromAttr(socketFile, result, "_delegate_methods"); return result; } - private static void addMethodsFromAttr(PyFile socketFile, List result, final String attrName) { + private static void addMethodsFromAttr(PyFile socketFile, List result, final String attrName) { final PyTargetExpression socketMethods = socketFile.findTopLevelAttribute(attrName); if (socketMethods != null) { final List methods = PyUtil.getStringListFromTargetExpression(socketMethods); if (methods != null) { for (String name : methods) { - result.add(new PyDynamicMember(name).resolvesTo("_socket").toClass("SocketType").toFunction(name)); + result.add(new PyCustomMember(name).resolvesTo("_socket").toClass("SocketType").toFunction(name)); } } } diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibModuleMembersProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibModuleMembersProvider.java index 80d3627ac083..a724b7808a75 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibModuleMembersProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibModuleMembersProvider.java @@ -18,7 +18,7 @@ package com.jetbrains.python.codeInsight.stdlib; import com.intellij.openapi.util.SystemInfo; import com.intellij.psi.PsiElement; import com.intellij.psi.util.QualifiedName; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.resolve.ResolveImportUtil; import com.jetbrains.python.psi.types.PyModuleMembersProvider; @@ -33,15 +33,15 @@ import java.util.List; */ public class PyStdlibModuleMembersProvider extends PyModuleMembersProvider { @Override - protected Collection getMembersByQName(PyFile module, String qName) { + protected Collection getMembersByQName(PyFile module, String qName) { if (qName.equals("os")) { - final List results = new ArrayList(); + final List results = new ArrayList(); PsiElement path = null; if (module != null) { final String pathModuleName = SystemInfo.isWindows ? "ntpath" : "posixpath"; path = ResolveImportUtil.resolveModuleInRoots(QualifiedName.fromDottedString(pathModuleName), module); } - results.add(new PyDynamicMember("path", path)); + results.add(new PyCustomMember("path", path)); return results; } return Collections.emptyList(); diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsClassMembersProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsClassMembersProvider.java index 5ac7fc10751c..bcc39aab9010 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsClassMembersProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsClassMembersProvider.java @@ -16,7 +16,7 @@ package com.jetbrains.python.codeInsight.userSkeletons; import com.intellij.psi.PsiElement; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.PyTargetExpression; @@ -37,7 +37,7 @@ import java.util.List; public class PyUserSkeletonsClassMembersProvider extends PyClassMembersProviderBase implements PyOverridingAncestorsClassMembersProvider { @NotNull @Override - public Collection getMembers(@NotNull PyClassType classType, PsiElement location) { + public Collection getMembers(@NotNull PyClassType classType, PsiElement location) { final PyClass cls = classType.getPyClass(); final PyClass skeleton = PyUserSkeletonsUtil.getUserSkeleton(cls); if (skeleton != null) { @@ -73,24 +73,24 @@ public class PyUserSkeletonsClassMembersProvider extends PyClassMembersProviderB return null; } - private static Collection getClassMembers(@NotNull PyClass cls) { - final List result = new ArrayList(); - for (PyFunction function : cls.getMethods()) { + private static Collection getClassMembers(@NotNull PyClass cls) { + final List result = new ArrayList(); + for (PyFunction function : cls.getMethods(false)) { final String name = function.getName(); if (name != null) { - result.add(new PyDynamicMember(name, function)); + result.add(new PyCustomMember(name, function)); } } for (PyTargetExpression attribute : cls.getInstanceAttributes()) { final String name = attribute.getName(); if (name != null) { - result.add(new PyDynamicMember(name, attribute)); + result.add(new PyCustomMember(name, attribute)); } } for (PyTargetExpression attribute : cls.getClassAttributes()) { final String name = attribute.getName(); if (name != null) { - result.add(new PyDynamicMember(name, attribute)); + result.add(new PyCustomMember(name, attribute)); } } return result; diff --git a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsModuleMembersProvider.java b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsModuleMembersProvider.java index ad876ee4ec91..c42d15c6f463 100644 --- a/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsModuleMembersProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/userSkeletons/PyUserSkeletonsModuleMembersProvider.java @@ -17,7 +17,7 @@ package com.jetbrains.python.codeInsight.userSkeletons; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFileSystemItem; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.PyElement; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.types.PyModuleMembersProvider; @@ -43,17 +43,17 @@ public class PyUserSkeletonsModuleMembersProvider extends PyModuleMembersProvide } @Override - protected Collection getMembersByQName(PyFile module, String qName) { + protected Collection getMembersByQName(PyFile module, String qName) { final PyFile moduleSkeleton = PyUserSkeletonsUtil.getUserSkeletonForModuleQName(qName, module); if (moduleSkeleton != null) { - final List results = new ArrayList(); + final List results = new ArrayList(); for (PyElement element : moduleSkeleton.iterateNames()) { if (element instanceof PsiFileSystemItem) { continue; } final String name = element.getName(); if (name != null) { - results.add(new PyDynamicMember(name, element)); + results.add(new PyCustomMember(name, element)); } } return results; diff --git a/python/src/com/jetbrains/python/documentation/DocStringParameterReference.java b/python/src/com/jetbrains/python/documentation/DocStringParameterReference.java index 968d41368d37..f0b15da7a7a6 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringParameterReference.java +++ b/python/src/com/jetbrains/python/documentation/DocStringParameterReference.java @@ -173,7 +173,7 @@ public class DocStringParameterReference extends PsiReferenceBase 0) addAnchor = meths[0].getPrevSibling(); PyStatementList clsContent = cls.getStatementList(); newInit = (PyFunction) clsContent.addAfter(newInit, addAnchor); diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java index 8049546a6e92..10b4c6f8705a 100644 --- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java @@ -33,9 +33,10 @@ import com.intellij.psi.util.QualifiedName; import com.intellij.util.Consumer; import com.intellij.util.PlatformUtils; import com.jetbrains.python.PyBundle; +import com.jetbrains.python.PyCustomMembersType; import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.PyCodeInsightSettings; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.codeInsight.imports.AutoImportHintAction; @@ -462,7 +463,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } if (expr.isQualified()) { final PyClassTypeImpl object_type = (PyClassTypeImpl)PyBuiltinCache.getInstance(node).getObjectType(); - if ((object_type != null) && object_type.getPossibleInstanceMembers().contains(refName)){ + if ((object_type != null) && object_type.getPossibleInstanceMembers().contains(refName)) { return; } } @@ -542,6 +543,10 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } markedQualified = true; } + else if (isHasCustomMember(refName, type)) { + // We have dynamic members + return; + } else { description = PyBundle.message("INSP.cannot.find.$0.in.$1", refText, type.getName()); markedQualified = true; @@ -605,6 +610,16 @@ public class PyUnresolvedReferencesInspection extends PyInspection { registerProblem(node, description, hl_type, null, rangeInElement, actions.toArray(new LocalQuickFix[actions.size()])); } + /** + * Checks if type is custom-member based and has custom member with certain name + * @param refName name to check + * @param type type + * @return true if has one + */ + private static boolean isHasCustomMember(@NotNull final String refName, @NotNull final PyType type) { + return (type instanceof PyCustomMembersType) && ((PyCustomMembersType)type).hasMember(refName); + } + /** * Return the canonical qualified name for a reference (even for an unresolved one). */ @@ -687,6 +702,13 @@ public class PyUnresolvedReferencesInspection extends PyInspection { return true; } } + if (type instanceof PyCustomMembersType) { + // Skip custom member types that mimics another class with fuzzy parents + PyClassType mimic = ((PyCustomMembersType)type).getTypeToMimic(); + if (mimic != null && PyUtil.hasUnresolvedAncestors(mimic.getPyClass(), myTypeEvalContext)) { + return true; + } + } if (type instanceof PyClassTypeImpl) { PyClass cls = ((PyClassType)type).getPyClass(); if (overridesGetAttr(cls, myTypeEvalContext)) { @@ -721,8 +743,8 @@ public class PyUnresolvedReferencesInspection extends PyInspection { PsiReference reference, @NotNull final String name) { for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { - final Collection resolveResult = provider.getMembers(type, reference.getElement()); - for (PyDynamicMember member : resolveResult) { + final Collection resolveResult = provider.getMembers(type, reference.getElement()); + for (PyCustomMember member : resolveResult) { if (member.getName().equals(name)) return true; } } @@ -810,7 +832,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } } } - for (PyFunction method : containedClass.getMethods()) { + for (PyFunction method : containedClass.getMethods(false)) { if (expr.getText().equals(method.getName())) { actions.add(new UnresolvedReferenceAddSelfQuickFix(expr, qualifier)); } diff --git a/python/src/com/jetbrains/python/projectView/PyElementNode.java b/python/src/com/jetbrains/python/projectView/PyElementNode.java index 6ec347236773..3ef8ddd71a6b 100644 --- a/python/src/com/jetbrains/python/projectView/PyElementNode.java +++ b/python/src/com/jetbrains/python/projectView/PyElementNode.java @@ -50,7 +50,7 @@ public class PyElementNode extends BasePsiNode { for (PyClass aClass : pyClass.getNestedClasses()) { result.add(new PyElementNode(myProject, aClass, getSettings())); } - for (PyFunction function : pyClass.getMethods()) { + for (PyFunction function : pyClass.getMethods(false)) { result.add(new PyElementNode(myProject, function, getSettings())); } return result; diff --git a/python/src/com/jetbrains/python/psi/PsiQuery.java b/python/src/com/jetbrains/python/psi/PsiQuery.java index d41f6ba68a2c..3e1e26de12c3 100644 --- a/python/src/com/jetbrains/python/psi/PsiQuery.java +++ b/python/src/com/jetbrains/python/psi/PsiQuery.java @@ -172,9 +172,7 @@ public class PsiQuery { } } } - @SuppressWarnings("unchecked") // Type is preserved - final T[] array = (T[])result.toArray(new PsiElement[result.size()]); - return new PsiTypedQuery(clazz, array); + return new PsiTypedQuery(clazz, result); } @@ -309,14 +307,17 @@ public class PsiQuery { * Filter elements by class */ @NotNull - public PsiQuery filter(@NotNull final Class clazz) { + public PsiTypedQuery filter(@NotNull final Class clazz) { final Set result = new HashSet(Arrays.asList(myPsiElements)); for (final PsiElement element : myPsiElements) { - if (PyUtil.as(element, clazz) == null) { + if (!(clazz.isInstance(element))) { result.remove(element); } } - return new PsiQuery(result.toArray(new PsiElement[result.size()])); + // We checked it in runtime + @SuppressWarnings("unchecked") + final List toAdd = (List)new ArrayList(result); + return new PsiTypedQuery(clazz, toAdd); } @@ -351,16 +352,16 @@ public class PsiQuery { @NotNull private final Class myClass; @NotNull - private final T[] myElements; + private final List myElements; /** * @param clazz type * @param elements elements */ - private PsiTypedQuery(@NotNull final Class clazz, @NotNull final T... elements) { + private PsiTypedQuery(@NotNull final Class clazz, @NotNull final List elements) { super(elements); myClass = clazz; - myElements = elements.clone(); + myElements = elements; } /** @@ -383,8 +384,8 @@ public class PsiQuery { * @return All elements of certain type */ @NotNull - public T[] getElements() { - return myElements.clone(); + public List getElements() { + return Collections.unmodifiableList(myElements); } } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 611cbc84ad2e..c7f2173973c0 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -389,9 +389,34 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla return result; } + @Override @NotNull - public PyFunction[] getMethods() { - return getClassChildren(PythonDialectsTokenSetProvider.INSTANCE.getFunctionDeclarationTokens(), PyFunction.ARRAY_FACTORY); + public PyFunction[] getMethods(final boolean inherited) { + final PyFunction[] thisClassFunctions = + getClassChildren(PythonDialectsTokenSetProvider.INSTANCE.getFunctionDeclarationTokens(), PyFunction.ARRAY_FACTORY); + if (!inherited) { + return thisClassFunctions; + } + // Map to get rid of duplicated (overwritten methods) + final Map result = new HashMap(); + // We get classes in MRO order (hopefully), so last methods are last + for (final PyClass superClass : getSuperClasses()) { + for (final PyFunction function : superClass.getMethods(false)) { + final String functionName = function.getName(); + if (functionName != null) { + result.put(functionName, function); + } + } + } + // We now need to add our own methods + for (final PyFunction function : thisClassFunctions) { + final String functionName = function.getName(); + if (functionName != null) { + result.put(functionName, function); + } + } + final Collection functionsToReturn = result.values(); + return functionsToReturn.toArray(new PyFunction[functionsToReturn.size()]); } @Override @@ -514,7 +539,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla // look at @property decorators Map> grouped = new HashMap>(); // group suitable same-named methods, each group defines a property - for (PyFunction method : getMethods()) { + for (PyFunction method : getMethods(false)) { final String methodName = method.getName(); if (name == null || name.equals(methodName)) { List bucket = grouped.get(methodName); @@ -826,7 +851,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla public boolean visitMethods(Processor processor, boolean inherited, boolean skipClassObj) { - PyFunction[] methods = getMethods(); + PyFunction[] methods = getMethods(false); if (!ContainerUtil.process(methods, processor)) return false; if (inherited) { for (PyClass ancestor : getAncestorClasses()) { @@ -932,7 +957,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla collectInstanceAttributes(initMethod, result); } Set namesInInit = new HashSet(result.keySet()); - final PyFunction[] methods = getMethods(); + final PyFunction[] methods = getMethods(false); for (PyFunction method : methods) { if (!PyNames.INIT.equals(method.getName())) { collectInstanceAttributes(method, result, namesInInit); @@ -981,7 +1006,8 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla final List result = new ArrayList(); statementList.accept(new PyRecursiveElementVisitor() { @Override - public void visitPyClass(PyClass node) {} + public void visitPyClass(PyClass node) { + } public void visitPyAssignmentStatement(final PyAssignmentStatement node) { for (PyExpression expression : node.getTargets()) { @@ -1338,4 +1364,10 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla } return null; } + + @Nullable + @Override + public PyClassLikeType getType(@NotNull TypeEvalContext context) { + return PyUtil.as(context.getType(this), PyClassLikeType.class); + } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java b/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java index dea9296f12c6..3f948c496592 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java +++ b/python/src/com/jetbrains/python/psi/impl/PyEvaluator.java @@ -65,6 +65,15 @@ public class PyEvaluator { if (expr instanceof PySequenceExpression) { return evaluateSequenceExpression((PySequenceExpression)expr); } + if (expr instanceof PyQualifiedExpression) { // support bool + final String referencedName = ((PyQualifiedExpression)expr).getReferencedName(); + if (PyNames.TRUE.equals(referencedName)) { + return true; + } + if (PyNames.FALSE.equals(referencedName)) { + return true; + } + } if (expr instanceof PyCallExpression) { return evaluateCall((PyCallExpression)expr); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 2c1842f3337f..9f6afb5e43f7 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; import com.intellij.psi.StubBasedPsiElement; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; @@ -699,4 +700,39 @@ public class PyFunctionImpl extends PyBaseElementImpl implements public String getQualifiedName() { return QualifiedNameFinder.getQualifiedName(this); } + + @NotNull + @Override + public List findAttributes() { + final List result = new ArrayList(); + for (final PyAssignmentStatement statement : new PsiQuery(this).siblings(PyAssignmentStatement.class).getElements()) { + for (final PyQualifiedExpression targetExpression : new PsiQuery(statement.getTargets()).filter(PyQualifiedExpression.class) + .getElements()) { + final PyExpression qualifier = targetExpression.getQualifier(); + if (qualifier == null) { + continue; + } + final PsiReference qualifierReference = qualifier.getReference(); + if (qualifierReference == null) { + continue; + } + if (qualifierReference.isReferenceTo(this)) { + result.add(statement); + } + } + } + return result; + } + + @NotNull + @Override + public ProtectionLevel getProtectionLevel() { + final int underscoreLevels = PyUtil.getInitialUnderscores(getName()); + for (final ProtectionLevel level : ProtectionLevel.values()) { + if (level.getUnderscoreLevel() == underscoreLevels) { + return level; + } + } + return ProtectionLevel.PRIVATE; + } } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 34a92e16bf01..d9b69121aa50 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -16,7 +16,6 @@ package com.jetbrains.python.psi.types; import com.intellij.codeInsight.completion.CompletionUtil; -import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.openapi.extensions.Extensions; @@ -33,7 +32,8 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.ProcessingContext; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyNames; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; +import com.jetbrains.python.codeInsight.PyCustomMemberUtils; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.impl.ResolveResultList; @@ -151,7 +151,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @NotNull PyResolveContext resolveContext, boolean inherited) { final TypeEvalContext context = resolveContext.getTypeEvalContext(); - PsiElement classMember = resolveByOverridingMembersProviders(this, name, location); //overriding members provers have priority to normal resolve + PsiElement classMember = + resolveByOverridingMembersProviders(this, name, location); //overriding members provers have priority to normal resolve if (classMember != null) { return ResolveResultList.to(classMember); } @@ -219,7 +220,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } if (inherited) { - classMember = resolveByMembersProviders(this, name, location); //ask providers after real class introspection as providers have less priority + classMember = + resolveByMembersProviders(this, name, location); //ask providers after real class introspection as providers have less priority } if (classMember != null) { @@ -414,16 +416,11 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { addInheritedMembers(prefix, location, namesAlready, context, ret, typeEvalContext); // from providers - for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { - for (PyDynamicMember member : provider.getMembers(this, location)) { + for (final PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { + for (final PyCustomMember member : provider.getMembers(this, location)) { final String name = member.getName(); if (!namesAlready.contains(name)) { - LookupElementBuilder lookupElementBuilder = LookupElementBuilder.create(name).withIcon(member.getIcon()).withTypeText(getName()); - if (member.isFunction()) { - lookupElementBuilder = lookupElementBuilder.withInsertHandler(ParenthesesInsertHandler.NO_PARAMETERS); - lookupElementBuilder.withTailText("()"); - } - ret.add(lookupElementBuilder); + ret.add(PyCustomMemberUtils.toLookUpElement(member, getName())); } } } diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index db5a9ba3f1ae..0aec8612c989 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -30,7 +30,7 @@ import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ProcessingContext; import com.jetbrains.python.PyNames; -import com.jetbrains.python.codeInsight.PyDynamicMember; +import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.psi.*; @@ -289,7 +289,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje Set namesAlready = context.get(CTX_NAMES); PointInImport point = ResolveImportUtil.getPointInImport(location); for (PyModuleMembersProvider provider : Extensions.getExtensions(PyModuleMembersProvider.EP_NAME)) { - for (PyDynamicMember member : provider.getMembers(myModule, point)) { + for (PyCustomMember member : provider.getMembers(myModule, point)) { final String name = member.getName(); if (namesAlready != null) { namesAlready.add(name); diff --git a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java index 52c32d95d38d..56bd80ca3077 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java +++ b/python/src/com/jetbrains/python/refactoring/classes/membersManager/MethodsManager.java @@ -44,7 +44,7 @@ class MethodsManager extends MembersManager { @Override public boolean hasConflict(@NotNull final PyFunction member, @NotNull final PyClass aClass) { - return NamePredicate.hasElementWithSameName(member, Arrays.asList(aClass.getMethods())); + return NamePredicate.hasElementWithSameName(member, Arrays.asList(aClass.getMethods(false))); } @NotNull @@ -64,7 +64,7 @@ class MethodsManager extends MembersManager { @NotNull @Override protected List getMembersCouldBeMoved(@NotNull final PyClass pyClass) { - return FluentIterable.from(Arrays.asList(pyClass.getMethods())).filter(new NamelessFilter()).filter(NO_PROPERTIES).toList(); + return FluentIterable.from(Arrays.asList(pyClass.getMethods(false))).filter(new NamelessFilter()).filter(NO_PROPERTIES).toList(); } @Override diff --git a/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java b/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java index d16712dea6c7..a396a354a381 100644 --- a/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java +++ b/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java @@ -181,7 +181,7 @@ public class PyExtractMethodUtil { scope.add(owner); final PyClass containingClass = ((PyFunction)owner).getContainingClass(); if (containingClass != null) { - for (PyFunction function : containingClass.getMethods()) { + for (PyFunction function : containingClass.getMethods(false)) { if (!function.equals(owner) && !function.equals(generatedMethod)) scope.add(function); } diff --git a/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java index d0a6d19e19e2..006749a25e96 100644 --- a/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java +++ b/python/src/com/jetbrains/python/testing/attest/PythonAtTestConfigurationProducer.java @@ -60,7 +60,7 @@ public class PythonAtTestConfigurationProducer extends } private static boolean hasTestFunction(@NotNull final PyClass pyClass) { - PyFunction[] methods = pyClass.getMethods(); + PyFunction[] methods = pyClass.getMethods(false); for (PyFunction function : methods) { PyDecoratorList decorators = function.getDecoratorList(); if (decorators == null) continue; diff --git a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestUtil.java b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestUtil.java index fd6e9ef357af..b0889b72c46d 100644 --- a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestUtil.java +++ b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestUtil.java @@ -58,7 +58,7 @@ public class PythonDocTestUtil { } public static boolean isDocTestClass(PyClass pyClass) { - for (PyFunction cls : pyClass.getMethods()) { + for (PyFunction cls : pyClass.getMethods(false)) { if (isDocTestFunction(cls)) { return true; } diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java b/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java index b6f463b15706..357227532727 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestUtil.java @@ -80,7 +80,7 @@ public class PyTestUtil { if (className == null) return false; final String name = className.toLowerCase(); if (name.startsWith("test")) { - for (PyFunction cls : pyClass.getMethods()) { + for (PyFunction cls : pyClass.getMethods(false)) { if (isPyTestFunction(cls)) { return true; } diff --git a/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java b/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java index 203b462c5a44..c5e489c06485 100644 --- a/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java +++ b/python/testSrc/com/jetbrains/python/PyControlFlowBuilderTest.java @@ -205,7 +205,7 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase { configureByFile(testName + ".py"); final String fullPath = getTestDataPath() + testName + ".txt"; final PyClass pyClass = ((PyFile) myFile).getTopLevelClasses().get(0); - final ControlFlow flow = ControlFlowCache.getControlFlow(pyClass.getMethods()[0]); + final ControlFlow flow = ControlFlowCache.getControlFlow(pyClass.getMethods(false)[0]); check(fullPath, flow); } @@ -214,7 +214,7 @@ public class PyControlFlowBuilderTest extends LightMarkedTestCase { configureByFile(testName + ".py"); final String fullPath = getTestDataPath() + testName + ".txt"; final PyClass pyClass = ((PyFile) myFile).getTopLevelClasses().get(0); - final ControlFlow flow = ControlFlowCache.getControlFlow(pyClass.getMethods()[0]); + final ControlFlow flow = ControlFlowCache.getControlFlow(pyClass.getMethods(false)[0]); check(fullPath, flow); } diff --git a/python/testSrc/com/jetbrains/python/PyOverrideTest.java b/python/testSrc/com/jetbrains/python/PyOverrideTest.java index d80dc06182e7..fddb9e26c905 100644 --- a/python/testSrc/com/jetbrains/python/PyOverrideTest.java +++ b/python/testSrc/com/jetbrains/python/PyOverrideTest.java @@ -35,7 +35,7 @@ import java.util.Collections; public class PyOverrideTest extends PyTestCase { private void doTest() { myFixture.configureByFile("override/" + getTestName(true) + ".py"); - PyFunction toOverride = getTopLevelClass(0).getMethods() [0]; + PyFunction toOverride = getTopLevelClass(0).getMethods(false) [0]; PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), getTopLevelClass(1), Collections.singletonList(new PyMethodMember(toOverride)), false); myFixture.checkResultByFile("override/" + getTestName(true) + "_after.py", true); @@ -86,7 +86,7 @@ public class PyOverrideTest extends PyTestCase { public void testInnerClass() { // PY-10976 myFixture.configureByFile("override/" + getTestName(true) + ".py"); - PyFunction toOverride = getTopLevelClass(0).getMethods()[0]; + PyFunction toOverride = getTopLevelClass(0).getMethods(false)[0]; PyClass pyClass = getTopLevelClass(1).getNestedClasses()[0]; PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), pyClass, Collections.singletonList(new PyMethodMember(toOverride)), false); @@ -95,7 +95,7 @@ public class PyOverrideTest extends PyTestCase { public void testInnerFunctionClass() { myFixture.configureByFile("override/" + getTestName(true) + ".py"); - PyFunction toOverride = getTopLevelClass(0).getMethods()[0]; + PyFunction toOverride = getTopLevelClass(0).getMethods(false)[0]; final PsiElement element = myFixture.getElementAtCaret(); PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), PsiTreeUtil.getParentOfType(element, PyClass.class, false), Collections.singletonList(new PyMethodMember(toOverride)), false); @@ -115,7 +115,7 @@ public class PyOverrideTest extends PyTestCase { public void testImplement() { myFixture.configureByFile("override/" + getTestName(true) + ".py"); - PyFunction toImplement = getTopLevelClass(0).getMethods()[1]; + PyFunction toImplement = getTopLevelClass(0).getMethods(false)[1]; PyOverrideImplementUtil.overrideMethods(myFixture.getEditor(), getTopLevelClass(1), Collections.singletonList(new PyMethodMember(toImplement)), true); myFixture.checkResultByFile("override/" + getTestName(true) + "_after.py", true); diff --git a/python/testSrc/com/jetbrains/python/PyStubsTest.java b/python/testSrc/com/jetbrains/python/PyStubsTest.java index 0904b4c3d7d0..2a58613f1668 100644 --- a/python/testSrc/com/jetbrains/python/PyStubsTest.java +++ b/python/testSrc/com/jetbrains/python/PyStubsTest.java @@ -75,7 +75,7 @@ public class PyStubsTest extends PyTestCase { assertEquals("staticField", attrs.get(0).getName()); assertTrue(attrs.get(0).getAssignedQName().matches("deco")); - final PyFunction[] methods = pyClass.getMethods(); + final PyFunction[] methods = pyClass.getMethods(false); assertEquals(2, methods.length); assertEquals("__init__", methods [0].getName()); assertEquals("fooFunction", methods [1].getName()); @@ -122,7 +122,7 @@ public class PyStubsTest extends PyTestCase { Property prop = pyClass.findProperty("value", true); Maybe maybe_function = prop.getGetter(); assertTrue(maybe_function.isDefined()); - assertEquals(pyClass.getMethods()[0], maybe_function.value()); + assertEquals(pyClass.getMethods(false)[0], maybe_function.value()); Property setvalueProp = pyClass.findProperty("setvalue", true); Maybe setter = setvalueProp.getSetter(); @@ -135,10 +135,10 @@ public class PyStubsTest extends PyTestCase { prop = pyClass.findProperty("x", true); maybe_function = prop.getGetter(); assertTrue(maybe_function.isDefined()); - assertEquals(pyClass.getMethods()[0], maybe_function.value()); + assertEquals(pyClass.getMethods(false)[0], maybe_function.value()); maybe_function = prop.getSetter(); assertTrue(maybe_function.isDefined()); - assertEquals(pyClass.getMethods()[1], maybe_function.value()); + assertEquals(pyClass.getMethods(false)[1], maybe_function.value()); // ...and the juice: assertNotParsed(file); @@ -342,7 +342,7 @@ public class PyStubsTest extends PyTestCase { public void testWrappedStaticMethod() { final PyFileImpl file = (PyFileImpl) getTestFile(); final PyClass pyClass = file.getTopLevelClasses().get(0); - final PyFunction[] methods = pyClass.getMethods(); + final PyFunction[] methods = pyClass.getMethods(false); assertEquals(1, methods.length); final PyFunction.Modifier modifier = methods[0].getModifier(); assertEquals(PyFunction.Modifier.STATICMETHOD, modifier); diff --git a/python/testSrc/com/jetbrains/python/refactoring/classes/PyDependenciesComparatorTest.java b/python/testSrc/com/jetbrains/python/refactoring/classes/PyDependenciesComparatorTest.java index 9ebe01b127dc..b3be3825f970 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/classes/PyDependenciesComparatorTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/classes/PyDependenciesComparatorTest.java @@ -1,7 +1,6 @@ package com.jetbrains.python.refactoring.classes; import com.intellij.psi.PsiElement; -import com.intellij.util.text.Matcher; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.psi.*; import org.hamcrest.Matchers; @@ -23,7 +22,7 @@ public class PyDependenciesComparatorTest extends PyTestCase { @SuppressWarnings("ConstantConditions") // Can't be null (class has docstring) PsiElement docStringExpression = clazz.getDocStringExpression().getParent(); - PyFunction method = clazz.getMethods()[0]; + PyFunction method = clazz.getMethods(false)[0]; PsiElement classField = clazz.getClassAttributes().get(0).getParent(); final List elementList = new ArrayList(); diff --git a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index b7738ec08ef8..6fc2aa0775b6 100644 --- a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -169,6 +169,7 @@ giud globals google gruntfile +gulpfile gzip gzipped hamcrest