From e12ce52d741420a62ac38d5de3cdf91fb9133a79 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 24 Feb 2011 17:45:30 +0100 Subject: [PATCH 01/11] "Confusing 'else' branch" fixes and tests --- .../controlflow/ConfusingElseInspection.java | 32 +++++++++++--- .../confusing/ConfusingElseInspection.java | 26 ----------- .../confusing_else/ConfusingElse.java | 43 +++++++++++++++++++ .../controlflow/confusing_else/expected.xml | 17 ++++++++ .../ConfusingElseInspectionTest.java | 12 ++++++ 5 files changed, 99 insertions(+), 31 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingElseInspection.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/confusing_else/ConfusingElse.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/confusing_else/expected.xml create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/ConfusingElseInspectionTest.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConfusingElseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConfusingElseInspection.java index c29d1c9e5acd..297eb276753c 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConfusingElseInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConfusingElseInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,26 +31,31 @@ import org.jetbrains.annotations.Nullable; public class ConfusingElseInspection extends BaseInspection { + @Override @NotNull public String getID() { return "ConfusingElseBranch"; } + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message("confusing.else.display.name"); } + @Override @NotNull protected String buildErrorString(Object... infos) { return InspectionGadgetsBundle.message( "confusing.else.problem.descriptor"); } + @Override public BaseInspectionVisitor buildVisitor() { return new ConfusingElseVisitor(); } + @Override @Nullable protected InspectionGadgetsFix buildFix(Object... infos) { return new ConfusingElseFix(); @@ -64,6 +69,7 @@ public class ConfusingElseInspection extends BaseInspection { "confusing.else.unwrap.quickfix"); } + @Override public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiElement ifKeyword = descriptor.getPsiElement(); @@ -127,15 +133,13 @@ public class ConfusingElseInspection extends BaseInspection { if (ControlFlowUtils.statementMayCompleteNormally(thenBranch)) { return; } - final PsiStatement nextStatement = - PsiTreeUtil.getNextSiblingOfType(statement, - PsiStatement.class); + final PsiStatement nextStatement = getNextStatement(statement); if (nextStatement == null) { return; } if (!ControlFlowUtils.statementMayCompleteNormally(elseBranch)) { return; - //protecting against an edge case where both branches return + // protecting against an edge case where both branches return // and are followed by a case label } final PsiElement elseToken = statement.getElseElement(); @@ -144,5 +148,23 @@ public class ConfusingElseInspection extends BaseInspection { } registerError(elseToken); } + + private static PsiStatement getNextStatement(PsiIfStatement statement) { + while (true) { + final PsiElement parent = statement.getParent(); + if (parent instanceof PsiIfStatement) { + final PsiIfStatement parentIfStatement = + (PsiIfStatement) parent; + final PsiStatement elseBranch = + parentIfStatement.getElseBranch(); + if (elseBranch == statement) { + statement = parentIfStatement; + continue; + } + } + return PsiTreeUtil.getNextSiblingOfType(statement, + PsiStatement.class); + } + } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingElseInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingElseInspection.java deleted file mode 100644 index 5b76c7657e92..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/ConfusingElseInspection.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.siyeh.igtest.confusing; - -public class ConfusingElseInspection -{ - public static void main(String[] args) - { - if(foo()) - { - return; - } - else - { - System.out.println("ConfusingElseInspection.main"); - } - bar(); - } - - private static void bar() - { - } - - private static boolean foo() - { - return true; - } -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/confusing_else/ConfusingElse.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/confusing_else/ConfusingElse.java new file mode 100644 index 000000000000..7dcdc93a207a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/confusing_else/ConfusingElse.java @@ -0,0 +1,43 @@ +package com.siyeh.igtest.controlflow.confusing_else; + +public class ConfusingElse { + + public static void main(String[] args) { + if (foo()) { + return; + } else { + System.out.println("ConfusingElseInspection.main"); + } + bar(); + } + + private static void bar() { + } + + private static boolean foo() { + return true; + } + + void two(boolean b) { + if (foo()) { + + } else if (b) { + return; + } else { + + } + bar(); + } + + void three(boolean b) { + switch (3) { + case 2: + if (foo()) { + return; + } else { + return; + } + case 3: + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/confusing_else/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/confusing_else/expected.xml new file mode 100644 index 000000000000..109893caafe7 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/confusing_else/expected.xml @@ -0,0 +1,17 @@ + + + + ConfusingElse.java + 8 + Confusing 'else' branch + <code>else</code> branch may be unwrapped, as the if branch never completes #loc + + + + ConfusingElse.java + 26 + Confusing 'else' branch + <code>else</code> branch may be unwrapped, as the if branch never completes #loc + + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/ConfusingElseInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/ConfusingElseInspectionTest.java new file mode 100644 index 000000000000..1c6d9d24a57a --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/controlflow/ConfusingElseInspectionTest.java @@ -0,0 +1,12 @@ +package com.siyeh.ig.controlflow; + +import com.IGInspectionTestCase; + +public class ConfusingElseInspectionTest + extends IGInspectionTestCase { + + public void test() throws Exception { + doTest("com/siyeh/igtest/controlflow/confusing_else", + new ConfusingElseInspection()); + } +} \ No newline at end of file From ec28f13cbb789dae1933d0fc7a8e0e368b246462 Mon Sep 17 00:00:00 2001 From: andrey zaytsev Date: Thu, 24 Feb 2011 21:05:53 +0300 Subject: [PATCH 02/11] replace actions shouldn't be grouped by document. every single replace action is separate group. replace-all actions are grouped by document. --- platform/lang-impl/src/com/intellij/find/FindUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index 03d0f56d5cbe..f8c8a41aead7 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -766,7 +766,7 @@ public class FindUtil { } }); } - }, null, document); + }, null, null); return startOffset + converted.length(); } From 695ee8b40f02aec43c118b0708839c480f0aa9b4 Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Thu, 24 Feb 2011 21:37:07 +0300 Subject: [PATCH 03/11] Symbols serialization, file symbol tables cache to depend on inclusion context. TODO is to actually persist serialized tables. --- .../containers/MostlySingularMultiMap.java | 11 ++ .../intellij/util/io/CompactDataInput.java | 153 ++++++++++++++++++ .../intellij/util/io/CompactDataOutput.java | 121 ++++++++++++++ 3 files changed, 285 insertions(+) create mode 100644 platform/util/src/com/intellij/util/io/CompactDataInput.java create mode 100644 platform/util/src/com/intellij/util/io/CompactDataOutput.java diff --git a/platform/util/src/com/intellij/util/containers/MostlySingularMultiMap.java b/platform/util/src/com/intellij/util/containers/MostlySingularMultiMap.java index 2dc7aabb479f..41f04e3b4721 100644 --- a/platform/util/src/com/intellij/util/containers/MostlySingularMultiMap.java +++ b/platform/util/src/com/intellij/util/containers/MostlySingularMultiMap.java @@ -83,6 +83,17 @@ public class MostlySingularMultiMap { return true; } + public int size() { + return myMap.size(); + } + + public int valuesForKey(K key) { + Object current = myMap.get(key); + if (current == null) return 0; + if (current instanceof Object[]) return ((Object[])current).length; + return 1; + } + @NotNull public Iterable get(K name) { final Object value = myMap.get(name); diff --git a/platform/util/src/com/intellij/util/io/CompactDataInput.java b/platform/util/src/com/intellij/util/io/CompactDataInput.java new file mode 100644 index 000000000000..5fef6016bcd8 --- /dev/null +++ b/platform/util/src/com/intellij/util/io/CompactDataInput.java @@ -0,0 +1,153 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @author max + */ +package com.intellij.util.io; + +import java.io.DataInput; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +public class CompactDataInput implements DataInput { + private final InputStream in; + private final byte[] readBuffer = IOUtil.allocReadWriteUTFBuffer(); + + public CompactDataInput(InputStream in) { + this.in = in; + } + + @Override + public void readFully(byte[] b) throws IOException { + readFully(b, 0, b.length); + } + + @Override + public void readFully(byte[] b, int off, int len) throws IOException { + if (len < 0) + throw new IndexOutOfBoundsException(); + int n = 0; + while (n < len) { + int count = in.read(b, off + n, len - n); + if (count < 0) + throw new EOFException(); + n += count; + } + } + + @Override + public int skipBytes(int n) throws IOException { + int total = 0; + int cur = 0; + + while ((total 0)) { + total += cur; + } + + return total; + } + + @Override + public boolean readBoolean() throws IOException { + int ch = in.read(); + if (ch < 0) + throw new EOFException(); + return (ch != 0); + } + + @Override + public byte readByte() throws IOException { + int ch = in.read(); + if (ch < 0) + throw new EOFException(); + return (byte)(ch); + } + + @Override + public int readUnsignedByte() throws IOException { + int ch = in.read(); + if (ch < 0) + throw new EOFException(); + return ch; + } + + @Override + public short readShort() throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (short)((ch1 << 8) + (ch2 << 0)); + } + + @Override + public int readUnsignedShort() throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (ch1 << 8) + (ch2 << 0); + } + + @Override + public char readChar() throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (char)((ch1 << 8) + (ch2 << 0)); + } + + @Override + public int readInt() throws IOException { + return DataInputOutputUtil.readINT(this); + } + + @Override + public long readLong() throws IOException { // TODO: Make longs actually compact + readFully(readBuffer, 0, 8); + return (((long)readBuffer[0] << 56) + + ((long)(readBuffer[1] & 255) << 48) + + ((long)(readBuffer[2] & 255) << 40) + + ((long)(readBuffer[3] & 255) << 32) + + ((long)(readBuffer[4] & 255) << 24) + + ((readBuffer[5] & 255) << 16) + + ((readBuffer[6] & 255) << 8) + + ((readBuffer[7] & 255) << 0)); + } + + @Override + public float readFloat() throws IOException { + return Float.intBitsToFloat(readInt()); + } + + @Override + public double readDouble() throws IOException { + return Double.longBitsToDouble(readLong()); + } + + @Override + public String readLine() throws IOException { + throw new UnsupportedOperationException("readLine is not implemented!"); + } + + @Override + public String readUTF() throws IOException { + return IOUtil.readUTFFast(readBuffer, this); + } +} diff --git a/platform/util/src/com/intellij/util/io/CompactDataOutput.java b/platform/util/src/com/intellij/util/io/CompactDataOutput.java new file mode 100644 index 000000000000..41d1488472a2 --- /dev/null +++ b/platform/util/src/com/intellij/util/io/CompactDataOutput.java @@ -0,0 +1,121 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * @author max + */ +package com.intellij.util.io; + +import java.io.DataOutput; +import java.io.IOException; +import java.io.OutputStream; + +public class CompactDataOutput implements DataOutput { + private final OutputStream out; + private final byte[] writeBuffer = IOUtil.allocReadWriteUTFBuffer(); + + public CompactDataOutput(OutputStream out) { + this.out = out; + } + + @Override + public void write(int b) throws IOException { + out.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + out.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + out.write(b, off, len); + } + + @Override + public void writeBoolean(boolean v) throws IOException { + out.write(v ? 1 : 0); + } + + @Override + public void writeByte(int v) throws IOException { + out.write(v); + } + + @Override + public void writeShort(int v) throws IOException { + out.write((v >>> 8) & 0xFF); + out.write(v & 0xFF); + } + + @Override + public void writeChar(int v) throws IOException { + out.write((v >>> 8) & 0xFF); + out.write(v & 0xFF); + } + + @Override + public void writeInt(int val) throws IOException { + DataInputOutputUtil.writeINT(this, val); + } + + @Override + public void writeLong(long v) throws IOException { // TODO: Make longs actually compact + writeBuffer[0] = (byte)(v >>> 56); + writeBuffer[1] = (byte)(v >>> 48); + writeBuffer[2] = (byte)(v >>> 40); + writeBuffer[3] = (byte)(v >>> 32); + writeBuffer[4] = (byte)(v >>> 24); + writeBuffer[5] = (byte)(v >>> 16); + writeBuffer[6] = (byte)(v >>> 8); + writeBuffer[7] = (byte)(v >>> 0); + out.write(writeBuffer, 0, 8); + } + + @Override + public void writeFloat(float v) throws IOException { + writeInt(Float.floatToIntBits(v)); + } + + @Override + public void writeDouble(double v) throws IOException { + writeLong(Double.doubleToLongBits(v)); + } + + @Override + public void writeBytes(String s) throws IOException { + int len = s.length(); + for (int i = 0 ; i < len ; i++) { + out.write((byte)s.charAt(i)); + } + } + + @Override + public void writeChars(String s) throws IOException { + int len = s.length(); + for (int i = 0 ; i < len ; i++) { + int v = s.charAt(i); + out.write((v >>> 8) & 0xFF); + out.write((v >>> 0) & 0xFF); + } + } + + @Override + public void writeUTF(String s) throws IOException { + IOUtil.writeUTFFast(writeBuffer, this, s); + } +} From 9e0bef7dcd439529eb87725f9b26ed26cb0b2baa Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 24 Feb 2011 19:53:10 +0100 Subject: [PATCH 04/11] Project Coin try-with-resource support, take 4 --- .../intellij/codeInsight/ExceptionUtil.java | 6 +- .../analysis/HighlightControlFlowUtil.java | 4 +- .../daemon/impl/analysis/HighlightUtil.java | 6 +- .../impl/analysis/HighlightVisitorImpl.java | 9 +- .../quickfix/ReuseVariableDeclarationFix.java | 4 +- .../defUse/DefUseInspection.java | 2 +- .../lang/java/parser/DeclarationParser.java | 116 +++++++++--------- .../psi/controlFlow/ControlFlowAnalyzer.java | 21 +--- .../intellij/psi/controlFlow/DefUseUtil.java | 10 +- .../com/intellij/psi/impl/PsiImplUtil.java | 9 +- .../psi/impl/PsiJavaParserFacadeImpl.java | 6 +- .../psi/impl/source/PsiModifierListImpl.java | 5 +- .../psi/impl/source/tree/JavaElementType.java | 2 +- .../tree/java/PsiLocalVariableImpl.java | 27 ++-- .../source/tree/java/PsiResourceImpl.java | 74 ----------- .../source/tree/java/PsiResourceListImpl.java | 4 +- .../tree/java/PsiResourceVariableImpl.java | 70 +++++++++++ .../advHighlighting7/TryWithResources.java | 14 +-- .../TryWithResourcesWarn.java | 31 ++--- .../statements/TryIncomplete10.txt | 2 + .../statements/TryIncomplete11.txt | 2 +- .../statements/TryIncomplete12.txt | 2 - .../statements/TryIncomplete13.txt | 6 +- .../statements/TryIncomplete14.txt | 6 +- .../statements/TryIncomplete15.txt | 25 ++-- .../statements/TryIncomplete16.txt | 29 +++-- .../statements/TryIncomplete17.txt | 36 +++--- .../parser-partial/statements/TryNormal4.txt | 31 +++-- .../parser-partial/statements/TryNormal5.txt | 62 +++++----- .../parser-partial/statements/TryNormal6.txt | 23 +++- .../parser-partial/statements/TryNormal7.txt | 19 --- .../daemon/LightAdvHighlightingJdk7Test.java | 3 +- .../parser/partial/StatementParserTest.java | 5 +- .../com/intellij/psi/JavaElementVisitor.java | 4 +- .../com/intellij/psi/PsiJavaParserFacade.java | 2 +- .../src/com/intellij/psi/PsiResource.java | 39 ------ .../src/com/intellij/psi/PsiResourceList.java | 2 +- ...Variable.java => PsiResourceVariable.java} | 13 +- 38 files changed, 316 insertions(+), 415 deletions(-) delete mode 100644 java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceImpl.java create mode 100644 java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceVariableImpl.java delete mode 100644 java/java-tests/testData/psi/parser-partial/statements/TryNormal7.txt delete mode 100644 java/openapi/src/com/intellij/psi/PsiResource.java rename java/openapi/src/com/intellij/psi/{PsiScopedLocalVariable.java => PsiResourceVariable.java} (73%) diff --git a/java/java-impl/src/com/intellij/codeInsight/ExceptionUtil.java b/java/java-impl/src/com/intellij/codeInsight/ExceptionUtil.java index 64fe99852282..08753166bdd4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExceptionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExceptionUtil.java @@ -246,8 +246,8 @@ public class ExceptionUtil { unhandledExceptions = unhandled; } - if (element instanceof PsiResource) { - final List unhandled = getUnhandledCloserExceptions((PsiResource)element, topElement); + if (element instanceof PsiResourceVariable) { + final List unhandled = getUnhandledCloserExceptions((PsiResourceVariable)element, topElement); if (unhandledExceptions == null) { unhandledExceptions = unhandled; } @@ -331,7 +331,7 @@ public class ExceptionUtil { } @NotNull - public static List getUnhandledCloserExceptions(final PsiResource resource, final PsiElement topElement) { + public static List getUnhandledCloserExceptions(final PsiResourceVariable resource, final PsiElement topElement) { final PsiType resourceType = resource.getType(); if (resourceType instanceof PsiClassType) { final PsiClass resourceClass = ((PsiClassType)resourceType).resolve(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 83704c2c63be..1785837da3a2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -675,8 +675,8 @@ public class HighlightControlFlowUtil { @Nullable public static PsiClass getInnerClassVariableReferencedFrom(PsiVariable variable, PsiElement context) { PsiElement[] scope; - if (variable instanceof PsiScopedLocalVariable) { - scope = ((PsiScopedLocalVariable)variable).getDeclarationScope(); + if (variable instanceof PsiResourceVariable) { + scope = ((PsiResourceVariable)variable).getDeclarationScope(); } else if (variable instanceof PsiLocalVariable) { scope = new PsiElement[]{variable.getParent().getParent()}; // code block or for statement diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 70db6cf0ce8b..df75fdf060e8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -435,7 +435,7 @@ public class HighlightUtil { @Nullable static HighlightInfo checkVariableInitializerType(PsiVariable variable) { PsiExpression initializer = variable.getInitializer(); - // array initalizer checked in checkArrayInitializerApplicable + // array initializer checked in checkArrayInitializerApplicable if (initializer == null || initializer instanceof PsiArrayInitializerExpression) return null; PsiType lType = variable.getType(); PsiType rType = initializer.getType(); @@ -655,7 +655,7 @@ public class HighlightUtil { } @Nullable - public static HighlightInfo checkUnhandledCloserExceptions(final PsiResource resource) { + public static HighlightInfo checkUnhandledCloserExceptions(final PsiResourceVariable resource) { final List unhandled = ExceptionUtil.getUnhandledCloserExceptions(resource, null); if (unhandled.isEmpty()) return null; @@ -1148,7 +1148,7 @@ public class HighlightUtil { } @Nullable - public static HighlightInfo checkTryResourceIsAutoCloseable(@NotNull final PsiResource resource) { + public static HighlightInfo checkTryResourceIsAutoCloseable(@NotNull final PsiResourceVariable resource) { final PsiType type = resource.getType(); if (type == null) return null; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index decc5b2d7126..7ca8e460bdac 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -906,11 +906,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } @Override - public void visitResource(final PsiResource resource) { - myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resource)); - if (!myHolder.hasErrorResults()) { - myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resource)); - } + public void visitResourceVariable(final PsiResourceVariable resourceVariable) { + visitVariable(resourceVariable); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resourceVariable)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resourceVariable)); } @Override public void visitTypeElement(PsiTypeElement type) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java index 0e6cd0ae748e..2a681620886f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java @@ -57,7 +57,7 @@ public class ReuseVariableDeclarationFix implements IntentionAction { return myVariable != null && myVariable.isValid() && myVariable instanceof PsiLocalVariable && - !(myVariable.getParent() instanceof PsiResource && myVariable.getInitializer() == null) && + !(myVariable.getParent() instanceof PsiResourceVariable && myVariable.getInitializer() == null) && previousVariable != null && Comparing.equal(previousVariable.getType(), myVariable.getType()) && myIdentifier != null && @@ -82,7 +82,7 @@ public class ReuseVariableDeclarationFix implements IntentionAction { final PsiElementFactory factory = JavaPsiFacade.getInstance(myVariable.getProject()).getElementFactory(); final PsiElement replacement; final PsiElement parent = myVariable.getParent(); - if (parent instanceof PsiResource) { + if (parent instanceof PsiResourceVariable) { replacement = factory.createResourceFromText(myVariable.getName() + " = " + initializer.getText(), null); } else { diff --git a/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java b/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java index 34293268c478..106d6b6f4b3f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/defUse/DefUseInspection.java @@ -97,7 +97,7 @@ public class DefUseInspection extends BaseLocalInspectionTool { PsiElement context = info.getContext(); PsiVariable psiVariable = info.getVariable(); - if (context instanceof PsiDeclarationStatement || context instanceof PsiResource) { + if (context instanceof PsiDeclarationStatement || context instanceof PsiResourceVariable) { if (!info.isRead()) { if (!isOnTheFly) { holder.registerProblem(psiVariable.getNameIdentifier(), diff --git a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java index b162024dcd20..7ee229f840a5 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/DeclarationParser.java @@ -36,7 +36,7 @@ import static com.intellij.lang.java.parser.JavaParserUtil.exprType; public class DeclarationParser { public enum Context { - FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE, RESOURCE_LIST + FILE, CLASS, CODE_BLOCK, ANNOTATION_INTERFACE } private static final TokenSet AFTER_END_DECLARATION_SET = TokenSet.create(JavaElementType.FIELD, JavaElementType.METHOD); @@ -223,7 +223,7 @@ public class DeclarationParser { if (tokenType == null) return null; if (tokenType == JavaTokenType.LBRACE) { - if (context == Context.FILE || context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) return null; + if (context == Context.FILE || context == Context.CODE_BLOCK) return null; } else if (tokenType == JavaTokenType.IDENTIFIER || ElementType.PRIMITIVE_TYPE_BIT_SET.contains(tokenType)) { if (context == Context.FILE) return null; @@ -235,7 +235,7 @@ public class DeclarationParser { else if (!ElementType.MODIFIER_BIT_SET.contains(tokenType) && !ElementType.CLASS_KEYWORD_BIT_SET.contains(tokenType) && tokenType != JavaTokenType.AT && - (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST || tokenType != JavaTokenType.LT)) { + (context == Context.CODE_BLOCK || tokenType != JavaTokenType.LT)) { return null; } @@ -279,7 +279,7 @@ public class DeclarationParser { final PsiBuilder.Marker idPos = builder.mark(); type = parseTypeNotNull(builder); if (builder.getTokenType() == JavaTokenType.LPARENTH) { // constructor - if (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) { + if (context == Context.CODE_BLOCK) { declaration.rollbackTo(); return null; } @@ -302,10 +302,6 @@ public class DeclarationParser { declaration.drop(); return modList; } - else if (context == Context.RESOURCE_LIST) { - declaration.rollbackTo(); - return null; - } final PsiBuilder.Marker codeBlock = StatementParser.parseCodeBlock(builder); assert codeBlock != null : builder.getOriginalText(); @@ -331,7 +327,7 @@ public class DeclarationParser { } if (!expect(builder, JavaTokenType.IDENTIFIER)) { - if ((context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) && modListInfo.second) { + if ((context == Context.CODE_BLOCK) && modListInfo.second) { declaration.rollbackTo(); return null; } @@ -473,11 +469,11 @@ public class DeclarationParser { PsiBuilder.Marker invalidElements = null; String errorMessage = null; boolean delimiterExpected = false; - int elementCount = 0; + boolean noElements = true; while (true) { final IElementType tokenType = builder.getTokenType(); if (tokenType == null || tokenType == JavaTokenType.RPARENTH || tokenType == JavaTokenType.LBRACE) { - boolean noLastElement = !delimiterExpected && elementCount > 0; + final boolean noLastElement = !delimiterExpected && (!noElements && !resources || noElements && resources); if (noLastElement) { error(builder, JavaErrorMessages.message("expected.identifier.or.type")); } @@ -486,13 +482,10 @@ public class DeclarationParser { invalidElements.error(errorMessage); invalidElements = null; } - else if (resources && elementCount == 0) { - error(builder, JavaErrorMessages.message("expected.resource")); - } builder.advanceLexer(); } else { - if (!noLastElement) { + if (!noLastElement || resources) { if (invalidElements != null) { invalidElements.error(errorMessage); } @@ -522,7 +515,7 @@ public class DeclarationParser { invalidElements.errorBefore(errorMessage, listElement); invalidElements = null; } - elementCount++; + noElements= false; continue; } } @@ -531,6 +524,9 @@ public class DeclarationParser { if (builder.getTokenType() == delimiter) { error(builder, noElementMsg); builder.advanceLexer(); + if (noElements && resources) { + noElements = false; + } continue; } else { @@ -556,6 +552,19 @@ public class DeclarationParser { @Nullable public static PsiBuilder.Marker parseParameter(final PsiBuilder builder, final boolean ellipsis, final boolean disjunctiveType) { + return parseListElement(builder, ellipsis, disjunctiveType, false); + } + + @Nullable + public static PsiBuilder.Marker parseResource(final PsiBuilder builder) { + return parseListElement(builder, false, false, true); + } + + @Nullable + private static PsiBuilder.Marker parseListElement(final PsiBuilder builder, + final boolean ellipsis, + final boolean disjunctiveType, + final boolean resource) { final PsiBuilder.Marker param = builder.mark(); final Pair modListInfo = parseModifierList(builder); @@ -577,34 +586,26 @@ public class DeclarationParser { } if (expect(builder, JavaTokenType.IDENTIFIER)) { - eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen")); - done(param, JavaElementType.PARAMETER); - return param; + if (!resource) { + eatBrackets(builder, typeInfo != null && typeInfo.isVarArg, JavaErrorMessages.message("expected.rparen")); + done(param, JavaElementType.PARAMETER); + return param; + } } else { error(builder, JavaErrorMessages.message("expected.identifier")); param.drop(); return modListInfo.first; } - } - @Nullable - public static PsiBuilder.Marker parseResource(final PsiBuilder builder) { - PsiBuilder.Marker element = parse(builder, Context.RESOURCE_LIST); - if (exprType(element) == JavaElementType.MODIFIER_LIST) { - return element; - } - else if (element == null) { - element = ExpressionParser.parse(builder); + if (expectOrError(builder, JavaTokenType.EQ, JavaErrorMessages.message("expected.eq"))) { + if (ExpressionParser.parse(builder) == null) { + error(builder, JavaErrorMessages.message("expected.expression")); + } } - if (element != null) { - final PsiBuilder.Marker resource = element.precede(); - done(resource, JavaElementType.RESOURCE); - return resource; - } - - return null; + done(param, JavaElementType.RESOURCE_VARIABLE); + return param; } @Nullable @@ -614,7 +615,7 @@ public class DeclarationParser { if (context == Context.CLASS || context == Context.ANNOTATION_INTERFACE) { varType = JavaElementType.FIELD; } - else if (context == Context.CODE_BLOCK || context == Context.RESOURCE_LIST) { + else if (context == Context.CODE_BLOCK) { varType = JavaElementType.LOCAL_VARIABLE; } else { @@ -645,11 +646,6 @@ public class DeclarationParser { unclosed = true; break; } - if (context == Context.RESOURCE_LIST) break; - } - else if (context == Context.RESOURCE_LIST) { - error(builder, JavaErrorMessages.message("expected.eq")); - break; } if (builder.getTokenType() != JavaTokenType.COMMA) break; @@ -668,28 +664,26 @@ public class DeclarationParser { builder.advanceLexer(); } - if (context != Context.RESOURCE_LIST) { - if (builder.getTokenType() == JavaTokenType.SEMICOLON && eatSemicolon) { - builder.advanceLexer(); + if (builder.getTokenType() == JavaTokenType.SEMICOLON && eatSemicolon) { + builder.advanceLexer(); + } + else { + // special treatment (see DeclarationParserTest.testMultiLineUnclosed()) + if (!builder.eof() && shouldRollback) { + final CharSequence text = builder.getOriginalText(); + final int spaceEnd = builder.getCurrentOffset(); + final int spaceStart = CharArrayUtil.shiftBackward(text, spaceEnd-1, WHITESPACES); + final int lineStart = CharArrayUtil.shiftBackwardUntil(text, spaceEnd, LINE_ENDS); + + if (declarationStart < lineStart && lineStart < spaceStart) { + final int newBufferEnd = CharArrayUtil.shiftForward(text, lineStart, WHITESPACES); + declaration.rollbackTo(); + return parse(stoppingBuilder(builder, newBufferEnd), context); + } } - else { - // special treatment (see DeclarationParserTest.testMultiLineUnclosed()) - if (!builder.eof() && shouldRollback) { - final CharSequence text = builder.getOriginalText(); - final int spaceEnd = builder.getCurrentOffset(); - final int spaceStart = CharArrayUtil.shiftBackward(text, spaceEnd-1, WHITESPACES); - final int lineStart = CharArrayUtil.shiftBackwardUntil(text, spaceEnd, LINE_ENDS); - if (declarationStart < lineStart && lineStart < spaceStart) { - final int newBufferEnd = CharArrayUtil.shiftForward(text, lineStart, WHITESPACES); - declaration.rollbackTo(); - return parse(stoppingBuilder(builder, newBufferEnd), context); - } - } - - if (!unclosed) { - error(builder, JavaErrorMessages.message("expected.semicolon")); - } + if (!unclosed) { + error(builder, JavaErrorMessages.message("expected.semicolon")); } } diff --git a/java/java-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java b/java/java-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java index a7e726fae882..553515046fdf 100644 --- a/java/java-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java +++ b/java/java-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java @@ -1166,30 +1166,15 @@ class ControlFlowAnalyzer extends JavaJspElementVisitor { public void visitResourceList(final PsiResourceList resourceList) { startElement(resourceList); - final List resources = resourceList.getResources(); - for (PsiResource resource : resources) { + final List resources = resourceList.getResourceVariables(); + for (PsiResourceVariable resource : resources) { ProgressManager.checkCanceled(); - resource.accept(this); + processVariable(resource); } finishElement(resourceList); } - @Override - public void visitResource(final PsiResource resource) { - startElement(resource); - - final PsiElement resourceElement = resource.getResourceElement(); - if (resourceElement instanceof PsiLocalVariable) { - processVariable((PsiLocalVariable)resourceElement); - } - else if (resourceElement instanceof PsiExpression) { - resourceElement.accept(this); - } - - finishElement(resource); - } - @Override public void visitWhileStatement(PsiWhileStatement statement) { startElement(statement); diff --git a/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java b/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java index daba17413a5d..742863afe51a 100644 --- a/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java +++ b/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java @@ -230,11 +230,10 @@ public class DefUseUtil { if (!defsArmed[i]) { PsiElement context = PsiTreeUtil.getNonStrictParentOfType(flow.getElement(i), PsiStatement.class, PsiAssignmentExpression.class, - PsiPostfixExpression.class, PsiPrefixExpression.class, - PsiResource.class); + PsiPostfixExpression.class, PsiPrefixExpression.class); PsiVariable psiVariable = writeInstruction.variable; if (context != null && !(context instanceof PsiTryStatement)) { - if (isDeclaration(context) && psiVariable.getInitializer() == null) { + if (context instanceof PsiDeclarationStatement && psiVariable.getInitializer() == null) { if (!assignedVariables.contains(psiVariable)) { unusedDefs.add(new Info(psiVariable, context, false)); } @@ -250,11 +249,6 @@ public class DefUseUtil { return unusedDefs; } - private static boolean isDeclaration(final PsiElement context) { - return context instanceof PsiDeclarationStatement || - context instanceof PsiResource && ((PsiResource)context).getResourceElement() instanceof PsiLocalVariable; - } - @NotNull public static PsiElement[] getDefs(PsiCodeBlock body, final PsiVariable def, PsiElement ref) { try { diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-impl/src/com/intellij/psi/impl/PsiImplUtil.java index 44bbf950c6d1..85eea92a8563 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -198,12 +198,9 @@ public class PsiImplUtil { @NotNull final PsiScopeProcessor processor, @NotNull final ResolveState state, final PsiElement lastParent) { - final List resources = resourceList.getResources(); - for (PsiResource resource : resources) { - final PsiElement resourceElement = resource.getResourceElement(); - if (resourceElement instanceof PsiLocalVariable && - !resourceElement.equals(lastParent) && - !processor.execute(resourceElement, state)) return false; + final List resources = resourceList.getResourceVariables(); + for (PsiResourceVariable resource : resources) { + if (!resource.equals(lastParent) && !processor.execute(resource, state)) return false; } return true; diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java index 49ec4a074d84..e8911819f860 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiJavaParserFacadeImpl.java @@ -259,13 +259,13 @@ public class PsiJavaParserFacadeImpl extends PsiParserFacadeImpl implements PsiJ @NotNull @Override - public PsiResource createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { + public PsiResourceVariable createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException { final DummyHolder holder = DummyHolderFactory.createHolder(myManager, new JavaDummyElement(text, RESOURCE, false), context); final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(holder.getTreeElement().getFirstChildNode()); - if (!(element instanceof PsiResource)) { + if (!(element instanceof PsiResourceVariable)) { throw new IncorrectOperationException("Incorrect resource \"" + text + "\"."); } - return (PsiResource)element; + return (PsiResourceVariable)element; } @NotNull diff --git a/java/java-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java index e2329c6d3578..2152c847a2e9 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java @@ -177,9 +177,8 @@ public class PsiModifierListImpl extends JavaStubPsiElement else if (parent instanceof PsiParameter) { if (type == JavaTokenType.FINAL_KEYWORD && ((PsiParameter)parent).getType() instanceof PsiDisjunctionType) return true; } - else if (parent instanceof PsiLocalVariable) { - PsiElement grandParent = parent.getParent(); - if (type == JavaTokenType.FINAL_KEYWORD && grandParent instanceof PsiResource) return true; + else if (parent instanceof PsiResourceVariable) { + if (type == JavaTokenType.FINAL_KEYWORD) return true; } if (type == null) { // package local diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java index 593bb11d77c3..3a6026e33880 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java @@ -128,7 +128,7 @@ public interface JavaElementType { IElementType SYNCHRONIZED_STATEMENT = new JavaCompositeElementType("SYNCHRONIZED_STATEMENT", PsiSynchronizedStatementImpl.class); IElementType TRY_STATEMENT = new JavaCompositeElementType("TRY_STATEMENT", PsiTryStatementImpl.class); IElementType RESOURCE_LIST = new JavaCompositeElementType("RESOURCE_LIST", PsiResourceListImpl.class); - IElementType RESOURCE = new JavaCompositeElementType("RESOURCE", PsiResourceImpl.class); + IElementType RESOURCE_VARIABLE = new JavaCompositeElementType("RESOURCE_VARIABLE", PsiResourceVariableImpl.class); IElementType CATCH_SECTION = new JavaCompositeElementType("CATCH_SECTION", PsiCatchSectionImpl.class); IElementType LABELED_STATEMENT = new JavaCompositeElementType("LABELED_STATEMENT", PsiLabeledStatementImpl.class); IElementType ASSERT_STATEMENT = new JavaCompositeElementType("ASSERT_STATEMENT", PsiAssertStatementImpl.class); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiLocalVariableImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiLocalVariableImpl.java index ad809cdf9ad3..7ac00396e348 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiLocalVariableImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiLocalVariableImpl.java @@ -49,13 +49,17 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.util.Set; -public class PsiLocalVariableImpl extends CompositePsiElement implements PsiScopedLocalVariable, PsiVariableEx, Constants { +public class PsiLocalVariableImpl extends CompositePsiElement implements PsiLocalVariable, PsiVariableEx, Constants { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiLocalVariableImpl"); private volatile String myCachedName = null; public PsiLocalVariableImpl() { - super(LOCAL_VARIABLE); + this(LOCAL_VARIABLE); + } + + protected PsiLocalVariableImpl(final IElementType type) { + super(type); } public void clearCaches() { @@ -279,21 +283,6 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiScop return "PsiLocalVariable:" + getName(); } - @NotNull - public PsiElement[] getDeclarationScope() { - final PsiElement parentElement = getParent(); - if (parentElement instanceof PsiDeclarationStatement) { - return new PsiElement[]{parentElement.getParent()}; - } - else if (parentElement instanceof PsiResource) { - final PsiResourceList resourceList = (PsiResourceList)parentElement.getParent(); - final PsiTryStatement tryStatement = (PsiTryStatement)resourceList.getParent(); - final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); - return tryBlock != null ? new PsiElement[]{resourceList, tryBlock} : new PsiElement[]{resourceList}; - } - return new PsiElement[]{parentElement.getParent()}; - } - @NotNull public SearchScope getUseScope() { if (JspPsiUtil.isInJspFile(this)) { @@ -321,8 +310,8 @@ public class PsiLocalVariableImpl extends CompositePsiElement implements PsiScop } final PsiElement parentElement = getParent(); - if (parentElement instanceof PsiDeclarationStatement || parentElement instanceof PsiResource) { - return new LocalSearchScope(getDeclarationScope()); + if (parentElement instanceof PsiDeclarationStatement) { + return new LocalSearchScope(parentElement.getParent()); } else { return getManager().getFileManager().getUseScope(this); diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceImpl.java deleted file mode 100644 index 6a09eefdfece..000000000000 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceImpl.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi.impl.source.tree.java; - -import com.intellij.openapi.diagnostic.LogUtil; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.tree.CompositePsiElement; -import com.intellij.psi.impl.source.tree.JavaElementType; -import org.jetbrains.annotations.NotNull; - -public class PsiResourceImpl extends CompositePsiElement implements PsiResource { - private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiResourceImpl"); - - public PsiResourceImpl() { - super(JavaElementType.RESOURCE); - } - - @NotNull - @Override - public PsiElement getResourceElement() { - final PsiElement element = getFirstChild(); - assert element != null : this; - return element; - } - - @Override - public PsiType getType() { - final PsiElement element = getResourceElement(); - if (element instanceof PsiLocalVariable) { - return ((PsiLocalVariable)element).getType(); - } - else if (element instanceof PsiExpression) { - return ((PsiExpression)element).getType(); - } - LOG.error("Unexpected resource type: " + LogUtil.objectAndClass(element)); - return null; - } - - @Override - public void accept(@NotNull final PsiElementVisitor visitor) { - if (visitor instanceof JavaElementVisitor) { - ((JavaElementVisitor)visitor).visitResource(this); - } - else { - visitor.visitElement(this); - } - } - - public String getName() { - final PsiElement element = getFirstChild(); - if (element instanceof PsiLocalVariable) return ((PsiLocalVariable)element).getName(); - if (element instanceof PsiAssignmentExpression) return ((PsiAssignmentExpression)element).getLExpression().toString(); - return ""; - } - - @Override - public String toString() { - return "PsiResource:" + getName(); - } -} diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceListImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceListImpl.java index 0ecec5626043..a6b67409cab1 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceListImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceListImpl.java @@ -32,8 +32,8 @@ public class PsiResourceListImpl extends CompositePsiElement implements PsiResou @NotNull @Override - public List getResources() { - return PsiTreeUtil.getChildrenOfTypeAsList(this, PsiResource.class); + public List getResourceVariables() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, PsiResourceVariable.class); } @Override diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceVariableImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceVariableImpl.java new file mode 100644 index 000000000000..4df67b7ced2a --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/java/PsiResourceVariableImpl.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.impl.source.tree.java; + +import com.intellij.psi.*; +import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.SearchScope; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; + +public class PsiResourceVariableImpl extends PsiLocalVariableImpl implements PsiResourceVariable { + public PsiResourceVariableImpl() { + super(JavaElementType.RESOURCE_VARIABLE); + } + + @NotNull + @Override + public PsiElement[] getDeclarationScope() { + final PsiResourceList resourceList = (PsiResourceList)getParent(); + final PsiTryStatement tryStatement = (PsiTryStatement)resourceList.getParent(); + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + return tryBlock != null ? new PsiElement[]{resourceList, tryBlock} : new PsiElement[]{resourceList}; + } + + @NotNull + @Override + public PsiTypeElement getTypeElement() { + return PsiTreeUtil.getRequiredChildOfType(this, PsiTypeElement.class); + } + + @Override + public PsiModifierList getModifierList() { + return PsiTreeUtil.getChildOfType(this, PsiModifierList.class); + } + + @Override + public void accept(@NotNull final PsiElementVisitor visitor) { + if (visitor instanceof JavaElementVisitor) { + ((JavaElementVisitor)visitor).visitResourceVariable(this); + } + else { + visitor.visitElement(this); + } + } + + @NotNull + @Override + public SearchScope getUseScope() { + return new LocalSearchScope(getDeclarationScope()); + } + + @Override + public String toString() { + return "PsiResourceVariable:" + getName(); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResources.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResources.java index fa8f950ef4b1..63a5b7b9e619 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResources.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResources.java @@ -14,24 +14,22 @@ class C { try (MyResource r = new MyResource()) { r.doSomething(); } catch (E1 | E2 | E3 ignore) { } - try (new MyResource()) { } + try (MyResource r = new MyResource()) { } catch (E1 | E3 ignore) { } - MyResource r; - - try (r = new MyResource()) { } + try (MyResource r = new MyResource()) { } catch (E1 e) { } - try (r = new MyResource()) { } + try (MyResource r = new MyResource()) { } catch (E3 e) { } - try (r = new MyResource()) { } + try (MyResource r = new MyResource()) { } } void m2() throws Exception { try (Object r = new MyResource()) { } - try ("resource") { } + try (AutoCloseable r = "resource") { } } void m3(int p) throws Exception { @@ -56,7 +54,7 @@ class C { MyResource r = null; try (MyResource r = new MyResource()) { } - try (r = new MyResource()) { } + try (MyResource rr = r) { } try (MyResource p = new MyResource()) { } new Runnable() { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java index 68b4fb4b4925..2cf0fe3f0c2d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/TryWithResourcesWarn.java @@ -6,35 +6,28 @@ class C { } void m1() throws Exception { - MyResource r1; - try (r1 = new MyResource()) { + try (MyResource r1 = new MyResource()) { System.out.println(r1); } - try (MyResource r2 = new MyResource()) { - System.out.println(r2); - } - - MyResource r3 = new MyResource(); - try (MyResource r = r3) { + MyResource r2 = new MyResource(); + try (MyResource r = r2) { System.out.println(r); + System.out.println(r2); } } void m2() throws Exception { - MyResource r1 = null; - try (r1 = new MyResource()) { - System.out.println(r1); - } + // todo: test in IG + //MyResource < warning descr="Local variable 'r1' is redundant">r1 = null; + //try (MyResource r = r1) { + // System.out.println(r); + //} - MyResource r2 = null; - System.out.println(r2); - try (r2 = new MyResource()) { } + try (MyResource r2 = new MyResource()) { } - try (MyResource r3 = new MyResource()) { } - - MyResource r4; - try (MyResource r = r4) { + MyResource r3; + try (MyResource r = r3) { System.out.println(r); } } diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete10.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete10.txt index 2e113f719226..07461ff12a2d 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete10.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete10.txt @@ -3,6 +3,8 @@ PsiJavaFile:TryIncomplete10.java PsiKeyword:try('try') PsiResourceList:( PsiJavaToken:LPARENTH('(') + PsiErrorElement:Identifier or type expected + PsiErrorElement:')' expected PsiCodeBlock diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete11.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete11.txt index 11b2811b4174..fda6eb428b58 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete11.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete11.txt @@ -3,7 +3,7 @@ PsiJavaFile:TryIncomplete11.java PsiKeyword:try('try') PsiResourceList:() PsiJavaToken:LPARENTH('(') - PsiErrorElement:Resource definition expected + PsiErrorElement:Identifier or type expected PsiJavaToken:RPARENTH(')') PsiCodeBlock diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete12.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete12.txt index 78a125c530b4..f37c59d95818 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete12.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete12.txt @@ -6,8 +6,6 @@ PsiJavaFile:TryIncomplete12.java PsiErrorElement:Resource definition expected PsiJavaToken:SEMICOLON(';') - PsiErrorElement:Resource definition expected - PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete13.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete13.txt index 598f1ac3e5c0..b4301f60f0b6 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete13.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete13.txt @@ -5,9 +5,13 @@ PsiJavaFile:TryIncomplete13.java PsiJavaToken:LPARENTH('(') PsiModifierList:final PsiKeyword:final('final') - PsiErrorElement:Identifier or type expected + PsiErrorElement:Type expected PsiWhiteSpace(' ') + PsiTypeElement: + + PsiErrorElement:Identifier expected + PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete14.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete14.txt index 88a8aca925b2..97482c52ec46 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete14.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete14.txt @@ -3,8 +3,12 @@ PsiJavaFile:TryIncomplete14.java PsiKeyword:try('try') PsiResourceList:(int) PsiJavaToken:LPARENTH('(') - PsiErrorElement:Resource definition expected + PsiModifierList: + + PsiTypeElement:int PsiKeyword:int('int') + PsiErrorElement:Identifier expected + PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete15.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete15.txt index 5748458436f0..2da2c5a6c22a 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete15.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete15.txt @@ -3,19 +3,18 @@ PsiJavaFile:TryIncomplete15.java PsiKeyword:try('try') PsiResourceList:(R r) PsiJavaToken:LPARENTH('(') - PsiResource:r - PsiLocalVariable:r - PsiModifierList: - - PsiTypeElement:R - PsiJavaCodeReferenceElement:R - PsiIdentifier:R('R') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r('r') - PsiErrorElement:'=' expected - + PsiResourceVariable:r + PsiModifierList: + + PsiTypeElement:R + PsiJavaCodeReferenceElement:R + PsiIdentifier:R('R') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiErrorElement:'=' expected + PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete16.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete16.txt index e04ca47331f8..837e354734f4 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete16.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete16.txt @@ -3,21 +3,20 @@ PsiJavaFile:TryIncomplete16.java PsiKeyword:try('try') PsiResourceList:(R r =) PsiJavaToken:LPARENTH('(') - PsiResource:r - PsiLocalVariable:r - PsiModifierList: - - PsiTypeElement:R - PsiJavaCodeReferenceElement:R - PsiIdentifier:R('R') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r('r') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiErrorElement:Expression expected - + PsiResourceVariable:r + PsiModifierList: + + PsiTypeElement:R + PsiJavaCodeReferenceElement:R + PsiIdentifier:R('R') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiErrorElement:Expression expected + PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete17.txt b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete17.txt index e4f111fb50c8..cf19d8c861dc 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete17.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryIncomplete17.txt @@ -1,27 +1,27 @@ PsiJavaFile:TryIncomplete17.java PsiTryStatement PsiKeyword:try('try') - PsiResourceList:(R r = 0;) + PsiResourceList:(R r = 0;;) PsiJavaToken:LPARENTH('(') - PsiResource:r - PsiLocalVariable:r - PsiModifierList: - - PsiTypeElement:R - PsiJavaCodeReferenceElement:R - PsiIdentifier:R('R') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r('r') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiWhiteSpace(' ') - PsiLiteralExpression:0 - PsiJavaToken:INTEGER_LITERAL('0') + PsiResourceVariable:r + PsiModifierList: + + PsiTypeElement:R + PsiJavaCodeReferenceElement:R + PsiIdentifier:R('R') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') PsiJavaToken:SEMICOLON(';') - PsiErrorElement:Identifier or type expected + PsiErrorElement:Resource definition expected + PsiJavaToken:SEMICOLON(';') PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryNormal4.txt b/java/java-tests/testData/psi/parser-partial/statements/TryNormal4.txt index c3bec38b2bf4..35a8f5f03eec 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryNormal4.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryNormal4.txt @@ -3,22 +3,21 @@ PsiJavaFile:TryNormal4.java PsiKeyword:try('try') PsiResourceList:(R r = 0) PsiJavaToken:LPARENTH('(') - PsiResource:r - PsiLocalVariable:r - PsiModifierList: - - PsiTypeElement:R - PsiJavaCodeReferenceElement:R - PsiIdentifier:R('R') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r('r') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiWhiteSpace(' ') - PsiLiteralExpression:0 - PsiJavaToken:INTEGER_LITERAL('0') + PsiResourceVariable:r + PsiModifierList: + + PsiTypeElement:R + PsiJavaCodeReferenceElement:R + PsiIdentifier:R('R') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryNormal5.txt b/java/java-tests/testData/psi/parser-partial/statements/TryNormal5.txt index b69bed12f700..7a09f71bba3e 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryNormal5.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryNormal5.txt @@ -3,40 +3,38 @@ PsiJavaFile:TryNormal5.java PsiKeyword:try('try') PsiResourceList:(R1 r1 = 1; R2 r2 = 2) PsiJavaToken:LPARENTH('(') - PsiResource:r1 - PsiLocalVariable:r1 - PsiModifierList: - - PsiTypeElement:R1 - PsiJavaCodeReferenceElement:R1 - PsiIdentifier:R1('R1') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r1('r1') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiWhiteSpace(' ') - PsiLiteralExpression:1 - PsiJavaToken:INTEGER_LITERAL('1') + PsiResourceVariable:r1 + PsiModifierList: + + PsiTypeElement:R1 + PsiJavaCodeReferenceElement:R1 + PsiIdentifier:R1('R1') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r1('r1') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:1 + PsiJavaToken:INTEGER_LITERAL('1') PsiJavaToken:SEMICOLON(';') PsiWhiteSpace(' ') - PsiResource:r2 - PsiLocalVariable:r2 - PsiModifierList: - - PsiTypeElement:R2 - PsiJavaCodeReferenceElement:R2 - PsiIdentifier:R2('R2') - PsiReferenceParameterList - - PsiWhiteSpace(' ') - PsiIdentifier:r2('r2') - PsiWhiteSpace(' ') - PsiJavaToken:EQ('=') - PsiWhiteSpace(' ') - PsiLiteralExpression:2 - PsiJavaToken:INTEGER_LITERAL('2') + PsiResourceVariable:r2 + PsiModifierList: + + PsiTypeElement:R2 + PsiJavaCodeReferenceElement:R2 + PsiIdentifier:R2('R2') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r2('r2') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:2 + PsiJavaToken:INTEGER_LITERAL('2') PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryNormal6.txt b/java/java-tests/testData/psi/parser-partial/statements/TryNormal6.txt index bf1b0ed88fd3..272652e46932 100644 --- a/java/java-tests/testData/psi/parser-partial/statements/TryNormal6.txt +++ b/java/java-tests/testData/psi/parser-partial/statements/TryNormal6.txt @@ -1,13 +1,24 @@ PsiJavaFile:TryNormal6.java PsiTryStatement PsiKeyword:try('try') - PsiResourceList:(r) + PsiResourceList:(R r = 0;) PsiJavaToken:LPARENTH('(') - PsiResource: - PsiReferenceExpression:r - PsiReferenceParameterList - - PsiIdentifier:r('r') + PsiResourceVariable:r + PsiModifierList: + + PsiTypeElement:R + PsiJavaCodeReferenceElement:R + PsiIdentifier:R('R') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiIdentifier:r('r') + PsiWhiteSpace(' ') + PsiJavaToken:EQ('=') + PsiWhiteSpace(' ') + PsiLiteralExpression:0 + PsiJavaToken:INTEGER_LITERAL('0') + PsiJavaToken:SEMICOLON(';') PsiJavaToken:RPARENTH(')') PsiCodeBlock PsiJavaToken:LBRACE('{') diff --git a/java/java-tests/testData/psi/parser-partial/statements/TryNormal7.txt b/java/java-tests/testData/psi/parser-partial/statements/TryNormal7.txt deleted file mode 100644 index 1299595c7a9b..000000000000 --- a/java/java-tests/testData/psi/parser-partial/statements/TryNormal7.txt +++ /dev/null @@ -1,19 +0,0 @@ -PsiJavaFile:TryNormal7.java - PsiTryStatement - PsiKeyword:try('try') - PsiResourceList:(r; null) - PsiJavaToken:LPARENTH('(') - PsiResource: - PsiReferenceExpression:r - PsiReferenceParameterList - - PsiIdentifier:r('r') - PsiJavaToken:SEMICOLON(';') - PsiWhiteSpace(' ') - PsiResource: - PsiLiteralExpression:null - PsiJavaToken:NULL_KEYWORD('null') - PsiJavaToken:RPARENTH(')') - PsiCodeBlock - PsiJavaToken:LBRACE('{') - PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index 83a619d5559d..5982a56f7a16 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -32,7 +32,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { @Override protected LocalInspectionTool[] configureLocalInspectionTools() { - return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UncheckedWarningLocalInspection(), new DefUseInspection()}; + return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UncheckedWarningLocalInspection()}; } public void testDuplicateAnnotations() throws Exception { @@ -194,6 +194,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { } public void testTryWithResourcesWarn() throws Exception { + enableInspectionTool(new DefUseInspection()); doTest(true, false); } diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/StatementParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/StatementParserTest.java index df12da3f6c62..118d33e54e96 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/StatementParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/StatementParserTest.java @@ -122,8 +122,7 @@ public class StatementParserTest extends JavaParsingTestCase { public void testTryNormal3() { doParserTestJDK7("try{}catch(A|B e){}"); } public void testTryNormal4() { doParserTestJDK7("try(R r = 0){}"); } public void testTryNormal5() { doParserTestJDK7("try(R1 r1 = 1; R2 r2 = 2){}"); } - public void testTryNormal6() { doParserTestJDK7("try(r){}"); } - public void testTryNormal7() { doParserTestJDK7("try(r; null){}"); } + public void testTryNormal6() { doParserTestJDK7("try(R r = 0;){}"); } public void testTryIncomplete0() { doParserTest("try"); } public void testTryIncomplete1() { doParserTest("try{}"); } public void testTryIncomplete2() { doParserTest("try{}catch"); } @@ -141,7 +140,7 @@ public class StatementParserTest extends JavaParsingTestCase { public void testTryIncomplete14() { doParserTestJDK7("try(int){}"); } public void testTryIncomplete15() { doParserTestJDK7("try(R r){}"); } public void testTryIncomplete16() { doParserTestJDK7("try(R r =){}"); } - public void testTryIncomplete17() { doParserTestJDK7("try(R r = 0;){}"); } + public void testTryIncomplete17() { doParserTestJDK7("try(R r = 0;;){}"); } public void testWhileNormal() { doParserTest("while (true) foo();"); } public void testWhileIncomplete0() { doParserTest("while"); } diff --git a/java/openapi/src/com/intellij/psi/JavaElementVisitor.java b/java/openapi/src/com/intellij/psi/JavaElementVisitor.java index c8162c6004b3..772a1e7963b3 100644 --- a/java/openapi/src/com/intellij/psi/JavaElementVisitor.java +++ b/java/openapi/src/com/intellij/psi/JavaElementVisitor.java @@ -300,8 +300,8 @@ public abstract class JavaElementVisitor extends PsiElementVisitor { visitElement(resourceList); } - public void visitResource(PsiResource resource) { - visitElement(resource); + public void visitResourceVariable(PsiResourceVariable resourceVariable) { + visitLocalVariable(resourceVariable); } public void visitTypeElement(PsiTypeElement type) { diff --git a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java index 6e59d5430e38..332f2f2928f2 100644 --- a/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java +++ b/java/openapi/src/com/intellij/psi/PsiJavaParserFacade.java @@ -125,7 +125,7 @@ public interface PsiJavaParserFacade extends PsiParserFacade { * @throws com.intellij.util.IncorrectOperationException if the text is not a valid resource definition. */ @NotNull - PsiResource createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException; + PsiResourceVariable createResourceFromText(@NotNull final String text, final PsiElement context) throws IncorrectOperationException; /** * Creates a Java type from the specified text. diff --git a/java/openapi/src/com/intellij/psi/PsiResource.java b/java/openapi/src/com/intellij/psi/PsiResource.java deleted file mode 100644 index e53289079c86..000000000000 --- a/java/openapi/src/com/intellij/psi/PsiResource.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Represents a resource list of try-with-resources statement (automatic resource management) introduced in JDK 7. - * - * @see PsiResourceList#getResources() - * @since 10.5. - */ -public interface PsiResource extends PsiElement { - /** - * Returns main element of the resource. - * It may be PsiLocalVariable, PsiAssignmentExpression, or other instance of PsiExpression. - * - * @return resource element. - */ - @NotNull - PsiElement getResourceElement(); - - @Nullable - PsiType getType(); -} diff --git a/java/openapi/src/com/intellij/psi/PsiResourceList.java b/java/openapi/src/com/intellij/psi/PsiResourceList.java index c954ae7e79bd..831151b15cc0 100644 --- a/java/openapi/src/com/intellij/psi/PsiResourceList.java +++ b/java/openapi/src/com/intellij/psi/PsiResourceList.java @@ -27,5 +27,5 @@ import java.util.List; */ public interface PsiResourceList extends PsiElement { @NotNull - List getResources(); + List getResourceVariables(); } diff --git a/java/openapi/src/com/intellij/psi/PsiScopedLocalVariable.java b/java/openapi/src/com/intellij/psi/PsiResourceVariable.java similarity index 73% rename from java/openapi/src/com/intellij/psi/PsiScopedLocalVariable.java rename to java/openapi/src/com/intellij/psi/PsiResourceVariable.java index b6f74359b683..113d69c321e2 100644 --- a/java/openapi/src/com/intellij/psi/PsiScopedLocalVariable.java +++ b/java/openapi/src/com/intellij/psi/PsiResourceVariable.java @@ -17,12 +17,13 @@ package com.intellij.psi; import org.jetbrains.annotations.NotNull; -public interface PsiScopedLocalVariable extends PsiLocalVariable { - /** - * Returns the element or elements (method, "for" statement or try block) in which the variable is declared. - * - * @return the declaration scope for the variable. - */ +/** + * Represents a resource variable of try-with-resources statement (automatic resource management) introduced in JDK 7. + * + * @see PsiResourceList#getResourceVariables() + * @since 10.5. + */ +public interface PsiResourceVariable extends PsiLocalVariable { @NotNull PsiElement[] getDeclarationScope(); } From e4eacc4451a1c49a1fbba75203eed350c6429c69 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 24 Feb 2011 21:35:40 +0100 Subject: [PATCH 05/11] "Reuse variable declaration" no more suitable for resource variables --- .../daemon/impl/analysis/HighlightUtil.java | 4 +++- .../impl/quickfix/ReuseVariableDeclarationFix.java | 13 ++----------- .../quickFix/reuseVariableDeclaration/after7.java | 14 -------------- .../quickFix/reuseVariableDeclaration/before7.java | 14 -------------- 4 files changed, 5 insertions(+), 40 deletions(-) delete mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/after7.java delete mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/before7.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index df75fdf060e8..1892c2df2a8d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -608,7 +608,9 @@ public class HighlightUtil { if (isIncorrect) { String description = JavaErrorMessages.message("variable.already.defined", name); HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, identifier, description); - QuickFixAction.registerQuickFixAction(highlightInfo, new ReuseVariableDeclarationFix(variable, identifier)); + if (!(variable instanceof PsiResourceVariable)) { + QuickFixAction.registerQuickFixAction(highlightInfo, new ReuseVariableDeclarationFix(variable, identifier)); + } return highlightInfo; } return null; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java index 2a681620886f..bd36c7434f41 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReuseVariableDeclarationFix.java @@ -57,7 +57,6 @@ public class ReuseVariableDeclarationFix implements IntentionAction { return myVariable != null && myVariable.isValid() && myVariable instanceof PsiLocalVariable && - !(myVariable.getParent() instanceof PsiResourceVariable && myVariable.getInitializer() == null) && previousVariable != null && Comparing.equal(previousVariable.getType(), myVariable.getType()) && myIdentifier != null && @@ -78,17 +77,9 @@ public class ReuseVariableDeclarationFix implements IntentionAction { } PsiUtil.setModifierProperty(refVariable, PsiModifier.FINAL, false); - final PsiElementFactory factory = JavaPsiFacade.getInstance(myVariable.getProject()).getElementFactory(); - final PsiElement replacement; - final PsiElement parent = myVariable.getParent(); - if (parent instanceof PsiResourceVariable) { - replacement = factory.createResourceFromText(myVariable.getName() + " = " + initializer.getText(), null); - } - else { - replacement = factory.createStatementFromText(myVariable.getName() + " = " + initializer.getText() + ";", null); - } - parent.replace(replacement); + final PsiElement statement = factory.createStatementFromText(myVariable.getName() + " = " + initializer.getText() + ";", null); + myVariable.getParent().replace(statement); } @Nullable diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/after7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/after7.java deleted file mode 100644 index 5b655ed5ba30..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/after7.java +++ /dev/null @@ -1,14 +0,0 @@ -// "Reuse previous variable 'r' declaration" "true" -import java.io.*; - -class a { - static class MyResource implements AutoCloseable { - public void close() { } - } - - void m() { - MyResource r; - try (r = new MyResource()) { - } - } -} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/before7.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/before7.java deleted file mode 100644 index dab83655490c..000000000000 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/reuseVariableDeclaration/before7.java +++ /dev/null @@ -1,14 +0,0 @@ -// "Reuse previous variable 'r' declaration" "true" -import java.io.*; - -class a { - static class MyResource implements AutoCloseable { - public void close() { } - } - - void m() { - MyResource r; - try (MyResource r = new MyResource()) { - } - } -} From e2302efffc4d7d73ff7d4e1c5ffe8a6005201c12 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 24 Feb 2011 22:01:18 +0100 Subject: [PATCH 06/11] Don't create stub for modifier list of resource variable --- .../stubs/JavaModifierListElementType.java | 6 -- .../psi/impl/source/JavaLightStubBuilder.java | 4 +- .../com/intellij/psi/JavaStubBuilderTest.java | 58 ++++++++++++------- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaModifierListElementType.java b/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaModifierListElementType.java index 5e1a2d1fa230..44366af5a6ff 100644 --- a/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaModifierListElementType.java +++ b/java/java-impl/src/com/intellij/psi/impl/java/stubs/JavaModifierListElementType.java @@ -78,12 +78,6 @@ public class JavaModifierListElementType extends JavaStubElementType Date: Fri, 25 Feb 2011 10:47:49 +0300 Subject: [PATCH 07/11] fixed unscrambling on frame activation --- .../unscramble/UnscrambleListener.java | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java b/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java index 6c44fad99e3a..e071b153df23 100644 --- a/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java +++ b/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java @@ -15,9 +15,11 @@ */ package com.intellij.unscramble; +import com.intellij.Patches; import com.intellij.openapi.application.ApplicationAdapter; import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.IdeFrame; +import com.intellij.util.Alarm; import java.util.regex.Pattern; @@ -29,16 +31,29 @@ public class UnscrambleListener extends ApplicationAdapter { private String stacktrace = null; @Override - public void applicationActivated(IdeFrame ideFrame) { - final String clipboard = AnalyzeStacktraceUtil.getTextInClipboard(); - if (clipboard != null && clipboard.length() < MAX_STACKTRACE_SIZE && !clipboard.equals(stacktrace)) { - stacktrace = clipboard; - final Project project = ideFrame.getProject(); - if (project != null && isStacktrace(stacktrace)) { - final UnscrambleDialog dialog = new UnscrambleDialog(project); - dialog.createNormalizeTextAction().actionPerformed(null); - dialog.doOKAction(); + public void applicationActivated(final IdeFrame ideFrame) { + final Runnable processClipboard = new Runnable() { + @Override + public void run() { + final String clipboard = AnalyzeStacktraceUtil.getTextInClipboard(); + if (clipboard != null && clipboard.length() < MAX_STACKTRACE_SIZE && !clipboard.equals(stacktrace)) { + stacktrace = clipboard; + final Project project = ideFrame.getProject(); + if (project != null && isStacktrace(stacktrace)) { + final UnscrambleDialog dialog = new UnscrambleDialog(project); + dialog.createNormalizeTextAction().actionPerformed(null); + dialog.doOKAction(); + } + } } + }; + + if (Patches.SLOW_GETTING_CLIPBOARD_CONTENTS) { + //IDEA's clipboard is synchronized with the system clipboard on frame activation so we need to postpone clipboard processing + new Alarm().addRequest(processClipboard, 300); + } + else { + processClipboard.run(); } } From 58cc76e0296fe2f075be9bf3d0e7e445e1cddeb0 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 25 Feb 2011 09:27:24 +0100 Subject: [PATCH 08/11] Added an option to also report when no more statements follow the if statement IDEA-65277 (Create an Inspection from the Intention "Remove Redundant 'else'".) --- .../siyeh/InspectionGadgetsBundle.properties | 3 +- .../controlflow/ConfusingElseInspection.java | 39 +++++++++++++------ .../inspectionDescriptions/ConfusingElse.html | 13 +++++-- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 19b949b8de96..9fc422581bbe 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -889,7 +889,7 @@ octal.literal.problem.descriptor=Octal integer #ref #loc implicit.call.to.super.problem.descriptor=Implicit call to super() #ref #loc negated.if.else.problem.descriptor=#ref statement with negated condition #loc negated.conditional.problem.descriptor=Conditional expression with negated condition #loc -confusing.else.problem.descriptor=#ref branch may be unwrapped, as the if branch never completes #loc +confusing.else.problem.descriptor=#ref branch may be unwrapped, as the 'if' branch never completes #loc switch.statement.with.confusing.declaration.problem.descriptor=Local variable #ref declared in one 'switch' branch and used in another #loc raw.use.of.parameterized.type.problem.descriptor=Raw use of parameterized class #ref #loc final.class.problem.descriptor=Class declared #ref #loc @@ -1856,3 +1856,4 @@ if.can.be.switch.enum.option=Suggest switch on enum unnecessarily.qualified.inner.class.access.option=Ignore references to foreign inner classes unqualified.inner.class.access.option=Ignore references to local inner classes try.with.identical.catches.quickfix=Collapse catch blocks into multi-catch +confusing.else.option=Also report when there are no more statements after the 'if' statement diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConfusingElseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConfusingElseInspection.java index 297eb276753c..cc96ede26eb7 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConfusingElseInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConfusingElseInspection.java @@ -16,6 +16,7 @@ package com.siyeh.ig.controlflow; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; @@ -29,8 +30,13 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; + public class ConfusingElseInspection extends BaseInspection { + @SuppressWarnings({"PublicField"}) + public boolean reportWhenNoStatementFollow = false; + @Override @NotNull public String getID() { @@ -50,6 +56,13 @@ public class ConfusingElseInspection extends BaseInspection { "confusing.else.problem.descriptor"); } + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel( + InspectionGadgetsBundle.message("confusing.else.option"), + this, "reportWhenNoStatementFollow"); + } + @Override public BaseInspectionVisitor buildVisitor() { return new ConfusingElseVisitor(); @@ -114,10 +127,11 @@ public class ConfusingElseInspection extends BaseInspection { } } - private static class ConfusingElseVisitor + private class ConfusingElseVisitor extends BaseInspectionVisitor { - @Override public void visitIfStatement(@NotNull PsiIfStatement statement) { + @Override public void visitIfStatement( + @NotNull PsiIfStatement statement) { super.visitIfStatement(statement); final PsiStatement thenBranch = statement.getThenBranch(); if (thenBranch == null) { @@ -133,14 +147,17 @@ public class ConfusingElseInspection extends BaseInspection { if (ControlFlowUtils.statementMayCompleteNormally(thenBranch)) { return; } - final PsiStatement nextStatement = getNextStatement(statement); - if (nextStatement == null) { - return; - } - if (!ControlFlowUtils.statementMayCompleteNormally(elseBranch)) { - return; - // protecting against an edge case where both branches return - // and are followed by a case label + if (reportWhenNoStatementFollow) { + final PsiStatement nextStatement = getNextStatement(statement); + if (nextStatement == null) { + return; + } + if (!ControlFlowUtils.statementMayCompleteNormally( + elseBranch)) { + return; + // protecting against an edge case where both branches return + // and are followed by a case label + } } final PsiElement elseToken = statement.getElseElement(); if (elseToken == null) { @@ -149,7 +166,7 @@ public class ConfusingElseInspection extends BaseInspection { registerError(elseToken); } - private static PsiStatement getNextStatement(PsiIfStatement statement) { + private PsiStatement getNextStatement(PsiIfStatement statement) { while (true) { final PsiElement parent = statement.getParent(); if (parent instanceof PsiIfStatement) { diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingElse.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingElse.html index 765f344f73bb..4317540c3c13 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingElse.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ConfusingElse.html @@ -1,9 +1,14 @@ -This inspection reports confusing else branches. Confusing else -branches are branches of if statements whose if branch cannot complete normally and -which are followed by other statements. In these cases, the statements following the -if statement may be moved into the else branch, for increased clarity. +This inspection reports confusing else branches. else branches are confusing +when the if statement is followed by other statements and the if branch +cannot complete normally, for example because it ends with a return statement. In these +cases the statements in the else can be moved after the if statement and +the else branch removed. +

+Use the checkbox below to also report else branches of if statements whose +if branch cannot complete normally and which are not followed by more statements, +similar to the Redundant Else intention.

Powered by InspectionGadgets From 90f6fb7914ae1b908e6f3bd32f597ed8c531b066 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 25 Feb 2011 09:50:20 +0100 Subject: [PATCH 09/11] less enthusiastic reporting of duplicate if branches to prevent the quickfix from changing the semantics of code --- ...IfStatementWithIdenticalBranchesInspection.java | 11 ++--------- .../expected.xml | 14 -------------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java index 696cfbb905fd..20a756755786 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java @@ -157,12 +157,10 @@ public class IfStatementWithIdenticalBranchesInspection private static class IfStatementWithIdenticalBranchesVisitor extends BaseInspectionVisitor{ - private static final int LIMIT_DEPTH = 20; // Dirty fix for 'squared' algorithm. - @Override public void visitIfStatement( @NotNull PsiIfStatement ifStatement){ super.visitIfStatement(ifStatement); - PsiStatement elseBranch = ifStatement.getElseBranch(); + final PsiStatement elseBranch = ifStatement.getElseBranch(); final PsiStatement thenBranch = ifStatement.getThenBranch(); if (thenBranch == null) { return; @@ -175,11 +173,7 @@ public class IfStatementWithIdenticalBranchesInspection new DuplicatesFinder(new PsiElement[]{thenBranch}, inputVariables, null, Collections.emptyList()); - int depth = 0; - while (elseBranch instanceof PsiIfStatement) { - if (depth++ > LIMIT_DEPTH) { - break; - } + if (elseBranch instanceof PsiIfStatement) { final PsiIfStatement statement = (PsiIfStatement) elseBranch; final PsiStatement branch = statement.getThenBranch(); @@ -191,7 +185,6 @@ public class IfStatementWithIdenticalBranchesInspection registerStatementError(ifStatement, statement); return; } - elseBranch = statement.getElseBranch(); } if (elseBranch == null) { checkIfStatementWithoutElseBranch(ifStatement); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/expected.xml index 09413c6c0692..fd2d89330b04 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/if_statement_with_identical_branches/expected.xml @@ -35,20 +35,6 @@ <code>if</code> statement with identical branches #loc - - IfStatementWithIdenticalBranches.java - 71 - 'if' statement with identical branches - <code>if</code> statement with identical branches #loc - - - - IfStatementWithIdenticalBranches.java - 82 - 'if' statement with identical branches - <code>if</code> statement with identical branches #loc - - IfStatementWithIdenticalBranches.java 92 From 9779ac6a5031ebaab8a55d1aad0c9f0f2a9d5efd Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 25 Feb 2011 12:22:23 +0300 Subject: [PATCH 10/11] document leak fixed --- .../openapi/editor/impl/DocumentImpl.java | 20 +++--- .../impl/DocumentMarkupModelManager.java | 66 +++++++++++++++++++ .../src/componentSets/Editor.xml | 5 +- 3 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentMarkupModelManager.java diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java index 64e6f0832ddd..734f2f2cb502 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentImpl.java @@ -658,7 +658,8 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { return markupModel; } - if (project.isDisposed()) { + final DocumentMarkupModelManager documentMarkupModelManager = project.isDisposed() ? null : DocumentMarkupModelManager.getInstance(project); + if (documentMarkupModelManager == null || documentMarkupModelManager.isDisposed() || project.isDisposed()) { return new EmptyMarkupModel(this); } @@ -669,15 +670,7 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { if (model == null) { model = new MarkupModelImpl(this); myProjectToMarkupModelMap.put(project, model); - Disposer.register(project, new Disposable() { - @Override - public void dispose() { - MarkupModelImpl removed = myProjectToMarkupModelMap.remove(project); - if (removed != null) { - removed.dispose(); - } - } - }); + documentMarkupModelManager.registerDocument(this); } } } @@ -685,6 +678,13 @@ public class DocumentImpl extends UserDataHolderBase implements DocumentEx { return model; } + void removeMarkupModel(@NotNull Project project) { + MarkupModelImpl removed = myProjectToMarkupModelMap.remove(project); + if (removed != null) { + removed.dispose(); + } + } + public void setCyclicBufferSize(int bufferSize) { myText.setBufferSize(bufferSize); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentMarkupModelManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentMarkupModelManager.java new file mode 100644 index 000000000000..1cdc183a8370 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/DocumentMarkupModelManager.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.impl; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.util.containers.WeakList; +import org.jetbrains.annotations.NotNull; + +/** + * @author max + */ +public class DocumentMarkupModelManager extends AbstractProjectComponent { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.DocumentMarkupModelManager"); + + private final WeakList myDocumentSet = new WeakList(); + private volatile boolean myDisposed; + + public static DocumentMarkupModelManager getInstance(Project project) { + return project.getComponent(DocumentMarkupModelManager.class); + } + + public DocumentMarkupModelManager(@NotNull Project project) { + super(project); + Disposer.register(project, new Disposable() { + @Override + public void dispose() { + cleanupProjectMarkups(); + } + }); + } + + public void registerDocument(DocumentImpl document) { + LOG.assertTrue(!myDisposed); + myDocumentSet.add(document); + } + + public boolean isDisposed() { + return myDisposed; + } + + private void cleanupProjectMarkups() { + if (!myDisposed) { + myDisposed = true; + for (DocumentImpl document : myDocumentSet.toStrongList()) { + document.removeMarkupModel(myProject); + } + } + } +} diff --git a/platform/platform-resources/src/componentSets/Editor.xml b/platform/platform-resources/src/componentSets/Editor.xml index e93ee1fa321a..28ecbbeb4ef1 100644 --- a/platform/platform-resources/src/componentSets/Editor.xml +++ b/platform/platform-resources/src/componentSets/Editor.xml @@ -19,6 +19,9 @@ + + com.intellij.openapi.editor.impl.DocumentMarkupModelManager + com.intellij.openapi.fileEditor.impl.EditorHistoryManager - + \ No newline at end of file From 357404d5fea8e4708fde64c417a09d88834da419 Mon Sep 17 00:00:00 2001 From: andrey zaytsev Date: Fri, 25 Feb 2011 13:14:24 +0300 Subject: [PATCH 11/11] search/replace refactoring: changing of editors selection is responsibility of controller --- .../intellij/find/EditorSearchComponent.java | 85 +++++-------------- .../intellij/find/impl/FindManagerImpl.java | 7 +- .../LivePreviewControllerBase.java | 53 +++++++++++- .../find/impl/livePreview/SearchResults.java | 4 + 4 files changed, 82 insertions(+), 67 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java index 301dd51768a9..8a38ca076080 100644 --- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java +++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java @@ -29,8 +29,6 @@ import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; -import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.event.SelectionEvent; import com.intellij.openapi.editor.event.SelectionListener; @@ -108,7 +106,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec private boolean myIsReplace; private boolean myListeningSelection = false; - private boolean myToChangeSelection = true; private SearchResults mySearchResults; private Balloon myOptionsBalloon; @@ -129,59 +126,40 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec int count = sr.getActualFound(); if (mySearchField.getText().isEmpty()) { nothingToSearchFor(); - return; - } + } else { + if (count <= mySearchResults.getMatchesLimit()) { + myClickToHighlightLabel.setVisible(false); - if (count <= mySearchResults.getMatchesLimit()) { - myClickToHighlightLabel.setVisible(false); - - if (count > 0) { - setRegularBackground(); - if (count > 1) { - myMatchInfoLabel.setText(count + " matches"); + if (count > 0) { + setRegularBackground(); + if (count > 1) { + myMatchInfoLabel.setText(count + " matches"); + } + else { + myMatchInfoLabel.setText("1 match"); + } } else { - myMatchInfoLabel.setText("1 match"); + setNotFoundBackground(); + myMatchInfoLabel.setText("No matches"); } } else { - setNotFoundBackground(); - myMatchInfoLabel.setText("No matches"); + setRegularBackground(); + myMatchInfoLabel.setText("More than " + mySearchResults.getMatchesLimit() + " matches"); + myClickToHighlightLabel.setVisible(true); + boldMatchInfo(); } } - else { - setRegularBackground(); - myMatchInfoLabel.setText("More than " + mySearchResults.getMatchesLimit() + " matches"); - myClickToHighlightLabel.setVisible(true); - boldMatchInfo(); - } - updateSelection(); updateExcludeStatus(); } @Override public void cursorMoved() { - updateSelection(); updateExcludeStatus(); } - private void updateSelection() { - SelectionModel selection = myEditor.getSelectionModel(); - if (myToChangeSelection && (mySelectionOnly == null || !mySelectionOnly.isSelected())) { - LiveOccurrence cursor = mySearchResults.getCursor(); - if (cursor != null) { - TextRange range = cursor.getPrimaryRange(); - selection.setSelection(range.getStartOffset(), range.getEndOffset()); - - myEditor.getCaretModel().moveToOffset(range.getEndOffset()); - myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - - } - myToChangeSelection = false; - } - } - @Override public void editorChanged(SearchResults sr, Editor oldEditor) { } @@ -580,14 +558,13 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec } private void searchBackward() { - moveCursor(false); + moveCursor(SearchResults.Direction.UP); addCurrentTextToRecents(); } private void searchForward() { - moveCursor(true); - + moveCursor(SearchResults.Direction.DOWN); addCurrentTextToRecents(); } @@ -603,13 +580,8 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec updateResults(true); } - public void moveCursor(boolean forwardOrBackward) { - myToChangeSelection = true; - if (forwardOrBackward) { - mySearchResults.nextOccurrence(); - } else { - mySearchResults.prevOccurrence(); - } + public void moveCursor(SearchResults.Direction direction) { + myLivePreviewController.moveCursor(direction, true); } public void replaceCurrent() { @@ -660,7 +632,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec myEditor.getDocument().addDocumentListener(myDocumentListener); if (myLivePreview != null) { - myLivePreviewController.updateInBackground(mySearchResults.getFindModel()); + myLivePreviewController.updateInBackground(mySearchResults.getFindModel(), false); } } @@ -727,11 +699,7 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec model.setGlobal(!mySelectionOnly.isSelected()); model.setPreserveCase(myPreserveCase.isEnabled() && myPreserveCase.isSelected()); } - if (!myToChangeSelection) { - myToChangeSelection = allowedToChangedEditorSelection; - } - - myLivePreviewController.updateInBackground(model); + myLivePreviewController.updateInBackground(model, allowedToChangedEditorSelection); } } @@ -1006,13 +974,6 @@ public class EditorSearchComponent extends JPanel implements DataProvider, Selec mySearchField.requestFocus(); } - @Override - public TextRange performReplace(LiveOccurrence occurrence, String replacement, Editor editor) { - myToChangeSelection = true; - return super - .performReplace(occurrence, replacement, editor); //To change body of overridden methods use File | Settings | File Templates. - } - public void performReplace() { String replacement = getStringToReplace(myEditor, mySearchResults.getCursor()); performReplace(mySearchResults.getCursor(), replacement, myEditor); diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index dc3eef7c724c..9f3c590b9a91 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -24,6 +24,7 @@ import com.intellij.codeInsight.hint.HintManagerImpl; import com.intellij.codeInsight.hint.HintUtil; import com.intellij.find.*; import com.intellij.find.findUsages.FindUsagesManager; +import com.intellij.find.impl.livePreview.SearchResults; import com.intellij.lang.Language; import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.ParserDefinition; @@ -655,7 +656,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo } } - private boolean tryToFindNextUsageViaEditorSearchComponent(Editor editor, boolean forwardOrBackward) { + private boolean tryToFindNextUsageViaEditorSearchComponent(Editor editor, SearchResults.Direction forwardOrBackward) { if (editor.getHeaderComponent() instanceof EditorSearchComponent) { EditorSearchComponent searchComponent = (EditorSearchComponent)editor.getHeaderComponent(); if (searchComponent.hasMatches()) { @@ -670,7 +671,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo if (fileEditor instanceof TextEditor) { TextEditor textEditor = (TextEditor)fileEditor; Editor editor = textEditor.getEditor(); - if (tryToFindNextUsageViaEditorSearchComponent(editor, true)) { + if (tryToFindNextUsageViaEditorSearchComponent(editor, SearchResults.Direction.DOWN)) { return true; } FindModel model = getFindNextModel(editor); @@ -689,7 +690,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo if (fileEditor instanceof TextEditor) { TextEditor textEditor = (TextEditor)fileEditor; Editor editor = textEditor.getEditor(); - if (tryToFindNextUsageViaEditorSearchComponent(editor, false)) { + if (tryToFindNextUsageViaEditorSearchComponent(editor, SearchResults.Direction.UP)) { return true; } FindModel model = getFindNextModel(editor); diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java index 8e053661000f..94c344b19124 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewControllerBase.java @@ -6,6 +6,8 @@ import com.intellij.find.FindUtil; import com.intellij.find.impl.FindResultImpl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.util.Alarm; @@ -13,7 +15,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil.ReplaceDelegate { +public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil.ReplaceDelegate, SearchResults.SearchResultsListener { private static final String EMPTY_STRING_DISPLAY_TEXT = ""; @@ -26,6 +28,48 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil private SearchResults mySearchResults; private LivePreview myLivePreview; + private boolean myToChangeSelection = true; + + private void updateSelection() { + Editor editor = mySearchResults.getEditor(); + SelectionModel selection = editor.getSelectionModel(); + FindModel findModel = mySearchResults.getFindModel(); + if (myToChangeSelection && findModel.isGlobal()) { + LiveOccurrence cursor = mySearchResults.getCursor(); + if (cursor != null) { + TextRange range = cursor.getPrimaryRange(); + selection.setSelection(range.getStartOffset(), range.getEndOffset()); + + editor.getCaretModel().moveToOffset(range.getEndOffset()); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + + } + myToChangeSelection = false; + } + } + + @Override + public void searchResultsUpdated(SearchResults sr) { + updateSelection(); + } + + @Override + public void editorChanged(SearchResults sr, Editor oldEditor) {} + + @Override + public void cursorMoved() { + updateSelection(); + } + + public void moveCursor(SearchResults.Direction direction, boolean toChangeSelection) { + myToChangeSelection = toChangeSelection; + if (direction == SearchResults.Direction.UP) { + mySearchResults.prevOccurrence(); + } else { + mySearchResults.nextOccurrence(); + } + } + public interface ReplaceListener { void replacePerformed(LiveOccurrence occurrence, final String replacement, final Editor editor); void replaceAllPerformed(Editor e); @@ -43,6 +87,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil public LivePreviewControllerBase(SearchResults searchResults, LivePreview livePreview) { mySearchResults = searchResults; + mySearchResults.addListener(this); myLivePreview = livePreview; myLivePreview.setDelegate(this); } @@ -55,7 +100,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil myUserActivityDelay = userActivityDelay; } - public void updateInBackground(final FindModel findModel) { + public void updateInBackground(final FindModel findModel, boolean allowedToChangedEditorSelection) { myLivePreviewAlarm.cancelAllRequests(); if (findModel == null) return; Runnable request = new Runnable() { @@ -69,6 +114,9 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil } else { myLivePreviewAlarm.addRequest(request, myUserActivityDelay); } + if (allowedToChangedEditorSelection) { + myToChangeSelection = true; + } } @Override @@ -99,6 +147,7 @@ public class LivePreviewControllerBase implements LivePreview.Delegate, FindUtil @Nullable @Override public TextRange performReplace(final LiveOccurrence occurrence, final String replacement, final Editor editor) { + myToChangeSelection = true; TextRange range = occurrence.getPrimaryRange(); FindModel findModel = mySearchResults.getFindModel(); TextRange result = null; diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java index 4dd7da36d644..ddd5c03c77ec 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java +++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java @@ -19,6 +19,8 @@ import java.util.List; public class SearchResults { + public enum Direction {UP, DOWN} + private int myActualFound = 0; private List myListeners = new ArrayList(); @@ -293,6 +295,8 @@ public class SearchResults { for (LiveOccurrence searchResult : getOccurrences()) { if (searchResult.getPrimaryRange().intersects(oldCursorRange)) { mayBeOldCursor = searchResult; + } + if (searchResult.getPrimaryRange().equals(oldCursorRange)) { break; } }