diff --git a/.idea/libraries/junit5_rt.xml b/.idea/libraries/junit5_rt.xml new file mode 100644 index 000000000000..5a0fe646a47b --- /dev/null +++ b/.idea/libraries/junit5_rt.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/opentest4j.xml b/.idea/libraries/opentest4j.xml new file mode 100644 index 000000000000..a950465a1404 --- /dev/null +++ b/.idea/libraries/opentest4j.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 15c4ae1ce18a..98246cf2ab4c 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -151,6 +151,7 @@ + diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index e7cc2e2458d8..8a75218a72ca 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -472,6 +472,12 @@ public def layoutCommunityPlugins(String home, boolean maySkipAndroidPlugin = fa jar("junit-rt.jar") { module("junit_rt") } + jar("junit5-rt.jar") { + module("junit5_rt") + } + fileset(dir: "$home/plugins/junit5_rt/lib") { + include(name: "*.jar") + } } pluginDir("ByteCodeViewer") { @@ -955,7 +961,6 @@ def layout_core(String home, String target) { module("util") module("core-api") module("core-impl") - module("boot") module("extensions") module("java-psi-api") module("java-psi-impl") diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant index 3f0eaf561e28..9b61c888ba32 100644 --- a/build/scripts/libLicenses.gant +++ b/build/scripts/libLicenses.gant @@ -244,6 +244,7 @@ libraryLicense(name: "jsr305", libraryName: "jsr305", version: "snapshot", licen libraryLicense(name: "Jsr305", version: "1.3.9", license: "New BSD", url: "http://code.google.com/p/jsr-305/", licenseUrl: "http://opensource.org/licenses/BSD-3-Clause") libraryLicense(name: "JUnit", libraryName: "JUnit3", version: "3.8.1", license: "CPL 1.0", url: "http://junit.org/") libraryLicense(name: "JUnit", libraryName: "JUnit4", version: "4.11", license: "CPL 1.0", url: "http://junit.org/") +libraryLicense(name: "junit5_rt", libraryName: "junit5_rt", version: "5.0.0", license: "Eclipse Public License 1.0", url: "http://junit.org/") libraryLicense(name: "jzlib", libraryName: "jzlib", version: "1.1.1", license: "BSD", url: "http://www.jcraft.com/jzlib/", licenseUrl: "http://www.jcraft.com/jzlib/LICENSE.txt") libraryLicense(name: "Kryo", libraryName: "Kryo", version: "2.22", license: "New BSD License", url: "https://github.com/EsotericSoftware/kryo", licenseUrl: "https://github.com/EsotericSoftware/kryo/blob/master/license.txt") libraryLicense(name: "kXML2", libraryName: "kxml2", version: "2.3.0", license: "BSD", url: "http://sourceforge.net/projects/kxml/") @@ -266,6 +267,7 @@ libraryLicense(name: "NanoXML", version: "2.2.3", license: "zlib/libpng", url: " libraryLicense(name: "nekohtml", libraryName: "nekohtml", version: "1.9.14", license: "Apache 2.0", url: "http://nekohtml.sourceforge.net/", licenseUrl: "http://apache.org/licenses/LICENSE-2.0.txt") libraryLicense(name: "Netty", libraryName: "Netty", version: "4.1.0.Beta3", license: "Apache 2.0", url: "http://netty.io", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0") libraryLicense(name: "Objenesis", libraryName: "objenesis-1.2.jar", version: "1.2", license: "Apache 2.0", url: "http://objenesis.org/", licenseUrl: "http://apache.org/licenses/LICENSE-2.0") +libraryLicense(name: "opentest4j", libraryName: "opentest4j", version: "1.0.0", license: "Apache 2.0", url: "https://github.com/ota4j-team/opentest4j", licenseUrl: "http://apache.org/licenses/LICENSE-2.0") libraryLicense(name: "pep8.py", attachedTo: "python-helpers", version: "1.6.2", license: "MIT", url: "http://pep8.readthedocs.org/") libraryLicense(name: "PicoContainer", libraryName: "picocontainer", version: "1.2", license: "BSD", url: "http://www.picocontainer.org/", licenseUrl: "http://docs.codehaus.org/display/PICO/License") libraryLicense(name: "plexus-archiver", libraryName: "plexus-archiver-2.4.4.jar", version: "2.4.4", license: "Apache 2.0", url: "https://github.com/codehaus-plexus/plexus-archiver", licenseUrl: "http://apache.org/licenses/LICENSE-2.0") diff --git a/java/debugger/impl/debugger-impl.iml b/java/debugger/impl/debugger-impl.iml index b35289246ebb..3a9669db998f 100644 --- a/java/debugger/impl/debugger-impl.iml +++ b/java/debugger/impl/debugger-impl.iml @@ -21,8 +21,6 @@ - - diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java index f790a0bf68ce..6183d59f03c4 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/CodeFragmentFactoryContextWrapper.java @@ -26,6 +26,7 @@ import com.intellij.psi.JavaRecursiveElementVisitor; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiLocalVariable; import com.intellij.util.StringBuilderSpinAllocator; +import com.intellij.util.containers.ContainerUtil; import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.impl.XDebugSessionImpl; @@ -87,7 +88,7 @@ public class CodeFragmentFactoryContextWrapper extends CodeFragmentFactory { XValueMarkers markers = ((XDebugSessionImpl)session).getValueMarkers(); Map markupMap = markers != null ? markers.getAllMarkers() : null; //final Map markupMap = ValueDescriptorImpl.getMarkupMap(process); - if (markupMap != null && markupMap.size() > 0) { + if (!ContainerUtil.isEmpty(markupMap)) { final Pair> markupVariables = createMarkupVariablesText(markupMap); int offset = markupVariables.getFirst().length() - 1; final TextWithImportsImpl textWithImports = new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, markupVariables.getFirst(), "", myDelegate.getFileType()); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CatchEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CatchEvaluator.java new file mode 100644 index 000000000000..0ad17237fec4 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CatchEvaluator.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2016 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.debugger.engine.evaluation.expression; + +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.sun.jdi.ObjectReference; + +/** + * @author egor + */ +public class CatchEvaluator implements Evaluator { + private final String myExceptionType; + private final String myParamName; + private final CodeFragmentEvaluator myEvaluator; + + public CatchEvaluator(String exceptionType, String paramName, CodeFragmentEvaluator evaluator) { + myExceptionType = exceptionType; + myParamName = paramName; + myEvaluator = evaluator; + } + + public Object evaluate(ObjectReference exception, EvaluationContextImpl context) throws EvaluateException { + myEvaluator.setValue(myParamName, exception); + return myEvaluator.evaluate(context); + } + + @Override + public Object evaluate(EvaluationContextImpl context) throws EvaluateException { + throw new IllegalStateException("Use evaluate(ObjectReference exception, EvaluationContextImpl context)"); + } + + public String getExceptionType() { + return myExceptionType; + } + + @Override + public Modifier getModifier() { + return null; + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CodeFragmentEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CodeFragmentEvaluator.java index 3575d76fab4f..f3fae7db1796 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CodeFragmentEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/CodeFragmentEvaluator.java @@ -18,6 +18,7 @@ package com.intellij.debugger.engine.evaluation.expression; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; +import com.intellij.debugger.engine.evaluation.EvaluateRuntimeException; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.containers.HashMap; @@ -103,10 +104,11 @@ public class CodeFragmentEvaluator extends BlockStatementEvaluator{ } } - public void setInitialValue(String localName, Object value) throws EvaluateException { + public void setInitialValue(String localName, Object value) { LOG.assertTrue(!(value instanceof Value), "use setValue for jdi values"); if(hasValue(localName)) { - throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.variable.already.declared", localName)); + throw new EvaluateRuntimeException( + EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.variable.already.declared", localName))); } mySyntheticLocals.put(localName, value); } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java index 291407a2989d..b0a57d5e5b98 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java @@ -190,9 +190,51 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { @Override public void visitTryStatement(PsiTryStatement statement) { - throw new EvaluateRuntimeException(new UnsupportedExpressionException(statement.getText())); + if (statement.getResourceList() != null) { + throw new EvaluateRuntimeException(new UnsupportedExpressionException("Try with resources is not yet supported")); + } + Evaluator bodyEvaluator = accept(statement.getTryBlock()); + if (bodyEvaluator != null) { + PsiCatchSection[] catchSections = statement.getCatchSections(); + List evaluators = new ArrayList<>(); + for (PsiCatchSection catchSection : catchSections) { + PsiParameter parameter = catchSection.getParameter(); + PsiCodeBlock catchBlock = catchSection.getCatchBlock(); + if (parameter != null && catchBlock != null) { + CodeFragmentEvaluator oldFragmentEvaluator = setNewCodeFragmentEvaluator(); + try { + myCurrentFragmentEvaluator.setInitialValue(parameter.getName(), null); + myCurrentFragmentEvaluator.setStatements(visitStatements(catchBlock.getStatements())); + PsiType type = parameter.getType(); + List types = + type instanceof PsiDisjunctionType ? ((PsiDisjunctionType)type).getDisjunctions() : Collections.singletonList(type); + for (PsiType psiType : types) { + evaluators.add(new CatchEvaluator(psiType.getCanonicalText(), parameter.getName(), myCurrentFragmentEvaluator)); + } + } + finally{ + myCurrentFragmentEvaluator = oldFragmentEvaluator; + } + } + } + myResult = new TryEvaluator(bodyEvaluator, evaluators, accept(statement.getFinallyBlock())); + } } + @Override + public void visitThrowStatement(PsiThrowStatement statement) { + Evaluator accept = accept(statement.getException()); + if (accept != null) { + myResult = new ThrowEvaluator(accept); + } + } + + @Override + public void visitReturnStatement(PsiReturnStatement statement) { + myResult = new ReturnEvaluator(accept(statement.getReturnValue())); + } + + @Override public void visitStatement(PsiStatement statement) { throwEvaluateException(DebuggerBundle.message("evaluation.error.statement.not.supported", statement.getText())); @@ -204,25 +246,33 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { return old; } + private Evaluator[] visitStatements(PsiStatement[] statements) { + Evaluator[] evaluators = new Evaluator[statements.length]; + for (int i = 0; i < statements.length; i++) { + PsiStatement psiStatement = statements[i]; + psiStatement.accept(this); + evaluators[i] = new DisableGC(myResult); + myResult = null; + } + return evaluators; + } + @Override - public void visitBlockStatement(PsiBlockStatement statement) { + public void visitCodeBlock(PsiCodeBlock block) { CodeFragmentEvaluator oldFragmentEvaluator = setNewCodeFragmentEvaluator(); try { - PsiStatement[] statements = statement.getCodeBlock().getStatements(); - Evaluator[] evaluators = new Evaluator[statements.length]; - for (int i = 0; i < statements.length; i++) { - PsiStatement psiStatement = statements[i]; - psiStatement.accept(this); - evaluators[i] = new DisableGC(myResult); - myResult = null; - } - myResult = new BlockStatementEvaluator(evaluators); + myResult = new BlockStatementEvaluator(visitStatements(block.getStatements())); } finally { myCurrentFragmentEvaluator = oldFragmentEvaluator; } } + @Override + public void visitBlockStatement(PsiBlockStatement statement) { + visitCodeBlock(statement.getCodeBlock()); + } + @Override public void visitLabeledStatement(PsiLabeledStatement labeledStatement) { PsiStatement statement = labeledStatement.getStatement(); @@ -259,33 +309,40 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { @Override public void visitForStatement(PsiForStatement statement) { - Evaluator initializerEvaluator = accept(statement.getInitialization()); - Evaluator conditionEvaluator = accept(statement.getCondition()); - if (conditionEvaluator != null) { - conditionEvaluator = new UnBoxingEvaluator(conditionEvaluator); - } - Evaluator updateEvaluator = accept(statement.getUpdate()); - Evaluator bodyEvaluator = accept(statement.getBody()); - if (bodyEvaluator != null) { - myResult = new ForStatementEvaluator(initializerEvaluator, conditionEvaluator, updateEvaluator, bodyEvaluator, getLabel(statement)); + CodeFragmentEvaluator oldFragmentEvaluator = setNewCodeFragmentEvaluator(); + try { + Evaluator initializerEvaluator = accept(statement.getInitialization()); + Evaluator conditionEvaluator = accept(statement.getCondition()); + if (conditionEvaluator != null) { + conditionEvaluator = new UnBoxingEvaluator(conditionEvaluator); + } + Evaluator updateEvaluator = accept(statement.getUpdate()); + Evaluator bodyEvaluator = accept(statement.getBody()); + if (bodyEvaluator != null) { + myResult = + new ForStatementEvaluator(initializerEvaluator, conditionEvaluator, updateEvaluator, bodyEvaluator, getLabel(statement)); + } + } finally { + myCurrentFragmentEvaluator = oldFragmentEvaluator; } } @Override public void visitForeachStatement(PsiForeachStatement statement) { + CodeFragmentEvaluator oldFragmentEvaluator = setNewCodeFragmentEvaluator(); try { String iterationParameterName = statement.getIterationParameter().getName(); myCurrentFragmentEvaluator.setInitialValue(iterationParameterName, null); - SyntheticVariableEvaluator iterationParameterEvaluator = new SyntheticVariableEvaluator(myCurrentFragmentEvaluator, iterationParameterName); + SyntheticVariableEvaluator iterationParameterEvaluator = + new SyntheticVariableEvaluator(myCurrentFragmentEvaluator, iterationParameterName); Evaluator iteratedValueEvaluator = accept(statement.getIteratedValue()); Evaluator bodyEvaluator = accept(statement.getBody()); if (bodyEvaluator != null) { myResult = new ForeachStatementEvaluator(iterationParameterEvaluator, iteratedValueEvaluator, bodyEvaluator, getLabel(statement)); } - } - catch (EvaluateException e) { - throw new EvaluateRuntimeException(e); + } finally { + myCurrentFragmentEvaluator = oldFragmentEvaluator; } } @@ -538,9 +595,6 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder { catch (IncorrectOperationException e) { LOG.error(e); } - catch (EvaluateException e) { - throw new EvaluateRuntimeException(e); - } PsiExpression initializer = localVariable.getInitializer(); if (initializer != null) { diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java index 9c8ab0671541..b0e19e6ac527 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ExpressionEvaluatorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -72,6 +72,9 @@ public class ExpressionEvaluatorImpl implements ExpressionEvaluator { myValue = (Value)value; return myValue; } + catch (ReturnEvaluator.ReturnException r) { + return (Value)r.getReturnValue(); + } catch (Throwable/*IncompatibleThreadStateException*/ e) { if (LOG.isDebugEnabled()) { LOG.debug(e); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ReturnEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ReturnEvaluator.java new file mode 100644 index 000000000000..a1b4057d04df --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ReturnEvaluator.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2016 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.debugger.engine.evaluation.expression; + +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import org.jetbrains.annotations.Nullable; + +/** + * @author egor + */ +public class ReturnEvaluator implements Evaluator { + @Nullable private final Evaluator myReturnValueEvaluator; + + public ReturnEvaluator(@Nullable Evaluator returnValueEvaluator) { + myReturnValueEvaluator = returnValueEvaluator; + } + + @Override + public Object evaluate(EvaluationContextImpl context) throws EvaluateException { + Object returnValue = myReturnValueEvaluator == null ? + context.getDebugProcess().getVirtualMachineProxy().mirrorOfVoid() : + myReturnValueEvaluator.evaluate(context); + throw new ReturnException(returnValue); + } + + @Override + public Modifier getModifier() { + return null; + } + + public static class ReturnException extends EvaluateException { + private final Object myReturnValue; + + public ReturnException(Object returnValue) { + super("Return"); + myReturnValue = returnValue; + } + + public Object getReturnValue() { + return myReturnValue; + } + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThrowEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThrowEvaluator.java new file mode 100644 index 000000000000..b14bb4b371d9 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/ThrowEvaluator.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2016 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.debugger.engine.evaluation.expression; + +import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.sun.jdi.ObjectReference; +import org.jetbrains.annotations.NotNull; + +/** + * @author egor + */ +public class ThrowEvaluator implements Evaluator { + @NotNull private final Evaluator myExceptionEvaluator; + + public ThrowEvaluator(@NotNull Evaluator exceptionEvaluator) { + myExceptionEvaluator = exceptionEvaluator; + } + + @Override + public Object evaluate(EvaluationContextImpl context) throws EvaluateException { + ObjectReference exception = (ObjectReference)myExceptionEvaluator.evaluate(context); + EvaluateException ex = new EvaluateException( + DebuggerBundle.message("evaluation.error.method.exception", exception.referenceType().name())); + ex.setTargetException(exception); + throw ex; + } + + @Override + public Modifier getModifier() { + return null; + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TryEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TryEvaluator.java new file mode 100644 index 000000000000..d3267e6f2ab6 --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/TryEvaluator.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2016 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.debugger.engine.evaluation.expression; + +import com.intellij.debugger.engine.DebuggerUtils; +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.sun.jdi.ObjectReference; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @author egor + */ +public class TryEvaluator implements Evaluator { + @NotNull private final Evaluator myBodyEvaluator; + private final List myCatchBlockEvaluators; + @Nullable private final Evaluator myFinallyEvaluator; + + public TryEvaluator(@NotNull Evaluator bodyEvaluator, + List catchBlockEvaluators, + @Nullable Evaluator finallyEvaluator) { + myBodyEvaluator = bodyEvaluator; + myCatchBlockEvaluators = catchBlockEvaluators; + myFinallyEvaluator = finallyEvaluator; + } + + @Override + public Object evaluate(EvaluationContextImpl context) throws EvaluateException { + Object result = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOfVoid(); + try { + result = myBodyEvaluator.evaluate(context); + } catch (EvaluateException e) { + boolean catched = false; + ObjectReference vmException = e.getExceptionFromTargetVM(); + if (vmException != null) { + for (CatchEvaluator evaluator : myCatchBlockEvaluators) { + if (evaluator != null && DebuggerUtils.instanceOf(vmException.type(), evaluator.getExceptionType())) { + result = evaluator.evaluate(vmException, context); + catched = true; + break; + } + } + } + if (!catched) { + throw e; + } + } finally { + if (myFinallyEvaluator != null) { + result = myFinallyEvaluator.evaluate(context); + } + } + return result; + } + + @Override + public Modifier getModifier() { + return null; + } +} diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java index 7819a3dd076d..542fd55570da 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -153,10 +153,17 @@ public abstract class DebuggerUtils { public static Method findMethod(@NotNull ReferenceType refType, @NonNls String methodName, @Nullable @NonNls String methodSignature) { if (refType instanceof ArrayType) { // for array types methodByName() in JDI always returns empty list - final Method method = findMethod(refType.virtualMachine().classesByName(CommonClassNames.JAVA_LANG_OBJECT).get(0), methodName, methodSignature); + Method method = findMethod(refType.virtualMachine().classesByName(CommonClassNames.JAVA_LANG_OBJECT).get(0), methodName, methodSignature); if (method != null) { return method; } + // for arrays, clone signature may return array of objects, there is no such method in Object class + if ("clone".equals(methodName) && "()[Ljava/lang/Object;".equals(methodSignature)) { + method = findMethod(refType.virtualMachine().classesByName(CommonClassNames.JAVA_LANG_OBJECT).get(0), "clone", null); + if (method != null) { + return method; + } + } } Method method = null; diff --git a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java index 2f538f46db98..d52bb86f8fcc 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java +++ b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java @@ -21,13 +21,14 @@ import com.intellij.execution.junit2.PsiMemberParameterizedLocation; import com.intellij.execution.junit2.info.MethodLocation; import com.intellij.ide.util.PsiClassListCellRenderer; import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Conditions; import com.intellij.psi.*; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.util.PsiClassUtil; @@ -88,10 +89,11 @@ public class InheritorChooser { if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { @Override public void run() { + final boolean isJUnit5 = ApplicationManager.getApplication().runReadAction((Computable)() -> JUnitUtil.isJUnit5(containingClass)); ClassInheritorsSearch.search(containingClass).forEach(new Processor() { @Override public boolean process(PsiClass aClass) { - if (PsiClassUtil.isRunnableClass(aClass, true, true)) { + if (PsiClassUtil.isRunnableClass(aClass, !isJUnit5, true)) { classes.add(aClass); } return true; diff --git a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java index 74bf67d2c428..db073a2738d5 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java +++ b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java @@ -37,10 +37,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; +import java.util.*; @SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) public class JUnitUtil { @@ -48,17 +45,38 @@ public class JUnitUtil { @NonNls private static final String TEST_INTERFACE = "junit.framework.Test"; @NonNls private static final String TESTSUITE_CLASS = "junit.framework.TestSuite"; @NonNls public static final String TEST_ANNOTATION = "org.junit.Test"; + @NonNls public static final String TEST5_ANNOTATION = "org.junit.gen5.api.Test"; @NonNls public static final String IGNORE_ANNOTATION = "org.junit.Ignore"; @NonNls public static final String RUN_WITH = "org.junit.runner.RunWith"; @NonNls public static final String DATA_POINT = "org.junit.experimental.theories.DataPoint"; @NonNls public static final String SUITE_METHOD_NAME = "suite"; + public static final String BEFORE_ANNOTATION_NAME = "org.junit.Before"; public static final String AFTER_ANNOTATION_NAME = "org.junit.After"; + + public static final String BEFORE_EACH_ANNOTATION_NAME = "org.junit.gen5.api.BeforeEach"; + public static final String AFTER_EACH_ANNOTATION_NAME = "org.junit.gen5.api.AfterEach"; + public static final String PARAMETRIZED_PARAMETERS_ANNOTATION_NAME = "org.junit.runners.Parameterized.Parameters"; + public static final String AFTER_CLASS_ANNOTATION_NAME = "org.junit.AfterClass"; public static final String BEFORE_CLASS_ANNOTATION_NAME = "org.junit.BeforeClass"; + + public static final String BEFORE_ALL_ANNOTATION_NAME = "org.junit.gen5.api.BeforeAll"; + public static final String AFTER_ALL_ANNOTATION_NAME = "org.junit.gen5.api.AfterAll"; + + private static final Collection TEST_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(TEST_ANNOTATION, TEST5_ANNOTATION)); + + private static final List INSTANCE_CONFIGS = Arrays.asList(BEFORE_ANNOTATION_NAME, AFTER_ANNOTATION_NAME); + private static final List INSTANCE_5_CONFIGS = Arrays.asList(BEFORE_EACH_ANNOTATION_NAME, AFTER_EACH_ANNOTATION_NAME); + + private static final List STATIC_5_CONFIGS = Arrays.asList(BEFORE_ALL_ANNOTATION_NAME, AFTER_ALL_ANNOTATION_NAME); + + private static final List STATIC_CONFIGS = Arrays.asList(BEFORE_CLASS_ANNOTATION_NAME, AFTER_CLASS_ANNOTATION_NAME, + PARAMETRIZED_PARAMETERS_ANNOTATION_NAME); private static final Collection CONFIGURATIONS_ANNOTATION_NAME = Collections.unmodifiableList( - Arrays.asList(DATA_POINT, AFTER_ANNOTATION_NAME, BEFORE_ANNOTATION_NAME, AFTER_CLASS_ANNOTATION_NAME, BEFORE_CLASS_ANNOTATION_NAME)); + Arrays.asList(DATA_POINT, AFTER_ANNOTATION_NAME, BEFORE_ANNOTATION_NAME, AFTER_CLASS_ANNOTATION_NAME, BEFORE_CLASS_ANNOTATION_NAME, + BEFORE_ALL_ANNOTATION_NAME, AFTER_ALL_ANNOTATION_NAME)); @NonNls public static final String PARAMETERIZED_CLASS_NAME = "org.junit.runners.Parameterized"; @NonNls public static final String SUITE_CLASS_NAME = "org.junit.runners.Suite"; @@ -126,17 +144,27 @@ public class JUnitUtil { } } } - if (!PsiClassUtil.isRunnableClass(psiClass, true, checkAbstract)) return false; - if (checkForTestCaseInheritance && isTestCaseInheritor(psiClass)) return true; final PsiModifierList modifierList = psiClass.getModifierList(); if (modifierList == null) return false; if (AnnotationUtil.isAnnotated(psiClass, RUN_WITH, true)) return true; + final boolean hasJUnit5 = isJUnit5(modifierList); + if (!PsiClassUtil.isRunnableClass(psiClass, !hasJUnit5, checkAbstract)) return false; + if (checkForTestCaseInheritance && (!hasJUnit5 || psiClass.hasModifierProperty(PsiModifier.PUBLIC)) && isTestCaseInheritor(psiClass)) return true; + for (final PsiMethod method : psiClass.getAllMethods()) { ProgressManager.checkCanceled(); if (isSuiteMethod(method)) return true; if (isTestAnnotated(method)) return true; } + + if (hasJUnit5) { + for (PsiClass innerClass : psiClass.getInnerClasses()) { + for (PsiMethod method : innerClass.getAllMethods()) { + if (isTestAnnotated(method)) return true; + } + } + } return false; } @@ -150,11 +178,12 @@ public class JUnitUtil { } private static boolean isJUnit4TestClass(final PsiClass psiClass, boolean checkAbstract) { - if (!PsiClassUtil.isRunnableClass(psiClass, true, checkAbstract)) return false; - final PsiModifierList modifierList = psiClass.getModifierList(); if (modifierList == null) return false; if (AnnotationUtil.isAnnotated(psiClass, RUN_WITH, true)) return true; + + if (!PsiClassUtil.isRunnableClass(psiClass, !isJUnit5(modifierList), checkAbstract)) return false; + for (final PsiMethod method : psiClass.getAllMethods()) { ProgressManager.checkCanceled(); if (isTestAnnotated(method)) return true; @@ -163,8 +192,16 @@ public class JUnitUtil { return false; } + public static boolean isJUnit5(@NotNull PsiElement element) { + return isJUnit5(element.getResolveScope(), element.getProject()); + } + + public static boolean isJUnit5(GlobalSearchScope scope, Project project) { + return JavaPsiFacade.getInstance(project).findClass(TEST5_ANNOTATION, scope) != null; + } + public static boolean isTestAnnotated(final PsiMethod method) { - if (AnnotationUtil.isAnnotated(method, TEST_ANNOTATION, false) || JUnitRecognizer.willBeAnnotatedAfterCompilation(method)) { + if (AnnotationUtil.isAnnotated(method, TEST_ANNOTATIONS, false) || JUnitRecognizer.willBeAnnotatedAfterCompilation(method)) { final PsiAnnotation annotation = AnnotationUtil.findAnnotationInHierarchy(method.getContainingClass(), Collections.singleton(RUN_WITH)); if (annotation != null) { final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); @@ -240,18 +277,28 @@ public class JUnitUtil { } } final String name = psiMethod.getName(); - if (psiMethod.hasModifierProperty(PsiModifier.PUBLIC) && !psiMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { - if (SUITE_METHOD_NAME.equals(name) || "setUp".equals(name) || "tearDown".equals(name)) { + final boolean isPublic = psiMethod.hasModifierProperty(PsiModifier.PUBLIC); + if (!psiMethod.hasModifierProperty(PsiModifier.ABSTRACT)) { + if (isPublic && (SUITE_METHOD_NAME.equals(name) || "setUp".equals(name) || "tearDown".equals(name))) { return true; } + if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) { - if (AnnotationUtil.isAnnotated(psiMethod, Arrays.asList(BEFORE_CLASS_ANNOTATION_NAME, AFTER_CLASS_ANNOTATION_NAME, - PARAMETRIZED_PARAMETERS_ANNOTATION_NAME))) { + if (AnnotationUtil.isAnnotated(psiMethod, STATIC_CONFIGS)) { + return isPublic; + } + if (AnnotationUtil.isAnnotated(psiMethod, STATIC_5_CONFIGS)) { return true; } } else { - if (AnnotationUtil.isAnnotated(psiMethod, Arrays.asList(BEFORE_ANNOTATION_NAME, AFTER_ANNOTATION_NAME))) return true; + if (AnnotationUtil.isAnnotated(psiMethod, INSTANCE_CONFIGS)) { + return isPublic; + } + + if (AnnotationUtil.isAnnotated(psiMethod, INSTANCE_5_CONFIGS)) { + return true; + } } } return false; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java index 6d4ac0cebcfa..721215762768 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnnotateMethodFix.java @@ -101,7 +101,7 @@ public class AnnotateMethodFix implements LocalQuickFix { @Override @NotNull public String getFamilyName() { - return getName(); + return InspectionsBundle.message("inspection.annotate.method.quickfix.family.name"); } private void annotateMethod(@NotNull PsiMethod method) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java index 0c8a33278d3c..b263fc278ffe 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocLocalInspectionBase.java @@ -16,6 +16,7 @@ package com.intellij.codeInspection.javaDoc; import com.intellij.ToolExtensionPoints; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInspection.*; import com.intellij.openapi.extensions.ExtensionPoint; import com.intellij.openapi.extensions.Extensions; @@ -168,16 +169,10 @@ public class JavaDocLocalInspectionBase extends BaseJavaBatchLocalInspectionTool boolean required = aPackage != null && JavadocHighlightUtil.isJavaDocRequired(this, aPackage); ProblemHolderImpl holder = new ProblemHolderImpl(manager, isOnTheFly); - if (IGNORE_DEPRECATED) { - if (aPackage != null) { - PsiModifierList modifierList = aPackage.getModifierList(); - if (modifierList != null && modifierList.findAnnotation("java.lang.Deprecated") != null) { - return null; - } - } - if (docComment != null && docComment.findTagByName("deprecated") != null) { - return null; - } + if (IGNORE_DEPRECATED && + (AnnotationUtil.findAnnotation(aPackage, CommonClassNames.JAVA_LANG_DEPRECATED) != null || + docComment != null && docComment.findTagByName("deprecated") != null)) { + return null; } if (docComment == null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspectionBase.java index d32a21279e9d..ecbe13ea09eb 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavaDocReferenceInspectionBase.java @@ -248,7 +248,7 @@ public class JavaDocReferenceInspectionBase extends BaseJavaBatchLocalInspectio @Override @NotNull public String getFamilyName() { - return getName(); + return "Remove tag"; } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavadocHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavadocHighlightUtil.java index 5a6697869b86..3a25e62e4fc4 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavadocHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavadocHighlightUtil.java @@ -15,7 +15,8 @@ */ package com.intellij.codeInspection.javaDoc; -import com.intellij.codeInspection.*; +import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.reference.RefJavaUtil; import com.intellij.lang.ASTNode; import com.intellij.openapi.project.Project; @@ -23,7 +24,9 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.javadoc.PsiDocParamRef; +import com.intellij.psi.impl.source.tree.JavaDocElementType; import com.intellij.psi.javadoc.*; +import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; @@ -39,6 +42,8 @@ import java.util.stream.Stream; public class JavadocHighlightUtil { private static final String[] TAGS_TO_CHECK = {"author", "version", "since"}; private static final Set UNIQUE_TAGS = ContainerUtil.newHashSet("return", "deprecated", "serial", "serialData"); + private static final TokenSet SEE_TAG_REFS = TokenSet.create( + JavaDocElementType.DOC_REFERENCE_HOLDER, JavaDocElementType.DOC_METHOD_OR_FIELD_REF); public interface ProblemHolder { Project project(); @@ -181,7 +186,18 @@ public class JavadocHighlightUtil { } } - checkInlineTags(tag.getDataElements(), holder); + PsiElement[] dataElements = tag.getDataElements(); + + if ("see".equals(tagName)) { + if (dataElements.length == 0 || dataElements.length == 1 && empty(dataElements[0])) { + holder.problem(tag.getNameElement(), InspectionsBundle.message("inspection.javadoc.problem.see.tag.expecting.ref"), null); + } + else if (!SEE_TAG_REFS.contains(dataElements[0].getNode().getElementType())) { + holder.problem(dataElements[0], InspectionsBundle.message("inspection.javadoc.problem.see.tag.expecting.ref"), null); + } + } + + checkInlineTags(dataElements, holder); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java index c1dbdbf78f0e..c00eb42484a9 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/nullable/AnnotateOverriddenMethodParameterFix.java @@ -98,6 +98,6 @@ public class AnnotateOverriddenMethodParameterFix implements LocalQuickFix { @Override @NotNull public String getFamilyName() { - return getName(); + return InspectionsBundle.message("annotate.overridden.methods.parameters.family.name"); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java index 27be172ae58a..accdc0b2b17b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/uncheckedWarnings/UncheckedWarningLocalInspectionBase.java @@ -42,6 +42,7 @@ import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspectionTool { @@ -68,8 +69,8 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe return uncheckedCb; } - public static LocalQuickFix[] getChangeVariableTypeFixes(@NotNull PsiVariable parameter, PsiType itemType) { - if (itemType instanceof PsiMethodReferenceType) return LocalQuickFix.EMPTY_ARRAY; + public static LocalQuickFix[] getChangeVariableTypeFixes(@NotNull PsiVariable parameter, PsiType itemType, LocalQuickFix[] generifyFixes) { + if (itemType instanceof PsiMethodReferenceType) return generifyFixes; final List result = new ArrayList(); LOG.assertTrue(parameter.isValid()); if (itemType != null) { @@ -81,6 +82,10 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe } } } + + if (generifyFixes.length > 0) { + Collections.addAll(result, generifyFixes); + } return result.toArray(new LocalQuickFix[result.size()]); } @@ -283,7 +288,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe if (initializer == null || initializer instanceof PsiArrayInitializerExpression) return; final PsiType initializerType = initializer.getType(); checkRawToGenericsAssignment(initializer, initializer, variable.getType(), initializerType, true, - myOnTheFly ? getChangeVariableTypeFixes(variable, initializerType) : LocalQuickFix.EMPTY_ARRAY); + myOnTheFly ? getChangeVariableTypeFixes(variable, initializerType, myGenerifyFixes) : LocalQuickFix.EMPTY_ARRAY); } @Override @@ -295,7 +300,8 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe final PsiExpression iteratedValue = statement.getIteratedValue(); if (iteratedValue == null) return; final PsiType itemType = JavaGenericsUtil.getCollectionItemType(iteratedValue); - checkRawToGenericsAssignment(parameter, iteratedValue, parameterType, itemType, true, myOnTheFly ? getChangeVariableTypeFixes(parameter, itemType) : LocalQuickFix.EMPTY_ARRAY); + checkRawToGenericsAssignment(parameter, iteratedValue, parameterType, itemType, true, myOnTheFly ? getChangeVariableTypeFixes(parameter, itemType, + myGenerifyFixes) : LocalQuickFix.EMPTY_ARRAY); } @Override @@ -316,7 +322,7 @@ public class UncheckedWarningLocalInspectionBase extends BaseJavaBatchLocalInspe leftVar = (PsiVariable)element; } } - checkRawToGenericsAssignment(rExpr, rExpr, lType, rType, true, myOnTheFly && leftVar != null ? getChangeVariableTypeFixes(leftVar, rType) : LocalQuickFix.EMPTY_ARRAY); + checkRawToGenericsAssignment(rExpr, rExpr, lType, rType, true, myOnTheFly && leftVar != null ? getChangeVariableTypeFixes(leftVar, rType, myGenerifyFixes) : LocalQuickFix.EMPTY_ARRAY); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java index 919c6b447259..aca399d6b20e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java @@ -31,6 +31,8 @@ import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.introduceParameter.AbstractJavaInplaceIntroducer; +import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import org.jetbrains.annotations.NotNull; /** @@ -73,7 +75,9 @@ public class CreateLocalFromUsageFix extends CreateVarFromUsageFix { final PsiFile targetFile = targetClass.getContainingFile(); PsiType[] expectedTypes = CreateFromUsageUtils.guessType(myReferenceExpression, false); - PsiType type = expectedTypes[0]; + final SmartTypePointer defaultType = SmartTypePointerManager.getInstance(project).createSmartTypePointer(expectedTypes[0]); + final PsiType preferredType = TypeSelectorManagerImpl.getPreferredType(expectedTypes, expectedTypes[0]); + PsiType type = preferredType != null ? preferredType : expectedTypes[0]; String varName = myReferenceExpression.getReferenceName(); PsiExpression initializer = null; @@ -116,7 +120,10 @@ public class CreateLocalFromUsageFix extends CreateVarFromUsageFix { var = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(var); if (var == null) return; TemplateBuilderImpl builder = new TemplateBuilderImpl(var); - builder.replaceElement(var.getTypeElement(), expression); + final PsiTypeElement typeElement = var.getTypeElement(); + LOG.assertTrue(typeElement != null); + builder.replaceElement(typeElement, + AbstractJavaInplaceIntroducer.createExpression(expression, typeElement.getText())); builder.setEndVariableAfter(var.getNameIdentifier()); Template template = builder.buildTemplate(); @@ -132,6 +139,8 @@ public class CreateLocalFromUsageFix extends CreateVarFromUsageFix { final int offset = newEditor.getCaretModel().getOffset(); final PsiLocalVariable localVariable = PsiTreeUtil.findElementOfClassAtOffset(targetFile, offset, PsiLocalVariable.class, false); if (localVariable != null) { + TypeSelectorManagerImpl.typeSelected(localVariable.getType(), defaultType.getType()); + ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodParameterFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodParameterFix.java index 3ce3b66b3835..cf7fa5c74550 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodParameterFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodParameterFix.java @@ -115,6 +115,11 @@ public class MethodParameterFix extends LocalQuickFixAndIntentionActionOnPsiElem } } + @Override + public boolean startInWriteAction() { + return false; + } + private ParameterInfoImpl[] getNewParametersInfo(PsiMethod method) throws IncorrectOperationException { List result = new ArrayList(); PsiParameter[] parameters = method.getParameterList().getParameters(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplacePrimitiveWithBoxedTypeAction.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplacePrimitiveWithBoxedTypeAction.java index 95ed0c7cfb02..973a694657b9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplacePrimitiveWithBoxedTypeAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplacePrimitiveWithBoxedTypeAction.java @@ -46,7 +46,7 @@ public class ReplacePrimitiveWithBoxedTypeAction extends LocalQuickFixAndIntenti @NotNull @Override public String getFamilyName() { - return getText(); + return "Convert primitive to boxed type"; } @Override diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java index 302e1faca415..85e0b4560bf4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java @@ -595,10 +595,6 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta css.addRule("p.problem-description-group {text-indent: " + JBUI.scale(12) + "px;font-weight:bold;}"); css.addRule("div.problem-description {margin-left: " + JBUI.scale(10) + "px;}"); css.addRule("ul {margin-left:" + JBUI.scale(10) + "px;text-indent: 0}"); - //TODO Dmitry Batkovich: it's hack to hide tags in JEditorPane (any standard methods (display...) are unsupported in java) - final StringBuilder sb = new StringBuilder(); - UIUtil.appendColor(UIUtil.getLabelBackground(), sb); - css.addRule(".package {color: #" + sb.toString() + ";}"); final StringBuffer buf = new StringBuffer(); getComposer().compose(buf, entity, false); final String text = buf.toString(); diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/HTMLJavaHTMLComposerImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/HTMLJavaHTMLComposerImpl.java index ea448a93c7fc..a8382980e462 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/HTMLJavaHTMLComposerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/HTMLJavaHTMLComposerImpl.java @@ -338,17 +338,20 @@ public class HTMLJavaHTMLComposerImpl extends HTMLJavaHTMLComposer { buf.append(HTMLComposerImpl.CODE_CLOSING); - if (refElement instanceof RefClass && ((RefClass)refElement).isAnonymous()) { - buf.append(" "); - buf.append(InspectionsBundle.message("inspection.export.results.anonymous.ref.in.owner")); - buf.append(" "); - myComposer.appendElementReference(buf, ((RefElement)refElement.getOwner()), isPackageIncluded); - } - else if (isPackageIncluded) { - buf.append(" ").append("").append("("); - myComposer.appendQualifiedName(buf, refElement.getOwner()); -// buf.append(RefUtil.getPackageName(refElement)); - buf.append(")").append(HTMLComposerImpl.CODE_CLOSING); + final RefEntity owner = refElement.getOwner(); + if (owner != null) { + if ((refElement instanceof RefClass && ((RefClass)refElement).isAnonymous())) { + buf.append(" "); + buf.append(InspectionsBundle.message("inspection.export.results.anonymous.ref.in.owner")); + buf.append(" "); + myComposer.appendElementReference(buf, (RefElement) owner, isPackageIncluded); + } + else if (isPackageIncluded) { + buf.append(" ").append("").append("("); + myComposer.appendQualifiedName(buf, owner); + // buf.append(RefUtil.getPackageName(refElement)); + buf.append(")").append(HTMLComposerImpl.CODE_CLOSING); + } } } diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java b/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java index 5ac31e88f656..0a9415f38cc4 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -15,21 +15,17 @@ */ package com.intellij.javadoc; -import com.intellij.openapi.util.DefaultJDOMExternalizer; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.JDOMExternalizable; -import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.PsiKeyword; -import org.jdom.Element; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Field; +import com.intellij.util.xmlb.SerializationFilter; /** * @author Eugene Zhuravlev - * Date: Apr 24, 2004 + * @since Apr 24, 2004 */ -public class JavadocConfiguration implements JDOMExternalizable { +public class JavadocConfiguration { + public static final SerializationFilter FILTER = (accessor, bean) -> + !accessor.getName().equals("OPTION_LINK_TO_JDK_DOCS") || ((JavadocConfiguration)bean).OPTION_LINK_TO_JDK_DOCS; + public String OUTPUT_DIRECTORY; public String OPTION_SCOPE = PsiKeyword.PROTECTED; public boolean OPTION_HIERARCHY = true; @@ -47,21 +43,4 @@ public class JavadocConfiguration implements JDOMExternalizable { public boolean OPEN_IN_BROWSER = true; public boolean OPTION_INCLUDE_LIBS = false; public boolean OPTION_LINK_TO_JDK_DOCS = false; - - public JavadocConfiguration() { - } - - public void readExternal(Element element) throws InvalidDataException { - DefaultJDOMExternalizer.readExternal(this, element); - } - - public void writeExternal(Element element) throws WriteExternalException { - DefaultJDOMExternalizer.writeExternal(this, element, new DefaultJDOMExternalizer.JDOMFilter() { - @Override - public boolean isAccept(@NotNull Field field) { - return !field.getName().equals("OPTION_LINK_TO_JDK_DOCS") || OPTION_LINK_TO_JDK_DOCS; - } - }); - } -} - +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java b/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java index 7dbd51d06036..b94e25ce5399 100644 --- a/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java +++ b/java/java-impl/src/com/intellij/javadoc/JavadocGenerationManager.java @@ -24,17 +24,14 @@ import com.intellij.execution.util.ExecutionErrorDialog; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.components.State; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.WriteExternalException; +import com.intellij.util.xmlb.XmlSerializer; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @State(name = "JavadocGenerationManager") public final class JavadocGenerationManager implements PersistentStateComponent { - private static final Logger LOG = Logger.getInstance("#com.intellij.javadoc.JavadocGenerationManager"); - private final JavadocConfiguration myConfiguration; + private final JavadocConfiguration myConfiguration = new JavadocConfiguration(); private final Project myProject; public static JavadocGenerationManager getInstance(@NotNull Project project) { @@ -43,31 +40,19 @@ public final class JavadocGenerationManager implements PersistentStateComponent< JavadocGenerationManager(Project project) { myProject = project; - myConfiguration = new JavadocConfiguration(); } @Override public Element getState() { - final Element state = new Element("state"); - try { - myConfiguration.writeExternal(state); - } - catch (WriteExternalException e) { - LOG.error(e); - } - return state; + return XmlSerializer.serialize(myConfiguration, JavadocConfiguration.FILTER); } @Override public void loadState(Element state) { - try { - myConfiguration.readExternal(state); - } - catch (InvalidDataException e) { - LOG.error(e); - } + XmlSerializer.deserializeInto(myConfiguration, state); } + @NotNull public JavadocConfiguration getConfiguration() { return myConfiguration; } @@ -81,4 +66,4 @@ public final class JavadocGenerationManager implements PersistentStateComponent< ExecutionErrorDialog.show(e, CommonBundle.getErrorTitle(), myProject); } } -} +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java index c1a707718308..6e7cdac9a820 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/AbstractJavaInplaceIntroducer.java @@ -2,6 +2,7 @@ package com.intellij.refactoring.introduceParameter; import com.intellij.codeInsight.intention.impl.TypeExpression; import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; import com.intellij.codeInsight.template.Expression; import com.intellij.codeInsight.template.ExpressionContext; import com.intellij.codeInsight.template.Result; @@ -200,7 +201,23 @@ public abstract class AbstractJavaInplaceIntroducer extends AbstractInplaceIntro @Override public LookupElement[] calculateLookupItems(ExpressionContext context) { - return expression.calculateLookupItems(context); + final LookupElement[] elements = expression.calculateLookupItems(context); + if (elements != null) { + LookupElement toBeSelected = null; + for (LookupElement element : elements) { + if (element instanceof PsiTypeLookupItem && ((PsiTypeLookupItem)element).getType().getPresentableText().equals(defaultType)) { + toBeSelected = element; + break; + } + } + if (toBeSelected != null) { + final int idx = ArrayUtil.find(elements, toBeSelected); + if (idx > 0) { + return ArrayUtil.prepend(toBeSelected, ArrayUtil.remove(elements, idx)); + } + } + } + return elements; } @Override diff --git a/java/java-impl/src/com/intellij/refactoring/typeCook/Util.java b/java/java-impl/src/com/intellij/refactoring/typeCook/Util.java index 54149613704b..09370d3afe5a 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeCook/Util.java +++ b/java/java-impl/src/com/intellij/refactoring/typeCook/Util.java @@ -17,6 +17,7 @@ package com.intellij.refactoring.typeCook; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; +import com.intellij.psi.impl.PsiDiamondTypeUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.typeCook.deductive.PsiTypeVariableFactory; @@ -405,6 +406,10 @@ public class Util { list .add(factory.createTypeElement(aType == null ? PsiType.getJavaLangObject(list.getManager(), list.getResolveScope()) : aType)); } + + if (PsiDiamondTypeUtil.canCollapseToDiamond(newx, newx, newx.getType())) { + PsiDiamondTypeUtil.replaceExplicitWithDiamond(list); + } } } else { diff --git a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java index b308a4cdf929..308ee4b175fb 100644 --- a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java @@ -312,18 +312,25 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { private void setTypesAndPreselect(PsiType[] types) { myTypeSelector.setTypes(types); + final PsiType preferredType = getPreferredType(types, getDefaultType()); + if (preferredType != null) { + myTypeSelector.selectType(preferredType); + } + } + + public static PsiType getPreferredType(PsiType[] types, PsiType defaultType) { Map map = new THashMap(); for (final PsiType type : types) { map.put(serialize(type), type); } - for (StatisticsInfo info : StatisticsManager.getInstance().getAllValues(getStatsKey())) { + for (StatisticsInfo info : StatisticsManager.getInstance().getAllValues(getStatsKey(defaultType))) { final PsiType candidate = map.get(info.getValue()); if (candidate != null && StatisticsManager.getInstance().getUseCount(info) > 0) { - myTypeSelector.selectType(candidate); - return; + return candidate; } } + return null; } @Override @@ -353,15 +360,10 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { StatisticsManager.getInstance().incUseCount(new StatisticsInfo(getStatsKey(defaultType), serialize(type))); } - private String getStatsKey() { - final PsiType defaultType = getDefaultType(); + private static String getStatsKey(final PsiType defaultType) { if (defaultType == null) { return "IntroduceVariable##"; } - return getStatsKey(defaultType); - } - - private static String getStatsKey(final PsiType defaultType) { return "IntroduceVariable##" + serialize(defaultType); } diff --git a/java/java-indexing-api/src/com/intellij/psi/search/searches/DirectClassInheritorsSearch.java b/java/java-indexing-api/src/com/intellij/psi/search/searches/DirectClassInheritorsSearch.java index 8db0cf827e9b..6cbf5bbe4bed 100644 --- a/java/java-indexing-api/src/com/intellij/psi/search/searches/DirectClassInheritorsSearch.java +++ b/java/java-indexing-api/src/com/intellij/psi/search/searches/DirectClassInheritorsSearch.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -16,7 +16,6 @@ package com.intellij.psi.search.searches; import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiAnonymousClass; import com.intellij.psi.PsiClass; import com.intellij.psi.search.GlobalSearchScope; @@ -25,6 +24,7 @@ import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.FilteredQuery; import com.intellij.util.Query; import com.intellij.util.QueryExecutor; +import org.jetbrains.annotations.NotNull; /** * @author max @@ -34,30 +34,32 @@ public class DirectClassInheritorsSearch extends ExtensibleQueryFactory raw = INSTANCE.createUniqueResultsQuery(new SearchParameters(aClass, scope, includeAnonymous, checkInheritance)); if (!includeAnonymous) { - return new FilteredQuery(raw, new Condition() { - @Override - public boolean value(final PsiClass psiClass) { - return !(psiClass instanceof PsiAnonymousClass); - } - }); + return new FilteredQuery<>(raw, psiClass -> !(psiClass instanceof PsiAnonymousClass)); } return raw; diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java index a0ea9b3fd68f..2c3505df7246 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -37,6 +37,7 @@ import com.intellij.util.QueryExecutor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -51,87 +52,46 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor consumer) { final PsiClass aClass = p.getClassToProcess(); - final SearchScope useScope = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public SearchScope compute() { - return aClass.getUseScope(); - } - }); + final SearchScope useScope = ApplicationManager.getApplication().runReadAction((Computable)aClass::getUseScope); - final String qualifiedName = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return aClass.getQualifiedName(); - } - }); + final String qualifiedName = ApplicationManager.getApplication().runReadAction((Computable)aClass::getQualifiedName); final Project project = PsiUtilCore.getProjectInReadAction(aClass); if (CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName)) { - //[pasynkov]: WTF? - //final SearchScope scope = useScope.intersectWith(GlobalSearchScope.notScope(GlobalSearchScope.getScopeRestrictedByFileTypes( - // GlobalSearchScope.allScope(psiManager.getProject()), StdFileTypes.JSP, StdFileTypes.JSPX))); - - return AllClassesSearch.search(useScope, project).forEach(new Processor() { - @Override - public boolean process(final PsiClass psiClass) { - ProgressManager.checkCanceled(); - if (psiClass.isInterface()) { - return consumer.process(psiClass); - } - final PsiClass superClass = psiClass.getSuperClass(); - if (superClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(ApplicationManager.getApplication().runReadAction(new Computable() { - public String compute() { - return superClass.getQualifiedName(); - } - }))) { - return consumer.process(psiClass); - } - return true; + return AllClassesSearch.search(useScope, project).forEach(psiClass -> { + ProgressManager.checkCanceled(); + if (psiClass.isInterface()) { + return consumer.process(psiClass); } + final PsiClass superClass = psiClass.getSuperClass(); + if (superClass != null && + CommonClassNames.JAVA_LANG_OBJECT.equals(ApplicationManager.getApplication().runReadAction((Computable)superClass::getQualifiedName))) { + return consumer.process(psiClass); + } + return true; }); } final GlobalSearchScope scope = useScope instanceof GlobalSearchScope ? (GlobalSearchScope)useScope : new EverythingGlobalScope(project); - final String searchKey = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return aClass.getName(); - } - }); + final String searchKey = ApplicationManager.getApplication().runReadAction((Computable)aClass::getName); if (StringUtil.isEmpty(searchKey)) { return true; } - Collection candidates = MethodUsagesSearcher.resolveInReadAction(project, - new Computable>() { - @Override - public Collection compute() { - return JavaSuperClassNameOccurenceIndex - .getInstance().get(searchKey, project, scope); - } - }); + Collection candidates = + MethodUsagesSearcher.resolveInReadAction(project, () -> JavaSuperClassNameOccurenceIndex.getInstance().get(searchKey, project, scope)); - Map> classes = new HashMap>(); + Map> classes = new HashMap<>(); for (final PsiReferenceList referenceList : candidates) { ProgressManager.checkCanceled(); - final PsiClass candidate = (PsiClass)ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiElement compute() { - return referenceList.getParent(); - } - }); + final PsiClass candidate = (PsiClass)ApplicationManager.getApplication().runReadAction((Computable)referenceList::getParent); if (!checkInheritance(p, aClass, candidate, project)) continue; - String fqn = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return candidate.getQualifiedName(); - } - }); + String fqn = ApplicationManager.getApplication().runReadAction((Computable)candidate::getQualifiedName); List list = classes.get(fqn); if (list == null) { - list = new ArrayList(); + list = new ArrayList<>(); classes.put(fqn, list); } list.add(candidate); @@ -141,20 +101,13 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor sameNamedClasses : classes.values()) { ProgressManager.checkCanceled(); - if (!processSameNamedClasses(consumer, sameNamedClasses, jarFile)) return false; + if (!processSameNamedClasses(sameNamedClasses, jarFile, consumer)) return false; } } if (p.includeAnonymous()) { - Collection anonymousCandidates = MethodUsagesSearcher.resolveInReadAction(project, - new Computable>() { - @Override - public Collection compute() { - return JavaAnonymousClassBaseRefOccurenceIndex - .getInstance() - .get(searchKey, project, scope); - } - }); + Collection anonymousCandidates = + MethodUsagesSearcher.resolveInReadAction(project, () -> JavaAnonymousClassBaseRefOccurenceIndex.getInstance().get(searchKey, project, scope)); for (PsiAnonymousClass candidate : anonymousCandidates) { ProgressManager.checkCanceled(); @@ -163,30 +116,15 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor() { - @Override - public Boolean compute() { - return aClass.isEnum(); - } - }); + boolean isEnum = ApplicationManager.getApplication().runReadAction((Computable)aClass::isEnum); if (isEnum) { // abstract enum can be subclassed in the body - PsiField[] fields = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiField[] compute() { - return aClass.getFields(); - } - }); + PsiField[] fields = ApplicationManager.getApplication().runReadAction((Computable)aClass::getFields); for (final PsiField field : fields) { ProgressManager.checkCanceled(); if (field instanceof PsiEnumConstant) { PsiEnumConstantInitializer initializingClass = - ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiEnumConstantInitializer compute() { - return ((PsiEnumConstant)field).getInitializingClass(); - } - }); + ApplicationManager.getApplication().runReadAction((Computable)((PsiEnumConstant)field)::getInitializingClass); if (initializingClass != null) { if (!consumer.process(initializingClass)) return false; } @@ -198,16 +136,16 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor() { - @Override - public Boolean compute() { - return !p.isCheckInheritance() || candidate.isInheritor(aClass, false); - } - }); + private static boolean checkInheritance(@NotNull DirectClassInheritorsSearch.SearchParameters p, + @NotNull PsiClass aClass, + @NotNull PsiClass candidate, + @NotNull Project project) { + return MethodUsagesSearcher.resolveInReadAction(project, () -> !p.isCheckInheritance() || candidate.isInheritor(aClass, false)); } - private static boolean processSameNamedClasses(Processor consumer, List sameNamedClasses, final VirtualFile jarFile) { + private static boolean processSameNamedClasses(@NotNull List sameNamedClasses, + @Nullable VirtualFile jarFile, + @NotNull Processor consumer) { // if there is a class from the same jar, prefer it boolean sameJarClassFound = false; @@ -225,12 +163,7 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor() { - @Override - public VirtualFile compute() { - return PsiUtil.getJarFile(aClass); - } - }); + private static VirtualFile getJarFile(@NotNull PsiClass aClass) { + return ApplicationManager.getApplication().runReadAction((Computable)() -> PsiUtil.getJarFile(aClass)); } } diff --git a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java index 4dad59cfb946..f63fcb976dd2 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/AnnotationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -16,7 +16,6 @@ package com.intellij.codeInsight; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.*; import com.intellij.util.ArrayUtil; @@ -87,9 +86,9 @@ public class AnnotationUtil { } @Nullable - public static PsiAnnotation findAnnotation(@Nullable PsiModifierListOwner listOwner, final boolean skipExternal, @NotNull String... annotationNames) { + public static PsiAnnotation findAnnotation(@Nullable PsiModifierListOwner listOwner, boolean skipExternal, @NotNull String... annotationNames) { if (annotationNames.length == 0) return null; - Set set = annotationNames.length == 1 ? Collections.singleton(annotationNames[0]) : new HashSet(Arrays.asList(annotationNames)); + Set set = annotationNames.length == 1 ? Collections.singleton(annotationNames[0]) : ContainerUtil.newHashSet(annotationNames); return findAnnotation(listOwner, set, skipExternal); } @@ -104,8 +103,7 @@ public class AnnotationUtil { } @Nullable - public static PsiAnnotation findAnnotation(@Nullable PsiModifierListOwner listOwner, @NotNull Collection annotationNames, - final boolean skipExternal) { + public static PsiAnnotation findAnnotation(@Nullable PsiModifierListOwner listOwner, @NotNull Collection annotationNames, boolean skipExternal) { if (listOwner == null) return null; PsiAnnotation annotation = findOwnAnnotation(listOwner, annotationNames); diff --git a/java/java-psi-api/src/com/intellij/psi/javadoc/JavadocTagInfo.java b/java/java-psi-api/src/com/intellij/psi/javadoc/JavadocTagInfo.java index d79132857438..fdbee5a2d5c4 100644 --- a/java/java-psi-api/src/com/intellij/psi/javadoc/JavadocTagInfo.java +++ b/java/java-psi-api/src/com/intellij/psi/javadoc/JavadocTagInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ package com.intellij.psi.javadoc; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; /** @@ -27,13 +26,12 @@ import org.jetbrains.annotations.Nullable; public interface JavadocTagInfo { ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.javadocTagInfo"); - @NonNls String getName(); + String getName(); + boolean isInline(); boolean isValidInContext(PsiElement element); - Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix); - /** * Checks the tag value for correctness. * @@ -45,4 +43,4 @@ public interface JavadocTagInfo { @Nullable PsiReference getReference(PsiDocTagValue value); -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ExceptionTagInfo.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ExceptionTagInfo.java index 06e68c41dabe..8901416ebf1f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ExceptionTagInfo.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ExceptionTagInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -20,7 +20,6 @@ import com.intellij.psi.*; import com.intellij.psi.javadoc.JavadocTagInfo; import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; /** @@ -33,6 +32,22 @@ class ExceptionTagInfo implements JavadocTagInfo { myName = name; } + @Override + public String getName() { + return myName; + } + + @Override + public boolean isInline() { + return false; + } + + @Override + public boolean isValidInContext(PsiElement element) { + if (!(element instanceof PsiMethod)) return false; + return true; + } + @Override public String checkTagValue(PsiDocTagValue value) { if (value == null) return JavaErrorMessages.message("javadoc.exception.tag.exception.class.expected"); @@ -89,29 +104,8 @@ class ExceptionTagInfo implements JavadocTagInfo { return JavaErrorMessages.message("javadoc.exception.tag.exception.is.not.thrown", exceptionClass.getName(), method.getName()); } - @Override - public String getName() { - return myName; - } - - @Override - public Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix) { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - @Override public PsiReference getReference(PsiDocTagValue value) { return null; } - - @Override - public boolean isValidInContext(PsiElement element) { - if (!(element instanceof PsiMethod)) return false; - return true; - } - - @Override - public boolean isInline() { - return false; - } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java index 1fd12fd8d55a..ea0d03a9b4e6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -68,16 +68,12 @@ public class JavadocManagerImpl implements JavadocManager { myInfos.add(new ValueDocTagInfo()); Collections.addAll(myInfos, Extensions.getExtensions(JavadocTagInfo.EP_NAME, project)); + for (CustomJavadocTagProvider extension : Extensions.getExtensions(CustomJavadocTagProvider.EP_NAME)) { myInfos.addAll(extension.getSupportedTags()); } } - @Deprecated - public void registerTagInfo(@NotNull JavadocTagInfo info) { - myInfos.add(info); - } - @Override @NotNull public JavadocTagInfo[] getTagInfos(PsiElement context) { @@ -96,9 +92,11 @@ public class JavadocManagerImpl implements JavadocManager { @Nullable public JavadocTagInfo getTagInfo(String name) { for (JavadocTagInfo info : myInfos) { - if (info.getName().equals(name)) return info; + if (info.getName().equals(name)) { + return info; + } } return null; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ParamDocTagInfo.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ParamDocTagInfo.java index ca4d827653bc..af91d31fb6f3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ParamDocTagInfo.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ParamDocTagInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,12 +21,6 @@ import com.intellij.psi.*; import com.intellij.psi.javadoc.JavadocTagInfo; import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.ContainerUtil; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; /** * @author mike @@ -38,25 +32,14 @@ class ParamDocTagInfo implements JavadocTagInfo { } @Override - public boolean isValidInContext(PsiElement element) { - return element instanceof PsiMethod || - (element instanceof PsiClass && PsiUtil.isLanguageLevel5OrHigher(element)); + public boolean isInline() { + return false; } @Override - public Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix) { - if (context instanceof PsiTypeParameterListOwner) { - List result = new ArrayList(Arrays.asList(((PsiTypeParameterListOwner)context).getTypeParameters())); - - if (context instanceof PsiMethod) { - PsiMethod method = (PsiMethod)context; - ContainerUtil.addAll(result, method.getParameterList().getParameters()); - } - - return result.toArray(new PsiNamedElement[result.size()]); - } - - return ArrayUtil.EMPTY_OBJECT_ARRAY; + public boolean isValidInContext(PsiElement element) { + return element instanceof PsiMethod || + (element instanceof PsiClass && PsiUtil.isLanguageLevel5OrHigher(element)); } @Override @@ -81,10 +64,4 @@ class ParamDocTagInfo implements JavadocTagInfo { if (value instanceof PsiDocParamRef) return value.getReference(); return null; } - - - @Override - public boolean isInline() { - return false; - } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ReturnDocTagInfo.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ReturnDocTagInfo.java index 6e9de7361c5c..7680cc2dad7c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ReturnDocTagInfo.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ReturnDocTagInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,30 +21,19 @@ import com.intellij.psi.PsiReference; import com.intellij.psi.PsiType; import com.intellij.psi.javadoc.JavadocTagInfo; import com.intellij.psi.javadoc.PsiDocTagValue; -import com.intellij.util.ArrayUtil; /** * @author mike */ class ReturnDocTagInfo implements JavadocTagInfo { - @Override - public String checkTagValue(PsiDocTagValue value) { - return null; - } - @Override public String getName() { return "return"; } @Override - public Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix) { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - - @Override - public PsiReference getReference(PsiDocTagValue value) { - return null; + public boolean isInline() { + return false; } @Override @@ -57,7 +46,12 @@ class ReturnDocTagInfo implements JavadocTagInfo { } @Override - public boolean isInline() { - return false; + public String checkTagValue(PsiDocTagValue value) { + return null; } -} + + @Override + public PsiReference getReference(PsiDocTagValue value) { + return null; + } +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SeeDocTagInfo.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SeeDocTagInfo.java index 5356938959e1..83bc31dc1959 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SeeDocTagInfo.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SeeDocTagInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -16,123 +16,53 @@ package com.intellij.psi.impl.source.javadoc; import com.intellij.pom.java.LanguageLevel; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.tree.JavaElementType; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.impl.source.SourceTreeToPsiMap; -import com.intellij.psi.impl.source.tree.ElementType; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; import com.intellij.psi.javadoc.JavadocTagInfo; import com.intellij.psi.javadoc.PsiDocTagValue; -import com.intellij.psi.javadoc.PsiDocToken; -import com.intellij.psi.tree.IElementType; -import com.intellij.util.ArrayUtil; -import org.jetbrains.annotations.NonNls; - -import java.util.ArrayList; -import java.util.List; +import com.intellij.psi.util.PsiUtil; /** * @author mike */ class SeeDocTagInfo implements JavadocTagInfo { + private static final String LINKPLAIN_TAG = "linkplain"; + private final String myName; private final boolean myInline; - @NonNls private static final String LINKPLAIN_TAG = "linkplain"; - public SeeDocTagInfo(@NonNls String name, boolean isInline) { + public SeeDocTagInfo(String name, boolean isInline) { myName = name; myInline = isInline; } - @Override - public String checkTagValue(PsiDocTagValue value) { - return null; - } - @Override public String getName() { return myName; } @Override - public Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix) { - if (place instanceof PsiDocToken) { - PsiDocToken token = (PsiDocToken) place; - if (token.getTokenType() == JavaDocTokenType.DOC_TAG_VALUE_SHARP_TOKEN) { - return getPossibleMethodsAndFields(context, place, prefix); - } else if (token.getTokenType() == JavaDocTokenType.DOC_TAG_VALUE_LPAREN) { - if (token.getPrevSibling() == null) return ArrayUtil.EMPTY_OBJECT_ARRAY; - final String methodName = token.getPrevSibling().getText(); - - PsiElement targetContext = getTargetContext(context, place); - - List result = new ArrayList(); - final PsiMethod[] methods = PsiDocMethodOrFieldRef.getAllMethods(targetContext, place); - for (final PsiMethod method : methods) { - if (method.getName().equals(methodName)) { - result.add(method); - } - } - return ArrayUtil.toObjectArray(result); - } else if (token.getTokenType() == JavaDocTokenType.DOC_TAG_VALUE_TOKEN && place.getParent() instanceof PsiDocMethodOrFieldRef) { - return getPossibleMethodsAndFields(context, place, prefix); - } - } - - return ArrayUtil.EMPTY_OBJECT_ARRAY; + public boolean isInline() { + return myInline; } - private Object[] getPossibleMethodsAndFields(PsiElement context, PsiElement place, String prefix) { - List result = new ArrayList(); - - PsiElement targetContext = getTargetContext(context, place); - - final PsiMethod[] methods = PsiDocMethodOrFieldRef.getAllMethods(targetContext, place); - for (PsiMethod method : methods) { - result.add(method); - } - - final PsiVariable[] variables = PsiDocMethodOrFieldRef.getAllVariables(targetContext, place); - for (PsiVariable variable : variables) { - result.add(variable); - } - - return ArrayUtil.toObjectArray(result); - } - - private PsiElement getTargetContext(PsiElement context, PsiElement place) { - PsiElement targetContext = context; - - if (place.getParent() instanceof PsiDocMethodOrFieldRef) { - PsiDocMethodOrFieldRef methodRef = (PsiDocMethodOrFieldRef) place.getParent(); - - final IElementType firstChildType = methodRef.getFirstChildNode().getElementType(); - if (firstChildType == JavaElementType.JAVA_CODE_REFERENCE || firstChildType == JavaElementType.REFERENCE_EXPRESSION) { - PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement) SourceTreeToPsiMap.treeElementToPsi(methodRef.getFirstChildNode()); - final PsiElement element = referenceElement.resolve(); - if (element instanceof PsiClass) { - targetContext = element.getFirstChild(); - } - } - } - return targetContext; - } @Override public boolean isValidInContext(PsiElement element) { - if (myInline && myName.equals(LINKPLAIN_TAG) && element != null) + if (myInline && myName.equals(LINKPLAIN_TAG) && element != null) { return PsiUtil.getLanguageLevel(element).compareTo(LanguageLevel.JDK_1_4) >= 0; + } return true; } + @Override + public String checkTagValue(PsiDocTagValue value) { + return null; + } + @Override public PsiReference getReference(PsiDocTagValue value) { return null; } - - @Override - public boolean isInline() { - return myInline; - } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SerialDocTagInfo.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SerialDocTagInfo.java index 7f5a68f0e8c8..5eb7838ec28c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SerialDocTagInfo.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SerialDocTagInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,7 +21,6 @@ import com.intellij.psi.PsiField; import com.intellij.psi.PsiReference; import com.intellij.psi.javadoc.JavadocTagInfo; import com.intellij.psi.javadoc.PsiDocTagValue; -import com.intellij.util.ArrayUtil; public class SerialDocTagInfo implements JavadocTagInfo { @Override @@ -39,11 +38,6 @@ public class SerialDocTagInfo implements JavadocTagInfo { return element instanceof PsiClass || element instanceof PsiField; } - @Override - public Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix) { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - @Override public String checkTagValue(PsiDocTagValue value) { return null; @@ -53,4 +47,4 @@ public class SerialDocTagInfo implements JavadocTagInfo { public PsiReference getReference(PsiDocTagValue value) { return null; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SimpleDocTagInfo.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SimpleDocTagInfo.java index ddb6187a6420..78eb239b42c8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SimpleDocTagInfo.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/SimpleDocTagInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,9 @@ package com.intellij.psi.impl.source.javadoc; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; -import com.intellij.psi.util.PsiUtil; import com.intellij.psi.javadoc.JavadocTagInfo; import com.intellij.psi.javadoc.PsiDocTagValue; -import com.intellij.util.ArrayUtil; +import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NonNls; /** @@ -55,6 +54,11 @@ class SimpleDocTagInfo implements JavadocTagInfo { return myName; } + @Override + public boolean isInline() { + return myInline; + } + @Override public boolean isValidInContext(PsiElement element) { if (element != null && PsiUtil.getLanguageLevel(element).compareTo(myLanguageLevel) < 0) { @@ -64,11 +68,6 @@ class SimpleDocTagInfo implements JavadocTagInfo { return myContext.isInstance(element) || (myAdditionalContext != null && myAdditionalContext.isInstance(element)); } - @Override - public Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix) { - return ArrayUtil.EMPTY_OBJECT_ARRAY; - } - @Override public String checkTagValue(PsiDocTagValue value) { return null; @@ -78,9 +77,4 @@ class SimpleDocTagInfo implements JavadocTagInfo { public PsiReference getReference(PsiDocTagValue value) { return null; } - - @Override - public boolean isInline() { - return myInline; - } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ValueDocTagInfo.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ValueDocTagInfo.java index 81838d615fa5..dcfca2b52970 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ValueDocTagInfo.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/ValueDocTagInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -44,11 +44,6 @@ public class ValueDocTagInfo implements JavadocTagInfo { return true; } - @Override - public Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix) { - return null; - } - @Override public String checkTagValue(PsiDocTagValue value) { boolean hasReference = (value != null && value.getFirstChild() != null); @@ -85,4 +80,4 @@ public class ValueDocTagInfo implements JavadocTagInfo { public PsiReference getReference(PsiDocTagValue value) { return null; } -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index cae20db0f0c5..555ebb946ef1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -41,8 +41,11 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm @Override public boolean reduce(InferenceSession session, List constraints) { if (!PsiPolyExpressionUtil.isPolyExpression(myExpression)) { + + PsiType exprType = myExpression.getType(); + if (session.isProperType(myT)) { - final boolean assignmentCompatible = TypeConversionUtil.areTypesAssignmentCompatible(myT, myExpression); + final boolean assignmentCompatible = exprType == null || TypeConversionUtil.isAssignable(myT, exprType); if (!assignmentCompatible) { final PsiType type = myExpression.getType(); session.registerIncompatibleErrorMessage((type != null ? type.getPresentableText() : myExpression.getText()) + " is not compatible with " + session.getPresentableText(myT)); @@ -50,8 +53,6 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm return assignmentCompatible; } - PsiType exprType = myExpression.getType(); - if (exprType instanceof PsiLambdaParameterType) { return false; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java index 125b06a7d076..adecfa3687e4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java @@ -214,7 +214,7 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi PsiParameter parameter = lambdaParameters[lambdaParamIdx]; final PsiTypeElement typeElement = parameter.getTypeElement(); if (typeElement != null) { - final PsiType lambdaFormalType = toArray(typeElement.getType()); + final PsiType lambdaFormalType = toArray(parameter.getType()); final PsiType methodParameterType = toArray(parameterTypes[lambdaParamIdx]); if (!lambdaFormalType.equals(methodParameterType)) { return false; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/LooseInvocationContextForProperPrimitiveTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/LooseInvocationContextForProperPrimitiveTypes.java new file mode 100644 index 000000000000..5c9d04006208 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/LooseInvocationContextForProperPrimitiveTypes.java @@ -0,0 +1,8 @@ +class Test { + + { + pair(2); + } + + static void pair( byte b) {} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/LinkToItself.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/LinkToItself.java new file mode 100644 index 000000000000..29c7e846dd3d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/LinkToItself.java @@ -0,0 +1,6 @@ +class Foo { + /** + * {@link #foo()} + */ + void foo(){} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See2.java index 7b842427978c..8531d3734c1b 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See2.java @@ -1,6 +1,6 @@ class Test { /** - * @see A# + * @see A# */ public void i() {} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See6.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See6.java deleted file mode 100644 index 91b8c48404ab..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See6.java +++ /dev/null @@ -1,6 +0,0 @@ -class Foo { - /** - * {@link #foo()} - */ - void foo(){} -} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeNonRefs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeNonRefs.java new file mode 100644 index 000000000000..2a128c97508d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeNonRefs.java @@ -0,0 +1,10 @@ +/** + * @see + * @see {@link C} clarification + * + * @see C a correct one + * @see C#f + */ +class C { + int f; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CLikeArrayDeclarationInLambdaWithExplicitTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CLikeArrayDeclarationInLambdaWithExplicitTypes.java new file mode 100644 index 000000000000..cfdefea43c04 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/CLikeArrayDeclarationInLambdaWithExplicitTypes.java @@ -0,0 +1,10 @@ + +interface X { + void foo(int[] x); +} + +class C { + static void main(String[] args){ + X a = (int x[]) -> { }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA152659.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA152659.java new file mode 100644 index 000000000000..757d8dfec160 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA152659.java @@ -0,0 +1,28 @@ +import java.util.*; + +class X, B extends Comparable> { + + class Pair implements Comparable { + A a; + B b; + + + public A getA() { + return a; + } + + + public B getB() { + return b; + } + + + @Override + public int compareTo(Pair other) { + Comparator comparator = Comparator.comparing(Pair::getA).thenComparing(Pair::getB); + + return comparator.compare(this, other); + } + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generifyFile/before2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generifyFile/before2.java new file mode 100644 index 000000000000..e821781e448e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/generifyFile/before2.java @@ -0,0 +1,7 @@ +// "Try to generify 'before2.java'" "true" +import java.util.ArrayList; +class Use { + void f() { + ArrayList s = new ArrayList(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/typeCook/convertToDiamond/after/Test.1.items b/java/java-tests/testData/refactoring/typeCook/convertToDiamond/after/Test.1.items new file mode 100644 index 000000000000..3b9e27f05d2c --- /dev/null +++ b/java/java-tests/testData/refactoring/typeCook/convertToDiamond/after/Test.1.items @@ -0,0 +1 @@ +java.util.ArrayList\nnew diff --git a/java/java-tests/testData/refactoring/typeCook/convertToDiamond/after/Test.items b/java/java-tests/testData/refactoring/typeCook/convertToDiamond/after/Test.items new file mode 100644 index 000000000000..f994691fb0c5 --- /dev/null +++ b/java/java-tests/testData/refactoring/typeCook/convertToDiamond/after/Test.items @@ -0,0 +1 @@ +java.util.ArrayList\nnew diff --git a/java/java-tests/testData/refactoring/typeCook/convertToDiamond/after/test.java b/java/java-tests/testData/refactoring/typeCook/convertToDiamond/after/test.java new file mode 100644 index 000000000000..e61c977ebe95 --- /dev/null +++ b/java/java-tests/testData/refactoring/typeCook/convertToDiamond/after/test.java @@ -0,0 +1,6 @@ +import java.util.ArrayList; + +class Test +{ + ArrayList l = new ArrayList(); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/typeCook/convertToDiamond/before/test.java b/java/java-tests/testData/refactoring/typeCook/convertToDiamond/before/test.java new file mode 100644 index 000000000000..e61c977ebe95 --- /dev/null +++ b/java/java-tests/testData/refactoring/typeCook/convertToDiamond/before/test.java @@ -0,0 +1,6 @@ +import java.util.ArrayList; + +class Test +{ + ArrayList l = new ArrayList(); +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java index 83b328b41e92..b9790fc35c6e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java @@ -65,8 +65,9 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { public void testSee3() { doTest(); } public void testSee4() { doTest(); } public void testSee5() { doTest(); } - public void testSee6() { doTest(); } + public void testLinkToItself() { doTest(); } public void testSeeConstants() { doTest(); } + public void testSeeNonRefs() { doTest(); } public void testReturn0() { doTest(); } public void testException0() { doTest(); } public void testException1() { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java index 40904c0b5c97..504f48ee0470 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java @@ -978,4 +978,8 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase { public void testIDEA152179() throws Exception { doTest(); } + + public void testLooseInvocationContextForProperPrimitiveTypes() throws Exception { + doTest(); + } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java index 7e3595fdbd83..dff25973cdc5 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java @@ -276,6 +276,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testCLikeArrayDeclarationInLambdaWithExplicitTypes() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java index 91d9cf2104ea..2451d8280718 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java @@ -498,6 +498,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(); } + public void testIDEA152659() throws Exception { + doTest(); + } + private void doTest() { doTest(false); } diff --git a/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java b/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java index 861c5ef62b1d..78ac7052b2a4 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/TypeCookTest.java @@ -17,9 +17,11 @@ package com.intellij.refactoring; import com.intellij.JavaTestUtil; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.PsiClass; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.typeCook.Settings; @@ -667,6 +669,18 @@ public class TypeCookTest extends MultiFileTestCase { start(); } + public void testConvertToDiamond() throws Exception { + final LanguageLevelProjectExtension levelProjectExtension = LanguageLevelProjectExtension.getInstance(getProject()); + final LanguageLevel oldLevel = levelProjectExtension.getLanguageLevel(); + try { + levelProjectExtension.setLanguageLevel(LanguageLevel.JDK_1_8); + start(); + } + finally { + levelProjectExtension.setLanguageLevel(oldLevel); + } + } + public void start() throws Exception { start(false); } diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertAtomicToLongAdderIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertAtomicToLongAdderIntention.java index 5b30001450ad..c51e0be4c483 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertAtomicToLongAdderIntention.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ConvertAtomicToLongAdderIntention.java @@ -77,7 +77,7 @@ public class ConvertAtomicToLongAdderIntention extends PsiElementBaseIntentionAc @Override public boolean startInWriteAction() { - return true; + return false; } @NotNull diff --git a/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionAction.java b/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionAction.java index 8c2a8c5c51e2..ba47b7f5e045 100644 --- a/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionAction.java +++ b/platform/analysis-api/src/com/intellij/codeInsight/intention/IntentionAction.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.intention; import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.WriteActionAware; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Iconable; @@ -39,7 +40,7 @@ import org.jetbrains.annotations.NotNull; * * @see IntentionManager#registerIntentionAndMetaData(IntentionAction, String...) */ -public interface IntentionAction { +public interface IntentionAction extends WriteActionAware { IntentionAction[] EMPTY_ARRAY = new IntentionAction[0]; /** * Returns text to be shown in the list of available actions, if this action diff --git a/platform/analysis-api/src/com/intellij/codeInspection/QuickFix.java b/platform/analysis-api/src/com/intellij/codeInspection/QuickFix.java index ae6b97a0421e..e585d3bc49b1 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/QuickFix.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/QuickFix.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInspection; +import com.intellij.openapi.application.WriteActionAware; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -26,7 +27,7 @@ import org.jetbrains.annotations.NotNull; * @since 6.0 * @see CommonProblemDescriptor#getFixes() */ -public interface QuickFix { +public interface QuickFix extends WriteActionAware { QuickFix[] EMPTY_ARRAY = new QuickFix[0]; /** diff --git a/platform/analysis-api/src/com/intellij/openapi/application/WriteActionAware.java b/platform/analysis-api/src/com/intellij/openapi/application/WriteActionAware.java new file mode 100644 index 000000000000..ed7cb85d8533 --- /dev/null +++ b/platform/analysis-api/src/com/intellij/openapi/application/WriteActionAware.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2016 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.application; + +public interface WriteActionAware { + /** + * Indicate whether this action should be invoked inside write action. + * Should return false if e.g. modal dialog is shown inside the action. + * If false is returned the action itself is responsible for starting write action + * when needed, by calling {@link Application#runWriteAction(Runnable)}. + * + * @return true if the action requires a write action, false otherwise. + */ + default boolean startInWriteAction() { + return true; + } +} diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java index 251226105993..774ee7101b93 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java @@ -92,8 +92,7 @@ public class QuickFixWrapper implements IntentionAction { @Override public boolean startInWriteAction() { - final LocalQuickFix fix = getFix(); - return !(fix instanceof IntentionAction) || ((IntentionAction)fix).startInWriteAction(); + return getFix().startInWriteAction(); } public LocalQuickFix getFix() { diff --git a/platform/boot/boot.iml b/platform/boot/boot.iml index b96e3da1edc5..9a0e7ff45829 100644 --- a/platform/boot/boot.iml +++ b/platform/boot/boot.iml @@ -1,12 +1,12 @@ - + - + diff --git a/platform/boot/src/com/intellij/concurrency/IdeaForkJoinWorkerThreadFactory.java b/platform/boot/src/com/intellij/concurrency/IdeaForkJoinWorkerThreadFactory.java new file mode 100644 index 000000000000..1d741f87abe1 --- /dev/null +++ b/platform/boot/src/com/intellij/concurrency/IdeaForkJoinWorkerThreadFactory.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2016 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.concurrency; + +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinWorkerThread; +import java.util.concurrent.atomic.AtomicLong; + +// must be accessible via "ClassLoader.getSystemClassLoader().loadClass(fp).newInstance()" from java.util.concurrent.ForkJoinPool.makeCommonPool() +public class IdeaForkJoinWorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory { + private static final int PARALLELISM = Runtime.getRuntime().availableProcessors(); + + // must be called in the earliest possible moment on startup + public static void setupForkJoinCommonPool() { + System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", String.valueOf(PARALLELISM)); + System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory", IdeaForkJoinWorkerThreadFactory.class.getName()); + + if (!ForkJoinPool.commonPool().getFactory().getClass().getName().equals(IdeaForkJoinWorkerThreadFactory.class.getName())) { + throw new IllegalStateException("Could not set ForkJoinPool thread factory: got "+ForkJoinPool.commonPool().getFactory()); + } + } + + private static final AtomicLong bits = new AtomicLong(); + @Override + public ForkJoinWorkerThread newThread(ForkJoinPool pool) { + final int n = setNextBit(); + ForkJoinWorkerThread thread = new ForkJoinWorkerThread(pool) { + @Override + protected void onTermination(Throwable exception) { + clearBit(n); + super.onTermination(exception); + } + }; + thread.setName("JobScheduler FJ pool " + n + "/" + PARALLELISM); + return thread; + } + + private static int setNextBit() { + long oldValue = bits.getAndUpdate(value -> value + 1 | value); + return Long.numberOfTrailingZeros(oldValue + 1); + } + + private static void clearBit(int n) { + bits.updateAndGet(value -> value & ~(1L << n)); + } +} diff --git a/platform/core-api/src/com/intellij/lexer/StringLiteralLexer.java b/platform/core-api/src/com/intellij/lexer/StringLiteralLexer.java index 3b943b9e6018..3703409fcf23 100644 --- a/platform/core-api/src/com/intellij/lexer/StringLiteralLexer.java +++ b/platform/core-api/src/com/intellij/lexer/StringLiteralLexer.java @@ -32,13 +32,13 @@ public class StringLiteralLexer extends LexerBase { public static final char NO_QUOTE_CHAR = (char)-1; - private CharSequence myBuffer; - private int myStart; - private int myEnd; + protected CharSequence myBuffer; + protected int myStart; + protected int myEnd; private int myState; private int myLastState; - private int myBufferEnd; - private final char myQuoteChar; + protected int myBufferEnd; + protected final char myQuoteChar; private final IElementType myOriginalLiteralToken; private final boolean myCanEscapeEolOrFramingSpaces; private final String myAdditionalValidEscapes; @@ -114,10 +114,7 @@ public class StringLiteralLexer extends LexerBase { return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN; } if (nextChar == 'u') { - for(int i = myStart + 2; i < myStart + 6; i++) { - if (i >= myEnd || !StringUtil.isHexDigit(myBuffer.charAt(i))) return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN; - } - return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN; + return getUnicodeEscapeSequenceType(); } if (nextChar == 'x' && myAllowHex) { @@ -155,6 +152,14 @@ public class StringLiteralLexer extends LexerBase { return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN; } + @NotNull + protected IElementType getUnicodeEscapeSequenceType() { + for (int i = myStart + 2; i < myStart + 6; i++) { + if (i >= myEnd || !StringUtil.isHexDigit(myBuffer.charAt(i))) return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN; + } + return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN; + } + // all subsequent chars are escaped spaces private boolean isTrailingSpace(final int start) { for (int i=start;i T submitTransactionAndWait(@NotNull TransactionKind kind, @NotNull final Computable transaction) throws ProcessCanceledException { + final Ref result = Ref.create(); + submitTransactionAndWait(kind, new Runnable() { + @Override + public void run() { + result.set(transaction.compute()); + } + }); + return result.get(); + } + /** * A synchronous version of {@link #submitMergeableTransaction(TransactionKind, Runnable)}. * @return a token object for this transaction. Call {@link AccessToken#finish()} (inside finally) when the transaction is complete. diff --git a/platform/core-api/src/com/intellij/psi/util/PsiCacheKey.java b/platform/core-api/src/com/intellij/psi/util/PsiCacheKey.java index d91e4823c5c0..bd57a08c6ba6 100644 --- a/platform/core-api/src/com/intellij/psi/util/PsiCacheKey.java +++ b/platform/core-api/src/com/intellij/psi/util/PsiCacheKey.java @@ -76,7 +76,7 @@ public class PsiCacheKey extends Key template2argument = findMatchingTemplates(file, editor, shortcutChar, templateSettings); + Map template2argument = findMatchingTemplates(file, editor, shortcutChar, TemplateSettings.getInstance()); - for (final CustomLiveTemplate customLiveTemplate : CustomLiveTemplate.EP_NAME.getExtensions()) { - if (shortcutChar == customLiveTemplate.getShortcut()) { - if (editor.getCaretModel().getCaretCount() > 1 && !supportsMultiCaretMode(customLiveTemplate)) { - continue; - } - final Document document = editor.getDocument(); - PsiDocumentManager.getInstance(myProject).commitDocument(document); - if (isApplicable(customLiveTemplate, editor, file)) { - final CustomTemplateCallback callback = new CustomTemplateCallback(editor, file); - final String key = customLiveTemplate.computeTemplateKey(callback); + List customCandidates = ContainerUtil.findAll(CustomLiveTemplate.EP_NAME.getExtensions(), customLiveTemplate -> + shortcutChar == customLiveTemplate.getShortcut() && + (editor.getCaretModel().getCaretCount() <= 1 || supportsMultiCaretMode(customLiveTemplate))); + if (!customCandidates.isEmpty()) { + int caretOffset = editor.getCaretModel().getOffset(); + PsiFile fileCopy = insertDummyIdentifierIfNeeded(file, caretOffset, caretOffset, ""); + Document document = editor.getDocument(); + + for (final CustomLiveTemplate customLiveTemplate : customCandidates) { + if (isApplicable(customLiveTemplate, editor, fileCopy)) { + final String key = customLiveTemplate.computeTemplateKey(new CustomTemplateCallback(editor, fileCopy)); if (key != null) { - int caretOffset = editor.getCaretModel().getOffset(); int offsetBeforeKey = caretOffset - key.length(); CharSequence text = document.getImmutableCharSequence(); if (template2argument == null || !containsTemplateStartingBefore(template2argument, offsetBeforeKey, caretOffset, text)) { - return new Runnable() { - @Override - public void run() { - customLiveTemplate.expand(key, callback); - } - }; + return () -> customLiveTemplate.expand(key, new CustomTemplateCallback(editor, file)); } } } } } + return startNonCustomTemplates(template2argument, editor, processor); } @@ -357,13 +356,6 @@ public class TemplateManagerImpl extends TemplateManager implements Disposable { return null; } - CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { - @Override - public void run() { - PsiDocumentManager.getInstance(myProject).commitDocument(document); - } - }, "", null); - candidatesWithoutArgument = filterApplicableCandidates(file, caretOffset, candidatesWithoutArgument); candidatesWithArgument = filterApplicableCandidates(file, argumentOffset, candidatesWithArgument); Map candidate2Argument = new HashMap(); @@ -474,7 +466,7 @@ public class TemplateManagerImpl extends TemplateManager implements Disposable { return candidates; } - PsiFile copy = insertDummyIdentifier(file, caretOffset, caretOffset); + PsiFile copy = insertDummyIdentifierIfNeeded(file, caretOffset, caretOffset, CompletionUtil.DUMMY_IDENTIFIER_TRIMMED); List result = new ArrayList(); for (TemplateImpl candidate : candidates) { @@ -610,15 +602,34 @@ public class TemplateManagerImpl extends TemplateManager implements Disposable { boolean selection = editor.getSelectionModel().hasSelection(); final int startOffset = selection ? editor.getSelectionModel().getSelectionStart() : editor.getCaretModel().getOffset(); final int endOffset = selection ? editor.getSelectionModel().getSelectionEnd() : startOffset; - return insertDummyIdentifier(file, startOffset, endOffset); + return insertDummyIdentifierIfNeeded(file, startOffset, endOffset, CompletionUtil.DUMMY_IDENTIFIER_TRIMMED); } - public static PsiFile insertDummyIdentifier(PsiFile file, final int startOffset, final int endOffset) { - file = (PsiFile)file.copy(); - final Document document = file.getViewProvider().getDocument(); - assert document != null; - document.replaceString(startOffset, endOffset, CompletionUtil.DUMMY_IDENTIFIER_TRIMMED); - PsiDocumentManager.getInstance(file.getProject()).commitDocument(document); - return file; + private static PsiFile insertDummyIdentifierIfNeeded(PsiFile file, final int startOffset, final int endOffset, String replacement) { + Document originalDocument = file.getViewProvider().getDocument(); + assert originalDocument != null; + + if (replacement.isEmpty() && PsiDocumentManager.getInstance(file.getProject()).isCommitted(originalDocument)) { + return file; + } + + ConcurrentFactoryMap, PsiFile> map = + CachedValuesManager.getCachedValue(file, () -> CachedValueProvider.Result.create(new ConcurrentFactoryMap, PsiFile>() { + @Nullable + @Override + protected PsiFile create(Trinity key) { + PsiFile copy = (PsiFile)file.copy(); + + final Document document = copy.getViewProvider().getDocument(); + assert document != null; + + document.setText(originalDocument.getImmutableCharSequence()); // original file might be uncommitted + document.replaceString(key.first, key.second, key.third); + PsiDocumentManager.getInstance(copy.getProject()).commitDocument(document); + return copy; + } + }, file, originalDocument)); + + return map.get(Trinity.create(startOffset, endOffset, replacement)); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/ExpandLiveTemplateCustomAction.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/ExpandLiveTemplateCustomAction.java index 44f138f2229a..c35a85497d57 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/ExpandLiveTemplateCustomAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/editorActions/ExpandLiveTemplateCustomAction.java @@ -36,7 +36,7 @@ public class ExpandLiveTemplateCustomAction extends EditorAction { setInjectedContext(true); } - static EditorWriteActionHandler createExpandTemplateHandler(final char shortcutChar) { + public static EditorWriteActionHandler createExpandTemplateHandler(final char shortcutChar) { return new EditorWriteActionHandler(true) { @Override public void executeWriteAction(Editor editor, @Nullable Caret caret, DataContext dataContext) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java index 1cbba4208da2..2feab8fec30e 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java @@ -225,9 +225,7 @@ public class ViewOfflineResultsAction extends AnAction { final InspectionResultsView view = new InspectionResultsView(context, new OfflineInspectionRVContentProvider(resMap, project)); ((RefManagerImpl)context.getRefManager()).startOfflineView(); - ApplicationManager.getApplication().executeOnPooledThread(() -> { - ApplicationManager.getApplication().runReadAction((Runnable)view::buildTree); - }); + view.update(); TreeUtil.selectFirstNode(view.getTree()); context.addView(view, title); return view; diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index 74dd8f344560..99bdc8a754ad 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -91,7 +91,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.GlobalInspectionContextImpl"); private static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.toolWindowGroup("Inspection Results", ToolWindowId.INSPECTION); private final NotNullLazyValue myContentManager; - private InspectionResultsView myView; + private volatile InspectionResultsView myView; private Content myContent; private volatile boolean myViewClosed = true; @@ -125,7 +125,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp }); myView = view; - myView.getTree().setPaintBusy(true); + myView.setUpdating(true); myContent = ContentFactory.SERVICE.getInstance().createContent(view, title, false); myContent.setDisposer(myView); @@ -344,7 +344,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp } else { view = null; } - if (!(myView == null ? view : myView).update() && !getUIOptions().SHOW_ONLY_DIFF) { + if (!(myView == null ? view : myView).hasProblems() && !getUIOptions().SHOW_ONLY_DIFF) { NOTIFICATION_GROUP.createNotification(InspectionsBundle.message("inspection.no.problems.message", scope.getFileCount(), scope.getDisplayName()), MessageType.INFO).notify(getProject()); close(true); if (view != null) { @@ -355,7 +355,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp addView(view); } if (myView != null) { - myView.getTree().setPaintBusy(false); + myView.setUpdating(false); } } }); @@ -779,7 +779,15 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp @Override public void close(boolean noSuspisiousCodeFound) { - if (!noSuspisiousCodeFound && (myView == null || myView.isRerun())) return; + if (!noSuspisiousCodeFound) { + if (myView.isRerun()) { + myViewClosed = true; + myView = null; + } + if (myView == null) { + return; + } + } AnalysisUIOptions.getInstance(getProject()).save(myUIOptions); if (myContent != null) { final ContentManager contentManager = getContentManager(); @@ -800,7 +808,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp } } if (myView != null) { - myView.getTree().setPaintBusy(false); + myView.setUpdating(false); } super.cleanup(); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/PerformFixesModalTask.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/PerformFixesModalTask.java index 96281b57098f..fc5b3964730e 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/PerformFixesModalTask.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/PerformFixesModalTask.java @@ -77,13 +77,11 @@ public abstract class PerformFixesModalTask implements SequentialTask { final QuickFix[] fixes = descriptor.getFixes(); if (fixes != null) { for (QuickFix fix : fixes) { - if (fix instanceof IntentionAction) { - if (!((IntentionAction)fix).startInWriteAction()) { - runInReadAction[0] = true; - } else { - runInReadAction[0] = false; - break; - } + if (!fix.startInWriteAction()) { + runInReadAction[0] = true; + } else { + runInReadAction[0] = false; + break; } } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java index d3cf6cbfb2fd..089651efa15d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java @@ -77,7 +77,7 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro private Map myOldProblemElements = null; protected static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.DescriptorProviderInspection"); - private boolean isDisposed; + private volatile boolean isDisposed; public DefaultInspectionToolPresentation(@NotNull InspectionToolWrapper toolWrapper, @NotNull GlobalInspectionContextImpl context) { myToolWrapper = toolWrapper; @@ -230,46 +230,43 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro return; } if (myToolWrapper instanceof LocalInspectionToolWrapper) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - InspectionResultsView view = context.getView(); - if (view == null) { - view = new InspectionResultsView(context, - new InspectionRVContentProviderImpl(context.getProject())); - context.addView(view); + InspectionResultsView view = context.getView(); + if (view == null) { + view = UIUtil.invokeAndWaitIfNeeded(() -> { + InspectionResultsView newView = context.getView(); + if (newView != null) { + return newView; } - if (!isDisposed()) { - final InspectionResultsView finalView = view; - ApplicationManager.getApplication().executeOnPooledThread(() -> { - ApplicationManager.getApplication().runReadAction(() -> { - synchronized (finalView.getTreeWriteLock()) { - final InspectionNode toolNode; - toolNode = myToolNode == null ? - finalView.addTool(myToolWrapper, HighlightDisplayLevel.find(getSeverity((RefElement)refElement)), - context.getUIOptions().GROUP_BY_SEVERITY) : myToolNode; + newView = new InspectionResultsView(context, new InspectionRVContentProviderImpl(context.getProject())); + context.addView(newView); + return newView; + }); + } + if (!isDisposed()) { + ApplicationManager.getApplication().assertReadAccessAllowed(); + synchronized (view.getTreeWriteLock()) { + final InspectionNode toolNode; + toolNode = myToolNode == null ? + view.addTool(myToolWrapper, HighlightDisplayLevel.find(getSeverity((RefElement)refElement)), + context.getUIOptions().GROUP_BY_SEVERITY) : myToolNode; - final Map problems = new HashMap(); - problems.put(refElement, descriptors); - final Map> contents = new HashMap>(); - final String groupName = refElement.getRefManager().getGroupName((RefElement)refElement); - Set content = contents.get(groupName); - if (content == null) { - content = new HashSet(); - contents.put(groupName, content); - } - content.add(refElement); - - finalView.getProvider().appendToolNodeContent(context, toolNode, - (InspectionTreeNode)toolNode.getParent(), context.getUIOptions().SHOW_STRUCTURE, - contents, problems, (DefaultTreeModel)finalView.getTree().getModel()); - - } - }); - }); + final Map problems = new HashMap(); + problems.put(refElement, descriptors); + final Map> contents = new HashMap>(); + final String groupName = refElement.getRefManager().getGroupName((RefElement)refElement); + Set content = contents.get(groupName); + if (content == null) { + content = new HashSet(); + contents.put(groupName, content); } + content.add(refElement); + + view.getProvider().appendToolNodeContent(context, toolNode, + (InspectionTreeNode)toolNode.getParent(), context.getUIOptions().SHOW_STRUCTURE, + contents, problems, (DefaultTreeModel)view.getTree().getModel()); + } - }); + } } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index f4a00097dee2..f29ea68ee74c 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -34,6 +34,7 @@ import com.intellij.ide.actions.ContextHelpAction; import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; @@ -43,6 +44,7 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; @@ -50,10 +52,7 @@ import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.pom.Navigatable; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; +import com.intellij.psi.*; import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.*; import com.intellij.ui.components.JBLabel; @@ -62,6 +61,7 @@ import com.intellij.util.ConcurrencyUtil; import com.intellij.util.EditSourceOnDoubleClickHandler; import com.intellij.util.OpenSourceUtil; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -94,7 +94,8 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private final Project myProject; private final InspectionTree myTree; - private final ConcurrentMap> myGroups = ContainerUtil.newConcurrentMap(); + private final ConcurrentMap> myGroups = + ContainerUtil.newConcurrentMap(); private final OccurenceNavigator myOccurenceNavigator; private volatile InspectionProfile myInspectionProfile; @NotNull @@ -108,12 +109,14 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private final GlobalInspectionContextImpl myGlobalInspectionContext; private boolean myRerun; private volatile boolean myDisposed; + private boolean myUpdating; @NotNull private final InspectionRVContentProvider myProvider; private AnAction myIncludeAction; private AnAction myExcludeAction; private Editor myPreviewEditor; + private InspectionTreeLoadingProgressAware myLoadingProgressPreview; private final Object myTreeWriteLock = new Object(); @@ -126,7 +129,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren myGlobalInspectionContext = globalInspectionContext; myProvider = provider; - myTree = new InspectionTree(myProject, globalInspectionContext); + myTree = new InspectionTree(myProject, globalInspectionContext, this); initTreeListeners(); myOccurenceNavigator = initOccurenceNavigator(); @@ -144,8 +147,24 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren createActionsToolbar(); TreeUtil.selectFirstNode(myTree); - } + PsiManager.getInstance(myProject).addPsiTreeChangeListener(new PsiTreeChangeAdapter() { + @Override + public void childRemoved(@NotNull PsiTreeChangeEvent event) { + myTree.queueUpdate(); + } + + @Override + public void childReplaced(@NotNull PsiTreeChangeEvent event) { + myTree.queueUpdate(); + } + + @Override + public void childMoved(@NotNull PsiTreeChangeEvent event) { + myTree.queueUpdate(); + } + }, this); + } private void initTreeListeners() { @@ -181,7 +200,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren SmartExpander.installOn(myTree); } - private OccurenceNavigatorSupport initOccurenceNavigator(){ + private OccurenceNavigatorSupport initOccurenceNavigator() { return new OccurenceNavigatorSupport(myTree) { @Override @Nullable @@ -238,7 +257,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren @SuppressWarnings({"NonStaticInitializer"}) private JComponent createRightActionsToolbar() { - myIncludeAction = new AnAction(InspectionsBundle.message("inspections.result.view.include.action.text")){ + myIncludeAction = new AnAction(InspectionsBundle.message("inspections.result.view.include.action.text")) { { registerCustomShortcutSet(CommonShortcuts.INSERT, myTree); } @@ -251,13 +270,13 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren ((InspectionTreeNode)path.getLastPathComponent()).amnesty(); } } - updateView(false); + myTree.queueUpdate(); } @Override public void update(final AnActionEvent e) { final TreePath[] paths = myTree.getSelectionPaths(); - e.getPresentation().setEnabled(paths != null && paths.length > 0 && + e.getPresentation().setEnabled(paths != null && paths.length > 0 && !myGlobalInspectionContext.getUIOptions().FILTER_RESOLVED_ITEMS); } }; @@ -383,6 +402,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren private void syncRightPanel() { final Editor oldEditor = myPreviewEditor; + if (myLoadingProgressPreview != null) { + Disposer.dispose(myLoadingProgressPreview); + myLoadingProgressPreview = null; + } if (myTree.getSelectionModel().getSelectionCount() != 1) { if (myTree.getSelectedToolWrapper() == null) { mySplitter.setSecondComponent(getNothingToShowTextLabel()); @@ -408,12 +431,15 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final String shortName = ((InspectionNode)node).getToolWrapper().getShortName(); if (shortName.isEmpty()) { mySplitter.setSecondComponent(getNothingToShowTextLabel()); - } else { + } + else { showInRightPanel(null); } } else if (node instanceof InspectionRootNode || node instanceof InspectionGroupNode || node instanceof InspectionSeverityGroupNode) { - mySplitter.setSecondComponent(new InspectionViewNavigationPanel(node, myTree)); + final InspectionViewNavigationPanel panel = new InspectionViewNavigationPanel(node, myTree); + myLoadingProgressPreview = panel; + mySplitter.setSecondComponent(panel); } else { LOG.error("Unexpected node: " + node.getClass()); @@ -456,11 +482,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } editorPanel.add(previewPanel, BorderLayout.CENTER); if (problemCount > 0) { - editorPanel.add(new QuickFixToolbar(myTree, - myProject, - myPreviewEditor, - myProvider.getQuickFixes(tool, myTree)), - BorderLayout.NORTH); + final QuickFixToolbar fixToolbar = new QuickFixToolbar(myPreviewEditor, this); + myLoadingProgressPreview = fixToolbar; + editorPanel.add(fixToolbar, BorderLayout.NORTH); } mySplitter.setSecondComponent(editorPanel); } @@ -526,7 +550,9 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } @NotNull - public InspectionNode addTool(@NotNull final InspectionToolWrapper toolWrapper, HighlightDisplayLevel errorLevel, boolean groupedBySeverity) { + public InspectionNode addTool(@NotNull final InspectionToolWrapper toolWrapper, + HighlightDisplayLevel errorLevel, + boolean groupedBySeverity) { String groupName = toolWrapper.getGroupDisplayName().isEmpty() ? InspectionProfileEntry.GENERAL_GROUP_NAME : toolWrapper.getGroupDisplayName(); InspectionTreeNode parentNode = getToolParentNode(groupName, errorLevel, groupedBySeverity); @@ -551,11 +577,6 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } - private void clearTree() { - myTree.removeAllNodes(); - mySeverityGroupNodes.clear(); - } - @Nullable public String getCurrentProfileName() { return myInspectionProfile == null ? null : myInspectionProfile.getDisplayName(); @@ -565,45 +586,73 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren return myInspectionProfile; } - public boolean update(){ - return updateView(true); + public void update() { + updateView(true); } - public boolean updateView(boolean strict) { - if (!strict && !myGlobalInspectionContext.getUIOptions().FILTER_RESOLVED_ITEMS){ + public void updateView(boolean strict) { + ApplicationManager.getApplication().assertIsDispatchThread(); + if (!strict && !myGlobalInspectionContext.getUIOptions().FILTER_RESOLVED_ITEMS) { myTree.repaint(); - return false; } - clearTree(); - boolean resultsFound = buildTree(); - myTree.restoreExpansionAndSelection(); - return resultsFound; + myTree.removeAllNodes(); + mySeverityGroupNodes.clear(); + buildTree(); + } + + public void setUpdating(boolean isUpdating) { + final Runnable update = () -> { + myUpdating = isUpdating; + myTree.setPaintBusy(isUpdating); + if (!isUpdating && myLoadingProgressPreview != null) { + myLoadingProgressPreview.treeLoaded(); + } + }; + final Application app = ApplicationManager.getApplication(); + if (app.isDispatchThread()) { + update.run(); + } + else { + app.invokeLater(update, ModalityState.any()); + } } public Object getTreeWriteLock() { return myTreeWriteLock; } - public boolean buildTree() { - synchronized (myTreeWriteLock) { - InspectionProfile profile = myInspectionProfile; - boolean isGroupedBySeverity = myGlobalInspectionContext.getUIOptions().GROUP_BY_SEVERITY; - myGroups.clear(); - final Map tools = myGlobalInspectionContext.getTools(); - boolean resultsFound = false; - for (Tools currentTools : tools.values()) { - InspectionToolWrapper defaultToolWrapper = currentTools.getDefaultState().getTool(); - final HighlightDisplayKey key = HighlightDisplayKey.find(defaultToolWrapper.getShortName()); - for (ScopeToolState state : myProvider.getTools(currentTools)) { - InspectionToolWrapper toolWrapper = state.getTool(); - if (myProvider.checkReportedProblems(myGlobalInspectionContext, toolWrapper)) { - addTool(toolWrapper, ((InspectionProfileImpl)profile).getErrorLevel(key, state.getScope(myProject), myProject), + public void buildTree() { + final Application app = ApplicationManager.getApplication(); + final Runnable buildAction = () -> { + try { + setUpdating(true); + InspectionProfile profile = myInspectionProfile; + boolean isGroupedBySeverity = myGlobalInspectionContext.getUIOptions().GROUP_BY_SEVERITY; + myGroups.clear(); + final Map tools = myGlobalInspectionContext.getTools(); + for (Tools currentTools : tools.values()) { + InspectionToolWrapper defaultToolWrapper = currentTools.getDefaultState().getTool(); + final HighlightDisplayKey key = HighlightDisplayKey.find(defaultToolWrapper.getShortName()); + for (ScopeToolState state : myProvider.getTools(currentTools)) { + InspectionToolWrapper toolWrapper = state.getTool(); + if (myProvider.checkReportedProblems(myGlobalInspectionContext, toolWrapper)) { + addTool(toolWrapper, ((InspectionProfileImpl)profile).getErrorLevel(key, state.getScope(myProject), myProject), isGroupedBySeverity); - resultsFound = true; + } } } } - return resultsFound; + finally { + setUpdating(false); + UIUtil.invokeLaterIfNeeded(myTree::restoreExpansionAndSelection); + } + }; + if (app.isUnitTestMode()) { + buildAction.run(); + } else { + app.executeOnPooledThread(() -> { + app.runReadAction(buildAction); + }); } } @@ -627,7 +676,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } } if (group == null) { - group = ConcurrencyUtil.cacheOrGet(map, groupName, new InspectionGroupNode(groupName)); + group = ConcurrencyUtil.cacheOrGet(map, groupName, new InspectionGroupNode(groupName)); if (!myDisposed) { insertByIndex(group, getRelativeRootNode(groupedBySeverity, errorLevel)); } @@ -756,7 +805,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren @Nullable private Navigatable getSelectedNavigatable(final CommonProblemDescriptor descriptor, final PsiElement psiElement) { if (descriptor instanceof ProblemDescriptorBase) { - Navigatable navigatable = ((ProblemDescriptorBase) descriptor).getNavigatable(); + Navigatable navigatable = ((ProblemDescriptorBase)descriptor).getNavigatable(); if (navigatable != null) { return navigatable; } @@ -837,7 +886,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren } @NotNull - public InspectionTree getTree(){ + public InspectionTree getTree() { return myTree; } @@ -887,7 +936,8 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren final InputEvent event = e.getInputEvent(); if (event instanceof MouseEvent) { popup.showUnderneathOf(event.getComponent()); - } else { + } + else { popup.showInBestPositionFor(e.getDataContext()); } } @@ -900,6 +950,29 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren syncRightPanel(); } + public boolean isUpdating() { + return myUpdating; + } + + public void updateRightPanelLoading() { + if (!myDisposed && isUpdating() && myLoadingProgressPreview != null) { + myLoadingProgressPreview.updateLoadingProgress(); + } + } + + public boolean hasProblems() { + final Map tools = myGlobalInspectionContext.getTools(); + for (Tools currentTools : tools.values()) { + for (ScopeToolState state : myProvider.getTools(currentTools)) { + InspectionToolWrapper toolWrapper = state.getTool(); + if (myProvider.checkReportedProblems(myGlobalInspectionContext, toolWrapper)) { + return true; + } + } + } + return false; + } + private class CloseAction extends AnAction implements DumbAware { private CloseAction() { super(CommonBundle.message("action.close"), null, AllIcons.Actions.Cancel); @@ -929,9 +1002,10 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren if (toolWrapper != null) { final HighlightDisplayKey key = HighlightDisplayKey.find(toolWrapper.getShortName()); //do not search for dead code entry point tool - if (key != null){ - if (new EditInspectionToolsSettingsAction(key).editToolSettings(myProject, (InspectionProfileImpl)inspectionProfile, profileIsDefined) - && profileIsDefined){ + if (key != null) { + if (new EditInspectionToolsSettingsAction(key) + .editToolSettings(myProject, (InspectionProfileImpl)inspectionProfile, profileIsDefined) + && profileIsDefined) { updateCurrentProfile(); } return; @@ -941,7 +1015,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren updateCurrentProfile(); } } - } + } public void updateCurrentProfile() { final String name = myInspectionProfile.getName(); @@ -964,6 +1038,7 @@ public class InspectionResultsView extends JPanel implements Disposable, Occuren public void actionPerformed(AnActionEvent e) { rerun(); } + private void rerun() { myRerun = true; if (myScope.isValid()) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java index 3443152fe515..a9807900b53c 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java @@ -24,7 +24,6 @@ package com.intellij.codeInspection.ui; import com.intellij.codeInspection.CommonProblemDescriptor; import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ex.*; import com.intellij.codeInspection.reference.RefElement; import com.intellij.codeInspection.reference.RefEntity; @@ -40,7 +39,6 @@ import com.intellij.ui.treeStructure.Tree; import com.intellij.util.containers.Convertor; import com.intellij.util.containers.MultiMap; import com.intellij.util.ui.UIUtil; -import com.intellij.util.ui.tree.TreeModelAdapter; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -59,8 +57,9 @@ public class InspectionTree extends Tree { private SelectionPath mySelectionPath; private boolean myQueueUpdate; - public InspectionTree(@NotNull Project project, @NotNull GlobalInspectionContextImpl context) { - setModel(new DefaultTreeModel(new InspectionRootNode(project, new InspectionTreeUpdater(this)))); + public InspectionTree(@NotNull Project project, + @NotNull GlobalInspectionContextImpl context, InspectionResultsView view) { + setModel(new DefaultTreeModel(new InspectionRootNode(project, new InspectionTreeUpdater(view)))); myContext = context; setCellRenderer(new CellRenderer()); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeLoadingProgressAware.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeLoadingProgressAware.java new file mode 100644 index 000000000000..4ad87cb489bc --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeLoadingProgressAware.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2016 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.codeInspection.ui; + +import com.intellij.openapi.Disposable; + +/** + * @author Dmitry Batkovich + */ +public interface InspectionTreeLoadingProgressAware extends Disposable { + + void updateLoadingProgress(); + + void treeLoaded(); + + @Override + default void dispose() { + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java index 574902b3c16e..0927185fb70f 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeNode.java @@ -22,7 +22,9 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; import java.util.Enumeration; /** @@ -87,7 +89,7 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode { super.add(newChild); if (myUpdater != null) { ((InspectionTreeNode)newChild).propagateUpdater(myUpdater); - myUpdater.update(); + myUpdater.updateWithPreviewPanel(); } } @@ -96,7 +98,7 @@ public abstract class InspectionTreeNode extends DefaultMutableTreeNode { super.insert(newChild, childIndex); if (myUpdater != null) { ((InspectionTreeNode)newChild).propagateUpdater(myUpdater); - myUpdater.update(); + myUpdater.updateWithPreviewPanel(); } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeUpdater.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeUpdater.java index 338055f2c7d5..e10a744feb35 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeUpdater.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTreeUpdater.java @@ -20,21 +20,24 @@ import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; import javax.swing.tree.DefaultTreeModel; +import java.util.concurrent.atomic.AtomicBoolean; /** * @author Dmitry Batkovich */ public class InspectionTreeUpdater { - private final InspectionTree myTree; private final MergingUpdateQueue myUpdateQueue; + private final InspectionResultsView myView; + private final AtomicBoolean myDoUpdatePreviewPanel = new AtomicBoolean(false); - public InspectionTreeUpdater(InspectionTree tree) { - myTree = tree; - myUpdateQueue = new MergingUpdateQueue("InspectionView", 100, true, tree); + public InspectionTreeUpdater(InspectionResultsView view) { + myView = view; + myUpdateQueue = new MergingUpdateQueue("InspectionView", 100, true, view); } - public void update() { + public void updateWithPreviewPanel() { update(false); + myDoUpdatePreviewPanel.compareAndSet(false, true); } public void update(boolean force) { @@ -44,14 +47,18 @@ public class InspectionTreeUpdater { myUpdateQueue.queue(new Update("TreeRepaint") { @Override public void run() { + final InspectionTree tree = myView.getTree(); try { - myTree.setQueueUpdate(true); - ((DefaultTreeModel)myTree.getModel()).reload(); - myTree.revalidate(); - myTree.repaint(); - myTree.restoreExpansionAndSelection(); + tree.setQueueUpdate(true); + ((DefaultTreeModel)tree.getModel()).reload(); + tree.revalidate(); + tree.repaint(); + tree.restoreExpansionAndSelection(); + if (myDoUpdatePreviewPanel.compareAndSet(true, false)) { + myView.updateRightPanelLoading(); + } } finally { - myTree.setQueueUpdate(false); + tree.setQueueUpdate(false); } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java index 0b316bb3b9c9..7db226688f08 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionViewNavigationPanel.java @@ -30,26 +30,43 @@ import java.awt.*; /** * @author Dmitry Batkovich */ -public class InspectionViewNavigationPanel extends JPanel { +public class InspectionViewNavigationPanel extends JPanel implements InspectionTreeLoadingProgressAware { + private final InspectionTreeNode myNode; + private final InspectionTree myTree; + private final JPanel myLinks; + private int myShownChildrenCount; + public InspectionViewNavigationPanel(InspectionTreeNode node, InspectionTree tree) { + myNode = node; + myTree = tree; setLayout(new BorderLayout()); setBorder(IdeBorderFactory.createEmptyBorder(5, 7, 0, 0)); - final String titleLabelText = getTitleText(node instanceof InspectionRootNode, true); + final String titleLabelText = getTitleText(myNode instanceof InspectionRootNode, true); add(new JBLabel(titleLabelText), BorderLayout.NORTH); - final JPanel links = new JPanel(); - links.setLayout(new BoxLayout(links, BoxLayout.Y_AXIS)); - links.add(Box.createVerticalStrut(JBUI.scale(10))); - add(BorderLayout.CENTER, links); - for (int i = 0; i < node.getChildCount(); i++) { - final TreeNode child = node.getChildAt(i); - final LinkLabel link = new LinkLabel(child.toString(), null) { - @Override - public void doClick() { - TreeUtil.selectInTree((DefaultMutableTreeNode)child, true, tree); - } - }; - link.setBorder(IdeBorderFactory.createEmptyBorder(1, 17, 3, 1)); - links.add(link); + myLinks = new JPanel(); + myLinks.setLayout(new BoxLayout(myLinks, BoxLayout.Y_AXIS)); + + add(BorderLayout.CENTER, myLinks); + resetChildrenNavigation(); + } + + private void resetChildrenNavigation() { + final int currentChildrenCount = myNode.getChildCount(); + if (myShownChildrenCount != currentChildrenCount) { + myLinks.removeAll(); + myLinks.add(Box.createVerticalStrut(JBUI.scale(10))); + for (int i = 0; i < currentChildrenCount; i++) { + final TreeNode child = myNode.getChildAt(i); + final LinkLabel link = new LinkLabel(child.toString(), null) { + @Override + public void doClick() { + TreeUtil.selectInTree((DefaultMutableTreeNode)child, true, myTree); + } + }; + link.setBorder(IdeBorderFactory.createEmptyBorder(1, 17, 3, 1)); + myLinks.add(link); + } + myShownChildrenCount = currentChildrenCount; } } @@ -57,4 +74,14 @@ public class InspectionViewNavigationPanel extends JPanel { public static String getTitleText(boolean addGroupWord, boolean addColon) { return "Select inspection" + (addGroupWord ? " group " : " ") + "to see problems" + (addColon ? ":" : "."); } + + @Override + public void updateLoadingProgress() { + resetChildrenNavigation(); + } + + @Override + public void treeLoaded() { + resetChildrenNavigation(); + } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java index 0208d56427f5..2a587334a10f 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/QuickFixToolbar.java @@ -25,15 +25,15 @@ import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; import com.intellij.openapi.actionSystem.ex.CustomComponentAction; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.ui.ClickListener; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.SimpleColoredComponent; -import com.intellij.ui.SimpleTextAttributes; -import com.intellij.util.ui.JBInsets; +import com.intellij.util.ui.AsyncProcessIcon; import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,48 +41,121 @@ import javax.swing.*; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; import java.util.function.Supplier; /** * @author Dmitry Batkovich */ -public class QuickFixToolbar extends JPanel { +public class QuickFixToolbar extends JPanel implements InspectionTreeLoadingProgressAware { + private static final Logger LOG = Logger.getInstance(QuickFixToolbar.class); private static final int MAX_FIX_COUNT = 3; + @Nullable private final Editor myEditor; + @Nullable private final String myTargetName; + @NotNull private final InspectionResultsView myView; + private final InspectionToolWrapper myWrapper; - public QuickFixToolbar(@NotNull InspectionTree tree, - @NotNull Project project, - @Nullable Editor editor, - @Nullable QuickFixAction[] fixes) { - final boolean hasFixes = fixes != null && fixes.length != 0; - CommonProblemDescriptor[] descriptors = tree.getSelectedDescriptors(); + private SimpleColoredComponent myWaitingLabel; + + public QuickFixToolbar(@Nullable Editor editor, + @NotNull InspectionResultsView view) { + myEditor = editor; + myView = view; + myWrapper = view.getTree().getSelectedToolWrapper(); + LOG.assertTrue(myWrapper != null); + CommonProblemDescriptor[] descriptors = myView.getTree().getSelectedDescriptors(); int problemCount = descriptors.length; - final boolean multipleDescriptors = problemCount > 1; setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); - setBorder(IdeBorderFactory.createEmptyBorder(7 + (hasFixes ? 0 : 5), hasFixes ? 12 : 9, hasFixes ? 0 : 6, 0)); + setBorder(IdeBorderFactory.createEmptyBorder(7, 11, 0, 0)); + myTargetName = getTargetName(); - fill(multipleDescriptors, () -> getLabel(fixes, tree.getSelectionCount() == 1 ? (InspectionTreeNode)tree.getSelectionPath().getLastPathComponent() : null, problemCount), this); + if (view.isUpdating() && !areDescriptorNodesSelected()) { + AsyncProcessIcon waitingIcon = new AsyncProcessIcon("Inspection preview panel updating..."); + Disposer.register(this, waitingIcon); + myWaitingLabel = getLabel(null, problemCount); + add(myWaitingLabel); + add(waitingIcon); + } + else { + QuickFixAction[] fixes = view.getProvider().getQuickFixes(myWrapper, view.getTree()); + fillPanel(editor, fixes, descriptors); + } + } + + @Override + public void treeLoaded() { + if (myWaitingLabel != null) { + removeAll(); + final InspectionTree tree = myView.getTree(); + QuickFixAction[] fixes = myView.getProvider().getQuickFixes(myWrapper, tree); + CommonProblemDescriptor[] descriptors = tree.getSelectedDescriptors(); + fillPanel(myEditor, fixes, descriptors); + } + } + + @Override + public void updateLoadingProgress() { + if (myWaitingLabel != null) { + myWaitingLabel.clear(); + final InspectionTree tree = myView.getTree(); + appendTextToLabel(myWaitingLabel, tree.getSelectedProblemCount(), null); + } + } + + private void fillPanel(@Nullable Editor editor, + @Nullable QuickFixAction[] fixes, + CommonProblemDescriptor[] descriptors) { + InspectionTree tree = myView.getTree(); + Project project = myView.getProject(); + boolean hasFixes = fixes != null && fixes.length != 0; + int problemCount = descriptors.length; + boolean multipleDescriptors = problemCount > 1; + fill(multipleDescriptors, () -> getLabel(fixes, problemCount), this); fill(hasFixes, () -> createFixPanel(fixes, multipleDescriptors), this); - fill(true, () -> createSuppressionCombo(tree.getSelectedToolWrapper(), tree.getSelectionPaths(), project, multipleDescriptors), this); - fill(multipleDescriptors && editor != null, () -> ActionManager.getInstance().createActionToolbar("", GoToSubsequentOccurrenceAction.createNextPreviousActions( - editor, descriptors), true).getComponent(), this); + fill(true, () -> createSuppressionCombo(myWrapper, tree.getSelectionPaths(), project, multipleDescriptors), this); + fill(multipleDescriptors && editor != null, + () -> ActionManager.getInstance().createActionToolbar("", GoToSubsequentOccurrenceAction.createNextPreviousActions( + editor, descriptors), true).getComponent(), this); + } + + @Nullable + private String getTargetName() { + if (myView.getTree().getSelectionCount() == 1) { + final Object node = myView.getTree().getSelectionPath().getLastPathComponent(); + return node instanceof RefElementNode ? ((RefElementNode)node).getElement().getName() : null; + } + return null; + } + + private boolean areDescriptorNodesSelected() { + final TreePath[] paths = myView.getTree().getSelectionPaths(); + for (TreePath path : paths) { + if (!(path.getLastPathComponent() instanceof ProblemDescriptionNode)) { + return false; + } + } + return true; } @NotNull - private static JComponent getLabel(QuickFixAction[] fixes, InspectionTreeNode targetNode, int problemsCount) { - final String targetName = targetNode instanceof RefElementNode ? ((RefElementNode)targetNode).getElement().getName() : null; + private SimpleColoredComponent getLabel(QuickFixAction[] fixes, int problemsCount) { SimpleColoredComponent label = new SimpleColoredComponent(); + appendTextToLabel(label, problemsCount, fixes); + label.setBorder(IdeBorderFactory.createEmptyBorder(0, 0, 0, 2)); + return label; + } + + private void appendTextToLabel(SimpleColoredComponent label, + int problemsCount, + QuickFixAction[] fixes) { boolean hasFixesNonIntersectedFixes = fixes != null && fixes.length == 0; label.append(problemsCount + " problems" + - (targetName == null ? "" : (" in " + targetName)) + - (problemsCount > 1 && (fixes != null && fixes.length == MAX_FIX_COUNT) ? " Fix all:" : "") + - (hasFixesNonIntersectedFixes ? ":" : "" )); + (myTargetName == null ? "" : (" in " + myTargetName)) + + (problemsCount > 1 && (fixes != null && fixes.length >= MAX_FIX_COUNT) ? " Fix all:" : "") + + (hasFixesNonIntersectedFixes ? ":" : "")); if (hasFixesNonIntersectedFixes) { label.append(" select a single problem to see its quick fixes"); } - label.setBorder(IdeBorderFactory.createEmptyBorder(0, 0, 0, 2)); - return label; } private static JComponent createSuppressionCombo(@NotNull final InspectionToolWrapper toolWrapper, @@ -108,6 +181,14 @@ public class QuickFixToolbar extends JPanel { return action.createCustomComponent(action.getTemplatePresentation()); } + private static void fill(boolean add, + @NotNull Supplier componentSupplier, + @NotNull JPanel parent) { + if (add) { + parent.add(componentSupplier.get()); + } + } + @NotNull private static JPanel createFixPanel(QuickFixAction[] fixes, boolean multipleDescriptors) { JPanel fixPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, JBUI.scale(3), JBUI.scale(5))); @@ -140,14 +221,6 @@ public class QuickFixToolbar extends JPanel { return fixPanel; } - private static void fill(boolean add, - @NotNull Supplier componentSupplier, - @NotNull JPanel parent) { - if (add) { - parent.add(componentSupplier.get()); - } - } - private static JComponent createQuickFixButton(@NotNull QuickFixAction fix, boolean multipleFixes) { final MyCustomComponentLocalQuickFixWrapper action = new MyCustomComponentLocalQuickFixWrapper(fix); if (multipleFixes) { diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java index 52448f725767..004a3b5036b6 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java @@ -73,6 +73,7 @@ import com.intellij.usageView.UsageInfo; import com.intellij.usages.*; import com.intellij.usages.impl.UsagePreviewPanel; import com.intellij.util.*; +import com.intellij.util.containers.Convertor; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -644,6 +645,12 @@ public class FindDialog extends DialogWrapper { } }; myResultsPreviewTable = table; + new TableSpeedSearch(table, new Convertor() { + @Override + public String convert(Object o) { + return ((UsageInfo2UsageAdapter)o).getFile().getName(); + } + }); myResultsPreviewTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java index a06a2efcee42..64d245d4512e 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/AbstractProjectViewPane.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. diff --git a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java index c7fb3d8659f6..df91d3ea19fd 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/BaseRefactoringProcessor.java @@ -543,7 +543,7 @@ public abstract class BaseRefactoringProcessor implements Runnable { return; } if (ApplicationManager.getApplication().isWriteAccessAllowed()) { - LOG.error(new Exception()); + LOG.error("Refactorings should not be started inside write action\n because they start progress inside and any read action from the progress task would cause the deadlock", new Exception()); DumbService.getInstance(myProject).smartInvokeLater(new Runnable() { @Override public void run() { diff --git a/platform/platform-api/src/com/intellij/ide/Prefs.java b/platform/platform-api/src/com/intellij/ide/Prefs.java new file mode 100644 index 000000000000..9efb3b2a33be --- /dev/null +++ b/platform/platform-api/src/com/intellij/ide/Prefs.java @@ -0,0 +1,126 @@ +package com.intellij.ide; + +import com.intellij.openapi.util.Comparing; +import com.intellij.util.text.StringTokenizer; + +import java.util.Locale; +import java.util.prefs.Preferences; + +/** + * Utility class for working with Preferences + * todo: in one year the migration code could be removed + * @author Eugene Zhuravlev + * Date: 05-Mar-16 + */ +public class Prefs { + + public static void put(String key, String value) { + Preferences.userRoot().remove(key); // remove from old location + getPreferences(key).put(getNodeKey(key), value); + } + + public static String get(String key, String def) { + migrate(key, def, Preferences::get, Preferences::put); + return getPreferences(key).get(getNodeKey(key), def); + } + + public static void putInt(String key, int value) { + Preferences.userRoot().remove(key); // remove from old location + getPreferences(key).putInt(getNodeKey(key), value); + } + + public static int getInt(String key, int def) { + migrate(key, def, Preferences::getInt, Preferences::putInt); + return getPreferences(key).getInt(getNodeKey(key), def); + } + + public static void putLong(String key, long value) { + Preferences.userRoot().remove(key); // remove from old location + getPreferences(key).putLong(getNodeKey(key), value); + } + + public static long getLong(String key, long def) { + migrate(key, def, Preferences::getLong, Preferences::putLong); + return getPreferences(key).getLong(getNodeKey(key), def); + } + + public static void putBoolean(String key, boolean value) { + Preferences.userRoot().remove(key); // remove from old location + getPreferences(key).putBoolean(getNodeKey(key), value); + } + + public static boolean getBoolean(String key, boolean def) { + migrate(key, def, Preferences::getBoolean, Preferences::putBoolean); + return getPreferences(key).getBoolean(getNodeKey(key), def); + } + + public static void putFloat(String key, float value) { + Preferences.userRoot().remove(key); // remove from old location + getPreferences(key).putFloat(getNodeKey(key), value); + } + + public static float getFloat(String key, float def) { + migrate(key, def, Preferences::getFloat, Preferences::putFloat); + return getPreferences(key).getFloat(getNodeKey(key), def); + } + + public static void putDouble(String key, double value) { + Preferences.userRoot().remove(key); // remove from old location + getPreferences(key).putDouble(getNodeKey(key), value); + } + + public static double getDouble(String key, double def) { + migrate(key, def, Preferences::getDouble, Preferences::putDouble); + return getPreferences(key).getDouble(getNodeKey(key), def); + } + + public static void putByteArray(String key, byte[] value) { + Preferences.userRoot().remove(key); // remove from old location + getPreferences(key).putByteArray(getNodeKey(key), value); + } + + public static byte[] getByteArray(String key, byte[] def) { + migrate(key, def, Preferences::getByteArray, Preferences::putByteArray); + return getPreferences(key).getByteArray(getNodeKey(key), def); + } + + public static void remove(String key) { + getPreferences(key).remove(getNodeKey(key)); + } + + private static String getNodeKey(String key) { + final int dotIndex = key.lastIndexOf('.'); + return (dotIndex >= 0 ? key.substring(dotIndex + 1) : key).toLowerCase(Locale.US); + } + + private static Preferences getPreferences(String key) { + Preferences prefs = Preferences.userRoot(); + final int dotIndex = key.lastIndexOf('.'); + if (dotIndex > 0) { + final StringTokenizer tokenizer = new StringTokenizer(key.substring(0, dotIndex), ".", false); + while (tokenizer.hasMoreElements()) { + prefs = prefs.node(tokenizer.nextElement().toLowerCase(Locale.US)); + } + } + return prefs; + } + + private interface Getter { + T get(Preferences prefs, String key, T def); + } + + private interface Setter { + void set(Preferences prefs, String key, T value); + } + + private static void migrate(String key, T def, Getter getter, Setter setter) { + // rewrite from old location into the new one + final Preferences prefs = Preferences.userRoot(); + final T val = getter.get(prefs, key, def); + if (!Comparing.equal(val, def)) { + setter.set(getPreferences(key), getNodeKey(key), val); + prefs.remove(key); + } + } + +} diff --git a/platform/platform-api/src/com/intellij/ide/PrivacyPolicy.java b/platform/platform-api/src/com/intellij/ide/PrivacyPolicy.java new file mode 100644 index 000000000000..fb00a542ea1e --- /dev/null +++ b/platform/platform-api/src/com/intellij/ide/PrivacyPolicy.java @@ -0,0 +1,257 @@ +/* + * Copyright 2000-2016 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; + +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.*; + +/** + * @author Eugene Zhuravlev + * Date: 09-Mar-16 + */ +public final class PrivacyPolicy { + private static final Logger LOG = Logger.getInstance("#com.intellij.ide.PrivacyPolicy"); + private static final String CACHED_RESOURCE_NAME = "Cached"; + private static final String RELATIVE_RESOURCE_PATH = "JetBrains/PrivacyPolicy"; + private static final String VERSION_COMMENT_START = ""; + private static final String ACCEPTED_VERSION_KEY = "JetBrains.privacy_policy.accepted_version"; + private static final Version EMBEDDED_VERSION = new Version(1, 0); + @Nullable + private static volatile Version ourLatestVersion; + + private static final File ourCachedPolicyFile; + static { + File dataDir = null; + if (SystemInfo.isWindows) { + final String appdata = System.getenv("APPDATA"); + if (appdata != null) { + dataDir = new File(appdata, RELATIVE_RESOURCE_PATH); + } + } + else { + final String userHome = System.getProperty("user.home"); + if (userHome != null) { + if (SystemInfo.isMac) { + final File dataRoot = new File(userHome, "/Library/Application Support"); + if (dataRoot.exists()) { + dataDir = new File(dataRoot, RELATIVE_RESOURCE_PATH); + } + } + else if (SystemInfo.isUnix) { + final String dataHome = System.getenv("XDG_DATA_HOME"); + final File dataRoot = dataHome == null ? new File(userHome, ".local/share") : new File(dataHome); + if (dataRoot.exists()) { + dataDir = new File(dataRoot, RELATIVE_RESOURCE_PATH); + } + } + } + } + if (dataDir == null) { + // default location + dataDir = new File(PathManager.getSystemPath(), "PrivacyPolicy"); + } + dataDir.mkdirs(); + ourCachedPolicyFile = new File(dataDir, CACHED_RESOURCE_NAME); + } + + public static boolean isLatestVersionAccepted() { + return getAcceptedVersion().equals(getLatestVersion()); + } + + public static void setVersionAccepted(@NotNull Version version) { + if (version.isUnknown()) { + Prefs.remove(ACCEPTED_VERSION_KEY); + } + else { + Prefs.put(ACCEPTED_VERSION_KEY, version.toString()); + } + } + + @NotNull + public static Version getLatestVersion() { + final Version cached = ourLatestVersion; + if (cached != null) { + return cached; + } + Version latest = EMBEDDED_VERSION; + if (ourCachedPolicyFile.exists()) { + try { + final Version version = loadVersion(new FileInputStream(ourCachedPolicyFile)); + if (!version.isUnknown() && version.compareTo(latest) > 0) { + latest = version; + } + } + catch (FileNotFoundException ignored) { + } + } + ourLatestVersion = latest; + return latest; + } + + @NotNull + public static Version getAcceptedVersion() { + return new Version(Prefs.get(ACCEPTED_VERSION_KEY, null)); + } + + public static String getText() { + return getText(getLatestVersion()); + } + + @NotNull + public static String getText(@NotNull Version version) { + String text = null; + try { + if (EMBEDDED_VERSION.equals(version)) { + text = loadText(PrivacyPolicy.class.getResourceAsStream("/PrivacyPolicy-" + EMBEDDED_VERSION + ".html")); + } + else { + text = loadText(new FileInputStream(ourCachedPolicyFile)); + } + } + catch (Exception ignored) { + } + return text == null? "" : text; + } + + public static void updateText(String text) { + try { + FileUtil.writeToFile(ourCachedPolicyFile, text); + } + catch (IOException e) { + LOG.info(e); + } + finally { + ourLatestVersion = null; // clear cache + } + } + + @Nullable + private static String loadText(InputStream stream) { + try { + if (stream != null) { + final Reader reader = new InputStreamReader(stream, "utf-8"); + try { + return new String(FileUtil.adaptiveLoadText(reader)); + } + finally { + reader.close(); + } + } + } + catch (IOException e) { + LOG.info(e); + } + return null; + } + + @NotNull + private static Version loadVersion(final InputStream is) { + try { + final BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8")); + try { + final String line = reader.readLine(); + if (line != null) { + final int startComment = line.indexOf(VERSION_COMMENT_START); + if (startComment >= 0 ) { + final int endComment = line.indexOf(VERSION_COMMENT_END); + if (endComment > startComment) { + return new Version(line.substring(startComment + VERSION_COMMENT_START.length(), endComment).trim()); + } + } + } + } + finally { + reader.close(); + } + } + catch (IOException e) { + LOG.info(e); + } + return Version.UNKNOWN; + } + + public static final class Version implements Comparable{ + public static final Version UNKNOWN = new Version(-1, -1); + + private final int myMajor; + private final int myMinor; + + /** + * @param version string in format "[major].[minor]" + */ + public Version(@Nullable String version) { + final int dot = version == null? -1 : version.indexOf('.'); + if (dot > 0) { + myMajor = Integer.parseInt(version.substring(0, dot)); + myMinor = Integer.parseInt(version.substring(dot + 1)); + } + else { + myMajor = -1; + myMinor = -1; + } + } + + private Version(int major, int minor) { + myMajor = major; + myMinor = minor; + } + + public boolean isUnknown() { + return myMajor < 0 || myMinor < 0; + } + + @Override + public int compareTo(Version other) { + if (isUnknown()) { + return other.isUnknown()? 0 : -1; + } + final int majorDiff = myMajor - other.myMajor; + return majorDiff != 0? majorDiff : myMinor - other.myMinor; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Version version = (Version)o; + + if (myMajor != version.myMajor) return false; + if (myMinor != version.myMinor) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myMajor; + result = 31 * result + myMinor; + return result; + } + + @Override + public String toString() { + return isUnknown()? "unknown" : myMajor + "." + myMinor; + } + } +} diff --git a/platform/platform-api/src/com/intellij/ui/components/MacScrollBarUI.java b/platform/platform-api/src/com/intellij/ui/components/MacScrollBarUI.java index 23068a0f8e17..00ee6dd6cef2 100644 --- a/platform/platform-api/src/com/intellij/ui/components/MacScrollBarUI.java +++ b/platform/platform-api/src/com/intellij/ui/components/MacScrollBarUI.java @@ -31,8 +31,10 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Collections; +import java.util.Iterator; import java.util.List; import static com.intellij.ui.mac.foundation.Foundation.*; @@ -42,7 +44,7 @@ import static com.intellij.ui.mac.foundation.Foundation.*; */ final class MacScrollBarUI extends DefaultScrollBarUI { private static final RegistryValue DISABLED = Registry.get("ide.mac.disableMacScrollbars"); - private static final List UI = Collections.synchronizedList(new ArrayList()); + private static final List> UI = new ArrayList<>(); private final Alarm myAlarm = new Alarm(); private boolean myTrackHovered; @@ -119,16 +121,45 @@ final class MacScrollBarUI extends DefaultScrollBarUI { public void installUI(JComponent c) { super.installUI(c); updateStyle(Style.CURRENT.get()); - UI.add(this); + processReferences(this, null, null); } @Override public void uninstallUI(JComponent c) { - UI.remove(this); + processReferences(null, this, null); myAlarm.cancelAllRequests(); super.uninstallUI(c); } + /** + * Processes references in the static list of references synchronously. + * This method removes all cleared references and the reference specified to remove, + * collects objects from other references into the specified list and + * adds the reference specified to add. + * + * @param toAdd the object to add to the static list of references (ignored if {@code null}) + * @param toRemove the object to remove from the static list of references (ignored if {@code null}) + * @param list the list to collect all available objects (ignored if {@code null}) + */ + private static void processReferences(MacScrollBarUI toAdd, MacScrollBarUI toRemove, List list) { + synchronized (UI) { + Iterator> iterator = UI.iterator(); + while (iterator.hasNext()) { + Reference reference = iterator.next(); + MacScrollBarUI ui = reference.get(); + if (ui == null || ui == toRemove) { + iterator.remove(); + } + else if (list != null) { + list.add(ui); + } + } + if (toAdd != null) { + UI.add(new WeakReference(toAdd)); + } + } + } + private void updateStyle(Style style) { if (myScrollBar != null) { myScrollBar.setOpaque(style != Style.Overlay); @@ -209,7 +240,9 @@ final class MacScrollBarUI extends DefaultScrollBarUI { if (!DISABLED.asBoolean() && SystemInfo.isMacOSMountainLion) super.run(); Style newStyle = get(); if (newStyle != oldStyle) { - for (MacScrollBarUI ui : UI.toArray(new MacScrollBarUI[0])) { + List list = new ArrayList<>(); + processReferences(null, null, list); + for (MacScrollBarUI ui : list) { ui.updateStyle(newStyle); } } diff --git a/platform/platform-api/src/com/intellij/util/ui/NSScrollerHelper.java b/platform/platform-api/src/com/intellij/util/ui/NSScrollerHelper.java index 6498ed4e063b..09a0b92cf6b4 100644 --- a/platform/platform-api/src/com/intellij/util/ui/NSScrollerHelper.java +++ b/platform/platform-api/src/com/intellij/util/ui/NSScrollerHelper.java @@ -23,8 +23,12 @@ import com.sun.jna.Pointer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.event.EventListenerList; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.EventListener; +import java.util.Iterator; +import java.util.List; import static com.intellij.ui.mac.foundation.Foundation.invoke; @@ -57,7 +61,7 @@ class NSScrollerHelper { public enum Style {Legacy, Overlay} private static ClickBehavior ourClickBehavior = null; - private static final EventListenerList ourStyleListeners = new EventListenerList(); + private static final List> ourStyleListeners = new ArrayList<>(); static { if (SystemInfo.isMac) { @@ -152,19 +156,37 @@ class NSScrollerHelper { } public static void addScrollbarStyleListener(@NotNull ScrollbarStyleListener listener) { - ourStyleListeners.add(ScrollbarStyleListener.class, listener); + processReferences(listener, null, null); } public static void removeScrollbarStyleListener(@NotNull ScrollbarStyleListener listener) { - ourStyleListeners.remove(ScrollbarStyleListener.class, listener); + processReferences(null, listener, null); + } + + private static void processReferences(ScrollbarStyleListener toAdd, ScrollbarStyleListener toRemove, List list) { + synchronized (ourStyleListeners) { + Iterator> iterator = ourStyleListeners.iterator(); + while (iterator.hasNext()) { + Reference reference = iterator.next(); + ScrollbarStyleListener ui = reference.get(); + if (ui == null || ui == toRemove) { + iterator.remove(); + } + else if (list != null) { + list.add(ui); + } + } + if (toAdd != null) { + ourStyleListeners.add(new WeakReference(toAdd)); + } + } } private static void fireStyleChanged() { - Object[] listeners = ourStyleListeners.getListenerList(); - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ScrollbarStyleListener.class) { - ((ScrollbarStyleListener)listeners[i + 1]).styleChanged(); - } + List list = new ArrayList<>(); + processReferences(null, null, list); + for (ScrollbarStyleListener listener : list) { + listener.styleChanged(); } } diff --git a/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java b/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java index d77604988e49..fdb3bd48a5fa 100644 --- a/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java +++ b/platform/platform-impl/src/com/intellij/concurrency/ApplierCompleter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,12 +21,12 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.util.Processor; import com.intellij.util.concurrency.AtomicFieldUpdater; -import jsr166e.CountedCompleter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.concurrent.CountedCompleter; /** * Executes processor on array elements in range from lo (inclusive) to hi (exclusive). @@ -38,7 +38,7 @@ import java.util.List; * After that, the task completes itself. * The process of completing traverses task parent hierarchy, decrementing each pending count until it either * decrements not-zero pending count and stops or - * reaches the top, in which case it invokes {@link jsr166e.ForkJoinTask#quietlyComplete()} which causes the top level task to wake up and join successfully. + * reaches the top, in which case it invokes {@link java.util.concurrent.ForkJoinTask#quietlyComplete()} which causes the top level task to wake up and join successfully. * The exceptions from the sub tasks bubble up to the top and saved in {@link #throwable}. */ class ApplierCompleter extends CountedCompleter { @@ -55,7 +55,7 @@ class ApplierCompleter extends CountedCompleter { private static final AtomicFieldUpdater throwableUpdater = AtomicFieldUpdater.forFieldOfType(ApplierCompleter.class, Throwable.class); // if not null, the read action has failed and this list contains unfinished subtasks - private List> failedSubTasks; + private final Collection> failedSubTasks; //private final List children = new ArrayList(); @@ -72,6 +72,7 @@ class ApplierCompleter extends CountedCompleter { @NotNull Processor processor, int lo, int hi, + @NotNull Collection> failedSubTasks, ApplierCompleter next) { super(parent); this.runInReadAction = runInReadAction; @@ -80,28 +81,20 @@ class ApplierCompleter extends CountedCompleter { this.processor = processor; this.lo = lo; this.hi = hi; + this.failedSubTasks = failedSubTasks; this.next = next; } @Override public void compute() { - wrapInReadActionAndIndicator(new Runnable() { - @Override - public void run() { - execAndForkSubTasks(); - } - }); + wrapInReadActionAndIndicator(this::execAndForkSubTasks); } private void wrapInReadActionAndIndicator(@NotNull final Runnable process) { - Runnable toRun = runInReadAction ? new Runnable() { - @Override - public void run() { - if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(process)) { - failedSubTasks = new ArrayList>(); - failedSubTasks.add(ApplierCompleter.this); - doComplete(throwable); - } + Runnable toRun = runInReadAction ? () -> { + if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(process)) { + failedSubTasks.add(this); + doComplete(throwable); } } : process; ProgressIndicator existing = ProgressManager.getInstance().getProgressIndicator(); @@ -122,6 +115,7 @@ class ApplierCompleter extends CountedCompleter { long start = System.currentTimeMillis(); ApplierCompleter right = null; Throwable throwable = null; + try { for (int i = lo; i < hi; ++i) { progressIndicator.checkCanceled(); @@ -132,7 +126,7 @@ class ApplierCompleter extends CountedCompleter { long elapsed = finish - start; if (elapsed > 5 && hi - i >= 2 && getSurplusQueuedTaskCount() <= JobSchedulerImpl.CORES_COUNT) { int mid = i + hi >>> 1; - right = new ApplierCompleter(this, runInReadAction, progressIndicator, array, processor, mid, hi, right); + right = new ApplierCompleter<>(this, runInReadAction, progressIndicator, array, processor, mid, hi, failedSubTasks, right); //children.add(right); addToPendingCount(1); right.fork(); @@ -223,34 +217,23 @@ class ApplierCompleter extends CountedCompleter { } boolean completeTaskWhichFailToAcquireReadAction() { - if (failedSubTasks == null) { - return true; - } final boolean[] result = {true}; // these tasks could not be executed in the other thread; do them here for (final ApplierCompleter task : failedSubTasks) { - task.failedSubTasks = null; - task.wrapInReadActionAndIndicator(new Runnable() { - @Override - public void run() { - for (int i = task.lo; i < task.hi; ++i) { - if (!task.processor.process(task.array.get(i))) { - result[0] = false; - break; - } + task.wrapInReadActionAndIndicator(() -> { + for (int i = task.lo; i < task.hi; ++i) { + if (!task.processor.process(task.array.get(i))) { + result[0] = false; + break; } } }); - if (task.failedSubTasks != null) { - result[0] = false; - break; - } } return result[0]; } @Override public String toString() { - return System.identityHashCode(this) + " ("+lo+"-"+hi+")"; + return "("+lo+"-"+hi+")"+(getCompleter() == null ? "" : " parent: "+getCompleter()); } } diff --git a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java index fc705c315f06..9650b9deb1c1 100644 --- a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java +++ b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java @@ -15,7 +15,6 @@ */ package com.intellij.concurrency; -import com.intellij.Patches; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; @@ -25,64 +24,20 @@ import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; import com.intellij.util.Processor; import com.intellij.util.io.storage.HeavyProcessLatch; -import jsr166e.ForkJoinPool; -import jsr166e.ForkJoinTask; -import jsr166e.ForkJoinWorkerThread; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Queue; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; /** * @author cdr */ public class JobLauncherImpl extends JobLauncher { - private static final AtomicLong bits = new AtomicLong(); - static { - assert Patches.USE_REFLECTION_TO_ACCESS_JDK8 : "Please port to java.util.concurrent.ForkJoinPool"; - } - private static final ForkJoinPool.ForkJoinWorkerThreadFactory FACTORY = new ForkJoinPool.ForkJoinWorkerThreadFactory() { - @Override - public ForkJoinWorkerThread newThread(ForkJoinPool pool) { - final int n = addThread(); - ForkJoinWorkerThread thread = new ForkJoinWorkerThread(pool) { - @Override - protected void onTermination(Throwable exception) { - finishThread(n); - super.onTermination(exception); - } - }; - thread.setName("JobScheduler FJ pool "+ n +"/"+ JobSchedulerImpl.CORES_COUNT); - return thread; - } - - private int addThread() { - boolean set; - int n; - do { - long l = bits.longValue(); - long next = (l + 1) | l; - n = Long.numberOfTrailingZeros(l + 1); - set = bits.compareAndSet(l, next); - } while (!set); - return n; - } - private void finishThread(int n) { - boolean set; - do { - long l = bits.get(); - long next = l & ~(1L << n); - set = bits.compareAndSet(l, next); - } while (!set); - } - }; - - private static final ForkJoinPool pool = new ForkJoinPool(JobSchedulerImpl.CORES_COUNT, FACTORY, null, false); static final int CORES_FORK_THRESHOLD = 1; @Override @@ -99,9 +54,10 @@ public class JobLauncherImpl extends JobLauncher { HeavyProcessLatch.INSTANCE.stopThreadPrioritizing(); - ApplierCompleter applier = new ApplierCompleter<>(null, runInReadAction, wrapper, things, thingProcessor, 0, things.size(), null); + List> failedSubTasks = Collections.synchronizedList(new ArrayList<>()); + ApplierCompleter applier = new ApplierCompleter<>(null, runInReadAction, wrapper, things, thingProcessor, 0, things.size(), failedSubTasks, null); try { - pool.invoke(applier); + ForkJoinPool.commonPool().invoke(applier); if (applier.throwable != null) throw applier.throwable; } catch (ApplierCompleter.ComputationAbortedException e) { @@ -217,7 +173,7 @@ public class JobLauncherImpl extends JobLauncher { } private void submit() { - pool.submit(myForkJoinTask); + ForkJoinPool.commonPool().submit(myForkJoinTask); } //////////////// Job @@ -282,8 +238,8 @@ public class JobLauncherImpl extends JobLauncher { catch (CancellationException e) { // was canceled in the middle of execution // can't do anything but wait. help other tasks in the meantime - if (Thread.currentThread() instanceof ForkJoinWorkerThread) { // if called outside FJP the FJTask.fork() starts up commonPool which is undesirable - pool.awaitQuiescence(millis, TimeUnit.MILLISECONDS); + if (!isDone()) { + ForkJoinPool.commonPool().awaitQuiescence(millis, TimeUnit.MILLISECONDS); } } } @@ -365,7 +321,7 @@ public class JobLauncherImpl extends JobLauncher { List> tasks = new ArrayList<>(); for (int i = 0; i < JobSchedulerImpl.CORES_COUNT; i++) { - tasks.add(pool.submit(new MyTask(i))); + tasks.add(ForkJoinPool.commonPool().submit(new MyTask(i))); } boolean result = true; diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java index 9405d6670bea..197edec791ae 100644 --- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java +++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java @@ -16,6 +16,7 @@ package com.intellij.idea; import com.intellij.ide.BrowserUtil; +import com.intellij.ide.PrivacyPolicy; import com.intellij.ide.customize.CustomizeIDEWizardDialog; import com.intellij.ide.customize.CustomizeIDEWizardStepsProvider; import com.intellij.ide.plugins.PluginManagerCore; @@ -152,6 +153,23 @@ public class StartupUtil { if (!Main.isHeadless()) { AppUIUtil.updateWindowIcon(JOptionPane.getRootFrame()); AppUIUtil.registerBundledFonts(); + if (!PrivacyPolicy.isLatestVersionAccepted()) { + final PrivacyPolicy.Version latestVersion = PrivacyPolicy.getLatestVersion(); + final String text = PrivacyPolicy.getText(latestVersion); + if (!text.isEmpty()) { + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + showPrivacyPolicyAgreement(text); + } + }); + PrivacyPolicy.setVersionAccepted(latestVersion); + } + catch (Exception ignored) { + } + } + } } appStarter.start(newConfigFolder); @@ -448,10 +466,16 @@ public class StartupUtil { }); viewer.setText(htmlText); StyleSheet styleSheet = ((HTMLDocument)viewer.getDocument()).getStyleSheet(); - styleSheet.addRule("body {font-size:" + JBUI.scaleFontSize(17) + "pt;}"); - styleSheet.addRule("h4 {font-size:" + JBUI.scaleFontSize(18) + "pt;}"); + styleSheet.addRule("body {font-family: \"Segoe UI\", Tahoma, sans-serif;}"); + styleSheet.addRule("body {margin-top:0;padding-top:0;}"); + styleSheet.addRule("body {font-size:" + JBUI.scaleFontSize(13) + "pt;}"); + styleSheet.addRule("h2, em {margin-top:" + JBUI.scaleFontSize(20) + "pt;}"); + styleSheet.addRule("h1, h2, h3, p, h4, em {margin-bottom:0;padding-bottom:0;}"); + styleSheet.addRule("p, h1 {margin-top:0;padding-top:"+JBUI.scaleFontSize(6)+"pt;}"); + styleSheet.addRule("li {margin-bottom:" + JBUI.scaleFontSize(6) + "pt;}"); + styleSheet.addRule("h2 {margin-top:0;padding-top:"+JBUI.scaleFontSize(13)+"pt;}"); viewer.setCaretPosition(0); - viewer.setBorder(JBUI.Borders.empty(5)); + viewer.setBorder(JBUI.Borders.empty(0, 5, 5, 5)); centerPanel.add(new JLabel("Please read and accept these terms and conditions:"), BorderLayout.NORTH); centerPanel .add(new JBScrollPane(viewer, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER), diff --git a/platform/platform-impl/src/com/intellij/notification/EventLog.java b/platform/platform-impl/src/com/intellij/notification/EventLog.java index ee8871d590cc..f239624650c3 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLog.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -31,7 +31,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.ShutDownTracker; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.Trinity; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.*; import com.intellij.ui.awt.RelativePoint; @@ -535,8 +538,7 @@ public class EventLog { if (target != null) { IdeFrame frame = WindowManager.getInstance().getIdeFrame(project); assert frame != null; - Balloon balloon = NotificationsManagerImpl.createBalloon(frame, myNotification, true, true, null); - Disposer.register(project, balloon); + Balloon balloon = NotificationsManagerImpl.createBalloon(frame, myNotification, true, true, null, project); balloon.show(target, Balloon.Position.above); } } diff --git a/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java index 7952ad2a6278..e56eca06b402 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,6 +21,7 @@ import com.intellij.ide.ui.laf.darcula.ui.DarculaButtonPainter; import com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI; import com.intellij.notification.*; import com.intellij.notification.impl.ui.NotificationsUtil; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; @@ -228,8 +229,7 @@ public class NotificationsManagerImpl extends NotificationsManager { final boolean noProjects = projectManager.getOpenProjects().length == 0; final boolean sticky = NotificationDisplayType.STICKY_BALLOON == displayType || noProjects; Ref layoutDataRef = newEnabled() ? new Ref() : null; - final Balloon balloon = createBalloon((IdeFrame)window, notification, false, false, layoutDataRef); - Disposer.register(project != null ? project : ApplicationManager.getApplication(), balloon); + final Balloon balloon = createBalloon((IdeFrame)window, notification, false, false, layoutDataRef, project != null ? project : ApplicationManager.getApplication()); if (notification.isExpired()) { return null; @@ -295,8 +295,9 @@ public class NotificationsManagerImpl extends NotificationsManager { @NotNull final Notification notification, final boolean showCallout, final boolean hideOnClickOutside, - @Nullable Ref layoutDataRef) { - return createBalloon(window.getComponent(), notification, showCallout, hideOnClickOutside, layoutDataRef); + @Nullable Ref layoutDataRef, + @NotNull Disposable parentDisposable) { + return createBalloon(window.getComponent(), notification, showCallout, hideOnClickOutside, layoutDataRef, parentDisposable); } @NotNull @@ -304,9 +305,12 @@ public class NotificationsManagerImpl extends NotificationsManager { @NotNull final Notification notification, final boolean showCallout, final boolean hideOnClickOutside, - @Nullable Ref layoutDataRef) { + @Nullable Ref layoutDataRef, + @NotNull Disposable parentDisposable) { if (layoutDataRef != null) { - return createNewBalloon(windowComponent, notification, showCallout, hideOnClickOutside, layoutDataRef); + Balloon balloon = createNewBalloon(windowComponent, notification, showCallout, hideOnClickOutside, layoutDataRef); + Disposer.register(parentDisposable, balloon); + return balloon; } final JEditorPane text = new JEditorPane(); @@ -380,6 +384,7 @@ public class NotificationsManagerImpl extends NotificationsManager { final Balloon balloon = builder.createBalloon(); balloon.setAnimationEnabled(false); notification.setBalloon(balloon); + Disposer.register(parentDisposable, balloon); return balloon; } diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index 2030906c2e9a..1f9f0fcd1ded 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -17,7 +17,7 @@ package com.intellij.openapi.application.impl; import com.intellij.BundleBase; import com.intellij.CommonBundle; -import com.intellij.Patches; +import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory; import com.intellij.diagnostic.LogEventException; import com.intellij.diagnostic.PerformanceWatcher; import com.intellij.diagnostic.ThreadDumper; @@ -77,12 +77,12 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.ide.PooledThreadExecutor; import org.picocontainer.MutablePicoContainer; +import sun.awt.AWTAccessor; import javax.swing.*; import java.awt.*; import java.io.File; import java.io.IOException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; @@ -168,6 +168,10 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App } }; + static { + IdeaForkJoinWorkerThreadFactory.setupForkJoinCommonPool(); + } + public ApplicationImpl(boolean isInternal, boolean isUnitTestMode, boolean isHeadless, @@ -1077,15 +1081,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App private static Thread getEventQueueThread() { EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue(); - try { - // use sun.awt.AWTAccessor.EventQueueAccessor? - assert Patches.USE_REFLECTION_TO_ACCESS_JDK8; - Method method = ReflectionUtil.getDeclaredMethod(EventQueue.class, "getDispatchThread"); - return (Thread)method.invoke(eventQueue); - } - catch (Exception e) { - throw new RuntimeException(e); - } + return AWTAccessor.getEventQueueAccessor().getDispatchThread(eventQueue); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java index ce4f2dbf54cf..7f4a76a8558a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/ServiceManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -182,7 +182,7 @@ public class ServiceManagerImpl implements BaseComponent { private final ServiceDescriptor myDescriptor; private final PluginDescriptor myPluginDescriptor; private final ComponentManagerEx myComponentManager; - private volatile Object myInitializedComponentInstance = null; + private volatile Object myInitializedComponentInstance; public MyComponentAdapter(final ServiceDescriptor descriptor, final PluginDescriptor pluginDescriptor, ComponentManagerEx componentManager) { myDescriptor = descriptor; diff --git a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java index b478f7f829a6..cf0d89d8a3ee 100644 --- a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java @@ -917,8 +917,6 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui { Toolkit.getDefaultToolkit().removeAWTEventListener(myAwtActivityListener); if (myLayeredPane != null) { myLayeredPane.removeComponentListener(myComponentListener); - Disposer.register(ApplicationManager.getApplication(), - this); // to be safe if Application suddenly exits and animation wouldn't have a chance to complete runAnimation(false, myLayeredPane, disposeRunnable); } diff --git a/platform/platform-resources-en/src/messages/DiffBundle.properties b/platform/platform-resources-en/src/messages/DiffBundle.properties index ac08cc3ddaff..e433aa8232d6 100644 --- a/platform/platform-resources-en/src/messages/DiffBundle.properties +++ b/platform/platform-resources-en/src/messages/DiffBundle.properties @@ -9,7 +9,7 @@ unknown.file.type.error=Unknown file type: {0} save.merge.result.command.name=Merge compare.file.vs.file.dialog.title={0} vs {1} diff.content.editor.content.title=Editor -diff.content.clipboard.content.title=Clipboard +diff.content.clipboard.content.title=From \u0441lipboard diff.clipboard.vs.editor.dialog.title=Clipboard vs Editor diff.clipboard.vs.file.dialog.title=Clipboard vs {0} diff.content.selection.from.editor.content.title=Selection from Editor diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 6b73096a1039..ce1fec43b296 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -271,6 +271,7 @@ inspection.javadoc.problem.descriptor=Required Javadoc is absent inspection.javadoc.problem.descriptor1=Period in the documentation is missing. The period is used by the Javadoc tool to generate the comment for the overview page inspection.javadoc.problem.missing.tag=Required tag {0} is missing inspection.javadoc.problem.missing.tag.description={0} is missing after @{1} tag +inspection.javadoc.problem.see.tag.expecting.ref=Class or method reference is expected after @see tag inspection.javadoc.problem.cannot.resolve=Cannot resolve symbol {0} inspection.javadoc.problem.name.expected=Name expected inspection.javadoc.problem.wrong.tag=Wrong tag {0} @@ -423,7 +424,7 @@ inspection.dead.code.problem.synopsis21=Method is never used as a member of this inspection.dead.code.problem.synopsis22=Method overrides a library method but
  • its {0} is never instantiated OR
  • its {0} instantiation is not reachable from entry points.
inspection.dead.code.problem.synopsis23={0} is not implemented. inspection.dead.code.problem.synopsis24={0} has an implementation but
  • it is never instantiated OR
  • no instantiations are reachable from entry points.
-inspection.dead.code.problem.synopsis25={0} has {1, choice, 1#direct or indirect implementation|2#{1,number} direct or indirect implementations} but
  • they are never instantiated OR
  • no instantiations are reachable from entry points.
+inspection.dead.code.problem.synopsis25={0} has {1, choice, 1#direct or indirect implementation|2#{1,number} direct or indirect implementations} but
  • \u2014they are never instantiated OR
  • \u2014no instantiations are reachable from entry points.
inspection.dead.code.problem.synopsis26.constructor=Constructor is never used. inspection.dead.code.problem.synopsis27.constructor=Constructor has usage(s) but they all belong to calls chain that has no members reachable from entry points. inspection.dead.code.problem.synopsis28.constructor=Constructor has one usage but it is not reachable from entry points. @@ -662,6 +663,7 @@ annotate.overridden.methods.as.notnull=Annotate overridden methods as ''@{0}'' nullable.stuff.problems.overridden.methods.are.not.annotated=Overridden methods are not annotated nullable.stuff.problems.overridden.method.parameters.are.not.annotated=Overridden method parameters are not annotated annotate.overridden.methods.parameters=Annotate overridden method parameters as ''@{0}'' +annotate.overridden.methods.parameters.family.name=Annotate overridden method parameters offline.inspections.library.was.not.resolved=Please configure library ''{0}'' which is used in module ''{1}'' report.suspicious.but.possibly.correct.method.calls=&Report suspicious but possibly correct method calls unused.library.display.name=Unused library diff --git a/platform/script-debugger/backend/src/StandaloneVmHelper.kt b/platform/script-debugger/backend/src/StandaloneVmHelper.kt index a263b4e5a9ec..782e6ab8c0c4 100644 --- a/platform/script-debugger/backend/src/StandaloneVmHelper.kt +++ b/platform/script-debugger/backend/src/StandaloneVmHelper.kt @@ -61,7 +61,7 @@ open class StandaloneVmHelper(private val vm: Vm, private val messageProcessor: messageProcessor.send(disconnectRequest) .rejected { if (it.message != CONNECTION_CLOSED_MESSAGE) { - LOG.error(it) + Promise.logError(LOG, it) } } // we don't wait response because 1) no response to "disconnect" message (V8 for example) 2) closed message manager just ignore any incoming messages diff --git a/platform/script-debugger/debugger-ui/src/DebugProcessImpl.kt b/platform/script-debugger/debugger-ui/src/DebugProcessImpl.kt index 5a5ed158d4cb..d3df02dc8f18 100644 --- a/platform/script-debugger/debugger-ui/src/DebugProcessImpl.kt +++ b/platform/script-debugger/debugger-ui/src/DebugProcessImpl.kt @@ -41,6 +41,7 @@ interface MultiVmDebugProcess { val mainVm: Vm? val activeOrMainVm: Vm? val childConnections: List> + get() = emptyList() } abstract class DebugProcessImpl>(session: XDebugSession, @@ -256,15 +257,8 @@ abstract class DebugProcessImpl>(session: XDebugSession, protected fun addChildVm(vm: Vm) { beforeInitBreakpoints(vm) - val breakpointManager = XDebuggerManager.getInstance(session.project).breakpointManager - @Suppress("UNCHECKED_CAST") - for (breakpointHandler in breakpointHandlers) { - if (breakpointHandler is LineBreakpointHandler) { - val breakpoints = runReadAction { breakpointManager.getBreakpoints(breakpointHandler.breakpointTypeClass) } - for (breakpoint in breakpoints) { - breakpointHandler.manager.setBreakpoint(vm, breakpoint) - } - } + processBreakpoints { handler, breakpoint -> + handler.manager.setBreakpoint(vm, breakpoint) } } @@ -276,6 +270,18 @@ abstract class DebugProcessImpl>(session: XDebugSession, } } } + + protected inline fun processBreakpoints(processor: (handler: LineBreakpointHandler, breakpoint: XLineBreakpoint<*>) -> Unit) { + val breakpointManager = XDebuggerManager.getInstance(session.project).breakpointManager + for (breakpointHandler in breakpointHandlers) { + if (breakpointHandler is LineBreakpointHandler) { + val breakpoints = runReadAction { breakpointManager.getBreakpoints(breakpointHandler.breakpointTypeClass) } + for (breakpoint in breakpoints) { + processor(breakpointHandler, breakpoint) + } + } + } + } } @Suppress("UNCHECKED_CAST") diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java index 899d467348d4..8cbb3fc8bcea 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertor.java @@ -23,7 +23,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.util.containers.ContainerUtil; -import gnu.trove.TIntObjectHashMap; +import com.intellij.util.containers.hash.HashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -31,7 +31,7 @@ import java.util.Set; public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsProcessor { - private final TIntObjectHashMap myNodeByIdMap = new TIntObjectHashMap(); + private final HashMap myNodeByIdMap = new HashMap<>(); private final Set myRunningTestNodes = ContainerUtil.newHashSet(); private final SMTestProxy.SMRootTestProxy myTestsRootProxy; private final Node myTestsRootNode; @@ -45,7 +45,7 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP @NotNull String testFrameworkName) { super(project, testFrameworkName); myTestsRootProxy = testsRootProxy; - myTestsRootNode = new Node(0, null, testsRootProxy); + myTestsRootNode = new Node(TreeNodeEvent.ROOT_NODE_ID, null, testsRootProxy); myNodeByIdMap.put(myTestsRootNode.getId(), myTestsRootNode); } @@ -169,12 +169,12 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP @Nullable private Node findValidParentNode(@NotNull BaseStartedNodeEvent startedNodeEvent) { - int parentId = startedNodeEvent.getParentId(); - if (parentId < 0) { - logProblem("Parent node id should be non-negative: " + startedNodeEvent + ".", true); + String parentId = startedNodeEvent.getParentId(); + if (parentId == null) { + logProblem("Parent node id should be defined: " + startedNodeEvent + ".", true); return null; } - Node parentNode = myNodeByIdMap.get(startedNodeEvent.getParentId()); + Node parentNode = myNodeByIdMap.get(parentId); if (parentNode == null) { logProblem("Parent node is undefined for " + startedNodeEvent + ".", true); return null; @@ -336,9 +336,9 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP } private boolean validateNodeId(@NotNull TreeNodeEvent treeNodeEvent) { - int nodeId = treeNodeEvent.getId(); - if (nodeId <= 0) { - logProblem("Node id should be positive: " + treeNodeEvent + ".", true); + String nodeId = treeNodeEvent.getId(); + if (nodeId == null || nodeId.equals(TreeNodeEvent.ROOT_NODE_ID)) { + logProblem("Node id should be initialized: " + treeNodeEvent + ".", true); return false; } return true; @@ -353,7 +353,7 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP } @Nullable - public SMTestProxy findProxyById(int id) { + public SMTestProxy findProxyById(@NotNull String id) { Node node = myNodeByIdMap.get(id); return node != null ? node.getProxy() : null; } @@ -413,19 +413,20 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP } private static class Node { - private final int myId; + private final String myId; private final Node myParentNode; private final SMTestProxy myProxy; private State myState; - Node(int id, @Nullable Node parentNode, @NotNull SMTestProxy proxy) { + Node(@Nullable String id, @Nullable Node parentNode, @NotNull SMTestProxy proxy) { myId = id; myParentNode = parentNode; myProxy = proxy; myState = State.NOT_RUNNING; } - public int getId() { + @Nullable + public String getId() { return myId; } @@ -472,7 +473,7 @@ public class GeneralIdBasedToSMTRunnerEventsConvertor extends GeneralTestEventsP @Override public int hashCode() { - return myId; + return myId != null ? myId.hashCode() : -1; } @Override diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/BaseStartedNodeEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/BaseStartedNodeEvent.java index 19231e1fac87..7d4a2a740055 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/BaseStartedNodeEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/BaseStartedNodeEvent.java @@ -22,15 +22,15 @@ import org.jetbrains.annotations.Nullable; public abstract class BaseStartedNodeEvent extends TreeNodeEvent { - private final int myParentId; + private final String myParentId; private final String myLocationUrl; private final String myNodeType; private final String myNodeArgs; private final boolean myRunning; protected BaseStartedNodeEvent(@Nullable String name, - int id, - int parentId, + @Nullable String id, + @Nullable String parentId, @Nullable final String locationUrl, @Nullable String nodeType, @Nullable String nodeArgs, @@ -44,9 +44,10 @@ public abstract class BaseStartedNodeEvent extends TreeNodeEvent { } /** - * @return parent node id (non-negative integer), or -1 if undefined + * @return parent node id, or null if undefined */ - public int getParentId() { + @Nullable + public String getParentId() { return myParentId; } @@ -76,8 +77,9 @@ public abstract class BaseStartedNodeEvent extends TreeNodeEvent { append(buf, "running", myRunning); } - public static int getParentNodeId(@NotNull MessageWithAttributes message) { - return TreeNodeEvent.getIntAttribute(message, "parentNodeId"); + @Nullable + public static String getParentNodeId(@NotNull MessageWithAttributes message) { + return TreeNodeEvent.getNodeId(message, "parentNodeId"); } @Nullable diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFailedEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFailedEvent.java index 1fd16a3afa16..9065828abdc7 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFailedEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFailedEvent.java @@ -68,7 +68,7 @@ public class TestFailedEvent extends TreeNodeEvent { @Nullable String comparisonFailureActualText, @Nullable String comparisonFailureExpectedText) { this(testName, - -1, + null, localizedFailureMessage, stackTrace, testError, @@ -79,7 +79,7 @@ public class TestFailedEvent extends TreeNodeEvent { } public TestFailedEvent(@Nullable String testName, - int id, + @Nullable String id, @NotNull String localizedFailureMessage, @Nullable String stackTrace, boolean testError, diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFinishedEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFinishedEvent.java index 5f520792da2a..eddd519b9734 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFinishedEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestFinishedEvent.java @@ -32,24 +32,24 @@ public class TestFinishedEvent extends TreeNodeEvent { this(testFinished.getTestName(), TreeNodeEvent.getNodeId(testFinished), duration, outputFile); } - public TestFinishedEvent(@Nullable String name, int id, long duration) { + public TestFinishedEvent(@Nullable String name, @Nullable String id, long duration) { this(name, id, duration, null); } - public TestFinishedEvent(@Nullable String name, int id, long duration, String outputFile) { + public TestFinishedEvent(@Nullable String name, @Nullable String id, long duration, String outputFile) { super(name, id); myDuration = duration; myOutputFile = outputFile; } public TestFinishedEvent(@NotNull String name, long duration) { - this(name, -1, duration); + this(name, null, duration); } /** @deprecated use {@link #TestFinishedEvent(String, long)} (to be removed in IDEA 16) */ @SuppressWarnings("unused") public TestFinishedEvent(@NotNull String name, int duration) { - this(name, -1, duration); + this(name, null, duration); } public long getDuration() { diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestIgnoredEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestIgnoredEvent.java index 408a51760bf9..500cecb109de 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestIgnoredEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestIgnoredEvent.java @@ -26,7 +26,7 @@ public class TestIgnoredEvent extends TreeNodeEvent { private final String myStacktrace; public TestIgnoredEvent(@NotNull String testName, @NotNull String ignoreComment, @Nullable String stacktrace) { - super(testName, -1); + super(testName, null); myIgnoreComment = ignoreComment; myStacktrace = stacktrace; } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestOutputEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestOutputEvent.java index 7af40f9bf027..846aa9406e33 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestOutputEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestOutputEvent.java @@ -30,7 +30,7 @@ public class TestOutputEvent extends TreeNodeEvent { } public TestOutputEvent(@NotNull String testName, @NotNull String text, boolean stdOut) { - super(testName, -1); + super(testName, null); myText = text; myStdOut = stdOut; } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestStartedEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestStartedEvent.java index 61bb3a607a5d..67ea2ba82a70 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestStartedEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestStartedEvent.java @@ -35,8 +35,8 @@ public class TestStartedEvent extends BaseStartedNodeEvent { } public TestStartedEvent(@Nullable String name, - int id, - int parentId, + @Nullable String id, + @Nullable String parentId, @Nullable final String locationUrl, @Nullable String nodeType, @Nullable String nodeArgs, @@ -51,7 +51,7 @@ public class TestStartedEvent extends BaseStartedNodeEvent { } public TestStartedEvent(@NotNull String name, @Nullable String locationUrl) { - super(name, -1, -1, locationUrl, null, null, true); + super(name, null, null, locationUrl, null, null, true); } public void setConfig(boolean config) { diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestSuiteFinishedEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestSuiteFinishedEvent.java index 3b7c36e0c87a..af456bd0ee2f 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestSuiteFinishedEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestSuiteFinishedEvent.java @@ -25,7 +25,7 @@ public class TestSuiteFinishedEvent extends TreeNodeEvent { } public TestSuiteFinishedEvent(@NotNull String name) { - super(name, -1); + super(name, null); } @Override diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestSuiteStartedEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestSuiteStartedEvent.java index 3242723722c6..3c1c1bae0931 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestSuiteStartedEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TestSuiteStartedEvent.java @@ -33,7 +33,7 @@ public class TestSuiteStartedEvent extends BaseStartedNodeEvent { } public TestSuiteStartedEvent(@NotNull String name, @Nullable String locationUrl) { - super(name, -1, -1, locationUrl, null, null, true); + super(name, null, null, locationUrl, null, null, true); } } diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TreeNodeEvent.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TreeNodeEvent.java index 038d34760454..d5ae5e9dca1c 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TreeNodeEvent.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/events/TreeNodeEvent.java @@ -16,24 +16,19 @@ package com.intellij.execution.testframework.sm.runner.events; import jetbrains.buildServer.messages.serviceMessages.ServiceMessage; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public abstract class TreeNodeEvent { + @NonNls public static final String ROOT_NODE_ID = "0"; private final String myName; - private final int myId; + private final String myId; - public TreeNodeEvent(@Nullable String name, int id) { + public TreeNodeEvent(@Nullable String name, @Nullable String id) { myName = name; myId = id; - validate(); - } - - private void validate() { - if (myId < -1) { - fail("id should be greater than -2"); - } } protected void fail(@NotNull String message) { @@ -46,9 +41,10 @@ public abstract class TreeNodeEvent { } /** - * @return tree node id (non-negative integer), or -1 if undefined + * @return tree node id, or null if undefined */ - public int getId() { + @Nullable + public String getId() { return myId; } @@ -80,16 +76,14 @@ public abstract class TreeNodeEvent { } } - public static int getNodeId(@NotNull ServiceMessage message) { - return getIntAttribute(message, "nodeId"); + @Nullable + public static String getNodeId(@NotNull ServiceMessage message) { + return getNodeId(message, "nodeId"); } - public static int getIntAttribute(@NotNull ServiceMessage message, @NotNull String key) { - String value = message.getAttributes().get(key); - if (value == null) { - return -1; - } - return Integer.parseInt(value); + @Nullable + public static String getNodeId(@NotNull ServiceMessage message, String key) { + return message.getAttributes().get(key); } } diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertorTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertorTest.java index d1066a7c1aca..38b0f3770788 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertorTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/GeneralIdBasedToSMTRunnerEventsConvertorTest.java @@ -45,26 +45,26 @@ public class GeneralIdBasedToSMTRunnerEventsConvertorTest extends BaseSMTRunnerT } public void testOnTestStarted() throws InterruptedException { - onTestStarted("my test", 1, 0); - SMTestProxy proxy = myEventsProcessor.findProxyById(1); + onTestStarted("my test", "1", "0"); + SMTestProxy proxy = myEventsProcessor.findProxyById("1"); assertNotNull(proxy); assertTrue(proxy.isInProgress()); assertEquals(1, myRootProxy.getChildren().size()); - onTestFailed(1, "", 1); - proxy = myEventsProcessor.findProxyById(1); + onTestFailed("1", "", 1); + proxy = myEventsProcessor.findProxyById("1"); assertNotNull(proxy); assertTrue(proxy.isDefect()); assertEquals(Long.valueOf(1), proxy.getDuration()); } - private void onTestStarted(@NotNull String testName, int id, int parentId) { + private void onTestStarted(@NotNull String testName, String id, String parentId) { myEventsProcessor.onTestStarted(new TestStartedEvent(testName, id, parentId, null, null, null, true)); } - private void onTestFailed(int id, @NotNull String errorMessage, int duration) { + private void onTestFailed(String id, @NotNull String errorMessage, int duration) { myEventsProcessor.onTestFailure(new TestFailedEvent(null, id, errorMessage, null, false, null, null, null, duration)); } diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 364df20afe67..2f1ac417c375 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -2702,6 +2702,11 @@ public class ContainerUtil extends ContainerUtilRt { return collection == null || collection.isEmpty(); } + @Contract(value = "null -> true", pure = true) + public static boolean isEmpty(Map map) { + return map == null || map.isEmpty(); + } + @NotNull @Contract(pure=true) public static List notNullize(@Nullable List list) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java index 0b8f47d141b5..6af228909dfe 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateDiffViewerAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -46,7 +46,6 @@ import com.intellij.openapi.progress.util.BackgroundTaskUtil; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.*; @@ -388,8 +387,7 @@ public class AnnotateDiffViewerAction extends ToggleAction implements DumbAware return; } - Balloon balloon = NotificationsManagerImpl.createBalloon(component, notification, false, true, null); - Disposer.register(viewer, balloon); + Balloon balloon = NotificationsManagerImpl.createBalloon(component, notification, false, true, null, viewer); Dimension componentSize = component.getSize(); Dimension balloonSize = balloon.getPreferredSize(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 1431c61a2bea..6ff2146adf49 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -119,12 +119,12 @@ public class LineStatusTracker { } @CalledInAwt - public void initialize(@NotNull final String vcsContent, @NotNull RevisionPack baseRevisionNumber) { + public void setBaseRevision(@NotNull final String vcsContent, @NotNull RevisionPack baseRevisionNumber) { myApplication.assertIsDispatchThread(); synchronized (myLock) { try { - if (myInitialized || myReleased) return; + if (myReleased) return; if (myBaseRevisionNumber != null && myBaseRevisionNumber.contains(baseRevisionNumber)) return; myBaseRevisionNumber = baseRevisionNumber; diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java index 1045a7614243..66864a413a9b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java @@ -385,7 +385,7 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra } final LineStatusTracker tracker = myLineStatusTrackers.get(myDocument); if (tracker != null) { - tracker.initialize(converted, revisionPack); + tracker.setBaseRevision(converted, revisionPack); } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/EmptyDirectoryInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/EmptyDirectoryInspection.java index e52bd30ed231..2d0f81eb12d5 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/EmptyDirectoryInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/EmptyDirectoryInspection.java @@ -155,7 +155,7 @@ public class EmptyDirectoryInspection extends BaseGlobalInspection { @NotNull @Override public String getFamilyName() { - return getName(); + return InspectionGadgetsBundle.message("empty.directories.delete.quickfix", ""); } @Override diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodMayBeStaticInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodMayBeStaticInspection.java index 36230a3e8d85..093004bf75f8 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodMayBeStaticInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/MethodMayBeStaticInspection.java @@ -42,6 +42,11 @@ public class MethodMayBeStaticInspection extends MethodMayBeStaticInspectionBase } } + @Override + public boolean startInWriteAction() { + return false; + } + @Override @NotNull public String getName() { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverUtil.java index c080512f86e0..51300948655f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverUtil.java @@ -109,8 +109,8 @@ public class GradleProjectResolverUtil { @NotNull public static String getModuleConfigPath(@NotNull ProjectResolverContext resolverCtx, - @NotNull IdeaModule gradleModule, - @NotNull String rootProjectPath) { + @NotNull IdeaModule gradleModule, + @NotNull String rootProjectPath) { GradleBuild build = resolverCtx.getExtraProject(gradleModule, GradleBuild.class); if (build != null) { String gradlePath = gradleModule.getGradleProject().getPath(); @@ -339,9 +339,10 @@ public class GradleProjectResolverUtil { Map dependencyMap = ContainerUtil.newLinkedHashMap(); for (ExternalDependency dependency : dependencies) { final ExternalDependency dep = dependencyMap.get(dependency.getId()); - if(dep instanceof AbstractExternalDependency) { + if (dep instanceof AbstractExternalDependency) { dep.getDependencies().addAll(ContainerUtil.subtract(dependency.getDependencies(), dep.getDependencies())); - } else { + } + else { dependencyMap.put(dependency.getId(), dependency); } } @@ -364,18 +365,35 @@ public class GradleProjectResolverUtil { final ExternalProjectDependency projectDependency = (ExternalProjectDependency)mergedDependency; String moduleId = getModuleId(projectDependency); Pair, ExternalSourceSet> projectPair = sourceSetMap.get(moduleId); - ModuleDependencyData moduleDependencyData = new ModuleDependencyData(ownerModule, projectPair.first.getData()); - moduleDependencyData.setScope(dependencyScope); - if ("test".equals(projectPair.second.getName())) { - moduleDependencyData.setProductionOnTestDependency(true); - } - moduleDependencyData.setOrder(mergedDependency.getClasspathOrder()); - moduleDependencyData.setExported(mergedDependency.getExported()); - moduleDependencyData.setModuleDependencyArtifacts(projectDependency.getProjectDependencyArtifacts()); + if (projectPair == null) { + final LibraryLevel level = LibraryLevel.MODULE; + final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, ""); + LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); + libraryDependencyData.setScope(dependencyScope); + libraryDependencyData.setOrder(mergedDependency.getClasspathOrder()); + libraryDependencyData.setExported(mergedDependency.getExported()); - DataNode ideModuleDependencyNode = - ownerDataNode.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData); - doBuildDependencies(sourceSetMap, mergedDependencyMap, ideModuleDependencyNode, dependency.getDependencies(), ideProject); + if (!projectDependency.getProjectDependencyArtifacts().isEmpty()) { + for (String artifactPath : projectDependency.getProjectDependencyArtifacts()) { + library.addPath(LibraryPathType.BINARY, artifactPath); + } + ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); + } + } + else { + ModuleDependencyData moduleDependencyData = new ModuleDependencyData(ownerModule, projectPair.first.getData()); + moduleDependencyData.setScope(dependencyScope); + if ("test".equals(projectPair.second.getName())) { + moduleDependencyData.setProductionOnTestDependency(true); + } + moduleDependencyData.setOrder(mergedDependency.getClasspathOrder()); + moduleDependencyData.setExported(mergedDependency.getExported()); + moduleDependencyData.setModuleDependencyArtifacts(projectDependency.getProjectDependencyArtifacts()); + + DataNode ideModuleDependencyNode = + ownerDataNode.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData); + doBuildDependencies(sourceSetMap, mergedDependencyMap, ideModuleDependencyNode, dependency.getDependencies(), ideProject); + } } if (mergedDependency instanceof ExternalLibraryDependency) { final LibraryLevel level = LibraryLevel.PROJECT; @@ -510,10 +528,10 @@ public class GradleProjectResolverUtil { final int i = taskPath.lastIndexOf(':'); String path = taskPath.substring(0, i); moduleNode = findModuleById(projectNode, path); - if(moduleNode == null || !FileUtil.isAncestor(moduleNode.getData().getLinkedExternalProjectPath(), modulePath, false)) { + if (moduleNode == null || !FileUtil.isAncestor(moduleNode.getData().getLinkedExternalProjectPath(), modulePath, false)) { moduleNode = findModule(projectNode, modulePath); } - taskName = (i + 1) <= taskPath.length() ? taskPath.substring(i + 1): taskPath; + taskName = (i + 1) <= taskPath.length() ? taskPath.substring(i + 1) : taskPath; } else { moduleNode = findModule(projectNode, modulePath); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/SubstitutorComputer.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/SubstitutorComputer.java index deeae4e88e43..87ecf001c2f4 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/SubstitutorComputer.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/SubstitutorComputer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -33,6 +33,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnState import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -95,7 +96,13 @@ public class SubstitutorComputer { } } else if (parent instanceof GrAssignmentExpression && myPlaceToInferContext.equals(((GrAssignmentExpression)parent).getRValue())) { - return ((GrAssignmentExpression)parent).getLValue().getType(); + GrExpression lValue = ((GrAssignmentExpression)parent).getLValue(); + if (lValue instanceof GrIndexProperty) { + return null; + } + else { + return lValue.getType(); + } } else if (parent instanceof GrVariable) { return ((GrVariable)parent).getDeclaredType(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GrMoveToDirFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GrMoveToDirFix.java index 3e3fb880f373..6637825aa528 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GrMoveToDirFix.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/GrMoveToDirFix.java @@ -81,4 +81,9 @@ public class GrMoveToDirFix extends GroovyFix { } new MoveFilesOrDirectoriesProcessor(project, new PsiElement[]{file}, directory, false, false, false, null, null).run(); } + + @Override + public boolean startInWriteAction() { + return false; + } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightingTest.groovy index f37b6c998232..c328a68656cb 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightingTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyHighlightingTest.groovy @@ -1969,6 +1969,24 @@ import groovy.transform.Field @Field def (,) +''' + } + + void 'test no SOE in index property assignment with generic function'() { + testHighlighting ''' +class Main { + + static T foo() {} + + static void main(String[] args) { + def main = new Main() + main[Main] = foo() + } + + def putAt(x, String t) { + println "Works: $x = $t" + } +} ''' } } diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/GenerateGetterSetterTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/GenerateGetterSetterTest.java index 3c41bf68379a..c5ae9fc93656 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/GenerateGetterSetterTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/GenerateGetterSetterTest.java @@ -26,6 +26,7 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.javaFX.fxml.AbstractJavaFXTestCase; @PlatformTestCase.WrapInCommand public class GenerateGetterSetterTest extends DaemonAnalyzerTestCase { @@ -40,7 +41,7 @@ public class GenerateGetterSetterTest extends DaemonAnalyzerTestCase { @Override protected void setUpModule() { super.setUpModule(); - PsiTestUtil.addLibrary(getModule(), "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "jfxrt.jar"); + AbstractJavaFXTestCase.addJavaFxJarAsLibrary(getModule()); } protected void doTest() throws Exception { diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/AbstractJavaFXTestCase.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/AbstractJavaFXTestCase.java index d74a73d12441..272a950829d9 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/AbstractJavaFXTestCase.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/AbstractJavaFXTestCase.java @@ -24,6 +24,9 @@ import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; /** * User: anna @@ -33,11 +36,25 @@ public abstract class AbstractJavaFXTestCase extends LightCodeInsightFixtureTest public static final DefaultLightProjectDescriptor JAVA_FX_DESCRIPTOR = new DefaultLightProjectDescriptor() { @Override public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) { - PsiTestUtil.addLibrary(module, model, "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "jfxrt.jar"); + addJavaFxJarAsLibrary(module, model); super.configureModule(module, model, contentEntry); } }; + public static void addJavaFxJarAsLibrary(@NotNull Module module) { + addJavaFxJarAsLibrary(module, null); + } + + public static void addJavaFxJarAsLibrary(@NotNull Module module, @Nullable ModifiableRootModel model) { + final String libPath = System.getProperty("java.home") + File.separator + "lib" + File.separator + "ext"; + if (model != null) { + PsiTestUtil.addLibrary(module, model, "javafx", libPath, "jfxrt.jar"); + } + else { + PsiTestUtil.addLibrary(module, "javafx", libPath, "jfxrt.jar"); + } + } + @NotNull @Override protected LightProjectDescriptor getProjectDescriptor() { diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXCollapseSubtagToAttributeTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXCollapseSubtagToAttributeTest.java index 9839bef63707..fa0c74ead15d 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXCollapseSubtagToAttributeTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXCollapseSubtagToAttributeTest.java @@ -31,7 +31,7 @@ public class JavaFXCollapseSubtagToAttributeTest extends DaemonAnalyzerTestCase @Override protected void setUpModule() { super.setUpModule(); - PsiTestUtil.addLibrary(getModule(), "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "jfxrt.jar"); + AbstractJavaFXTestCase.addJavaFxJarAsLibrary(getModule()); } public void testAdditionalSubtags() throws Exception { diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXExpandAttributeTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXExpandAttributeTest.java index bcee2c97e692..f9361dd25434 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXExpandAttributeTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXExpandAttributeTest.java @@ -31,7 +31,7 @@ public class JavaFXExpandAttributeTest extends DaemonAnalyzerTestCase { @Override protected void setUpModule() { super.setUpModule(); - PsiTestUtil.addLibrary(getModule(), "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "jfxrt.jar"); + AbstractJavaFXTestCase.addJavaFxJarAsLibrary(getModule()); } public void testDefaultAttr() throws Exception { diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXImportTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXImportTest.java index e8fea47215e8..510f5b5b3d76 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXImportTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXImportTest.java @@ -27,7 +27,7 @@ public class JavaFXImportTest extends DaemonAnalyzerTestCase { @Override protected void setUpModule() { super.setUpModule(); - PsiTestUtil.addLibrary(getModule(), "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "jfxrt.jar"); + AbstractJavaFXTestCase.addJavaFxJarAsLibrary(getModule()); } public void testSimpleImport() throws Exception { diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java index 0658ce0f8a92..70c5151212eb 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java @@ -40,7 +40,7 @@ public class JavaFXQuickfixTest extends LightCodeInsightFixtureTestCase { public static final DefaultLightProjectDescriptor JAVA_FX_WITH_GROOVY_DESCRIPTOR = new DefaultLightProjectDescriptor() { @Override public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) { - PsiTestUtil.addLibrary(module, model, "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "jfxrt.jar"); + AbstractJavaFXTestCase.addJavaFxJarAsLibrary(module, model); PsiTestUtil.addLibrary(module, model, "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "groovy-1.8.0.jar"); super.configureModule(module, model, contentEntry); } diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXRenameTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXRenameTest.java index 713bc42382e4..808fa190b203 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXRenameTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXRenameTest.java @@ -30,7 +30,7 @@ public class JavaFXRenameTest extends DaemonAnalyzerTestCase { @Override protected void setUpModule() { super.setUpModule(); - PsiTestUtil.addLibrary(getModule(), "javafx", PluginPathManager.getPluginHomePath("javaFX") + "/testData", "jfxrt.jar"); + AbstractJavaFXTestCase.addJavaFxJarAsLibrary(getModule()); } public void testCustomComponent() throws Exception { diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java index 6ebc4e2aebd0..812c9d650005 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java @@ -369,7 +369,7 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor, PsiClass aClass = myPsiClass; final XmlAttribute constAttr = context.getAttribute(FxmlConstants.FX_CONSTANT); if (constAttr != null && aClass != null) { - final PsiField constField = aClass.findFieldByName(constAttr.getValue(), false); + final PsiField constField = aClass.findFieldByName(constAttr.getValue(), true); if (constField != null) { aClass = PsiUtil.resolveClassInType(constField.getType()); } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java index 9f52ae28df19..557bc3e130c1 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java @@ -110,8 +110,8 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript public PsiElement getEnumeratedValueDeclaration(XmlElement xmlElement, String value) { final PsiClass aClass = getEnum(); if (aClass != null) { - final PsiField fieldByName = aClass.findFieldByName(value, false); - return fieldByName != null ? fieldByName : aClass.findFieldByName(value.toUpperCase(), false); + final PsiField fieldByName = aClass.findFieldByName(value, true); + return fieldByName != null ? fieldByName : aClass.findFieldByName(value.toUpperCase(), true); } return xmlElement; } diff --git a/plugins/javaFX/testData/highlighting/readOnly.fxml b/plugins/javaFX/testData/highlighting/readOnly.fxml index 431a6d12c66d..3e27198260ff 100644 --- a/plugins/javaFX/testData/highlighting/readOnly.fxml +++ b/plugins/javaFX/testData/highlighting/readOnly.fxml @@ -1,6 +1,6 @@ -mystyle.css" backgroundFills=""> +mystyle.css" backgroundFills=""> mystyle.css"/> diff --git a/plugins/javaFX/testData/jfxrt.jar b/plugins/javaFX/testData/jfxrt.jar deleted file mode 100644 index 48109d611026..000000000000 Binary files a/plugins/javaFX/testData/jfxrt.jar and /dev/null differ diff --git a/plugins/junit/junit.iml b/plugins/junit/junit.iml index 4b114db22d86..103c9789465b 100644 --- a/plugins/junit/junit.iml +++ b/plugins/junit/junit.iml @@ -22,6 +22,7 @@ + diff --git a/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java b/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java index 0d0354fabafa..040f4cb52bb3 100644 --- a/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java +++ b/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java @@ -35,8 +35,8 @@ import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.ClassesWithAnnotatedMembersSearch; import com.intellij.psi.stubsHierarchy.impl.ClassAnchorUtil; -import com.intellij.psi.stubsHierarchy.impl.SingleClassHierarchy; import com.intellij.psi.stubsHierarchy.impl.HierarchyService; +import com.intellij.psi.stubsHierarchy.impl.SingleClassHierarchy; import com.intellij.psi.stubsHierarchy.impl.SmartClassAnchor; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Processor; @@ -103,8 +103,9 @@ public class ConfigurationUtil { } Set processed = ContainerUtil.newHashSet(); - boolean hasJunit4 = addAnnotatedMethodsAnSubclasses(manager, scope, testClassFilter, found, processed, "org.junit.Test", true, symbols); - hasJunit4 |= addAnnotatedMethodsAnSubclasses(manager, scope, testClassFilter, found, processed, "org.junit.runner.RunWith", false, symbols); + boolean hasJunit4 = addAnnotatedMethodsAnSubclasses(manager, scope, testClassFilter, found, processed, JUnitUtil.TEST_ANNOTATION, true, symbols); + hasJunit4 |= addAnnotatedMethodsAnSubclasses(manager, scope, testClassFilter, found, processed, JUnitUtil.TEST5_ANNOTATION, true, symbols); + hasJunit4 |= addAnnotatedMethodsAnSubclasses(manager, scope, testClassFilter, found, processed, JUnitUtil.RUN_WITH, false, symbols); return hasJunit4; } diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java index 3b68c8fb60f8..2808eab23761 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java @@ -51,7 +51,7 @@ class TestMethod extends TestObject { protected void addJUnit3Parameter(JavaParameters javaParameters, final JUnitConfiguration.Data data, Project project) throws ExecutionException { final PsiClass psiClass = JavaExecutionUtil.findMainClass(project, data.getMainClassName(), GlobalSearchScope.allScope(project)); - if (psiClass == null || JUnitUtil.isJUnit4TestClass(psiClass)) { + if (psiClass == null || JUnitUtil.isJUnit4TestClass(psiClass) || JUnitUtil.isJUnit5(psiClass)) { return; } final String methodName = data.getMethodName(); diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index a48926d97494..2a25b1a0145f 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -40,10 +40,12 @@ import com.intellij.execution.testframework.*; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.util.JavaParametersUtil; import com.intellij.execution.util.ProgramParametersUtil; +import com.intellij.junit5.JUnit5IdeaTestRunner; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.Key; @@ -51,6 +53,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.listeners.RefactoringElementListener; import com.intellij.rt.execution.junit.IDEAJUnitListener; import com.intellij.rt.execution.junit.JUnitStarter; @@ -155,6 +158,13 @@ public abstract class TestObject extends JavaTestFrameworkRunnableState findProcessor = new CommonProcessors.FindProcessor() { diff --git a/plugins/junit5_rt/junit5_rt.iml b/plugins/junit5_rt/junit5_rt.iml new file mode 100644 index 000000000000..ec639f339e82 --- /dev/null +++ b/plugins/junit5_rt/junit5_rt.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/junit5_rt/lib/junit-commons-5.0.0-ALPHA.jar b/plugins/junit5_rt/lib/junit-commons-5.0.0-ALPHA.jar new file mode 100644 index 000000000000..0e941851fd0e Binary files /dev/null and b/plugins/junit5_rt/lib/junit-commons-5.0.0-ALPHA.jar differ diff --git a/plugins/junit5_rt/lib/junit-engine-api-5.0.0-ALPHA.jar b/plugins/junit5_rt/lib/junit-engine-api-5.0.0-ALPHA.jar new file mode 100644 index 000000000000..3346ebab9a16 Binary files /dev/null and b/plugins/junit5_rt/lib/junit-engine-api-5.0.0-ALPHA.jar differ diff --git a/plugins/junit5_rt/lib/junit-launcher-5.0.0-ALPHA.jar b/plugins/junit5_rt/lib/junit-launcher-5.0.0-ALPHA.jar new file mode 100644 index 000000000000..f881f91ec5bf Binary files /dev/null and b/plugins/junit5_rt/lib/junit-launcher-5.0.0-ALPHA.jar differ diff --git a/plugins/junit5_rt/lib/opentest4j-1.0.0.jar b/plugins/junit5_rt/lib/opentest4j-1.0.0.jar new file mode 100644 index 000000000000..7208395ee319 Binary files /dev/null and b/plugins/junit5_rt/lib/opentest4j-1.0.0.jar differ diff --git a/plugins/junit5_rt/src/com/intellij/junit5/JUnit5IdeaTestRunner.java b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5IdeaTestRunner.java new file mode 100644 index 000000000000..6084caddab43 --- /dev/null +++ b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5IdeaTestRunner.java @@ -0,0 +1,87 @@ +/* + * Copyright 2000-2016 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.junit5; + +import com.intellij.rt.execution.junit.IdeaTestRunner; +import com.intellij.rt.execution.junit.segments.OutputObjectRegistry; +import org.junit.gen5.launcher.Launcher; +import org.junit.gen5.launcher.TestDiscoveryRequest; +import org.junit.gen5.launcher.TestIdentifier; +import org.junit.gen5.launcher.TestPlan; +import org.junit.gen5.launcher.main.LauncherFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class JUnit5IdeaTestRunner implements IdeaTestRunner { + private JUnit5TestExecutionListener myListener; + private TestPlan myTestPlan; + + @Override + public int startRunnerWithArgs(String[] args, ArrayList listeners, String name, int count, boolean sendTree) { + Launcher launcher = LauncherFactory.create(); + launcher.registerTestExecutionListeners(myListener); + final String[] packageNameRef = new String[1]; + final TestDiscoveryRequest discoveryRequest = JUnit5TestRunnerUtil.buildRequest(args, packageNameRef); + myTestPlan = launcher.discover(discoveryRequest); + myListener.sendTree(myTestPlan, packageNameRef[0]); + launcher.execute(discoveryRequest); + + return 0; + } + + @Override + public void setStreams(Object segmentedOut, Object segmentedErr, int lastIdx) { + myListener = new JUnit5TestExecutionListener(System.out); + } + + @Override + public OutputObjectRegistry getRegistry() { + return null; + } + + @Override + public Object getTestToStart(String[] args, String name) { + final TestDiscoveryRequest request = JUnit5TestRunnerUtil.buildRequest(args, new String[1]); + Launcher launcher = LauncherFactory.create(); + myTestPlan = launcher.discover(request); + final Set roots = myTestPlan.getRoots(); + + return roots.isEmpty() ? null : roots.iterator().next(); + } + + @Override + public List getChildTests(Object description) { + return new ArrayList<>(myTestPlan.getChildren((TestIdentifier)description)); + } + + @Override + public String getStartDescription(Object child) { + final TestIdentifier testIdentifier = (TestIdentifier)child; + final String className = JUnit5TestExecutionListener.getClassName(testIdentifier); + final String methodName = JUnit5TestExecutionListener.getMethodName(testIdentifier); + if (methodName != null) { + return className + "#" + methodName; + } + return className != null ? className : (testIdentifier).getDisplayName(); + } + + @Override + public String getTestClassName(Object child) { + return child.toString(); + } +} diff --git a/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestExecutionListener.java b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestExecutionListener.java new file mode 100644 index 000000000000..fcc78338351a --- /dev/null +++ b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestExecutionListener.java @@ -0,0 +1,234 @@ +/* + * Copyright 2000-2016 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.junit5; + +import com.intellij.junit4.ExpectedPatterns; +import com.intellij.rt.execution.junit.ComparisonFailureData; +import com.intellij.rt.execution.junit.MapSerializerUtil; +import org.junit.gen5.engine.TestExecutionResult; +import org.junit.gen5.engine.support.descriptor.JavaSource; +import org.junit.gen5.launcher.TestExecutionListener; +import org.junit.gen5.launcher.TestIdentifier; +import org.junit.gen5.launcher.TestPlan; +import org.opentest4j.AssertionFailedError; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class JUnit5TestExecutionListener implements TestExecutionListener { + private final PrintStream myPrintStream; + private TestPlan myTestPlan; + private long myCurrentTestStart; + private int myFinishCount = 0; + private String myRootName; + + public JUnit5TestExecutionListener() { + this(System.out); + } + + public JUnit5TestExecutionListener(PrintStream printStream) { + myPrintStream = printStream; + myPrintStream.println("##teamcity[enteredTheMatrix]"); + } + + @Override + public void testPlanExecutionStarted(TestPlan testPlan) { + if (myRootName != null) { + int lastPointIdx = myRootName.lastIndexOf('.'); + String name = myRootName; + String comment = null; + if (lastPointIdx >= 0) { + name = myRootName.substring(lastPointIdx + 1); + comment = myRootName.substring(0, lastPointIdx); + } + + myPrintStream.println("##teamcity[rootName name = \'" + escapeName(name) + + (comment != null ? ("\' comment = \'" + escapeName(comment)) : "") + "\'" + + " location = \'java:suite://" + escapeName(myRootName) + + "\']"); + } + } + + @Override + public void testPlanExecutionFinished(TestPlan testPlan) { + myTestPlan = null; + } + + @Override + public void executionSkipped(TestIdentifier testIdentifier, String reason) { + testIgnored(testIdentifier, reason); + } + + private void testIgnored(TestIdentifier testIdentifier, String reason) { + if (testIdentifier.isTest()) { + executionStarted(testIdentifier); + Map attrs = new HashMap<>(); + if (reason != null) { + attrs.put("message", reason); + } + attrs.put("name", testIdentifier.getDisplayName()); + attrs.put("id", testIdentifier.getUniqueId().toString()); + myPrintStream.println(MapSerializerUtil.asString(MapSerializerUtil.TEST_IGNORED, attrs)); + + testFinished(testIdentifier, System.currentTimeMillis() - myCurrentTestStart); + } + else { + myTestPlan.getDescendants(testIdentifier).forEach(identifier -> testIgnored(identifier, reason)); + } + } + + @Override + public void executionStarted(TestIdentifier testIdentifier) { + if (testIdentifier.isTest()) { + testStarted(testIdentifier); + myCurrentTestStart = System.currentTimeMillis(); + } + else { + myFinishCount = 0; + myPrintStream.println("##teamcity[testSuiteStarted" + idAndName(testIdentifier) + "\']"); + } + } + + private static String idAndName(TestIdentifier testIdentifier) { + return idAndName(testIdentifier, testIdentifier.getDisplayName()); + } + + private static String idAndName(TestIdentifier testIdentifier, String displayName) { + return " id=\'" + testIdentifier.getUniqueId().toString() + "\' name=\'" + escapeName(displayName); + } + + @Override + public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) { + final String displayName = testIdentifier.getDisplayName(); + final TestExecutionResult.Status status = testExecutionResult.getStatus(); + final Throwable throwableOptional = testExecutionResult.getThrowable().orElse(null); + if (testIdentifier.isTest()) { + final long duration = System.currentTimeMillis() - myCurrentTestStart; + if (status == TestExecutionResult.Status.FAILED) { + testFailure(throwableOptional, MapSerializerUtil.TEST_FAILED, testIdentifier, duration); + } + else if (status == TestExecutionResult.Status.ABORTED) { + testFailure(throwableOptional, MapSerializerUtil.TEST_IGNORED, testIdentifier, duration); + } + testFinished(testIdentifier, duration); + myFinishCount++; + } + else { + String messageName = null; + if (status == TestExecutionResult.Status.FAILED) { + messageName = MapSerializerUtil.TEST_FAILED; + } + else if (status == TestExecutionResult.Status.ABORTED) { + messageName = MapSerializerUtil.TEST_IGNORED; + } + if (messageName != null && myFinishCount == 0) { + for (TestIdentifier childIdentifier : myTestPlan.getChildren(testIdentifier)) { + testStarted(childIdentifier); + testFailure(throwableOptional, messageName, childIdentifier, 0); + testFinished(childIdentifier, 0); + } + } + myPrintStream.println("##teamcity[testSuiteFinished " + idAndName(testIdentifier, displayName) + "\']"); + } + } + + private void testStarted(TestIdentifier testIdentifier) { + myPrintStream.println("\n##teamcity[testStarted" + idAndName(testIdentifier) + "\']"); + } + + private void testFinished(TestIdentifier testIdentifier, long duration) { + myPrintStream.println("\n##teamcity[testFinished" + idAndName(testIdentifier) + (duration > 0 ? "\' duration=\'" + Long.toString(duration) : "") + "\']"); + } + + private void testFailure(Throwable ex, String messageName, TestIdentifier testIdentifier, long duration) { + final Map attrs = new HashMap<>(); + attrs.put("name", testIdentifier.getDisplayName()); + attrs.put("id", testIdentifier.getUniqueId().toString()); + if (duration > 0) { + attrs.put("duration", Long.toString(duration)); + } + try { + if (ex != null) { + final StringWriter stringWriter = new StringWriter(); + final PrintWriter writer = new PrintWriter(stringWriter); + ex.printStackTrace(writer); + final ComparisonFailureData failureData; + if (ex instanceof AssertionFailedError && ((AssertionFailedError)ex).isActualDefined() && ((AssertionFailedError)ex).isExpectedDefined()) { + final Object actual = ((AssertionFailedError)ex).getActual(); + final Object expected = ((AssertionFailedError)ex).getExpected(); + failureData = new ComparisonFailureData(expected.toString(), actual.toString()); + } + else { + failureData = ExpectedPatterns.createExceptionNotification(ex); + } + ComparisonFailureData.registerSMAttributes(failureData, stringWriter.toString(), ex.getMessage(), attrs, ex); + } + } + finally { + myPrintStream.println("\n" + MapSerializerUtil.asString(messageName, attrs)); + } + } + + + public void sendTree(TestPlan testPlan, String rootName) { + myTestPlan = testPlan; + myRootName = rootName; + for (TestIdentifier root : testPlan.getRoots()) { + sendTreeUnderRoot(testPlan, root); + } + myPrintStream.println("##teamcity[treeEnded]"); + } + + private void sendTreeUnderRoot(TestPlan testPlan, TestIdentifier root) { + final String idAndName = idAndName(root); + if (root.isContainer()) { + myPrintStream.println("##teamcity[suiteTreeStarted" + idAndName + "\' locationHint=\'java:suite://" + escapeName(getClassName(root)) + "\']"); + for (TestIdentifier childIdentifier : testPlan.getChildren(root)) { + sendTreeUnderRoot(testPlan, childIdentifier); + } + myPrintStream.println("##teamcity[suiteTreeEnded" + idAndName + "\']"); + } + else if (root.isTest()) { + myPrintStream.println("##teamcity[suiteTreeNode " + idAndName + "\' locationHint=\'java:test://" + escapeName(getClassName(root) + "." + getMethodName(root)) + "\']"); + } + } + + + private static String escapeName(String str) { + return MapSerializerUtil.escapeStr(str, MapSerializerUtil.STD_ESCAPER); + } + + static String getClassName(TestIdentifier description) { + Optional javaSource = getJavaSource(description); + return javaSource.map(source -> { + final Optional> javaClass = source.getJavaClass(); + return javaClass.isPresent() ? javaClass.get().getName() : null; + }).orElse(null); + } + + static String getMethodName(TestIdentifier testIdentifier) { + return getJavaSource(testIdentifier).map((source) -> source.getJavaMethodName().orElse(null)).orElse(null); + } + + private static Optional getJavaSource(TestIdentifier testIdentifier) { + return testIdentifier.getSource().filter(JavaSource.class::isInstance).map(JavaSource.class::cast); + } + +} diff --git a/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java new file mode 100644 index 000000000000..a8d271f648db --- /dev/null +++ b/plugins/junit5_rt/src/com/intellij/junit5/JUnit5TestRunnerUtil.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2016 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.junit5; + +import org.junit.gen5.engine.discovery.NameBasedSelector; +import org.junit.gen5.launcher.TestDiscoveryRequest; +import org.junit.gen5.launcher.main.TestDiscoveryRequestBuilder; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class JUnit5TestRunnerUtil { + + public static TestDiscoveryRequest buildRequest(String[] suiteClassNames, String[] packageNameRef) { + if (suiteClassNames.length == 0) { + return null; + } + + final TestDiscoveryRequestBuilder builder = TestDiscoveryRequestBuilder.request(); + final List lines = new ArrayList<>(); + + + if (suiteClassNames.length == 1 && suiteClassNames[0].charAt(0) == '@') { + // all tests in the package specified + try { + BufferedReader reader = new BufferedReader(new FileReader(suiteClassNames[0].substring(1))); + try { + final String packageName = reader.readLine(); + if (packageName == null) return null; + + //todo category? + final String categoryName = reader.readLine(); + String line; + + while ((line = reader.readLine()) != null) { + lines.add(line); + } + packageNameRef[0] = packageName.length() == 0 ? "" : packageName; + } + finally { + reader.close(); + } + } + catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + } + else { + Collections.addAll(lines, suiteClassNames); + } + + final List mappedLines = lines.stream().map(line -> line.replaceFirst(",", "#")).collect(Collectors.toList()); + return builder.select(NameBasedSelector.forNames(mappedLines)).build(); + } + +} diff --git a/plugins/junit_rt/src/com/intellij/junit4/ExpectedPatterns.java b/plugins/junit_rt/src/com/intellij/junit4/ExpectedPatterns.java index 364577a2a028..ef879e7fa64f 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/ExpectedPatterns.java +++ b/plugins/junit_rt/src/com/intellij/junit4/ExpectedPatterns.java @@ -15,8 +15,9 @@ */ package com.intellij.junit4; -import com.intellij.rt.execution.testFrameworks.AbstractExpectedPatterns; import com.intellij.rt.execution.junit.ComparisonFailureData; +import com.intellij.rt.execution.testFrameworks.AbstractExpectedPatterns; +import junit.framework.ComparisonFailure; import java.util.ArrayList; import java.util.List; @@ -35,6 +36,10 @@ public class ExpectedPatterns extends AbstractExpectedPatterns { ".*?\\s*expected: (.*)\\s*but was: (.*)" }; + private static final String MESSAGE_LENGTH_FOR_PATTERN_MATCHING = "idea.junit.message.length.threshold"; + private static final String JUNIT_FRAMEWORK_COMPARISON_NAME = ComparisonFailure.class.getName(); + private static final String ORG_JUNIT_COMPARISON_NAME = "org.junit.ComparisonFailure"; + static { registerPatterns(PATTERN_STRINGS, PATTERNS); } @@ -42,4 +47,55 @@ public class ExpectedPatterns extends AbstractExpectedPatterns { public static ComparisonFailureData createExceptionNotification(String message) { return createExceptionNotification(message, PATTERNS); } + + public static ComparisonFailureData createExceptionNotification(Throwable assertion) { + if (isComparisonFailure(assertion)) { + return ComparisonFailureData.create(assertion); + } + try { + final Throwable cause = assertion.getCause(); + if (isComparisonFailure(cause)) { + return ComparisonFailureData.create(cause); + } + } + catch (Throwable ignore) { + } + + final String message = assertion.getMessage(); + if (message != null && acceptedByThreshold(message.length())) { + try { + return createExceptionNotification(message); + } + catch (Throwable ignored) {} + } + return null; + } + + private static boolean isComparisonFailure(Throwable throwable) { + if (throwable == null) return false; + return isComparisonFailure(throwable.getClass()); + } + + private static boolean isComparisonFailure(Class aClass) { + if (aClass == null) return false; + final String throwableClassName = aClass.getName(); + if (throwableClassName.equals(JUNIT_FRAMEWORK_COMPARISON_NAME) || throwableClassName.equals(ORG_JUNIT_COMPARISON_NAME)) return true; + return isComparisonFailure(aClass.getSuperclass()); + } + + + private static boolean acceptedByThreshold(int messageLength) { + int threshold = 10000; + try { + final String property = System.getProperty(MESSAGE_LENGTH_FOR_PATTERN_MATCHING); + if (property != null) { + try { + threshold = Integer.parseInt(property); + } + catch (NumberFormatException ignore) {} + } + } + catch (SecurityException ignored) {} + return messageLength < threshold; + } } diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestListener.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestListener.java index bcb71b321c60..a8b978d18dde 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestListener.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestListener.java @@ -22,7 +22,6 @@ package com.intellij.junit4; import com.intellij.rt.execution.junit.ComparisonFailureData; import com.intellij.rt.execution.junit.MapSerializerUtil; -import junit.framework.ComparisonFailure; import org.junit.Ignore; import org.junit.runner.Description; import org.junit.runner.Result; @@ -36,9 +35,6 @@ import java.lang.annotation.Annotation; import java.util.*; public class JUnit4TestListener extends RunListener { - private static final String MESSAGE_LENGTH_FOR_PATTERN_MATCHING = "idea.junit.message.length.threshold"; - private static final String JUNIT_FRAMEWORK_COMPARISON_NAME = ComparisonFailure.class.getName(); - private static final String ORG_JUNIT_COMPARISON_NAME = "org.junit.ComparisonFailure"; public static final String EMPTY_SUITE_NAME = "junit.framework.TestSuite$1"; public static final String EMPTY_SUITE_WARNING = "warning"; @@ -202,7 +198,7 @@ public class JUnit4TestListener extends RunListener { if (failure != null) { final String trace = getTrace(failure); final Throwable ex = failure.getException(); - final ComparisonFailureData notification = createExceptionNotification(ex); + final ComparisonFailureData notification = ExpectedPatterns.createExceptionNotification(ex); ComparisonFailureData.registerSMAttributes(notification, trace, failure.getMessage(), attrs, ex); } } @@ -283,55 +279,6 @@ public class JUnit4TestListener extends RunListener { testFinished(description); } - private static boolean isComparisonFailure(Throwable throwable) { - if (throwable == null) return false; - return isComparisonFailure(throwable.getClass()); - } - - private static boolean isComparisonFailure(Class aClass) { - if (aClass == null) return false; - final String throwableClassName = aClass.getName(); - if (throwableClassName.equals(JUNIT_FRAMEWORK_COMPARISON_NAME) || throwableClassName.equals(ORG_JUNIT_COMPARISON_NAME)) return true; - return isComparisonFailure(aClass.getSuperclass()); - } - - static ComparisonFailureData createExceptionNotification(Throwable assertion) { - if (isComparisonFailure(assertion)) { - return ComparisonFailureData.create(assertion); - } - try { - final Throwable cause = assertion.getCause(); - if (isComparisonFailure(cause)) { - return ComparisonFailureData.create(cause); - } - } - catch (Throwable ignore) { - } - final String message = assertion.getMessage(); - if (message != null && acceptedByThreshold(message.length())) { - try { - return ExpectedPatterns.createExceptionNotification(message); - } - catch (Throwable ignored) {} - } - return null; - } - - private static boolean acceptedByThreshold(int messageLength) { - int threshold = 10000; - try { - final String property = System.getProperty(MESSAGE_LENGTH_FOR_PATTERN_MATCHING); - if (property != null) { - try { - threshold = Integer.parseInt(property); - } - catch (NumberFormatException ignore) {} - } - } - catch (SecurityException ignored) {} - return messageLength < threshold; - } - private void sendTree(Description description, Description parent, List currentParents) { List pParents = new ArrayList(3); pParents.addAll(currentParents); diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java index b15959fa499a..9f73562b18a4 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java @@ -98,7 +98,7 @@ public class JUnit4TestResultsSender extends RunListener { private static PacketFactory createExceptionNotification(Throwable assertion) { if (assertion instanceof KnownException) return ((KnownException)assertion).getPacketFactory(); - final ComparisonFailureData notification = JUnit4TestListener.createExceptionNotification(assertion); + final ComparisonFailureData notification = ExpectedPatterns.createExceptionNotification(assertion); if (notification != null) { return ComparisonDetailsExtractor.create(assertion, notification.getExpected(), notification.getActual()); } diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedSplitter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedSplitter.java index f9fa01fd147e..3cd7532c4924 100644 --- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedSplitter.java +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedSplitter.java @@ -43,7 +43,7 @@ public class JUnitForkedSplitter extends ForkedSplitter { protected Object createRootDescription(String[] args, String configName) throws InstantiationException, IllegalAccessException, ClassNotFoundException { - myTestRunner = (IdeaTestRunner)JUnitStarter.getAgentClass(Boolean.valueOf((String)myNewArgs.get(0)).booleanValue()).newInstance(); + myTestRunner = (IdeaTestRunner)JUnitStarter.getAgentClass((String)myNewArgs.get(0)).newInstance(); myTestRunner.setStreams(myOut, myErr, 0); return myTestRunner.getTestToStart(args, configName); } diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java index c7b2c7ebecd9..6aec02979bc1 100644 --- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java @@ -31,12 +31,12 @@ public class JUnitForkedStarter extends ChildVMStarter { throws InstantiationException, IllegalAccessException, ClassNotFoundException { final int lastIdx = Integer.parseInt(args[1]); final String[] childTestDescription = {args[2]}; - final boolean isJUnit4 = args[3].equalsIgnoreCase("true"); + final String argentName = args[3]; final ArrayList listeners = new ArrayList(); for (int i = 4, argsLength = args.length; i < argsLength; i++) { listeners.add(args[i]); } - IdeaTestRunner testRunner = (IdeaTestRunner)JUnitStarter.getAgentClass(isJUnit4).newInstance(); + IdeaTestRunner testRunner = (IdeaTestRunner)JUnitStarter.getAgentClass(argentName).newInstance(); //noinspection IOResourceOpenedButNotSafelyClosed testRunner.setStreams(new SegmentedOutputStream(out, true), new SegmentedOutputStream(err, true), lastIdx); System.exit(testRunner.startRunnerWithArgs(childTestDescription, listeners, null, 1, false)); diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java index b852a9b281b7..7e6dbbad721e 100644 --- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java +++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java @@ -32,8 +32,15 @@ import java.util.Vector; public class JUnitStarter { public static final int VERSION = 5; public static final String IDE_VERSION = "-ideVersion"; + public static final String JUNIT3_PARAMETER = "-junit3"; + public static final String JUNIT4_PARAMETER = "-junit4"; + public static final String JUNIT5_PARAMETER = "-junit5"; + private static final String SOCKET = "-socket"; + public static final String JUNIT3_RUNNER_NAME = "com.intellij.junit3.JUnit3IdeaTestRunner"; + public static final String JUNIT4_RUNNER_NAME = "com.intellij.junit4.JUnit4IdeaTestRunner"; + public static final String JUNIT5_RUNNER_NAME = "com.intellij.junit5.JUnit5IdeaTestRunner"; private static String ourForkMode; private static String ourCommandFileName; private static String ourWorkingDirs; @@ -60,9 +67,9 @@ public class JUnitStarter { final ArrayList listeners = new ArrayList(); final String[] name = new String[1]; - boolean isJUnit4 = processParameters(argList, listeners, name); + String agentName = processParameters(argList, listeners, name); - if (!canWorkWithJUnitVersion(System.err, isJUnit4)) { + if (!canWorkWithJUnitVersion(System.err, agentName)) { System.exit(-3); } if (!checkVersion(args, System.err)) { @@ -71,12 +78,12 @@ public class JUnitStarter { String[] array = new String[argList.size()]; argList.copyInto(array); - int exitCode = prepareStreamsAndStart(array, isJUnit4, listeners, name[0]); + int exitCode = prepareStreamsAndStart(array, agentName, listeners, name[0]); System.exit(exitCode); } - private static boolean processParameters(Vector args, final List listeners, String[] params) { - boolean isJunit4 = true; + private static String processParameters(Vector args, final List listeners, String[] params) { + String agentName = JUNIT4_RUNNER_NAME; Vector result = new Vector(args.size()); for (int i = 0; i < args.size(); i++) { String arg = (String)args.get(i); @@ -84,7 +91,13 @@ public class JUnitStarter { //ignore } else if (arg.equals(JUNIT3_PARAMETER)){ - isJunit4 = false; + agentName = JUNIT3_RUNNER_NAME; + } + else if (arg.equals(JUNIT4_PARAMETER)) { + agentName = JUNIT4_RUNNER_NAME; + } + else if (arg.equals(JUNIT5_PARAMETER)) { + agentName = JUNIT5_RUNNER_NAME; } else { if (arg.startsWith("@name")) { @@ -145,26 +158,22 @@ public class JUnitStarter { String arg = (String)result.get(i); args.addElement(arg); } - if (!isJunit4) { + if (JUNIT3_RUNNER_NAME.equals(agentName)) { try { Class.forName("org.junit.runner.Computer"); + agentName = JUNIT4_RUNNER_NAME; } catch (ClassNotFoundException e) { - return false; + return JUNIT3_RUNNER_NAME; } } + try { final String forceJUnit3 = System.getProperty("idea.force.junit3"); - if (forceJUnit3 != null && Boolean.valueOf(forceJUnit3).booleanValue()) return false; + if (forceJUnit3 != null && Boolean.valueOf(forceJUnit3).booleanValue()) return JUNIT3_RUNNER_NAME; } catch (SecurityException ignored) {} - try { - Class.forName("org.junit.Test"); - return true; - } - catch (ClassNotFoundException e) { - return false; - } + return agentName; } public static boolean checkVersion(String[] args, PrintStream printStream) { @@ -183,9 +192,9 @@ public class JUnitStarter { return false; } - private static boolean canWorkWithJUnitVersion(PrintStream printStream, boolean isJUnit4) { + private static boolean canWorkWithJUnitVersion(PrintStream printStream, String agentName) { try { - junitVersionChecks(isJUnit4); + junitVersionChecks(agentName); } catch (Throwable e) { printStream.println("!!! JUnit version 3.8 or later expected:"); printStream.println(); @@ -198,21 +207,21 @@ public class JUnitStarter { return true; } - private static void junitVersionChecks(boolean isJUnit4) throws ClassNotFoundException { + private static void junitVersionChecks(String agentName) throws ClassNotFoundException { Class.forName("junit.framework.ComparisonFailure"); - getAgentClass(isJUnit4); + getAgentClass(agentName); //noinspection UnnecessaryFullyQualifiedName new junit.textui.TestRunner().setPrinter(new com.intellij.junit3.JUnit3IdeaTestRunner.MockResultPrinter()); } private static int prepareStreamsAndStart(String[] args, - final boolean isJUnit4, + final String agentName, ArrayList listeners, String name) { PrintStream oldOut = System.out; PrintStream oldErr = System.err; try { - IdeaTestRunner testRunner = (IdeaTestRunner)getAgentClass(isJUnit4).newInstance(); + IdeaTestRunner testRunner = (IdeaTestRunner)getAgentClass(agentName).newInstance(); Object out = SM_RUNNER ? System.out : (Object)new SegmentedOutputStream(System.out); Object err = SM_RUNNER ? System.err : (Object)new SegmentedOutputStream(System.err); if (!SM_RUNNER) { @@ -222,7 +231,7 @@ public class JUnitStarter { if (ourCommandFileName != null) { if (!"none".equals(ourForkMode) || ourWorkingDirs != null && new File(ourWorkingDirs).length() > 0) { final List newArgs = new ArrayList(); - newArgs.add(String.valueOf(isJUnit4)); + newArgs.add(agentName); newArgs.addAll(listeners); PrintStream printOutputStream = SM_RUNNER ? ((PrintStream)out) : ((SegmentedOutputStream)out).getPrintStream(); PrintStream printErrStream = SM_RUNNER ? ((PrintStream)err) : ((SegmentedOutputStream)err).getPrintStream(); @@ -243,11 +252,8 @@ public class JUnitStarter { } } - static Class getAgentClass(boolean isJUnit4) throws ClassNotFoundException { - return isJUnit4 - ? Class.forName("com.intellij.junit4.JUnit4IdeaTestRunner") - : Class.forName("com.intellij.junit3.JUnit3IdeaTestRunner"); - + static Class getAgentClass(String agentName) throws ClassNotFoundException { + return Class.forName(agentName); } public static void printClassesList(List classNames, String packageName, String category, File tempFile) throws IOException { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/javadoc/MojoClassAnnotationTagProvider.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/javadoc/MojoClassAnnotationTagProvider.java index 545fb6e99788..f846d7af7ed3 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/javadoc/MojoClassAnnotationTagProvider.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/javadoc/MojoClassAnnotationTagProvider.java @@ -1,20 +1,5 @@ /* - * Copyright 2000-2015 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 org.jetbrains.idea.maven.javadoc;/* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -28,6 +13,7 @@ package org.jetbrains.idea.maven.javadoc;/* * See the License for the specific language governing permissions and * limitations under the License. */ +package org.jetbrains.idea.maven.javadoc; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; @@ -44,7 +30,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; public class MojoClassAnnotationTagProvider implements CustomJavadocTagProvider { - private static final String[] ANNOTATION_NAMES = { "goal", "requiresDependencyResolution", @@ -66,12 +51,11 @@ public class MojoClassAnnotationTagProvider implements CustomJavadocTagProvider } }); } - } class MojoAnnotationInfo implements JavadocTagInfo { - private static final String BASE_CLASS = "org.apache.maven.plugin.Mojo"; + private final String myName; public MojoAnnotationInfo(@NotNull String name) { @@ -97,11 +81,6 @@ class MojoAnnotationInfo implements JavadocTagInfo { return false; } - @Override - public Object[] getPossibleValues(PsiElement context, PsiElement place, String prefix) { - return null; - } - @Nullable @Override public String checkTagValue(PsiDocTagValue value) { @@ -113,7 +92,4 @@ class MojoAnnotationInfo implements JavadocTagInfo { public PsiReference getReference(PsiDocTagValue value) { return null; } -} - - - +} \ No newline at end of file diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index 75e4d6c4f1fc..2c1eb879f09a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -40,8 +40,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.wm.impl.status.StatusBarUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.NotNullFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; +import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -308,7 +310,7 @@ public class SvnUtil { } @NotNull - public static Map, Set> splitChangesIntoWc(@NotNull SvnVcs vcs, @NotNull List changes) { + public static MultiMap, Change> splitChangesIntoWc(@NotNull SvnVcs vcs, @NotNull List changes) { return splitIntoRepositoriesMap(vcs, changes, new Convertor() { @Override public FilePath convert(@NotNull Change change) { @@ -318,12 +320,13 @@ public class SvnUtil { } @NotNull - public static Map, Set> splitIntoRepositoriesMap(@NotNull final SvnVcs vcs, + public static MultiMap, T> splitIntoRepositoriesMap(@NotNull final SvnVcs vcs, @NotNull List items, @NotNull final Convertor converter) { - return ContainerUtil.classify(items.iterator(), new Convertor>() { + return ContainerUtil.groupBy(items, new NotNullFunction>() { + @NotNull @Override - public Pair convert(@NotNull T item) { + public Pair fun(@NotNull T item) { RootUrlInfo path = vcs.getSvnFileUrlMapping().getWcRootForFilePath(converter.convert(item).getIOFile()); return path == null ? UNKNOWN_REPOSITORY_AND_FORMAT : Pair.create(path.getRepositoryUrlUrl(), path.getFormat()); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java index 588e218c0167..63bb448b4a44 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java @@ -40,6 +40,7 @@ import com.intellij.util.NullableFunction; import com.intellij.util.PairConsumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; +import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; @@ -84,8 +85,9 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { private void doCommit(@NotNull List committables, String comment, List exception, final Set feedback) { //noinspection unchecked - Map, Set> map = SvnUtil.splitIntoRepositoriesMap(mySvnVcs, committables, Convertor.SELF); - for (Map.Entry, Set> entry : map.entrySet()) { + MultiMap, FilePath> map = SvnUtil.splitIntoRepositoriesMap(mySvnVcs, committables, Convertor.SELF); + + for (Map.Entry, Collection> entry : map.entrySet()) { try { doCommitOneRepo(entry.getValue(), comment, exception, feedback, entry.getKey().getSecond()); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java index ce9ce271ffa6..272e90bc1ae6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java @@ -17,6 +17,7 @@ package org.jetbrains.idea.svn.rollback; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Couple; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; @@ -29,12 +30,14 @@ import org.jetbrains.idea.svn.*; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.info.Info; import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import java.io.File; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; /** * @author yole @@ -56,9 +59,9 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { @NotNull RollbackProgressListener listener) { listener.indeterminate(); - for (Collection collection : SvnUtil.splitChangesIntoWc(mySvnVcs, changes).values()) { + for (Map.Entry, Collection> entry : SvnUtil.splitChangesIntoWc(mySvnVcs, changes).entrySet()) { // to be more sure about nested changes, being or being not reverted - List sortedChanges = ContainerUtil.sorted(collection, ChangesAfterPathComparator.getInstance()); + List sortedChanges = ContainerUtil.sorted(entry.getValue(), ChangesAfterPathComparator.getInstance()); rollbackGroupForWc(sortedChanges, exceptions, listener); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java index 45f033e937fd..1dc14d36bb51 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java @@ -102,7 +102,7 @@ public class StudyProjectComponent implements ProjectComponent { studyToolWindow.show(null); } if (progressToolWindow != null) { - StudyUtils.updateToolWindows(myProject); + StudyUtils.initToolWindows(myProject); progressToolWindow.show(null); } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index a1ed979c5309..0f68f81654ef 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -18,6 +18,7 @@ import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; @@ -26,26 +27,30 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.ui.JBColor; import com.intellij.ui.awt.RelativePoint; +import com.intellij.ui.content.Content; import com.intellij.util.ui.UIUtil; import com.jetbrains.edu.EduAnswerPlaceholderDeleteHandler; import com.jetbrains.edu.EduAnswerPlaceholderPainter; import com.jetbrains.edu.EduNames; import com.jetbrains.edu.EduUtils; import com.jetbrains.edu.courseFormat.*; -import com.jetbrains.edu.learning.editor.StudyEditor; import com.jetbrains.edu.learning.checker.StudyExecutor; import com.jetbrains.edu.learning.checker.StudyTestRunner; +import com.jetbrains.edu.learning.editor.StudyEditor; import com.jetbrains.edu.learning.ui.StudyProgressToolWindowFactory; +import com.jetbrains.edu.learning.ui.StudyToolWindow; import com.jetbrains.edu.learning.ui.StudyToolWindowFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.awt.*; import java.io.*; import java.util.Collection; @@ -56,6 +61,7 @@ public class StudyUtils { } private static final Logger LOG = Logger.getInstance(StudyUtils.class.getName()); + private static final String EMPTY_TASK_TEXT = "Please, open any task to see task description"; public static void closeSilently(@Nullable final Closeable stream) { if (stream != null) { @@ -122,15 +128,42 @@ public class StudyUtils { } public static void updateToolWindows(@NotNull final Project project) { + final ToolWindowManager windowManager = ToolWindowManager.getInstance(project); + StudyToolWindowFactory factory = new StudyToolWindowFactory(); + factory.update(project); + + createProgressToolWindowContent(project, windowManager); + } + + public static void initToolWindows(@NotNull final Project project) { final ToolWindowManager windowManager = ToolWindowManager.getInstance(project); windowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW).getContentManager().removeAllContents(false); StudyToolWindowFactory factory = new StudyToolWindowFactory(); factory.createToolWindowContent(project, windowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW)); + createProgressToolWindowContent(project, windowManager); + } + + private static void createProgressToolWindowContent(@NotNull Project project, ToolWindowManager windowManager) { windowManager.getToolWindow(StudyProgressToolWindowFactory.ID).getContentManager().removeAllContents(false); StudyProgressToolWindowFactory windowFactory = new StudyProgressToolWindowFactory(); windowFactory.createToolWindowContent(project, windowManager.getToolWindow(StudyProgressToolWindowFactory.ID)); } + + @Nullable + public static StudyToolWindow getStudyToolWindow(@NotNull final Project project) { + ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW); + if (toolWindow != null) { + Content[] contents = toolWindow.getContentManager().getContents(); + for (Content content: contents) { + JComponent component = content.getComponent(); + if (component != null && component instanceof StudyToolWindow) { + return (StudyToolWindow)component; + } + } + } + return null; + } public static void deleteFile(@NotNull final VirtualFile file) { try { @@ -427,4 +460,23 @@ public class StudyUtils { } return null; } + + public static String getTaskText(@NotNull final Project project) { + VirtualFile[] files = FileEditorManager.getInstance(project).getSelectedFiles(); + TaskFile taskFile = null; + for (VirtualFile file : files) { + taskFile = getTaskFile(project, file); + if (taskFile != null) { + break; + } + } + if (taskFile == null) { + return EMPTY_TASK_TEXT; + } + final Task task = taskFile.getTask(); + if (task != null) { + return getTaskTextFromTask(task, task.getTaskDir(project)); + } + return null; + } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java index c03a621624e7..e77592c7e355 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindow.java @@ -21,17 +21,13 @@ import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.FileEditorManagerListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.SimpleToolWindowPanel; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.JBCardLayout; import com.intellij.ui.OnePixelSplitter; import com.intellij.util.ui.JBUI; import com.jetbrains.edu.courseFormat.Course; -import com.jetbrains.edu.courseFormat.Task; -import com.jetbrains.edu.courseFormat.TaskFile; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyToolWindowConfigurator; import com.jetbrains.edu.learning.StudyUtils; @@ -43,7 +39,6 @@ import java.util.Map; public abstract class StudyToolWindow extends SimpleToolWindowPanel implements DataProvider, Disposable { private static final Logger LOG = Logger.getInstance(StudyToolWindow.class); - private static final String EMPTY_TASK_TEXT = "Please, open any task to see task description"; private static final String TASK_INFO_ID = "taskInfo"; private final JBCardLayout myCardLayout; private final JPanel myContentPanel; @@ -57,7 +52,7 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D } public void init(Project project) { - String taskText = getTaskText(project); + String taskText = StudyUtils.getTaskText(project); if (taskText == null) return; JPanel toolbarPanel = createToolbarPanel(project); @@ -117,27 +112,8 @@ public abstract class StudyToolWindow extends SimpleToolWindowPanel implements D public JPanel getContentPanel() { return myContentPanel; } - - - private static String getTaskText(@NotNull final Project project) { - VirtualFile[] files = FileEditorManager.getInstance(project).getSelectedFiles(); - TaskFile taskFile = null; - for (VirtualFile file : files) { - taskFile = StudyUtils.getTaskFile(project, file); - if (taskFile != null) { - break; - } - } - if (taskFile == null) { - return EMPTY_TASK_TEXT; - } - final Task task = taskFile.getTask(); - if (task != null) { - return StudyUtils.getTaskTextFromTask(task, task.getTaskDir(project)); - } - return null; - } - + + public abstract JComponent createTaskInfoPanel(String taskText, Project project); private static JPanel createToolbarPanel(@NotNull final Project project) { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java index c0ededad3dc6..2394f32158cb 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/ui/StudyToolWindowFactory.java @@ -10,6 +10,7 @@ import com.intellij.ui.content.ContentManager; import com.jetbrains.edu.courseFormat.Course; import com.jetbrains.edu.learning.StudyProjectComponent; import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; import icons.InteractiveLearningIcons; import org.jetbrains.annotations.NotNull; @@ -39,4 +40,11 @@ public class StudyToolWindowFactory implements ToolWindowFactory, DumbAware { } } + public void update(Project project) { + final StudyToolWindow studyToolWindow = StudyUtils.getStudyToolWindow(project); + if (studyToolWindow != null) { + String taskText = StudyUtils.getTaskText(project); + studyToolWindow.setTaskText(taskText); + } + } } diff --git a/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py b/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py index 68f83cf73582..69d68d84ce85 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py @@ -1,7 +1,7 @@ from _pydev_bundle.pydev_imports import xmlrpclib, _queue, Exec import sys from _pydevd_bundle.pydevd_constants import IS_JYTHON -from _pydev_imps import _pydev_thread as thread +from _pydev_imps._pydev_saved_modules import thread from _pydevd_bundle import pydevd_xml from _pydevd_bundle import pydevd_vars from _pydevd_bundle.pydevd_utils import * # @UnusedWildImport @@ -489,7 +489,7 @@ class BaseInterpreterInterface: try: # Try to import the packages needed to attach the debugger import pydevd - from _pydev_imps import _pydev_threading as threading + from _pydev_imps._pydev_saved_modules import threading except: # This happens on Jython embedded in host eclipse diff --git a/python/helpers/pydev/_pydev_bundle/pydev_imports.py b/python/helpers/pydev/_pydev_bundle/pydev_imports.py index b6c582dc847c..4adc6b2d3183 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_imports.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_imports.py @@ -4,7 +4,7 @@ from _pydevd_bundle.pydevd_constants import USE_LIB_COPY, izip try: try: if USE_LIB_COPY: - from _pydev_imps import _pydev_xmlrpclib as xmlrpclib + from _pydev_imps._pydev_saved_modules import xmlrpclib else: import xmlrpclib except ImportError: @@ -16,7 +16,8 @@ except ImportError: try: try: if USE_LIB_COPY: - from _pydev_imps._pydev_SimpleXMLRPCServer import SimpleXMLRPCServer + from _pydev_imps._pydev_saved_modules import _pydev_SimpleXMLRPCServer + from _pydev_SimpleXMLRPCServer import SimpleXMLRPCServer else: from SimpleXMLRPCServer import SimpleXMLRPCServer except ImportError: @@ -40,7 +41,7 @@ except NameError: try: if USE_LIB_COPY: - from _pydev_imps import _pydev_Queue as _queue + from _pydev_imps._pydev_saved_modules import _queue else: import Queue as _queue except: diff --git a/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py b/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py index 67be6facb4bc..d1a63d7541e2 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_is_thread_alive.py @@ -1,4 +1,4 @@ -from _pydev_imps import _pydev_threading as threading +from _pydev_imps._pydev_saved_modules import threading # Hack for https://sw-brainwy.rhcloud.com/tracker/PyDev/363 (i.e.: calling isAlive() can throw AssertionError under some circumstances) # It is required to debug threads started by start_new_thread in Python 3.4 diff --git a/python/helpers/pydev/_pydev_bundle/pydev_localhost.py b/python/helpers/pydev/_pydev_bundle/pydev_localhost.py index 9d52635a8b35..3772db295471 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_localhost.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_localhost.py @@ -1,5 +1,5 @@ from _pydevd_bundle import pydevd_constants -from _pydev_imps import _pydev_socket as socket +from _pydev_imps._pydev_saved_modules import socket _cache = None def get_localhost(): diff --git a/python/helpers/pydev/_pydev_bundle/pydev_log.py b/python/helpers/pydev/_pydev_bundle/pydev_log.py index 680907e75a66..ae8f50455294 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_log.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_log.py @@ -1,7 +1,7 @@ import sys from _pydevd_bundle.pydevd_constants import DebugInfoHolder, dict_contains -from _pydev_imps import _pydev_threading -currentThread = _pydev_threading.currentThread +from _pydev_imps._pydev_saved_modules import threading +currentThread = threading.currentThread import traceback diff --git a/python/helpers/pydev/_pydev_imps/_pydev_BaseHTTPServer.py b/python/helpers/pydev/_pydev_imps/_pydev_BaseHTTPServer.py index 5f9dbfd63f4f..f8dd911127f6 100644 --- a/python/helpers/pydev/_pydev_imps/_pydev_BaseHTTPServer.py +++ b/python/helpers/pydev/_pydev_imps/_pydev_BaseHTTPServer.py @@ -71,8 +71,8 @@ __version__ = "0.3" __all__ = ["HTTPServer", "BaseHTTPRequestHandler"] import sys -from _pydev_imps import _pydev_time as time -from _pydev_imps import _pydev_socket as socket +from _pydev_imps._pydev_saved_modules import time +from _pydev_imps._pydev_saved_modules import socket from warnings import filterwarnings, catch_warnings with catch_warnings(): if sys.py3kwarning: diff --git a/python/helpers/pydev/_pydev_imps/_pydev_Queue.py b/python/helpers/pydev/_pydev_imps/_pydev_Queue.py deleted file mode 100644 index 89ae775928be..000000000000 --- a/python/helpers/pydev/_pydev_imps/_pydev_Queue.py +++ /dev/null @@ -1,245 +0,0 @@ -"""A multi-producer, multi-consumer queue.""" - -from _pydev_imps._pydev_time import time as _time -from _pydev_imps import _pydev_thread -try: - from _pydev_imps import _pydev_threading as _threading -except ImportError: - import dummy_threading as _threading -from collections import deque -import heapq - -__all__ = ['Empty', 'Full', 'Queue', 'PriorityQueue', 'LifoQueue'] - -class Empty(Exception): - "Exception raised by Queue.get(block=0)/get_nowait()." - pass - -class Full(Exception): - "Exception raised by Queue.put(block=0)/put_nowait()." - pass - -class Queue: - """Create a queue object with a given maximum size. - - If maxsize is <= 0, the queue size is infinite. - """ - def __init__(self, maxsize=0): - self.maxsize = maxsize - self._init(maxsize) - # mutex must be held whenever the queue is mutating. All methods - # that acquire mutex must release it before returning. mutex - # is shared between the three conditions, so acquiring and - # releasing the conditions also acquires and releases mutex. - self.mutex = _pydev_thread.allocate_lock() - # Notify not_empty whenever an item is added to the queue; a - # thread waiting to get is notified then. - self.not_empty = _threading.Condition(self.mutex) # @UndefinedVariable - # Notify not_full whenever an item is removed from the queue; - # a thread waiting to put is notified then. - self.not_full = _threading.Condition(self.mutex) # @UndefinedVariable - # Notify all_tasks_done whenever the number of unfinished tasks - # drops to zero; thread waiting to join() is notified to resume - self.all_tasks_done = _threading.Condition(self.mutex) # @UndefinedVariable - self.unfinished_tasks = 0 - - def task_done(self): - """Indicate that a formerly enqueued task is complete. - - Used by Queue consumer threads. For each get() used to fetch a task, - a subsequent call to task_done() tells the queue that the processing - on the task is complete. - - If a join() is currently blocking, it will resume when all items - have been processed (meaning that a task_done() call was received - for every item that had been put() into the queue). - - Raises a ValueError if called more times than there were items - placed in the queue. - """ - self.all_tasks_done.acquire() - try: - unfinished = self.unfinished_tasks - 1 - if unfinished <= 0: - if unfinished < 0: - raise ValueError('task_done() called too many times') - self.all_tasks_done.notify_all() - self.unfinished_tasks = unfinished - finally: - self.all_tasks_done.release() - - def join(self): - """Blocks until all items in the Queue have been gotten and processed. - - The count of unfinished tasks goes up whenever an item is added to the - queue. The count goes down whenever a consumer thread calls task_done() - to indicate the item was retrieved and all work on it is complete. - - When the count of unfinished tasks drops to zero, join() unblocks. - """ - self.all_tasks_done.acquire() - try: - while self.unfinished_tasks: - self.all_tasks_done.wait() - finally: - self.all_tasks_done.release() - - def qsize(self): - """Return the approximate size of the queue (not reliable!).""" - self.mutex.acquire() - n = self._qsize() - self.mutex.release() - return n - - def empty(self): - """Return True if the queue is empty, False otherwise (not reliable!).""" - self.mutex.acquire() - n = not self._qsize() - self.mutex.release() - return n - - def full(self): - """Return True if the queue is full, False otherwise (not reliable!).""" - self.mutex.acquire() - n = 0 < self.maxsize == self._qsize() - self.mutex.release() - return n - - def put(self, item, block=True, timeout=None): - """Put an item into the queue. - - If optional args 'block' is true and 'timeout' is None (the default), - block if necessary until a free slot is available. If 'timeout' is - a positive number, it blocks at most 'timeout' seconds and raises - the Full exception if no free slot was available within that time. - Otherwise ('block' is false), put an item on the queue if a free slot - is immediately available, else raise the Full exception ('timeout' - is ignored in that case). - """ - self.not_full.acquire() - try: - if self.maxsize > 0: - if not block: - if self._qsize() == self.maxsize: - raise Full - elif timeout is None: - while self._qsize() == self.maxsize: - self.not_full.wait() - elif timeout < 0: - raise ValueError("'timeout' must be a positive number") - else: - endtime = _time() + timeout - while self._qsize() == self.maxsize: - remaining = endtime - _time() - if remaining <= 0.0: - raise Full - self.not_full.wait(remaining) - self._put(item) - self.unfinished_tasks += 1 - self.not_empty.notify() - finally: - self.not_full.release() - - def put_nowait(self, item): - """Put an item into the queue without blocking. - - Only enqueue the item if a free slot is immediately available. - Otherwise raise the Full exception. - """ - return self.put(item, False) - - def get(self, block=True, timeout=None): - """Remove and return an item from the queue. - - If optional args 'block' is true and 'timeout' is None (the default), - block if necessary until an item is available. If 'timeout' is - a positive number, it blocks at most 'timeout' seconds and raises - the Empty exception if no item was available within that time. - Otherwise ('block' is false), return an item if one is immediately - available, else raise the Empty exception ('timeout' is ignored - in that case). - """ - self.not_empty.acquire() - try: - if not block: - if not self._qsize(): - raise Empty - elif timeout is None: - while not self._qsize(): - self.not_empty.wait() - elif timeout < 0: - raise ValueError("'timeout' must be a positive number") - else: - endtime = _time() + timeout - while not self._qsize(): - remaining = endtime - _time() - if remaining <= 0.0: - raise Empty - self.not_empty.wait(remaining) - item = self._get() - self.not_full.notify() - return item - finally: - self.not_empty.release() - - def get_nowait(self): - """Remove and return an item from the queue without blocking. - - Only get an item if one is immediately available. Otherwise - raise the Empty exception. - """ - return self.get(False) - - # Override these methods to implement other queue organizations - # (e.g. stack or priority queue). - # These will only be called with appropriate locks held - - # Initialize the queue representation - def _init(self, maxsize): - self.queue = deque() - - def _qsize(self, len=len): - return len(self.queue) - - # Put a new item in the queue - def _put(self, item): - self.queue.append(item) - - # Get an item from the queue - def _get(self): - return self.queue.popleft() - - -class PriorityQueue(Queue): - '''Variant of Queue that retrieves open entries in priority order (lowest first). - - Entries are typically tuples of the form: (priority number, data). - ''' - - def _init(self, maxsize): - self.queue = [] - - def _qsize(self, len=len): - return len(self.queue) - - def _put(self, item, heappush=heapq.heappush): - heappush(self.queue, item) - - def _get(self, heappop=heapq.heappop): - return heappop(self.queue) - - -class LifoQueue(Queue): - '''Variant of Queue that retrieves most recently added entries first.''' - - def _init(self, maxsize): - self.queue = [] - - def _qsize(self, len=len): - return len(self.queue) - - def _put(self, item): - self.queue.append(item) - - def _get(self): - return self.queue.pop() diff --git a/python/helpers/pydev/_pydev_imps/_pydev_SocketServer.py b/python/helpers/pydev/_pydev_imps/_pydev_SocketServer.py index 991a1678b05a..7af2777ac7ea 100644 --- a/python/helpers/pydev/_pydev_imps/_pydev_SocketServer.py +++ b/python/helpers/pydev/_pydev_imps/_pydev_SocketServer.py @@ -129,12 +129,12 @@ BaseServer: __version__ = "0.4" -from _pydev_imps import _pydev_socket as socket -from _pydev_imps import _pydev_select as select +from _pydev_imps._pydev_saved_modules import socket +from _pydev_imps._pydev_saved_modules import select import sys import os try: - from _pydev_imps import _pydev_threading as threading + from _pydev_imps._pydev_saved_modules import threading except ImportError: import dummy_threading as threading diff --git a/python/helpers/pydev/_pydev_imps/_pydev_saved_modules.py b/python/helpers/pydev/_pydev_imps/_pydev_saved_modules.py new file mode 100644 index 000000000000..35dc0a6a9768 --- /dev/null +++ b/python/helpers/pydev/_pydev_imps/_pydev_saved_modules.py @@ -0,0 +1,32 @@ +import threading + +try: + import thread +except: + import _thread as thread + +import time + +import socket + +import select + +try: + import Queue as _queue +except: + import queue as _queue + +try: + import xmlrpclib +except: + import xmlrpc.client as xmlrpclib + +try: + import SimpleXMLRPCServer as _pydev_SimpleXMLRPCServer +except: + import xmlrpc.server as _pydev_SimpleXMLRPCServer + +try: + import BaseHTTPServer +except: + import http.server as BaseHTTPServer \ No newline at end of file diff --git a/python/helpers/pydev/_pydev_imps/_pydev_select.py b/python/helpers/pydev/_pydev_imps/_pydev_select.py deleted file mode 100644 index d582beb80b72..000000000000 --- a/python/helpers/pydev/_pydev_imps/_pydev_select.py +++ /dev/null @@ -1,9 +0,0 @@ -from select import * - -try: - from gevent import monkey # @UnresolvedImport - saved = monkey.saved['select'] - for key, val in saved.items(): - globals()[key] = val -except: - pass \ No newline at end of file diff --git a/python/helpers/pydev/_pydev_imps/_pydev_socket.py b/python/helpers/pydev/_pydev_imps/_pydev_socket.py deleted file mode 100644 index 84e29021c4a1..000000000000 --- a/python/helpers/pydev/_pydev_imps/_pydev_socket.py +++ /dev/null @@ -1,9 +0,0 @@ -from socket import * - -try: - from gevent import monkey # @UnresolvedImport - saved = monkey.saved['socket'] - for key, val in saved.items(): - globals()[key] = val -except: - pass \ No newline at end of file diff --git a/python/helpers/pydev/_pydev_imps/_pydev_thread.py b/python/helpers/pydev/_pydev_imps/_pydev_thread.py deleted file mode 100644 index c996aef8a572..000000000000 --- a/python/helpers/pydev/_pydev_imps/_pydev_thread.py +++ /dev/null @@ -1,12 +0,0 @@ -try: - from thread import * -except: - from _thread import * #Py3k - -try: - from gevent import monkey # @UnresolvedImport - saved = monkey.saved['thread'] - for key, val in saved.items(): - globals()[key] = val -except: - pass diff --git a/python/helpers/pydev/_pydev_imps/_pydev_threading.py b/python/helpers/pydev/_pydev_imps/_pydev_threading.py deleted file mode 100644 index 9bb01ae42a33..000000000000 --- a/python/helpers/pydev/_pydev_imps/_pydev_threading.py +++ /dev/null @@ -1,21 +0,0 @@ -from threading import * # Make up for things we may forget @UnusedWildImport - -# Force what we know we need -from threading import enumerate, currentThread, Condition, Event, Thread, Lock -try: - from threading import settrace -except: - pass -try: - from threading import Timer -except: - pass # Jython 2.1 - - -try: - from gevent import monkey # @UnresolvedImport - saved = monkey.saved['threading'] - for key, val in saved.items(): - globals()[key] = val -except: - pass diff --git a/python/helpers/pydev/_pydev_imps/_pydev_time.py b/python/helpers/pydev/_pydev_imps/_pydev_time.py deleted file mode 100644 index 5a877d853ad0..000000000000 --- a/python/helpers/pydev/_pydev_imps/_pydev_time.py +++ /dev/null @@ -1,9 +0,0 @@ -from time import * - -try: - from gevent import monkey # @UnresolvedImport - saved = monkey.saved['time'] - for key, val in saved.items(): - globals()[key] = val -except: - pass diff --git a/python/helpers/pydev/_pydev_runfiles/pydev_runfiles_parallel.py b/python/helpers/pydev/_pydev_runfiles/pydev_runfiles_parallel.py index f91391bb5c39..f1c003f5221d 100644 --- a/python/helpers/pydev/_pydev_runfiles/pydev_runfiles_parallel.py +++ b/python/helpers/pydev/_pydev_runfiles/pydev_runfiles_parallel.py @@ -1,5 +1,5 @@ import unittest -from _pydev_imps import _pydev_thread +from _pydev_imps._pydev_saved_modules import thread try: import Queue except: @@ -283,9 +283,9 @@ class ClientThread(threading.Thread): if False: proc = subprocess.Popen(args, env=os.environ, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - _pydev_thread.start_new_thread(self._reader_thread,(proc.stdout, sys.stdout)) + thread.start_new_thread(self._reader_thread,(proc.stdout, sys.stdout)) - _pydev_thread.start_new_thread(target=self._reader_thread,args=(proc.stderr, sys.stderr)) + thread.start_new_thread(target=self._reader_thread,args=(proc.stderr, sys.stderr)) else: proc = subprocess.Popen(args, env=os.environ, shell=False) proc.wait() diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_additional_thread_info_regular.py b/python/helpers/pydev/_pydevd_bundle/pydevd_additional_thread_info_regular.py index fc0b564d9f3e..a5590627b3ba 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_additional_thread_info_regular.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_additional_thread_info_regular.py @@ -1,6 +1,6 @@ import sys import weakref -from _pydev_imps import _pydev_thread +from _pydev_imps._pydev_saved_modules import thread from _pydevd_bundle.pydevd_constants import STATE_RUN, PYTHON_SUSPEND, dict_iter_items from _pydevd_bundle.pydevd_frame import PyDBFrame @@ -109,7 +109,7 @@ class PyDBAdditionalThreadInfoWithoutCurrentFramesSupport(PyDBAdditionalThreadIn #Or if the user compiled threadframe (from http://www.majid.info/mylos/stories/2004/06/10/threadframe.html) #NOT RLock!! (could deadlock if it was) - self.lock = _pydev_thread.allocate_lock() + self.lock = thread.allocate_lock() self._acquire_lock = self.lock.acquire self._release_lock = self.lock.release diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_breakpoints.py b/python/helpers/pydev/_pydevd_bundle/pydevd_breakpoints.py index 2ecae4071ad8..ae990f130a8a 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_breakpoints.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_breakpoints.py @@ -8,7 +8,7 @@ _original_excepthook = None _handle_exceptions = None -from _pydev_imps import _pydev_threading as threading +from _pydev_imps._pydev_saved_modules import threading threadingCurrentThread = threading.currentThread diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py index 60ba0ac8d049..14fb74d11792 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py @@ -59,8 +59,10 @@ each command has a format: ''' from _pydev_bundle.pydev_imports import _queue -from _pydev_imps import _pydev_time as time, _pydev_thread -from _pydev_imps._pydev_socket import socket, AF_INET, SOCK_STREAM, SHUT_RD, SHUT_WR +from _pydev_imps._pydev_saved_modules import time +from _pydev_imps._pydev_saved_modules import thread +from _pydev_imps._pydev_saved_modules import socket +from socket import socket, AF_INET, SOCK_STREAM, SHUT_RD, SHUT_WR from _pydevd_bundle.pydevd_constants import * #@UnusedWildImport try: @@ -812,7 +814,7 @@ class ReloadCodeCommand(InternalThreadCommand): self.thread_id = thread_id self.module_name = module_name self.executed = False - self.lock = _pydev_thread.allocate_lock() + self.lock = thread.allocate_lock() def can_be_executed_by(self, thread_id): diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_constants.py b/python/helpers/pydev/_pydevd_bundle/pydevd_constants.py index cfc0f5de50c9..a7794b19bf3b 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_constants.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_constants.py @@ -95,11 +95,43 @@ except: # Jython 2.1 doesn't accept that construct SUPPORT_GEVENT = False -USE_LIB_COPY = SUPPORT_GEVENT and not IS_PY3K and sys.version_info[1] >= 6 -from _pydev_imps import _pydev_threading as threading +# At the moment gevent supports Python >= 2.6 and Python >= 3.3 +USE_LIB_COPY = SUPPORT_GEVENT and \ + ((not IS_PY3K and sys.version_info[1] >= 6) or + (IS_PY3K and sys.version_info[1] >= 3)) -from _pydev_imps import _pydev_thread -_nextThreadIdLock = _pydev_thread.allocate_lock() + +def protect_libraries_from_patching(): + patched = ['threading', 'thread', '_thread', 'time', 'socket', 'Queue', 'queue', 'select', + 'xmlrpclib', 'SimpleXMLRPCServer', 'BaseHTTPServer', 'SocketServer', + 'xmlrpc.client', 'xmlrpc.server', 'http.server', 'socketserver'] + + for name in patched: + try: + __import__(name) + except: + pass + + patched_modules = dict([(k, v) for k, v in sys.modules.items() + if k in patched]) + + for name in patched_modules: + del sys.modules[name] + + import _pydev_imps._pydev_saved_modules + + for name in patched_modules: + sys.modules[name] = patched_modules[name] + + +if USE_LIB_COPY: + protect_libraries_from_patching() + + +from _pydev_imps._pydev_saved_modules import threading + +from _pydev_imps._pydev_saved_modules import thread +_nextThreadIdLock = thread.allocate_lock() #======================================================================================================================= # Jython? diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_custom_frames.py b/python/helpers/pydev/_pydevd_bundle/pydevd_custom_frames.py index 0b72ca889cf5..79f77fd914ff 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_custom_frames.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_custom_frames.py @@ -1,6 +1,6 @@ from _pydevd_bundle.pydevd_constants import * #@UnusedWildImport from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame -from _pydev_imps import _pydev_thread +from _pydev_imps._pydev_saved_modules import thread threadingCurrentThread = threading.currentThread DEBUG = False @@ -22,7 +22,7 @@ class CustomFramesContainer: def custom_frames_container_init(): #Note: no staticmethod on jython 2.1 (so, use free-function) - CustomFramesContainer.custom_frames_lock = _pydev_thread.allocate_lock() + CustomFramesContainer.custom_frames_lock = thread.allocate_lock() # custom_frames can only be accessed if properly locked with custom_frames_lock! # Key is a string identifying the frame (as well as the thread it belongs to). diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py b/python/helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py index ec5f12d19c30..79d231878904 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py @@ -1,7 +1,7 @@ import traceback from _pydev_bundle.pydev_is_thread_alive import is_thread_alive -from _pydev_imps import _pydev_threading as threading +from _pydev_imps._pydev_saved_modules import threading from _pydevd_bundle.pydevd_constants import get_thread_id from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE from _pydevd_bundle.pydevd_kill_all_pydevd_threads import kill_all_pydev_threads diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_tracing.py b/python/helpers/pydev/_pydevd_bundle/pydevd_tracing.py index 4674a928f9e7..c1c5a0fdb939 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_tracing.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_tracing.py @@ -1,5 +1,5 @@ from _pydevd_bundle.pydevd_constants import * #@UnusedWildImport -from _pydev_imps import _pydev_thread +from _pydev_imps._pydev_saved_modules import thread try: import cStringIO as StringIO #may not always be available @UnusedImport @@ -20,7 +20,7 @@ class TracingFunctionHolder: ''' _original_tracing = None _warn = True - _lock = _pydev_thread.allocate_lock() + _lock = thread.allocate_lock() _traceback_limit = 1 _warnings_shown = {} diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_vars.py b/python/helpers/pydev/_pydevd_bundle/pydevd_vars.py index 6f3b1841f9e6..d928528c038a 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_vars.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_vars.py @@ -7,7 +7,7 @@ from types import * #@UnusedWildImport from _pydevd_bundle.pydevd_custom_frames import get_custom_frame from _pydevd_bundle.pydevd_xml import * -from _pydev_imps import _pydev_thread +from _pydev_imps._pydev_saved_modules import thread try: from StringIO import StringIO @@ -15,7 +15,7 @@ except ImportError: from io import StringIO import sys #@Reimport -from _pydev_imps import _pydev_threading as threading +from _pydev_imps._pydev_saved_modules import threading import traceback from _pydevd_bundle import pydevd_save_locals from _pydev_bundle.pydev_imports import Exec, quote, execfile @@ -68,7 +68,7 @@ def dump_frames(thread_id): # AdditionalFramesContainer #=============================================================================== class AdditionalFramesContainer: - lock = _pydev_thread.allocate_lock() + lock = thread.allocate_lock() additional_frames = {} #dict of dicts diff --git a/python/helpers/pydev/pycompletionserver.py b/python/helpers/pydev/pycompletionserver.py index baa54c90628f..913951032ddb 100644 --- a/python/helpers/pydev/pycompletionserver.py +++ b/python/helpers/pydev/pycompletionserver.py @@ -32,7 +32,7 @@ else: from _pydev_bundle import _pydev_imports_tipper -from _pydev_imps import _pydev_socket as socket +from _pydev_imps._pydev_saved_modules import socket import sys if sys.platform == "darwin": @@ -57,7 +57,7 @@ for name, mod in sys.modules.items(): import traceback -from _pydev_imps import _pydev_time as time +from _pydev_imps._pydev_saved_modules import time try: import StringIO @@ -194,7 +194,7 @@ class CompletionServer: def connect_to_server(self): - from _pydev_imps import _pydev_socket as socket + from _pydev_imps._pydev_saved_modules import socket self.socket = s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: diff --git a/python/helpers/pydev/pydev_ipython/inputhookglut.py b/python/helpers/pydev/pydev_ipython/inputhookglut.py index 6551bb99ace6..bbd6882fe8ec 100644 --- a/python/helpers/pydev/pydev_ipython/inputhookglut.py +++ b/python/helpers/pydev/pydev_ipython/inputhookglut.py @@ -31,7 +31,7 @@ GLUT Inputhook support functions #----------------------------------------------------------------------------- import os import sys -from _pydev_imps import _pydev_time as time +from _pydev_imps._pydev_saved_modules import time import signal import OpenGL.GLUT as glut # @UnresolvedImport import OpenGL.platform as platform # @UnresolvedImport diff --git a/python/helpers/pydev/pydev_ipython/inputhookpyglet.py b/python/helpers/pydev/pydev_ipython/inputhookpyglet.py index 98a7878ccb75..bf08afdc779d 100644 --- a/python/helpers/pydev/pydev_ipython/inputhookpyglet.py +++ b/python/helpers/pydev/pydev_ipython/inputhookpyglet.py @@ -22,7 +22,7 @@ Authors import os import sys -from _pydev_imps import _pydev_time as time +from _pydev_imps._pydev_saved_modules import time from timeit import default_timer as clock import pyglet # @UnresolvedImport from pydev_ipython.inputhook import stdin_ready diff --git a/python/helpers/pydev/pydev_ipython/inputhookwx.py b/python/helpers/pydev/pydev_ipython/inputhookwx.py index 6b72d61091b4..88fe2c6e3ba1 100644 --- a/python/helpers/pydev/pydev_ipython/inputhookwx.py +++ b/python/helpers/pydev/pydev_ipython/inputhookwx.py @@ -18,7 +18,7 @@ Authors: Robin Dunn, Brian Granger, Ondrej Certik import sys import signal -from _pydev_imps import _pydev_time as time +from _pydev_imps._pydev_saved_modules import time from timeit import default_timer as clock import wx diff --git a/python/helpers/pydev/pydevconsole.py b/python/helpers/pydev/pydevconsole.py index bb1f48266c6d..92198f715aff 100644 --- a/python/helpers/pydev/pydevconsole.py +++ b/python/helpers/pydev/pydevconsole.py @@ -1,7 +1,8 @@ ''' Entry point module to start the interactive console. ''' -from _pydev_imps._pydev_thread import start_new_thread +from _pydev_imps._pydev_saved_modules import thread +start_new_thread = thread.start_new_thread try: from code import InteractiveConsole @@ -14,7 +15,7 @@ from code import InteractiveInterpreter import os import sys -from _pydev_imps import _pydev_threading as threading +from _pydev_imps._pydev_saved_modules import threading import traceback from _pydev_bundle import fix_getpass diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index baeadb3601e5..5c608e335704 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -10,12 +10,16 @@ import os import sys import traceback +from _pydevd_bundle.pydevd_constants import IS_JYTH_LESS25, IS_PY3K, IS_PY34_OLDER, get_thread_id, dict_keys, dict_pop, dict_contains, \ + dict_iter_items, DebugInfoHolder, PYTHON_SUSPEND, STATE_SUSPEND, STATE_RUN, get_frame, xrange, \ + clear_cached_thread_id from _pydev_bundle import fix_getpass from _pydev_bundle import pydev_imports, pydev_log from _pydev_bundle._pydev_filesystem_encoding import getfilesystemencoding from _pydev_bundle.pydev_is_thread_alive import is_thread_alive -from _pydev_imps import _pydev_threading as threading -from _pydev_imps import _pydev_time as time, _pydev_thread +from _pydev_imps._pydev_saved_modules import threading +from _pydev_imps._pydev_saved_modules import time +from _pydev_imps._pydev_saved_modules import thread from _pydevd_bundle import pydevd_io, pydevd_vm_type, pydevd_tracing from _pydevd_bundle import pydevd_utils from _pydevd_bundle import pydevd_vars @@ -28,9 +32,6 @@ from _pydevd_bundle.pydevd_comm import CMD_SET_BREAK, CMD_SET_NEXT_STATEMENT, CM set_global_debugger, WriterThread, pydevd_find_thread_by_id, pydevd_log, \ start_client, start_server, InternalGetBreakpointException, InternalSendCurrExceptionTrace, \ InternalSendCurrExceptionTraceProceeded -from _pydevd_bundle.pydevd_constants import IS_JYTH_LESS25, IS_PY3K, IS_PY34_OLDER, get_thread_id, dict_keys, dict_pop, dict_contains, \ - dict_iter_items, DebugInfoHolder, PYTHON_SUSPEND, STATE_SUSPEND, STATE_RUN, get_frame, xrange, \ - clear_cached_thread_id from _pydevd_bundle.pydevd_custom_frames import CustomFramesContainer, custom_frames_container_init from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame from _pydevd_bundle.pydevd_kill_all_pydevd_threads import kill_all_pydev_threads @@ -202,8 +203,8 @@ class PyDB: self.break_on_caught_exceptions = {} self.ready_to_run = False - self._main_lock = _pydev_thread.allocate_lock() - self._lock_running_thread_ids = _pydev_thread.allocate_lock() + self._main_lock = thread.allocate_lock() + self._lock_running_thread_ids = thread.allocate_lock() self._py_db_command_thread_event = threading.Event() CustomFramesContainer._py_db_command_thread_event = self._py_db_command_thread_event self._finish_debugging_session = False @@ -1131,7 +1132,7 @@ def settrace( -_set_trace_lock = _pydev_thread.allocate_lock() +_set_trace_lock = thread.allocate_lock() def _locked_settrace( host, diff --git a/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_concurrency_logger.py b/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_concurrency_logger.py index 4377421507c0..6fe9fe06a72a 100644 --- a/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_concurrency_logger.py +++ b/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_concurrency_logger.py @@ -13,7 +13,7 @@ try: except: from urllib.parse import quote # @UnresolvedImport -from _pydev_imps import _pydev_threading as threading +from _pydev_imps._pydev_saved_modules import threading threadingCurrentThread = threading.currentThread diff --git a/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_thread_wrappers.py b/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_thread_wrappers.py index 1d093563f228..8658a7612457 100644 --- a/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_thread_wrappers.py +++ b/python/helpers/pydev/pydevd_concurrency_analyser/pydevd_thread_wrappers.py @@ -1,4 +1,4 @@ -from _pydev_imps import _pydev_threading as threading +from _pydev_imps._pydev_saved_modules import threading def wrapper(fun): diff --git a/python/helpers/pydev/tests/test_pyserver.py b/python/helpers/pydev/tests/test_pyserver.py index 95e7471328b7..98fe2a97f7d0 100644 --- a/python/helpers/pydev/tests/test_pyserver.py +++ b/python/helpers/pydev/tests/test_pyserver.py @@ -4,10 +4,12 @@ import sys import os try: - from _pydev_imps._pydev_thread import start_new_thread + from _pydev_imps._pydev_saved_modules import thread + start_new_thread = thread.start_new_thread except: sys.path.append(os.path.dirname(os.path.dirname(__file__))) - from _pydev_imps._pydev_thread import start_new_thread + from _pydev_imps._pydev_saved_modules import thread + start_new_thread = thread.start_new_thread #make it as if we were executing from the directory above this one (so that we can use pycompletionserver diff --git a/python/helpers/python-skeletons/__builtin__.py b/python/helpers/python-skeletons/__builtin__.py index d9f63538c4d9..95ace39a878a 100644 --- a/python/helpers/python-skeletons/__builtin__.py +++ b/python/helpers/python-skeletons/__builtin__.py @@ -2390,7 +2390,7 @@ class file(object): def next(self): """Returns the next input line. - :rtype: bytes | unicode + :rtype: bytes """ return '' @@ -2399,7 +2399,7 @@ class file(object): before obtaining size bytes). :type size: numbers.Integral - :rtype: bytes | unicode + :rtype: bytes """ return '' @@ -2407,7 +2407,7 @@ class file(object): """Read one entire line from the file. :type size: numbers.Integral - :rtype: bytes | unicode + :rtype: bytes """ return '' @@ -2416,14 +2416,14 @@ class file(object): lines thus read. :type sizehint: numbers.Integral - :rtype: list[bytes | unicode] + :rtype: list[bytes] """ return [] def xreadlines(self): """This method returns the same thing as iter(f). - :rtype: collections.Iterable[bytes | unicode] + :rtype: collections.Iterable[bytes] """ return [] @@ -2454,7 +2454,7 @@ class file(object): def write(self, str): """"Write a string to the file. - :type str: bytes | unicode + :type str: bytes :rtype: None """ pass @@ -2462,7 +2462,7 @@ class file(object): def writelines(self, sequence): """Write a sequence of strings to the file. - :type sequence: collections.Iterable[bytes | unicode] + :type sequence: collections.Iterable[bytes] :rtype: None """ pass diff --git a/python/helpers/rest_formatter.py b/python/helpers/rest_formatter.py index 76b988426139..b0241e4cd2f2 100644 --- a/python/helpers/rest_formatter.py +++ b/python/helpers/rest_formatter.py @@ -224,7 +224,7 @@ class RestHTMLTranslator(HTMLTranslator): return HTMLTranslator.visit_problematic(self, node) directive, text = self._strip_markup(node.astext()) - if directive[1:-1] in ('exc', 'class'): + if directive and directive[1:-1] in ('exc', 'class'): self.body.append(self.starttag(node, 'a', '', href='psi_element://#typename#' + text)) self.body.append(text) self.body.append('') diff --git a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java index 18b259214ea7..27be6ff10510 100644 --- a/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java +++ b/python/ipnb/src/org/jetbrains/plugins/ipnb/configuration/IpnbConnectionManager.java @@ -94,29 +94,22 @@ public final class IpnbConnectionManager implements ProjectComponent { } private void startConnection(@NotNull final IpnbCodePanel codePanel, final IpnbFileEditor fileEditor, final String path) { - String url = IpnbSettings.getInstance(myProject).getURL(); - if (StringUtil.isEmptyOrSpaces(url)) { - url = IpnbSettings.DEFAULT_URL; - } + String url = getURL(); boolean connectionStarted = startConnection(codePanel, path, url, false); if (!connectionStarted) { - final String finalUrl = url; - url = showDialogUrl(url); - if (url == null) return; - IpnbSettings.getInstance(myProject).setURL(url); ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { - final boolean serverStarted = startIpythonServer(finalUrl, fileEditor); + final boolean serverStarted = startIpythonServer(url, fileEditor); if (!serverStarted) { return; } UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { - startConnection(codePanel, path, finalUrl, true); + startConnection(codePanel, path, url, true); } }); } @@ -124,29 +117,39 @@ public final class IpnbConnectionManager implements ProjectComponent { } } + private String getURL() { + String url = IpnbSettings.getInstance(myProject).getURL(); + return StringUtil.isEmptyOrSpaces(url) ? IpnbSettings.DEFAULT_URL : url; + } + @Nullable public static String showDialogUrl(@NotNull final String initialUrl) { - final String url = Messages.showInputDialog("Jupyter Notebook URL:", "Start Jupyter Notebook", null, initialUrl, - new InputValidator() { - @Override - public boolean checkInput(String inputString) { - try { - final URI uri = new URI(inputString); - if (uri.getPort() == -1 || StringUtil.isEmptyOrSpaces(uri.getHost())) { - return false; - } - } - catch (URISyntaxException e) { - return false; - } - return !inputString.isEmpty(); - } + final String url = UIUtil.invokeAndWaitIfNeeded(new Computable() { + @Override + public String compute() { + return Messages.showInputDialog("Jupyter Notebook URL:", "Start Jupyter Notebook", null, initialUrl, + new InputValidator() { + @Override + public boolean checkInput(String inputString) { + try { + final URI uri = new URI(inputString); + if (uri.getPort() == -1 || StringUtil.isEmptyOrSpaces(uri.getHost())) { + return false; + } + } + catch (URISyntaxException e) { + return false; + } + return !inputString.isEmpty(); + } - @Override - public boolean canClose(String inputString) { - return true; - } - }); + @Override + public boolean canClose(String inputString) { + return true; + } + }); + } + }); return url == null ? null : StringUtil.trimEnd(url, "/"); } @@ -258,7 +261,7 @@ public final class IpnbConnectionManager implements ProjectComponent { }); } - public boolean startIpythonServer(@NotNull final String url, @NotNull final IpnbFileEditor fileEditor) { + public boolean startIpythonServer(@NotNull final String initUrl, @NotNull final IpnbFileEditor fileEditor) { final Module module = ProjectFileIndex.SERVICE.getInstance(myProject).getModuleForFile(fileEditor.getVirtualFile()); if (module == null) return false; final Sdk sdk = PythonSdkType.findPythonSdk(module); @@ -268,7 +271,8 @@ public final class IpnbConnectionManager implements ProjectComponent { } try { final PyPackage ipythonPackage = PyPackageManager.getInstance(sdk).findPackage("ipython", false); - if (ipythonPackage == null) { + final PyPackage jupyterPackage = PyPackageManager.getInstance(sdk).findPackage("jupyter", false); + if (ipythonPackage == null && jupyterPackage == null) { showWarning(fileEditor, "Add Jupyter to the interpreter of the current project.", null); return false; } @@ -276,6 +280,10 @@ public final class IpnbConnectionManager implements ProjectComponent { catch (ExecutionException ignored) { } + String url = showDialogUrl(initUrl); + if (url == null) return false; + IpnbSettings.getInstance(myProject).setURL(url); + final Pair hostPort = getHostPortFromUrl(url); if (hostPort == null) { showWarning(fileEditor, "Please, check Jupyter Notebook URL in Settings->Tools->Jupyter Notebook", diff --git a/python/pluginJava/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginJava/com/jetbrains/python/psi/impl/PyJavaClassType.java index 651b55ad18c8..ef2526744022 100644 --- a/python/pluginJava/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginJava/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -31,9 +31,7 @@ import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; /** * @author yole @@ -49,7 +47,7 @@ public class PyJavaClassType implements PyClassLikeType { @Nullable public List resolveMember(@NotNull final String name, - PyExpression location, + @Nullable PyExpression location, @NotNull AccessDirection direction, @NotNull PyResolveContext resolveContext) { return resolveMember(name, location, direction, resolveContext, true); @@ -153,14 +151,72 @@ public class PyJavaClassType implements PyClassLikeType { @Override public void visitMembers(@NotNull final Processor processor, final boolean inherited, @NotNull TypeEvalContext context) { - // TODO: Implement + for (PsiMethod method : myClass.getAllMethods()) { + processor.process(method); + } + + for (PsiField field : myClass.getAllFields()) { + processor.process(field); + } + + if (!inherited) { + return; + } + + for (PyClassLikeType type : getAncestorTypes(context)) { + if (type != null) { + type.visitMembers(processor, false, context); + } + } + } + + @NotNull + @Override + public Set getMemberNames(boolean inherited, @NotNull TypeEvalContext context) { + final Set result = new LinkedHashSet<>(); + + for (PsiMethod method : myClass.getAllMethods()) { + result.add(method.getName()); + } + + for (PsiField field : myClass.getAllFields()) { + result.add(field.getName()); + } + + if (inherited) { + for (PyClassLikeType type : getAncestorTypes(context)) { + if (type != null) { + result.addAll(type.getMemberNames(false, context)); + } + } + } + + return result; } @NotNull @Override public List getAncestorTypes(@NotNull final TypeEvalContext context) { - // TODO: Implement - return Collections.emptyList(); + final List result = new ArrayList<>(); + + final Deque deque = new LinkedList<>(); + final Set visited = new HashSet<>(); + + deque.addAll(Arrays.asList(myClass.getSupers())); + + while (!deque.isEmpty()) { + final PsiClass current = deque.pollFirst(); + + if (current == null || !visited.add(current)) { + continue; + } + + result.add(new PyJavaClassType(current, myDefinition)); + + deque.addAll(Arrays.asList(current.getSupers())); + } + + return result; } @Override diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java index 4cf201e14652..f7d40633fd48 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyClassLikeType.java @@ -26,6 +26,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Set; /** * @author vlan @@ -42,8 +43,10 @@ public interface PyClassLikeType extends PyCallableType, PyWithAncestors { List getSuperClassTypes(@NotNull TypeEvalContext context); @Nullable - List resolveMember(@NotNull final String name, @Nullable PyExpression location, - @NotNull AccessDirection direction, @NotNull PyResolveContext resolveContext, + List resolveMember(@NotNull final String name, + @Nullable PyExpression location, + @NotNull AccessDirection direction, + @NotNull PyResolveContext resolveContext, boolean inherited); // TODO: Pull to PyType at next iteration @@ -58,6 +61,9 @@ public interface PyClassLikeType extends PyCallableType, PyWithAncestors { */ void visitMembers(@NotNull Processor processor, boolean inherited, @NotNull TypeEvalContext context); + @NotNull + Set getMemberNames(boolean inherited, @NotNull TypeEvalContext context); + boolean isValid(); @Nullable diff --git a/python/src/com/jetbrains/python/PyCustomType.java b/python/src/com/jetbrains/python/PyCustomType.java index d01170f9d40f..f8dd377fa589 100644 --- a/python/src/com/jetbrains/python/PyCustomType.java +++ b/python/src/com/jetbrains/python/PyCustomType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -112,7 +112,10 @@ public class PyCustomType implements PyClassLikeType { // Delegate calls to classes, we mimic but filter if filter is set. for (final PyClassLikeType typeToMimic : myTypesToMimic) { - final List results = typeToMimic.toInstance().resolveMember(name, location, direction, resolveContext, inherited); + final List results = typeToMimic.toInstance().resolveMember( + name, location, direction, resolveContext, inherited + ); + if (results != null) { globalResult.addAll(Collections2.filter(results, new ResolveFilter())); } @@ -253,7 +256,9 @@ public class PyCustomType implements PyClassLikeType { } @Override - public final void visitMembers(@NotNull final Processor processor, final boolean inherited, @NotNull final TypeEvalContext context) { + public final void visitMembers(@NotNull final Processor processor, + final boolean inherited, + @NotNull final TypeEvalContext context) { for (final PyClassLikeType type : myTypesToMimic) { // Only visit methods that are allowed by filter (if any) type.visitMembers(new Processor() { @@ -271,6 +276,18 @@ public class PyCustomType implements PyClassLikeType { } } + @NotNull + @Override + public Set getMemberNames(boolean inherited, @NotNull TypeEvalContext context) { + final Set result = new LinkedHashSet<>(); + + for (PyClassLikeType type : myTypesToMimic) { + result.addAll(type.getMemberNames(inherited, context)); + } + + return result; + } + /** * Predicate that filters completion using {@link #myFilter} */ diff --git a/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java index 8d267245eb8f..d414e9abead1 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/PyTypingTypeProvider.java @@ -25,6 +25,7 @@ import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.HashSet; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyExpressionCodeFragmentImpl; @@ -82,7 +83,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { // XXX: Requires switching from stub to AST final PyExpression value = annotation.getValue(); if (value != null) { - final PyType type = getType(value, context); + final PyType type = getType(value, new Context(context)); if (type != null) { final PyType optionalType = getOptionalTypeFromDefaultNone(param, type, context); return Ref.create(optionalType != null ? optionalType : type); @@ -126,11 +127,11 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { // XXX: Requires switching from stub to AST final PyExpression value = annotation.getValue(); if (value != null) { - final PyType type = getType(value, context); + final PyType type = getType(value, new Context(context)); return type != null ? Ref.create(type) : null; } } - final PyType constructorType = getGenericConstructorType(function, context); + final PyType constructorType = getGenericConstructorType(function, new Context(context)); if (constructorType != null) { return Ref.create(constructorType); } @@ -154,7 +155,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { final PyExpression[] args = callExpr.getArguments(); if (args.length > 0) { final PyExpression typeExpr = args[0]; - return getType(typeExpr, context); + return getType(typeExpr, new Context(context)); } } return null; @@ -166,7 +167,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { final PyTargetExpression target = (PyTargetExpression)referenceTarget; final String comment = getTypeComment(target); if (comment != null) { - final PyType type = getStringBasedType(comment, referenceTarget, context); + final PyType type = getStringBasedType(comment, referenceTarget, new Context(context)); if (type instanceof PyTupleType) { final PyTupleExpression tupleExpr = PsiTreeUtil.getParentOfType(target, PyTupleExpression.class); if (tupleExpr != null) { @@ -243,7 +244,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getGenericConstructorType(@NotNull PyFunction function, @NotNull TypeEvalContext context) { + private static PyType getGenericConstructorType(@NotNull PyFunction function, @NotNull Context context) { if (PyUtil.isInit(function)) { final PyClass cls = function.getContainingClass(); if (cls != null) { @@ -258,9 +259,9 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @NotNull - private static List collectGenericTypes(@NotNull PyClass cls, @NotNull TypeEvalContext context) { + private static List collectGenericTypes(@NotNull PyClass cls, @NotNull Context context) { boolean isGeneric = false; - for (PyClass ancestor : cls.getAncestorClasses(context)) { + for (PyClass ancestor : cls.getAncestorClasses(context.getTypeContext())) { if (GENERIC_CLASSES.contains(ancestor.getQualifiedName())) { isGeneric = true; break; @@ -273,7 +274,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { if (expr instanceof PySubscriptionExpression) { final PyExpression indexExpr = ((PySubscriptionExpression)expr).getIndexExpression(); if (indexExpr != null) { - for (PsiElement resolved : tryResolving(indexExpr, context)) { + for (PsiElement resolved : tryResolving(indexExpr, context.getTypeContext())) { final PyGenericType genericType = getGenericType(resolved, context); if (genericType != null) { results.add(genericType); @@ -288,49 +289,60 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getType(@NotNull PyExpression expression, @NotNull TypeEvalContext context) { + private static PyType getType(@NotNull PyExpression expression, @NotNull Context context) { final List members = Lists.newArrayList(); - for (PsiElement resolved : tryResolving(expression, context)) { + for (PsiElement resolved : tryResolving(expression, context.getTypeContext())) { members.add(getTypeForResolvedElement(resolved, context)); } return PyUnionType.union(members); } @Nullable - private static PyType getTypeForResolvedElement(@NotNull PsiElement resolved, @NotNull TypeEvalContext context) { - final PyType unionType = getUnionType(resolved, context); - if (unionType != null) { - return unionType; + private static PyType getTypeForResolvedElement(@NotNull PsiElement resolved, @NotNull Context context) { + if (context.getExpressionCache().contains(resolved)) { + // Recursive types are not yet supported + return null; } - final Ref optionalType = getOptionalType(resolved, context); - if (optionalType != null) { - return optionalType.get(); + + context.getExpressionCache().add(resolved); + try { + final PyType unionType = getUnionType(resolved, context); + if (unionType != null) { + return unionType; + } + final Ref optionalType = getOptionalType(resolved, context); + if (optionalType != null) { + return optionalType.get(); + } + final PyType callableType = getCallableType(resolved, context); + if (callableType != null) { + return callableType; + } + final PyType parameterizedType = getParameterizedType(resolved, context); + if (parameterizedType != null) { + return parameterizedType; + } + final PyType builtinCollection = getBuiltinCollection(resolved); + if (builtinCollection != null) { + return builtinCollection; + } + final PyType genericType = getGenericType(resolved, context); + if (genericType != null) { + return genericType; + } + final Ref classType = getClassType(resolved, context.getTypeContext()); + if (classType != null) { + return classType.get(); + } + final PyType stringBasedType = getStringBasedType(resolved, context); + if (stringBasedType != null) { + return stringBasedType; + } + return null; } - final PyType callableType = getCallableType(resolved, context); - if (callableType != null) { - return callableType; + finally { + context.getExpressionCache().remove(resolved); } - final PyType parameterizedType = getParameterizedType(resolved, context); - if (parameterizedType != null) { - return parameterizedType; - } - final PyType builtinCollection = getBuiltinCollection(resolved); - if (builtinCollection != null) { - return builtinCollection; - } - final PyType genericType = getGenericType(resolved, context); - if (genericType != null) { - return genericType; - } - final Ref classType = getClassType(resolved, context); - if (classType != null) { - return classType.get(); - } - final PyType stringBasedType = getStringBasedType(resolved, context); - if (stringBasedType != null) { - return stringBasedType; - } - return null; } @Nullable @@ -358,6 +370,12 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { @Nullable public static PyType getTypeFromTargetExpression(@NotNull PyTargetExpression expression, @NotNull TypeEvalContext context) { + return getTypeFromTargetExpression(expression, new Context(context)); + } + + @Nullable + private static PyType getTypeFromTargetExpression(@NotNull PyTargetExpression expression, + @NotNull Context context) { // XXX: Requires switching from stub to AST final PyExpression assignedValue = expression.findAssignedValue(); return assignedValue != null ? getTypeForResolvedElement(assignedValue, context) : null; @@ -385,11 +403,11 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static Ref getOptionalType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + private static Ref getOptionalType(@NotNull PsiElement element, @NotNull Context context) { if (element instanceof PySubscriptionExpression) { final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)element; final PyExpression operand = subscriptionExpr.getOperand(); - final Collection operandNames = resolveToQualifiedNames(operand, context); + final Collection operandNames = resolveToQualifiedNames(operand, context.getTypeContext()); if (operandNames.contains("typing.Optional")) { final PyExpression indexExpr = subscriptionExpr.getIndexExpression(); if (indexExpr != null) { @@ -405,7 +423,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getStringBasedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + private static PyType getStringBasedType(@NotNull PsiElement element, @NotNull Context context) { if (element instanceof PyStringLiteralExpression) { // XXX: Requires switching from stub to AST final String contents = ((PyStringLiteralExpression)element).getStringValue(); @@ -415,7 +433,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getStringBasedType(@NotNull String contents, @NotNull PsiElement anchor, @NotNull TypeEvalContext context) { + private static PyType getStringBasedType(@NotNull String contents, @NotNull PsiElement anchor, @NotNull Context context) { final Project project = anchor.getProject(); final PyExpressionCodeFragmentImpl codeFragment = new PyExpressionCodeFragmentImpl(project, "dummy.py", contents, false); codeFragment.setContext(anchor.getContainingFile()); @@ -436,11 +454,11 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getCallableType(@NotNull PsiElement resolved, @NotNull TypeEvalContext context) { + private static PyType getCallableType(@NotNull PsiElement resolved, @NotNull Context context) { if (resolved instanceof PySubscriptionExpression) { final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)resolved; final PyExpression operand = subscriptionExpr.getOperand(); - final Collection operandNames = resolveToQualifiedNames(operand, context); + final Collection operandNames = resolveToQualifiedNames(operand, context.getTypeContext()); if (operandNames.contains("typing.Callable")) { final PyExpression indexExpr = subscriptionExpr.getIndexExpression(); if (indexExpr instanceof PyTupleExpression) { @@ -466,11 +484,11 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getUnionType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + private static PyType getUnionType(@NotNull PsiElement element, @NotNull Context context) { if (element instanceof PySubscriptionExpression) { final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)element; final PyExpression operand = subscriptionExpr.getOperand(); - final Collection operandNames = resolveToQualifiedNames(operand, context); + final Collection operandNames = resolveToQualifiedNames(operand, context.getTypeContext()); if (operandNames.contains("typing.Union")) { return PyUnionType.union(getIndexTypes(subscriptionExpr, context)); } @@ -479,12 +497,12 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyGenericType getGenericType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + private static PyGenericType getGenericType(@NotNull PsiElement element, @NotNull Context context) { if (element instanceof PyCallExpression) { final PyCallExpression assignedCall = (PyCallExpression)element; final PyExpression callee = assignedCall.getCallee(); if (callee != null) { - final Collection calleeQNames = resolveToQualifiedNames(callee, context); + final Collection calleeQNames = resolveToQualifiedNames(callee, context.getTypeContext()); if (calleeQNames.contains("typing.TypeVar")) { final PyExpression[] arguments = assignedCall.getArguments(); if (arguments.length > 0) { @@ -503,8 +521,8 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getGenericTypeBound(@NotNull PyExpression[] typeVarArguments, @NotNull TypeEvalContext context) { - final List types = new ArrayList(); + private static PyType getGenericTypeBound(@NotNull PyExpression[] typeVarArguments, @NotNull Context context) { + final List types = new ArrayList<>(); for (int i = 1; i < typeVarArguments.length; i++) { types.add(getType(typeVarArguments[i], context)); } @@ -512,7 +530,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @NotNull - private static List getIndexTypes(@NotNull PySubscriptionExpression expression, @NotNull TypeEvalContext context) { + private static List getIndexTypes(@NotNull PySubscriptionExpression expression, @NotNull Context context) { final List types = new ArrayList(); final PyExpression indexExpr = expression.getIndexExpression(); if (indexExpr instanceof PyTupleExpression) { @@ -528,7 +546,7 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType getParameterizedType(@NotNull PsiElement element, @NotNull TypeEvalContext context) { + private static PyType getParameterizedType(@NotNull PsiElement element, @NotNull Context context) { if (element instanceof PySubscriptionExpression) { final PySubscriptionExpression subscriptionExpr = (PySubscriptionExpression)element; final PyExpression operand = subscriptionExpr.getOperand(); @@ -611,4 +629,23 @@ public class PyTypingTypeProvider extends PyTypeProviderBase { } return null; } + + private static class Context { + @NotNull private final TypeEvalContext myContext; + @NotNull private final Set myCache = new HashSet<>(); + + private Context(@NotNull TypeEvalContext context) { + myContext = context; + } + + @NotNull + public TypeEvalContext getTypeContext() { + return myContext; + } + + @NotNull + public Set getExpressionCache() { + return myCache; + } + } } diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index 4de9ed6b41da..feaaceea053a 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -35,6 +35,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; /** * @author yole @@ -69,7 +70,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType return classMembers; } if (myFields.contains(name)) { - return Collections.singletonList(new RatedResolveResult(1000, new PyElementImpl(myDeclaration.getNode()))); + return Collections.singletonList(new RatedResolveResult(RatedResolveResult.RATE_HIGH, new PyElementImpl(myDeclaration.getNode()))); } return null; } @@ -98,7 +99,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType @Override public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { if (myDefinitionLevel > 0) { - return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, myDefinitionLevel-1); + return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, myDefinitionLevel - 1); } return null; } @@ -113,6 +114,15 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType return "PyNamedTupleType: " + myName; } + @NotNull + @Override + public Set getMemberNames(boolean inherited, @NotNull TypeEvalContext context) { + final Set result = super.getMemberNames(inherited, context); + result.addAll(myFields); + + return result; + } + @Nullable public static PyType fromCall(@NotNull PyCallExpression call, @NotNull TypeEvalContext context, int level) { final String name = PyPsiUtils.strValue(call.getArgument(0, PyExpression.class)); diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index b7a3c49c3bf4..ec08ba2ab102 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -44,8 +44,10 @@ import static com.jetbrains.python.psi.PyUtil.as; public class PyStdlibTypeProvider extends PyTypeProviderBase { private static final Set OPEN_FUNCTIONS = ImmutableSet.of("__builtin__.open", "io.open", "os.fdopen", "pathlib.Path.open"); - private static final String BINARY_FILE_TYPE = "io.FileIO[bytes]"; - private static final String TEXT_FILE_TYPE = "io.TextIOWrapper[unicode]"; + + private static final String PY2K_FILE_TYPE = "file"; + private static final String PY3K_BINARY_FILE_TYPE = "io.FileIO[bytes]"; + private static final String PY3K_TEXT_FILE_TYPE = "io.TextIOWrapper[unicode]"; @Nullable public static PyStdlibTypeProvider getInstance() { @@ -275,19 +277,16 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { } } final LanguageLevel level = LanguageLevel.forElement(anchor); - // Binary mode - if (mode.contains("b")) { - return PyTypeParser.getTypeByName(anchor, BINARY_FILE_TYPE); - } - // Text mode - else { - if (level.isPy3K() || "io.open".equals(callQName)) { - return PyTypeParser.getTypeByName(anchor, TEXT_FILE_TYPE); - } - else { - return PyTypeParser.getTypeByName(anchor, BINARY_FILE_TYPE); + + if (level.isPy3K() || "io.open".equals(callQName)) { + if (mode.contains("b")) { + return PyTypeParser.getTypeByName(anchor, PY3K_BINARY_FILE_TYPE); + } else { + return PyTypeParser.getTypeByName(anchor, PY3K_TEXT_FILE_TYPE); } } + + return PyTypeParser.getTypeByName(anchor, PY2K_FILE_TYPE); } @Nullable diff --git a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java index ac367f1de2cb..456b42f65c54 100644 --- a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java +++ b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java @@ -249,7 +249,11 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { if (parts.length > 0) { PySignature signature = new PySignature(path, parts[0]); for (int i = 1; i < parts.length; i++) { - String[] var = parts[i].split(":"); + String part = parts[i]; + if (part.isEmpty()) { + continue; + } + String[] var = part.split(":"); if (var.length == 2) { if (RETURN_TYPE.equals(var[0])) { signature = signature.addReturnType(var[1]); @@ -260,7 +264,7 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { } else { throw new IllegalStateException( - "Should be : format for arg or " + RETURN_TYPE + ": for return type; '" + parts[i] + "' instead."); + "Should be : format for arg or " + RETURN_TYPE + ": for return type; '" + part + "' instead."); } } return signature; diff --git a/python/src/com/jetbrains/python/documentation/docstrings/PyDocstringGenerator.java b/python/src/com/jetbrains/python/documentation/docstrings/PyDocstringGenerator.java index 50fea52fba76..d2456729a9e7 100644 --- a/python/src/com/jetbrains/python/documentation/docstrings/PyDocstringGenerator.java +++ b/python/src/com/jetbrains/python/documentation/docstrings/PyDocstringGenerator.java @@ -209,10 +209,7 @@ public class PyDocstringGenerator { statementList.accept(visitor); if (!isConstructor((PyFunction)myDocStringOwner) && (visitor.myHasReturn || addReturn)) { // will add :return: placeholder in Sphinx/Epydoc docstrings - myAddedParams.add(new DocstringParam("", null, true)); - if (PyCodeInsightSettings.getInstance().INSERT_TYPE_DOCSTUB) { - withReturnValue(""); - } + withReturnValue(null); } } return this; @@ -274,7 +271,8 @@ public class PyDocstringGenerator { String type = paramTypes.get(paramCoordinates); if (type == null && PyCodeInsightSettings.getInstance().INSERT_TYPE_DOCSTUB) { if (signature != null) { - type = StringUtil.notNullize(param.isReturnValue() ? signature.getReturnTypeQualifiedName() : + type = StringUtil.notNullize(param.isReturnValue() ? + signature.getReturnTypeQualifiedName() : signature.getArgTypeQualifiedName(param.getName())); } else { diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 4438beb72e93..a4858898a3f2 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -46,8 +46,9 @@ public class PyTypeCheckerInspection extends PyInspection { @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) { - if (LOG.isDebugEnabled()) + if (LOG.isDebugEnabled()) { session.putUserData(TIME_KEY, System.nanoTime()); + } return new Visitor(holder, session); } @@ -88,18 +89,22 @@ public class PyTypeCheckerInspection extends PyInspection { private void checkCallSite(@Nullable PyCallSiteExpression callSite) { final List resultsSet = PyTypeChecker.analyzeCallSite(callSite, myTypeEvalContext); - final List>> problemsSet = new ArrayList>>(); + final List>> problemsSet = + new ArrayList>>(); for (PyTypeChecker.AnalyzeCallResults results : resultsSet) { problemsSet.add(checkMapping(results.getReceiver(), results.getArguments())); } if (!problemsSet.isEmpty()) { - Map> minProblems = Collections.min(problemsSet, new Comparator>>() { - @Override - public int compare(Map> o1, - Map> o2) { - return o1.size() - o2.size(); + Map> minProblems = Collections.min( + problemsSet, + new Comparator>>() { + @Override + public int compare(Map> o1, + Map> o2) { + return o1.size() - o2.size(); + } } - }); + ); for (Map.Entry> entry : minProblems.entrySet()) { registerProblem(entry.getKey(), entry.getValue().getFirst(), entry.getValue().getSecond()); } @@ -109,7 +114,8 @@ public class PyTypeCheckerInspection extends PyInspection { @NotNull private Map> checkMapping(@Nullable PyExpression receiver, @NotNull Map mapping) { - final Map> problems = new HashMap>(); + final Map> problems = + new HashMap>(); final Map substitutions = new LinkedHashMap(); boolean genericsCollected = false; for (Map.Entry entry : mapping.entrySet()) { @@ -130,7 +136,6 @@ public class PyTypeCheckerInspection extends PyInspection { final Pair problem = checkTypes(paramType, argType, myTypeEvalContext, substitutions); if (problem != null) { problems.put(arg, problem); - } } return problems; @@ -151,13 +156,13 @@ public class PyTypeCheckerInspection extends PyInspection { final PyType substitute = PyTypeChecker.substitute(expected, substitutions, context); if (substitute != null) { quotedExpectedName = String.format("'%s' (matched generic type '%s')", - PythonDocumentationProvider.getTypeName(substitute, context), - expectedName); + PythonDocumentationProvider.getTypeName(substitute, context), + expectedName); highlightType = ProblemHighlightType.WEAK_WARNING; } } final String actualName = PythonDocumentationProvider.getTypeName(actual, context); - String msg= String.format("Expected type %s, got '%s' instead", quotedExpectedName, actualName); + String msg = String.format("Expected type %s, got '%s' instead", quotedExpectedName, actualName); if (expected instanceof PyStructuralType) { final Set expectedAttributes = ((PyStructuralType)expected).getAttributeNames(); final Set actualAttributes = getAttributes(actual, context); @@ -190,8 +195,8 @@ public class PyTypeCheckerInspection extends PyInspection { if (type instanceof PyStructuralType) { return ((PyStructuralType)type).getAttributeNames(); } - else if (type instanceof PyClassType) { - return PyTypeChecker.getClassTypeAttributes((PyClassType)type, true, context); + else if (type instanceof PyClassLikeType) { + return ((PyClassLikeType)type).getMemberNames(true, context); } return null; } diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyMakePublicQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyMakePublicQuickFix.java index 60dba50130c8..b6c7507bc6f5 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyMakePublicQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyMakePublicQuickFix.java @@ -59,4 +59,9 @@ public class PyMakePublicQuickFix implements LocalQuickFix { } } } + + @Override + public boolean startInWriteAction() { + return false; + } } diff --git a/python/src/com/jetbrains/python/inspections/quickfix/RenameParameterQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/RenameParameterQuickFix.java index c30bf35a1f48..7869568c6203 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/RenameParameterQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/RenameParameterQuickFix.java @@ -52,4 +52,9 @@ public class RenameParameterQuickFix implements LocalQuickFix { public String getName() { return PyBundle.message("QFIX.rename.parameter.to.$0", myNewName); } + + @Override + public boolean startInWriteAction() { + return false; + } } diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java index 326a27f643c3..e5cecb856ed0 100644 --- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java @@ -500,13 +500,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (PyNames.COMPARISON_OPERATORS.contains(refName)) { return; } - if (expr.isQualified()) { - final PyClassTypeImpl object_type = (PyClassTypeImpl)PyBuiltinCache.getInstance(node).getObjectType(); - if ((object_type != null) && object_type.getPossibleInstanceMembers().contains(refName)) { - return; - } - } - else { + if (!expr.isQualified()) { if (PyUnreachableCodeInspection.hasAnyInterruptedControlFlowPaths(expr)) { return; } diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 6cf072dc6a4a..8c1e318f0bf3 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -1718,6 +1718,66 @@ public class PyUtil { return ScratchFileService.isInScratchRoot(PsiUtilCore.getVirtualFile(element)); } + @Nullable + public static PyType getReturnTypeOfMember(@NotNull PyType type, + @NotNull String memberName, + @Nullable PyExpression location, + @NotNull TypeEvalContext context) { + final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); + final List resolveResults = type.resolveMember(memberName, location, AccessDirection.READ, + resolveContext); + + if (resolveResults != null) { + final List types = new ArrayList<>(); + + for (RatedResolveResult resolveResult : resolveResults) { + final PyType returnType = getReturnType(resolveResult.getElement(), context); + + if (returnType != null) { + types.add(returnType); + } + } + + return PyUnionType.union(types); + } + + return null; + } + + @Nullable + private static PyType getReturnType(@Nullable PsiElement element, @NotNull TypeEvalContext context) { + if (element instanceof PyTypedElement) { + final PyType type = context.getType((PyTypedElement)element); + + return getReturnType(type, context); + } + + return null; + } + + @Nullable + private static PyType getReturnType(@Nullable PyType type, @NotNull TypeEvalContext context) { + if (type instanceof PyCallableType) { + return ((PyCallableType)type).getReturnType(context); + } + + if (type instanceof PyUnionType) { + final List types = new ArrayList<>(); + + for (PyType pyType : ((PyUnionType)type).getMembers()) { + final PyType returnType = getReturnType(pyType, context); + + if (returnType != null) { + types.add(returnType); + } + } + + return PyUnionType.union(types); + } + + return null; + } + /** * This helper class allows to collect various information about AST nodes composing {@link PyStringLiteralExpression}. */ diff --git a/python/src/com/jetbrains/python/psi/impl/PySliceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PySliceExpressionImpl.java index 5fde15256d40..20a27d6ca6bb 100644 --- a/python/src/com/jetbrains/python/psi/impl/PySliceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PySliceExpressionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -17,13 +17,13 @@ package com.jetbrains.python.psi.impl; import com.intellij.lang.ASTNode; import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.PyNames; import com.jetbrains.python.PythonDialectsTokenSetProvider; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PySliceExpression; import com.jetbrains.python.psi.PySliceItem; -import com.jetbrains.python.psi.types.PyTupleType; -import com.jetbrains.python.psi.types.PyType; -import com.jetbrains.python.psi.types.TypeEvalContext; +import com.jetbrains.python.psi.PyUtil; +import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,11 +39,21 @@ public class PySliceExpressionImpl extends PyElementImpl implements PySliceExpre @Override public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyType type = context.getType(getOperand()); + // TODO: Currently we don't evaluate the static range of the slice, so we have to return a generic tuple type without elements if (type instanceof PyTupleType) { return PyBuiltinCache.getInstance(this).getTupleType(); } - return type; + + if (type instanceof PyCollectionType) { + return type; + } + + if (type instanceof PyClassType) { + return PyUtil.getReturnTypeOfMember(type, PyNames.GETITEM, null, context); + } + + return null; } @NotNull diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index dcdd2767e6a6..3bda9b954c31 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -368,66 +368,23 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { @Nullable @Override public PyType getReturnType(@NotNull TypeEvalContext context) { - return getReturnType(context, null); + return getPossibleCallType(context, null); } @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) { - return getReturnType(context, callSite); + return getPossibleCallType(context, callSite); } @Nullable - private PyType getReturnType(@NotNull TypeEvalContext context, @Nullable PyCallSiteExpression callSite) { + private PyType getPossibleCallType(@NotNull TypeEvalContext context, @Nullable PyCallSiteExpression callSite) { if (!isDefinition()) { - final PyResolveContext resolveContext = PyResolveContext.noImplicits().withTypeEvalContext(context); - final List resolveResults = resolveMember(PyNames.CALL, callSite, AccessDirection.READ, resolveContext); - - if (resolveResults != null) { - final ArrayList result = new ArrayList(); - - for (RatedResolveResult resolveResult : resolveResults) { - result.addAll( - getPossibleReturnTypes(resolveResult.getElement(), context) - ); - } - - return PyUnionType.union(result); - } + return PyUtil.getReturnTypeOfMember(this, PyNames.CALL, callSite, context); } else { return new PyClassTypeImpl(getPyClass(), false); } - - return null; - } - - @NotNull - private static List getPossibleReturnTypes(@Nullable PsiElement element, @NotNull TypeEvalContext context) { - final ArrayList result = new ArrayList(); - - if (element instanceof PyTypedElement) { - final PyType elementType = context.getType((PyTypedElement)element); - - result.addAll(getPossibleReturnTypes(elementType, context)); - - if (elementType instanceof PyUnionType) { - for (PyType type : ((PyUnionType)elementType).getMembers()) { - result.addAll(getPossibleReturnTypes(type, context)); - } - } - } - - return result; - } - - @NotNull - private static List getPossibleReturnTypes(@Nullable PyType type, @NotNull TypeEvalContext context) { - if (type instanceof PyCallableType) { - return Collections.singletonList(((PyCallableType)type).getReturnType(context)); - } - - return Collections.emptyList(); } @Nullable @@ -566,11 +523,12 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { public void visitMembers(@NotNull final Processor processor, final boolean inherited, @NotNull final TypeEvalContext context) { - myClass.visitMethods(new MyProcessorWrapper(processor), false, context); myClass.visitClassAttributes(new MyProcessorWrapper(processor), false, context); - // TODO: accept instance attributes as well + for (PyTargetExpression expression : myClass.getInstanceAttributes()) { + processor.process(expression); + } if (!inherited) { return; @@ -584,6 +542,42 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } } + @NotNull + @Override + public Set getMemberNames(boolean inherited, @NotNull TypeEvalContext context) { + final Set result = new LinkedHashSet<>(); + + for (PyFunction function : myClass.getMethods()) { + result.add(function.getName()); + } + + for (PyTargetExpression expression : myClass.getClassAttributes()) { + result.add(expression.getName()); + } + + for (PyTargetExpression expression : myClass.getInstanceAttributes()) { + result.add(expression.getName()); + } + + for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { + for (PyCustomMember member : provider.getMembers(this, null, context)) { + result.add(member.getName()); + } + } + + if (inherited) { + for (PyClassLikeType type : getAncestorTypes(context)) { + if (type != null) { + final PyClassLikeType ancestorType = isDefinition() ? type : type.toInstance(); + + result.addAll(ancestorType.getMemberNames(false, context)); + } + } + } + + return result; + } + private void addOwnClassMembers(PsiElement expressionHook, Set namesAlready, boolean suppressParentheses, @@ -690,19 +684,6 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } } - @NotNull - public Set getPossibleInstanceMembers() { - Set ret = new HashSet(); - /* - if (myClass != null) { - PyClassType otype = PyBuiltinCache.getInstance(myClass.getProject()).getObjectType(); - ret.addAll(otype.getPossibleInstanceMembers()); - } - */ - // TODO: add our own ideas here, e.g. from methods other than constructor - return Collections.unmodifiableSet(ret); - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index ae860229395c..807ec108cee0 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -15,11 +15,10 @@ */ package com.jetbrains.python.psi.types; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.psi.*; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiNamedElement; import com.intellij.util.ArrayUtil; import com.jetbrains.python.PyNames; -import com.jetbrains.python.codeInsight.PyCustomMember; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.impl.PyCallExpressionHelper; @@ -46,8 +45,8 @@ public class PyTypeChecker { * For example int matches object, while str doesn't match int. * Work for builtin types, classes, tuples etc. * - * @param expected expected type - * @param actual type to be matched against expected + * @param expected expected type + * @param actual type to be matched against expected * @param context * @param substitutions * @return @@ -179,11 +178,11 @@ public class PyTypeChecker { if (overridesGetAttr(actualClassType.getPyClass(), context)) { return true; } - final Set actualAttributes = getClassTypeAttributes(actualClassType, true, context); + final Set actualAttributes = actualClassType.getMemberNames(true, context); return actualAttributes.containsAll(((PyStructuralType)expected).getAttributeNames()); } if (actual instanceof PyStructuralType && expected instanceof PyClassType) { - final Set expectedAttributes = getClassTypeAttributes((PyClassType)expected, true, context); + final Set expectedAttributes = ((PyClassType)expected).getMemberNames(true, context); return expectedAttributes.containsAll(((PyStructuralType)actual).getAttributeNames()); } if (actual instanceof PyCallableType && expected instanceof PyCallableType) { @@ -212,47 +211,6 @@ public class PyTypeChecker { return matchNumericTypes(expected, actual); } - @NotNull - public static Set getClassTypeAttributes(@NotNull PyClassType type, boolean inherited, @NotNull TypeEvalContext context) { - final Set attributes = getClassAttributes(type.getPyClass(), inherited, type.isDefinition(), context); - for (PyClassMembersProvider provider : Extensions.getExtensions(PyClassMembersProvider.EP_NAME)) { - final Collection members = provider.getMembers(type, null, context); - for (PyCustomMember member : members) { - attributes.add(member.getName()); - } - } - return attributes; - } - - @NotNull - private static Set getClassAttributes(@NotNull PyClass cls, - boolean inherited, - boolean isDefinition, - @NotNull TypeEvalContext context) { - final Set attributes = new HashSet(); - for (PyFunction function : cls.getMethods()) { - attributes.add(function.getName()); - } - for (PyTargetExpression instanceAttribute : cls.getInstanceAttributes()) { - attributes.add(instanceAttribute.getName()); - } - for (PyTargetExpression classAttribute : cls.getClassAttributes()) { - attributes.add(classAttribute.getName()); - } - if (inherited) { - for (PyClass ancestor : cls.getAncestorClasses(null)) { - final PyType ancestorType = context.getType(ancestor); - if (ancestorType instanceof PyClassLikeType) { - final PyClassLikeType classType = isDefinition ? (PyClassLikeType)ancestorType : ((PyClassLikeType)ancestorType).toInstance(); - if (classType instanceof PyClassType) { - attributes.addAll(getClassTypeAttributes((PyClassType)classType, false, context)); - } - } - } - } - return attributes; - } - private static boolean matchNumericTypes(PyType expected, PyType actual) { final String superName = expected.getName(); final String subName = actual.getName(); @@ -527,7 +485,7 @@ public class PyTypeChecker { return isUnionCallable((PyUnionType)type); } if (type instanceof PyCallableType) { - return ((PyCallableType) type).isCallable(); + return ((PyCallableType)type).isCallable(); } if (type instanceof PyStructuralType && ((PyStructuralType)type).isInferredFromUsages()) { return true; diff --git a/python/testData/inspections/PyTypeCheckerInspection/NamedTupleBaseClass.py b/python/testData/inspections/PyTypeCheckerInspection/NamedTupleBaseClass.py new file mode 100644 index 000000000000..84410a41c8ae --- /dev/null +++ b/python/testData/inspections/PyTypeCheckerInspection/NamedTupleBaseClass.py @@ -0,0 +1,16 @@ +from collections import namedtuple + + +class C(namedtuple('C', ['foo', 'bar'])): + pass + + +def f(x): + return x.foo, x.bar + +def g(): + x = C(foo=0, bar=1) + return f(x) + + +print(g()) \ No newline at end of file diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/bytesIORead.py b/python/testData/inspections/PyUnresolvedReferencesInspection/bytesIOMethods.py similarity index 100% rename from python/testData/inspections/PyUnresolvedReferencesInspection/bytesIORead.py rename to python/testData/inspections/PyUnresolvedReferencesInspection/bytesIOMethods.py diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/fileMethods.py b/python/testData/inspections/PyUnresolvedReferencesInspection/fileMethods.py new file mode 100644 index 000000000000..8f69c667fa99 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/fileMethods.py @@ -0,0 +1,7 @@ +f = open("file.txt") +f.writelines("a") # OK +f.writeliness("a") + +f = open("file.txt", "rb") +f.writelines("a") # OK +f.writeliness("a") \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/Py3TypeTest.java b/python/testSrc/com/jetbrains/python/Py3TypeTest.java index b5d612a99171..a70fead0608a 100644 --- a/python/testSrc/com/jetbrains/python/Py3TypeTest.java +++ b/python/testSrc/com/jetbrains/python/Py3TypeTest.java @@ -195,6 +195,21 @@ public class Py3TypeTest extends PyTestCase { }); } + public void testOpenDefault() { + doTest("TextIOWrapper[str]", + "expr = open('foo')\n"); + } + + public void testOpenText() { + doTest("TextIOWrapper[str]", + "expr = open('foo', 'r')\n"); + } + + public void testOpenBinary() { + doTest("FileIO[bytes]", + "expr = open('foo', 'rb')\n"); + } + private void doTest(final String expectedType, final String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); final PyExpression expr = myFixture.findElementByText("expr", PyExpression.class); diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index 93e2973b1933..faf364ff2f74 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -175,11 +175,28 @@ public class PyTypeTest extends PyTestCase { "l = [1, 2, 3]; expr = l[0]"); } - public void testSliceType() { + public void testListSliceType() { doTest("List[int]", "l = [1, 2, 3]; expr = l[0:1]"); } + public void testTupleSliceType() { + doTest("tuple", + "l = (1, 2, 3); expr = l[0:1]"); + } + + // PY-18560 + public void testCustomSliceType() { + doTest( + "int", + "class RectangleFactory(object):\n" + + " def __getitem__(self, item):\n" + + " return 1\n" + + "factory = RectangleFactory()\n" + + "expr = factory[:]" + ); + } + public void testExceptType() { doTest("ImportError", "try:\n" + @@ -694,17 +711,17 @@ public class PyTypeTest extends PyTestCase { } public void testOpenDefault() { - doTest("FileIO[str]", + doTest("file", "expr = open('foo')\n"); } public void testOpenText() { - doTest("FileIO[str]", + doTest("file", "expr = open('foo', 'r')\n"); } public void testOpenBinary() { - doTest("FileIO[str]", + doTest("file", "expr = open('foo', 'rb')\n"); } diff --git a/python/testSrc/com/jetbrains/python/PyTypingTest.java b/python/testSrc/com/jetbrains/python/PyTypingTest.java index 8659fd088d1a..889f675ab65c 100644 --- a/python/testSrc/com/jetbrains/python/PyTypingTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypingTest.java @@ -472,6 +472,38 @@ public class PyTypingTest extends PyTestCase { } + // PY-18386 + public void testRecursiveType() { + doTest("Union[int, Any]", + "from typing import Union\n" + + "\n" + + "Type = Union[int, 'Type']\n" + + "expr = 42 # type: Type"); + } + + // PY-18386 + public void testRecursiveType2() { + doTest("Dict[str, Union[Union[str, int, float], Any]]", + "from typing import Dict, Union\n" + + "\n" + + "JsonDict = Dict[str, Union[str, int, float, 'JsonDict']]\n" + + "\n" + + "def f(x: JsonDict):\n" + + " expr = x"); + } + + // PY-18386 + public void testRecursiveType3() { + doTest("Union[Union[str, int], Any]", + "from typing import Union\n" + + "\n" + + "Type1 = Union[str, 'Type2']\n" + + "Type2 = Union[int, Type1]\n" + + "\n" + + "expr = None # type: Type1"); + + } + private void doTestNoInjectedText(@NotNull String text) { myFixture.configureByText(PythonFileType.INSTANCE, text); final InjectedLanguageManager languageManager = InjectedLanguageManager.getInstance(myFixture.getProject()); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java index c8d2a222a9ab..f1a4c1b6a338 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyTypeCheckerInspectionTest.java @@ -151,6 +151,11 @@ public class PyTypeCheckerInspectionTest extends PyTestCase { doTest(); } + // PY-18096 + public void testNamedTupleBaseClass() { + doTest(); + } + // PY-6803 public void testPropertyAndFactoryFunction() { doTest(); diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 9f979def0fd4..a79347e74771 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -348,7 +348,12 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doMultiFileTest("a.py"); } - public void testBytesIORead() { + public void testBytesIOMethods() { + doTest(); + } + + // PY-18322 + public void testFileMethods() { doTest(); }