diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index a4dc856755bd..1341b8ff8c69 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -254,9 +254,6 @@ public class BuildManager implements ApplicationComponent{ if (!eventFile.isValid()) { return true; // should be deleted } - if (ProjectCoreUtil.isProjectOrWorkspaceFile(eventFile)) { - continue; - } if (project == null) { // lazy init @@ -268,6 +265,10 @@ public class BuildManager implements ApplicationComponent{ } if (fileIndex.isInContent(eventFile)) { + if (ProjectCoreUtil.isProjectOrWorkspaceFile(eventFile)) { + continue; + } + return true; } } @@ -387,9 +388,9 @@ public class BuildManager implements ApplicationComponent{ public void clearState(Project project) { final String projectPath = getProjectPath(project); - + cancelPreloadedBuilds(projectPath); - + synchronized (myProjectDataMap) { final ProjectData data = myProjectDataMap.get(projectPath); if (data != null) { @@ -823,7 +824,7 @@ public class BuildManager implements ApplicationComponent{ private Future, OSProcessHandler>> launchPreloadedBuildProcess(final Project project, SequentialTaskExecutor projectTaskQueue) throws Exception { ensureListening(); - + // launching build process from projectTaskQueue ensures that no other build process for this project is currently running return projectTaskQueue.submit(new Callable, OSProcessHandler>>() { public Pair, OSProcessHandler> call() throws Exception { @@ -845,7 +846,7 @@ public class BuildManager implements ApplicationComponent{ } }); } - + private OSProcessHandler launchBuildProcess(Project project, final int port, final UUID sessionId, boolean requestProjectPreload) throws ExecutionException { final String compilerPath; final String vmExecutablePath; @@ -951,7 +952,7 @@ public class BuildManager implements ApplicationComponent{ cmdLine.addParameter("-Dpreload.project.path=" + FileUtil.toCanonicalPath(getProjectPath(project))); cmdLine.addParameter("-Dpreload.config.path=" + FileUtil.toCanonicalPath(PathManager.getOptionsPath())); } - + final String shouldGenerateIndex = System.getProperty(GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION); if (shouldGenerateIndex != null) { cmdLine.addParameter("-D"+ GlobalOptions.GENERATE_CLASSPATH_INDEX_OPTION +"=" + shouldGenerateIndex); @@ -975,11 +976,11 @@ public class BuildManager implements ApplicationComponent{ cmdLine.addParameter(option); } } - + if (isProfilingMode) { cmdLine.addParameter("-agentlib:yjpagent=disablej2ee,disablealloc,delay=10000,sessionname=ExternalBuild"); } - + // debugging final int debugPort = Registry.intValue("compiler.process.debug.port"); if (debugPort > 0) { @@ -1016,10 +1017,10 @@ public class BuildManager implements ApplicationComponent{ final List args = provider.getVMArguments(); cmdLine.addParameters(args); } - - @SuppressWarnings("UnnecessaryFullyQualifiedName") + + @SuppressWarnings("UnnecessaryFullyQualifiedName") final Class launcherClass = org.jetbrains.jps.cmdline.Launcher.class; - + final List launcherCp = new ArrayList(); launcherCp.add(ClasspathBootstrap.getResourcePath(launcherClass)); launcherCp.add(compilerPath); @@ -1027,7 +1028,7 @@ public class BuildManager implements ApplicationComponent{ launcherCp.addAll(BuildProcessClasspathManager.getLauncherClasspath(project)); cmdLine.addParameter("-classpath"); cmdLine.addParameter(classpathToString(launcherCp)); - + cmdLine.addParameter(launcherClass.getName()); final List cp = ClasspathBootstrap.getBuildProcessApplicationClasspath(true); @@ -1064,7 +1065,7 @@ public class BuildManager implements ApplicationComponent{ } } }); - + return processHandler; } @@ -1239,7 +1240,7 @@ public class BuildManager implements ApplicationComponent{ @Override public void onTextAvailable(ProcessEvent event, Key outputType) { String text; - + synchronized (this) { if (myStoredLength > 2048) { return; @@ -1250,7 +1251,7 @@ public class BuildManager implements ApplicationComponent{ } myStoredLength += text.length(); } - + try { myOutput.append(text); } @@ -1454,7 +1455,7 @@ public class BuildManager implements ApplicationComponent{ } myPath = list.toArray(); } - + public abstract String getValue(); @Override @@ -1473,12 +1474,12 @@ public class BuildManager implements ApplicationComponent{ public int hashCode() { return Arrays.hashCode(myPath); } - + public static InternedPath create(String path) { - return path.startsWith("/")? new XInternedPath(path) : new WinInternedPath(path); + return path.startsWith("/")? new XInternedPath(path) : new WinInternedPath(path); } } - + private static class WinInternedPath extends InternedPath { private WinInternedPath(String path) { super(path); @@ -1491,7 +1492,7 @@ public class BuildManager implements ApplicationComponent{ // handle case of windows drive letter return name.length() == 2 && name.endsWith(":")? name + "/" : name; } - + final StringBuilder buf = new StringBuilder(); for (int element : myPath) { if (buf.length() > 0) { diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java index 6214a9e44d7f..a36bc9ace4aa 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/CustomizeContextViewAction.java @@ -29,7 +29,6 @@ import com.intellij.openapi.options.TabbedConfigurable; import com.intellij.openapi.options.ex.SingleConfigurableEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; -import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase; @@ -88,13 +87,15 @@ public class CustomizeContextViewAction extends XDebuggerTreeActionBase { @Override public void update(AnActionEvent e) { - final XDebuggerManager debuggerManager = XDebuggerManager.getInstance(getEventProject(e)); - final XDebugSession currentSession = debuggerManager.getCurrentSession(); - if (currentSession != null) { - final XDebugProcess process = currentSession.getDebugProcess(); - e.getPresentation().setVisible(process instanceof JavaDebugProcess); - e.getPresentation().setEnabled(process instanceof JavaDebugProcess); - e.getPresentation().setText(ActionsBundle.actionText(DebuggerActions.CUSTOMIZE_VIEWS)); + e.getPresentation().setText(ActionsBundle.actionText(DebuggerActions.CUSTOMIZE_VIEWS)); + Project project = getEventProject(e); + if (project != null) { + final XDebugSession currentSession = XDebuggerManager.getInstance(project).getCurrentSession(); + if (currentSession != null) { + e.getPresentation().setEnabledAndVisible(currentSession.getDebugProcess() instanceof JavaDebugProcess); + return; + } } + e.getPresentation().setEnabledAndVisible(false); } } diff --git a/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java b/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java index 846e1fd5d0ee..38c0cf4abbf4 100644 --- a/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java +++ b/java/java-analysis-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesFinder.java @@ -97,7 +97,18 @@ public class DuplicatesFinder { } + public InputVariables getParameters() { + return myParameters; + } + public PsiElement[] getPattern() { + return myPattern; + } + + @Nullable + public ReturnValue getReturnValue() { + return myReturnValue; + } public List findDuplicates(PsiElement scope) { annotatePattern(); @@ -164,9 +175,7 @@ public class DuplicatesFinder { @Nullable private Match isDuplicateFragment(PsiElement candidate, boolean ignoreParameterTypesAndPostVariableUsages) { - for (PsiElement pattern : myPattern) { - if (PsiTreeUtil.isAncestor(pattern, candidate, false)) return null; - } + if (isSelf(candidate)) return null; PsiElement sibling = candidate; ArrayList candidates = new ArrayList(); for (final PsiElement element : myPattern) { @@ -206,6 +215,15 @@ public class DuplicatesFinder { return match; } + protected boolean isSelf(PsiElement candidate) { + for (PsiElement pattern : myPattern) { + if (PsiTreeUtil.isAncestor(pattern, candidate, false)) { + return true; + } + } + return false; + } + private boolean checkPostVariableUsages(final ArrayList candidates, final Match match) { final PsiElement codeFragment = ControlFlowUtil.findCodeFragment(candidates.get(0)); try { diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java index 8ed37ceb01a4..0044c599a851 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/TryStatementPostfixTemplate.java @@ -16,37 +16,41 @@ package com.intellij.codeInsight.template.postfix.templates; import com.intellij.codeInsight.generation.surroundWith.JavaWithTryCatchSurrounder; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import static com.intellij.codeInsight.template.postfix.templates.PostfixTemplatesUtils.selectorTopmost; -import static com.intellij.codeInsight.template.postfix.util.JavaPostfixTemplatesUtils.JAVA_PSI_INFO; - -public class TryStatementPostfixTemplate extends PostfixTemplateWithExpressionSelector { - - public static Condition HAS_TYPE = new Condition() { - @Override - public boolean value(@Nullable PsiElement element) { - return element instanceof PsiExpression && ((PsiExpression)element).getType() != null; - } - }; +public class TryStatementPostfixTemplate extends PostfixTemplate { protected TryStatementPostfixTemplate() { - super("try", "try { exp } catch(Exception e)", JAVA_PSI_INFO, selectorTopmost(HAS_TYPE)); + super("try", "try { exp } catch(Exception e)"); } + @Override + public boolean isApplicable(@NotNull PsiElement context, @NotNull Document copyDocument, int newOffset) { + PsiStatement statementParent = PsiTreeUtil.getNonStrictParentOfType(context, PsiStatement.class); + if (statementParent == null || + newOffset != statementParent.getTextRange().getEndOffset()) return false; + + if (statementParent instanceof PsiDeclarationStatement) return true; + + if (statementParent instanceof PsiExpressionStatement) { + PsiExpression expression = ((PsiExpressionStatement)statementParent).getExpression(); + return null != expression.getType(); + } + + return false; + } @Override - public void expandForChooseExpression(@NotNull PsiElement context, @NotNull Editor editor) { - PsiExpression expr = (PsiExpression)context; - PsiStatement statement = PsiTreeUtil.getParentOfType(expr, PsiStatement.class, false); + public void expand(@NotNull PsiElement context, @NotNull Editor editor) { + PsiStatement statement = PsiTreeUtil.getNonStrictParentOfType(context, PsiStatement.class); assert statement != null; PsiFile file = statement.getContainingFile(); diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java b/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java index f37d74bf9f72..fbf3b77ddf20 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java @@ -41,8 +41,6 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings { public static final int FULLY_QUALIFY_NAMES_ALWAYS = 2; public static final int SHORTEN_NAMES_ALWAYS_AND_ADD_IMPORT = 3; - public boolean LEGACY_SETTING_USE_FQ_CLASS_NAMES_IN_JAVADOC_IMPORTED = false; - public int CLASS_NAMES_IN_JAVADOC = FULLY_QUALIFY_NAMES_IF_NOT_IMPORTED; public boolean useFqNamesInJavadocAlways() { @@ -51,12 +49,15 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings { @Override public void importLegacySettings() { - if (!LEGACY_SETTING_USE_FQ_CLASS_NAMES_IN_JAVADOC_IMPORTED) { - CodeStyleSettings settings = getContainer(); - if (!settings.USE_FQ_CLASS_NAMES_IN_JAVADOC) { - CLASS_NAMES_IN_JAVADOC = SHORTEN_NAMES_ALWAYS_AND_ADD_IMPORT; - } - LEGACY_SETTING_USE_FQ_CLASS_NAMES_IN_JAVADOC_IMPORTED = true; + importLegacyUseFqClassNamesInJavadocSetting(); + } + + private void importLegacyUseFqClassNamesInJavadocSetting() { + CodeStyleSettings settings = getContainer(); + boolean isDefaultValue = settings.USE_FQ_CLASS_NAMES_IN_JAVADOC; + if (!isDefaultValue) { + CLASS_NAMES_IN_JAVADOC = SHORTEN_NAMES_ALWAYS_AND_ADD_IMPORT; + settings.USE_FQ_CLASS_NAMES_IN_JAVADOC = true; } } } diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index ba4c2471c7ce..3af0c948d209 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -47,7 +47,10 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.WindowManager; import com.intellij.psi.*; -import com.intellij.psi.codeStyle.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.controlFlow.ControlFlowUtil; import com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl; import com.intellij.psi.scope.processor.VariablesProcessor; @@ -725,6 +728,11 @@ public class ExtractMethodProcessor implements MatchProvider { myVariableDatum[i].passAsParameter = false; } + @TestOnly + public void changeParamName(int i, String param) { + myVariableDatum[i].name = param; + } + /** * Invoked in command and in atomic action */ @@ -783,6 +791,7 @@ public class ExtractMethodProcessor implements MatchProvider { } } + @Nullable private DuplicatesFinder initDuplicates() { List elements = new ArrayList(); for (PsiElement element : myElements) { @@ -1239,7 +1248,10 @@ public class ExtractMethodProcessor implements MatchProvider { } private void renameInputVariables() throws IncorrectOperationException { - for (VariableData data : myVariableDatum) { + //when multiple input variables should have the same name, unique names are generated + //without reverse, the second rename would rename variable without a prefix into second one though it was already renamed + for (int i = myVariableDatum.length - 1; i >= 0; i--) { + VariableData data = myVariableDatum[i]; PsiVariable variable = data.variable; if (!data.name.equals(variable.getName())) { for (PsiElement element : myElements) { @@ -1659,18 +1671,33 @@ public class ExtractMethodProcessor implements MatchProvider { return myExtractedMethod; } - public boolean hasDuplicates() { - final List duplicates = getDuplicates(); - return duplicates != null && !duplicates.isEmpty(); + public Boolean hasDuplicates() { + List duplicates = getDuplicates(); + if (duplicates != null && !duplicates.isEmpty()) { + return true; + } + final ExtractMethodSignatureSuggester suggester = new ExtractMethodSignatureSuggester(myProject, myExtractedMethod, myMethodCall, myVariableDatum); + duplicates = suggester.getDuplicates(myExtractedMethod, myMethodCall); + if (duplicates != null && !duplicates.isEmpty()) { + myDuplicates = duplicates; + myExtractedMethod = suggester.getExtractedMethod(); + myMethodCall = suggester.getMethodCall(); + myVariableDatum = suggester.getVariableData(); + return null; + } + return false; } public boolean hasDuplicates(Set files) { final DuplicatesFinder finder = initDuplicates(); - if (hasDuplicates()) return true; - final PsiManager psiManager = PsiManager.getInstance(myProject); - for (VirtualFile file : files) { - if (!finder.findDuplicates(psiManager.findFile(file)).isEmpty()) return true; + final Boolean hasDuplicates = hasDuplicates(); + if (hasDuplicates == null || hasDuplicates) return true; + if (finder != null) { + final PsiManager psiManager = PsiManager.getInstance(myProject); + for (VirtualFile file : files) { + if (!finder.findDuplicates(psiManager.findFile(file)).isEmpty()) return true; + } } return false; } diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodSignatureSuggester.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodSignatureSuggester.java new file mode 100644 index 000000000000..eecedb1f4f4f --- /dev/null +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodSignatureSuggester.java @@ -0,0 +1,328 @@ +/* + * Copyright 2000-2014 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.refactoring.extractMethod; + +import com.intellij.codeInsight.JavaPsiEquivalenceUtil; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.SuggestedNameInfo; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.refactoring.util.VariableData; +import com.intellij.refactoring.util.duplicates.DuplicatesFinder; +import com.intellij.refactoring.util.duplicates.Match; +import com.intellij.refactoring.util.duplicates.MethodDuplicatesHandler; +import com.intellij.util.text.UniqueNameGenerator; +import gnu.trove.THashMap; +import gnu.trove.THashSet; +import gnu.trove.TObjectHashingStrategy; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class ExtractMethodSignatureSuggester { + private static final Logger LOG = Logger.getInstance("#" + ExtractMethodSignatureSuggester.class.getName()); + private static final TObjectHashingStrategy ourEquivalenceStrategy = new TObjectHashingStrategy() { + @Override + public int computeHashCode(PsiExpression object) { + return RefactoringUtil.unparenthesizeExpression(object).getClass().hashCode(); + } + + @Override + public boolean equals(PsiExpression o1, PsiExpression o2) { + return JavaPsiEquivalenceUtil + .areExpressionsEquivalent(RefactoringUtil.unparenthesizeExpression(o1), RefactoringUtil.unparenthesizeExpression(o2)); + } + }; + + private Project myProject; + private PsiElementFactory myElementFactory; + + private PsiMethod myExtractedMethod; + private PsiMethodCallExpression myMethodCall; + private VariableData[] myVariableData; + + public ExtractMethodSignatureSuggester(Project project, + PsiMethod extractedMethod, + PsiMethodCallExpression methodCall, + VariableData[] variableDatum) { + myProject = project; + myElementFactory = JavaPsiFacade.getElementFactory(project); + + myExtractedMethod = (PsiMethod)extractedMethod.copy(); + myMethodCall = methodCall; + myVariableData = variableDatum; + } + + public List getDuplicates(final PsiMethod method, final PsiMethodCallExpression methodCall) { + final List duplicates = findDuplicatesSignature(method); + if (duplicates != null && !duplicates.isEmpty()) { + if (ApplicationManager.getApplication().isUnitTestMode() || + Messages.showYesNoDialog(myProject, "No exact duplicates found.\nWould you like to apply suggested changes to replace " + duplicates.size() + " duplicates?", "Extract Parameters to Replace Duplicates", + Messages.getQuestionIcon()) == Messages.YES) { + WriteCommandAction.runWriteCommandAction(myProject, new Runnable() { + @Override + public void run() { + myMethodCall = (PsiMethodCallExpression)methodCall.replace(myMethodCall); + myExtractedMethod = (PsiMethod)method.replace(myExtractedMethod); + } + }); + + final DuplicatesFinder finder = MethodDuplicatesHandler.createDuplicatesFinder(myExtractedMethod); + if (finder != null) { + final List datas = finder.getParameters().getInputVariables(); + myVariableData = datas.toArray(new VariableData[datas.size()]); + return finder.findDuplicates(myExtractedMethod.getContainingClass()); + } + } + } + return null; + } + + + public PsiMethod getExtractedMethod() { + return myExtractedMethod; + } + + public PsiMethodCallExpression getMethodCall() { + return myMethodCall; + } + + public VariableData[] getVariableData() { + return myVariableData; + } + + @Nullable + public List findDuplicatesSignature(final PsiMethod method) { + final List copies = new ArrayList(); + final InputVariables variables = detectTopLevelExpressionsToReplaceWithParameters(copies); + if (variables == null) { + return null; + } + + final DuplicatesFinder defaultFinder = MethodDuplicatesHandler.createDuplicatesFinder(myExtractedMethod); + if (defaultFinder == null) { + return null; + } + + final DuplicatesFinder finder = new DuplicatesFinder(defaultFinder.getPattern(), variables, defaultFinder.getReturnValue(), new ArrayList()) { + @Override + protected boolean isSelf(PsiElement candidate) { + return PsiTreeUtil.isAncestor(method, candidate, true); + } + }; + List duplicates = finder.findDuplicates(method.getContainingClass()); + + if (duplicates != null && !duplicates.isEmpty()) { + restoreRenamedParams(copies); + inlineSameArguments(method, copies, variables, duplicates); + myMethodCall = (PsiMethodCallExpression)myMethodCall.copy(); + for (PsiExpression expression : copies) { + myMethodCall.getArgumentList().add(expression); + } + return duplicates; + } + else { + return null; + } + } + + private void inlineSameArguments(PsiMethod method, List copies, InputVariables variables, List duplicates) { + final List variableDatum = variables.getInputVariables(); + final Map toInline = new HashMap(); + final int strongParamsCound = method.getParameterList().getParametersCount(); + for (int i = strongParamsCound; i < variableDatum.size(); i++) { + VariableData variableData = variableDatum.get(i); + final THashSet map = new THashSet(ourEquivalenceStrategy); + if (!collectParamValues(duplicates, variableData, map)) { + continue; + } + + final PsiExpression currentExpression = copies.get(i - strongParamsCound); + map.add(currentExpression); + + if (map.size() == 1) { + toInline.put(variableData.variable, currentExpression); + } + } + + if (!toInline.isEmpty()) { + copies.removeAll(toInline.values()); + inlineArgumentsInMethodBody(toInline); + removeRedundantParametersFromMethodSignature(toInline); + } + } + + private void removeRedundantParametersFromMethodSignature(Map param2ExprMap) { + for (PsiParameter parameter : myExtractedMethod.getParameterList().getParameters()) { + if (param2ExprMap.containsKey(parameter)) { + parameter.delete(); + } + } + } + + private void inlineArgumentsInMethodBody(final Map param2ExprMap) { + final Map replacement = new HashMap(); + myExtractedMethod.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement resolve = expression.resolve(); + if (resolve instanceof PsiVariable) { + final PsiExpression toInlineExpr = param2ExprMap.get((PsiVariable)resolve); + if (toInlineExpr != null) { + replacement.put(expression, toInlineExpr); + } + } + } + }); + for (PsiExpression expression : replacement.keySet()) { + expression.replace(replacement.get(expression)); + } + } + + private static boolean collectParamValues(List duplicates, VariableData variableData, THashSet map) { + for (Match duplicate : duplicates) { + final List values = duplicate.getParameterValues(variableData.variable); + if (values == null || values.isEmpty()) { + return false; + } + boolean found = false; + for (PsiElement value : values) { + if (value instanceof PsiExpression) { + map.add((PsiExpression)value); + found = true; + break; + } + } + if (!found) return false; + } + return true; + } + + private void restoreRenamedParams(List copies) { + final Map renameMap = new HashMap(); + for (VariableData data : myVariableData) { + if (!data.name.equals(data.variable.getName())) { + renameMap.put(data.name, data.variable); + } + } + + if (!renameMap.isEmpty()) { + for (PsiExpression currentExpression : copies) { + final Map params = new HashMap(); + currentExpression.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiElement resolve = expression.resolve(); + if (resolve instanceof PsiParameter && myExtractedMethod.equals(((PsiParameter)resolve).getDeclarationScope())) { + final String name = ((PsiParameter)resolve).getName(); + final PsiVariable variable = renameMap.get(name); + if (renameMap.containsKey(name)) { + params.put(expression, variable); + } + } + } + }); + for (PsiReferenceExpression expression : params.keySet()) { + final PsiVariable var = params.get(expression); + expression.replace(myElementFactory.createExpressionFromText(var.getName(), expression)); + } + } + } + } + + + @Nullable + private InputVariables detectTopLevelExpressionsToReplaceWithParameters(List copies) { + final PsiParameter[] parameters = myExtractedMethod.getParameterList().getParameters(); + final List inputVariables = new ArrayList(Arrays.asList(parameters)); + final PsiCodeBlock body = myExtractedMethod.getBody(); + LOG.assertTrue(body != null); + final PsiStatement[] pattern = body.getStatements(); + final List exprs = new ArrayList(); + for (PsiStatement statement : pattern) { + if (statement instanceof PsiExpressionStatement) { + final PsiExpression expression = ((PsiExpressionStatement)statement).getExpression(); + if (expression instanceof PsiIfStatement || expression instanceof PsiLoopStatement) { + continue; + } + } + statement.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitCallExpression(PsiCallExpression callExpression) { + final PsiExpressionList list = callExpression.getArgumentList(); + if (list != null) { + for (PsiExpression expression : list.getExpressions()) { + if (expression instanceof PsiReferenceExpression) { + final PsiElement resolve = ((PsiReferenceExpression)expression).resolve(); + if (resolve instanceof PsiField) { + exprs.add(expression); + } + } else { + exprs.add(expression); + } + } + } + } + }); + } + + if (exprs.isEmpty()) { + return null; + } + + final UniqueNameGenerator uniqueNameGenerator = new UniqueNameGenerator(); + for (PsiParameter parameter : parameters) { + uniqueNameGenerator.addExistingName(parameter.getName()); + } + final THashMap unique = new THashMap(ourEquivalenceStrategy); + final Map replacement = new HashMap(); + for (PsiExpression expr : exprs) { + String name = unique.get(expr); + if (name == null) { + + final PsiType type = GenericsUtil.getVariableTypeByExpressionType(expr.getType()); + if (type == null || type == PsiType.NULL || PsiUtil.resolveClassInType(type) instanceof PsiAnonymousClass) return null; + + copies.add(myElementFactory.createExpressionFromText(expr.getText(), body)); + + final SuggestedNameInfo info = JavaCodeStyleManager.getInstance(myProject).suggestVariableName(VariableKind.PARAMETER, null, expr, null); + name = uniqueNameGenerator.generateUniqueName(info.names[0]); + + final PsiParameter parameter = (PsiParameter)myExtractedMethod.getParameterList().add(myElementFactory.createParameter(name, type)); + inputVariables.add(parameter); + unique.put(expr, name); + } + replacement.put(expr, name); + } + + for (PsiExpression expression : replacement.keySet()) { + expression.replace(myElementFactory.createExpressionFromText(replacement.get(expression), null)); + } + + return new InputVariables(inputVariables, myExtractedMethod.getProject(), new LocalSearchScope(myExtractedMethod), false); + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java index 2a8741b88451..c7079345e98b 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java @@ -28,6 +28,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; @@ -61,6 +62,7 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.*; diff --git a/java/java-impl/src/com/intellij/refactoring/util/duplicates/ConstantMatchProvider.java b/java/java-impl/src/com/intellij/refactoring/util/duplicates/ConstantMatchProvider.java index 482cb6409b6c..7c66aaebcf03 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/duplicates/ConstantMatchProvider.java +++ b/java/java-impl/src/com/intellij/refactoring/util/duplicates/ConstantMatchProvider.java @@ -58,7 +58,7 @@ class ConstantMatchProvider implements MatchProvider { } @Override - public boolean hasDuplicates() { + public Boolean hasDuplicates() { return !myMatches.isEmpty(); } diff --git a/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesImpl.java b/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesImpl.java index 5e5b620bcd31..38c798b5549d 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/util/duplicates/DuplicatesImpl.java @@ -59,13 +59,17 @@ public class DuplicatesImpl { private DuplicatesImpl() {} public static void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull MatchProvider provider) { + invoke(project, editor, provider, true); + } + + public static void invoke(@NotNull final Project project, @NotNull Editor editor, @NotNull MatchProvider provider, boolean skipPromptWhenOne) { final List duplicates = provider.getDuplicates(); int idx = 0; final Ref showAll = new Ref(); final String confirmDuplicatePrompt = getConfirmationPrompt(provider, duplicates); for (final Match match : duplicates) { if (!match.getMatchStart().isValid() || !match.getMatchEnd().isValid()) continue; - if (replaceMatch(project, provider, match, editor, ++idx, duplicates.size(), showAll, confirmDuplicatePrompt, true)) return; + if (replaceMatch(project, provider, match, editor, ++idx, duplicates.size(), showAll, confirmDuplicatePrompt, skipPromptWhenOne)) return; } } @@ -186,18 +190,18 @@ public class DuplicatesImpl { } public static void processDuplicates(@NotNull MatchProvider provider, @NotNull Project project, @NotNull Editor editor) { - boolean hasDuplicates = provider.hasDuplicates(); - if (hasDuplicates) { + Boolean hasDuplicates = provider.hasDuplicates(); + if (hasDuplicates == null || hasDuplicates.booleanValue()) { List duplicates = provider.getDuplicates(); if (duplicates.size() == 1) { previewMatch(project, duplicates.get(0), editor); } - final int answer = ApplicationManager.getApplication().isUnitTestMode() ? Messages.YES : Messages.showYesNoDialog(project, + final int answer = ApplicationManager.getApplication().isUnitTestMode() || hasDuplicates == null ? Messages.YES : Messages.showYesNoDialog(project, RefactoringBundle.message("0.has.detected.1.code.fragments.in.this.file.that.can.be.replaced.with.a.call.to.extracted.method", ApplicationNamesInfo.getInstance().getProductName(), duplicates.size()), "Process Duplicates", Messages.getQuestionIcon()); if (answer == Messages.YES) { - invoke(project, editor, provider); + invoke(project, editor, provider, hasDuplicates != null); } } } diff --git a/java/java-impl/src/com/intellij/refactoring/util/duplicates/MatchProvider.java b/java/java-impl/src/com/intellij/refactoring/util/duplicates/MatchProvider.java index abe57ef465ab..8c067a215ef3 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/duplicates/MatchProvider.java +++ b/java/java-impl/src/com/intellij/refactoring/util/duplicates/MatchProvider.java @@ -30,7 +30,10 @@ public interface MatchProvider { List getDuplicates(); - boolean hasDuplicates(); + /** + * @return null if no confirmation prompt is expected + */ + @Nullable Boolean hasDuplicates(); @Nullable String getConfirmDuplicatePrompt(Match match); diff --git a/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesHandler.java b/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesHandler.java index d908d35ec3cd..78c4ed2ab216 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesHandler.java @@ -257,6 +257,16 @@ public class MethodDuplicatesHandler implements RefactoringActionHandler { } public static List hasDuplicates(final PsiFile file, final PsiMember member) { + final DuplicatesFinder duplicatesFinder = createDuplicatesFinder(member); + if (duplicatesFinder == null) { + return Collections.emptyList(); + } + + return duplicatesFinder.findDuplicates(file); + } + + @Nullable + public static DuplicatesFinder createDuplicatesFinder(PsiMember member) { PsiElement[] pattern; ReturnValue matchedReturnValue = null; if (member instanceof PsiMethod) { @@ -288,17 +298,14 @@ public class MethodDuplicatesHandler implements RefactoringActionHandler { pattern = new PsiElement[]{((PsiField)member).getInitializer()}; } if (pattern.length == 0) { - return Collections.emptyList(); + return null; } final List inputVariables = member instanceof PsiMethod ? Arrays.asList(((PsiMethod)member).getParameterList().getParameters()) : new ArrayList(); - final DuplicatesFinder duplicatesFinder = - new DuplicatesFinder(pattern, - new InputVariables(inputVariables, member.getProject(), new LocalSearchScope(pattern), false), - matchedReturnValue, - new ArrayList()); - - return duplicatesFinder.findDuplicates(file); + return new DuplicatesFinder(pattern, + new InputVariables(inputVariables, member.getProject(), new LocalSearchScope(pattern), false), + matchedReturnValue, + new ArrayList()); } static String getStatusMessage(final int duplicatesNo) { diff --git a/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesMatchProvider.java b/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesMatchProvider.java index 7686126427b6..f7b06702bce0 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesMatchProvider.java +++ b/java/java-impl/src/com/intellij/refactoring/util/duplicates/MethodDuplicatesMatchProvider.java @@ -149,7 +149,7 @@ class MethodDuplicatesMatchProvider implements MatchProvider { } @Override - public boolean hasDuplicates() { + public Boolean hasDuplicates() { return myDuplicates.isEmpty(); } diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/constructorStatement.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/constructorStatement.java new file mode 100644 index 000000000000..05edd3342c64 --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/constructorStatement.java @@ -0,0 +1,5 @@ +public class Foo { + void m() { + new Object().try + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/constructorStatement_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/constructorStatement_after.java new file mode 100644 index 000000000000..807cf33709ec --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/constructorStatement_after.java @@ -0,0 +1,9 @@ +public class Foo { + void m() { + try { + new Object() + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/declarationStatement.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/declarationStatement.java new file mode 100644 index 000000000000..ae6f5b02395d --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/declarationStatement.java @@ -0,0 +1,5 @@ +public class Foo { + void m() { + Object obj = new Object().try + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/declarationStatement_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/declarationStatement_after.java new file mode 100644 index 000000000000..c6c37844fc43 --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/declarationStatement_after.java @@ -0,0 +1,9 @@ +public class Foo { + void m() { + try { + Object obj = new Object() + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/expressionInMethodBody.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/expressionInMethodBody.java new file mode 100644 index 000000000000..ab9cacffb71f --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/expressionInMethodBody.java @@ -0,0 +1,9 @@ +public class Foo { + void m() { + doAct() + "aaa".try + } + + String doAct() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/expressionInMethodBody_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/expressionInMethodBody_after.java new file mode 100644 index 000000000000..ef09a53f103e --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/expressionInMethodBody_after.java @@ -0,0 +1,13 @@ +public class Foo { + void m() { + try { + doAct() + "aaa" + } catch (Exception e) { + e.printStackTrace(); + } + } + + String doAct() { + return null; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/incompleteStatement.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/incompleteStatement.java new file mode 100644 index 000000000000..b12d1eaeb327 --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/incompleteStatement.java @@ -0,0 +1,11 @@ +import java.lang.Exception; + +public class Foo { + void m() { + methodCall(.try + } + + void methodCall(String s) { + + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/incompleteStatement_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/incompleteStatement_after.java new file mode 100644 index 000000000000..8e1763f0f221 --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/incompleteStatement_after.java @@ -0,0 +1,11 @@ +import java.lang.Exception; + +public class Foo { + void m() { + methodCall(.try + } + + void methodCall(String s) { + + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/simpleWithThrowsCheckedException.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/simpleWithThrowsCheckedException.java new file mode 100644 index 000000000000..a28a0e66b63d --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/simpleWithThrowsCheckedException.java @@ -0,0 +1,9 @@ +import java.io.IOException; + +public class Foo { + void m() { + doAct().try + } + + void doAct() throws IOException {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/try/simpleWithThrowsCheckedException_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/try/simpleWithThrowsCheckedException_after.java new file mode 100644 index 000000000000..5c893da1d0be --- /dev/null +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/try/simpleWithThrowsCheckedException_after.java @@ -0,0 +1,13 @@ +import java.io.IOException; + +public class Foo { + void m() { + try { + doAct() + } catch (IOException e) { + e.printStackTrace(); + } + } + + void doAct() throws IOException {} +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/DefaultNamesConflictResolution.java b/java/java-tests/testData/refactoring/extractMethod/DefaultNamesConflictResolution.java new file mode 100644 index 000000000000..9acf21ea6efb --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/DefaultNamesConflictResolution.java @@ -0,0 +1,7 @@ +class X { + public static void main(String[] args) { + boolean _user = true; + String user = "foo"; + System.out.println(_user + " " + user); + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/DefaultNamesConflictResolution_after.java b/java/java-tests/testData/refactoring/extractMethod/DefaultNamesConflictResolution_after.java new file mode 100644 index 000000000000..0749b6ad85a7 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/DefaultNamesConflictResolution_after.java @@ -0,0 +1,11 @@ +class X { + public static void main(String[] args) { + boolean _user = true; + String user = "foo"; + newMethod(_user, user); + } + + private static void newMethod(boolean user, String user2) { + System.out.println(user + " " + user2); + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureLeaveSameExpressionsUntouched.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureLeaveSameExpressionsUntouched.java new file mode 100644 index 000000000000..ad1e6d5f632c --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureLeaveSameExpressionsUntouched.java @@ -0,0 +1,13 @@ +public class Test { + { + int x = 0; + + System.out.println("foo"); + System.out.println("bazz"); + System.out.println(x); + + System.out.println("bar"); + System.out.println("bazz"); + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureLeaveSameExpressionsUntouched_after.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureLeaveSameExpressionsUntouched_after.java new file mode 100644 index 000000000000..db07aa54c3a8 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureLeaveSameExpressionsUntouched_after.java @@ -0,0 +1,15 @@ +public class Test { + { + int x = 0; + + newMethod(x, "foo"); + + newMethod(x, "bar"); + } + + private void newMethod(int x, String foo) { + System.out.println(foo); + System.out.println("bazz"); + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParam.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParam.java new file mode 100644 index 000000000000..47681845c571 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParam.java @@ -0,0 +1,11 @@ +public class Test { + { + int x = 0; + + System.out.println("foo"); + System.out.println(x); + + System.out.println("bar"); + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParamMultipleTimesInside.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParamMultipleTimesInside.java new file mode 100644 index 000000000000..a345233a9c37 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParamMultipleTimesInside.java @@ -0,0 +1,13 @@ +public class Test { + { + int x = 0; + + System.out.println("foo"); + System.out.println("foo"); + System.out.println(x); + + System.out.println("bar"); + System.out.println("bar"); + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParamMultipleTimesInside_after.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParamMultipleTimesInside_after.java new file mode 100644 index 000000000000..c6d3c785933b --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParamMultipleTimesInside_after.java @@ -0,0 +1,15 @@ +public class Test { + { + int x = 0; + + newMethod(x, "foo"); + + newMethod(x, "bar"); + } + + private void newMethod(int x, String foo) { + System.out.println(foo); + System.out.println(foo); + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParam_after.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParam_after.java new file mode 100644 index 000000000000..ef16acc2489b --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureOneParam_after.java @@ -0,0 +1,14 @@ +public class Test { + { + int x = 0; + + newMethod(x, "foo"); + + newMethod(x, "bar"); + } + + private void newMethod(int x, String foo) { + System.out.println(foo); + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureSameParamNames.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureSameParamNames.java new file mode 100644 index 000000000000..ebb9e5910770 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureSameParamNames.java @@ -0,0 +1,13 @@ +public class Test { + { + int x = 0; + + System.out.println(1); + System.out.println(2); + System.out.println(x); + + System.out.println(3); + System.out.println(4); + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureSameParamNames_after.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureSameParamNames_after.java new file mode 100644 index 000000000000..47d1ed9ed8c6 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureSameParamNames_after.java @@ -0,0 +1,15 @@ +public class Test { + { + int x = 0; + + newMethod(x, 1, 2); + + newMethod(x, 3, 4); + } + + private void newMethod(int x, int x2, int x3) { + System.out.println(x2); + System.out.println(x3); + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureWithChangedParameterName.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureWithChangedParameterName.java new file mode 100644 index 000000000000..2445f2264db8 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureWithChangedParameterName.java @@ -0,0 +1,13 @@ +public class Test { + { + int x = 0; + + + System.out.println(x); + System.out.println(x + 1); + + + System.out.println(x); + System.out.println(x + 2); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureWithChangedParameterName_after.java b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureWithChangedParameterName_after.java new file mode 100644 index 000000000000..b3e5880154f3 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/SuggestChangeSignatureWithChangedParameterName_after.java @@ -0,0 +1,16 @@ +public class Test { + { + int x = 0; + + + newMethod(x, x + 1); + + + newMethod(x, x + 2); + } + + private void newMethod(int p, int x) { + System.out.println(p); + System.out.println(x); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/TryPostfixTemplateTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/TryPostfixTemplateTest.java index e17d479f0fd5..1b2e9d62c013 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/TryPostfixTemplateTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/template/postfix/templates/TryPostfixTemplateTest.java @@ -39,4 +39,24 @@ public class TryPostfixTemplateTest extends PostfixTemplateTestCase { public void testNotResolvedExpression() { doTest(); } + + public void testDeclarationStatement() { + doTest(); + } + + public void testExpressionInMethodBody() { + doTest(); + } + + public void testSimpleWithThrowsCheckedException() { + doTest(); + } + + public void testIncompleteStatement() { + doTest(); + } + + public void testConstructorStatement() { + doTest(); + } } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index 58678084b5d0..09e9863d6fc2 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -19,6 +19,7 @@ import com.intellij.JavaTestUtil; import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; @@ -33,6 +34,7 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.List; public class ExtractMethodTest extends LightCodeInsightTestCase { @@ -609,6 +611,29 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doDuplicatesTest(); } + public void testSuggestChangeSignatureOneParam() throws Exception { + doDuplicatesTest(); + } + + public void testSuggestChangeSignatureOneParamMultipleTimesInside() throws Exception { + doDuplicatesTest(); + } + + public void testSuggestChangeSignatureLeaveSameExpressionsUntouched() throws Exception { + doDuplicatesTest(); + } + + public void testSuggestChangeSignatureSameParamNames() throws Exception { + doDuplicatesTest(); + } + + public void testSuggestChangeSignatureWithChangedParameterName() throws Exception { + configureByFile(BASE_PATH + getTestName(false) + ".java"); + boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, null, false, "p"); + assertTrue(success); + checkResultByFile(BASE_PATH + getTestName(false) + "_after.java"); + } + public void testTargetAnonymous() throws Exception { doTest(); } @@ -646,6 +671,18 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTestPassFieldsAsParams(); } + public void testDefaultNamesConflictResolution() throws Exception { + final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + final String oldPrefix = settings.LOCAL_VARIABLE_NAME_PREFIX; + try { + settings.LOCAL_VARIABLE_NAME_PREFIX = "_"; + doTest(); + } + finally { + settings.LOCAL_VARIABLE_NAME_PREFIX = oldPrefix; + } + } + public void testCantPassFieldAsParameter() throws Exception { try { doTestPassFieldsAsParams(); @@ -670,7 +707,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { settings.ELSE_ON_NEW_LINE = true; settings.CATCH_ON_NEW_LINE = myCatchOnNewLine; configureByFile(BASE_PATH + getTestName(false) + ".java"); - boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, type, false); + boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, type, false, null); assertTrue(success); checkResultByFile(BASE_PATH + getTestName(false) + "_after.java"); } @@ -680,7 +717,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { settings.ELSE_ON_NEW_LINE = true; settings.CATCH_ON_NEW_LINE = myCatchOnNewLine; configureByFile(BASE_PATH + getTestName(false) + ".java"); - boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, null, true); + boolean success = performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, null, true, null); assertTrue(success); checkResultByFile(BASE_PATH + getTestName(false) + "_after.java"); } @@ -740,7 +777,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { final boolean extractChainedConstructor, int... disabledParams) throws PrepareFailedException, IncorrectOperationException { - return performExtractMethod(doRefactor, replaceAllDuplicates, editor, file, project, extractChainedConstructor, null, false, disabledParams); + return performExtractMethod(doRefactor, replaceAllDuplicates, editor, file, project, extractChainedConstructor, null, false, null, disabledParams); } public static boolean performExtractMethod(boolean doRefactor, @@ -751,6 +788,7 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { final boolean extractChainedConstructor, PsiType returnType, boolean makeStatic, + String newNameOfFirstParam, int... disabledParams) throws PrepareFailedException, IncorrectOperationException { int startOffset = editor.getSelectionModel().getSelectionStart(); @@ -789,15 +827,21 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { processor.doNotPassParameter(param); } } + if (newNameOfFirstParam != null) { + processor.changeParamName(0, newNameOfFirstParam); + } ExtractMethodHandler.run(project, editor, processor); } if (replaceAllDuplicates) { - final List duplicates = processor.getDuplicates(); - for (final Match match : duplicates) { - if (!match.getMatchStart().isValid() || !match.getMatchEnd().isValid()) continue; - PsiDocumentManager.getInstance(project).commitAllDocuments(); - processor.processMatch(match); + final Boolean hasDuplicates = processor.hasDuplicates(); + if (hasDuplicates == null || hasDuplicates.booleanValue()) { + final List duplicates = processor.getDuplicates(); + for (final Match match : duplicates) { + if (!match.getMatchStart().isValid() || !match.getMatchEnd().isValid()) continue; + PsiDocumentManager.getInstance(project).commitAllDocuments(); + processor.processMatch(match); + } } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java index be43de8349fb..9e0f18d2d9e7 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/Mappings.java @@ -2272,6 +2272,45 @@ public class Mappings { return true; } }); + + // some classes may be associated with multiple sources. + // In case some of these sources was not compiled, but the class was changed, we need to update + // sourceToClasses mapping for such sources to include the updated ClassRepr version of the changed class + final THashSet unchangedSources = new THashSet(FileUtil.FILE_HASHING_STRATEGY); + delta.mySourceFileToClasses.forEachEntry(new TObjectObjectProcedure>() { + @Override + public boolean execute(File source, Collection b) { + unchangedSources.add(source); + return true; + } + }); + unchangedSources.removeAll(delta.getChangedFiles()); + if (!unchangedSources.isEmpty()) { + unchangedSources.forEach(new TObjectProcedure() { + @Override + public boolean execute(File file) { + final Collection updatedClasses = delta.mySourceFileToClasses.get(file); + if (updatedClasses != null && !updatedClasses.isEmpty()) { + final List classesToAdd = new ArrayList(); + classesToAdd.addAll(updatedClasses); + Collection currentClasses = mySourceFileToClasses.get(file); + if (currentClasses != null) { + final TIntHashSet updatedClassNames = new TIntHashSet(); + for (ClassRepr aClass : updatedClasses) { + updatedClassNames.add(aClass.name); + } + for (ClassRepr aClass : currentClasses) { + if (!updatedClassNames.contains(aClass.name)) { + classesToAdd.add(aClass); + } + } + } + mySourceFileToClasses.replace(file, classesToAdd); + } + return true; + } + }); + } } else { myClassToSubclasses.putAll(delta.myClassToSubclasses); diff --git a/platform/core-api/src/com/intellij/openapi/project/ProjectCoreUtil.java b/platform/core-api/src/com/intellij/openapi/project/ProjectCoreUtil.java index 83e8b6924fd4..fce99a0fb479 100644 --- a/platform/core-api/src/com/intellij/openapi/project/ProjectCoreUtil.java +++ b/platform/core-api/src/com/intellij/openapi/project/ProjectCoreUtil.java @@ -2,6 +2,8 @@ package com.intellij.openapi.project; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.InternalFileType; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.SystemInfoRt; import com.intellij.openapi.vfs.VirtualFile; /** @@ -17,9 +19,9 @@ public class ProjectCoreUtil { public static boolean isProjectOrWorkspaceFile(final VirtualFile file, final FileType fileType) { if (fileType instanceof InternalFileType) return true; - VirtualFile parent = file.getParent(); - while(parent != null) { - if (DIRECTORY_BASED_PROJECT_DIR.equals(parent.getName())) return true; + VirtualFile parent = file.isDirectory() ? file: file.getParent(); + while (parent != null) { + if (Comparing.equal(parent.getNameSequence(), DIRECTORY_BASED_PROJECT_DIR, SystemInfoRt.isFileSystemCaseSensitive)) return true; parent = parent.getParent(); } return false; diff --git a/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java b/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java index 0dac0d7d3b0c..dcd0e8ae3513 100644 --- a/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/project/ProjectUtil.java @@ -20,7 +20,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.fileEditor.UniqueVFilePathBuilder; import com.intellij.openapi.fileTypes.FileType; -import com.intellij.openapi.fileTypes.InternalFileType; +import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -107,11 +107,12 @@ public class ProjectUtil { } public static boolean isProjectOrWorkspaceFile(final VirtualFile file) { - return isProjectOrWorkspaceFile(file, file.getFileType()); + // do not use file.getFileType() to avoid autodetection by content loading for arbitrary files + return isProjectOrWorkspaceFile(file, FileTypeManager.getInstance().getFileTypeByFileName(file.getName())); } - public static boolean isProjectOrWorkspaceFile(@NotNull VirtualFile file, @NotNull FileType fileType) { - return fileType instanceof InternalFileType || file.getPath().contains('/' + ProjectCoreUtil.DIRECTORY_BASED_PROJECT_DIR + '/'); + public static boolean isProjectOrWorkspaceFile(@NotNull VirtualFile file, @Nullable FileType fileType) { + return ProjectCoreUtil.isProjectOrWorkspaceFile(file, fileType); } @NotNull diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java index 577494fa216d..329820b8297a 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubUpdatingIndex.java @@ -31,6 +31,7 @@ import com.intellij.psi.tree.IStubFileElementType; import com.intellij.util.ExceptionUtil; import com.intellij.util.indexing.*; import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.DataInputOutputUtil; import com.intellij.util.io.IntInlineKeyDescriptor; import com.intellij.util.io.KeyDescriptor; import org.jetbrains.annotations.NotNull; @@ -45,7 +46,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi private static final Logger LOG = Logger.getInstance("#com.intellij.psi.stubs.StubUpdatingIndex"); // todo remove once we don't need this for stub-ast mismatch debug info - private static final FileAttribute INDEXED_STAMP = new FileAttribute("stubIndexStamp", 0, false); + private static final FileAttribute INDEXED_STAMP = new FileAttribute("stubIndexStamp", 1, false); public static final ID INDEX_ID = ID.create("Stubs"); @@ -145,8 +146,8 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi private static void rememberIndexingStamp(final VirtualFile file, long contentLength) { try { DataOutputStream stream = INDEXED_STAMP.writeAttribute(file); - stream.writeLong(file.getTimeStamp()); - stream.writeLong(contentLength); + DataInputOutputUtil.writeTIME(stream, file.getTimeStamp()); + DataInputOutputUtil.writeLONG(stream, contentLength); stream.close(); } catch (IOException e) { @@ -161,8 +162,8 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi return "no data"; } - long stamp = stream.readLong(); - long size = stream.readLong(); + long stamp = DataInputOutputUtil.readTIME(stream); + long size = DataInputOutputUtil.readLONG(stream); stream.close(); return "indexed at " + stamp + " with size " + size; } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index d8dd50719cf6..4ed9341ae882 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -254,13 +254,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { } public static boolean isProjectOrWorkspaceFile(@NotNull VirtualFile file, @Nullable FileType fileType) { - if (fileType instanceof InternalFileType) return true; - VirtualFile parent = file.isDirectory() ? file: file.getParent(); - while (parent != null) { - if (Comparing.equal(parent.getNameSequence(), ProjectCoreUtil.DIRECTORY_BASED_PROJECT_DIR, SystemInfoRt.isFileSystemCaseSensitive)) return true; - parent = parent.getParent(); - } - return false; + return ProjectCoreUtil.isProjectOrWorkspaceFile(file, fileType); } @Override diff --git a/platform/platform-api/src/com/intellij/ide/highlighter/WorkspaceFileType.java b/platform/platform-api/src/com/intellij/ide/highlighter/WorkspaceFileType.java index bff9dc107e43..3d1f3b9d2dea 100644 --- a/platform/platform-api/src/com/intellij/ide/highlighter/WorkspaceFileType.java +++ b/platform/platform-api/src/com/intellij/ide/highlighter/WorkspaceFileType.java @@ -26,9 +26,13 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; public class WorkspaceFileType implements InternalFileType { + public static final WorkspaceFileType INSTANCE = new WorkspaceFileType(); + @NonNls public static final String DEFAULT_EXTENSION = "iws"; @NonNls public static final String DOT_DEFAULT_EXTENSION = "." + DEFAULT_EXTENSION; + private WorkspaceFileType() {} + @Override @NotNull public String getName() { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index edc4b642d25a..1d03c327030d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -38,7 +38,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.editor.colors.EditorColors; -import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.event.EditorMouseEventArea; import com.intellij.openapi.editor.ex.*; @@ -96,7 +95,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse private ArrayList myTextAnnotationGutters = new ArrayList(); private final Map myProviderToListener = new HashMap(); private static final int GAP_BETWEEN_ANNOTATIONS = 5; - private Color myBackgroundColor = null; private String myLastGutterToolTip = null; @NotNull private TIntFunction myLineNumberConvertor; private boolean myShowDefaultGutterPopup = true; @@ -174,7 +172,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } public void reinitSettings() { - myBackgroundColor = null; revalidateMarkup(); repaint(); } @@ -197,8 +194,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } UISettings.setupAntialiasing(g); - paintLineNumbersBackground(g, clip); - paintAnnotationsBackground(g, clip); + Color backgroundColor = getBackground(); + paintLineNumbersBackground(g, clip, backgroundColor); + paintAnnotationsBackground(g, clip, backgroundColor); Object hint = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING); if (!UIUtil.isRetina()) g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); @@ -206,9 +204,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse try { int firstVisibleOffset = myEditor.logicalPositionToOffset(myEditor.xyToLogicalPosition(new Point(0, clip.y - myEditor.getLineHeight()))); int lastVisibleOffset = myEditor.logicalPositionToOffset(myEditor.xyToLogicalPosition(new Point(0, clip.y + clip.height + myEditor.getLineHeight()))); - paintFoldingBackground(g, clip); - paintLineMarkersBackground(g, clip); - paintBackground(g, clip, getLineMarkerAreaOffset(), getLineMarkerAreaWidth()); + paintFoldingBackground(g, clip, backgroundColor); + paintLineMarkersBackground(g, clip, backgroundColor); + paintBackground(g, clip, getLineMarkerAreaOffset(), getLineMarkerAreaWidth(), backgroundColor); paintEditorBackgrounds(g, firstVisibleOffset, lastVisibleOffset); paintAnnotations(g, clip); paintLineMarkers(g, firstVisibleOffset, lastVisibleOffset); @@ -298,11 +296,10 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - private void paintAnnotationsBackground(Graphics g, Rectangle clip) { + private void paintAnnotationsBackground(Graphics g, Rectangle clip, Color backgroundColor) { int w = getAnnotationsAreaWidthEx(); if (w == 0) return; - final Color background = myEditor.isInDistractionFreeMode() ? myEditor.getBackgroundColor() : getBackground(); - paintBackground(g, clip, getAnnotationsAreaOffset(), w, background); + paintBackground(g, clip, getAnnotationsAreaOffset(), w, backgroundColor); } private void paintAnnotations(Graphics g, Rectangle clip) { @@ -356,9 +353,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - private void paintLineMarkersBackground(Graphics g, Rectangle clip) { + private void paintLineMarkersBackground(Graphics g, Rectangle clip, Color bgColor) { if (isLineMarkersShown()) { - paintBackground(g, clip, getLineMarkerAreaOffset(), getLineMarkerAreaWidth()); + paintBackground(g, clip, getLineMarkerAreaOffset(), getLineMarkerAreaWidth(), bgColor); } } @@ -368,10 +365,6 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - private void paintBackground(final Graphics g, final Rectangle clip, final int x, final int width) { - paintBackground(g, clip, x, width, getBackground()); - } - private void paintBackground(final Graphics g, final Rectangle clip, final int x, @@ -399,21 +392,19 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - private void paintLineNumbersBackground(Graphics g, Rectangle clip) { + private void paintLineNumbersBackground(Graphics g, Rectangle clip, Color bgColor) { if (isLineNumbersShown()) { - paintBackground(g, clip, getLineNumberAreaOffset(), getLineNumberAreaWidth()); + paintBackground(g, clip, getLineNumberAreaOffset(), getLineNumberAreaWidth(), bgColor); } } @Override public Color getBackground() { - if (myBackgroundColor == null) { - EditorColorsScheme colorsScheme = myEditor.getColorsScheme(); - boolean distractionMode = myEditor.isInDistractionFreeMode(); - Color color = distractionMode ? colorsScheme.getDefaultBackground() : colorsScheme.getColor(EditorColors.GUTTER_BACKGROUND); - myBackgroundColor = color == null ? EditorColors.GUTTER_BACKGROUND.getDefaultColor() : color; + if (myEditor.isInDistractionFreeMode()) { + return myEditor.getBackgroundColor(); } - return myBackgroundColor; + Color color = myEditor.getColorsScheme().getColor(EditorColors.GUTTER_BACKGROUND); + return color != null ? color : EditorColors.GUTTER_BACKGROUND.getDefaultColor(); } private void doPaintLineNumbers(Graphics g, Rectangle clip) { @@ -850,9 +841,9 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - private void paintFoldingBackground(Graphics g, Rectangle clip) { + private void paintFoldingBackground(Graphics g, Rectangle clip, Color bgColor) { int lineX = getWhitespaceSeparatorOffset(); - paintBackground(g, clip, getFoldingAreaOffset(), getFoldingAreaWidth()); + paintBackground(g, clip, getFoldingAreaOffset(), getFoldingAreaWidth(), bgColor); g.setColor(myEditor.getBackgroundColor()); g.fillRect(lineX, clip.y, getFoldingAreaWidth(), clip.height); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/InternalFileTypeFactory.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/InternalFileTypeFactory.java index 5224b1309f4d..b7cf3ec1e306 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/InternalFileTypeFactory.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/InternalFileTypeFactory.java @@ -27,8 +27,8 @@ import org.jetbrains.annotations.NotNull; */ public class InternalFileTypeFactory extends FileTypeFactory { public void createFileTypes(@NotNull final FileTypeConsumer consumer) { - consumer.consume(new WorkspaceFileType(), WorkspaceFileType.DEFAULT_EXTENSION); - consumer.consume(new ModuleFileType(), ModuleFileType.DEFAULT_EXTENSION); - consumer.consume(new ProjectFileType(), ProjectFileType.DEFAULT_EXTENSION); + consumer.consume(WorkspaceFileType.INSTANCE, WorkspaceFileType.DEFAULT_EXTENSION); + consumer.consume(ModuleFileType.INSTANCE, ModuleFileType.DEFAULT_EXTENSION); + consumer.consume(ProjectFileType.INSTANCE, ProjectFileType.DEFAULT_EXTENSION); } } diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 13cfd5b731c9..2f1324ba9702 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -719,6 +719,7 @@ + diff --git a/platform/projectModel-api/src/com/intellij/ide/highlighter/ModuleFileType.java b/platform/projectModel-api/src/com/intellij/ide/highlighter/ModuleFileType.java index 6cc0f8b21305..5895c2c1fe5c 100644 --- a/platform/projectModel-api/src/com/intellij/ide/highlighter/ModuleFileType.java +++ b/platform/projectModel-api/src/com/intellij/ide/highlighter/ModuleFileType.java @@ -26,9 +26,13 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; public class ModuleFileType implements InternalFileType { + public static final ModuleFileType INSTANCE = new ModuleFileType(); + @NonNls public static final String DEFAULT_EXTENSION = "iml"; @NonNls public static final String DOT_DEFAULT_EXTENSION = ".iml"; + private ModuleFileType() {} + @Override @NotNull public String getName() { diff --git a/platform/projectModel-api/src/com/intellij/ide/highlighter/ProjectFileType.java b/platform/projectModel-api/src/com/intellij/ide/highlighter/ProjectFileType.java index 347908a22a08..4988159d68b9 100644 --- a/platform/projectModel-api/src/com/intellij/ide/highlighter/ProjectFileType.java +++ b/platform/projectModel-api/src/com/intellij/ide/highlighter/ProjectFileType.java @@ -26,9 +26,13 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; public class ProjectFileType implements InternalFileType { + public static final ProjectFileType INSTANCE = new ProjectFileType(); + @NonNls public static final String DEFAULT_EXTENSION = "ipr"; @NonNls public static final String DOT_DEFAULT_EXTENSION = ".ipr"; + private ProjectFileType() {} + @Override @NotNull public String getName() { diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootDetectorTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootDetectorTest.java index fed3cf3341d1..debc963c6d5a 100644 --- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootDetectorTest.java +++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootDetectorTest.java @@ -178,6 +178,9 @@ public class VcsRootDetectorTest extends VcsRootPlatformTest { @NotNull String... expectedPaths) throws IOException { initProject(vcsRootConfiguration); + if (startDir != null) { + startDir.refresh(false, true); + } Collection vcsRoots = detect(startDir); assertRoots(Arrays.asList(expectedPaths), getPaths( ContainerUtil.filter(vcsRoots, new Condition() { diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootErrorsFinderTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootErrorsFinderTest.java index 198cdbb92b89..9a91906e1fc2 100644 --- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootErrorsFinderTest.java +++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootErrorsFinderTest.java @@ -178,6 +178,7 @@ public class VcsRootErrorsFinderTest extends VcsRootPlatformTest { Collection expected = new ArrayList(); expected.addAll(unregAll(vcsRootConfiguration.getUnregErrors())); expected.addAll(extraAll(vcsRootConfiguration.getExtraErrors())); + myProjectRoot.refresh(false, true); Collection actual = ContainerUtil.filter(new VcsRootErrorsFinder(myProject).find(), new Condition() { @Override public boolean value(VcsRootError error) { diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootPlatformTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootPlatformTest.java index 8b04b601f9ef..70ae96eea8da 100644 --- a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootPlatformTest.java +++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/roots/VcsRootPlatformTest.java @@ -86,6 +86,7 @@ public abstract class VcsRootPlatformTest extends UsefulTestCase { .getInstance()); myRootModel = ((ModuleRootManagerImpl)ModuleRootManager.getInstance(module)).getRootModel(); mkdir(myRepositoryFolderName); + myProjectRoot.refresh(false, true); myRepository = myProjectRoot.findChild(myRepositoryFolderName); myVcs = new MockAbstractVcs(myProject); myVcsManager = (ProjectLevelVcsManagerImpl)ProjectLevelVcsManager.getInstance(myProject); @@ -109,6 +110,7 @@ public abstract class VcsRootPlatformTest extends UsefulTestCase { point.registerExtension(myExtension); myVcsManager.registerVcs(myVcs); myVcsName = myVcs.getName(); + myRepository.refresh(false, true); } private static ExtensionPoint getExtensionPoint() { @@ -146,6 +148,7 @@ public abstract class VcsRootPlatformTest extends UsefulTestCase { createProjectStructure(myProject, contentRoots); if (!contentRoots.isEmpty()) { for (String root : contentRoots) { + myProjectRoot.refresh(false, true); VirtualFile f = myProjectRoot.findFileByRelativePath(root); if (f != null) { myRootModel.addContentEntry(f); diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsUserRegistry.java b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsUserRegistry.java index 90971a4f172e..57dc92da5b62 100644 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsUserRegistry.java +++ b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsUserRegistry.java @@ -27,4 +27,6 @@ public interface VcsUserRegistry { @NotNull Set getUsers(); + @NotNull + VcsUser createUser(@NotNull String name, @NotNull String email); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsUserRegistryImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsUserRegistryImpl.java index 8621f379ce65..58896e5f8f5f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsUserRegistryImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsUserRegistryImpl.java @@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.ThrowableComputable; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Interner; import com.intellij.util.io.*; import com.intellij.vcs.log.VcsUser; import com.intellij.vcs.log.VcsUserRegistry; @@ -52,15 +53,17 @@ public class VcsUserRegistryImpl implements Disposable, VcsUserRegistry { }; @Nullable private final PersistentEnumerator myPersistentEnumerator; + @NotNull private final Interner myInterner; VcsUserRegistryImpl(@NotNull Project project) { final File mapFile = new File(USER_CACHE_APP_DIR, project.getName() + "." + project.getLocationHash()); Disposer.register(project, this); myPersistentEnumerator = initEnumerator(mapFile); + myInterner = new Interner(); } @Nullable - private static PersistentEnumerator initEnumerator(@NotNull final File mapFile) { + private PersistentEnumerator initEnumerator(@NotNull final File mapFile) { try { return IOUtil.openCleanOrResetBroken(new ThrowableComputable, IOException>() { @Override @@ -75,6 +78,12 @@ public class VcsUserRegistryImpl implements Disposable, VcsUserRegistry { } } + @NotNull + @Override + public VcsUser createUser(@NotNull String name, @NotNull String email) { + return myInterner.intern(new VcsUserImpl(name, email)); + } + public void addUser(@NotNull VcsUser user) { try { if (myPersistentEnumerator != null) { @@ -125,7 +134,7 @@ public class VcsUserRegistryImpl implements Disposable, VcsUserRegistry { } } - private static class MyDescriptor implements KeyDescriptor { + private class MyDescriptor implements KeyDescriptor { @Override public void save(@NotNull DataOutput out, VcsUser value) throws IOException { IOUtil.writeUTF(out, value.getName()); @@ -136,7 +145,7 @@ public class VcsUserRegistryImpl implements Disposable, VcsUserRegistry { public VcsUser read(@NotNull DataInput in) throws IOException { String name = IOUtil.readUTF(in); String email = IOUtil.readUTF(in); - return new VcsUserImpl(name, email); + return createUser(name, email); } @Override diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogObjectsFactoryImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogObjectsFactoryImpl.java index 06c1bc4564b9..b5502310bda5 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogObjectsFactoryImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogObjectsFactoryImpl.java @@ -11,6 +11,14 @@ import java.util.List; public class VcsLogObjectsFactoryImpl implements VcsLogObjectsFactory { + @NotNull private final VcsUserRegistry myUserRegistry; + + // created as application service + @SuppressWarnings("unused") + private VcsLogObjectsFactoryImpl(@NotNull VcsUserRegistry userRegistry) { + myUserRegistry = userRegistry; + } + @NotNull @Override public Hash createHash(@NotNull String stringHash) { @@ -60,7 +68,7 @@ public class VcsLogObjectsFactoryImpl implements VcsLogObjectsFactory { @NotNull @Override public VcsUser createUser(@NotNull String name, @NotNull String email) { - return new VcsUserImpl(name, email); + return myUserRegistry.createUser(name, email); } @NotNull diff --git a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java index faf9398ba966..be1ebac877ab 100644 --- a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java +++ b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java @@ -24,7 +24,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.ListCellRendererWrapper; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; -import git4idea.GitBranch; import git4idea.GitRemoteBranch; import git4idea.GitUtil; import git4idea.commands.GitCommand; @@ -175,7 +174,7 @@ public class GitPullDialog extends DialogWrapper { myBranchChooser.setElements(ContainerUtil.mapNotNull(remoteBranches, new Function() { @Override public String fun(GitRemoteBranch branch) { - return branch.getRemote().getName().equals(selectedRemote) ? branch.getName() : null; + return branch.getRemote().getName().equals(selectedRemote) ? branch.getNameForLocalOperations() : null; } }), false); if (currentRemoteBranch != null && currentRemoteBranch.getRemote().getName().equals(selectedRemote)) { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java index 7ae35a1105ba..94860b9361b7 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java @@ -61,7 +61,6 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository { private HgRepositoryImpl(@NotNull VirtualFile rootDir, @NotNull HgVcs vcs, @NotNull Disposable parentDisposable) { super(vcs.getProject(), rootDir, parentDisposable); - rootDir.refresh(false, true); myHgDir = rootDir.findChild(HgUtil.DOT_HG); assert myHgDir != null : ".hg directory wasn't found under " + rootDir.getPresentableUrl(); myReader = new HgRepositoryReader(vcs, VfsUtilCore.virtualToIoFile(myHgDir)); diff --git a/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRealRepositoryReaderTest.java b/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRealRepositoryReaderTest.java index 0792a96a28d1..cf72883c7994 100644 --- a/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRealRepositoryReaderTest.java +++ b/plugins/hg4idea/testSrc/hg4idea/test/repo/HgRealRepositoryReaderTest.java @@ -59,11 +59,12 @@ public class HgRealRepositoryReaderTest extends HgPlatformTest { public void testBranches() { VcsTestUtil.assertEqualCollections(myRepositoryReader.readBranches().keySet(), - Arrays.asList("default", "branchA", "branchB")); + Arrays.asList("default", "branchA", "branchB")); } public void testOpenedBranches() { cd(myRepository); + myRepository.refresh(false, true); HgRepository hgRepository = HgRepositoryImpl.getInstance(myRepository, myProject, myProject); hg("up branchA"); hg("commit -m 'close branch' --close-branch"); @@ -74,12 +75,12 @@ public class HgRealRepositoryReaderTest extends HgPlatformTest { public void testTags() { VcsTestUtil.assertEqualCollections(HgUtil.getNamesWithoutHashes(myRepositoryReader.readTags()), - Arrays.asList("tag1", "tag2")); + Arrays.asList("tag1", "tag2")); } public void testLocalTags() { VcsTestUtil.assertEqualCollections(HgUtil.getNamesWithoutHashes(myRepositoryReader.readLocalTags()), - Arrays.asList("localTag")); + Arrays.asList("localTag")); } public void testCurrentBookmark() { @@ -89,7 +90,7 @@ public class HgRealRepositoryReaderTest extends HgPlatformTest { public void testBookmarks() { VcsTestUtil.assertEqualCollections(HgUtil.getNamesWithoutHashes(myRepositoryReader.readBookmarks()), - Arrays.asList("A_BookMark", "B_BookMark", "C_BookMark")); + Arrays.asList("A_BookMark", "B_BookMark", "C_BookMark")); } private void createBranchesAndTags() { diff --git a/python/src/com/jetbrains/python/psi/search/PyKeywordArgumentSearchExecutor.java b/python/src/com/jetbrains/python/psi/search/PyKeywordArgumentSearchExecutor.java index 135a4b908bbf..2aa7d86b18c7 100644 --- a/python/src/com/jetbrains/python/psi/search/PyKeywordArgumentSearchExecutor.java +++ b/python/src/com/jetbrains/python/psi/search/PyKeywordArgumentSearchExecutor.java @@ -20,7 +20,6 @@ import com.intellij.openapi.application.QueryExecutorBase; import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; -import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Processor; @@ -39,17 +38,16 @@ public class PyKeywordArgumentSearchExecutor extends QueryExecutorBase() { + @Override + public ScopeOwner compute() { + return ScopeUtil.getScopeOwner(element); + } + }); if (!(owner instanceof PyFunction)) { return; } - SearchScope scope = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public SearchScope compute() { - return queryParameters.getEffectiveSearchScope(); - } - }); - ReferencesSearch.search(owner, scope).forEach(new Processor() { + ReferencesSearch.search(owner, queryParameters.getScopeDeterminedByUser()).forEach(new Processor() { @Override public boolean process(PsiReference reference) { final PsiElement refElement = reference.getElement();