diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java index da7c37b380b7..a994be84e76c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java @@ -41,6 +41,7 @@ import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.IncorrectOperationException; import com.sun.jdi.Value; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -321,7 +322,10 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { if (rType == null) { throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText())); } - PsiType typeForBinOp = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, opType, true); + final PsiType typeForBinOp = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, opType, true); + if (typeForBinOp == null) { + throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", wideExpression.getText())); + } myResult = createBinaryEvaluator(result, lType, rResult, rType, opType, typeForBinOp); lType = typeForBinOp; result = myResult; @@ -330,7 +334,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { // constructs binary evaluator handling unboxing and numeric promotion issues private static BinaryExpressionEvaluator createBinaryEvaluator( - Evaluator lResult, final PsiType lType, Evaluator rResult, final PsiType rType, final IElementType operation, final PsiType expressionExpectedType) { + Evaluator lResult, final PsiType lType, Evaluator rResult, final PsiType rType, final IElementType operation, final @NotNull PsiType expressionExpectedType) { // handle unboxing if neccesary if (isUnboxingInBinaryExpressionApplicable(lType, rType, operation)) { if (rType instanceof PsiClassType && UnBoxingEvaluator.isTypeUnboxable(rType.getCanonicalText())) { @@ -394,7 +398,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { } } - return new BinaryExpressionEvaluator(lResult, rResult, operation, expressionExpectedType == null ? null : expressionExpectedType.getCanonicalText()); + return new BinaryExpressionEvaluator(lResult, rResult, operation, expressionExpectedType.getCanonicalText()); } private static boolean isBinaryNumericPromotionApplicable(PsiType lType, PsiType rType, IElementType opType) { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java index a3c5b5c68a15..116da27861d4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateConstructorHandler.java @@ -134,6 +134,32 @@ public class GenerateConstructorHandler extends GenerateMembersHandlerBase { return members; } + @Override + protected MemberChooser createMembersChooser(ClassMember[] members, + boolean allowEmptySelection, + boolean copyJavadocCheckbox, + Project project) { + final MemberChooser chooser = super.createMembersChooser(members, allowEmptySelection, copyJavadocCheckbox, project); + final List preselection = preselect(members); + if (!preselection.isEmpty()) { + chooser.selectElements(preselection.toArray(new ClassMember[preselection.size()])); + } + return chooser; + } + + protected static List preselect(ClassMember[] members) { + final List preselection = new ArrayList(); + for (ClassMember member : members) { + if (member instanceof PsiFieldMember) { + final PsiField psiField = ((PsiFieldMember)member).getElement(); + if (psiField != null && psiField.hasModifierProperty(PsiModifier.FINAL)) { + preselection.add(member); + } + } + } + return preselection; + } + @NotNull protected List generateMemberPrototypes(PsiClass aClass, ClassMember[] members) throws IncorrectOperationException { List baseConstructors = new ArrayList(); diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersHandlerBase.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersHandlerBase.java index 79cbfe47eef0..a42018e62eb8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersHandlerBase.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersHandlerBase.java @@ -183,15 +183,23 @@ public abstract class GenerateMembersHandlerBase implements CodeInsightActionHan @Nullable protected ClassMember[] chooseMembers(ClassMember[] members, boolean allowEmptySelection, boolean copyJavadocCheckbox, Project project) { - MemberChooser chooser = new MemberChooser(members, allowEmptySelection, true, project); - chooser.setTitle(myChooserTitle); - chooser.setCopyJavadocVisible(copyJavadocCheckbox); + MemberChooser chooser = createMembersChooser(members, allowEmptySelection, copyJavadocCheckbox, project); chooser.show(); myToCopyJavaDoc = chooser.isCopyJavadoc(); final List list = chooser.getSelectedElements(); return list == null ? null : list.toArray(new ClassMember[list.size()]); } + protected MemberChooser createMembersChooser(ClassMember[] members, + boolean allowEmptySelection, + boolean copyJavadocCheckbox, + Project project) { + MemberChooser chooser = new MemberChooser(members, allowEmptySelection, true, project); + chooser.setTitle(myChooserTitle); + chooser.setCopyJavadocVisible(copyJavadocCheckbox); + return chooser; + } + @NotNull protected List generateMemberPrototypes(PsiClass aClass, ClassMember[] members) throws IncorrectOperationException { ArrayList array = new ArrayList(); diff --git a/java/java-tests/testData/codeInsight/generateConstructor/afterFinalFieldPreselection.java b/java/java-tests/testData/codeInsight/generateConstructor/afterFinalFieldPreselection.java new file mode 100644 index 000000000000..bd402a9b28b7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateConstructor/afterFinalFieldPreselection.java @@ -0,0 +1,11 @@ +class Test { + private int a; + private final int b; + private int c; + private final int d; + + Test(int b, int d) { + this.b = b; + this.d = d; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateConstructor/beforeFinalFieldPreselection.java b/java/java-tests/testData/codeInsight/generateConstructor/beforeFinalFieldPreselection.java new file mode 100644 index 000000000000..57459a5e4b37 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateConstructor/beforeFinalFieldPreselection.java @@ -0,0 +1,6 @@ +class Test { + private int a; + private final int b; + private int c; + private final int d; +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateConstructorTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateConstructorTest.java index 21efe1f59f4a..c04ab6a28d4c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateConstructorTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateConstructorTest.java @@ -10,6 +10,8 @@ import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.testFramework.LightCodeInsightTestCase; +import java.util.List; + public class GenerateConstructorTest extends LightCodeInsightTestCase { public void testAbstractClass() throws Exception { doTest(); } public void testPackageLocalClass() throws Exception { doTest(); } @@ -38,6 +40,22 @@ public class GenerateConstructorTest extends LightCodeInsightTestCase { doTest(); } + public void testFinalFieldPreselection() throws Exception { + String name = getTestName(false); + configureByFile("/codeInsight/generateConstructor/before" + name + ".java"); + new GenerateConstructorHandler() { + @Override + protected ClassMember[] chooseMembers(ClassMember[] members, + boolean allowEmptySelection, + boolean copyJavadocCheckbox, + Project project) { + final List preselection = GenerateConstructorHandler.preselect(members); + return preselection.toArray(new ClassMember[preselection.size()]); + } + }.invoke(getProject(), getEditor(), getFile()); + checkResultByFile("/codeInsight/generateConstructor/after" + name +".java"); + } + private void doTest() throws Exception { String name = getTestName(false); configureByFile("/codeInsight/generateConstructor/before" + diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java index 1d6084f48763..ff8f2b8913e0 100644 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java @@ -226,7 +226,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myProject = project; myEditor = editor; - mySearchResults = new SearchResults(myEditor); + mySearchResults = new SearchResults(myEditor, myProject); myDefaultBackground = new JTextField().getBackground(); diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java index b4f147d91239..6bf025589d68 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java @@ -58,6 +58,7 @@ public class SearchResults implements DocumentListener { private Set myExcluded = new HashSet(); private Editor myEditor; + private Project myProject; private FindModel myFindModel; private int myMatchesLimit = 100; @@ -72,8 +73,9 @@ public class SearchResults implements DocumentListener { private Stack> myCursorPositions = new Stack>(); - public SearchResults(Editor editor) { + public SearchResults(Editor editor, Project project) { myEditor = editor; + myProject = project; myEditor.getDocument().addDocumentListener(this); } @@ -161,7 +163,7 @@ public class SearchResults implements DocumentListener { @Nullable public Project getProject() { - return myEditor.getProject(); + return myProject; } public synchronized void setEditor(Editor editor) { @@ -328,7 +330,7 @@ public class SearchResults implements DocumentListener { int offset = r.getStartOffset(); while (true) { - FindManager findManager = FindManager.getInstance(editor.getProject()); + FindManager findManager = FindManager.getInstance(getProject()); FindResult result; try { BombedCharSequence diff --git a/platform/lang-impl/src/com/intellij/ide/macro/FilePromptMacro.java b/platform/lang-impl/src/com/intellij/ide/macro/FilePromptMacro.java index a6096602a02e..7346a6865e00 100644 --- a/platform/lang-impl/src/com/intellij/ide/macro/FilePromptMacro.java +++ b/platform/lang-impl/src/com/intellij/ide/macro/FilePromptMacro.java @@ -29,7 +29,7 @@ import com.intellij.openapi.vfs.VirtualFile; /** * @author yole */ -public class FilePromptMacro extends Macro implements SecondQueueExpandMacro { +public class FilePromptMacro extends PromptingMacro implements SecondQueueExpandMacro { @Override public String getName() { return "FilePrompt"; @@ -40,16 +40,12 @@ public class FilePromptMacro extends Macro implements SecondQueueExpandMacro { return "Shows a file chooser dialog"; } - @Override - public String expand(DataContext dataContext) throws ExecutionCancelledException { + protected String promptUser(DataContext dataContext) { Project project = PlatformDataKeys.PROJECT.getData(dataContext); final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleLocalFileDescriptor(); final FileChooserDialog fileChooser = FileChooserFactory.getInstance().createFileChooser(descriptor, project); final VirtualFile[] result = fileChooser.choose(null, project); - if (result.length != 1) { - throw new ExecutionCancelledException(); - } - return FileUtil.toSystemDependentName(result [0].getPath()); + return result.length == 1? FileUtil.toSystemDependentName(result[0].getPath()) : null; } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/macro/MacroManager.java b/platform/lang-impl/src/com/intellij/ide/macro/MacroManager.java index 1cfccc09c07d..378ad9777bc3 100644 --- a/platform/lang-impl/src/com/intellij/ide/macro/MacroManager.java +++ b/platform/lang-impl/src/com/intellij/ide/macro/MacroManager.java @@ -158,14 +158,17 @@ public final class MacroManager { } public String expandSilentMarcos(String str, boolean firstQueueExpand, DataContext dataContext) throws Macro.ExecutionCancelledException { - return expandMacroSet(str, firstQueueExpand, dataContext, - ConvertingIterator.create(getMacros().iterator(), new Convertor() { - public Macro convert(Macro macro) { - if (macro instanceof PromptMacro) - return new Macro.Silent(macro, ""); - return macro; - } - })); + final Convertor convertor = new Convertor() { + public Macro convert(Macro macro) { + if (macro instanceof PromptingMacro) { + return new Macro.Silent(macro, ""); + } + return macro; + } + }; + return expandMacroSet( + str, firstQueueExpand, dataContext, ConvertingIterator.create(getMacros().iterator(), convertor) + ); } } diff --git a/platform/lang-impl/src/com/intellij/ide/macro/PromptMacro.java b/platform/lang-impl/src/com/intellij/ide/macro/PromptMacro.java index 5aa4eec96baa..4d3caab3f275 100644 --- a/platform/lang-impl/src/com/intellij/ide/macro/PromptMacro.java +++ b/platform/lang-impl/src/com/intellij/ide/macro/PromptMacro.java @@ -19,8 +19,9 @@ package com.intellij.ide.macro; import com.intellij.ide.IdeBundle; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.ui.Messages; +import org.jetbrains.annotations.Nullable; -public final class PromptMacro extends Macro implements SecondQueueExpandMacro { +public final class PromptMacro extends PromptingMacro implements SecondQueueExpandMacro { public String getName() { return "Prompt"; } @@ -29,11 +30,9 @@ public final class PromptMacro extends Macro implements SecondQueueExpandMacro { return IdeBundle.message("macro.prompt"); } - public String expand(DataContext dataContext) throws ExecutionCancelledException { - String userInput = Messages.showInputDialog(IdeBundle.message("prompt.enter.parameters"), - IdeBundle.message("title.input"), Messages.getQuestionIcon()); - if (userInput == null) throw new ExecutionCancelledException(); - return userInput; + @Nullable + protected String promptUser(DataContext dataContext) { + return Messages.showInputDialog(IdeBundle.message("prompt.enter.parameters"), IdeBundle.message("title.input"), Messages.getQuestionIcon()); } public void cachePreview(DataContext dataContext) { diff --git a/platform/lang-impl/src/com/intellij/ide/macro/PromptingMacro.java b/platform/lang-impl/src/com/intellij/ide/macro/PromptingMacro.java new file mode 100644 index 000000000000..41453dedcf68 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/macro/PromptingMacro.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.macro; + +import com.intellij.openapi.actionSystem.DataContext; +import org.jetbrains.annotations.Nullable; + +/** + * @author Eugene Zhuravlev + * Date: 12/9/11 + */ +public abstract class PromptingMacro extends Macro{ + + public final String expand(DataContext dataContext) throws ExecutionCancelledException { + final String userInput = promptUser(dataContext); + if (userInput == null) { + throw new ExecutionCancelledException(); + } + return userInput; + } + + + /** + * Called from expand() method + * + * @param dataContext + * @return user input. If null is returned, ExecutionCancelledException is thrown by expand() method + */ + @Nullable + protected abstract String promptUser(DataContext dataContext); +} diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index bd92a2f434ea..aa4dedba329e 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -290,10 +290,10 @@ dialog.edit.template.label.abbreviation=&Abbreviation: dialog.edit.template.label.group=&Group: dialog.edit.template.label.description=&Description: dialog.edit.template.options.title=Options -dialog.edit.template.label.expand.with=&Expand with +dialog.edit.template.label.expand.with=E&xpand with dialog.edit.template.checkbox.reformat.according.to.style=&Reformat according to style dialog.edit.template.checkbox.shorten.fq.names=Shorten &FQ names -dialog.edit.template.checkbox.use.static.import=Use static import if possible +dialog.edit.template.checkbox.use.static.import=Use static &import if possible dialog.edit.template.context.title=Context dialog.edit.template.checkbox.html=&HTML dialog.edit.template.checkbox.xml=&XML diff --git a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/CvsBundle.properties b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/CvsBundle.properties index 34267dfc644a..c3667c19fe9f 100644 --- a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/CvsBundle.properties +++ b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/CvsBundle.properties @@ -101,8 +101,7 @@ error.message.connection.already.open=Connection already open checkbox.text.use.internal.ssh.implementation=Use &internal ssh implementation dialog.title.select.path.to.external.rsh=Select Path to External Rsh dialog.title.select.path.to.ssh.private.key=Select Path to Ssh Private Key -dialog.title.select.path.to.cvs.client=Select Path to CVS Client -dialog.description.select.path.to.cvs.client=Select path to CVS client +dialog.title.select.path.to.cvs.client=Select path to CVS executable error.title.invalid.cvs.root=Invalid CVS Root error.message.timeout.error=Timeout error. error.dialog.title.timeout.error=Timeout Error @@ -347,6 +346,7 @@ command.name.rollback.file.creation=Rollback file creation border.title.update.options.other.settings=Other Settings border.title.update.options.updating.group=Updating border.title.ext.protocol.settings=Ext Protocol Settings +border.title.local.protocol.settings=Local Protocol Settings border.title.configure.ssh.private.key.file=Private Key File border.title.configure.ssh.ssh.version=SSH version border.title.configure.proxy.proxy.settings=Proxy Settings diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/config/ui/Cvs2SettingsEditPanel.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/config/ui/Cvs2SettingsEditPanel.java index 7fd2ad4598db..bdd8a1e53b60 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/config/ui/Cvs2SettingsEditPanel.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/config/ui/Cvs2SettingsEditPanel.java @@ -91,7 +91,7 @@ public class Cvs2SettingsEditPanel { myConnectionSettingsPanel.setLayout(new CardLayout()); myExtConnectionSettingsEditor = new ExtConnectionDualPanel(); mySshConnectionSettingsEditor = new SshConnectionSettingsPanel(); - myLocalConnectionSettingsPanel = new LocalConnectionSettingsPanel(); + myLocalConnectionSettingsPanel = new LocalConnectionSettingsPanel(project); myConnectionSettingsPanel.add(myExtConnectionSettingsEditor.getPanel(), CvsMethod.EXT_METHOD.getDisplayName()); myConnectionSettingsPanel.add(new JPanel(), CvsMethod.PSERVER_METHOD.getDisplayName()); myConnectionSettingsPanel.add(mySshConnectionSettingsEditor.getPanel(), CvsMethod.SSH_METHOD.getDisplayName()); @@ -121,7 +121,9 @@ public class Cvs2SettingsEditPanel { myProxySettingsPanel.add(myProxySettingsNonEmptyPanel.getPanel(), NON_EMPTY_PROXY_SETTINGS); myProxySettingsPanel.add(new JPanel(), EMPTY); - if (readOnly) setEnabled(myDateOrRevisionOrTagSettingsPanel, false); + if (readOnly) { + setEnabled(myDateOrRevisionOrTagSettingsPanel, false); + } } public void addCvsRootChangeListener(CvsRootChangeListener cvsRootChangeListener) { diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/connections/local/ui/LocalConnectionSettingsPanel.form b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/connections/local/ui/LocalConnectionSettingsPanel.form index 6c7518b6925e..e0a181a84a52 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/connections/local/ui/LocalConnectionSettingsPanel.form +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/connections/local/ui/LocalConnectionSettingsPanel.form @@ -6,7 +6,10 @@ - + + + + diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/connections/local/ui/LocalConnectionSettingsPanel.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/connections/local/ui/LocalConnectionSettingsPanel.java index 1850bf4e7840..81ab9c2fc40b 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/connections/local/ui/LocalConnectionSettingsPanel.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/connections/local/ui/LocalConnectionSettingsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package com.intellij.cvsSupport2.connections.local.ui; import com.intellij.CvsBundle; import com.intellij.cvsSupport2.config.LocalSettings; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import javax.swing.*; @@ -30,9 +31,8 @@ public class LocalConnectionSettingsPanel { private TextFieldWithBrowseButton myPathToCvsClient; private JPanel myPanel; - public LocalConnectionSettingsPanel() { - myPathToCvsClient.addBrowseFolderListener(CvsBundle.message("dialog.title.select.path.to.cvs.client"), - CvsBundle.message("dialog.description.select.path.to.cvs.client"), null, + public LocalConnectionSettingsPanel(Project project) { + myPathToCvsClient.addBrowseFolderListener(CvsBundle.message("dialog.title.select.path.to.cvs.client"), null, project, FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor()); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/ResolveUtil.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/ResolveUtil.java index d078d44f384b..4e69d9e00d0f 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/ResolveUtil.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/ResolveUtil.java @@ -15,6 +15,7 @@ */ package org.intellij.lang.xpath.psi.impl; +import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; @@ -35,6 +36,8 @@ import java.util.Collections; import java.util.List; public class ResolveUtil { + public static final Key> DEPENDENCIES = Key.create("XSLT_DEPENDENCIES"); + @SuppressWarnings({"unchecked"}) private final THashSet myHistory = new THashSet(TObjectHashingStrategy.IDENTITY); diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java index 481d294a860c..31edc71120f9 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/psi/impl/XPathFunctionCallImpl.java @@ -145,8 +145,7 @@ public class XPathFunctionCallImpl extends XPathElementImpl implements XPathFunc if (name == null) return null; final Function functionDecl = contextProvider.getFunctionContext().resolve(name, getArgumentList().length); - - final XPathFunction impl = functionDecl instanceof XPathFunction ? (XPathFunction)functionDecl : new FunctionImpl(functionDecl); + final XPathFunction impl = functionDecl == null ? null : functionDecl instanceof XPathFunction ? (XPathFunction)functionDecl : new FunctionImpl(functionDecl); return (myFunction = Pair.create(getQName().toString(), impl)).second; } } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/Xslt2ContextProvider.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/Xslt2ContextProvider.java index 219b5dc03b0a..054adb037e8a 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/Xslt2ContextProvider.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/context/Xslt2ContextProvider.java @@ -15,11 +15,19 @@ */ package org.intellij.lang.xpath.xslt.context; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.UserDataCache; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.ParameterizedCachedValue; +import com.intellij.psi.util.ParameterizedCachedValueProvider; import com.intellij.psi.xml.XmlElement; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; +import com.intellij.util.ArrayUtil; +import com.intellij.util.SmartList; import org.apache.commons.collections.map.CompositeMap; import org.intellij.lang.xpath.context.ContextType; import org.intellij.lang.xpath.context.XPathVersion; @@ -27,21 +35,25 @@ import org.intellij.lang.xpath.context.functions.Function; import org.intellij.lang.xpath.context.functions.FunctionContext; import org.intellij.lang.xpath.psi.XPath2Type; import org.intellij.lang.xpath.psi.XPathType; +import org.intellij.lang.xpath.psi.impl.ResolveUtil; import org.intellij.lang.xpath.xslt.XsltSupport; import org.intellij.lang.xpath.xslt.psi.XsltElementFactory; import org.intellij.lang.xpath.xslt.psi.XsltFunction; -import org.intellij.lang.xpath.xslt.util.QNameUtil; +import org.intellij.lang.xpath.xslt.psi.XsltStylesheet; import org.intellij.lang.xpath.xslt.util.XsltCodeInsightUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.xml.namespace.QName; import java.util.HashMap; +import java.util.List; import java.util.Map; public class Xslt2ContextProvider extends XsltContextProviderBase { public static final ContextType TYPE = ContextType.lookupOrCreate("XSLT2", XPathVersion.V2); + private static final Key,Function>,XmlFile>> FUNCTIONS = Key.create("XSLT_FUNCTIONS"); + protected Xslt2ContextProvider(@NotNull XmlElement contextElement) { super(contextElement); } @@ -115,45 +127,57 @@ public class Xslt2ContextProvider extends XsltContextProviderBase { Xslt2FunctionContext.getInstance(); } - private static Map, Function> getCustomFunctions(XmlFile file) { - final XmlTag rootTag = file.getRootTag(); - assert rootTag != null; - - final XmlTag[] functionTags = rootTag.findSubTags("function", XsltSupport.XSLT_NS); - - final Map, Function> candidates = new HashMap, Function>(); - for (XmlTag tag : functionTags) { - final String n = tag.getAttributeValue("name"); - if (n == null) continue; - - final XsltFunction f = XsltElementFactory.getInstance().wrapElement(tag, XsltFunction.class); - candidates.put(Pair.create(f.getQName(), f.getParameters().length), f); + private static final UserDataCache,Function>,XmlFile>, XmlFile, Void> ourFunctionCacheProvider = + new UserDataCache,Function>,XmlFile>, XmlFile, Void>() { + @Override + protected ParameterizedCachedValue,Function>,XmlFile> compute(XmlFile file, Void p) { + return CachedValuesManager.getManager(file.getProject()).createParameterizedCachedValue(MyFunctionProvider.INSTANCE, false); } - return candidates; + }; + + private static Map, Function> getCustomFunctions(XmlFile file) { + return ourFunctionCacheProvider.get(FUNCTIONS, file, null).getValue(file); } @Nullable private static Function resolveCustomFunction(final XmlFile file, final QName name, int argCount) { - final XmlTag rootTag = file.getRootTag(); - assert rootTag != null; - - final XmlTag[] functionTags = rootTag.findSubTags("function", XsltSupport.XSLT_NS); - - XsltFunction candidate = null; - for (XmlTag tag : functionTags) { - final String n = tag.getAttributeValue("name"); - if (n == null) continue; - - final QName fName = QNameUtil.createQName(n, tag); - if (fName.equals(name)) { - candidate = XsltElementFactory.getInstance().wrapElement(tag, XsltFunction.class); - - if (candidate.getParameters().length == argCount) { // TODO: overrride=[yes|no] - return candidate; - } - } + final Map, Function> functions = getCustomFunctions(file); + final Function exactMatch = functions.get(Pair.create(name, argCount)); + if (exactMatch != null) { + return exactMatch; } + Function candidate = null; + for (Pair pair : functions.keySet()) { + if (pair.getFirst().equals(name)) { + candidate = functions.get(pair); + } + } return candidate; } + + private static class MyFunctionProvider implements ParameterizedCachedValueProvider, Function>, XmlFile> { + private static ParameterizedCachedValueProvider,Function>,XmlFile> INSTANCE = new MyFunctionProvider(); + + @Override + public CachedValueProvider.Result, Function>> compute(XmlFile param) { + final XmlTag rootTag = param.getRootTag(); + assert rootTag != null; + + final Map, Function> candidates = new HashMap, Function>(); + final XsltFunction[] functions = XsltElementFactory.getInstance().wrapElement(rootTag, XsltStylesheet.class).getFunctions(); + for (XsltFunction function : functions) { + candidates.put(Pair.create(function.getQName(), function.getParameters().length), function); + } + + List data = param.getUserData(ResolveUtil.DEPENDENCIES); + if (data == null) { + data = new SmartList(param); + } else { + data.add(param); + param.putUserData(ResolveUtil.DEPENDENCIES, null); + } + return CachedValueProvider.Result.create(candidates, ArrayUtil.toObjectArray(data)); + } + } } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/psi/XsltStylesheet.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/psi/XsltStylesheet.java index 17c911283a40..b9ee44860ec7 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/psi/XsltStylesheet.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/psi/XsltStylesheet.java @@ -18,7 +18,8 @@ package org.intellij.lang.xpath.xslt.psi; import org.jetbrains.annotations.NotNull; public interface XsltStylesheet extends XsltElement { - @NotNull + + @NotNull XsltParameter[] getParameters(); /** @@ -29,4 +30,7 @@ public interface XsltStylesheet extends XsltElement { @NotNull XsltTemplate[] getTemplates(); + + @NotNull + XsltFunction[] getFunctions(); } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/psi/impl/XsltStylesheetImpl.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/psi/impl/XsltStylesheetImpl.java index b83fad2c9972..ef100b8908b5 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/psi/impl/XsltStylesheetImpl.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/psi/impl/XsltStylesheetImpl.java @@ -15,47 +15,70 @@ */ package org.intellij.lang.xpath.xslt.psi.impl; -import org.intellij.lang.xpath.psi.impl.ResolveUtil; -import org.intellij.lang.xpath.xslt.psi.XsltParameter; -import org.intellij.lang.xpath.xslt.psi.XsltStylesheet; -import org.intellij.lang.xpath.xslt.psi.XsltTemplate; -import org.intellij.lang.xpath.xslt.psi.XsltVariable; -import org.intellij.lang.xpath.xslt.util.ParamMatcher; -import org.intellij.lang.xpath.xslt.util.TemplateMatcher; -import org.intellij.lang.xpath.xslt.XsltSupport; - import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlTag; +import org.intellij.lang.xpath.psi.impl.ResolveUtil; +import org.intellij.lang.xpath.xslt.XsltSupport; +import org.intellij.lang.xpath.xslt.psi.*; +import org.intellij.lang.xpath.xslt.util.IncludeAwareMatcher; +import org.intellij.lang.xpath.xslt.util.ParamMatcher; +import org.intellij.lang.xpath.xslt.util.TemplateMatcher; import org.jetbrains.annotations.NotNull; public class XsltStylesheetImpl extends XsltElementImpl implements XsltStylesheet { - public XsltStylesheetImpl(XmlTag target) { - super(target); + + public XsltStylesheetImpl(XmlTag target) { + super(target); + } + + @NotNull + public XsltParameter[] getParameters() { + return convertArray(ResolveUtil.collect(new ParamMatcher(getTag(), null)), XsltParameter.class); + } + + @NotNull + public XsltVariable[] getVariables() { + return convertArray(ResolveUtil.collect(new ParamMatcher(getTag(), null) { + protected boolean isApplicable(XmlTag tag) { + return XsltSupport.isVariable(tag); + } + }), XsltVariable.class); + } + + @NotNull + public XsltTemplate[] getTemplates() { + final XmlDocument document = PsiTreeUtil.getParentOfType(getTag(), XmlDocument.class); + return convertArray(ResolveUtil.collect(new TemplateMatcher(document)), XsltTemplate.class); + } + + @NotNull + @Override + public XsltFunction[] getFunctions() { + final XmlDocument document = PsiTreeUtil.getParentOfType(getTag(), XmlDocument.class); + return convertArray(ResolveUtil.collect(new FunctionMatcher(document)), XsltFunction.class); + } + + @Override + public String toString() { + return "XsltStylesheet"; + } + + private class FunctionMatcher extends IncludeAwareMatcher { + public FunctionMatcher(XmlDocument document) { + super(document); } - @NotNull - public XsltParameter[] getParameters() { - return convertArray(ResolveUtil.collect(new ParamMatcher(getTag(), null)), XsltParameter.class); + protected boolean matches(XmlTag element) { + return XsltSupport.isFunction(element); } - @NotNull - public XsltVariable[] getVariables() { - return convertArray(ResolveUtil.collect(new ParamMatcher(getTag(), null) { - protected boolean isApplicable(XmlTag tag) { - return XsltSupport.isVariable(tag); - } - }), XsltVariable.class); + protected ResolveUtil.Matcher changeDocument(XmlDocument document) { + return new FunctionMatcher(document); } - @NotNull - public XsltTemplate[] getTemplates() { - final XmlDocument document = PsiTreeUtil.getParentOfType(getTag(), XmlDocument.class); - return convertArray(ResolveUtil.collect(new TemplateMatcher(document)), XsltTemplate.class); - } - - @Override - public String toString() { - return "XsltStylesheet"; + public ResolveUtil.Matcher variantMatcher() { + return new FunctionMatcher(myDocument); } + } } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/util/IncludeAwareMatcher.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/util/IncludeAwareMatcher.java index 69639ce9a6f6..e29e6e4004f7 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/util/IncludeAwareMatcher.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/util/IncludeAwareMatcher.java @@ -15,6 +15,8 @@ */ package org.intellij.lang.xpath.xslt.util; +import com.intellij.psi.PsiElement; +import com.intellij.util.SmartList; import org.intellij.lang.xpath.psi.impl.ResolveUtil; import org.intellij.lang.xpath.xslt.XsltSupport; @@ -25,6 +27,8 @@ import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.Nullable; +import java.util.List; + public abstract class IncludeAwareMatcher extends BaseMatcher { protected final XmlDocument myDocument; @@ -49,7 +53,15 @@ public abstract class IncludeAwareMatcher extends BaseMatcher { final PsiFile file = ResolveUtil.resolveFile(href, f); if (file instanceof XmlFile) { - return Result.create(changeDocument(((XmlFile)file).getDocument())); + + final List data = myDocument.getContainingFile().getUserData(ResolveUtil.DEPENDENCIES); + if (data == null) { + myDocument.getContainingFile().putUserData(ResolveUtil.DEPENDENCIES, new SmartList(file)); + } else if (!data.contains(file)) { + data.add(file); + } + + return Result.create(changeDocument(((XmlFile)file).getDocument())); } } } else { diff --git a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java index 642d7f279dc9..e0234af216c8 100644 --- a/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java +++ b/plugins/xpath/xpath-lang/test/org/intellij/lang/xpath/xslt/XsltResolveTest.java @@ -15,19 +15,17 @@ */ package org.intellij.lang.xpath.xslt; -import org.intellij.lang.xpath.TestBase; -import org.intellij.lang.xpath.psi.XPathVariableReference; -import org.intellij.lang.xpath.xslt.psi.XsltElement; -import org.intellij.lang.xpath.xslt.psi.XsltParameter; -import org.intellij.lang.xpath.xslt.psi.XsltTemplate; -import org.intellij.lang.xpath.xslt.psi.XsltVariable; -import org.intellij.lang.xpath.xslt.util.XsltCodeInsightUtil; - import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.PsiReference; import com.intellij.psi.ResolveResult; +import com.intellij.util.ArrayUtil; +import org.intellij.lang.xpath.TestBase; +import org.intellij.lang.xpath.psi.XPathFunctionCall; +import org.intellij.lang.xpath.psi.XPathVariableReference; +import org.intellij.lang.xpath.xslt.psi.*; +import org.intellij.lang.xpath.xslt.util.XsltCodeInsightUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,6 +48,14 @@ public class XsltResolveTest extends TestBase { doVariableResolveTest(false); } + public void testResolveIncludedFunction() throws Throwable { + doFunctionResolveTest("included-2.xsl"); + } + + public void testResolveFunction() throws Throwable { + doFunctionResolveTest(); + } + public void testResolveSameName() throws Throwable { final XsltVariable variable = doVariableResolveTest(false); @@ -99,9 +105,22 @@ public class XsltResolveTest extends TestBase { return var; } + private XsltFunction doFunctionResolveTest(String... files) throws Throwable { + final PsiReference reference = findInjectedReferenceAtCaret(files); + + final PsiElement element = reference.resolve(); + assertTrue(element instanceof XsltFunction); + + final XsltFunction func = (XsltFunction)element; + final XPathFunctionCall call = (XPathFunctionCall)reference.getElement(); + assertEquals(func.getName(), call.getFunctionName()); + assertEquals(func.getParameters().length, call.getArgumentList().length); + return func; + } + @NotNull - private PsiReference findInjectedReferenceAtCaret() throws Throwable { - configure(); + private PsiReference findInjectedReferenceAtCaret(String... moreFiles) throws Throwable { + configure(moreFiles); final InjectedLanguageManager manager = InjectedLanguageManager.getInstance(myFixture.getProject()); final PsiElement e = manager.findInjectedElementAt(myFixture.getFile(), myFixture.getEditor().getCaretModel().getOffset()); @@ -112,8 +131,8 @@ public class XsltResolveTest extends TestBase { return reference; } - private void configure() throws Throwable { - myFixture.configureByFile(getTestFileName() + ".xsl"); + private void configure(String... moreFiles) throws Throwable { + myFixture.configureByFiles(ArrayUtil.mergeArrays(new String[]{getTestFileName() + ".xsl"}, moreFiles)); } @Override diff --git a/plugins/xpath/xpath-lang/testData/xslt/resolve/included-2.xsl b/plugins/xpath/xpath-lang/testData/xslt/resolve/included-2.xsl new file mode 100644 index 000000000000..4f2185f4e603 --- /dev/null +++ b/plugins/xpath/xpath-lang/testData/xslt/resolve/included-2.xsl @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/plugins/xpath/xpath-lang/testData/xslt/resolve/resolveFunction.xsl b/plugins/xpath/xpath-lang/testData/xslt/resolve/resolveFunction.xsl new file mode 100644 index 000000000000..61729b08ae76 --- /dev/null +++ b/plugins/xpath/xpath-lang/testData/xslt/resolve/resolveFunction.xsl @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/plugins/xpath/xpath-lang/testData/xslt/resolve/resolveIncludedFunction.xsl b/plugins/xpath/xpath-lang/testData/xslt/resolve/resolveIncludedFunction.xsl new file mode 100644 index 000000000000..6d87f392cf90 --- /dev/null +++ b/plugins/xpath/xpath-lang/testData/xslt/resolve/resolveIncludedFunction.xsl @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/plugins/xslt-debugger/engine/impl/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9StyleFrame.java b/plugins/xslt-debugger/engine/impl/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9StyleFrame.java index 26f61a84ff6a..0f32e4257f61 100644 --- a/plugins/xslt-debugger/engine/impl/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9StyleFrame.java +++ b/plugins/xslt-debugger/engine/impl/src/org/intellij/plugins/xsltDebugger/rt/engine/local/saxon9/Saxon9StyleFrame.java @@ -21,17 +21,20 @@ import net.sf.saxon.expr.instruct.GeneralVariable; import net.sf.saxon.expr.instruct.GlobalVariable; import net.sf.saxon.expr.instruct.LocalVariable; import net.sf.saxon.expr.instruct.SlotManager; +import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.om.*; import net.sf.saxon.style.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; +import net.sf.saxon.value.SequenceType; import org.intellij.plugins.xsltDebugger.rt.engine.Debugger; import org.intellij.plugins.xsltDebugger.rt.engine.Value; import org.intellij.plugins.xsltDebugger.rt.engine.local.VariableImpl; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -186,12 +189,10 @@ class Saxon9StyleFrame extends AbstractSaxon9Frame extends AbstractSaxon9Frame extends AbstractSaxon9Frame extends AbstractSaxon9Frame getVariables() { return getPrevious().getVariables(); } @@ -133,26 +130,21 @@ public class Saxon9TraceListener implements TraceListener { myInstruction = instr; } - @Override public void setSystemId(String systemId) { } - @Override public String getPublicId() { return null; } - @Override public String getSystemId() { return myInstruction.getSystemId(); } - @Override public int getLineNumber() { return myInstruction.getLineNumber(); } - @Override public int getColumnNumber() { return myInstruction.getColumnNumber(); } diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java index 4867c1b25173..c436629dc6dc 100644 --- a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java +++ b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/impl/XsltStackFrame.java @@ -33,7 +33,7 @@ public class XsltStackFrame extends XStackFrame { @Override public Object getEqualityObject() { - return super.getEqualityObject(); + return XsltStackFrame.class; } @Override