diff --git a/java/compiler/impl/src/com/intellij/compiler/server/DefaultMessageHandler.java b/java/compiler/impl/src/com/intellij/compiler/server/DefaultMessageHandler.java index 2b0618efa8fe..ae66d169e874 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/DefaultMessageHandler.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/DefaultMessageHandler.java @@ -97,7 +97,7 @@ public abstract class DefaultMessageHandler implements BuilderMessageHandler { final Ref isSuccess = Ref.create(Boolean.TRUE); final Set affectedPaths = new HashSet(); try { - if (DumbService.getInstance(myProject).isDumb()) { + if (isDumbMode()) { // do not wait until dumb mode finishes isSuccess.set(Boolean.FALSE); } @@ -176,6 +176,26 @@ public abstract class DefaultMessageHandler implements BuilderMessageHandler { } } + private boolean isDumbMode() { + final DumbService dumbService = DumbService.getInstance(myProject); + boolean isDumb = dumbService.isDumb(); + if (isDumb) { + // wait some time + for (int idx = 0; idx < 5; idx++) { + try { + Thread.sleep(10L); + } + catch (InterruptedException ignored) { + } + isDumb = dumbService.isDumb(); + if (!isDumb) { + break; + } + } + } + return isDumb; + } + private boolean performChangedConstantSearch(PsiClass aClass, PsiField field, int accessFlags, boolean isAccessibilityChange, Set affectedPaths) { if (!isAccessibilityChange && ClsUtil.isPrivate(accessFlags)) { return true; // optimization: don't need to search, cause may be used only in this class diff --git a/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java b/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java index cc1e787aab22..88d1a6bd3165 100644 --- a/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java +++ b/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java @@ -69,7 +69,7 @@ public class AbstractRerunFailedTestsAction extends AnAction { } public void update(AnActionEvent e) { - e.getPresentation().setEnabled(isActive(e)); + e.getPresentation().setEnabled(isActive(e) && !getModel().isRunning()); } private boolean isActive(AnActionEvent e) { @@ -92,7 +92,6 @@ public class AbstractRerunFailedTestsAction extends AnAction { } public void actionPerformed(AnActionEvent e) { - final DataContext dataContext = e.getDataContext(); boolean isDebug = myConsoleProperties.isDebug(); final MyRunProfile profile = getRunProfile(); try { @@ -104,7 +103,8 @@ public class AbstractRerunFailedTestsAction extends AnAction { profile.getProject(), myEnvironment.getRunnerSettings(), myEnvironment.getConfigurationSettings(), - null)); + myEnvironment.getContentToReuse(), + myEnvironment.getRunnerAndConfigurationSettings())); } catch (ExecutionException e1) { LOG.error(e1); diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java index a65c1d9704d7..c6a110c32e43 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java @@ -28,7 +28,7 @@ import com.intellij.ide.DataManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.command.undo.UndoUtil; +import com.intellij.openapi.command.undo.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; @@ -358,6 +358,18 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { } } }.execute(); + + UndoManager.getInstance(project).undoableActionPerformed(new BasicUndoableAction() { + @Override + public void undo() throws UnexpectedUndoException { + dropCache(); + } + + @Override + public void redo() throws UnexpectedUndoException { + dropCache(); + } + }); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/StatementMover.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/StatementMover.java index 5775503ab083..3d1983d91f70 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/StatementMover.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/StatementMover.java @@ -105,12 +105,43 @@ class StatementMover extends LineMover { return true; } - private boolean calcInsertOffset(PsiFile file, final Editor editor, LineRange range, @NotNull final MoveInfo info, final boolean down) { - int line = down ? range.endLine+1 : range.startLine - 1; + private int getDestLineForAnon(PsiFile file, Editor editor, LineRange range, MoveInfo info, boolean down) { + int destLine = down ? range.endLine+1 : range.startLine - 1; + if (!(range.firstElement instanceof PsiStatement)) { + return destLine; + } + PsiElement sibling = + StatementUpDownMover.firstNonWhiteElement(down ? range.firstElement.getNextSibling() : range.firstElement.getPrevSibling(), down); + PsiElement toMove = sibling; + if (!(sibling instanceof PsiStatement)) { + return destLine; + } + if (sibling instanceof PsiDeclarationStatement) { + PsiElement[] elements = ((PsiDeclarationStatement)sibling).getDeclaredElements(); + if (elements.length == 0) return destLine; + sibling = down ? elements[elements.length - 1] : elements[0]; + } + if (sibling instanceof PsiVariable) { + sibling = ((PsiVariable)sibling).getInitializer(); + } + if (sibling instanceof PsiExpressionStatement) { + sibling = ((PsiExpressionStatement)sibling).getExpression(); + } + if (sibling instanceof PsiNewExpression) { + sibling = ((PsiNewExpression)sibling).getAnonymousClass(); + } + if (!(sibling instanceof PsiClass)) return destLine; + destLine = editor.getDocument().getLineNumber(down ? toMove.getTextRange().getEndOffset() : toMove.getTextRange().getStartOffset()); + + return destLine; + } + private boolean calcInsertOffset(@NotNull PsiFile file, @NotNull Editor editor, @NotNull LineRange range, @NotNull final MoveInfo info, final boolean down) { + int destLine = getDestLineForAnon(file, editor, range, info, down); + int startLine = down ? range.endLine : range.startLine - 1; - if (line < 0 || startLine < 0) return false; + if (destLine < 0 || startLine < 0) return false; while (true) { - final int offset = editor.logicalPositionToOffset(new LogicalPosition(line, 0)); + final int offset = editor.logicalPositionToOffset(new LogicalPosition(destLine, 0)); PsiElement element = firstNonWhiteElement(offset, file, true); while (element != null && !(element instanceof PsiFile)) { @@ -133,7 +164,7 @@ class StatementMover extends LineMover { if (found) { statementToSurroundWithCodeBlock = elementToSurround; info.toMove = range; - int endLine = line; + int endLine = destLine; if (startLine > endLine) { int tmp = endLine; endLine = startLine; @@ -146,8 +177,8 @@ class StatementMover extends LineMover { } element = element.getParent(); } - line += down ? 1 : -1; - if (line == 0 || line >= editor.getDocument().getLineCount()) { + destLine += down ? 1 : -1; + if (destLine == 0 || destLine >= editor.getDocument().getLineCount()) { return false; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/DeannotateIntentionAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/DeannotateIntentionAction.java index 16cecf4d10d0..00c88892e0ee 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/DeannotateIntentionAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/DeannotateIntentionAction.java @@ -125,20 +125,18 @@ public class DeannotateIntentionAction implements IntentionAction { @Override public void invoke(@NotNull final Project project, Editor editor, final PsiFile file) throws IncorrectOperationException { final PsiModifierListOwner listOwner = getContainer(editor, file); + LOG.assertTrue(listOwner != null); final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project); final PsiAnnotation[] externalAnnotations = annotationsManager.findExternalAnnotations(listOwner); + LOG.assertTrue(externalAnnotations != null && externalAnnotations.length > 0); + if (externalAnnotations.length == 1) { + deannotate(externalAnnotations[0], project, file, annotationsManager, listOwner); + return; + } JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep(CodeInsightBundle.message("deannotate.intention.chooser.title"), externalAnnotations) { @Override public PopupStep onChosen(final PsiAnnotation selectedValue, final boolean finalChoice) { - new WriteCommandAction(project){ - @Override - protected void run(final Result result) throws Throwable { - final VirtualFile virtualFile = file.getVirtualFile(); - if (annotationsManager.deannotate(listOwner, selectedValue.getQualifiedName()) && virtualFile != null && virtualFile.isInLocalFileSystem()) { - UndoUtil.markPsiFileForUndo(file); - } - } - }.execute(); + deannotate(selectedValue, project, file, annotationsManager, listOwner); return PopupStep.FINAL_CHOICE; } @@ -152,6 +150,24 @@ public class DeannotateIntentionAction implements IntentionAction { }).showInBestPositionFor(editor); } + private void deannotate(final PsiAnnotation annotation, + final Project project, + final PsiFile file, + final ExternalAnnotationsManager annotationsManager, + final PsiModifierListOwner listOwner) { + new WriteCommandAction(project, getText()) { + @Override + protected void run(final Result result) throws Throwable { + final VirtualFile virtualFile = file.getVirtualFile(); + String qualifiedName = annotation.getQualifiedName(); + LOG.assertTrue(qualifiedName != null); + if (annotationsManager.deannotate(listOwner, qualifiedName) && virtualFile != null && virtualFile.isInLocalFileSystem()) { + UndoUtil.markPsiFileForUndo(file); + } + } + }.execute(); + } + @Override public boolean startInWriteAction() { return false; diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index 71c219343e19..067f5856e68f 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -49,6 +49,8 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspCodeBlock; import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy; import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil; +import com.intellij.psi.scope.processor.VariablesProcessor; +import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.util.PsiExpressionTrimRenderer; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -522,21 +524,9 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) return false; - PsiElement containerParent = tempContainer; - PsiElement lastScope = tempContainer; - while (true) { - if (containerParent instanceof PsiFile) break; - if (containerParent instanceof PsiMethod) break; - containerParent = containerParent.getParent(); - if (containerParent instanceof PsiCodeBlock) { - lastScope = containerParent; - } - } - - final ExpressionOccurrenceManager occurenceManager = new ExpressionOccurrenceManager(expr, lastScope, - NotInSuperCallOccurrenceFilter.INSTANCE); - final PsiExpression[] occurrences = occurenceManager.getOccurrences(); - final PsiElement anchorStatementIfAll = occurenceManager.getAnchorStatementForAll(); + final ExpressionOccurrenceManager occurrenceManager = createOccurrenceManager(expr, tempContainer); + final PsiExpression[] occurrences = occurrenceManager.getOccurrences(); + final PsiElement anchorStatementIfAll = occurrenceManager.getAnchorStatementForAll(); final LinkedHashMap> occurrencesMap = ContainerUtil.newLinkedHashMap(); @@ -550,8 +540,8 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { supportProvider.isInplaceIntroduceAvailable(expr, nameSuggestionContext) && !ApplicationManager.getApplication().isUnitTestMode() && !isInJspHolderMethod(expr); - final boolean inFinalContext = occurenceManager.isInFinalContext(); - final InputValidator validator = new InputValidator(this, project, anchorStatementIfAll, anchorStatement, occurenceManager); + final boolean inFinalContext = occurrenceManager.isInFinalContext(); + final InputValidator validator = new InputValidator(this, project, anchorStatementIfAll, anchorStatement, occurrenceManager); final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, originalType, expr, occurrences); final boolean[] wasSucceed = new boolean[]{true}; final Pass callback = new Pass() { @@ -613,6 +603,35 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { return wasSucceed[0]; } + private static ExpressionOccurrenceManager createOccurrenceManager(PsiExpression expr, PsiElement tempContainer) { + boolean skipForStatement = true; + final PsiForStatement forStatement = PsiTreeUtil.getParentOfType(expr, PsiForStatement.class); + if (forStatement != null) { + final VariablesProcessor variablesProcessor = new VariablesProcessor(false) { + @Override + protected boolean check(PsiVariable var, ResolveState state) { + return PsiTreeUtil.isAncestor(forStatement.getInitialization(), var, true); + } + }; + PsiScopesUtil.treeWalkUp(variablesProcessor, expr, null); + skipForStatement = variablesProcessor.size() == 0; + } + + PsiElement containerParent = tempContainer; + PsiElement lastScope = tempContainer; + while (true) { + if (containerParent instanceof PsiFile) break; + if (containerParent instanceof PsiMethod) break; + if (!skipForStatement && containerParent instanceof PsiForStatement) break; + containerParent = containerParent.getParent(); + if (containerParent instanceof PsiCodeBlock) { + lastScope = containerParent; + } + } + + return new ExpressionOccurrenceManager(expr, lastScope, NotInSuperCallOccurrenceFilter.INSTANCE); + } + private static boolean isInJspHolderMethod(PsiExpression expr) { final PsiElement parent1 = expr.getParent(); if (parent1 == null) { diff --git a/java/java-tests/testData/refactoring/introduceVariable/InsideForLoop.after.java b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoop.after.java new file mode 100644 index 000000000000..93ae967b3a49 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoop.after.java @@ -0,0 +1,11 @@ +public class C { + + public C(int[] ints) { + for (int i = 0; i < length && ints[i] > 0; i++) { + int temp = ints[i]; + System.out.println(temp); + System.out.println(temp); + System.out.println(temp); + } + } +} diff --git a/java/java-tests/testData/refactoring/introduceVariable/InsideForLoop.java b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoop.java new file mode 100644 index 000000000000..d5b64a2ebfac --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/InsideForLoop.java @@ -0,0 +1,10 @@ +public class C { + + public C(int[] ints) { + for (int i = 0; i < length && ints[i] > 0; i++) { + System.out.println(ints[i]); + System.out.println(ints[i]); + System.out.println(ints[i]); + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/JavaDocumentationTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/JavaDocumentationTest.groovy index 18a0a5f70b3d..78cea7063755 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/JavaDocumentationTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/JavaDocumentationTest.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -32,8 +32,10 @@ class Foo {{ }} ''' def ref = myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset) - assert CtrlMouseHandler.getInfo(ref.resolve(), ref.element) == """Bar - java.util.List<java.lang.String> foo (java.lang.String param)""" + assertEquals ( + 'Bar
List<java.lang.String> foo (java.lang.String param)', + CtrlMouseHandler.getInfo(ref.resolve(), ref.element) + ) } public void testGenericField() { @@ -45,8 +47,9 @@ class Foo {{ }} ''' def ref = myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset) - assert CtrlMouseHandler.getInfo(ref.resolve(), ref.element) == """Bar - java.lang.Integer field""" + assertEquals( + 'Bar
java.lang.Integer field', + CtrlMouseHandler.getInfo(ref.resolve(), ref.element) + ) } - } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java index 418a3353aa30..a66134f5cfc6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/ImportHelperTest.java @@ -429,4 +429,24 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase { } } + public void testAutoImportDoNotBreakCode() throws Throwable { + @NonNls String text = "package x; class S {{ S.\n Runnable r; }}"; + configureByText(StdFileTypes.JAVA, text); + + boolean old = CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY; + boolean opt = CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY; + CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = true; + CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY = true; + DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(true); + + try { + List errs = highlightErrors(); + assertEquals(1, errs.size()); + } + finally { + CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = old; + CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY = opt; + } + } + } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java index dda7a76bf962..2a9bcee98340 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java @@ -163,6 +163,10 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase { doTest(new MockIntroduceVariableHandler("temp", true, false, false, "int")); } + public void testInsideForLoop() throws Exception { + doTest(new MockIntroduceVariableHandler("temp", true, false, false, "int")); + } + public void testDuplicateGenericExpressions() throws Exception { doTest(new MockIntroduceVariableHandler("temp", true, false, false, "Foo2")); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index b4fb5421a5b9..9dfd02d0fe82 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -897,7 +897,7 @@ public class IncProjectBuilder { fsState.clearContextRoundData(context); fsState.clearContextChunk(context); - if (!Utils.ERRORS_DETECTED_KEY.get(context, Boolean.FALSE) && !context.getCancelStatus().isCanceled()) { + if (!Utils.errorsDetected(context) && !context.getCancelStatus().isCanceled()) { boolean marked = false; for (Module module : chunk.getModules()) { if (context.isMake()) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java index 541cd0ad756c..5c47fb4cdfd6 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java @@ -1,7 +1,6 @@ package org.jetbrains.jps.incremental; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jps.api.SequentialTaskExecutor; import org.jetbrains.jps.api.SharedThreadPool; import org.jetbrains.jps.incremental.java.JavaBuilder; import org.jetbrains.jps.incremental.resources.ResourcesBuilder; @@ -16,6 +15,6 @@ public class JavaBuilderService extends BuilderService { @NotNull @Override public List createModuleLevelBuilders() { - return Arrays.asList(new JavaBuilder(new SequentialTaskExecutor(SharedThreadPool.INSTANCE)), new ResourcesBuilder()); + return Arrays.asList(new JavaBuilder(SharedThreadPool.INSTANCE), new ResourcesBuilder()); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java index 6442ab7ea200..38cd4ef881e3 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/ModuleLevelBuilder.java @@ -64,7 +64,7 @@ public abstract class ModuleLevelBuilder extends Builder { * @throws Exception */ public final boolean updateMappings(CompileContext context, final Mappings delta, ModuleChunk chunk, Collection filesToCompile, Collection successfullyCompiled) throws IOException { - if (Utils.ERRORS_DETECTED_KEY.get(context, Boolean.FALSE)) { + if (Utils.errorsDetected(context)) { return false; } try { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/Utils.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/Utils.java index ba3dded12825..69b1fd812dcd 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/Utils.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/Utils.java @@ -134,4 +134,8 @@ public class Utils { final Map> removed = REMOVED_SOURCES_KEY.get(context); return removed != null && !removed.isEmpty(); } + + public static boolean errorsDetected(CompileContext context) { + return ERRORS_DETECTED_KEY.get(context, Boolean.FALSE); + } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 9095e219b767..056835759505 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -29,6 +29,7 @@ import org.jetbrains.ether.dependencyView.Mappings; import org.jetbrains.jps.*; import org.jetbrains.jps.api.GlobalOptions; import org.jetbrains.jps.api.RequestFuture; +import org.jetbrains.jps.api.SequentialTaskExecutor; import org.jetbrains.jps.cmdline.ProjectDescriptor; import org.jetbrains.jps.incremental.*; import org.jetbrains.jps.incremental.fs.RootDescriptor; @@ -105,7 +106,7 @@ public class JavaBuilder extends ModuleLevelBuilder { } } out.setTemp(isTemp); - if (!isTemp && out.getKind() == JavaFileObject.Kind.CLASS) { + if (!isTemp && out.getKind() == JavaFileObject.Kind.CLASS && !Utils.errorsDetected(context)) { final Callbacks.Backend callback = DELTA_MAPPINGS_CALLBACK_KEY.get(context); if (callback != null) { final ClassReader reader = new ClassReader(content.getBuffer(), content.getOffset(), content.getLength()); @@ -123,7 +124,7 @@ public class JavaBuilder extends ModuleLevelBuilder { public JavaBuilder(Executor tasksExecutor) { super(BuilderCategory.TRANSLATOR); - myTaskRunner = tasksExecutor; + myTaskRunner = new SequentialTaskExecutor(tasksExecutor); //add here class processors in the sequence they should be executed } diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java b/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java index 21fd56336451..66c561774f1c 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/StorageDumper.java @@ -3,9 +3,6 @@ package org.jetbrains.ether; import org.jetbrains.ether.dependencyView.Mappings; import java.io.File; -import java.io.PrintStream; -import java.text.SimpleDateFormat; -import java.util.Date; /** * Created with IntelliJ IDEA. @@ -110,24 +107,29 @@ public class StorageDumper { env.report(); - final String path = env.getProjectPath(); + final String dataPath = env.getProjectPath(); final String oath = env.getOutputPath(); - if (path == null) { + if (dataPath == null) { System.err.println("No project path specified."); } else { try { - final String outputPath = (oath == null ? "" : oath) + File.separator + "snapshot-" + new SimpleDateFormat("dd-MM-yy(hh:mm:ss)").format(new Date()) + ".log"; - final File dataStorageRoot = new File(path + File.separator + "mappings"); + final File parent = new File(oath == null ? "" : oath); + final File dataStorageRoot = new File(dataPath, "mappings"); final Mappings mappings = new Mappings(dataStorageRoot, true); - final PrintStream p = new PrintStream(outputPath); - - mappings.toStream(p); - mappings.close(); - - p.close(); + try { + //final File outputPath = new File(parent, "snapshot-" + new SimpleDateFormat("dd-MM-yy(hh-mm-ss)").format(new Date()) + ".log"); + //FileUtil.createIfDoesntExist(outputPath); + //final PrintStream p = new PrintStream(outputPath); + //mappings.toStream(p); + //p.close(); + mappings.toStream(parent); + } + finally { + mappings.close(); + } } catch (Exception e) { throw new RuntimeException(e); diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsFacet.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsFacet.java index 452484494845..d27c56e3fd0c 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/module/JpsFacet.java +++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsFacet.java @@ -1,6 +1,8 @@ package org.jetbrains.jps.model.module; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElementProperties; import org.jetbrains.jps.model.JpsNamedElement; import org.jetbrains.jps.model.JpsReferenceableElement; @@ -16,5 +18,17 @@ public interface JpsFacet extends JpsNamedElement, JpsReferenceableElement getType(); + @Nullable +

P getProperties(@NotNull JpsFacetType

type); + void delete(); + + @NotNull + @Override + JpsFacetReference createReference(); + + void setParentFacet(@NotNull JpsFacet facet); + + @Nullable + JpsFacet getParentFacet(); } diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsFacetReference.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsFacetReference.java new file mode 100644 index 000000000000..e8e122393867 --- /dev/null +++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsFacetReference.java @@ -0,0 +1,9 @@ +package org.jetbrains.jps.model.module; + +import org.jetbrains.jps.model.JpsElementReference; + +/** + * @author nik + */ +public interface JpsFacetReference extends JpsElementReference { +} diff --git a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModule.java b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModule.java index b020d641ca6f..6204da88f0a6 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/module/JpsModule.java +++ b/jps/model-api/src/org/jetbrains/jps/model/module/JpsModule.java @@ -33,7 +33,8 @@ public interface JpsModule extends JpsNamedElement, JpsReferenceableElement type); +

+ JpsFacet addFacet(@NotNull String name, @NotNull JpsFacetType

type, @NotNull P properties); @NotNull List getFacets(); diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsFacetImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsFacetImpl.java index 2932b7721944..ddfd9963154e 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsFacetImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsFacetImpl.java @@ -1,12 +1,16 @@ package org.jetbrains.jps.model.module.impl; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.JpsElementCollection; -import org.jetbrains.jps.model.JpsElementReference; +import org.jetbrains.jps.model.JpsElementKind; +import org.jetbrains.jps.model.JpsElementProperties; +import org.jetbrains.jps.model.impl.JpsElementKindBase; import org.jetbrains.jps.model.impl.JpsNamedCompositeElementBase; import org.jetbrains.jps.model.impl.JpsTypedDataImpl; import org.jetbrains.jps.model.impl.JpsTypedDataKind; import org.jetbrains.jps.model.module.JpsFacet; +import org.jetbrains.jps.model.module.JpsFacetReference; import org.jetbrains.jps.model.module.JpsFacetType; import org.jetbrains.jps.model.module.JpsModule; @@ -15,10 +19,12 @@ import org.jetbrains.jps.model.module.JpsModule; */ public class JpsFacetImpl extends JpsNamedCompositeElementBase implements JpsFacet { private static final JpsTypedDataKind> TYPED_DATA_KIND = new JpsTypedDataKind>(); + private static final JpsElementKind PARENT_FACET_REFERENCE = new JpsElementKindBase("parent facet"); - public JpsFacetImpl(JpsFacetType facetType, @NotNull String name) { + public

JpsFacetImpl(JpsFacetType facetType, @NotNull String name, @NotNull P properties) { super(name); - myContainer.setChild(TYPED_DATA_KIND, new JpsTypedDataImpl>(facetType, facetType.createDefaultProperties())); + myContainer.setChild(TYPED_DATA_KIND, new JpsTypedDataImpl>(facetType, properties)); + myContainer.setChild(JpsFacetKind.COLLECTION_KIND); } private JpsFacetImpl(JpsNamedCompositeElementBase original) { @@ -37,6 +43,23 @@ public class JpsFacetImpl extends JpsNamedCompositeElementBase imp return myContainer.getChild(TYPED_DATA_KIND).getType(); } + @Override + public

P getProperties(@NotNull JpsFacetType

type) { + return myContainer.getChild(TYPED_DATA_KIND).getProperties(type); + } + + @Override + public void setParentFacet(@NotNull JpsFacet facet) { + myContainer.setChild(PARENT_FACET_REFERENCE, facet.createReference()); + } + + @Override + @Nullable + public JpsFacet getParentFacet() { + final JpsFacetReference reference = myContainer.getChild(PARENT_FACET_REFERENCE); + return reference != null ? reference.resolve() : null; + } + @Override public JpsModule getModule() { return myParent != null ? (JpsModule)myParent.getParent() : null; @@ -44,7 +67,7 @@ public class JpsFacetImpl extends JpsNamedCompositeElementBase imp @NotNull @Override - public JpsElementReference createReference() { + public JpsFacetReference createReference() { return new JpsFacetReferenceImpl(getName(), getModule().createReference()); } diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsFacetReferenceImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsFacetReferenceImpl.java index 02509bb6472c..0f67615a4f38 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsFacetReferenceImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsFacetReferenceImpl.java @@ -5,12 +5,13 @@ import org.jetbrains.jps.model.JpsElementReference; import org.jetbrains.jps.model.JpsModel; import org.jetbrains.jps.model.impl.JpsNamedElementReferenceBase; import org.jetbrains.jps.model.module.JpsFacet; +import org.jetbrains.jps.model.module.JpsFacetReference; import org.jetbrains.jps.model.module.JpsModuleReference; /** * @author nik */ -public class JpsFacetReferenceImpl extends JpsNamedElementReferenceBase { +public class JpsFacetReferenceImpl extends JpsNamedElementReferenceBase implements JpsFacetReference { public JpsFacetReferenceImpl(String facetName, JpsModuleReference moduleReference) { super(JpsFacetKind.COLLECTION_KIND, facetName, moduleReference); } diff --git a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleImpl.java index 27a818ec7182..ba6918f67895 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/module/impl/JpsModuleImpl.java @@ -92,10 +92,10 @@ public class JpsModuleImpl extends JpsNamedCompositeElementBase i } } - @Override @NotNull - public JpsFacet addFacet(@NotNull String name, @NotNull JpsFacetType type) { - return myContainer.getChild(JpsFacetKind.COLLECTION_KIND).addChild(new JpsFacetImpl(type, name)); + @Override + public

JpsFacet addFacet(@NotNull String name, @NotNull JpsFacetType

type, @NotNull P properties) { + return myContainer.getChild(JpsFacetKind.COLLECTION_KIND).addChild(new JpsFacetImpl(type, name, properties)); } @NotNull diff --git a/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsFacetTest.java b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsFacetTest.java index 09e271aacf79..6c4b9924babb 100644 --- a/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsFacetTest.java +++ b/jps/model-impl/testSrc/org/jetbrains/jps/model/JpsFacetTest.java @@ -12,12 +12,12 @@ import org.jetbrains.jps.model.module.JpsModule; public class JpsFacetTest extends JpsModelTestCase { public void testAddFacet() { final JpsModule m = myModel.getProject().addModule("m", JpsJavaModuleType.INSTANCE); - m.addFacet("f", MY_FACET_TYPE); + m.addFacet("f", MY_FACET_TYPE, DummyJpsElementProperties.INSTANCE); assertEquals("f", assertOneElement(m.getFacets()).getName()); } public void testCreateReferenceByFacet() { - final JpsFacet facet = myModel.getProject().addModule("m", JpsJavaModuleType.INSTANCE).addFacet("f", MY_FACET_TYPE); + final JpsFacet facet = myModel.getProject().addModule("m", JpsJavaModuleType.INSTANCE).addFacet("f", MY_FACET_TYPE, DummyJpsElementProperties.INSTANCE); final JpsElementReference reference = facet.createReference().asExternal(myModel); assertSame(facet, reference.resolve()); } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModelLoaderExtension.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModelLoaderExtension.java index 420364c6fad7..4778e4fa67e6 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModelLoaderExtension.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsModelLoaderExtension.java @@ -4,13 +4,12 @@ import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.JpsCompositeElement; -import org.jetbrains.jps.model.JpsElementProperties; import org.jetbrains.jps.model.JpsElementReference; import org.jetbrains.jps.model.library.JpsOrderRootType; import org.jetbrains.jps.model.library.JpsSdkType; import org.jetbrains.jps.model.module.JpsDependencyElement; import org.jetbrains.jps.model.module.JpsModule; -import org.jetbrains.jps.model.module.JpsModuleType; +import org.jetbrains.jps.model.serialization.facet.JpsFacetPropertiesLoader; import java.util.Collections; import java.util.List; @@ -41,16 +40,6 @@ public abstract class JpsModelLoaderExtension { return null; } - @Nullable - public JpsModuleType getModuleType(@NotNull String typeId) { - return null; - } - - @Nullable - public

P loadModuleProperties(JpsModuleType

type, Element moduleRoot) { - return null; - } - @NotNull public List> getModulePropertiesLoaders() { return Collections.emptyList(); @@ -66,6 +55,10 @@ public abstract class JpsModelLoaderExtension { return Collections.emptyList(); } + public List> getFacetPropertiesLoaders() { + return Collections.emptyList(); + } + @Nullable public JpsOrderRootType getSdkRootType(@NotNull String typeId) { return null; diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java index 163327d57733..a079f41e3efb 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java @@ -12,6 +12,7 @@ import org.jetbrains.jps.model.JpsProject; import org.jetbrains.jps.model.java.JpsJavaModuleType; import org.jetbrains.jps.model.library.JpsSdkType; import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.model.serialization.facet.JpsFacetLoader; import org.jetbrains.jps.service.JpsServiceManager; import java.io.File; @@ -134,6 +135,7 @@ public class JpsProjectLoader extends JpsLoaderBase { final JpsModulePropertiesLoader loader = getModulePropertiesLoader(typeId); final JpsModule module = createModule(name, moduleRoot, loader); JpsModuleLoader.loadRootModel(module, findComponent(moduleRoot, "NewModuleRootManager")); + JpsFacetLoader.loadFacets(module, findComponent(moduleRoot, "FacetManager")); return module; } diff --git a/platform/lang-impl/src/com/intellij/facet/impl/FacetManagerState.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/FacetManagerState.java similarity index 95% rename from platform/lang-impl/src/com/intellij/facet/impl/FacetManagerState.java rename to jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/FacetManagerState.java index a748170b04b1..8a97d3156576 100644 --- a/platform/lang-impl/src/com/intellij/facet/impl/FacetManagerState.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/FacetManagerState.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.intellij.facet.impl; +package org.jetbrains.jps.model.serialization.facet; import com.intellij.util.xmlb.annotations.AbstractCollection; import com.intellij.util.xmlb.annotations.Property; diff --git a/platform/lang-impl/src/com/intellij/facet/impl/FacetState.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/FacetState.java similarity index 87% rename from platform/lang-impl/src/com/intellij/facet/impl/FacetState.java rename to jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/FacetState.java index 74809380cbf5..434a1789544e 100644 --- a/platform/lang-impl/src/com/intellij/facet/impl/FacetState.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/FacetState.java @@ -14,9 +14,8 @@ * limitations under the License. */ -package com.intellij.facet.impl; +package org.jetbrains.jps.model.serialization.facet; -import com.intellij.facet.FacetManagerImpl; import com.intellij.util.xmlb.annotations.Attribute; import com.intellij.util.xmlb.annotations.Tag; import com.intellij.util.xmlb.annotations.AbstractCollection; @@ -29,24 +28,24 @@ import java.util.ArrayList; /** * @author nik */ -@Tag(FacetManagerImpl.FACET_ELEMENT) +@Tag(JpsFacetLoader.FACET_ELEMENT) public class FacetState { private String myFacetType; private String myName; private Element myConfiguration; private List mySubFacets = new ArrayList(); - @Attribute(FacetManagerImpl.TYPE_ATTRIBUTE) + @Attribute(JpsFacetLoader.TYPE_ATTRIBUTE) public String getFacetType() { return myFacetType; } - @Attribute(FacetManagerImpl.NAME_ATTRIBUTE) + @Attribute(JpsFacetLoader.NAME_ATTRIBUTE) public String getName() { return myName; } - @Tag(FacetManagerImpl.CONFIGURATION_ELEMENT) + @Tag(JpsFacetLoader.CONFIGURATION_ELEMENT) public Element getConfiguration() { return myConfiguration; } diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/JpsFacetLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/JpsFacetLoader.java new file mode 100644 index 000000000000..dec98e54926c --- /dev/null +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/JpsFacetLoader.java @@ -0,0 +1,62 @@ +package org.jetbrains.jps.model.serialization.facet; + +import com.intellij.util.xmlb.XmlSerializer; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsElementProperties; +import org.jetbrains.jps.model.module.JpsFacet; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.model.serialization.JpsModelLoaderExtension; +import org.jetbrains.jps.service.JpsServiceManager; + +import java.util.List; + +/** + * @author nik + */ +public class JpsFacetLoader { + @NonNls public static final String FACET_ELEMENT = "facet"; + @NonNls public static final String TYPE_ATTRIBUTE = "type"; + @NonNls public static final String CONFIGURATION_ELEMENT = "configuration"; + @NonNls public static final String NAME_ATTRIBUTE = "name"; + + public static void loadFacets(JpsModule module, @Nullable Element facetManagerElement) { + if (facetManagerElement == null) return; + final FacetManagerState state = XmlSerializer.deserialize(facetManagerElement, FacetManagerState.class); + if (state != null) { + addFacets(module, state.getFacets(), null); + } + } + + private static void addFacets(JpsModule module, List facets, @Nullable final JpsFacet parentFacet) { + for (FacetState facetState : facets) { + final JpsFacetPropertiesLoader loader = getFacetPropertiesLoader(facetState.getFacetType()); + if (loader != null) { + final JpsFacet facet = addFacet(module, loader, facetState); + if (parentFacet != null) { + facet.setParentFacet(parentFacet); + } + addFacets(module, facetState.getSubFacets(), facet); + } + } + } + + private static

JpsFacet addFacet(JpsModule module, JpsFacetPropertiesLoader

loader, FacetState facet) { + return module.addFacet(facet.getName(), loader.getType(), loader.loadProperties(facet.getConfiguration())); + } + + @Nullable + private static JpsFacetPropertiesLoader getFacetPropertiesLoader(@NotNull String typeId) { + for (JpsModelLoaderExtension extension : JpsServiceManager.getInstance().getExtensions(JpsModelLoaderExtension.class)) { + for (JpsFacetPropertiesLoader loader : extension.getFacetPropertiesLoaders()) { + if (loader.getTypeId().equals(typeId)) { + return loader; + } + } + } + return null; + } + +} diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/JpsFacetPropertiesLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/JpsFacetPropertiesLoader.java new file mode 100644 index 000000000000..4fb3d5cca0c9 --- /dev/null +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/facet/JpsFacetPropertiesLoader.java @@ -0,0 +1,18 @@ +package org.jetbrains.jps.model.serialization.facet; + +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.model.JpsElementProperties; +import org.jetbrains.jps.model.module.JpsFacetType; +import org.jetbrains.jps.model.serialization.JpsElementPropertiesLoader; + +/** + * @author nik + */ +public abstract class JpsFacetPropertiesLoader

extends JpsElementPropertiesLoader> { + public JpsFacetPropertiesLoader(JpsFacetType

type, String typeId) { + super(type, typeId); + } + + public abstract P loadProperties(@NotNull Element facetConfigurationElement); +} diff --git a/jps/model-serialization/testData/iprProject/iprProject.iml b/jps/model-serialization/testData/iprProject/iprProject.iml index dbf84a250f51..814115b795e5 100644 --- a/jps/model-serialization/testData/iprProject/iprProject.iml +++ b/jps/model-serialization/testData/iprProject/iprProject.iml @@ -9,7 +9,6 @@ - diff --git a/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsGlobalSerializationTest.java b/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsGlobalSerializationTest.java index d37003265948..aa96a655b161 100644 --- a/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsGlobalSerializationTest.java +++ b/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsGlobalSerializationTest.java @@ -10,7 +10,7 @@ import java.util.List; */ public class JpsGlobalSerializationTest extends JpsSerializationTestCase { public void testLoadSdks() throws IOException { - JpsGlobalLoader.loadGlobalSettings(myModel.getGlobal(), getTestDataPath("config/options")); + JpsGlobalLoader.loadGlobalSettings(myModel.getGlobal(), getTestDataFileAbsolutePath("jps/model-serialization/testData/config/options")); final List libraries = myModel.getGlobal().getLibraryCollection().getLibraries(); assertEquals(3, libraries.size()); assertEquals("Gant", libraries.get(0).getName()); diff --git a/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsModuleSerializationTest.java b/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsModuleSerializationTest.java index 06f9ec2bead8..3405abb4b311 100644 --- a/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsModuleSerializationTest.java +++ b/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsModuleSerializationTest.java @@ -1,11 +1,11 @@ package org.jetbrains.jps.model.serialization; +import com.intellij.openapi.application.PathManager; +import org.jetbrains.jps.model.JpsProject; import org.jetbrains.jps.model.java.JpsJavaSdkType; import org.jetbrains.jps.model.library.JpsLibrary; import org.jetbrains.jps.model.module.*; -import java.io.IOException; -import java.util.Collections; import java.util.List; /** @@ -13,7 +13,7 @@ import java.util.List; */ public class JpsModuleSerializationTest extends JpsSerializationTestCase { public void test() { - loadProject("iprProject/iprProject.ipr"); + loadProject("/jps/model-serialization/testData/iprProject/iprProject.ipr"); final JpsModule module = assertOneElement(myModel.getProject().getModules()); assertEquals("iprProject", module.getName()); @@ -28,14 +28,12 @@ public class JpsModuleSerializationTest extends JpsSerializationTestCase { assertInstanceOf(dependencies.get(2), JpsLibraryDependency.class); assertInstanceOf(dependencies.get(3), JpsLibraryDependency.class); } - - private void loadProject(final String path) { - try { - final String projectPath = getTestDataPath(path); - JpsProjectLoader.loadProject(myModel.getProject(), Collections.emptyMap(), projectPath); - } - catch (IOException e) { - throw new RuntimeException(e); - } + + public void _testLoadIdeaProject() { + long start = System.currentTimeMillis(); + final JpsProject project = myModel.getProject(); + loadProject(PathManager.getHomePath()); + assertTrue(project.getModules().size() > 0); + System.out.println("Time: " + (System.currentTimeMillis() - start)); } } diff --git a/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsSerializationTestCase.java b/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsSerializationTestCase.java index 82a496ba39f9..59335b6a4ce4 100644 --- a/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsSerializationTestCase.java +++ b/jps/model-serialization/testSrc/org/jetbrains/jps/model/serialization/JpsSerializationTestCase.java @@ -2,20 +2,48 @@ package org.jetbrains.jps.model.serialization; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.io.FileUtilRt; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.util.PathUtil; import org.jetbrains.jps.model.JpsModelTestCase; import java.io.File; +import java.io.IOException; +import java.util.Collections; /** * @author nik */ public abstract class JpsSerializationTestCase extends JpsModelTestCase { - protected static String getTestDataPath(String relativePath) { - File baseDir = new File(PathManager.getHomePath()); - final File communityDir = new File(baseDir, "community"); - if (communityDir.exists()) { - baseDir = communityDir; + private String myProjectHomePath; + + protected void loadProject(final String relativePath) { + final String path = getTestDataFileAbsolutePath(relativePath); + + myProjectHomePath = FileUtilRt.toSystemIndependentName(path); + if (myProjectHomePath.endsWith(".ipr")) { + myProjectHomePath = PathUtil.getParentPath(myProjectHomePath); } - return FileUtilRt.toSystemIndependentName(baseDir.getAbsolutePath()) + "/jps/model-serialization/testData/" + relativePath; + try { + JpsProjectLoader.loadProject(myModel.getProject(), Collections.emptyMap(), path); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected String getUrl(String relativePath) { + return VfsUtilCore.pathToUrl(myProjectHomePath + "/" + relativePath); + } + + protected static String getTestDataFileAbsolutePath(String relativePath) { + File baseDir = new File(PathManager.getHomePath()); + File file = new File(baseDir, FileUtilRt.toSystemDependentName(relativePath)); + if (!file.exists()) { + final File communityDir = new File(baseDir, "community"); + if (communityDir.exists()) { + file = new File(communityDir, FileUtilRt.toSystemDependentName(relativePath)); + } + } + return FileUtilRt.toSystemDependentName(file.getAbsolutePath()); } } diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/ClassRepr.java b/jps/model/src/org/jetbrains/ether/dependencyView/ClassRepr.java index 36b5a6b26087..ed580e8d1272 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/ClassRepr.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/ClassRepr.java @@ -179,18 +179,18 @@ public class ClassRepr extends Proto { } public void updateClassUsages(final DependencyContext context, final Set s) { - mySuperClass.updateClassUsages(context, myName, s); + mySuperClass.updateClassUsages(context, name, s); for (TypeRepr.AbstractType t : myInterfaces) { - t.updateClassUsages(context, myName, s); + t.updateClassUsages(context, name, s); } for (MethodRepr m : myMethods) { - m.updateClassUsages(context, myName, s); + m.updateClassUsages(context, name, s); } for (FieldRepr f : myFields) { - f.updateClassUsages(context, myName, s); + f.updateClassUsages(context, name, s); } } @@ -264,7 +264,7 @@ public class ClassRepr extends Proto { } public boolean isAnnotation() { - return (myAccess & Opcodes.ACC_ANNOTATION) > 0; + return (access & Opcodes.ACC_ANNOTATION) > 0; } @Override @@ -275,22 +275,22 @@ public class ClassRepr extends Proto { ClassRepr classRepr = (ClassRepr)o; if (myFileName != classRepr.myFileName) return false; - if (myName != classRepr.myName) return false; + if (name != classRepr.name) return false; return true; } @Override public int hashCode() { - return 31 * myFileName + myName; + return 31 * myFileName + name; } public UsageRepr.Usage createUsage() { - return UsageRepr.createClassUsage(myContext, myName); + return UsageRepr.createClassUsage(myContext, name); } public String getPackageName() { - return getPackageName(myName); + return getPackageName(name); } public String getPackageName(final int s) { @@ -309,7 +309,7 @@ public class ClassRepr extends Proto { public FieldRepr findField(final int name) { for (FieldRepr f : myFields) { - if (f.myName == name) { + if (f.name == name) { return f; } } @@ -390,11 +390,11 @@ public class ClassRepr extends Proto { Arrays.sort(fs, new Comparator() { @Override public int compare(final FieldRepr o1, final FieldRepr o2) { - if (o1.myName == o2.myName) { + if (o1.name == o2.name) { return o1.myType.getDescr(context).compareTo(o2.myType.getDescr(context)); } - return context.getValue(o1.myName).compareTo(context.getValue(o2.myName)); + return context.getValue(o1.name).compareTo(context.getValue(o2.name)); } }); for (final FieldRepr f : fs) { @@ -407,7 +407,7 @@ public class ClassRepr extends Proto { Arrays.sort(ms, new Comparator() { @Override public int compare(final MethodRepr o1, final MethodRepr o2) { - if (o1.myName == o2.myName) { + if (o1.name == o2.name) { final String d1 = o1.myType.getDescr(context); final String d2 = o2.myType.getDescr(context); @@ -438,7 +438,7 @@ public class ClassRepr extends Proto { return c; } - return context.getValue(o1.myName).compareTo(context.getValue(o2.myName)); + return context.getValue(o1.name).compareTo(context.getValue(o2.name)); } }); for (final MethodRepr m : ms) { diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/FieldRepr.java b/jps/model/src/org/jetbrains/ether/dependencyView/FieldRepr.java index 822848b0d280..55f65321b969 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/FieldRepr.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/FieldRepr.java @@ -34,12 +34,12 @@ class FieldRepr extends ProtoMember { final FieldRepr fieldRepr = (FieldRepr)o; - return myName == fieldRepr.myName; + return name == fieldRepr.name; } @Override public int hashCode() { - return 31 * myName; + return 31 * name; } public static DataExternalizer externalizer(final DependencyContext context) { @@ -57,10 +57,10 @@ class FieldRepr extends ProtoMember { } public UsageRepr.Usage createUsage(final DependencyContext context, final int owner) { - return UsageRepr.createFieldUsage(context, myName, owner, context.get(myType.getDescr(context))); + return UsageRepr.createFieldUsage(context, name, owner, context.get(myType.getDescr(context))); } public UsageRepr.Usage createAssignUsage(final DependencyContext context, final int owner) { - return UsageRepr.createFieldAssignUsage(context, myName, owner, context.get(myType.getDescr(context))); + return UsageRepr.createFieldAssignUsage(context, name, owner, context.get(myType.getDescr(context))); } } diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/IntIntPersistentMaplet.java b/jps/model/src/org/jetbrains/ether/dependencyView/IntIntPersistentMaplet.java index c1b684503a20..6a814bfde0ca 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/IntIntPersistentMaplet.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/IntIntPersistentMaplet.java @@ -86,7 +86,7 @@ public class IntIntPersistentMaplet extends IntIntMaplet { @Override public int get(final int key) { final Object obj = myCache.get(key); - return obj == NULL_OBJ? -1 : (Integer)obj; + return obj == NULL_OBJ? 0 : (Integer)obj; } @Override diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java index 7d268958619b..5fd6228acb02 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Mappings.java @@ -5,13 +5,17 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.io.IntInlineKeyDescriptor; -import gnu.trove.*; +import gnu.trove.TIntHashSet; +import gnu.trove.TIntIntProcedure; +import gnu.trove.TIntObjectProcedure; +import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.ClassReader; import org.jetbrains.asm4.Opcodes; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; import java.lang.annotation.RetentionPolicy; @@ -116,10 +120,8 @@ public class Mappings { myClassToSourceFile = new IntIntTransientMaplet(); } else { - myClassToSubclasses = - new IntIntPersistentMultiMaplet(DependencyContext.getTableFile(myRootDir, CLASS_TO_SUBCLASSES), INT_KEY_DESCRIPTOR); - myClassToClassDependency = - new IntIntPersistentMultiMaplet(DependencyContext.getTableFile(myRootDir, CLASS_TO_CLASS), INT_KEY_DESCRIPTOR); + myClassToSubclasses = new IntIntPersistentMultiMaplet(DependencyContext.getTableFile(myRootDir, CLASS_TO_SUBCLASSES), INT_KEY_DESCRIPTOR); + myClassToClassDependency = new IntIntPersistentMultiMaplet(DependencyContext.getTableFile(myRootDir, CLASS_TO_CLASS), INT_KEY_DESCRIPTOR); mySourceFileToClasses = new IntObjectPersistentMultiMaplet( DependencyContext.getTableFile(myRootDir, SOURCE_TO_CLASS), INT_KEY_DESCRIPTOR, ClassRepr.externalizer(myContext), ourClassSetConstructor @@ -159,7 +161,7 @@ public class Mappings { if (reprs != null) { for (ClassRepr repr : reprs) { - if (repr.myName == name) { + if (repr.name == name) { return repr; } } @@ -188,7 +190,11 @@ public class Mappings { } private static class Option { - final X myValue; + static final Option TRUE = new Option(Boolean.TRUE); + static final Option FALSE = new Option(Boolean.FALSE); + static final Option UNKNOWN = new Option(); + + private final X myValue; Option(final X value) { this.myValue = value; @@ -198,15 +204,11 @@ public class Mappings { myValue = null; } - boolean isNone() { - return myValue == null; - } - - boolean isValue() { + public boolean isDefined() { return myValue != null; } - X value() { + public X value() { return myValue; } } @@ -234,7 +236,7 @@ public class Mappings { final Set deleted = myDeletedClasses; if (deleted != null) { for (ClassRepr repr : deleted) { - myChangedClasses.remove(repr.myName); + myChangedClasses.remove(repr.name); } } @@ -243,8 +245,8 @@ public class Mappings { } } - private static ClassRepr myMockClass = null; - private static MethodRepr myMockMethod = null; + private static final ClassRepr MOCK_CLASS = null; + private static final MethodRepr MOCK_METHOD = null; private class Util { final Mappings myDelta; @@ -258,7 +260,7 @@ public class Mappings { } void appendDependents(final ClassRepr c, final TIntHashSet result) { - final TIntHashSet depClasses = myDelta.myClassToClassDependency.get(c.myName); + final TIntHashSet depClasses = myDelta.myClassToClassDependency.get(c.name); if (depClasses != null) { addAll(result, depClasses); @@ -275,7 +277,7 @@ public class Mappings { for (Object o : members) { final ProtoMember m = (ProtoMember)o; - if (m.myName == name) { + if (m.name == name) { return; } } @@ -317,13 +319,13 @@ public class Mappings { return new MethodRepr.Predicate() { @Override public boolean satisfy(final MethodRepr m) { - if (m.myName == myInitName || m.myName != than.myName || m.myArgumentTypes.length != than.myArgumentTypes.length) { + if (m.name == myInitName || m.name != than.name || m.myArgumentTypes.length != than.myArgumentTypes.length) { return false; } for (int i = 0; i < than.myArgumentTypes.length; i++) { final Option subtypeOf = isSubtypeOf(than.myArgumentTypes[i], m.myArgumentTypes[i]); - if (subtypeOf.isValue() && !subtypeOf.value()) { + if (subtypeOf.isDefined() && !subtypeOf.value()) { return false; } } @@ -339,7 +341,7 @@ public class Mappings { new Object() { public void run(final ClassRepr c) { - final TIntHashSet subClasses = myClassToSubclasses.get(c.myName); + final TIntHashSet subClasses = myClassToSubclasses.get(c.name); if (subClasses != null) { subClasses.forEach(new TIntProcedure() { @@ -373,7 +375,7 @@ public class Mappings { return result; } - Collection> findOverridenMethods(final MethodRepr m, final ClassRepr c) { + Collection> findOverriddenMethods(final MethodRepr m, final ClassRepr c) { return findOverridenMethods(m, c, false); } @@ -405,7 +407,7 @@ public class Mappings { } } else { - result.add(new Pair(myMockMethod, myMockClass)); + result.add(new Pair(MOCK_METHOD, MOCK_CLASS)); } } } @@ -422,7 +424,7 @@ public class Mappings { return result; } - Collection> findOverridenFields(final FieldRepr f, final ClassRepr c) { + Collection> findOverriddenFields(final FieldRepr f, final ClassRepr c) { final Set> result = new HashSet>(); new Object() { @@ -436,7 +438,7 @@ public class Mappings { boolean cont = true; if (r.getFields().contains(f)) { - final FieldRepr ff = r.findField(f.myName); + final FieldRepr ff = r.findField(f.name); if (ff != null) { if (isVisibleIn(r, ff, c)) { @@ -457,6 +459,7 @@ public class Mappings { return result; } + @Nullable ClassRepr reprByName(final int name) { if (myDelta != null) { final ClassRepr r = myDelta.getReprByName(name); @@ -471,7 +474,7 @@ public class Mappings { Option isInheritorOf(final int who, final int whom) { if (who == whom) { - return new Option(true); + return Option.TRUE; } final ClassRepr repr = reprByName(who); @@ -479,22 +482,22 @@ public class Mappings { if (repr != null) { for (int s : repr.getSupers()) { final Option inheritorOf = isInheritorOf(s, whom); - if (inheritorOf.isValue() && inheritorOf.value()) { + if (inheritorOf.isDefined() && inheritorOf.value()) { return inheritorOf; } } } - return new Option(); + return Option.UNKNOWN; } Option isSubtypeOf(final TypeRepr.AbstractType who, final TypeRepr.AbstractType whom) { if (who.equals(whom)) { - return new Option(true); + return Option.TRUE; } if (who instanceof TypeRepr.PrimitiveType || whom instanceof TypeRepr.PrimitiveType) { - return new Option(false); + return Option.FALSE; } if (who instanceof TypeRepr.ArrayType) { @@ -505,17 +508,17 @@ public class Mappings { final String descr = whom.getDescr(myContext); if (descr.equals("Ljava/lang/Cloneable") || descr.equals("Ljava/lang/Object") || descr.equals("Ljava/io/Serializable")) { - return new Option(true); + return Option.TRUE; } - return new Option(false); + return Option.FALSE; } if (whom instanceof TypeRepr.ClassType) { return isInheritorOf(((TypeRepr.ClassType)who).myClassName, ((TypeRepr.ClassType)whom).myClassName); } - return new Option(false); + return Option.FALSE; } boolean methodVisible(final int className, final MethodRepr m) { @@ -526,7 +529,7 @@ public class Mappings { return true; } - return findOverridenMethods(m, r).size() > 0; + return findOverriddenMethods(m, r).size() > 0; } return false; @@ -540,7 +543,7 @@ public class Mappings { return true; } - return findOverridenFields(field, r).size() > 0; + return findOverriddenFields(field, r).size() > 0; } return true; @@ -555,7 +558,7 @@ public class Mappings { final int fileName = myClassToSourceFile.get(className); - if (fileName < 0) { + if (fileName <= 0) { debug("No source file detected for class ", className); debug("End of affectSubclasses"); return; @@ -569,7 +572,7 @@ public class Mappings { final ClassRepr classRepr = reprByName(className); if (classRepr != null) { - debug("Added class usage for ", classRepr.myName); + debug("Added class usage for ", classRepr.name); affectedUsages.add(classRepr.createUsage()); } } @@ -596,13 +599,13 @@ public class Mappings { } void affectFieldUsages(final FieldRepr field, - final TIntHashSet subclasses, + final TIntHashSet classes, final UsageRepr.Usage rootUsage, final Set affectedUsages, final TIntHashSet dependents) { affectedUsages.add(rootUsage); - subclasses.forEach(new TIntProcedure() { + classes.forEach(new TIntProcedure() { @Override public boolean execute(int p) { final TIntHashSet deps = myClassToClassDependency.get(p); @@ -612,8 +615,7 @@ public class Mappings { } debug("Affect field usage referenced of class ", p); - affectedUsages - .add(rootUsage instanceof UsageRepr.FieldAssignUsage ? field.createAssignUsage(myContext, p) : field.createUsage(myContext, p)); + affectedUsages.add(rootUsage instanceof UsageRepr.FieldAssignUsage ? field.createAssignUsage(myContext, p) : field.createUsage(myContext, p)); return true; } }); @@ -647,12 +649,11 @@ public class Mappings { } } - void affectAll(final int className, final Collection affectedFiles, final DependentFilesFilter filter) { - final TIntHashSet dependants = myClassToClassDependency.get(className); - - if (dependants != null) { - final int sourceFile = myClassToSourceFile.get(className); - if (sourceFile > 0) { + void affectAll(final int className, final Collection affectedFiles, @Nullable final DependentFilesFilter filter) { + final int sourceFile = myClassToSourceFile.get(className); + if (sourceFile > 0) { + final TIntHashSet dependants = myClassToClassDependency.get(className); + if (dependants != null) { dependants.forEach(new TIntProcedure() { @Override public boolean execute(int depClass) { @@ -699,7 +700,7 @@ public class Mappings { @Override public boolean checkResidence(final int residence) { final Option inheritorOf = isInheritorOf(residence, rootClass); - return inheritorOf.isNone() || !inheritorOf.value() || super.checkResidence(residence); + return !inheritorOf.isDefined() || !inheritorOf.value() || super.checkResidence(residence); } } @@ -733,25 +734,21 @@ public class Mappings { } private static boolean isVisibleIn(final ClassRepr c, final ProtoMember m, final ClassRepr scope) { - final boolean privacy = ((m.myAccess & Opcodes.ACC_PRIVATE) > 0) && c.myName != scope.myName; - final boolean packageLocality = Difference.isPackageLocal(m.myAccess) && !c.getPackageName().equals(scope.getPackageName()); - + final boolean privacy = ((m.access & Opcodes.ACC_PRIVATE) > 0) && c.name != scope.name; + final boolean packageLocality = Difference.isPackageLocal(m.access) && !c.getPackageName().equals(scope.getPackageName()); return !privacy && !packageLocality; } - private boolean empty(final int s) { + private boolean isEmpty(final int s) { return s == myEmptyName; } + @NotNull private TIntHashSet getAllSubclasses(final int root) { - final TIntHashSet result = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); - - addAllSubclasses(root, result); - - return result; + return addAllSubclasses(root, new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR)); } - private void addAllSubclasses(final int root, final TIntHashSet acc) { + private TIntHashSet addAllSubclasses(final int root, final TIntHashSet acc) { final TIntHashSet directSubclasses = myClassToSubclasses.get(root); acc.add(root); @@ -767,32 +764,43 @@ public class Mappings { } }); } + return acc; } private boolean incrementalDecision(final int owner, final Proto member, final Collection affectedFiles, - final DependentFilesFilter filter) { + @Nullable final DependentFilesFilter filter) { final boolean isField = member instanceof FieldRepr; final Util self = new Util(this); // Public branch --- hopeless - if ((member.myAccess & Opcodes.ACC_PUBLIC) > 0) { + if ((member.access & Opcodes.ACC_PUBLIC) > 0) { debug("Public access, switching to a non-incremental mode"); return false; } // Protected branch - if ((member.myAccess & Opcodes.ACC_PROTECTED) > 0) { + if ((member.access & Opcodes.ACC_PROTECTED) > 0) { debug("Protected access, softening non-incremental decision: adding all relevant subclasses for a recompilation"); debug("Root class: ", owner); - final TIntHashSet propagated = self.propagateFieldAccess(isField ? member.myName : myEmptyName, owner); - + final TIntHashSet propagated = self.propagateFieldAccess(isField ? member.name : myEmptyName, owner); + final TIntHashSet fileNames = new TIntHashSet(propagated.size()); propagated.forEach(new TIntProcedure() { @Override public boolean execute(int className) { - final String fileName = myContext.getValue(myClassToSourceFile.get(className)); + final int fileName = myClassToSourceFile.get(className); + if (fileName > 0) { + fileNames.add(fileName); + } + return true; + } + }); + fileNames.forEach(new TIntProcedure() { + @Override + public boolean execute(int file) { + final String fileName = myContext.getValue(file); debug("Adding ", fileName); affectedFiles.add(new File(fileName)); return true; @@ -800,22 +808,30 @@ public class Mappings { }); } - final String packageName = ClassRepr.getPackageName(myContext.getValue(isField ? owner : member.myName)); + final String packageName = ClassRepr.getPackageName(myContext.getValue(isField ? owner : member.name)); debug("Softening non-incremental decision: adding all package classes for a recompilation"); debug("Package name: ", packageName); // Package-local branch + final TIntHashSet fileNames = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); myClassToSourceFile.forEachEntry(new TIntIntProcedure() { @Override public boolean execute(int className, int fileName) { if (ClassRepr.getPackageName(myContext.getValue(className)).equals(packageName)) { - final String f = myContext.getValue(fileName); - final File file = new File(f); - if (filter.accept(file)) { - debug("Adding: ", f); - affectedFiles.add(file); - } + fileNames.add(fileName); + } + return true; + } + }); + fileNames.forEach(new TIntProcedure() { + @Override + public boolean execute(int fileName) { + final String f = myContext.getValue(fileName); + final File file = new File(f); + if (filter == null || filter.accept(file)) { + debug("Adding: ", f); + affectedFiles.add(file); } return true; } @@ -842,6 +858,7 @@ public class Mappings { final Collection myFilesToCompile; final Collection myCompiledFiles; final Collection myAffectedFiles; + @Nullable final DependentFilesFilter myFilter; @Nullable final Callbacks.ConstantAffectionResolver myConstantSearch; final DelayedWorks myDelayedWorks; @@ -884,8 +901,8 @@ public class Mappings { } else { final String className = myContext.getValue(ownerClass); - final String fieldName = myContext.getValue(changedField.myName); - future = myConstantSearch.request(className.replace('/', '.'), fieldName, changedField.myAccess, isRemoved, accessChanged); + final String fieldName = myContext.getValue(changedField.name); + future = myConstantSearch.request(className.replace('/', '.'), fieldName, changedField.access, isRemoved, accessChanged); } myQueue.add(new Triple(ownerClass, changedField, future)); } @@ -898,7 +915,7 @@ public class Mappings { final Callbacks.ConstantAffection affection = t.getAffection(); debug("Class: ", t.owner); - debug("Field: ", t.field.myName); + debug("Field: ", t.field.name); if (!affection.isKnown()) { debug("No external dependency information available."); @@ -1019,8 +1036,8 @@ public class Mappings { if (classes != null) { for (ClassRepr c : classes) { - debug("Affecting usages of removed class ", c.myName); - myUpdated.affectAll(c.myName, myAffectedFiles, myFilter); + debug("Affecting usages of removed class ", c.name); + myUpdated.affectAll(c.name, myAffectedFiles, myFilter); } } } @@ -1029,45 +1046,47 @@ public class Mappings { private void processAddedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { debug("Processing added methods: "); + if (it.isAnnotation()) { + debug("Class is annotation, skipping method analysis"); + return; + } + final TIntHashSet affectedFiles = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); + Ref oldItRef = null; for (final MethodRepr m : diff.methods().added()) { - debug("Method: ", m.myName); - - if (it.isAnnotation()) { - debug("Class is annotation, skipping method analysis"); - continue; - } - - if ((it.myAccess & Opcodes.ACC_INTERFACE) > 0 || - (it.myAccess & Opcodes.ACC_ABSTRACT) > 0 || - (m.myAccess & Opcodes.ACC_ABSTRACT) > 0) { + debug("Method: ", m.name); + if ((it.access & Opcodes.ACC_INTERFACE) > 0 || + (it.access & Opcodes.ACC_ABSTRACT) > 0 || + (m.access & Opcodes.ACC_ABSTRACT) > 0) { debug("Class is abstract, or is interface, or added method in abstract => affecting all subclasses"); - myUpdated.affectSubclasses(it.myName, myAffectedFiles, state.myAffectedUsages, state.myDependants, false); + myUpdated.affectSubclasses(it.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, false); } TIntHashSet propagated = null; - if ((m.myAccess & Opcodes.ACC_PRIVATE) == 0 && m.myName != myInitName) { - final ClassRepr oldIt = getReprByName(it.myName); + if ((m.access & Opcodes.ACC_PRIVATE) == 0 && m.name != myInitName) { + if (oldItRef == null) { + oldItRef = new Ref(getReprByName(it.name)); // lazy init + } + final ClassRepr oldIt = oldItRef.get(); - if (oldIt != null && mySelf.findOverridenMethods(m, oldIt).size() > 0) { + if (oldIt != null && mySelf.findOverriddenMethods(m, oldIt).size() > 0) { } else { if (m.myArgumentTypes.length > 0) { - propagated = myUpdated.propagateMethodAccess(m.myName, it.myName); + propagated = myUpdated.propagateMethodAccess(m.name, it.name); debug("Conservative case on overriding methods, affecting method usages"); - myUpdated - .affectMethodUsages(m, propagated, m.createMetaUsage(myContext, it.myName), state.myAffectedUsages, state.myDependants); + myUpdated.affectMethodUsages(m, propagated, m.createMetaUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } } } - if ((m.myAccess & Opcodes.ACC_PRIVATE) == 0) { + if ((m.access & Opcodes.ACC_PRIVATE) == 0) { final Collection> affectedMethods = myUpdated.findAllMethodsBySpecificity(m, it); final MethodRepr.Predicate overrides = MethodRepr.equalByJavaRules(m); if (propagated == null) { - propagated = myUpdated.propagateMethodAccess(m.myName, it.myName); + propagated = myUpdated.propagateMethodAccess(m.name, it.name); } final Collection lessSpecific = it.findMethods(myUpdated.lessSpecific(m)); @@ -1075,76 +1094,69 @@ public class Mappings { for (final MethodRepr mm : lessSpecific) { if (!mm.equals(m)) { debug("Found less specific method, affecting method usages"); - myUpdated - .affectMethodUsages(mm, propagated, mm.createUsage(myContext, it.myName), state.myAffectedUsages, state.myDependants); + myUpdated.affectMethodUsages(mm, propagated, mm.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } } debug("Processing affected by specificity methods"); - for (final Pair p : affectedMethods) { - final MethodRepr mm = p.first; - final ClassRepr cc = p.second; + for (final Pair pair : affectedMethods) { + final MethodRepr method = pair.first; + final ClassRepr methodClass = pair.second; - if (cc == myMockClass) { + if (methodClass == MOCK_CLASS) { + continue; + } + final Option inheritorOf = mySelf.isInheritorOf(methodClass.name, it.name); + final boolean isInheritor = inheritorOf.isDefined() && inheritorOf.value(); + debug("Method: ", method.name); + debug("Class : ", methodClass.name); + + if (overrides.satisfy(method) && isInheritor) { + debug("Current method overrides that found"); + + final int file = myClassToSourceFile.get(methodClass.name); + + if (file > 0) { + affectedFiles.add(file); + debug("Affecting file ", file); + } } else { - final Option inheritorOf = mySelf.isInheritorOf(cc.myName, it.myName); + debug("Current method does not override that found"); - debug("Method: ", mm.myName); - debug("Class : ", cc.myName); + final TIntHashSet yetPropagated = mySelf.propagateMethodAccess(method.name, it.name); - if (overrides.satisfy(mm) && inheritorOf.isValue() && inheritorOf.value()) { - debug("Current method overrides that found"); + if (isInheritor) { + final TIntHashSet deps = myClassToClassDependency.get(methodClass.name); - final int file = myClassToSourceFile.get(cc.myName); - - if (file > 0) { - final String f = myContext.getValue(file); - debug("Affecting file ", f); - myAffectedFiles.add(new File(f)); - } - } - else { - debug("Current method does not override that found"); - - final TIntHashSet yetPropagated = mySelf.propagateMethodAccess(mm.myName, it.myName); - - if (inheritorOf.isValue() && inheritorOf.value()) { - final TIntHashSet deps = myClassToClassDependency.get(cc.myName); - - if (deps != null) { - addAll(state.myDependants, deps); - } - - myUpdated - .affectMethodUsages(mm, yetPropagated, mm.createUsage(myContext, cc.myName), state.myAffectedUsages, - state.myDependants); + if (deps != null) { + addAll(state.myDependants, deps); } - debug("Affecting method usages for that found"); - myUpdated - .affectMethodUsages(mm, yetPropagated, mm.createUsage(myContext, it.myName), state.myAffectedUsages, state.myDependants); + myUpdated.affectMethodUsages(method, yetPropagated, method.createUsage(myContext, methodClass.name), state.myAffectedUsages, state.myDependants); } + + debug("Affecting method usages for that found"); + myUpdated.affectMethodUsages(method, yetPropagated, method.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } } - final TIntHashSet subClasses = getAllSubclasses(it.myName); + final TIntHashSet subClasses = getAllSubclasses(it.name); if (subClasses != null) { subClasses.forEach(new TIntProcedure() { @Override public boolean execute(int subClass) { final ClassRepr r = myUpdated.reprByName(subClass); - final int sourceFileName = myClassToSourceFile.get(subClass); - - if (r != null && sourceFileName > 0) { - final int outerClass = r.getOuterClassName(); - - if (myUpdated.methodVisible(outerClass, m)) { - final String f = myContext.getValue(sourceFileName); - debug("Affecting file due to local overriding: ", f); - myAffectedFiles.add(new File(f)); + if (r != null) { + final int sourceFileName = myClassToSourceFile.get(subClass); + if (sourceFileName > 0) { + final int outerClass = r.getOuterClassName(); + if (myUpdated.methodVisible(outerClass, m)) { + affectedFiles.add(sourceFileName); + debug("Affecting file due to local overriding: ", sourceFileName); + } } } return true; @@ -1153,20 +1165,28 @@ public class Mappings { } } } + affectedFiles.forEach(new TIntProcedure() { + @Override + public boolean execute(int file) { + myAffectedFiles.add(new File(myContext.getValue(file))); + return true; + } + }); debug("End of added methods processing"); } private void processRemovedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { debug("Processing removed methods:"); + final TIntHashSet affectedFiles = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); for (final MethodRepr m : diff.methods().removed()) { - debug("Method ", m.myName); + debug("Method ", m.name); - final Collection> overridenMethods = myUpdated.findOverridenMethods(m, it); - final TIntHashSet propagated = myUpdated.propagateMethodAccess(m.myName, it.myName); + final Collection> overridenMethods = myUpdated.findOverriddenMethods(m, it); + final TIntHashSet propagated = myUpdated.propagateMethodAccess(m.name, it.name); if (overridenMethods.size() == 0) { debug("No overridden methods found, affecting method usages"); - myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.myName), state.myAffectedUsages, state.myDependants); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } else { boolean clear = true; @@ -1175,7 +1195,7 @@ public class Mappings { for (final Pair overriden : overridenMethods) { final MethodRepr mm = overriden.first; - if (mm == myMockMethod || !mm.myType.equals(m.myType) || !empty(mm.mySignature) || !empty(m.mySignature)) { + if (mm == MOCK_METHOD || !mm.myType.equals(m.myType) || !isEmpty(mm.signature) || !isEmpty(m.signature)) { clear = false; break loop; } @@ -1183,27 +1203,27 @@ public class Mappings { if (!clear) { debug("No clearly overridden methods found, affecting method usages"); - myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.myName), state.myAffectedUsages, state.myDependants); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } } final Collection> overriding = myUpdated.findOverridingMethods(m, it, false); for (final Pair p : overriding) { - final int fName = myClassToSourceFile.get(p.second.myName); + final int fName = myClassToSourceFile.get(p.second.name); + affectedFiles.add(fName); debug("Affecting file by overriding: ", fName); - myAffectedFiles.add(new File(myContext.getValue(fName))); } - if ((m.myAccess & Opcodes.ACC_ABSTRACT) == 0) { + if ((m.access & Opcodes.ACC_ABSTRACT) == 0) { propagated.forEach(new TIntProcedure() { @Override public boolean execute(int p) { - if (p != it.myName) { + if (p != it.name) { final ClassRepr s = myUpdated.reprByName(p); if (s != null) { - final Collection> overridenInS = myUpdated.findOverridenMethods(m, s); + final Collection> overridenInS = myUpdated.findOverriddenMethods(m, s); overridenInS.addAll(overridenMethods); @@ -1213,17 +1233,17 @@ public class Mappings { for (final Pair pp : overridenInS) { final ClassRepr cc = pp.second; - if (cc == myMockClass) { + if (cc == MOCK_CLASS) { visited = true; continue; } - if (cc.myName == it.myName) { + if (cc.name == it.name) { continue; } visited = true; - allAbstract = ((pp.first.myAccess & Opcodes.ACC_ABSTRACT) > 0) || ((cc.myAccess & Opcodes.ACC_INTERFACE) > 0); + allAbstract = ((pp.first.access & Opcodes.ACC_ABSTRACT) > 0) || ((cc.access & Opcodes.ACC_INTERFACE) > 0); if (!allAbstract) { break; @@ -1234,12 +1254,9 @@ public class Mappings { final int source = myClassToSourceFile.get(p); if (source > 0) { - final String f = myContext.getValue(source); - debug( - "Removed method is not abstract & overrides some abstract method which is not then over-overriden in subclass ", - p); - debug("Affecting subclass source file ", f); - myAffectedFiles.add(new File(f)); + affectedFiles.add(source); + debug("Removed method is not abstract & overrides some abstract method which is not then over-overriden in subclass ", p); + debug("Affecting subclass source file ", source); } } } @@ -1249,6 +1266,14 @@ public class Mappings { }); } } + affectedFiles.forEach(new TIntProcedure() { + @Override + public boolean execute(int file) { + final String f = myContext.getValue(file); + myAffectedFiles.add(new File(f)); + return true; + } + }); debug("End of removed methods processing"); } @@ -1259,20 +1284,20 @@ public class Mappings { final MethodRepr.Diff d = (MethodRepr.Diff)mr.second; final boolean throwsChanged = (d.exceptions().added().size() > 0) || (d.exceptions().changed().size() > 0); - debug("Method: ", m.myName); + debug("Method: ", m.name); if (it.isAnnotation()) { if (d.defaultRemoved()) { debug("Class is annotation, default value is removed => adding annotation query"); final TIntHashSet l = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); - l.add(m.myName); + l.add(m.name); final UsageRepr.AnnotationUsage annotationUsage = (UsageRepr.AnnotationUsage)UsageRepr - .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.myName), l, null); + .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.name), l, null); state.myAnnotationQuery.add(annotationUsage); } } else if (d.base() != Difference.NONE || throwsChanged) { - final TIntHashSet propagated = myUpdated.propagateMethodAccess(m.myName, it.myName); + final TIntHashSet propagated = myUpdated.propagateMethodAccess(m.name, it.name); boolean affected = false; boolean constrained = false; @@ -1281,10 +1306,10 @@ public class Mappings { if (d.packageLocalOn()) { debug("Method became package-local, affecting method usages outside the package"); - myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.myName), usages, state.myDependants); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.myDependants); for (final UsageRepr.Usage usage : usages) { - state.myUsageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.myName)); + state.myUsageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.name)); } state.myAffectedUsages.addAll(usages); @@ -1295,7 +1320,7 @@ public class Mappings { if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0 || throwsChanged) { if (!affected) { debug("Return type, throws list or signature changed --- affecting method usages"); - myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.myName), usages, state.myDependants); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.myDependants); state.myAffectedUsages.addAll(usages); } } @@ -1305,13 +1330,13 @@ public class Mappings { (d.addedModifiers() & Opcodes.ACC_PRIVATE) > 0) { if (!affected) { debug("Added static or private specifier or removed static specifier --- affecting method usages"); - myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.myName), usages, state.myDependants); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.myDependants); state.myAffectedUsages.addAll(usages); } if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0) { debug("Added static specifier --- affecting subclasses"); - myUpdated.affectSubclasses(it.myName, myAffectedFiles, state.myAffectedUsages, state.myDependants, false); + myUpdated.affectSubclasses(it.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, false); } } else { @@ -1319,19 +1344,19 @@ public class Mappings { (d.addedModifiers() & Opcodes.ACC_PUBLIC) > 0 || (d.addedModifiers() & Opcodes.ACC_ABSTRACT) > 0) { debug("Added final, public or abstract specifier --- affecting subclasses"); - myUpdated.affectSubclasses(it.myName, myAffectedFiles, state.myAffectedUsages, state.myDependants, false); + myUpdated.affectSubclasses(it.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, false); } if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) > 0 && !((d.removedModifiers() & Opcodes.ACC_PRIVATE) > 0)) { if (!constrained) { debug("Added public or package-local method became protected --- affect method usages with protected constraint"); if (!affected) { - myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.myName), usages, state.myDependants); + myUpdated.affectMethodUsages(m, propagated, m.createUsage(myContext, it.name), usages, state.myDependants); state.myAffectedUsages.addAll(usages); } for (final UsageRepr.Usage usage : usages) { - state.myUsageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.myName)); + state.myUsageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.name)); } } } @@ -1342,45 +1367,42 @@ public class Mappings { debug("End of changed methods processing"); } - private boolean processAddedFields(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) { + private boolean processAddedFields(final DiffState state, final ClassRepr.Diff diff, final ClassRepr classRepr) { debug("Processing added fields"); for (final FieldRepr f : diff.fields().added()) { - debug("Field: ", f.myName); + debug("Field: ", f.name); - final boolean fPrivate = (f.myAccess & Opcodes.ACC_PRIVATE) > 0; - final boolean fProtected = (f.myAccess & Opcodes.ACC_PROTECTED) > 0; - final boolean fPublic = (f.myAccess & Opcodes.ACC_PUBLIC) > 0; + final boolean fPrivate = (f.access & Opcodes.ACC_PRIVATE) > 0; + final boolean fProtected = (f.access & Opcodes.ACC_PROTECTED) > 0; + final boolean fPublic = (f.access & Opcodes.ACC_PUBLIC) > 0; final boolean fPLocal = !fPrivate && !fProtected && !fPublic; if (!fPrivate) { - final TIntHashSet subClasses = getAllSubclasses(it.myName); + final TIntHashSet subClasses = getAllSubclasses(classRepr.name); subClasses.forEach(new TIntProcedure() { @Override public boolean execute(int subClass) { final ClassRepr r = myUpdated.reprByName(subClass); - final int sourceFileName = myClassToSourceFile.get(subClass); - - if (r != null && sourceFileName > 0) { - if (r.isLocal()) { - debug( - "Affecting local subclass (introduced field can potentially hide surrounding method parameters/local variables): ", - sourceFileName); - myAffectedFiles.add(new File(myContext.getValue(sourceFileName))); - } - else { - final int outerClass = r.getOuterClassName(); - - if (!empty(outerClass) && myUpdated.fieldVisible(outerClass, f)) { - debug("Affecting inner subclass (introduced field can potentially hide surrounding class fields): ", - sourceFileName); + if (r != null) { + final int sourceFileName = myClassToSourceFile.get(subClass); + if (sourceFileName > 0) { + if (r.isLocal()) { + debug("Affecting local subclass (introduced field can potentially hide surrounding method parameters/local variables): ", sourceFileName); myAffectedFiles.add(new File(myContext.getValue(sourceFileName))); } + else { + final int outerClass = r.getOuterClassName(); + if (!isEmpty(outerClass) && myUpdated.fieldVisible(outerClass, f)) { + debug("Affecting inner subclass (introduced field can potentially hide surrounding class fields): ", sourceFileName); + myAffectedFiles.add(new File(myContext.getValue(sourceFileName))); + } + } } } debug("Affecting field usages referenced from subclass ", subClass); - final TIntHashSet propagated = myUpdated.propagateFieldAccess(f.myName, subClass); + final TIntHashSet propagated = myUpdated.propagateFieldAccess(f.name, subClass); myUpdated.affectFieldUsages(f, propagated, f.createUsage(myContext, subClass), state.myAffectedUsages, state.myDependants); final TIntHashSet deps = myClassToClassDependency.get(subClass); @@ -1393,23 +1415,23 @@ public class Mappings { }); } - final Collection> overridden = myUpdated.findOverridenFields(f, it); + final Collection> overridden = myUpdated.findOverriddenFields(f, classRepr); for (final Pair p : overridden) { final FieldRepr ff = p.first; final ClassRepr cc = p.second; - final boolean ffPrivate = (ff.myAccess & Opcodes.ACC_PRIVATE) > 0; - final boolean ffProtected = (ff.myAccess & Opcodes.ACC_PROTECTED) > 0; - final boolean ffPublic = (ff.myAccess & Opcodes.ACC_PUBLIC) > 0; - final boolean ffPLocal = Difference.isPackageLocal(ff.myAccess); + final boolean ffPrivate = (ff.access & Opcodes.ACC_PRIVATE) > 0; + final boolean ffProtected = (ff.access & Opcodes.ACC_PROTECTED) > 0; + final boolean ffPublic = (ff.access & Opcodes.ACC_PUBLIC) > 0; + final boolean ffPLocal = Difference.isPackageLocal(ff.access); if (!ffPrivate) { - final TIntHashSet propagated = myOriginal.propagateFieldAccess(ff.myName, cc.myName); + final TIntHashSet propagated = myOriginal.propagateFieldAccess(ff.name, cc.name); final Set localUsages = new HashSet(); - debug("Affecting usages of overridden field in class ", cc.myName); - myUpdated.affectFieldUsages(ff, propagated, ff.createUsage(myContext, cc.myName), localUsages, state.myDependants); + debug("Affecting usages of overridden field in class ", cc.name); + myUpdated.affectFieldUsages(ff, propagated, ff.createUsage(myContext, cc.name), localUsages, state.myDependants); if (fPrivate || (fPublic && (ffPublic || ffPLocal)) || (fProtected && ffProtected) || (fPLocal && ffPLocal)) { @@ -1418,14 +1440,14 @@ public class Mappings { Util.UsageConstraint constaint; if ((ffProtected && fPublic) || (fProtected && ffPublic) || (ffPLocal && fProtected)) { - constaint = myUpdated.new NegationConstraint(myUpdated.new InheritanceConstraint(cc.myName)); + constaint = myUpdated.new NegationConstraint(myUpdated.new InheritanceConstraint(cc.name)); } else if (ffPublic && ffPLocal) { constaint = myUpdated.new NegationConstraint(myUpdated.new PackageConstraint(cc.getPackageName())); } else { constaint = - myUpdated.new IntersectionConstraint(myUpdated.new NegationConstraint(myUpdated.new InheritanceConstraint(cc.myName)), + myUpdated.new IntersectionConstraint(myUpdated.new NegationConstraint(myUpdated.new InheritanceConstraint(cc.name)), myUpdated.new NegationConstraint( myUpdated.new PackageConstraint(cc.getPackageName()))); } @@ -1448,23 +1470,23 @@ public class Mappings { debug("Processing removed fields:"); for (final FieldRepr f : diff.fields().removed()) { - debug("Field: ", f.myName); + debug("Field: ", f.name); - if ((f.myAccess & Opcodes.ACC_PRIVATE) == 0 && (f.myAccess & DESPERATE_MASK) == DESPERATE_MASK && f.hasValue()) { + if ((f.access & Opcodes.ACC_PRIVATE) == 0 && (f.access & DESPERATE_MASK) == DESPERATE_MASK && f.hasValue()) { debug("Field had value and was (non-private) final static => a switch to non-incremental mode requested"); if (myConstantSearch != null) { - myDelayedWorks.addConstantWork(it.myName, f, true, false); + myDelayedWorks.addConstantWork(it.name, f, true, false); } else { - if (!incrementalDecision(it.myName, f, myAffectedFiles, myFilter)) { + if (!incrementalDecision(it.name, f, myAffectedFiles, myFilter)) { debug("End of Differentiate, returning false"); return false; } } } - final TIntHashSet propagated = myUpdated.propagateFieldAccess(f.myName, it.myName); - myUpdated.affectFieldUsages(f, propagated, f.createUsage(myContext, it.myName), state.myAffectedUsages, state.myDependants); + final TIntHashSet propagated = myUpdated.propagateFieldAccess(f.name, it.name); + myUpdated.affectFieldUsages(f, propagated, f.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } debug("End of removed fields processing"); @@ -1478,9 +1500,9 @@ public class Mappings { final Difference d = f.second; final FieldRepr field = f.first; - debug("Field: ", field.myName); + debug("Field: ", field.name); - if ((field.myAccess & Opcodes.ACC_PRIVATE) == 0 && (field.myAccess & DESPERATE_MASK) == DESPERATE_MASK) { + if ((field.access & Opcodes.ACC_PRIVATE) == 0 && (field.access & DESPERATE_MASK) == DESPERATE_MASK) { final int changedModifiers = d.addedModifiers() | d.removedModifiers(); final boolean harmful = (changedModifiers & (Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)) > 0; final boolean accessChanged = (changedModifiers & (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) > 0; @@ -1489,10 +1511,10 @@ public class Mappings { if (harmful || valueChanged || (accessChanged && !d.weakedAccess())) { debug("Inline field changed it's access or value => a switch to non-incremental mode requested"); if (myConstantSearch != null) { - myDelayedWorks.addConstantWork(it.myName, field, false, accessChanged); + myDelayedWorks.addConstantWork(it.name, field, false, accessChanged); } else { - if (!incrementalDecision(it.myName, field, myAffectedFiles, myFilter)) { + if (!incrementalDecision(it.name, field, myAffectedFiles, myFilter)) { debug("End of Differentiate, returning false"); return false; } @@ -1501,12 +1523,12 @@ public class Mappings { } if (d.base() != Difference.NONE) { - final TIntHashSet propagated = myUpdated.propagateFieldAccess(field.myName, it.myName); + final TIntHashSet propagated = myUpdated.propagateFieldAccess(field.name, it.name); if ((d.base() & Difference.TYPE) > 0 || (d.base() & Difference.SIGNATURE) > 0) { debug("Type or signature changed --- affecting field usages"); myUpdated - .affectFieldUsages(field, propagated, field.createUsage(myContext, it.myName), state.myAffectedUsages, state.myDependants); + .affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } else if ((d.base() & Difference.ACCESS) > 0) { if ((d.addedModifiers() & Opcodes.ACC_STATIC) > 0 || @@ -1515,7 +1537,7 @@ public class Mappings { (d.addedModifiers() & Opcodes.ACC_VOLATILE) > 0) { debug("Added/removed static modifier or added private/volatile modifier --- affecting field usages"); myUpdated - .affectFieldUsages(field, propagated, field.createUsage(myContext, it.myName), state.myAffectedUsages, state.myDependants); + .affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants); } else { boolean affected = false; @@ -1523,7 +1545,7 @@ public class Mappings { if ((d.addedModifiers() & Opcodes.ACC_FINAL) > 0) { debug("Added final modifier --- affecting field assign usages"); - myUpdated.affectFieldUsages(field, propagated, field.createAssignUsage(myContext, it.myName), usages, state.myDependants); + myUpdated.affectFieldUsages(field, propagated, field.createAssignUsage(myContext, it.name), usages, state.myDependants); state.myAffectedUsages.addAll(usages); affected = true; } @@ -1531,13 +1553,13 @@ public class Mappings { if ((d.removedModifiers() & Opcodes.ACC_PUBLIC) > 0) { debug("Removed public modifier, affecting field usages with appropriate constraint"); if (!affected) { - myUpdated.affectFieldUsages(field, propagated, field.createUsage(myContext, it.myName), usages, state.myDependants); + myUpdated.affectFieldUsages(field, propagated, field.createUsage(myContext, it.name), usages, state.myDependants); state.myAffectedUsages.addAll(usages); } for (final UsageRepr.Usage usage : usages) { if ((d.addedModifiers() & Opcodes.ACC_PROTECTED) > 0) { - state.myUsageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.myName)); + state.myUsageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.name)); } else { state.myUsageConstraints.put(usage, myUpdated.new PackageConstraint(it.getPackageName())); @@ -1559,9 +1581,9 @@ public class Mappings { final ClassRepr it = changed.first; final ClassRepr.Diff diff = (ClassRepr.Diff)changed.second; - myDelta.addChangedClass(it.myName); + myDelta.addChangedClass(it.name); - debug("Changed: ", it.myName); + debug("Changed: ", it.name); final int addedModifiers = diff.addedModifiers(); @@ -1570,22 +1592,22 @@ public class Mappings { final boolean signatureChanged = (diff.base() & Difference.SIGNATURE) > 0; if (superClassChanged) { - myDelta.registerRemovedSuperClass(it.myName, ((TypeRepr.ClassType)it.getSuperClass()).myClassName); + myDelta.registerRemovedSuperClass(it.name, ((TypeRepr.ClassType)it.getSuperClass()).myClassName); - final ClassRepr newClass = myDelta.getReprByName(it.myName); + final ClassRepr newClass = myDelta.getReprByName(it.name); assert (newClass != null); - myDelta.registerAddedSuperClass(it.myName, ((TypeRepr.ClassType)newClass.getSuperClass()).myClassName); + myDelta.registerAddedSuperClass(it.name, ((TypeRepr.ClassType)newClass.getSuperClass()).myClassName); } if (interfacesChanged) { for (final TypeRepr.AbstractType typ : diff.interfaces().removed()) { - myDelta.registerRemovedSuperClass(it.myName, ((TypeRepr.ClassType)typ).myClassName); + myDelta.registerRemovedSuperClass(it.name, ((TypeRepr.ClassType)typ).myClassName); } for (final TypeRepr.AbstractType typ : diff.interfaces().added()) { - myDelta.registerAddedSuperClass(it.myName, ((TypeRepr.ClassType)typ).myClassName); + myDelta.registerAddedSuperClass(it.name, ((TypeRepr.ClassType)typ).myClassName); } } @@ -1606,7 +1628,7 @@ public class Mappings { debug("Extends changed: ", extendsChanged); debug("Interfaces removed: ", interfacesRemoved); - myUpdated.affectSubclasses(it.myName, myAffectedFiles, state.myAffectedUsages, state.myDependants, + myUpdated.affectSubclasses(it.name, myAffectedFiles, state.myAffectedUsages, state.myDependants, extendsChanged || interfacesRemoved || signatureChanged); } @@ -1628,7 +1650,7 @@ public class Mappings { final UsageRepr.Usage usage = it.createUsage(); state.myAffectedUsages.add(usage); - state.myUsageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.myName)); + state.myUsageConstraints.put(usage, myUpdated.new InheritanceConstraint(it.name)); } if (diff.packageLocalOn()) { @@ -1646,7 +1668,7 @@ public class Mappings { if ((addedModifiers & Opcodes.ACC_ABSTRACT) > 0 || (addedModifiers & Opcodes.ACC_STATIC) > 0) { debug("Introduction of 'abstract' or 'static' modifier(s) detected, adding class new usage to affected usages"); - state.myAffectedUsages.add(UsageRepr.createClassNewUsage(myContext, it.myName)); + state.myAffectedUsages.add(UsageRepr.createClassNewUsage(myContext, it.name)); } if (it.isAnnotation()) { @@ -1670,13 +1692,13 @@ public class Mappings { if (!removedtargets.isEmpty()) { debug("Removed some annotation targets, adding annotation query"); final UsageRepr.AnnotationUsage annotationUsage = (UsageRepr.AnnotationUsage)UsageRepr - .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.myName), null, EnumSet.copyOf(removedtargets)); + .createAnnotationUsage(myContext, TypeRepr.createClassType(myContext, it.name), null, EnumSet.copyOf(removedtargets)); state.myAnnotationQuery.add(annotationUsage); } for (final MethodRepr m : diff.methods().added()) { if (!m.hasValue()) { - debug("Added method with no default value: ", m.myName); + debug("Added method with no default value: ", m.name); debug("Adding class usage to affected usages"); state.myAffectedUsages.add(it.createUsage()); } @@ -1712,15 +1734,15 @@ public class Mappings { for (final ClassRepr c : state.myClassDiff.removed()) { myDelta.addDeletedClass(c); - final int fileName = myClassToSourceFile.get(c.myName); + final int fileName = myClassToSourceFile.get(c.name); - if (fileName != 0) { + if (fileName > 0) { myDelta.myChangedFiles.add(fileName); } if (!myEasyMode) { mySelf.appendDependents(c, state.myDependants); - debug("Adding usages of class ", c.myName); + debug("Adding usages of class ", c.name); state.myAffectedUsages.add(c.createUsage()); } } @@ -1730,30 +1752,36 @@ public class Mappings { private void processAddedClasses(final DiffState state) { debug("Processing added classes:"); for (final ClassRepr c : state.myClassDiff.added()) { - debug("Class name: ", c.myName); - myDelta.addChangedClass(c.myName); + debug("Class name: ", c.name); + myDelta.addChangedClass(c.name); for (final int sup : c.getSupers()) { - myDelta.registerAddedSuperClass(c.myName, sup); + myDelta.registerAddedSuperClass(c.name, sup); } if (!myEasyMode) { - final TIntHashSet depClasses = myClassToClassDependency.get(c.myName); + final TIntHashSet depClasses = myClassToClassDependency.get(c.name); if (depClasses != null) { + final TIntHashSet fileNames = new TIntHashSet(DEFAULT_SET_CAPACITY, DEFAULT_SET_LOAD_FACTOR); depClasses.forEach(new TIntProcedure() { @Override public boolean execute(int depClass) { final int fName = myClassToSourceFile.get(depClass); - if (fName > 0) { - final String f = myContext.getValue(fName); - final File theFile = new File(f); - - if (myFilter.accept(theFile)) { - debug("Adding dependent file ", f); - myAffectedFiles.add(theFile); - } + fileNames.add(fName); + } + return true; + } + }); + fileNames.forEach(new TIntProcedure() { + @Override + public boolean execute(int fName) { + final String f = myContext.getValue(fName); + final File theFile = new File(f); + if (myFilter == null || myFilter.accept(theFile)) { + debug("Adding dependent file ", f); + myAffectedFiles.add(theFile); } return true; } @@ -1765,7 +1793,7 @@ public class Mappings { debug("End of added classes processing."); } - private void calaulateAffectedFiles(final DiffState state) { + private void calculateAffectedFiles(final DiffState state) { debug("Checking dependent classes:"); state.myDependants.forEach(new TIntProcedure() { @@ -1773,7 +1801,7 @@ public class Mappings { public boolean execute(final int depClass) { final int depFile = myClassToSourceFile.get(depClass); - if (depFile != 0) { + if (depFile > 0) { final File theFile = new File(myContext.getValue(depFile)); if (myAffectedFiles.contains(theFile) || myCompiledFiles.contains(theFile)) { @@ -1860,6 +1888,7 @@ public class Mappings { final DiffState state = new DiffState(Difference.make(pastClasses, classes)); if (!processChangedClasses(state) && !myEasyMode) { + // turning non-incremental return false; } @@ -1867,7 +1896,7 @@ public class Mappings { processAddedClasses(state); if (!myEasyMode) { - calaulateAffectedFiles(state); + calculateAffectedFiles(state); } } @@ -1934,7 +1963,7 @@ public class Mappings { @NotNull final ClassRepr cr, final Set usages, final IntIntMultiMaplet dependenciesTrashBin) { - final int className = cr.myName; + final int className = cr.name; for (final int superSomething : cr.getSupers()) { delta.registerRemovedSuperClass(className, superSomething); @@ -1967,9 +1996,8 @@ public class Mappings { for (final ClassRepr aClass : fileClasses) { cleanupRemovedClass(delta, aClass, aClass.getUsages(), dependenciesTrashBin); } + mySourceFileToClasses.remove(fileName); } - - mySourceFileToClasses.remove(fileName); } } @@ -2033,14 +2061,7 @@ public class Mappings { @Override public boolean execute(final int fileName) { final Collection classes = delta.mySourceFileToClasses.get(fileName); - - if (classes != null) { - mySourceFileToClasses.replace(fileName, classes); - } - else { - mySourceFileToClasses.remove(fileName); - } - + mySourceFileToClasses.replace(fileName, classes); return true; } }); @@ -2048,7 +2069,6 @@ public class Mappings { else { myClassToSubclasses.putAll(delta.myClassToSubclasses); myClassToSourceFile.putAll(delta.myClassToSourceFile); - mySourceFileToClasses.replaceAll(delta.mySourceFileToClasses); } @@ -2108,34 +2128,23 @@ public class Mappings { final int classFileNameS = myContext.get(classFileName); final Pair> result = new ClassfileAnalyzer(myContext).analyze(classFileNameS, cr); final ClassRepr repr = result.first; - final Set localUsages = result.second; - - final int sourceFileNameS = myContext.get(sourceFileName); - if (repr != null) { - final int className = repr.myName; + final Set localUsages = result.second; + final int sourceFileNameS = myContext.get(sourceFileName); + final int className = repr.name; - myClassToSourceFile.put(repr.myName, sourceFileNameS); + myClassToSourceFile.put(className, sourceFileNameS); mySourceFileToClasses.put(sourceFileNameS, repr); for (final int s : repr.getSupers()) { - myClassToSubclasses.put(s, repr.myName); + myClassToSubclasses.put(s, className); } for (final UsageRepr.Usage u : localUsages) { final int owner = u.getOwner(); if (owner != className) { - final int ownerSourceFile = myClassToSourceFile.get(owner); - - if (ownerSourceFile > 0) { - if (ownerSourceFile != sourceFileNameS) { - myClassToClassDependency.put(owner, className); - } - } - else { - myClassToClassDependency.put(owner, className); - } + myClassToClassDependency.put(owner, className); } } } @@ -2144,36 +2153,38 @@ public class Mappings { @Override public void registerImports(final String className, final Collection imports, Collection staticImports) { + final List allImports = new ArrayList(); + for (String anImport : imports) { + if (!anImport.endsWith("*")) { + allImports.add(anImport); // filter out wildcard imports + } + } for (final String s : staticImports) { int i = s.length() - 1; for (; s.charAt(i) != '.'; i--) ; - imports.add(s.substring(0, i)); + final String anImport = s.substring(0, i); + if (!anImport.endsWith("*")) { + allImports.add(anImport); // filter out wildcard imports + } } - addPostPass(new PostPass() { - public void perform() { - final int rootClassName = myContext.get(className.replace(".", "/")); - final int fileName = myClassToSourceFile.get(rootClassName); + if (!allImports.isEmpty()) { + addPostPass(new PostPass() { + public void perform() { + final int rootClassName = myContext.get(className.replace(".", "/")); + final int fileName = myClassToSourceFile.get(rootClassName); + final ClassRepr repr = fileName > 0? getReprByName(rootClassName) : null; - for (final String i : imports) { - if (i.endsWith("*")) { - continue; // filter out wildcard imports - } - final int iname = myContext.get(i.replace(".", "/")); - - myClassToClassDependency.put(iname, rootClassName); - - final ClassRepr repr = getReprByName(rootClassName); - - if (repr != null && fileName != 0) { - if (repr.addUsage(UsageRepr.createClassUsage(myContext, iname))) { + for (final String i : allImports) { + final int iname = myContext.get(i.replace(".", "/")); + myClassToClassDependency.put(iname, rootClassName); + if (repr != null && repr.addUsage(UsageRepr.createClassUsage(myContext, iname))) { mySourceFileToClasses.put(fileName, repr); } - ; } } - } - }); + }); + } } }; } @@ -2276,16 +2287,16 @@ public class Mappings { myDeletedClasses.add(cr); - addChangedClass(cr.myName); + addChangedClass(cr.name); } private void addChangedClass(final int it) { assert (myChangedClasses != null && myChangedFiles != null); myChangedClasses.add(it); - final Integer file = myClassToSourceFile.get(it); + final int file = myClassToSourceFile.get(it); - if (file != null) { + if (file > 0) { myChangedFiles.add(file); } } @@ -2328,7 +2339,7 @@ public class Mappings { myClassToSubclasses, myClassToClassDependency, mySourceFileToClasses, - myClassToSourceFile + myClassToSourceFile, }; final String[] info = { @@ -2350,4 +2361,37 @@ public class Mappings { stream.println(info[i]); } } + + public void toStream(File outputRoot) { + final Streamable[] data = { + myClassToSubclasses, + myClassToClassDependency, + mySourceFileToClasses, + myClassToSourceFile, + }; + + final String[] info = { + "ClassToSubclasses", + "ClassToClassDependency", + "SourceFileToClasses", + "ClassToSourceFile", + }; + + for (int i = 0; i < data.length; i++) { + final File file = new File(outputRoot, info[i]); + FileUtil.createIfDoesntExist(file); + try { + final PrintStream stream = new PrintStream(file); + try { + data[i].toStream(myContext, stream); + } + finally { + stream.close(); + } + } + catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + } } \ No newline at end of file diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/MethodRepr.java b/jps/model/src/org/jetbrains/ether/dependencyView/MethodRepr.java index a28545c2af76..6f899f9b2ad0 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/MethodRepr.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/MethodRepr.java @@ -159,7 +159,7 @@ class MethodRepr extends ProtoMember { @Override public boolean satisfy(MethodRepr that) { if (me == that) return true; - return me.myName == that.myName && Arrays.equals(me.myArgumentTypes, that.myArgumentTypes); + return me.name == that.name && Arrays.equals(me.myArgumentTypes, that.myArgumentTypes); } }; } @@ -171,12 +171,12 @@ class MethodRepr extends ProtoMember { final MethodRepr that = (MethodRepr)o; - return myName == that.myName && myType.equals(that.myType) && Arrays.equals(myArgumentTypes, that.myArgumentTypes); + return name == that.name && myType.equals(that.myType) && Arrays.equals(myArgumentTypes, that.myArgumentTypes); } @Override public int hashCode() { - return 31 * (31 * Arrays.hashCode(myArgumentTypes) + myType.hashCode()) + myName; + return 31 * (31 * Arrays.hashCode(myArgumentTypes) + myType.hashCode()) + name; } private String getDescr(final DependencyContext context) { @@ -195,11 +195,11 @@ class MethodRepr extends ProtoMember { } public UsageRepr.Usage createUsage(final DependencyContext context, final int owner) { - return UsageRepr.createMethodUsage(context, myName, owner, getDescr(context)); + return UsageRepr.createMethodUsage(context, name, owner, getDescr(context)); } public UsageRepr.Usage createMetaUsage(final DependencyContext context, final int owner) { - return UsageRepr.createMetaMethodUsage(context, myName, owner, getDescr(context)); + return UsageRepr.createMetaMethodUsage(context, name, owner, getDescr(context)); } @Override diff --git a/jps/model/src/org/jetbrains/ether/dependencyView/Proto.java b/jps/model/src/org/jetbrains/ether/dependencyView/Proto.java index 58b2557faffc..16349c15bb77 100644 --- a/jps/model/src/org/jetbrains/ether/dependencyView/Proto.java +++ b/jps/model/src/org/jetbrains/ether/dependencyView/Proto.java @@ -16,21 +16,21 @@ import java.io.PrintStream; * To change this template use File | Settings | File Templates. */ class Proto implements RW.Savable, Streamable { - public final int myAccess; - public final int mySignature; - public final int myName; + public final int access; + public final int signature; + public final int name; protected Proto(final int access, final int signature, final int name) { - this.myAccess = access; - this.mySignature = signature; - this.myName = name; + this.access = access; + this.signature = signature; + this.name = name; } protected Proto(final DataInput in) { try { - myAccess = in.readInt(); - mySignature = in.readInt(); - myName = in.readInt(); + access = in.readInt(); + signature = in.readInt(); + name = in.readInt(); } catch (IOException e) { throw new RuntimeException(e); @@ -40,9 +40,9 @@ class Proto implements RW.Savable, Streamable { @Override public void save(final DataOutput out) { try { - out.writeInt(myAccess); - out.writeInt(mySignature); - out.writeInt(myName); + out.writeInt(access); + out.writeInt(signature); + out.writeInt(name); } catch (IOException e) { throw new RuntimeException(e); @@ -52,11 +52,11 @@ class Proto implements RW.Savable, Streamable { public Difference difference(final Proto past) { int diff = Difference.NONE; - if (past.myAccess != myAccess) { + if (past.access != access) { diff |= Difference.ACCESS; } - if (past.mySignature != mySignature) { + if (past.signature != signature) { diff |= Difference.SIGNATURE; } @@ -75,20 +75,20 @@ class Proto implements RW.Savable, Streamable { @Override public int addedModifiers() { - return ~past.myAccess & myAccess; + return ~past.access & access; } @Override public int removedModifiers() { - return ~myAccess & past.myAccess; + return ~access & past.access; } @Override public boolean packageLocalOn() { - return ((past.myAccess & Opcodes.ACC_PRIVATE) != 0 || - (past.myAccess & Opcodes.ACC_PUBLIC) != 0 || - (past.myAccess & Opcodes.ACC_PROTECTED) != 0) && - Difference.isPackageLocal(myAccess); + return ((past.access & Opcodes.ACC_PRIVATE) != 0 || + (past.access & Opcodes.ACC_PUBLIC) != 0 || + (past.access & Opcodes.ACC_PROTECTED) != 0) && + Difference.isPackageLocal(access); } @Override @@ -98,7 +98,7 @@ class Proto implements RW.Savable, Streamable { @Override public boolean weakedAccess() { - return Difference.weakerAccess(past.myAccess, myAccess); + return Difference.weakerAccess(past.access, access); } }; } @@ -108,25 +108,25 @@ class Proto implements RW.Savable, Streamable { if (this instanceof ClassRepr) { stream.print(" Class "); - stream.println(context.getValue(myName)); + stream.println(context.getValue(name)); } if (this instanceof MethodRepr) { stream.print(" Method "); - stream.println(context.getValue(myName)); + stream.println(context.getValue(name)); } if (this instanceof FieldRepr) { stream.print(" Field "); - stream.println(context.getValue(myName)); + stream.println(context.getValue(name)); } stream.print(d); stream.print("Access : "); - stream.println(myAccess); + stream.println(access); stream.print(d); stream.print("Signature : "); - stream.println(context.getValue(mySignature)); + stream.println(context.getValue(signature)); } } diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java index bf6674308a6a..1962dc6f8be5 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java @@ -152,7 +152,7 @@ public class VfsUtilCore { @NotNull public static InputStream byteStreamSkippingBOM(@NotNull byte[] buf, @NotNull VirtualFile file) throws IOException { - BufferExposingByteArrayInputStream stream = new BufferExposingByteArrayInputStream(buf); + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") BufferExposingByteArrayInputStream stream = new BufferExposingByteArrayInputStream(buf); return inputStreamSkippingBOM(stream, file); } @@ -176,22 +176,22 @@ public class VfsUtilCore { private static void visitChildrenRecursively(@NotNull VirtualFile file, @NotNull VirtualFileVisitor visitor, - @Nullable Set visitedSymlinks) { - + @Nullable Set visitedSymLinks) { if (!file.isValid()) return; if (!visitor.visitFile(file)) return; if (file.isSymLink()) { - if (visitedSymlinks == null) { - visitedSymlinks = new HashSet(); + if (!visitor.followSymLinks()) return; + if (visitedSymLinks == null) { + visitedSymLinks = new HashSet(); } - if (!visitedSymlinks.add(file)) { + if (!visitedSymLinks.add(file)) { visitor.afterChildrenVisited(file); return; } } VirtualFile[] children = file.getChildren(); for (VirtualFile child : children) { - visitChildrenRecursively(child, visitor, visitedSymlinks); + visitChildrenRecursively(child, visitor, visitedSymLinks); } visitor.afterChildrenVisited(file); } diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java index 774d52b16c5d..6cd27cf611d3 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -19,11 +19,24 @@ import org.jetbrains.annotations.NotNull; /** * @author Dmitry Avdeev - * Date: 10/31/11 + * @since 31.10.2011 */ public abstract class VirtualFileVisitor { + private final boolean myFollowSymLinks; + + protected VirtualFileVisitor() { + this(true); + } + + protected VirtualFileVisitor(boolean followSymLinks) { + myFollowSymLinks = followSymLinks; + } + + public boolean followSymLinks() { + return myFollowSymLinks; + } public abstract boolean visitFile(@NotNull VirtualFile file); - public void afterChildrenVisited(@NotNull VirtualFile file) {} + public void afterChildrenVisited(@NotNull VirtualFile file) { } } diff --git a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java index f31778d64f97..0973bca9e97d 100644 --- a/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java +++ b/platform/core-api/src/com/intellij/psi/PsiDocumentManager.java @@ -72,6 +72,7 @@ public abstract class PsiDocumentManager { * @param file the file for which the document is requested. * @return the document instance, or null if the file is binary or has no associated document. */ + @Nullable public abstract Document getDocument(@NotNull PsiFile file); /** diff --git a/platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironment.java b/platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironment.java index 58385f88e55f..60339169e0fe 100644 --- a/platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironment.java +++ b/platform/lang-api/src/com/intellij/execution/runners/ExecutionEnvironment.java @@ -40,13 +40,14 @@ public class ExecutionEnvironment extends UserDataHolderBase { @Nullable private RunnerSettings myRunnerSettings; @Nullable private ConfigurationPerRunnerSettings myConfigurationSettings; - @Nullable private RunnerAndConfigurationSettings myRunnerAndConfigurationSettings; + @Nullable private final RunnerAndConfigurationSettings myRunnerAndConfigurationSettings; @Nullable private final RunContentDescriptor myContentToReuse; @TestOnly public ExecutionEnvironment() { myProject = null; myContentToReuse = null; + myRunnerAndConfigurationSettings = null; } public ExecutionEnvironment(@NotNull final ProgramRunner runner, diff --git a/platform/lang-api/src/com/intellij/usageView/UsageTreeColorsScheme.java b/platform/lang-api/src/com/intellij/usageView/UsageTreeColorsScheme.java index 9e865ccd3083..ef205b037478 100644 --- a/platform/lang-api/src/com/intellij/usageView/UsageTreeColorsScheme.java +++ b/platform/lang-api/src/com/intellij/usageView/UsageTreeColorsScheme.java @@ -22,10 +22,14 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.ui.ColorUtil; +import com.intellij.util.ui.UIUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import java.awt.*; + public class UsageTreeColorsScheme implements NamedComponent, JDOMExternalizable{ private EditorColorsScheme myColorsScheme; private final EditorColorsManager myEditorColorsManager; @@ -51,7 +55,13 @@ public class UsageTreeColorsScheme implements NamedComponent, JDOMExternalizable public void readExternal(Element element) throws InvalidDataException { if (myColorsScheme == null){ - myColorsScheme = (EditorColorsScheme) myEditorColorsManager.getScheme(EditorColorsManager.DEFAULT_SCHEME_NAME).clone(); + Color color = UIUtil.getTreeTextBackground(); + if (color != null && ColorUtil.isDark(color)) { + myColorsScheme = (EditorColorsScheme)myEditorColorsManager.getGlobalScheme().clone(); + } + else { + myColorsScheme = (EditorColorsScheme)myEditorColorsManager.getScheme(EditorColorsManager.DEFAULT_SCHEME_NAME).clone(); + } } myColorsScheme.readExternal(element); } diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form index 3b0391ecd073..aab91296ed1b 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form @@ -304,7 +304,7 @@ - + @@ -317,7 +317,7 @@ - + @@ -333,44 +333,15 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java index 10e79040227f..334745b88800 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java @@ -21,10 +21,8 @@ import com.intellij.application.options.OptionsApplicabilityFilter; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPass; -import com.intellij.codeInsight.documentation.QuickDocOnMouseOverManager; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.application.ApplicationBundle; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; @@ -41,7 +39,6 @@ import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; @@ -49,11 +46,11 @@ import java.awt.event.ItemEvent; import java.awt.event.ItemListener; public class EditorOptionsPanel { - private JPanel myBehaviourPanel; + private JPanel myBehaviourPanel; private JCheckBox myCbHighlightBraces; private static final String STRIP_CHANGED = ApplicationBundle.message("combobox.strip.modified.lines"); - private static final String STRIP_ALL = ApplicationBundle.message("combobox.strip.all"); + private static final String STRIP_ALL = ApplicationBundle.message("combobox.strip.all"); private static final String STRIP_NONE = ApplicationBundle.message("combobox.strip.none"); private JComboBox myStripTrailingSpacesCombo; @@ -66,34 +63,32 @@ public class EditorOptionsPanel { private JCheckBox myCbHighlightScope; private JTextField myClipboardContentLimitTextField; - private JCheckBox myCbSmoothScrolling; - private JCheckBox myCbVirtualPageAtBottom; - private JCheckBox myCbEnableDnD; - private JCheckBox myCbEnableWheelFontChange; - private JCheckBox myCbHonorCamelHumpsWhenSelectingByClicking; + private JCheckBox myCbSmoothScrolling; + private JCheckBox myCbVirtualPageAtBottom; + private JCheckBox myCbEnableDnD; + private JCheckBox myCbEnableWheelFontChange; + private JCheckBox myCbHonorCamelHumpsWhenSelectingByClicking; - private JPanel myHighlightSettingsPanel; + private JPanel myHighlightSettingsPanel; private JRadioButton myRbPreferScrolling; private JRadioButton myRbPreferMovingCaret; - private JCheckBox myCbRenameLocalVariablesInplace; - private JCheckBox myCbHighlightIdentifierUnderCaret; - private JCheckBox myCbEnsureBlankLineBeforeCheckBox; - private JCheckBox myShowReformatCodeDialogCheckBox; - private JCheckBox myShowOptimizeImportsDialogCheckBox; - private JCheckBox myCbUseSoftWrapsAtEditor; - private JCheckBox myCbUseSoftWrapsAtConsole; - private JCheckBox myCbUseCustomSoftWrapIndent; - private JTextField myCustomSoftWrapIndent; - private JCheckBox myCbShowAllSoftWraps; - private JCheckBox myPreselectCheckBox; - private JCheckBox myCbShowQuickDocOnCheckBox; - private JTextField myQuickDocDelayTextField; + private JCheckBox myCbRenameLocalVariablesInplace; + private JCheckBox myCbHighlightIdentifierUnderCaret; + private JCheckBox myCbEnsureBlankLineBeforeCheckBox; + private JCheckBox myShowReformatCodeDialogCheckBox; + private JCheckBox myShowOptimizeImportsDialogCheckBox; + private JCheckBox myCbUseSoftWrapsAtEditor; + private JCheckBox myCbUseSoftWrapsAtConsole; + private JCheckBox myCbUseCustomSoftWrapIndent; + private JTextField myCustomSoftWrapIndent; + private JCheckBox myCbShowAllSoftWraps; + private JCheckBox myPreselectCheckBox; private final ErrorHighlightingPanel myErrorHighlightingPanel = new ErrorHighlightingPanel(); private final MyConfigurable myConfigurable; - public EditorOptionsPanel() { + public EditorOptionsPanel(){ if (SystemInfo.isMac) { myCbEnableWheelFontChange.setText(ApplicationBundle.message("checkbox.enable.ctrl.mousewheel.changes.font.size.macos")); } @@ -111,7 +106,6 @@ public class EditorOptionsPanel { myCbRenameLocalVariablesInplace.setVisible(OptionsApplicabilityFilter.isApplicable(OptionId.RENAME_IN_PLACE)); myConfigurable = new MyConfigurable(); - initQuickDocProcessing(); initSoftWrapsSettingsProcessing(); } @@ -162,9 +156,6 @@ public class EditorOptionsPanel { } myCbEnsureBlankLineBeforeCheckBox.setSelected(editorSettings.isEnsureNewLineAtEOF()); - myCbShowQuickDocOnCheckBox.setSelected(editorSettings.isShowQuickDocOnMouseOverElement()); - myQuickDocDelayTextField.setText(Long.toString(editorSettings.getQuickDocOnMouseOverElementDelayMillis())); - myQuickDocDelayTextField.setEnabled(editorSettings.isShowQuickDocOnMouseOverElement()); // Advanced mouse myCbEnableDnD.setSelected(editorSettings.isDndEnabled()); @@ -244,17 +235,6 @@ public class EditorOptionsPanel { editorSettings.setEnsureNewLineAtEOF(myCbEnsureBlankLineBeforeCheckBox.isSelected()); - if (myCbShowQuickDocOnCheckBox.isSelected() ^ editorSettings.isShowQuickDocOnMouseOverElement()) { - boolean enabled = myCbShowQuickDocOnCheckBox.isSelected(); - editorSettings.setShowQuickDocOnMouseOverElement(enabled); - ServiceManager.getService(QuickDocOnMouseOverManager.class).setEnabled(enabled); - } - - Long quickDocDelay = getQuickDocDelayFromGui(); - if (quickDocDelay != null) { - editorSettings.setQuickDocOnMouseOverElementDelayMillis(quickDocDelay); - } - editorSettings.setDndEnabled(myCbEnableDnD.isSelected()); editorSettings.setWheelFontChangeEnabled(myCbEnableWheelFontChange.isSelected()); @@ -288,23 +268,6 @@ public class EditorOptionsPanel { restartDaemons(); } - @Nullable - private Long getQuickDocDelayFromGui() { - String quickDocDelayAsText = myQuickDocDelayTextField.getText(); - if (StringUtil.isEmptyOrSpaces(quickDocDelayAsText)) { - return null; - } - - try { - long delay = Long.parseLong(quickDocDelayAsText); - return delay > 0 ? delay : null; - } - catch (NumberFormatException e) { - // Ignore incorrect value. - return null; - } - } - public static void restartDaemons() { Project[] projects = ProjectManager.getInstance().getOpenProjects(); for (Project project : projects) { @@ -378,11 +341,6 @@ public class EditorOptionsPanel { // Strip trailing spaces, ensure EOL on EOF on save isModified |= !getStripTrailingSpacesValue().equals(editorSettings.getStripTrailingSpaces()); isModified |= isModified(myCbEnsureBlankLineBeforeCheckBox, editorSettings.isEnsureNewLineAtEOF()); - isModified |= isModified(myCbShowQuickDocOnCheckBox, editorSettings.isShowQuickDocOnMouseOverElement()); - Long quickDocDelay = getQuickDocDelayFromGui(); - if (quickDocDelay != null && !quickDocDelay.equals(Long.valueOf(editorSettings.getQuickDocOnMouseOverElementDelayMillis()))) { - return true; - } // advanced mouse isModified |= isModified(myCbEnableDnD, editorSettings.isDndEnabled()); @@ -403,9 +361,7 @@ public class EditorOptionsPanel { isModified |= myErrorHighlightingPanel.isModified(); return isModified; } - - - + private static boolean isModified(JToggleButton checkBox, boolean value) { return checkBox.isSelected() != value; } @@ -448,15 +404,6 @@ public class EditorOptionsPanel { return defaultIndent; } - private void initQuickDocProcessing() { - myCbShowQuickDocOnCheckBox.addItemListener(new ItemListener() { - @Override - public void itemStateChanged(ItemEvent e) { - myQuickDocDelayTextField.setEnabled(myCbShowQuickDocOnCheckBox.isSelected()); - } - }); - } - private void initSoftWrapsSettingsProcessing() { ItemListener listener = new ItemListener() { @Override diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index 93126fa3acda..7055f9957b4d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -47,6 +47,7 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.Trinity; import com.intellij.openapi.util.text.StringUtil; @@ -490,7 +491,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass } }, myProject.getDisposed(), 200); - private final Set emptyActionRegistered = Collections.synchronizedSet(new THashSet()); + private final Set> emptyActionRegistered = Collections.synchronizedSet(new THashSet>()); private void addDescriptorIncrementally(@NotNull final ProblemDescriptor descriptor, @NotNull final LocalInspectionToolWrapper tool, @@ -569,7 +570,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass InspectionProfile inspectionProfile = InspectionProjectProfileManager.getInstance(myProject).getInspectionProfile(); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); InjectedLanguageManager ilManager = InjectedLanguageManager.getInstance(myProject); - Set emptyActionRegistered = new THashSet(); + Set> emptyActionRegistered = new THashSet>(); for (Map.Entry> entry : result.entrySet()) { indicator.checkCanceled(); @@ -593,7 +594,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass } private void createHighlightsForDescriptor(List outInfos, - Set emptyActionRegistered, + Set> emptyActionRegistered, InjectedLanguageManager ilManager, PsiFile file, Document documentRange, @@ -633,7 +634,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass private HighlightInfo createHighlightInfo(@NotNull ProblemDescriptor descriptor, @NotNull LocalInspectionToolWrapper tool, @NotNull HighlightInfoType level, - @NotNull Set emptyActionRegistered, + @NotNull Set> emptyActionRegistered, @NotNull PsiElement element) { @NonNls String message = ProblemDescriptionNode.renderDescriptionMessage(descriptor, element); @@ -665,7 +666,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass private static void registerQuickFixes(final LocalInspectionToolWrapper tool, final ProblemDescriptor descriptor, @NotNull HighlightInfo highlightInfo, - final Set emptyActionRegistered) { + final Set> emptyActionRegistered) { final HighlightDisplayKey key = HighlightDisplayKey.find(tool.getShortName()); boolean needEmptyAction = true; final QuickFix[] fixes = descriptor.getFixes(); @@ -685,7 +686,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass if (((ProblemDescriptorImpl)descriptor).getEnforcedTextAttributes() != null) { needEmptyAction = false; } - if (needEmptyAction && emptyActionRegistered.add(new TextRange(highlightInfo.fixStartOffset, highlightInfo.fixEndOffset))) { + if (needEmptyAction && emptyActionRegistered.add(Pair.create(new TextRange(highlightInfo.fixStartOffset, highlightInfo.fixEndOffset), tool.getShortName()))) { EmptyIntentionAction emptyIntentionAction = new EmptyIntentionAction(tool.getDisplayName()); QuickFixAction.registerQuickFixAction(highlightInfo, emptyIntentionAction, key); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowAutoImportPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowAutoImportPass.java index f01f7dcac22c..2dd47e6958d3 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowAutoImportPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowAutoImportPass.java @@ -39,6 +39,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiReference; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; @@ -102,7 +103,8 @@ public class ShowAutoImportPass extends TextEditorHighlightingPass { if (!info.hasHint() || info.getSeverity() != HighlightSeverity.ERROR) { return true; } - if (TextRange.create(info.getActualStartOffset(), info.getActualEndOffset()).containsOffset(caretOffset)) return true; + PsiReference reference = myFile.findReferenceAt(info.getActualStartOffset()); + if (reference != null && reference.getElement().getTextRange().containsOffset(caretOffset)) return true; infos.add(info); return true; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java index 2d8469c26136..b42eeb14e60f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -180,8 +180,8 @@ public class DocumentationManager extends DockablePopupManager - * Not thread-safe. - * - * @author Denis Zhdanov - * @since 7/2/12 9:09 AM - */ -public class QuickDocOnMouseOverManager { - - @NotNull private final EditorMouseMotionListener myMouseListener = new MyEditorMouseListener(); - @NotNull private final VisibleAreaListener myVisibleAreaListener = new MyVisibleAreaListener(); - @NotNull private final CaretListener myCaretListener = new MyCaretListener(); - @NotNull private final DocumentListener myDocumentListener = new MyDocumentListener(); - @NotNull private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); - @NotNull private final Runnable myRequest = new MyShowQuickDocRequest(); - @NotNull private final Runnable myHintCloseCallback = new MyCloseDocCallback(); - @NotNull private final Map myMonitoredDocuments = new WeakHashMap(); - - private final Map myActiveElements - = new WeakHashMap(); - - /** Holds a reference (if any) to the documentation manager used last time to show an 'auto quick doc' popup. */ - @Nullable private WeakReference myDocumentationManager; - - @Nullable private DelayedQuickDocInfo myDelayedQuickDocInfo; - private boolean myEnabled; - private boolean myApplicationActive; - - public QuickDocOnMouseOverManager(@NotNull Application application) { - EditorFactory factory = EditorFactory.getInstance(); - if (factory != null) { - factory.addEditorFactoryListener(new MyEditorFactoryListener(), application); - } - - ApplicationManager.getApplication().getMessageBus().connect().subscribe( - ApplicationActivationListener.TOPIC, - new ApplicationActivationListener() { - @Override - public void applicationActivated(IdeFrame ideFrame) { - myApplicationActive = true; - } - - @Override - public void applicationDeactivated(IdeFrame ideFrame) { - myApplicationActive = false; - } - }); - } - - /** - * Instructs the manager to enable or disable 'show quick doc automatically when the mouse goes over an editor element' mode. - * - * @param enabled flag that identifies if quick doc should be automatically shown - */ - public void setEnabled(boolean enabled) { - myEnabled = enabled; - myApplicationActive = enabled; - if (!enabled) { - closeQuickDocIfPossible(); - myAlarm.cancelAllRequests(); - } - EditorFactory factory = EditorFactory.getInstance(); - if (factory == null) { - return; - } - for (Editor editor : factory.getAllEditors()) { - if (enabled) { - registerListeners(editor); - } - else { - unRegisterListeners(editor); - } - } - } - - private void registerListeners(@NotNull Editor editor) { - editor.addEditorMouseMotionListener(myMouseListener); - editor.getScrollingModel().addVisibleAreaListener(myVisibleAreaListener); - editor.getCaretModel().addCaretListener(myCaretListener); - - Document document = editor.getDocument(); - if (myMonitoredDocuments.put(document, Boolean.TRUE) == null) { - document.addDocumentListener(myDocumentListener); - } - } - - private void unRegisterListeners(@NotNull Editor editor) { - editor.removeEditorMouseMotionListener(myMouseListener); - editor.getScrollingModel().removeVisibleAreaListener(myVisibleAreaListener); - editor.getCaretModel().removeCaretListener(myCaretListener); - - Document document = editor.getDocument(); - if (myMonitoredDocuments.remove(document) != null) { - document.removeDocumentListener(myDocumentListener); - } - } - - private void processMouseMove(@NotNull EditorMouseEvent e) { - if (!myApplicationActive || e.getArea() != EditorMouseEventArea.EDITING_AREA) { - // Skip if the mouse is not at the editing area. - closeQuickDocIfPossible(); - return; - } - - if (e.getMouseEvent().getModifiers() != 0) { - // Don't show the control when any modifier is active (e.g. Ctrl or Alt is hold). There is a common situation that a user - // wants to navigate via Ctrl+click or perform quick evaluate by Alt+click. - return; - } - - Editor editor = e.getEditor(); - if (editor.isOneLineMode()) { - // Don't want auto quick doc to mess at, say, editor used for debugger condition. - return; - } - - Project project = editor.getProject(); - if (project == null) { - return; - } - - DocumentationManager documentationManager = DocumentationManager.getInstance(project); - JBPopup hint = documentationManager.getDocInfoHint(); - if (hint != null) { - - // Skip the event if the control is shown because of explicit 'show quick doc' action call. - WeakReference ref = myDocumentationManager; - if (ref == null) { - return; - } - DocumentationManager manager = ref.get(); - if (manager == null || !manager.isCloseOnSneeze()) { - return; - } - - // Skip the event if the mouse is under the opened quick doc control. - Point hintLocation = hint.getLocationOnScreen(); - Dimension hintSize = hint.getSize(); - int mouseX = e.getMouseEvent().getXOnScreen(); - int mouseY = e.getMouseEvent().getYOnScreen(); - if (mouseX >= hintLocation.x && mouseX <= hintLocation.x + hintSize.width && mouseY >= hintLocation.y - && mouseY <= hintLocation.y + hintSize.height) - { - return; - } - } - - PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); - if (psiFile == null) { - closeQuickDocIfPossible(); - return; - } - - int mouseOffset = editor.logicalPositionToOffset(editor.xyToLogicalPosition(e.getMouseEvent().getPoint())); - PsiElement elementUnderMouse = psiFile.findElementAt(mouseOffset); - if (elementUnderMouse == null || elementUnderMouse instanceof PsiWhiteSpace) { - closeQuickDocIfPossible(); - return; - } - - PsiElement targetElementUnderMouse = documentationManager.findTargetElement(editor, mouseOffset, psiFile, elementUnderMouse); - if (targetElementUnderMouse == null) { - // No PSI element is located under the current mouse position - close quick doc if any. - closeQuickDocIfPossible(); - return; - } - - PsiElement activeElement = myActiveElements.get(editor); - if (targetElementUnderMouse.equals(activeElement) - && (myAlarm.getActiveRequestCount() > 0 // Request to show documentation for the target component has been already queued. - || hint != null)) // Documentation for the target component is being shown. - { - return; - } - allowUpdateFromContext(false); - closeQuickDocIfPossible(); - myActiveElements.put(editor, targetElementUnderMouse); - myDelayedQuickDocInfo = new DelayedQuickDocInfo(documentationManager, editor, targetElementUnderMouse, elementUnderMouse); - - myAlarm.cancelAllRequests(); - myAlarm.addRequest(myRequest, EditorSettingsExternalizable.getInstance().getQuickDocOnMouseOverElementDelayMillis()); - } - - private void closeQuickDocIfPossible() { - myAlarm.cancelAllRequests(); - DocumentationManager docManager = getDocManager(); - if (docManager == null) { - return; - } - - JBPopup hint = docManager.getDocInfoHint(); - if (hint == null) { - return; - } - - hint.cancel(); - myDocumentationManager = null; - } - - private void allowUpdateFromContext(boolean allow) { - DocumentationManager documentationManager = getDocManager(); - if (documentationManager != null) { - documentationManager.setAllowContentUpdateFromContext(allow); - } - } - - @Nullable - private DocumentationManager getDocManager() { - WeakReference ref = myDocumentationManager; - if (ref == null) { - return null; - } - - DocumentationManager docManager = ref.get(); - if (docManager == null) { - return null; - } - return docManager; - } - - private static class DelayedQuickDocInfo { - - @NotNull public final DocumentationManager docManager; - @NotNull public final Editor editor; - @NotNull public final PsiElement targetElement; - @NotNull public final PsiElement originalElement; - - private DelayedQuickDocInfo(@NotNull DocumentationManager docManager, - @NotNull Editor editor, @NotNull PsiElement targetElement, - @NotNull PsiElement originalElement) - { - this.docManager = docManager; - this.editor = editor; - this.targetElement = targetElement; - this.originalElement = originalElement; - } - } - - private class MyShowQuickDocRequest implements Runnable { - - private final HintManager myHintManager = HintManager.getInstance(); - - @Override - public void run() { - myAlarm.cancelAllRequests(); - - // Skip the request if it's outdated (the mouse is moved other another element). - DelayedQuickDocInfo info = myDelayedQuickDocInfo; - if (info == null || !info.targetElement.equals(myActiveElements.get(info.editor))) { - return; - } - - // Skip the request if there is a control shown as a result of explicit 'show quick doc' (Ctrl + Q) invocation. - if (info.docManager.getDocInfoHint() != null && !info.docManager.isCloseOnSneeze()) { - return; - } - - // We don't want to show a quick doc control if there is an active hint (e.g. the mouse is under an invalid element - // and corresponding error info is shown). - if (!info.docManager.hasDockedDocWindow() && myHintManager.hasShownHintsThatWillHideByOtherHint(false)) { - myAlarm.addRequest(this, EditorSettingsExternalizable.getInstance().getQuickDocOnMouseOverElementDelayMillis()); - return; - } - - info.editor.putUserData(PopupFactoryImpl.ANCHOR_POPUP_POSITION, - info.editor.offsetToVisualPosition(info.originalElement.getTextRange().getStartOffset())); - try { - info.docManager.showJavaDocInfo(info.editor, info.targetElement, info.originalElement, myHintCloseCallback, true, true); - myDocumentationManager = new WeakReference(info.docManager); - } - finally { - info.editor.putUserData(PopupFactoryImpl.ANCHOR_POPUP_POSITION, null); - } - } - } - - private class MyCloseDocCallback implements Runnable { - @Override - public void run() { - myActiveElements.clear(); - myDocumentationManager = null; - } - } - - private class MyEditorFactoryListener implements EditorFactoryListener { - @Override - public void editorCreated(@NotNull EditorFactoryEvent event) { - if (myEnabled) { - registerListeners(event.getEditor()); - } - } - - @Override - public void editorReleased(@NotNull EditorFactoryEvent event) { - if (myEnabled) { - // We do this in the 'if' block because editor logs an error on attempt to remove already released listener. - unRegisterListeners(event.getEditor()); - } - } - } - - private class MyEditorMouseListener extends EditorMouseMotionAdapter { - - @Override - public void mouseMoved(EditorMouseEvent e) { - processMouseMove(e); - } - } - - private class MyVisibleAreaListener implements VisibleAreaListener { - @Override - public void visibleAreaChanged(VisibleAreaEvent e) { - closeQuickDocIfPossible(); - } - } - - private class MyCaretListener implements CaretListener { - @Override - public void caretPositionChanged(CaretEvent e) { - allowUpdateFromContext(true); - closeQuickDocIfPossible(); - } - } - - private class MyDocumentListener extends DocumentAdapter { - @Override - public void documentChanged(DocumentEvent e) { - closeQuickDocIfPossible(); - } - } -} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverStartupActivity.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverStartupActivity.java deleted file mode 100644 index 7c9de68b4362..000000000000 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverStartupActivity.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2000-2012 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.codeInsight.documentation; - -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.startup.StartupActivity; - -/** - * @author Denis Zhdanov - * @since 7/2/12 9:44 AM - */ -public class QuickDocOnMouseOverStartupActivity implements StartupActivity { - - @Override - public void runActivity(Project project) { - if (EditorSettingsExternalizable.getInstance().isShowQuickDocOnMouseOverElement()) { - ServiceManager.getService(QuickDocOnMouseOverManager.class).setEnabled(true); - } - } -} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java index e3022dceeb20..1d7bc392995c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java @@ -29,10 +29,12 @@ import com.intellij.ide.util.EditSourceUtil; import com.intellij.lang.documentation.DocumentationProvider; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.NavigationItem; -import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.actionSystem.MouseShortcut; -import com.intellij.openapi.actionSystem.Shortcut; -import com.intellij.openapi.application.*; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.impl.ActionButton; +import com.intellij.openapi.actionSystem.impl.PresentationFactory; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -56,6 +58,8 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -69,6 +73,7 @@ import com.intellij.usageView.UsageViewShortNameLocation; import com.intellij.usageView.UsageViewTypeLocation; import com.intellij.util.Processor; import org.intellij.lang.annotations.JdkConstants; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -84,14 +89,19 @@ import java.util.List; public class CtrlMouseHandler extends AbstractProjectComponent { - private static final int ourQuickDocRowsNumber = getIntProperty("quick.doc.desired.rows.number", 2); - private static final int ourQuickDocSymbolsInRowNumber = getIntProperty("quick.doc.desired.symbols.in.row.number", 80); + public static final DataKey> + ELEMENT_UNDER_MOUSE_INFO_KEY = DataKey.create("ElementUnderMouseInfo"); + + private static final AnAction[] ourTooltipActions = { + new ShowQuickDocFromTooltipAction(), new ShowQuickDocAtPinnedWindowFromTooltipAction() + }; private final TextAttributes ourReferenceAttributes; private HighlightersSet myHighlighter; @JdkConstants.InputEventMask private int myStoredModifiers = 0; private TooltipProvider myTooltipProvider = null; - private final FileEditorManager myFileEditorManager; + private final FileEditorManager myFileEditorManager; + private final DocumentationManager myDocumentationManager; private enum BrowseMode {None, Declaration, TypeDeclaration, Implementation} @@ -194,17 +204,26 @@ public class CtrlMouseHandler extends AbstractProjectComponent { .createTextAttributesKey("CTRL_CLICKABLE", new TextAttributes(Color.blue, null, Color.blue, EffectType.LINE_UNDERSCORE, 0)); public CtrlMouseHandler(final Project project, StartupManager startupManager, EditorColorsManager colorsManager, - FileEditorManager fileEditorManager) { + FileEditorManager fileEditorManager, @NotNull DocumentationManager documentationManager, + @NotNull final EditorFactory editorFactory) + { super(project); startupManager.registerPostStartupActivity(new DumbAwareRunnable() { public void run() { - EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster(); + EditorEventMulticaster eventMulticaster = editorFactory.getEventMulticaster(); eventMulticaster.addEditorMouseListener(myEditorMouseAdapter, project); eventMulticaster.addEditorMouseMotionListener(myEditorMouseMotionListener, project); + eventMulticaster.addCaretListener(new CaretListener() { + @Override + public void caretPositionChanged(CaretEvent e) { + myDocumentationManager.setAllowContentUpdateFromContext(true); + } + }, project); } }); ourReferenceAttributes = colorsManager.getGlobalScheme().getAttributes(CTRL_CLICKABLE_ATTRIBUTES_KEY); myFileEditorManager = fileEditorManager; + myDocumentationManager = documentationManager; } @NotNull @@ -212,20 +231,6 @@ public class CtrlMouseHandler extends AbstractProjectComponent { return "CtrlMouseHandler"; } - private static int getIntProperty(@NotNull String propertyName, int defaultValue) { - String valueAsString = System.getProperty(propertyName); - if (valueAsString == null) { - return defaultValue; - } - - try { - return Integer.parseInt(valueAsString); - } - catch (Exception e) { - return defaultValue; - } - } - private static BrowseMode getBrowseMode(@JdkConstants.InputEventMask int modifiers) { if (modifiers != 0) { final Keymap activeKeymap = KeymapManager.getInstance().getActiveKeymap(); @@ -263,8 +268,8 @@ public class CtrlMouseHandler extends AbstractProjectComponent { if (result != null) { String fullText = documentationProvider.generateDoc(element, atPointer); String qName = element instanceof PsiQualifiedNamedElement ? ((PsiQualifiedNamedElement)element).getQualifiedName() : null; - String text = DocPreviewUtil.buildPreview(result, qName, fullText, ourQuickDocRowsNumber, ourQuickDocSymbolsInRowNumber); - return new DocInfo(text, documentationProvider, atPointer); + String text = DocPreviewUtil.buildPreview(result, qName, fullText); + return new DocInfo(text, documentationProvider, element); } return DocInfo.EMPTY; } @@ -343,6 +348,8 @@ public class CtrlMouseHandler extends AbstractProjectComponent { public abstract boolean isValid(Document document); + public abstract void showDocInfo(@NotNull DocumentationManager docManager); + protected boolean rangesAreCorrect(Document document) { final TextRange docRange = new TextRange(0, document.getTextLength()); for (TextRange range : getRanges()) { @@ -392,6 +399,12 @@ public class CtrlMouseHandler extends AbstractProjectComponent { return rangesAreCorrect(document); } + + @Override + public void showDocInfo(@NotNull DocumentationManager docManager) { + docManager.showJavaDocInfo(myTargetElement, myElementAtPointer, true, null); + docManager.setAllowContentUpdateFromContext(false); + } } private static class InfoMultiple extends Info { @@ -408,6 +421,11 @@ public class CtrlMouseHandler extends AbstractProjectComponent { public boolean isValid(Document document) { return rangesAreCorrect(document); } + + @Override + public void showDocInfo(@NotNull DocumentationManager docManager) { + // Do nothing + } } @Nullable @@ -608,19 +626,48 @@ public class CtrlMouseHandler extends AbstractProjectComponent { DocInfo docInfo = info.getInfo(); if (docInfo.text == null) return; + + if (myDocumentationManager.hasActiveDockedDocWindow()) { + info.showDocInfo(myDocumentationManager); + } - HyperlinkListener listener = (docInfo.docProvider == null || docInfo.context == null) + HyperlinkListener hyperlinkListener = docInfo.docProvider == null ? null - : new QuickDocHyperlinkListener(myProject, docInfo.docProvider, docInfo.context); - JComponent label = HintUtil.createInformationLabel(docInfo.text, listener); - final LightweightHint hint = new LightweightHint(label); + : new QuickDocHyperlinkListener(myProject, myDocumentationManager, docInfo.docProvider, + info.myElementAtPointer); + final Ref quickDocPaneRef = new Ref(); + MouseListener mouseListener = new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + QuickDocInfoPane pane = quickDocPaneRef.get(); + if (pane != null) { + pane.mouseEntered(e); + } + } + + @Override + public void mouseExited(MouseEvent e) { + QuickDocInfoPane pane = quickDocPaneRef.get(); + if (pane != null) { + pane.mouseExited(e); + } + } + }; + JComponent label = HintUtil.createInformationLabel(docInfo.text, hyperlinkListener, mouseListener); + QuickDocInfoPane quickDocPane = null; + if (docInfo.documentationAnchor != null) { + quickDocPane = new QuickDocInfoPane(docInfo.documentationAnchor, info.myElementAtPointer, label); + quickDocPaneRef.set(quickDocPane); + } + + JComponent hintContent = quickDocPane == null ? label : quickDocPane; + final LightweightHint hint = new LightweightHint(hintContent); final HintManagerImpl hintManager = HintManagerImpl.getInstanceImpl(); Point p = HintManagerImpl.getHintPosition(hint, myEditor, myPosition, HintManager.ABOVE); hintManager.showEditorHint(hint, myEditor, p, HintManager.HIDE_BY_ANY_KEY | HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0, false, HintManagerImpl.createHintHint(myEditor, p, hint, HintManager.ABOVE).setContentActive(false)); } - } private HighlightersSet installHighlighterSet(Info info, Editor editor) { @@ -679,23 +726,105 @@ public class CtrlMouseHandler extends AbstractProjectComponent { @Nullable public final String text; @Nullable public final DocumentationProvider docProvider; - @Nullable public final PsiElement context; + @Nullable public final PsiElement documentationAnchor; - DocInfo(@Nullable String text, @Nullable DocumentationProvider provider, @Nullable PsiElement context) { + DocInfo(@Nullable String text, @Nullable DocumentationProvider provider, @Nullable PsiElement documentationAnchor) { this.text = text; docProvider = provider; - this.context = context; + this.documentationAnchor = documentationAnchor; + } + } + + private class QuickDocInfoPane extends JLayeredPane implements DataProvider { + + @NotNull private final List myButtons = new ArrayList(); + @NotNull private final Pair myElementUnderMouseInfo; + @NotNull private final JComponent myBaseDocControl; + + QuickDocInfoPane(@NotNull PsiElement documentationAnchor, @NotNull PsiElement elementUnderMouse, @NotNull JComponent baseDocControl) { + myElementUnderMouseInfo = Pair.create(documentationAnchor, elementUnderMouse); + myBaseDocControl = baseDocControl; + + PresentationFactory presentationFactory = new PresentationFactory(); + for (AnAction action : ourTooltipActions) { + Icon icon = action.getTemplatePresentation().getIcon(); + Dimension minSize = new Dimension(icon.getIconWidth(), icon.getIconHeight()); + myButtons.add(new ActionButton(action, presentationFactory.getPresentation(action), IdeTooltipManager.IDE_TOOLTIP_PLACE, minSize)); + } + Collections.reverse(myButtons); + + setPreferredSize(baseDocControl.getPreferredSize()); + setMaximumSize(baseDocControl.getMaximumSize()); + setMinimumSize(baseDocControl.getMinimumSize()); + setBackground(baseDocControl.getBackground()); + + add(baseDocControl, Integer.valueOf(0)); + for (JComponent button : myButtons) { + button.setBorder(null); + button.setBackground(baseDocControl.getBackground()); + add(button, Integer.valueOf(1)); + button.setVisible(false); + } + } + + @Override + public Object getData(@NonNls String dataId) { + return ELEMENT_UNDER_MOUSE_INFO_KEY.is(dataId) ? myElementUnderMouseInfo : null; + } + + @Override + public void doLayout() { + Rectangle bounds = getBounds(); + myBaseDocControl.setBounds(bounds); + + final int buttonsHGap = 5; + int x = bounds.width; + for (JComponent button : myButtons) { + Dimension buttonSize = button.getPreferredSize(); + x -= buttonSize.width; + button.setBounds(x, 0, buttonSize.width, buttonSize.height); + x -= buttonsHGap; + } + } + + public void mouseEntered(@NotNull MouseEvent e) { + processStateChangeIfNecessary(e.getLocationOnScreen(), true); + } + + public void mouseExited(@NotNull MouseEvent e) { + processStateChangeIfNecessary(e.getLocationOnScreen(), false); + } + + private void processStateChangeIfNecessary(@NotNull Point mouseScreenLocation, boolean mouseEntered) { + // Don't show 'view quick doc' buttons if docked quick doc control is already active. + if (myDocumentationManager.hasActiveDockedDocWindow()) { + return; + } + + // Skip event triggered when mouse leaves action button area. + if (!mouseEntered && new Rectangle(getLocationOnScreen(), getSize()).contains(mouseScreenLocation)) { + return; + } + for (JComponent button : myButtons) { + button.setVisible(mouseEntered); + } } } private static class QuickDocHyperlinkListener implements HyperlinkListener { @NotNull private final Project myProject; + @NotNull private final DocumentationManager myDocumentationManager; @NotNull private final DocumentationProvider myProvider; @NotNull private final PsiElement myContext; - QuickDocHyperlinkListener(@NotNull Project project, @NotNull DocumentationProvider provider, @NotNull PsiElement context) { + QuickDocHyperlinkListener(@NotNull Project project, + @NotNull DocumentationManager manager, + @NotNull DocumentationProvider provider, + @NotNull PsiElement context) + { myProject = project; + myDocumentationManager = manager; myProvider = provider; myContext = context; } @@ -712,11 +841,11 @@ public class CtrlMouseHandler extends AbstractProjectComponent { } String elementName = e.getDescription().substring(DocumentationManager.PSI_ELEMENT_PROTOCOL.length()); - + final PsiElement targetElement = myProvider.getDocumentationElementForLink(PsiManager.getInstance(myProject), elementName, myContext); if (targetElement != null) { ApplicationManager.getApplication().getComponent(IdeTooltipManager.class).hideCurrentNow(false); - DocumentationManager.getInstance(myProject).showJavaDocInfo(targetElement, myContext, true, null); + myDocumentationManager.showJavaDocInfo(targetElement, myContext, true, null); } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/DocPreviewUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/DocPreviewUtil.java index c96394c3c9de..898a06f1bc12 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/DocPreviewUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/DocPreviewUtil.java @@ -15,15 +15,16 @@ */ package com.intellij.codeInsight.navigation; +import com.intellij.codeInsight.documentation.DocumentationManager; import com.intellij.lang.documentation.DocumentationProvider; import com.intellij.psi.PsiElement; -import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Provides utility methods for building documentation preview. @@ -35,15 +36,12 @@ import java.util.Set; */ public class DocPreviewUtil { - private static final Set TAGS_TO_ADD_LF = new HashSet(Arrays.asList("p", "blockquote", "pre")); - private static final Set TAGS_TO_IGNORE = new HashSet(Arrays.asList("style", "b", "small")); - private DocPreviewUtil() { } /** - * Allows to build a documentation preview from the given arguments. Basically, takes given 'full documentation', wraps it according - * to the given 'desired rows and columns per-row' arguments and returns a result. + * Allows to build a documentation preview from the given arguments. Basically, takes given 'header' text and tries to modify + * it by using hyperlink information encapsulated at the given 'full text'. * * @param header target documentation header. Is expected to be a result of the * {@link DocumentationProvider#getQuickNavigateInfo(PsiElement, PsiElement)} call @@ -51,393 +49,165 @@ public class DocPreviewUtil { * (according to the given 'desired rows and columns per-row' arguments). A link that points to the * element with the given qualified name is added to the preview's end if the qName is provided then * @param fullText full documentation text (if available) - * @param desiredRowsNumber maximum number of rows to use at the preview's body ('header' text is not count here) - * @param desiredSymbolsInRowNumber desired max number of columns per row - * @return preview text to use for the given arguments */ @NotNull - public static String buildPreview(@NotNull String header, - @Nullable String qName, - @Nullable String fullText, - int desiredRowsNumber, - int desiredSymbolsInRowNumber) - { + public static String buildPreview(@NotNull final String header, @Nullable final String qName, @Nullable final String fullText) { if (fullText == null) { return header; } - int bodyStart = fullText.indexOf(""); - if (bodyStart < 0) { - return header; - } - bodyStart += "".length(); - - int bodyEnd = fullText.indexOf(""); - if (bodyEnd < 0) { - return header; + // Build links info. + Map links = new HashMap(); + process(fullText, new LinksCollector(links)); + if (qName != null) { + links.put(qName, DocumentationManager.PSI_ELEMENT_PROTOCOL + qName); } - String body = fullText.substring(bodyStart, bodyEnd); - - // The algorithm is: - // 1. Process full text body as follows: - // 1.1. Count non-markup symbols until desired row symbols number is exceeded; - // 1.2. Insert
after that to start a new row; - // 1.3. Stop processing as soon as the desired rows number is reached or the text is finished; - // 2. Add closing tags for all non-matched open tags; - - final Context context = new Context(desiredRowsNumber, desiredSymbolsInRowNumber); - int startParseOffset = 0; - - //region 1. Prepare header to use - - // Include information about the library/module location. - int bracket = header.indexOf(']'); - int lf = header.indexOf('\n'); - if (bracket > 0 && (lf < 0 || bracket < lf)) { - context.buffer.append(header.substring(0, bracket + 1)).append(" "); + // Apply links info to the header template. + String result = header.replace("\n", "
"); + for (Map.Entry entry : links.entrySet()) { + String visibleName = entry.getKey(); + int i = visibleName.lastIndexOf('.'); + if (i > 0 && i < visibleName.length() - 1) { + visibleName = visibleName.substring(i + 1); + } + result = result.replace(entry.getKey(), String.format("%s", entry.getValue(), visibleName)); } - - // Include information that is available at the given header (it's not count to the given rows/columns arguments). - startParseOffset = process(body, startParseOffset, body.length(), getHeaderParser(context, header)); - - //endregion - - //region Parse body - startParseOffset = process(body, startParseOffset, body.length(), getBodyParser(context)); - //endregion - - if (qName != null && startParseOffset < body.length()) { - context.buffer.append(String.format("<more>", qName)); - } - - //region Add closing tags - while (!context.openTags.isEmpty()) { - context.buffer.append("'); - } - //endregion - - return context.buffer.toString(); + return result; } + + private enum State {TEXT, INSIDE_OPEN_TAG, INSIDE_CLOSE_TAG} @SuppressWarnings("AssignmentToForLoopParameter") - private static int process(@NotNull String text, int start, int end, @NotNull Callback callback) { + private static int process(@NotNull String text, @NotNull Callback callback) { State state = State.TEXT; - int dataStartOffset = start; - int tagNameStartOffset = start; + int dataStartOffset = 0; + int tagNameStartOffset = 0; String tagName = null; - for (; start < end; start++) { - char c = text.charAt(start); + int i = 0; + for (; i < text.length(); i++) { + char c = text.charAt(i); switch (state) { case TEXT: if (c == '<') { - if (start > dataStartOffset) { - if (!callback.onText(text.substring(dataStartOffset, start).replace(" ", " "))) { + if (i > dataStartOffset) { + if (!callback.onText(text.substring(dataStartOffset, i).replace(" ", " "))) { return dataStartOffset; } } - dataStartOffset = start; - if (start < text.length() - 1 && text.charAt(start + 1) == '/') { + dataStartOffset = i; + if (i < text.length() - 1 && text.charAt(i + 1) == '/') { state = State.INSIDE_CLOSE_TAG; - tagNameStartOffset = ++start + 1; + tagNameStartOffset = ++i + 1; } else { state = State.INSIDE_OPEN_TAG; - tagNameStartOffset = start + 1; + tagNameStartOffset = i + 1; } } break; case INSIDE_OPEN_TAG: if (c == ' ') { - tagName = text.substring(tagNameStartOffset, start); + tagName = text.substring(tagNameStartOffset, i); } else if (c == '/') { - if (start < text.length() - 1 && text.charAt(start + 1) == '>') { + if (i < text.length() - 1 && text.charAt(i + 1) == '>') { if (tagName == null) { - tagName = text.substring(tagNameStartOffset, start); + tagName = text.substring(tagNameStartOffset, i); } - if (!callback.onStandaloneTag(tagName, text.substring(dataStartOffset, start + 2))) { + if (!callback.onStandaloneTag(tagName, text.substring(dataStartOffset, i + 2))) { return dataStartOffset; } tagName = null; state = State.TEXT; - dataStartOffset = ++start + 1; + dataStartOffset = ++i + 1; break; } } else if (c == '>') { if (tagName == null) { - tagName = text.substring(tagNameStartOffset, start); + tagName = text.substring(tagNameStartOffset, i); } - if (!callback.onOpenTag(tagName, text.substring(dataStartOffset, start + 1))) { + if (!callback.onOpenTag(tagName, text.substring(dataStartOffset, i + 1))) { return dataStartOffset; } tagName = null; state = State.TEXT; - dataStartOffset = start + 1; + dataStartOffset = i + 1; } break; case INSIDE_CLOSE_TAG: if (c == '>') { if (tagName == null) { - tagName = text.substring(tagNameStartOffset, start); + tagName = text.substring(tagNameStartOffset, i); } - if (!callback.onCloseTag(tagName, text.substring(dataStartOffset, start + 1))) { + if (!callback.onCloseTag(tagName, text.substring(dataStartOffset, i + 1))) { return dataStartOffset; } tagName = null; state = State.TEXT; - dataStartOffset = start + 1; + dataStartOffset = i + 1; } } } - return start; - } - - @NotNull - private static Callback getHeaderParser(@NotNull Context context, @NotNull final String header) { - return new AbstractCallback(context, false) { - - private boolean myStop; - - @Override - public boolean onOpenTag(@NotNull String name, @NotNull String text) { - return !myStop && super.onOpenTag(name, text); - } - @Override - public boolean onText(@NotNull String text) { - boolean addLf = false; - for (String s : text.split("\n")) { - if (addLf) { - newLine(); - } - else { - addLf = true; - } - - if (s.length() <= 0) { - continue; - } - - if (!header.contains(s) && s.startsWith("java.lang.")) { - s = s.substring("java.lang.".length()); - } - - if (myStop || !header.contains(s)) { - return false; - } - - if (header.endsWith(s)) { - myStop = true; - } - - addText(s); - } - if (text.endsWith("\n")) { - newLine(); - } - return true; - } - - @Override - protected boolean canBreakBeforeText(@NotNull String text) { - // Don't allow line break before the closing type parameter bracket. - return !text.startsWith(">") && !text.startsWith(","); - } - }; - } - - @NotNull - private static Callback getBodyParser(@NotNull final Context context) { - return new AbstractCallback(context, true) { - - @Override - public boolean onText(@NotNull String text) { - return addText(text); - } - }; - } - - private static class Context { + if (dataStartOffset < text.length()) { + callback.onText(text.substring(dataStartOffset, text.length()).replace(" ", " ")); + } - @NotNull public final Stack openTags = new Stack(); - @NotNull public final StringBuilder buffer = new StringBuilder(); - public final int rows; - public final int columnsPerRow; - public int currentRow; - public int currentColumn; - - public Context(int rows, int columnsPerRow) { - this.rows = rows; - this.columnsPerRow = columnsPerRow; - } + return i; } private interface Callback { boolean onOpenTag(@NotNull String name, @NotNull String text); - boolean onCloseTag(@NotNull String name, @NotNull String text); - boolean onStandaloneTag(@NotNull String name, @NotNull String text); - boolean onText(@NotNull String text); } - - private static abstract class AbstractCallback implements Callback { - @NotNull protected final Context myContext; - private final boolean myCountRows; - private boolean myScheduleNewLine; - private boolean myInsidePre; + private static class LinksCollector implements Callback { - protected AbstractCallback(@NotNull Context context, boolean countRows) { - myContext = context; - myCountRows = countRows; + private static final Pattern HREF_PATTERN = Pattern.compile("href=[\"']([^\"']+)"); + + @NotNull private final Map myLinks; + private String myHref; + + LinksCollector(@NotNull Map links) { + myLinks = links; } @Override public boolean onOpenTag(@NotNull String name, @NotNull String text) { - if ("pre".equals(name)) { - myInsidePre = true; + if (!"a".equals(name)) { + return true; } - if (!processDelayedLfTag(name)) { - return myContext.currentRow < myContext.rows; - } - - if (!TAGS_TO_IGNORE.contains(name)) { - myContext.buffer.append(text); - myContext.openTags.push(name); + Matcher matcher = HREF_PATTERN.matcher(text); + if (matcher.find()) { + myHref = matcher.group(1); } return true; } - private boolean processDelayedLfTag(@NotNull String name) { - if (!TAGS_TO_ADD_LF.contains(name)) { - if (myScheduleNewLine) { - newLine(); - } - return true; - } - - myScheduleNewLine = true; - return false; - } - @Override public boolean onCloseTag(@NotNull String name, @NotNull String text) { - if ("pre".equals(name)) { - myInsidePre = false; - } - - if (!processDelayedLfTag(name)) { - return myContext.currentRow < myContext.rows; - } - - if (!TAGS_TO_IGNORE.contains(name)) { - myContext.buffer.append(text); - myContext.openTags.remove(name); + if ("a".equals(name)) { + myHref = null; } return true; } @Override public boolean onStandaloneTag(@NotNull String name, @NotNull String text) { - if (!processDelayedLfTag(name)) { - return true; - } - - if (!TAGS_TO_IGNORE.contains(name)) { - myContext.buffer.append(text); - } return true; } @Override public boolean onText(@NotNull String text) { - myContext.buffer.append(text); - return true; - } - - protected boolean canBreakBeforeText(@NotNull String text) { - return true; - } - - protected boolean addText(@NotNull String text) { - boolean addSpace = false; - if (!text.isEmpty() && (text.startsWith(" ") || text.startsWith("\t"))) { - myContext.buffer.append(text.charAt(0)); - myContext.currentColumn++; - } - - String tailText = (!text.isEmpty() && (text.endsWith(" ") || text.endsWith("\t"))) ? text.substring(text.length() - 1) : null; - - text = text.trim(); - if (myInsidePre && text.contains("\n")) { - boolean addLf = false; - for (String s : text.split("\n")) { - if (addLf) { - newLine(); - if (myContext.currentRow >= myContext.rows) { - return false; - } - } - else { - addLf = true; - } - addText(s); - if (myContext.currentRow >= myContext.rows) { - return false; - } - } - return myContext.currentRow < myContext.rows; - } - - for (String s : text.split(" ")) { - s = s.trim(); - if (s.length() <= 0) { - continue; - } - - if (myScheduleNewLine && canBreakBeforeText(s)) { - newLine(); - addSpace = false; - if (myContext.currentRow >= myContext.rows) { - return false; - } - } - - if (addSpace) { - myContext.buffer.append(" "); - myContext.currentColumn++; - } - else { - addSpace = true; - } - - myContext.currentColumn += s.length(); - myContext.buffer.append(s); - if (myContext.currentColumn < myContext.columnsPerRow) { - continue; - } - myScheduleNewLine = true; - } - if (tailText != null) { - myContext.buffer.append(tailText); - myContext.currentColumn += tailText.length(); + if (myHref != null) { + myLinks.put(text, myHref); + myHref = null; } return true; } - - protected void newLine() { - myContext.buffer.append("
"); - myContext.currentColumn = 0; - myScheduleNewLine = false; - if (myCountRows) { - myContext.currentRow++; - } - } } - - private enum State {TEXT, INSIDE_OPEN_TAG, INSIDE_CLOSE_TAG} } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/ShowQuickDocAtPinnedWindowFromTooltipAction.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/ShowQuickDocAtPinnedWindowFromTooltipAction.java new file mode 100644 index 000000000000..3e3652cd9267 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/ShowQuickDocAtPinnedWindowFromTooltipAction.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2012 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.codeInsight.navigation; + +import com.intellij.codeInsight.documentation.DocumentationManager; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +/** + * @author Denis Zhdanov + * @since 7/13/12 11:43 AM + */ +public class ShowQuickDocAtPinnedWindowFromTooltipAction extends ShowQuickDocFromTooltipAction { + + public ShowQuickDocAtPinnedWindowFromTooltipAction() { + super(AllIcons.General.Pin_tab); + } + + @Override + protected void doActionPerformed(@NotNull Pair docInfo, @NotNull DocumentationManager docManager) { + docManager.createToolWindow(docInfo.first, docInfo.second); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/ShowQuickDocFromTooltipAction.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/ShowQuickDocFromTooltipAction.java new file mode 100644 index 000000000000..c044e8b9ec98 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/ShowQuickDocFromTooltipAction.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2012 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.codeInsight.navigation; + +import com.intellij.codeInsight.documentation.DocumentationManager; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.ide.IdeTooltip; +import com.intellij.ide.IdeTooltipManager; +import com.intellij.idea.ActionsBundle; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiElement; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.lang.ref.WeakReference; + +/** + * @author Denis Zhdanov + * @since 7/13/12 10:00 AM + */ +public class ShowQuickDocFromTooltipAction extends AnAction { + + @NotNull private final IdeTooltipManager myTooltipManager = IdeTooltipManager.getInstance(); + @NotNull private final DataManager myDataManager = DataManager.getInstance(); + + private WeakReference> myInfo; + + public ShowQuickDocFromTooltipAction() { + this(AllIcons.Actions.Find); + } + + public ShowQuickDocFromTooltipAction(@NotNull Icon icon) { + String className = getClass().getName(); + String actionId = className.substring(0, className.lastIndexOf("Action")); + getTemplatePresentation().setText(ActionsBundle.actionText(actionId)); + getTemplatePresentation().setDescription(ActionsBundle.actionDescription(actionId)); + getTemplatePresentation().setIcon(icon); + } + + @Override + public void update(AnActionEvent e) { + + // We can't use data context from the given event because it's built from the focused component and IDE tooltip doesn't have focus. + IdeTooltip tooltip = myTooltipManager.getCurrentTooltip(); + if (tooltip == null) { + return; + } + + JComponent component = tooltip.getTipComponent(); + if (component == null) { + return; + } + + Pair info = CtrlMouseHandler.ELEMENT_UNDER_MOUSE_INFO_KEY.getData(myDataManager.getDataContext(component)); + if (info != null) { + // Target info is retrieved during AnAction.update() processing because IDE tooltip is closed on action activation, + // i.e. IdeTooltipManager.getCurrentComponent() returns null during AnAction.actionPerformed() execution. + myInfo = new WeakReference>(info); + } + } + + @Override + public void actionPerformed(AnActionEvent e) { + WeakReference> infoRef = myInfo; + if (infoRef == null) { + return; + } + Pair info = infoRef.get(); + if (info == null) { + return; + } + + Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); + if (project == null) { + return; + } + + myInfo = null; + doActionPerformed(info, DocumentationManager.getInstance(project)); + } + + protected void doActionPerformed(@NotNull Pair docInfo, + @NotNull DocumentationManager docManager) + { + docManager.showJavaDocInfo(docInfo.first, docInfo.second, true, null); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java index 656946038734..3494cee4a608 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/CustomTemplateCallback.java @@ -114,7 +114,9 @@ public class CustomTemplateCallback { } public void startTemplate(Template template, Map predefinedValues, TemplateEditingListener listener) { - template.setToReformat(!myInInjectedFragment); + if(myInInjectedFragment) { + template.setToReformat(false); + } myTemplateManager.startTemplate(myEditor, template, false, predefinedValues, listener); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java b/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java index 64f63f0897c4..fd7a58ae8b5f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java @@ -36,6 +36,7 @@ public class LiveTemplateBuilder { private final List myVariableOccurences = new ArrayList(); private final List myMarkers = new ArrayList(); private String myLastEndVarName; + private boolean myIsToReformat = false; public CharSequence getText() { return myText; @@ -123,6 +124,7 @@ public class LiveTemplateBuilder { last = occurence.myOffset; } template.addTextSegment(myText.substring(last)); + template.setToReformat(myIsToReformat); return template; } @@ -215,6 +217,7 @@ public class LiveTemplateBuilder { }*/ public int insertTemplate(int offset, TemplateImpl template, Map predefinedVarValues) { + myIsToReformat = myText.length() > 0 || template.isToReformat(); removeEndVarAtOffset(offset); String text = template.getTemplateText(); @@ -301,17 +304,6 @@ public class LiveTemplateBuilder { } } - private boolean isInEmptyText(int offset) { - if (offset >= myText.length()) { - return false; - } - char c = myText.charAt(offset++); - while (Character.isWhitespace(c) && offset < myText.length()) { - c = myText.charAt(offset++); - } - return c == '<' || c == '"'; - } - private boolean hasVarAtOffset(int offset) { boolean flag = false; for (VarOccurence occurence : myVariableOccurences) { diff --git a/platform/lang-impl/src/com/intellij/conversion/DetachFacetConversionProcessor.java b/platform/lang-impl/src/com/intellij/conversion/DetachFacetConversionProcessor.java index d49b1d51b49f..42346df7e23a 100644 --- a/platform/lang-impl/src/com/intellij/conversion/DetachFacetConversionProcessor.java +++ b/platform/lang-impl/src/com/intellij/conversion/DetachFacetConversionProcessor.java @@ -19,6 +19,7 @@ package com.intellij.conversion; import com.intellij.facet.FacetManagerImpl; import org.jdom.Element; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.model.serialization.facet.JpsFacetLoader; import java.util.List; @@ -44,9 +45,9 @@ public class DetachFacetConversionProcessor extends ConversionProcessor getFacetElements(@NotNull String facetTypeId) { final Element facetManager = getComponentElement(FacetManagerImpl.COMPONENT_NAME); final ArrayList elements = new ArrayList(); - for (Element child : JDOMUtil.getChildren(facetManager, FacetManagerImpl.FACET_ELEMENT)) { - if (facetTypeId.equals(child.getAttributeValue(FacetManagerImpl.TYPE_ATTRIBUTE))) { + for (Element child : JDOMUtil.getChildren(facetManager, JpsFacetLoader.FACET_ELEMENT)) { + if (facetTypeId.equals(child.getAttributeValue(JpsFacetLoader.TYPE_ATTRIBUTE))) { elements.add(child); } } diff --git a/platform/lang-impl/src/com/intellij/execution/runners/RestartAction.java b/platform/lang-impl/src/com/intellij/execution/runners/RestartAction.java index 22b29784be92..70e138e8416b 100644 --- a/platform/lang-impl/src/com/intellij/execution/runners/RestartAction.java +++ b/platform/lang-impl/src/com/intellij/execution/runners/RestartAction.java @@ -1,112 +1,116 @@ -/* - * Copyright 2000-2009 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.execution.runners; - -import com.intellij.execution.*; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.ui.RunContentDescriptor; -import com.intellij.icons.AllIcons; -import com.intellij.ide.DataManager; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.keymap.KeymapManager; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - -/** - * @author dyoma - */ -public class RestartAction extends AnAction implements DumbAware { - private static final Icon STOP_AND_START_ICON = AllIcons.Actions.Restart; - - private ProcessHandler myProcessHandler; - private final ProgramRunner myRunner; - private final RunContentDescriptor myDescriptor; - private final Executor myExecutor; - private final Icon myIcon; - private final ExecutionEnvironment myEnvironment; - - public RestartAction(final Executor executor, - final ProgramRunner runner, - final ProcessHandler processHandler, - final Icon icon, - final RunContentDescriptor descritor, - @NotNull final ExecutionEnvironment env) { - super(null, null, icon); - myIcon = icon; - myEnvironment = env; - getTemplatePresentation().setEnabled(false); - myProcessHandler = processHandler; - myRunner = runner; - myDescriptor = descritor; - myExecutor = executor; - // see IDEADEV-698 - } - - public void actionPerformed(final AnActionEvent e) { - ExecutionManager.getInstance(myEnvironment.getProject()).restartRunProfile(myEnvironment.getProject(), - myExecutor, - myEnvironment.getExecutionTarget(), - myEnvironment.getRunnerAndConfigurationSettings()); - } - - public void restart() { - doRestart(DataManager.getInstance().getDataContext(myDescriptor.getComponent())); - } - - private void doRestart(final DataContext dataContext) { - final Project project = PlatformDataKeys.PROJECT.getData(dataContext); - if (ExecutorRegistry.getInstance().isStarting(project, myExecutor.getId(), myRunner.getRunnerId())) { - return; - } - try { - final ExecutionEnvironment old = myEnvironment; - myRunner.execute(myExecutor, new ExecutionEnvironment(old.getRunProfile(), - old.getExecutionTarget(), - project, - old.getRunnerSettings(), - old.getConfigurationSettings(), - myDescriptor, - old.getRunnerAndConfigurationSettings())); - } - catch (RunCanceledByUserException ignore) { - } - catch (ExecutionException e1) { - Messages.showErrorDialog(project, e1.getMessage(), ExecutionBundle.message("restart.error.message.title")); - } - } - - public void update(final AnActionEvent event) { - final Presentation presentation = event.getPresentation(); - presentation.setText(ExecutionBundle.message("rerun.configuration.action.name", myEnvironment.getRunProfile().getName())); - final boolean isRunning = myProcessHandler != null && !myProcessHandler.isProcessTerminated(); - if (myProcessHandler != null && !isRunning) { - myProcessHandler = null; // already terminated - } - presentation.setIcon(isRunning ? STOP_AND_START_ICON : myIcon); - boolean isTerminating = myProcessHandler != null && myProcessHandler.isProcessTerminating(); - boolean isStarting = ExecutorRegistry.getInstance().isStarting(myEnvironment.getProject(), myExecutor.getId(), myRunner.getRunnerId()); - presentation.setEnabled(!isStarting && !isTerminating); - } - - public void registerShortcut(final JComponent component) { - registerCustomShortcutSet(new CustomShortcutSet(KeymapManager.getInstance().getActiveKeymap().getShortcuts(IdeActions.ACTION_RERUN)), - component); - } -} +/* + * Copyright 2000-2009 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.execution.runners; + +import com.intellij.execution.*; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.icons.AllIcons; +import com.intellij.ide.DataManager; +import com.intellij.idea.ActionsBundle; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.keymap.KeymapManager; +import com.intellij.openapi.project.DumbAware; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author dyoma + */ +public class RestartAction extends AnAction implements DumbAware { + private static final Icon STOP_AND_START_ICON = AllIcons.Actions.Restart; + + private ProcessHandler myProcessHandler; + private final ProgramRunner myRunner; + private final RunContentDescriptor myDescriptor; + @NotNull private final Executor myExecutor; + private final Icon myIcon; + private final ExecutionEnvironment myEnvironment; + + public RestartAction(@NotNull final Executor executor, + final ProgramRunner runner, + final ProcessHandler processHandler, + final Icon icon, + final RunContentDescriptor descriptor, + @NotNull final ExecutionEnvironment env) { + super(null, null, icon); + myIcon = icon; + myEnvironment = env; + getTemplatePresentation().setEnabled(false); + myProcessHandler = processHandler; + myRunner = runner; + myDescriptor = descriptor; + myExecutor = executor; + // see IDEADEV-698 + } + + public void actionPerformed(final AnActionEvent e) { + ExecutionManager.getInstance(myEnvironment.getProject()).restartRunProfile(myEnvironment.getProject(), + myExecutor, + myEnvironment.getExecutionTarget(), + myEnvironment.getRunnerAndConfigurationSettings()); + } + + public void restart() { + doRestart(DataManager.getInstance().getDataContext(myDescriptor.getComponent())); + } + + private void doRestart(final DataContext dataContext) { + final Project project = PlatformDataKeys.PROJECT.getData(dataContext); + if (ExecutorRegistry.getInstance().isStarting(project, myExecutor.getId(), myRunner.getRunnerId())) { + return; + } + try { + final ExecutionEnvironment old = myEnvironment; + myRunner.execute(myExecutor, new ExecutionEnvironment(old.getRunProfile(), + old.getExecutionTarget(), + project, + old.getRunnerSettings(), + old.getConfigurationSettings(), + myDescriptor, + old.getRunnerAndConfigurationSettings())); + } + catch (RunCanceledByUserException ignore) { + } + catch (ExecutionException e1) { + Messages.showErrorDialog(project, e1.getMessage(), ExecutionBundle.message("restart.error.message.title")); + } + } + + public void update(final AnActionEvent event) { + final Presentation presentation = event.getPresentation(); + String name = myEnvironment.getRunProfile().getName(); + if (name.startsWith(ActionsBundle.message("action.RerunFailedTests.text"))) + name = myEnvironment.getRunnerAndConfigurationSettings().getName(); + presentation.setText(ExecutionBundle.message("rerun.configuration.action.name", name)); + final boolean isRunning = myProcessHandler != null && !myProcessHandler.isProcessTerminated(); + if (myProcessHandler != null && !isRunning) { + myProcessHandler = null; // already terminated + } + presentation.setIcon(isRunning ? STOP_AND_START_ICON : myIcon); + boolean isTerminating = myProcessHandler != null && myProcessHandler.isProcessTerminating(); + boolean isStarting = ExecutorRegistry.getInstance().isStarting(myEnvironment.getProject(), myExecutor.getId(), myRunner.getRunnerId()); + presentation.setEnabled(!isStarting && !isTerminating); + } + + public void registerShortcut(final JComponent component) { + registerCustomShortcutSet(new CustomShortcutSet(KeymapManager.getInstance().getActiveKeymap().getShortcuts(IdeActions.ACTION_RERUN)), + component); + } +} diff --git a/platform/lang-impl/src/com/intellij/facet/FacetManagerImpl.java b/platform/lang-impl/src/com/intellij/facet/FacetManagerImpl.java index 4cb3f4e56fb9..97d27474d395 100644 --- a/platform/lang-impl/src/com/intellij/facet/FacetManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/facet/FacetManagerImpl.java @@ -38,6 +38,8 @@ import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.serialization.facet.FacetManagerState; +import org.jetbrains.jps.model.serialization.facet.FacetState; import java.util.*; @@ -54,10 +56,6 @@ import java.util.*; ) public class FacetManagerImpl extends FacetManager implements ModuleComponent, PersistentStateComponent { private static final Logger LOG = Logger.getInstance("#com.intellij.facet.FacetManagerImpl"); - @NonNls public static final String FACET_ELEMENT = "facet"; - @NonNls public static final String TYPE_ATTRIBUTE = "type"; - @NonNls public static final String CONFIGURATION_ELEMENT = "configuration"; - @NonNls public static final String NAME_ATTRIBUTE = "name"; @NonNls public static final String COMPONENT_NAME = "FacetManager"; private final Module myModule; diff --git a/platform/lang-impl/src/com/intellij/facet/impl/FacetUtil.java b/platform/lang-impl/src/com/intellij/facet/impl/FacetUtil.java index ea11e8f0d286..8389f5175e55 100644 --- a/platform/lang-impl/src/com/intellij/facet/impl/FacetUtil.java +++ b/platform/lang-impl/src/com/intellij/facet/impl/FacetUtil.java @@ -30,6 +30,7 @@ import com.intellij.util.xmlb.XmlSerializer; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.serialization.facet.JpsFacetLoader; import java.lang.reflect.TypeVariable; import java.util.Arrays; @@ -94,7 +95,7 @@ public class FacetUtil { return XmlSerializer.serialize(state, new SkipDefaultValuesSerializationFilters()); } else { - final Element config = new Element(FacetManagerImpl.CONFIGURATION_ELEMENT); + final Element config = new Element(JpsFacetLoader.CONFIGURATION_ELEMENT); configuration.writeExternal(config); return config; } diff --git a/platform/lang-impl/src/com/intellij/facet/impl/invalid/InvalidFacetConfiguration.java b/platform/lang-impl/src/com/intellij/facet/impl/invalid/InvalidFacetConfiguration.java index bf043297d0e8..f0fb40c47b82 100644 --- a/platform/lang-impl/src/com/intellij/facet/impl/invalid/InvalidFacetConfiguration.java +++ b/platform/lang-impl/src/com/intellij/facet/impl/invalid/InvalidFacetConfiguration.java @@ -16,7 +16,7 @@ package com.intellij.facet.impl.invalid; import com.intellij.facet.FacetConfiguration; -import com.intellij.facet.impl.FacetState; +import org.jetbrains.jps.model.serialization.facet.FacetState; import com.intellij.facet.ui.FacetEditorContext; import com.intellij.facet.ui.FacetEditorTab; import com.intellij.facet.ui.FacetValidatorsManager; diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java index 83bfe13a9c51..94abeec74040 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/DefaultChooseByNameItemProvider.java @@ -1,314 +1,318 @@ -/* - * 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.util.gotoByName; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiElement; -import com.intellij.psi.codeStyle.MinusculeMatcher; -import com.intellij.psi.codeStyle.NameUtil; -import com.intellij.psi.util.proximity.PsiProximityComparator; -import com.intellij.util.Function; -import com.intellij.util.Processor; -import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.Nullable; - -import java.lang.ref.WeakReference; -import java.util.*; - -public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider { - private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.ChooseByNameIdea"); - private WeakReference myContext; - - public DefaultChooseByNameItemProvider(PsiElement context) { - myContext = new WeakReference(context); - } - - @Override - public void filterElements(ChooseByNameBase base, - String pattern, - boolean everywhere, - Computable cancelled, - Processor consumer) { - String namePattern = getNamePattern(base, pattern); - String qualifierPattern = getQualifierPattern(base, pattern); - String modifiedNamePattern = null; - - if (base.isSearchInAnyPlace() && !namePattern.trim().isEmpty()) { - modifiedNamePattern = "*" + namePattern + "*"; - } - - boolean empty = namePattern.isEmpty() || namePattern.equals("@"); // TODO[yole]: remove implicit dependency - if (empty && !base.canShowListForEmptyPattern()) return; - - List namesList = new ArrayList(); - String[] names = base.getNames(everywhere); - getNamesByPattern(base, names, cancelled, namesList, namePattern, - modifiedNamePattern != null ? NameUtil.MatchingCaseSensitivity.ALL : NameUtil.MatchingCaseSensitivity.NONE); - if (cancelled.compute()) { - throw new ProcessCanceledException(); - } - sortNamesList(namePattern, namesList); - - if (modifiedNamePattern != null) { - final Set matched = new HashSet(namesList); - List additionalNamesList = new ArrayList(); - namePattern = modifiedNamePattern; - getNamesByPattern(base, names, cancelled, additionalNamesList, namePattern, NameUtil.MatchingCaseSensitivity.NONE); - additionalNamesList = ContainerUtil.filter(additionalNamesList, new Condition() { - @Override - public boolean value(String name) { - return !matched.contains(name); - } - }); - sortNamesList(namePattern, additionalNamesList); - namesList.add(ChooseByNameBase.NON_PREFIX_SEPARATOR); - namesList.addAll(additionalNamesList); - } - - if (cancelled.compute()) { - throw new ProcessCanceledException(); - } - - List sameNameElements = new SmartList(); - boolean previousElemSeparator = false; - boolean wasElement = false; - - for (String name : namesList) { - if (cancelled.compute()) { - throw new ProcessCanceledException(); - } - if (name == ChooseByNameBase.NON_PREFIX_SEPARATOR) { - previousElemSeparator = wasElement; - continue; - } - final Object[] elements = base.getModel().getElementsByName(name, everywhere, namePattern); - if (elements.length > 1) { - sameNameElements.clear(); - for (final Object element : elements) { - if (matchesQualifier(element, qualifierPattern, base)) { - sameNameElements.add(element); - } - } - sortByProximity(base, sameNameElements); - for (Object element : sameNameElements) { - if (previousElemSeparator && !consumer.process(ChooseByNameBase.NON_PREFIX_SEPARATOR)) return; - if (!consumer.process(element)) return; - previousElemSeparator = false; - wasElement = true; - } - } - else if (elements.length == 1 && matchesQualifier(elements[0], qualifierPattern, base)) { - if (previousElemSeparator && !consumer.process(ChooseByNameBase.NON_PREFIX_SEPARATOR)) return; - if (!consumer.process(elements[0])) return; - previousElemSeparator = false; - wasElement = true; - } - } - } - - protected void sortNamesList(String namePattern, List namesList) { - // Here we sort using namePattern to have similar logic with empty qualified patten case - Collections.sort(namesList, new MatchesComparator(namePattern)); - } - - private void sortByProximity(ChooseByNameBase base, final List sameNameElements) { - final ChooseByNameModel model = base.getModel(); - if (model instanceof Comparator) { - //noinspection unchecked - Collections.sort(sameNameElements, (Comparator)model); - } else { - Collections.sort(sameNameElements, new PathProximityComparator(model, myContext.get())); - } - } - - private static String getQualifierPattern(ChooseByNameBase base, String pattern) { - final String[] separators = base.getModel().getSeparators(); - int lastSeparatorOccurrence = 0; - for (String separator : separators) { - lastSeparatorOccurrence = Math.max(lastSeparatorOccurrence, pattern.lastIndexOf(separator)); - } - return pattern.substring(0, lastSeparatorOccurrence); - } - - public static String getNamePattern(ChooseByNameBase base, String pattern) { - pattern = base.transformPattern(pattern); - - ChooseByNameModel model = base.getModel(); - final String[] separators = model.getSeparators(); - int lastSeparatorOccurrence = 0; - for (String separator : separators) { - final int idx = pattern.lastIndexOf(separator); - lastSeparatorOccurrence = Math.max(lastSeparatorOccurrence, idx == -1 ? idx : idx + separator.length()); - } - - return pattern.substring(lastSeparatorOccurrence); - } - - private static List split(String s, ChooseByNameBase base) { - List answer = new ArrayList(); - for (String token : StringUtil.tokenize(s, StringUtil.join(base.getModel().getSeparators(), ""))) { - if (!token.isEmpty()) { - answer.add(token); - } - } - - return answer.isEmpty() ? Collections.singletonList(s) : answer; - } - - private static boolean matchesQualifier(final Object element, - final String qualifierPattern, - final ChooseByNameBase base) { - final String name = base.getModel().getFullName(element); - if (name == null) return false; - - final List suspects = split(name, base); - final List> patternsAndMatchers = - ContainerUtil.map2List(split(qualifierPattern, base), new Function>() { - @Override - public Pair fun(String s) { - return Pair.create(getNamePattern(base, s), buildPatternMatcher(getNamePattern(base, s), NameUtil.MatchingCaseSensitivity.NONE)); - } - }); - - int matchPosition = 0; - - try { - patterns: - for (Pair patternAndMatcher : patternsAndMatchers) { - final String pattern = patternAndMatcher.first; - final MinusculeMatcher matcher = patternAndMatcher.second; - if (!pattern.isEmpty()) { - for (int j = matchPosition; j < suspects.size() - 1; j++) { - String suspect = suspects.get(j); - if (matches(base, pattern, matcher, suspect)) { - matchPosition = j + 1; - continue patterns; - } - } - - return false; - } - } - } - catch (Exception e) { - // Do nothing. No matches appears valid result for "bad" pattern - return false; - } - - return true; - } - - @Override - public List filterNames(ChooseByNameBase base, String[] names, String pattern) { - ArrayList res = new ArrayList(); - getNamesByPattern(base, names, null, res, pattern, NameUtil.MatchingCaseSensitivity.NONE); - return res; - } - - private static void getNamesByPattern(ChooseByNameBase base, - String[] names, - @Nullable Computable cancelled, - final List list, - String pattern, - NameUtil.MatchingCaseSensitivity caseSensitivity) - throws ProcessCanceledException { - if (!base.canShowListForEmptyPattern()) { - LOG.assertTrue(!pattern.isEmpty(), base); - } - - if (pattern.startsWith("@")) { - pattern = pattern.substring(1); - } - - final MinusculeMatcher matcher = buildPatternMatcher(pattern, caseSensitivity); - - try { - for (String name : names) { - if (cancelled != null && cancelled.compute()) { - break; - } - if (matches(base, pattern, matcher, name)) { - list.add(name); - } - } - } - catch (Exception e) { - // Do nothing. No matches appears valid result for "bad" pattern - } - } - - private static boolean matches(ChooseByNameBase base, String pattern, MinusculeMatcher matcher, String name) { - boolean matches = false; - if (name != null) { - if (base.getModel() instanceof CustomMatcherModel) { - if (((CustomMatcherModel)base.getModel()).matches(name, pattern)) { - matches = true; - } - } - else if (pattern.isEmpty() || matcher.matches(name)) { - matches = true; - } - } - return matches; - } - - private static MinusculeMatcher buildPatternMatcher(String pattern, NameUtil.MatchingCaseSensitivity caseSensitivity) { - return NameUtil.buildMatcher(pattern, caseSensitivity); - } - - private static class MatchesComparator implements Comparator { - private final String myOriginalPattern; - - private MatchesComparator(final String originalPattern) { - myOriginalPattern = originalPattern.trim(); - } - - @Override - public int compare(final String a, final String b) { - boolean aStarts = a.startsWith(myOriginalPattern); - boolean bStarts = b.startsWith(myOriginalPattern); - if (aStarts && bStarts) return a.compareToIgnoreCase(b); - if (aStarts && !bStarts) return -1; - if (bStarts && !aStarts) return 1; - return a.compareToIgnoreCase(b); - } - } - - private static class PathProximityComparator implements Comparator { - private final ChooseByNameModel myModel; - private final PsiProximityComparator myProximityComparator; - - private PathProximityComparator(final ChooseByNameModel model, @Nullable final PsiElement context) { - myModel = model; - myProximityComparator = new PsiProximityComparator(context); - } - - @Override - public int compare(final Object o1, final Object o2) { - int rc = myProximityComparator.compare(o1, o2); - if (rc != 0) return rc; - - return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2)); - } - } -} +/* + * 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.util.gotoByName; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.codeStyle.MinusculeMatcher; +import com.intellij.psi.codeStyle.NameUtil; +import com.intellij.psi.util.proximity.PsiProximityComparator; +import com.intellij.util.Function; +import com.intellij.util.Processor; +import com.intellij.util.SmartList; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.WeakReference; +import java.util.*; + +public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider { + private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.ChooseByNameIdea"); + private WeakReference myContext; + + public DefaultChooseByNameItemProvider(PsiElement context) { + myContext = new WeakReference(context); + } + + @Override + public void filterElements(ChooseByNameBase base, + String pattern, + boolean everywhere, + Computable cancelled, + Processor consumer) { + String namePattern = getNamePattern(base, pattern); + String qualifierPattern = getQualifierPattern(base, pattern); + String modifiedNamePattern = null; + + if (base.isSearchInAnyPlace() && !namePattern.trim().isEmpty()) { + modifiedNamePattern = "*" + namePattern + (namePattern.endsWith(" ") ? "" : "*"); + } + + boolean empty = namePattern.isEmpty() || namePattern.equals("@"); // TODO[yole]: remove implicit dependency + if (empty && !base.canShowListForEmptyPattern()) return; + + List namesList = new ArrayList(); + String[] names = base.getNames(everywhere); + getNamesByPattern(base, names, cancelled, namesList, namePattern, + modifiedNamePattern != null ? NameUtil.MatchingCaseSensitivity.ALL : NameUtil.MatchingCaseSensitivity.NONE); + + if (modifiedNamePattern != null && namesList.isEmpty()) { + getNamesByPattern(base, names, cancelled, namesList, namePattern, NameUtil.MatchingCaseSensitivity.NONE); + } + if (cancelled.compute()) { + throw new ProcessCanceledException(); + } + sortNamesList(namePattern, namesList); + + if (modifiedNamePattern != null) { + final Set matched = new HashSet(namesList); + List additionalNamesList = new ArrayList(); + namePattern = modifiedNamePattern; + getNamesByPattern(base, names, cancelled, additionalNamesList, namePattern, NameUtil.MatchingCaseSensitivity.NONE); + additionalNamesList = ContainerUtil.filter(additionalNamesList, new Condition() { + @Override + public boolean value(String name) { + return !matched.contains(name); + } + }); + sortNamesList(namePattern, additionalNamesList); + namesList.add(ChooseByNameBase.NON_PREFIX_SEPARATOR); + namesList.addAll(additionalNamesList); + } + + if (cancelled.compute()) { + throw new ProcessCanceledException(); + } + + List sameNameElements = new SmartList(); + boolean previousElemSeparator = false; + boolean wasElement = false; + + for (String name : namesList) { + if (cancelled.compute()) { + throw new ProcessCanceledException(); + } + if (name == ChooseByNameBase.NON_PREFIX_SEPARATOR) { + previousElemSeparator = wasElement; + continue; + } + final Object[] elements = base.getModel().getElementsByName(name, everywhere, namePattern); + if (elements.length > 1) { + sameNameElements.clear(); + for (final Object element : elements) { + if (matchesQualifier(element, qualifierPattern, base)) { + sameNameElements.add(element); + } + } + sortByProximity(base, sameNameElements); + for (Object element : sameNameElements) { + if (previousElemSeparator && !consumer.process(ChooseByNameBase.NON_PREFIX_SEPARATOR)) return; + if (!consumer.process(element)) return; + previousElemSeparator = false; + wasElement = true; + } + } + else if (elements.length == 1 && matchesQualifier(elements[0], qualifierPattern, base)) { + if (previousElemSeparator && !consumer.process(ChooseByNameBase.NON_PREFIX_SEPARATOR)) return; + if (!consumer.process(elements[0])) return; + previousElemSeparator = false; + wasElement = true; + } + } + } + + protected void sortNamesList(String namePattern, List namesList) { + // Here we sort using namePattern to have similar logic with empty qualified patten case + Collections.sort(namesList, new MatchesComparator(namePattern)); + } + + private void sortByProximity(ChooseByNameBase base, final List sameNameElements) { + final ChooseByNameModel model = base.getModel(); + if (model instanceof Comparator) { + //noinspection unchecked + Collections.sort(sameNameElements, (Comparator)model); + } else { + Collections.sort(sameNameElements, new PathProximityComparator(model, myContext.get())); + } + } + + private static String getQualifierPattern(ChooseByNameBase base, String pattern) { + final String[] separators = base.getModel().getSeparators(); + int lastSeparatorOccurrence = 0; + for (String separator : separators) { + lastSeparatorOccurrence = Math.max(lastSeparatorOccurrence, pattern.lastIndexOf(separator)); + } + return pattern.substring(0, lastSeparatorOccurrence); + } + + public static String getNamePattern(ChooseByNameBase base, String pattern) { + pattern = base.transformPattern(pattern); + + ChooseByNameModel model = base.getModel(); + final String[] separators = model.getSeparators(); + int lastSeparatorOccurrence = 0; + for (String separator : separators) { + final int idx = pattern.lastIndexOf(separator); + lastSeparatorOccurrence = Math.max(lastSeparatorOccurrence, idx == -1 ? idx : idx + separator.length()); + } + + return pattern.substring(lastSeparatorOccurrence); + } + + private static List split(String s, ChooseByNameBase base) { + List answer = new ArrayList(); + for (String token : StringUtil.tokenize(s, StringUtil.join(base.getModel().getSeparators(), ""))) { + if (!token.isEmpty()) { + answer.add(token); + } + } + + return answer.isEmpty() ? Collections.singletonList(s) : answer; + } + + private static boolean matchesQualifier(final Object element, + final String qualifierPattern, + final ChooseByNameBase base) { + final String name = base.getModel().getFullName(element); + if (name == null) return false; + + final List suspects = split(name, base); + final List> patternsAndMatchers = + ContainerUtil.map2List(split(qualifierPattern, base), new Function>() { + @Override + public Pair fun(String s) { + return Pair.create(getNamePattern(base, s), buildPatternMatcher(getNamePattern(base, s), NameUtil.MatchingCaseSensitivity.NONE)); + } + }); + + int matchPosition = 0; + + try { + patterns: + for (Pair patternAndMatcher : patternsAndMatchers) { + final String pattern = patternAndMatcher.first; + final MinusculeMatcher matcher = patternAndMatcher.second; + if (!pattern.isEmpty()) { + for (int j = matchPosition; j < suspects.size() - 1; j++) { + String suspect = suspects.get(j); + if (matches(base, pattern, matcher, suspect)) { + matchPosition = j + 1; + continue patterns; + } + } + + return false; + } + } + } + catch (Exception e) { + // Do nothing. No matches appears valid result for "bad" pattern + return false; + } + + return true; + } + + @Override + public List filterNames(ChooseByNameBase base, String[] names, String pattern) { + ArrayList res = new ArrayList(); + getNamesByPattern(base, names, null, res, pattern, NameUtil.MatchingCaseSensitivity.NONE); + return res; + } + + private static void getNamesByPattern(ChooseByNameBase base, + String[] names, + @Nullable Computable cancelled, + final List list, + String pattern, + NameUtil.MatchingCaseSensitivity caseSensitivity) + throws ProcessCanceledException { + if (!base.canShowListForEmptyPattern()) { + LOG.assertTrue(!pattern.isEmpty(), base); + } + + if (pattern.startsWith("@")) { + pattern = pattern.substring(1); + } + + final MinusculeMatcher matcher = buildPatternMatcher(pattern, caseSensitivity); + + try { + for (String name : names) { + if (cancelled != null && cancelled.compute()) { + break; + } + if (matches(base, pattern, matcher, name)) { + list.add(name); + } + } + } + catch (Exception e) { + // Do nothing. No matches appears valid result for "bad" pattern + } + } + + private static boolean matches(ChooseByNameBase base, String pattern, MinusculeMatcher matcher, String name) { + boolean matches = false; + if (name != null) { + if (base.getModel() instanceof CustomMatcherModel) { + if (((CustomMatcherModel)base.getModel()).matches(name, pattern)) { + matches = true; + } + } + else if (pattern.isEmpty() || matcher.matches(name)) { + matches = true; + } + } + return matches; + } + + private static MinusculeMatcher buildPatternMatcher(String pattern, NameUtil.MatchingCaseSensitivity caseSensitivity) { + return NameUtil.buildMatcher(pattern, caseSensitivity); + } + + private static class MatchesComparator implements Comparator { + private final String myOriginalPattern; + + private MatchesComparator(final String originalPattern) { + myOriginalPattern = originalPattern.trim(); + } + + @Override + public int compare(final String a, final String b) { + boolean aStarts = a.startsWith(myOriginalPattern); + boolean bStarts = b.startsWith(myOriginalPattern); + if (aStarts && bStarts) return a.compareToIgnoreCase(b); + if (aStarts && !bStarts) return -1; + if (bStarts && !aStarts) return 1; + return a.compareToIgnoreCase(b); + } + } + + private static class PathProximityComparator implements Comparator { + private final ChooseByNameModel myModel; + private final PsiProximityComparator myProximityComparator; + + private PathProximityComparator(final ChooseByNameModel model, @Nullable final PsiElement context) { + myModel = model; + myProximityComparator = new PsiProximityComparator(context); + } + + @Override + public int compare(final Object o1, final Object o2) { + int rc = myProximityComparator.compare(o1, o2); + if (rc != 0) return rc; + + return Comparing.compare(myModel.getFullName(o1), myModel.getFullName(o2)); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.form b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.form index 365527c4f34a..1e6fb6091a61 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.form +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.form @@ -51,7 +51,7 @@ - + @@ -59,7 +59,7 @@ - + diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index d8f47c2a1947..9e3734e9de52 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -203,6 +203,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec return ((PsiManagerEx)myPsiManager).getFileManager().findFile(virtualFile); } + @Nullable @Override public Document getDocument(@NotNull PsiFile file) { if (file instanceof PsiBinaryFile) return null; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java index c0d69b38c25c..23cccbe8138b 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -229,7 +229,12 @@ public class CodeStyleManagerImpl extends CodeStyleManager { } } + if (editor == null) { + return; + } + if (visualColumnToRestore < 0) { + editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); return; } CaretModel caretModel = editor.getCaretModel(); diff --git a/platform/lang-impl/src/com/intellij/refactoring/lang/ExtractIncludeDialog.java b/platform/lang-impl/src/com/intellij/refactoring/lang/ExtractIncludeDialog.java index c3a0556e5848..7f1524c7b073 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/lang/ExtractIncludeDialog.java +++ b/platform/lang-impl/src/com/intellij/refactoring/lang/ExtractIncludeDialog.java @@ -20,6 +20,8 @@ import com.intellij.ide.util.DirectoryUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.ex.FileTypeChooser; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; @@ -140,6 +142,11 @@ public class ExtractIncludeDialog extends DialogWrapper { return; } + final FileType type = FileTypeChooser.getKnownFileTypeOrAssociate(targetFileName); + if (type == null) { + return; + } + CommandProcessor.getInstance().executeCommand(project, new Runnable() { public void run() { final Runnable action = new Runnable() { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IOUtils.java b/platform/lang-impl/src/com/intellij/util/indexing/IOUtils.java index 783c4a8cb08f..85064910d31d 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IOUtils.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IOUtils.java @@ -31,9 +31,14 @@ public class IOUtils { private static volatile boolean canUseSnappy; static { try { - Field impl = Snappy.class.getDeclaredField("impl"); - impl.setAccessible(true); - canUseSnappy = impl.get(null) != null && System.getProperty("idea.no.snappy") == null; + if (System.getProperty("idea.no.snappy") == null) { // if enabled + Field impl = Snappy.class.getDeclaredField("impl"); + impl.setAccessible(true); + canUseSnappy = impl.get(null) != null; + } + else { + canUseSnappy = false; + } } catch (Throwable e) {} } diff --git a/platform/lang-impl/testSources/com/intellij/codeInsight/navigation/DocPreviewUtilTest.groovy b/platform/lang-impl/testSources/com/intellij/codeInsight/navigation/DocPreviewUtilTest.groovy index 75c5cb036774..e9f4e1ebf11d 100644 --- a/platform/lang-impl/testSources/com/intellij/codeInsight/navigation/DocPreviewUtilTest.groovy +++ b/platform/lang-impl/testSources/com/intellij/codeInsight/navigation/DocPreviewUtilTest.groovy @@ -19,6 +19,7 @@ package com.intellij.codeInsight.navigation; import org.junit.Test import static org.junit.Assert.assertEquals +import static org.junit.Assert.assertTrue /** * @author Denis Zhdanov @@ -103,10 +104,28 @@ implements java.io.Serializab ''' def expected = '''\ -[< 1.7 >] java.lang
public final class java.lang.String
extends
Object
implements java.io.Serializable, java.lang.Comparable<java.lang.String
>, java.lang.CharSequence

The String class represents character strings. All string literals
in Java programs, such as "abc", are implemented as instances
<more>\ +java.lang
public final class String extends Object
implements Serializable, Comparable<String>, CharSequence\ ''' - def actual = DocPreviewUtil.buildPreview(header, "java.lang.String", fullText, 2, 60) + def actual = DocPreviewUtil.buildPreview(header, "java.lang.String", fullText) + assertTrue(actual.endsWith(expected)) // Can't check for equals() because jdk name might differ on different machines. + } + + @Test + void fieldTypeSubstitution() { + def header = '''\ +Bar + java.util.List<java.lang.String> foo (java.lang.String param)\ +''' + + def fullText = '''\ + Bar
java.util.List<T> foo(T param)
\ +''' + + def expected = '''\ +Bar
List<String> foo (String param)\ +''' + def actual = DocPreviewUtil.buildPreview(header, "java.lang.String", fullText) assertEquals(expected, actual) } } diff --git a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java index d048ba4c5f11..fa155286244f 100644 --- a/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java +++ b/platform/platform-impl/src/com/intellij/codeInsight/hint/HintUtil.java @@ -33,6 +33,9 @@ import javax.swing.border.EmptyBorder; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; public class HintUtil { public static final Color INFORMATION_COLOR = new Color(253, 254, 226); @@ -49,10 +52,13 @@ public class HintUtil { } public static JComponent createInformationLabel(@NotNull String text) { - return createInformationLabel(text, null); + return createInformationLabel(text, null, null); } - - public static JComponent createInformationLabel(@NotNull String text, @Nullable HyperlinkListener listener) { + + public static JComponent createInformationLabel(@NotNull String text, + @Nullable HyperlinkListener hyperlinkListener, + @Nullable MouseListener mouseListener) + { HintHint hintHint = new HintHint().setTextBg(INFORMATION_COLOR).setTextFg(Color.black).setFont(getBoldFont()).setAwtTooltip(true); HintLabel label = new HintLabel(); @@ -67,8 +73,11 @@ public class HintUtil { label.setOpaque(true); } - if (listener != null) { - label.myPane.addHyperlinkListener(listener); + if (hyperlinkListener != null) { + label.myPane.addHyperlinkListener(hyperlinkListener); + } + if (mouseListener != null) { + label.myPane.addMouseListener(mouseListener); } return label; diff --git a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java index 9a80da99d7f0..f033ac7a01b2 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java +++ b/platform/platform-impl/src/com/intellij/ide/IdeTooltipManager.java @@ -57,6 +57,8 @@ import java.awt.event.MouseEvent; public class IdeTooltipManager implements ApplicationComponent, AWTEventListener { + public static final String IDE_TOOLTIP_PLACE = "IdeTooltip"; + public static final Color GRAPHITE_COLOR = new Color(100, 100, 100, 230); private RegistryValue myIsEnabled; @@ -64,8 +66,8 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener private Component myQueuedComponent; private BalloonImpl myCurrentTipUi; - private MouseEvent myCurrentEvent; - private boolean myCurrentTipIsCentered; + private MouseEvent myCurrentEvent; + private boolean myCurrentTipIsCentered; private Runnable myHideRunnable; @@ -75,12 +77,12 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener private final Alarm myAlarm = new Alarm(); - private int myX; - private int myY; + private int myX; + private int myY; private RegistryValue myMode; private IdeTooltip myCurrentTooltip; - private Runnable myShowRequest; + private Runnable myShowRequest; private IdeTooltip myQueuedTooltip; @@ -341,7 +343,11 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener } }, tooltip.getDismissDelay()); } - + + @Nullable + public IdeTooltip getCurrentTooltip() { + return myCurrentTooltip; + } public Color getTextForeground(boolean awtTooltip) { return useGraphite(awtTooltip) ? Color.white : UIUtil.getToolTipForeground(); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java index 476863b6adaf..0be8fe3d7f4d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java @@ -19,7 +19,6 @@ import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.ExportableApplicationComponent; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces; import com.intellij.openapi.options.OptionsBundle; import com.intellij.openapi.util.DefaultJDOMExternalizer; @@ -51,8 +50,6 @@ public class EditorSettingsExternalizable implements NamedJDOMExternalizable, Ex public boolean IS_CARET_INSIDE_TABS; @NonNls public String STRIP_TRAILING_SPACES = "Changed"; public boolean IS_ENSURE_NEWLINE_AT_EOF = false; - public boolean SHOW_QUICK_DOC_ON_MOUSE_OVER_ELEMENT = false; - public long QUICK_DOC_ON_MOUSE_OVER_DELAY_MS = 500; public boolean IS_CARET_BLINKING = true; public int CARET_BLINKING_PERIOD = 500; public boolean IS_RIGHT_MARGIN_SHOWN = true; @@ -368,28 +365,6 @@ public class EditorSettingsExternalizable implements NamedJDOMExternalizable, Ex myOptions.STRIP_TRAILING_SPACES = stripTrailingSpaces; } - public boolean isShowQuickDocOnMouseOverElement() { - return myOptions.SHOW_QUICK_DOC_ON_MOUSE_OVER_ELEMENT; - } - - public void setShowQuickDocOnMouseOverElement(boolean show) { - myOptions.SHOW_QUICK_DOC_ON_MOUSE_OVER_ELEMENT = show; - } - - public long getQuickDocOnMouseOverElementDelayMillis() { - return myOptions.QUICK_DOC_ON_MOUSE_OVER_DELAY_MS; - } - - public void setQuickDocOnMouseOverElementDelayMillis(long delay) throws IllegalArgumentException { - if (delay <= 0) { - throw new IllegalArgumentException(String.format( - "Non-positive delay for the 'show quick doc on mouse over element' value detected! Expected positive value but got %d", - delay - )); - } - myOptions.QUICK_DOC_ON_MOUSE_OVER_DELAY_MS = delay; - } - public boolean isRefrainFromScrolling() { return myOptions.REFRAIN_FROM_SCROLLING; } diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java index 76797c6f7201..6a7de8845652 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java @@ -209,13 +209,11 @@ public class DumbServiceImpl extends DumbService { } runnable = myRunWhenSmartQueue.pullFirst(); } - if (!myProject.isDisposed()) { - try { - runnable.run(); - } - catch (Throwable e) { - LOG.error(e); - } + try { + runnable.run(); + } + catch (Throwable e) { + LOG.error(e); } } } @@ -364,7 +362,7 @@ public class DumbServiceImpl extends DumbService { public void run() { IndexUpdateRunnable nextUpdateRunnable = null; try { - nextUpdateRunnable = myUpdatesQueue.pullFirst(); + nextUpdateRunnable = myUpdatesQueue.isEmpty()? null : myUpdatesQueue.pullFirst(); if (nextUpdateRunnable == null) { // really terminate the task myActionQueue.offer(NULL_ACTION); diff --git a/platform/platform-impl/src/com/intellij/ui/TreeExpandableItemsHandler.java b/platform/platform-impl/src/com/intellij/ui/TreeExpandableItemsHandler.java index e659a2194bdf..6a33df2d5b03 100644 --- a/platform/platform-impl/src/com/intellij/ui/TreeExpandableItemsHandler.java +++ b/platform/platform-impl/src/com/intellij/ui/TreeExpandableItemsHandler.java @@ -154,7 +154,7 @@ public class TreeExpandableItemsHandler extends AbstractExpandableItemsHandler - - - diff --git a/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml b/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml index 046a54fe4195..fc4d0c88bbe1 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensionPoints.xml @@ -42,6 +42,7 @@ interface="com.intellij.openapi.vcs.actions.VcsQuickListContentProvider"/> + diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java index bbb6d2f5d6e1..122287bf76bd 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java @@ -131,12 +131,15 @@ public class FileWatcherTest extends PlatformLangTestCase { refresh(file); final LocalFileSystem.WatchRequest request = watch(file); try { + myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, file.getAbsolutePath()); + myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, file.getAbsolutePath()); + myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); } @@ -158,12 +161,15 @@ public class FileWatcherTest extends PlatformLangTestCase { final String watchRoot = file.getAbsolutePath().toUpperCase(Locale.US); final LocalFileSystem.WatchRequest request = watch(new File(watchRoot)); try { + myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, file.getAbsolutePath()); + myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, file.getAbsolutePath()); + myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); } @@ -179,19 +185,24 @@ public class FileWatcherTest extends PlatformLangTestCase { final LocalFileSystem.WatchRequest request = watch(topDir); try { + myAccept = true; final File subDir = FileUtil.createTempDirectory(topDir, "sub.", null); assertEvent(VFileCreateEvent.class, subDir.getAbsolutePath()); refresh(subDir); + myAccept = true; final File file = FileUtil.createTempFile(subDir, "test.", ".txt", true, false); assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); + myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, file.getAbsolutePath()); + myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, file.getAbsolutePath()); + myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); } @@ -210,9 +221,11 @@ public class FileWatcherTest extends PlatformLangTestCase { final LocalFileSystem.WatchRequest request = watch(topDir, false); try { + myAccept = true; FileUtil.writeToFile(watchedFile, "new content"); assertEvent(VFileContentChangeEvent.class, watchedFile.getAbsolutePath()); + myAccept = true; FileUtil.writeToFile(unwatchedFile, "new content"); assertEvent(VFileEvent.class); } @@ -235,6 +248,7 @@ public class FileWatcherTest extends PlatformLangTestCase { final LocalFileSystem.WatchRequest topRequest = watch(topDir, false); final LocalFileSystem.WatchRequest subRequest = watch(sub2Dir); try { + myAccept = true; FileUtil.writeToFile(watchedFile1, "new content"); FileUtil.writeToFile(watchedFile2, "new content"); FileUtil.writeToFile(unwatchedFile, "new content"); @@ -254,10 +268,12 @@ public class FileWatcherTest extends PlatformLangTestCase { final LocalFileSystem.WatchRequest request = watch(subDir); try { + myAccept = true; assertTrue(subDir.toString(), subDir.mkdir()); assertEvent(VFileCreateEvent.class, subDir.getAbsolutePath()); refresh(subDir); + myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileCreateEvent.class, file.getAbsolutePath()); } @@ -280,6 +296,7 @@ public class FileWatcherTest extends PlatformLangTestCase { final LocalFileSystem.WatchRequest request1 = watch(subDir); final LocalFileSystem.WatchRequest request2 = watch(sideDir); try { + myAccept = true; FileUtil.writeToFile(file1, "new content"); FileUtil.writeToFile(file2, "new content"); FileUtil.writeToFile(file3, "new content"); @@ -287,6 +304,7 @@ public class FileWatcherTest extends PlatformLangTestCase { final LocalFileSystem.WatchRequest request3 = watch(topDir); try { + myAccept = true; FileUtil.writeToFile(file1, "newer content"); FileUtil.writeToFile(file2, "newer content"); FileUtil.writeToFile(file3, "newer content"); @@ -296,11 +314,13 @@ public class FileWatcherTest extends PlatformLangTestCase { unwatch(request3); } + myAccept = true; FileUtil.writeToFile(file1, "newest content"); FileUtil.writeToFile(file2, "newest content"); FileUtil.writeToFile(file3, "newest content"); assertEvent(VFileContentChangeEvent.class, file2.getAbsolutePath(), file3.getAbsolutePath()); + myAccept = true; FileUtil.delete(file1); FileUtil.delete(file2); FileUtil.delete(file3); @@ -369,6 +389,7 @@ public class FileWatcherTest extends PlatformLangTestCase { } */ + @SuppressWarnings("UnusedDeclaration") public void _testSubst() throws Exception { if (!SystemInfo.isWindows) { System.err.println("Ignored: Windows required"); @@ -407,11 +428,13 @@ public class FileWatcherTest extends PlatformLangTestCase { final LocalFileSystem.WatchRequest request = watch(substDir); try { + myAccept = true; FileUtil.writeToFile(file, "new content"); assertEvent(VFileContentChangeEvent.class, substFile.getAbsolutePath()); final LocalFileSystem.WatchRequest request2 = watch(targetDir); try { + myAccept = true; FileUtil.delete(file); assertEvent(VFileDeleteEvent.class, file.getAbsolutePath(), substFile.getAbsolutePath()); } @@ -419,6 +442,7 @@ public class FileWatcherTest extends PlatformLangTestCase { unwatch(request2); } + myAccept = true; FileUtil.writeToFile(file, "re-creation"); assertEvent(VFileCreateEvent.class, substFile.getAbsolutePath()); } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java index 0d610e8d4970..02cd796d711d 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java @@ -152,6 +152,11 @@ public class SMTestProxy extends AbstractTestProxy { return myState.wasTerminated(); } + @Override + public boolean isIgnored() { + return myState.getMagnitude() == TestStateInfo.Magnitude.SKIPPED_INDEX; + } + public boolean isPassed() { return myState.getMagnitude() == TestStateInfo.Magnitude.SKIPPED_INDEX || myState.getMagnitude() == TestStateInfo.Magnitude.COMPLETE_INDEX || diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java index 0571b0f8ee77..6314fa2752b8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java @@ -124,7 +124,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { long testHighlightingAllFiles(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, @TestDataFile @NonNls String... filePaths); - long testHighlightingAllFiles(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, @NonNls VirtualFile... files); + long testHighlightingAllFiles(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, @TestDataFile @NonNls VirtualFile... files); /** * Check highlighting of file already loaded by configure* methods @@ -145,7 +145,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * * @return highlighting duration in milliseconds */ - long testHighlighting(@NonNls String... filePaths); + long testHighlighting(@TestDataFile @NonNls String... filePaths); long testHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, VirtualFile file); HighlightTestInfo testFile(@NonNls @NotNull String... filePath); @@ -290,7 +290,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { * @return gutter renderer at the caret position. */ @Nullable - GutterIconRenderer findGutter(@NonNls String filePath); + GutterIconRenderer findGutter(@TestDataFile @NonNls String filePath); PsiManager getPsiManager(); diff --git a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java index 61a213cc6b95..f37184d3e31b 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java @@ -47,6 +47,8 @@ public abstract class AbstractTestProxy extends CompositePrintable { public abstract boolean isInterrupted(); + public abstract boolean isIgnored(); + public abstract boolean isPassed(); public abstract String getName(); diff --git a/platform/testRunner/src/com/intellij/execution/testframework/Filter.java b/platform/testRunner/src/com/intellij/execution/testframework/Filter.java index 25c580b8b493..7d43fcd2a7e1 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/Filter.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/Filter.java @@ -72,6 +72,12 @@ public abstract class Filter { } }; + public static final Filter IGNORED = new Filter() { + public boolean shouldAccept(final AbstractTestProxy test) { + return test.isIgnored(); + } + }; + public static final Filter NOT_PASSED = new Filter() { public boolean shouldAccept(final AbstractTestProxy test) { return !test.isPassed(); diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java b/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java index fa670d6c4308..96952bb3500d 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java @@ -44,6 +44,7 @@ public abstract class TestConsoleProperties extends StoringPropertyContainer imp public static final BooleanProperty SORT_ALPHABETICALLY = new BooleanProperty("sortTestsAlphabetically", false); public static final BooleanProperty SELECT_FIRST_DEFECT = new BooleanProperty("selectFirtsDefect", false); public static final BooleanProperty TRACK_RUNNING_TEST = new BooleanProperty("trackRunningTest", true); + public static final BooleanProperty HIDE_IGNORED_TEST = new BooleanProperty("hideIgnoredTests", false); public static final BooleanProperty HIDE_PASSED_TESTS = new BooleanProperty("hidePassedTests", true); public static final BooleanProperty SCROLL_TO_SOURCE = new BooleanProperty("scrollToSource", false); public static final BooleanProperty OPEN_FAILURE_LINE = new BooleanProperty("openFailureLine", false); diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ToolbarPanel.java b/platform/testRunner/src/com/intellij/execution/testframework/ToolbarPanel.java index 219a20b59bc9..06f530090813 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/ToolbarPanel.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/ToolbarPanel.java @@ -67,6 +67,7 @@ public class ToolbarPanel extends JPanel implements OccurenceNavigator, Disposab ExecutionBundle.message("junit.runing.info.track.test.action.description"), AllIcons.RunConfigurations.TrackTests, properties, TestConsoleProperties.TRACK_RUNNING_TEST)).setAsSecondary(true); + actionGroup.addAction(new ToggleBooleanProperty("Hide Ignored", null, null, properties, TestConsoleProperties.HIDE_IGNORED_TEST)).setAsSecondary(true); actionGroup.addAction(new ToggleBooleanProperty(ExecutionBundle.message("junit.runing.info.sort.alphabetically.action.name"), ExecutionBundle.message("junit.runing.info.sort.alphabetically.action.description"), diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/TestFrameworkActions.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/TestFrameworkActions.java index 45908640edc4..5d2f9d2cb70c 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/actions/TestFrameworkActions.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/TestFrameworkActions.java @@ -38,6 +38,15 @@ public class TestFrameworkActions { } }; addPropertyListener(TestConsoleProperties.HIDE_PASSED_TESTS, hidePropertyListener, model, true); + + final TestConsoleProperties ignoreProperties = model.getProperties(); + final TestFrameworkPropertyListener ignorePropertyListener = new TestFrameworkPropertyListener() { + public void onChanged(final Boolean value) { + final boolean shouldFilter = TestConsoleProperties.HIDE_IGNORED_TEST.value(ignoreProperties); + model.setFilter(shouldFilter ? Filter.IGNORED.not() : Filter.NO_FILTER); + } + }; + addPropertyListener(TestConsoleProperties.HIDE_IGNORED_TEST, ignorePropertyListener, model, true); } public static void addPropertyListener(final AbstractProperty property, diff --git a/platform/util/src/com/intellij/util/ArrayUtil.java b/platform/util/src/com/intellij/util/ArrayUtil.java index aca3963f21f3..aaa48d042c7f 100644 --- a/platform/util/src/com/intellij/util/ArrayUtil.java +++ b/platform/util/src/com/intellij/util/ArrayUtil.java @@ -145,7 +145,7 @@ public class ArrayUtil extends ArrayUtilRt { @NotNull public static int[] toIntArray(@NotNull List list) { - int[] ret = new int[list.size()]; + int[] ret = newIntArray(list.size()); int i = 0; for (Integer e : list) { ret[i++] = e.intValue(); @@ -370,7 +370,7 @@ public class ArrayUtil extends ArrayUtilRt { if (idx < 0 || idx >= length) { throw new IllegalArgumentException("invalid index: " + idx); } - int[] result = new int[src.length - 1]; + int[] result = newIntArray(src.length - 1); System.arraycopy(src, 0, result, 0, idx); System.arraycopy(src, idx + 1, result, idx, length - idx - 1); return result; @@ -381,7 +381,7 @@ public class ArrayUtil extends ArrayUtilRt { if (idx < 0 || idx >= length) { throw new IllegalArgumentException("invalid index: " + idx); } - short[] result = new short[src.length - 1]; + short[] result = src.length == 1 ? EMPTY_SHORT_ARRAY : new short[src.length - 1]; System.arraycopy(src, 0, result, 0, idx); System.arraycopy(src, idx + 1, result, idx, length - idx - 1); return result; diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 263134ff600f..081f67008d6a 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -631,6 +631,11 @@ public class UIUtil { return isUnderDarcula() ? Gray._52 : UNFOCUSED_SELECTION_COLOR; } + public static Color getTreeUnfocusedSelectionBackground() { + Color background = getTreeTextBackground(); + return ColorUtil.isDark(background) ? Gray._30 : UNFOCUSED_SELECTION_COLOR; + } + public static Color getTextFieldForeground() { return UIManager.getColor("TextField.foreground"); } diff --git a/platform/util/src/com/intellij/util/ui/tree/MacTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/MacTreeUI.java index 6e48b613f1bc..61d227e627cc 100644 --- a/platform/util/src/com/intellij/util/ui/tree/MacTreeUI.java +++ b/platform/util/src/com/intellij/util/ui/tree/MacTreeUI.java @@ -274,7 +274,7 @@ public class MacTreeUI extends BasicTreeUI { } } else { - Color bg = tree.hasFocus() ? UIUtil.getTreeSelectionBackground() : UIUtil.getListUnfocusedSelectionBackground(); + Color bg = tree.hasFocus() ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeUnfocusedSelectionBackground(); if (!selected) { bg = background; } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/annotate/AnnotationGutterActionProvider.java b/platform/vcs-api/src/com/intellij/openapi/vcs/annotate/AnnotationGutterActionProvider.java new file mode 100644 index 000000000000..d3bc6fcda482 --- /dev/null +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/annotate/AnnotationGutterActionProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright 2000-2012 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.openapi.vcs.annotate; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.extensions.ExtensionPointName; +import org.jetbrains.annotations.NotNull; + +/** + * Implement this to add additional custom actions to the popup invoked by right-clicking on the annotation gutter. + * + * @author Kirill Likhodedov + */ +public interface AnnotationGutterActionProvider { + + ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.vcsAnnotationGutterActionProvider"); + + /** + * Create an action that will be added to the annotation gutter popup. + * @param annotation annotation which is currently shown on the gutter. + * @return new action that can be invoked from the annotation gutter popup. + */ + @NotNull + AnAction createAction(FileAnnotation annotation); + +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java index 6f9ce4b23b09..a82236fd3d3a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java @@ -17,6 +17,7 @@ package com.intellij.openapi.vcs.actions; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Separator; import com.intellij.openapi.actionSystem.ToggleAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -207,12 +208,6 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware, Ann new AnnotationPresentation(highlighting, switcher, editorGutter, gutters, additionalActions.toArray(new AnAction[additionalActions.size()])); - for (AnAction action : additionalActions) { - if (action instanceof LineNumberListener) { - presentation.addLineNumberListener((LineNumberListener)action); - } - } - final Map bgColorMap = Registry.is("vcs.show.colored.annotations") ? computeBgColors(fileAnnotation) : null; final Map historyIds = Registry.is("vcs.show.history.numbers") ? computeLineNumbers(fileAnnotation) : null; @@ -248,9 +243,17 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware, Ann gutters.add(new HighlightedAdditionalColumn(fileAnnotation, editor, null, presentation, highlighting, bgColorMap)); final AnnotateActionGroup actionGroup = new AnnotateActionGroup(gutters, editorGutter); presentation.addAction(actionGroup, 1); - presentation.addAction(new ShowHideAdditionalInfoAction(gutters, editorGutter, actionGroup)); gutters.add(new ExtraFieldGutter(fileAnnotation, editor, presentation, bgColorMap, actionGroup)); + presentation.addAction(new ShowHideAdditionalInfoAction(gutters, editorGutter, actionGroup)); + addActionsFromExtensions(presentation, fileAnnotation); + + for (AnAction action : presentation.getActions()) { + if (action instanceof LineNumberListener) { + presentation.addLineNumberListener((LineNumberListener)action); + } + } + for (AnnotationFieldGutter gutter : gutters) { final AnnotationGutterLineConvertorProxy proxy = new AnnotationGutterLineConvertorProxy(getUpToDateLineNumber, gutter); if (gutter.isGutterAction()) { @@ -263,6 +266,16 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware, Ann } } + private static void addActionsFromExtensions(@NotNull AnnotationPresentation presentation, @NotNull FileAnnotation fileAnnotation) { + AnnotationGutterActionProvider[] extensions = AnnotationGutterActionProvider.EP_NAME.getExtensions(); + if (extensions.length > 0) { + presentation.addAction(new Separator()); + } + for (AnnotationGutterActionProvider provider : extensions) { + presentation.addAction(provider.createAction(fileAnnotation)); + } + } + @Nullable private static Map computeLineNumbers(FileAnnotation fileAnnotation) { final SortedList revisions = new SortedList(new Comparator() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationPresentation.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationPresentation.java index bf36fb72b917..f2c887a5078d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationPresentation.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationPresentation.java @@ -85,6 +85,11 @@ class AnnotationPresentation implements TextAnnotationPresentation { return myActions; } + @NotNull + public List getActions() { + return myActions; + } + public void addSourceSwitchListener(final Consumer listener) { mySwitchAction.addSourceSwitchListener(listener); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeListNode.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeListNode.java index 2179109ba8f5..e6d1de6e7678 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeListNode.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/ChangesBrowserChangeListNode.java @@ -45,7 +45,7 @@ public class ChangesBrowserChangeListNode extends ChangesBrowserNode if (userObject instanceof LocalChangeList) { final LocalChangeList list = ((LocalChangeList)userObject); renderer.appendTextWithIssueLinks(list.getName(), - list.isDefault() ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES : SimpleTextAttributes.SIMPLE_CELL_ATTRIBUTES); + list.isDefault() ? SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES); appendCount(renderer); for(ChangeListDecorator decorator: myDecorators) { decorator.decorateChangeList(list, renderer, selected, expanded, hasFocus); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java index 4e41eebacfe0..051257a1146d 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/VcsRootIterator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 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. @@ -22,10 +22,13 @@ import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vcs.*; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileVisitor; import com.intellij.util.PairProcessor; import com.intellij.util.Processor; import com.intellij.util.StringLenComparator; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -69,42 +72,41 @@ public class VcsRootIterator { }); } - public static boolean iterateVfUnderVcsRoot(Project project, VirtualFile file, Processor processor) { - final MyRootIterator rootIterator = new MyRootIterator(project, file, null, processor, null); - return rootIterator.iterate(); - } - private static class MyRootFilter { private final VirtualFile myRoot; private final String myVcsName; // virtual file URLs - private final List myExcludedByOtherVcss; + private final List myExcludedByOthers; private MyRootFilter(final VirtualFile root, final String vcsName) { myRoot = root; myVcsName = vcsName; - myExcludedByOtherVcss = new LinkedList(); + myExcludedByOthers = new LinkedList(); } private void init(final VcsRoot[] allRoots) { final String ourPath = myRoot.getUrl(); for (VcsRoot root : allRoots) { - if (Comparing.equal(root.getVcs().getName(), myVcsName)) continue; - final String url = root.getPath().getUrl(); - if (url.startsWith(ourPath)) { - myExcludedByOtherVcss.add(url); + final AbstractVcs vcs = root.getVcs(); + if (vcs == null || Comparing.equal(vcs.getName(), myVcsName)) continue; + final VirtualFile path = root.getPath(); + if (path != null) { + final String url = path.getUrl(); + if (url.startsWith(ourPath)) { + myExcludedByOthers.add(url); + } } } - Collections.sort(myExcludedByOtherVcss, StringLenComparator.getDescendingInstance()); + Collections.sort(myExcludedByOthers, StringLenComparator.getDescendingInstance()); } public boolean accept(final VirtualFile vf) { final String url = vf.getUrl(); - for (String excludedByOtherVcs : myExcludedByOtherVcss) { + for (String excludedByOtherVcs : myExcludedByOthers) { // use the fact that they are sorted if (url.length() > excludedByOtherVcs.length()) return true; if (url.startsWith(excludedByOtherVcs)) return false; @@ -113,11 +115,22 @@ public class VcsRootIterator { } } - public static boolean iterateVcsRoot(final Project project, final VirtualFile root, final Processor processor) { + public static boolean iterateVfUnderVcsRoot(final Project project, + final VirtualFile root, + final Processor processor) { + final MyRootIterator rootIterator = new MyRootIterator(project, root, null, processor, null); + return rootIterator.iterate(); + } + + public static boolean iterateVcsRoot(final Project project, + final VirtualFile root, + final Processor processor) { return iterateVcsRoot(project, root, processor, null); } - public static boolean iterateVcsRoot(final Project project, final VirtualFile root, final Processor processor, + public static boolean iterateVcsRoot(final Project project, + final VirtualFile root, + final Processor processor, @Nullable PairProcessor directoryFilter) { final MyRootIterator rootIterator = new MyRootIterator(project, root, processor, null, directoryFilter); return rootIterator.iterate(); @@ -125,54 +138,64 @@ public class VcsRootIterator { private static class MyRootIterator { private final Project myProject; - private final Processor myProcessor; - private final Processor myVfProcessor; + private final Processor myPathProcessor; + private final Processor myFileProcessor; @Nullable private final PairProcessor myDirectoryFilter; - private final LinkedList myQueue; + private final VirtualFile myRoot; private final MyRootFilter myRootPresentFilter; private final FileIndexFacade myExcludedFileIndex; - private MyRootIterator(final Project project, final VirtualFile root, final Processor processor, final Processor vfProcessor, + private MyRootIterator(final Project project, + final VirtualFile root, + @Nullable final Processor pathProcessor, + @Nullable final Processor fileProcessor, @Nullable PairProcessor directoryFilter) { myProject = project; - myProcessor = processor; - myVfProcessor = vfProcessor; + myPathProcessor = pathProcessor; + myFileProcessor = fileProcessor; myDirectoryFilter = directoryFilter; + myRoot = root; final ProjectLevelVcsManager plVcsManager = ProjectLevelVcsManager.getInstance(project); final AbstractVcs vcs = plVcsManager.getVcsFor(root); myRootPresentFilter = (vcs == null) ? null : new MyRootFilter(root, vcs.getName()); myExcludedFileIndex = PeriodicalTasksCloser.getInstance().safeGetService(project, FileIndexFacade.class); - - myQueue = new LinkedList(); - myQueue.add(root); } public boolean iterate() { - while (! myQueue.isEmpty()) { - final VirtualFile current = myQueue.removeFirst(); - if (myProject.isDisposed() || !process(current)) return false; + class StopIterationException extends RuntimeException { } - if (current.isDirectory()) { - final VirtualFile[] files = current.getChildren(); - if (myDirectoryFilter != null && ! myDirectoryFilter.process(current, files)) continue; + try { + VfsUtilCore.visitChildrenRecursively(myRoot, new VirtualFileVisitor(false) { + @Override + public boolean visitFile(@NotNull VirtualFile file) { + if (myRootPresentFilter != null && !myRootPresentFilter.accept(file)) return false; + if (isExcluded(myExcludedFileIndex, file)) return false; - for (VirtualFile child : files) { - if (myRootPresentFilter != null && (! myRootPresentFilter.accept(child))) continue; - if (isExcluded(myExcludedFileIndex, child)) continue; - myQueue.add(child); + if (myProject.isDisposed() || !process(file)) throw new StopIterationException(); + + final VirtualFile[] files = file.getChildren(); + if (myDirectoryFilter != null && !myDirectoryFilter.process(file, files)) return false; + + return true; } - } + }); } + catch (StopIterationException e) { + return false; + } + return true; } private boolean process(VirtualFile current) { - if (myProcessor != null) { - return myProcessor.process(new FilePathImpl(current)); - } else { - return myVfProcessor.process(current); + if (myPathProcessor != null) { + return myPathProcessor.process(new FilePathImpl(current)); } + else if (myFileProcessor != null) { + return myFileProcessor.process(current); + } + return false; } } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java index 8a539d3c84e9..a8313de20d06 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspection.java @@ -17,6 +17,7 @@ package com.siyeh.ig; import com.intellij.codeInspection.BaseJavaLocalInspectionTool; import com.intellij.codeInspection.LocalInspectionToolSession; +import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; @@ -76,12 +77,12 @@ public abstract class BaseInspection extends BaseJavaLocalInspectionTool { } @Nullable - protected InspectionGadgetsFix buildFix(Object... infos) { + protected LocalQuickFix buildFix(Object... infos) { return null; } @NotNull - protected InspectionGadgetsFix[] buildFixes(Object... infos) { + protected LocalQuickFix[] buildFixes(Object... infos) { return InspectionGadgetsFix.EMPTY_ARRAY; } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java index 028b3591837f..bb79b58e2b8d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/BaseInspectionVisitor.java @@ -15,6 +15,7 @@ */ package com.siyeh.ig; +import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.openapi.util.TextRange; @@ -183,9 +184,11 @@ public abstract class BaseInspectionVisitor extends JavaElementVisitor { if (location.getTextLength() == 0 && !(location instanceof PsiFile)) { return; } - final InspectionGadgetsFix[] fixes = createFixes(infos); - for (InspectionGadgetsFix fix : fixes) { - fix.setOnTheFly(onTheFly); + final LocalQuickFix[] fixes = createFixes(infos); + for (LocalQuickFix fix : fixes) { + if (fix instanceof InspectionGadgetsFix) { + ((InspectionGadgetsFix)fix).setOnTheFly(onTheFly); + } } final String description = inspection.buildErrorString(infos); holder.registerProblem(location, description, highlightType, fixes); @@ -196,9 +199,11 @@ public abstract class BaseInspectionVisitor extends JavaElementVisitor { if (location.getTextLength() == 0 || length == 0) { return; } - final InspectionGadgetsFix[] fixes = createFixes(infos); - for (InspectionGadgetsFix fix : fixes) { - fix.setOnTheFly(onTheFly); + final LocalQuickFix[] fixes = createFixes(infos); + for (LocalQuickFix fix : fixes) { + if (fix instanceof InspectionGadgetsFix) { + ((InspectionGadgetsFix)fix).setOnTheFly(onTheFly); + } } final String description = inspection.buildErrorString(infos); final TextRange range = new TextRange(offset, offset + length); @@ -206,19 +211,19 @@ public abstract class BaseInspectionVisitor extends JavaElementVisitor { } @NotNull - private InspectionGadgetsFix[] createFixes(Object... infos) { + private LocalQuickFix[] createFixes(Object... infos) { if (!onTheFly && inspection.buildQuickFixesOnlyForOnTheFlyErrors()) { return InspectionGadgetsFix.EMPTY_ARRAY; } - final InspectionGadgetsFix[] fixes = inspection.buildFixes(infos); + final LocalQuickFix[] fixes = inspection.buildFixes(infos); if (fixes.length > 0) { return fixes; } - final InspectionGadgetsFix fix = inspection.buildFix(infos); + final LocalQuickFix fix = inspection.buildFix(infos); if (fix == null) { return InspectionGadgetsFix.EMPTY_ARRAY; } - return new InspectionGadgetsFix[]{fix}; + return new LocalQuickFix[]{fix}; } @Override diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/assignment/AssignmentToNullInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/assignment/AssignmentToNullInspection.java index c46f3c01dbea..5c8665045d8b 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/assignment/AssignmentToNullInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/assignment/AssignmentToNullInspection.java @@ -15,7 +15,10 @@ */ package com.siyeh.ig.assignment; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.NullableNotNullManager; +import com.intellij.codeInsight.intention.AddAnnotationFix; +import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.psi.*; import com.siyeh.InspectionGadgetsBundle; @@ -44,6 +47,12 @@ public class AssignmentToNullInspection extends BaseInspection { "assignment.to.null.problem.descriptor"); } + @Override + protected LocalQuickFix buildFix(Object... infos) { + PsiVariable resolve = (PsiVariable)((PsiReferenceExpression)infos[0]).resolve(); + return resolve != null ? new AddAnnotationFix(AnnotationUtil.NULLABLE, resolve) : null; + } + @Override public JComponent createOptionsPanel() { return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message( @@ -82,7 +91,7 @@ public class AssignmentToNullInspection extends BaseInspection { if (lhs == null || isReferenceToNullableVariable(lhs)) { return; } - registerError(lhs); + registerError(lhs, lhs); } private boolean isReferenceToNullableVariable( diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReflectionForUnavailableAnnotationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReflectionForUnavailableAnnotationInspection.java index dff665fbe5e8..f13ac0f4fd8d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReflectionForUnavailableAnnotationInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/ReflectionForUnavailableAnnotationInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2006-2012 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,21 +23,18 @@ import com.siyeh.ig.psiutils.TypeUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -public class ReflectionForUnavailableAnnotationInspection - extends BaseInspection { +public class ReflectionForUnavailableAnnotationInspection extends BaseInspection { @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "reflection.for.unavailable.annotation.display.name"); + return InspectionGadgetsBundle.message("reflection.for.unavailable.annotation.display.name"); } @Override @NotNull public String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "reflection.for.unavailable.annotation.problem.descriptor"); + return InspectionGadgetsBundle.message("reflection.for.unavailable.annotation.problem.descriptor"); } @Override @@ -50,19 +47,14 @@ public class ReflectionForUnavailableAnnotationInspection return new ReflectionForUnavailableAnnotationVisitor(); } - private static class ReflectionForUnavailableAnnotationVisitor - extends BaseInspectionVisitor { + private static class ReflectionForUnavailableAnnotationVisitor extends BaseInspectionVisitor { @Override - public void visitMethodCallExpression( - @NotNull PsiMethodCallExpression expression) { + public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) { super.visitMethodCallExpression(expression); - final PsiReferenceExpression methodExpression = - expression.getMethodExpression(); - @NonNls final String methodName = - methodExpression.getReferenceName(); - if (!"isAnnotationPresent".equals(methodName) && - !"getAnnotation".equals(methodName)) { + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + @NonNls final String methodName = methodExpression.getReferenceName(); + if (!"isAnnotationPresent".equals(methodName) && !"getAnnotation".equals(methodName)) { return; } final PsiExpressionList argumentList = expression.getArgumentList(); @@ -77,36 +69,28 @@ public class ReflectionForUnavailableAnnotationInspection if (!(arg instanceof PsiClassObjectAccessExpression)) { return; } - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); - if (!TypeUtils.expressionHasTypeOrSubtype(qualifier, - "java.lang.reflect.AnnotatedElement")) { + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (!TypeUtils.expressionHasTypeOrSubtype(qualifier, "java.lang.reflect.AnnotatedElement")) { return; } - final PsiClassObjectAccessExpression classObjectAccessExpression = - (PsiClassObjectAccessExpression)arg; - final PsiTypeElement operand = - classObjectAccessExpression.getOperand(); + final PsiClassObjectAccessExpression classObjectAccessExpression = (PsiClassObjectAccessExpression)arg; + final PsiTypeElement operand = classObjectAccessExpression.getOperand(); - final PsiClassType annotationClassType = - (PsiClassType)operand.getType(); + final PsiClassType annotationClassType = (PsiClassType)operand.getType(); final PsiClass annotationClass = annotationClassType.resolve(); if (annotationClass == null) { return; } - final PsiModifierList modifierList = - annotationClass.getModifierList(); + final PsiModifierList modifierList = annotationClass.getModifierList(); if (modifierList == null) { return; } - final PsiAnnotation retentionAnnotation = - modifierList.findAnnotation("java.lang.annotation.Retention"); + final PsiAnnotation retentionAnnotation = modifierList.findAnnotation("java.lang.annotation.Retention"); if (retentionAnnotation == null) { registerError(arg); return; } - final PsiAnnotationParameterList parameters = - retentionAnnotation.getParameterList(); + final PsiAnnotationParameterList parameters = retentionAnnotation.getParameterList(); final PsiNameValuePair[] attributes = parameters.getAttributes(); for (PsiNameValuePair attribute : attributes) { @NonNls final String name = attribute.getName(); @@ -114,6 +98,9 @@ public class ReflectionForUnavailableAnnotationInspection continue; } final PsiAnnotationMemberValue value = attribute.getValue(); + if (value == null) { + continue; + } @NonNls final String text = value.getText(); if (!text.contains("RUNTIME")) { registerError(arg); diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntention.java index 8d724eaf013b..5b5dcd549051 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntention.java @@ -22,6 +22,9 @@ import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.List; + public class JoinConcatenatedStringLiteralsIntention extends Intention { @Override @@ -40,34 +43,48 @@ public class JoinConcatenatedStringLiteralsIntention extends Intention { } final PsiJavaToken token = (PsiJavaToken)element; final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)element.getParent(); - final PsiExpression[] operands = polyadicExpression.getOperands(); StringBuilder newExpression = new StringBuilder(); - PsiExpression previous = null; - for (PsiExpression operand : operands) { - if (newExpression.length() != 0 && previous != null) { - newExpression.append('+'); + final PsiElement[] children = polyadicExpression.getChildren(); + final List buffer = new ArrayList(3); + for (PsiElement child : children) { + if (child instanceof PsiJavaToken) { + if (token.equals(child)) { + final PsiLiteralExpression literalExpression = (PsiLiteralExpression)buffer.get(0); + final Object value = literalExpression.getValue(); + assert value != null; + newExpression.append('"').append(StringUtil.escapeStringCharacters(value.toString())); + } + else { + for (PsiElement bufferedElement : buffer) { + newExpression.append(bufferedElement.getText()); + } + buffer.clear(); + newExpression.append(child.getText()); + } } - final PsiJavaToken currentToken = polyadicExpression.getTokenBeforeOperand(operand); - if (token == currentToken) { - final PsiLiteralExpression literal1 = (PsiLiteralExpression)previous; - assert literal1 != null; - final PsiLiteralExpression literal2 = (PsiLiteralExpression)operand; - final Object value1 = literal1.getValue(); - final Object value2 = literal2.getValue(); - assert value1 != null && value2 != null; - final String text1 = StringUtil.escapeStringCharacters(value1.toString()); - final String text2 = StringUtil.escapeStringCharacters(value2.toString()); - newExpression.append('"').append(text1).append(text2).append('"'); - previous = null; - } else { - if (previous != null) { - newExpression.append(previous.getText()); + else if (child instanceof PsiLiteralExpression) { + if (buffer.isEmpty()) { + buffer.add(child); + } + else { + final PsiLiteralExpression literalExpression = (PsiLiteralExpression)child; + final Object value = literalExpression.getValue(); + assert value != null; + newExpression.append(StringUtil.escapeStringCharacters(value.toString())).append('"'); + buffer.clear(); + } + } + else { + if (buffer.isEmpty()) { + newExpression.append(child.getText()); + } + else { + buffer.add(child); } - previous = operand; } } - if (previous != null) { - newExpression.append('+').append(previous.getText()); + for (PsiElement bufferedElement : buffer) { + newExpression.append(bufferedElement.getText()); } replaceExpression(newExpression.toString(), polyadicExpression); } diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/join_concat/KeepCommentsAndWhitespace.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/join_concat/KeepCommentsAndWhitespace.java new file mode 100644 index 000000000000..874ce65ceeb1 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/join_concat/KeepCommentsAndWhitespace.java @@ -0,0 +1,12 @@ +class KeepCommentsAndWhitespace { + static { + System.out.println("select foo_id, bar, baz "+ + "from foo f "+ + "where bar=1 "+ + " and baz=2 " + + " and gazonk < ("+ // comment + " select count(distinct feeble) " + + " from dribble "+ + " where zabble = f.bar)"); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/join_concat/KeepCommentsAndWhitespace_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/join_concat/KeepCommentsAndWhitespace_after.java new file mode 100644 index 000000000000..1622f5eded8e --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/concatenation/join_concat/KeepCommentsAndWhitespace_after.java @@ -0,0 +1,11 @@ +class KeepCommentsAndWhitespace { + static { + System.out.println("select foo_id, bar, baz " + + "from foo f " + + "where bar=1 " + + " and baz=2 and gazonk < (" + // comment + " select count(distinct feeble) " + + " from dribble " + + " where zabble = f.bar)"); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntentionTest.java index 769c1ed24042..ca3dd1a368d5 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/concatenation/JoinConcatenatedStringLiteralsIntentionTest.java @@ -9,6 +9,7 @@ public class JoinConcatenatedStringLiteralsIntentionTest extends IPPTestCase { public void testNonString() { doTest(); } public void testNonString2() { doTest(); } public void testNotAvailable() { assertIntentionNotAvailable(); } + public void testKeepCommentsAndWhitespace() { doTest(); } @Override protected String getIntentionName() { diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index 1c71fbec8a32..8879306301f5 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -1,1540 +1,1569 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - - - - - - - - ]]> - - - - - - - - - - - - - - - - - - - - -