From bcf4fd2f658777fe5370b442d25973ca3a67da09 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sat, 17 Mar 2012 17:40:17 +0100 Subject: [PATCH 1/9] fix "Suspicious test for oddness" inspection description --- .../src/inspectionDescriptions/BadOddness.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/BadOddness.html b/plugins/InspectionGadgets/src/inspectionDescriptions/BadOddness.html index ae1eb20bdc84..6e0616a2ac02 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/BadOddness.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/BadOddness.html @@ -3,7 +3,7 @@ This inspection reports any checks for oddness of the form:
x % 2 == 1
Such checks will fail for negative odd values, which is probably not the behaviour intended. Consider using: -
x % 2 != 0
or:
x & 1 == 1
instead. +
x % 2 != 0
or:
(x & 1) == 1
instead.

Powered by InspectionGadgets From 00d1d56b049c0e39a38b96b4454a1fddffe3cf3f Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sat, 17 Mar 2012 17:41:35 +0100 Subject: [PATCH 2/9] DEA-82643 ("Abstract method overrides abstract method" should allow for exceptions based on annotations) --- .../siyeh/InspectionGadgetsBundle.properties | 3 +- ...thodOverridesAbstractMethodInspection.java | 64 +++++++++++++++++-- ...AbstractMethodOverridesAbstractMethod.html | 6 +- ...thodOverridesAbstractMethodInspection.java | 11 ---- ...AbstractMethodOverridesAbstractMethod.java | 31 +++++++++ .../expected.xml | 11 ++++ ...OverridesAbstractMethodInspectionTest.java | 13 ++++ 7 files changed, 119 insertions(+), 20 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesAbstractMethodInspection.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/abstract_method_overrides_abstract_method/AbstractMethodOverridesAbstractMethod.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/abstract_method_overrides_abstract_method/expected.xml create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/AbstractMethodOverridesAbstractMethodInspectionTest.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 62555bcfe923..a1a6f8eab86d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -917,7 +917,8 @@ utility.class.without.private.constructor.problem.descriptor=Class #ref#ref() overrides concrete method #loc abstract.method.with.missing.implementations.problem.descriptor=Abstract method #ref() is not implemented in every subclass #loc abstract.method.overrides.abstract.method.problem.descriptor=Abstract method #ref() overrides abstract method #loc -abstract.method.overrides.abstract.method.ignore.different.javadoc.option=Ignore methods with a different JavaDoc than their super methods +abstract.method.overrides.abstract.method.ignore.different.javadoc.option=Ignore methods with different JavaDoc than their super methods +abstract.method.overrides.abstract.method.ignore.different.annotations.option=Ignore methods with different annotations than their super methods abstract.class.extends.concrete.class.problem.descriptor=Class #ref is declared 'abstract', and extends a concrete class #loc static.non.final.field.problem.descriptor='static' non-'final' field #ref #loc constant.declared.in.abstract.class.problem.descriptor=Constant #ref declared in abstract class #loc diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/inheritance/AbstractMethodOverridesAbstractMethodInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/inheritance/AbstractMethodOverridesAbstractMethodInspection.java index cd1de1310380..9ef603908f9c 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/inheritance/AbstractMethodOverridesAbstractMethodInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/inheritance/AbstractMethodOverridesAbstractMethodInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ package com.siyeh.ig.inheritance; import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; +import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.javadoc.PsiDocComment; @@ -34,8 +34,12 @@ import java.util.Set; public class AbstractMethodOverridesAbstractMethodInspection extends BaseInspection { + @SuppressWarnings("PublicField") public boolean ignoreJavaDoc = false; + @SuppressWarnings("PublicField") + public boolean ignoreAnnotations = false; + @Override @NotNull public String getDisplayName() { @@ -55,8 +59,12 @@ public class AbstractMethodOverridesAbstractMethodInspection extends BaseInspect @Override public JComponent createOptionsPanel() { - return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message( - "abstract.method.overrides.abstract.method.ignore.different.javadoc.option"), this, "ignoreJavaDoc"); + final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this); + panel.addCheckbox(InspectionGadgetsBundle.message( + "abstract.method.overrides.abstract.method.ignore.different.javadoc.option"), "ignoreJavaDoc"); + panel.addCheckbox(InspectionGadgetsBundle.message( + "abstract.method.overrides.abstract.method.ignore.different.annotations.option"), "ignoreAnnotations"); + return panel; } private static class AbstractMethodOverridesAbstractMethodFix extends InspectionGadgetsFix { @@ -83,7 +91,6 @@ public class AbstractMethodOverridesAbstractMethodInspection extends BaseInspect private class AbstractMethodOverridesAbstractMethodVisitor extends BaseInspectionVisitor { - @Override public void visitMethod(@NotNull PsiMethod method) { //no call to super, so we don't drill into anonymous classes @@ -105,18 +112,61 @@ public class AbstractMethodOverridesAbstractMethodInspection extends BaseInspect if (!isAbstract(superMethod)) { continue; } - if (!methodsHaveSameReturnTypes(method, superMethod) || - !haveSameExceptionSignatures(method, superMethod)) { + if (!methodsHaveSameReturnTypes(method, superMethod) || !haveSameExceptionSignatures(method, superMethod)) { continue; } if (ignoreJavaDoc && !haveSameJavaDoc(method, superMethod)) { return; } + if (ignoreAnnotations && !methodsHaveSameAnnotations(method, superMethod)) { + return; + } registerMethodError(method); return; } } + private boolean methodsHaveSameAnnotations(PsiMethod method, PsiMethod superMethod) { + if (!haveSameAnnotations(method, superMethod)) { + return false; + } + final PsiParameterList superParameterList = superMethod.getParameterList(); + final PsiParameter[] superParameters = superParameterList.getParameters(); + final PsiParameterList parameterList = method.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + for (int i = 0, length = superParameters.length; i < length; i++) { + final PsiParameter superParameter = superParameters[i]; + final PsiParameter parameter = parameters[i]; + if (!haveSameAnnotations(parameter, superParameter)) { + return false; + } + } + return true; + } + + private boolean haveSameAnnotations(PsiModifierListOwner owner1, PsiModifierListOwner owner2) { + final PsiModifierList modifierList = owner1.getModifierList(); + final PsiModifierList superModifierList = owner2.getModifierList(); + if (superModifierList == null) { + return modifierList == null; + } else if (modifierList == null) { + return false; + } + final PsiAnnotation[] superAnnotations = superModifierList.getAnnotations(); + final PsiAnnotation[] annotations = modifierList.getAnnotations(); + final Set annotationsSet = new HashSet(Arrays.asList(superAnnotations)); + for (PsiAnnotation annotation : annotations) { + final String qualifiedName = annotation.getQualifiedName(); + if ("java.lang.Override".equals(qualifiedName)) { + continue; + } + if (!annotationsSet.contains(annotation)) { + return false; + } + } + return true; + } + private boolean haveSameJavaDoc(PsiMethod method, PsiMethod superMethod) { final PsiDocComment superDocComment = superMethod.getDocComment(); final PsiDocComment docComment = method.getDocComment(); diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesAbstractMethod.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesAbstractMethod.html index abd9135fc4c2..59e628bae7ef 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesAbstractMethod.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AbstractMethodOverridesAbstractMethod.html @@ -1,9 +1,13 @@ -This inspection reports abstract methods which override abstract methods. Methods with +This inspection reports abstract methods which override abstract methods. Methods with different return types or exception declarations than the method they override are not reported by this inspection.

+Use the first checkbox to ignore any abstract methods that have a different JavaDoc comment than their super method. +

+Use the second checkbox to ignore any abstract methods that have one or more annotations that are not present on their super method. +

Powered by InspectionGadgets \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesAbstractMethodInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesAbstractMethodInspection.java deleted file mode 100644 index 2cdf865ca3ec..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/AbstractMethodOverridesAbstractMethodInspection.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.siyeh.igtest.classlayout; - - -public abstract class AbstractMethodOverridesAbstractMethodInspection { - public abstract Object foo() throws Exception; -} - - abstract class Child extends AbstractMethodOverridesAbstractMethodInspection -{ - public abstract Object foo() ; -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/abstract_method_overrides_abstract_method/AbstractMethodOverridesAbstractMethod.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/abstract_method_overrides_abstract_method/AbstractMethodOverridesAbstractMethod.java new file mode 100644 index 000000000000..55c25977c82b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/abstract_method_overrides_abstract_method/AbstractMethodOverridesAbstractMethod.java @@ -0,0 +1,31 @@ +package com.siyeh.igtest.inheritance.abstract_method_overrides_abstract_method; + + +import org.jetbrains.annotations.Nullable; + +public abstract class AbstractMethodOverridesAbstractMethod { + public abstract Object foo() throws Exception; + + abstract void one(String s); + + abstract void two(); + + public abstract void three(); + + + + +} +abstract class Child extends AbstractMethodOverridesAbstractMethod +{ + public abstract String foo() ; + + abstract void one(@Nullable String s); + + /** + * some documentation + */ + abstract void two(); + + public abstract void three(); +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/abstract_method_overrides_abstract_method/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/abstract_method_overrides_abstract_method/expected.xml new file mode 100644 index 000000000000..7682ee3c3a6a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/inheritance/abstract_method_overrides_abstract_method/expected.xml @@ -0,0 +1,11 @@ + + + + + AbstractMethodOverridesAbstractMethod.java + 30 + Abstract method overrides abstract method + Abstract method <code>three()</code> overrides abstract method #loc + + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/AbstractMethodOverridesAbstractMethodInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/AbstractMethodOverridesAbstractMethodInspectionTest.java new file mode 100644 index 000000000000..5e6ed0b25c88 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/AbstractMethodOverridesAbstractMethodInspectionTest.java @@ -0,0 +1,13 @@ +package com.siyeh.ig.inheritance; + +import com.siyeh.ig.IGInspectionTestCase; + +public class AbstractMethodOverridesAbstractMethodInspectionTest extends IGInspectionTestCase { + + public void test() throws Exception { + final AbstractMethodOverridesAbstractMethodInspection tool = new AbstractMethodOverridesAbstractMethodInspection(); + tool.ignoreAnnotations = true; + tool.ignoreJavaDoc = true; + doTest("com/siyeh/igtest/inheritance/abstract_method_overrides_abstract_method", tool); + } +} From 3f9745383d7198059611f7989ec5409f09628740 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 19 Mar 2012 09:15:17 +0100 Subject: [PATCH 3/9] get back automatic stacktrace analyzer on mac --- .../src/com/intellij/unscramble/UnscrambleListener.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java b/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java index 23afeba19ed8..2612500f018e 100644 --- a/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java +++ b/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java @@ -33,8 +33,6 @@ public class UnscrambleListener implements ApplicationActivationListener { @Override public void applicationActivated(final IdeFrame ideFrame) { - if (SystemInfo.isMac) return; - final Runnable processClipboard = new Runnable() { @Override public void run() { From 409ba238394bdf6f0f829e8cc953d5b1a27bc99f Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Mon, 19 Mar 2012 13:01:06 +0400 Subject: [PATCH 4/9] Limit custom folding lookup depth --- .../intellij/lang/folding/CustomFoldingBuilder.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java index 1b5822fbe3e2..cc6c34625ef8 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java @@ -22,6 +22,7 @@ import java.util.List; public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements DumbAware { private CustomFoldingProvider myDefaultProvider; + private static final int MAX_LOOKUP_DEPTH = 10; @NotNull @Override @@ -29,7 +30,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D List descriptors = new ArrayList(); if (CustomFoldingProvider.getAllProviders().length > 0) { myDefaultProvider = null; - addCustomFoldingRegionsRecursively(null, root.getNode(), descriptors); + addCustomFoldingRegionsRecursively(null, root.getNode(), descriptors, 0); } buildLanguageFoldRegions(descriptors, root, document, quick); return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); @@ -57,7 +58,8 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D private void addCustomFoldingRegionsRecursively(@Nullable FoldingStack foldingStack, @NotNull ASTNode node, - List descriptors) { + List descriptors, + int currDepth) { FoldingStack localFoldingStack = isCustomFoldingRoot(node) || foldingStack == null ? new FoldingStack(node) : foldingStack; for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) { if (isCustomRegionStart(child)) { @@ -72,7 +74,9 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D } } else { - addCustomFoldingRegionsRecursively(localFoldingStack, child, descriptors); + if (currDepth < MAX_LOOKUP_DEPTH) { + addCustomFoldingRegionsRecursively(localFoldingStack, child, descriptors, currDepth + 1); + } } } } From 3b51803ddb07010974589d8e3c75a842469bbce8 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 16 Mar 2012 15:52:32 +0400 Subject: [PATCH 5/9] synchronization --- .../vfs/newvfs/impl/VirtualDirectoryImpl.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index 035266c4dd47..c7b2b88a308c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -73,7 +73,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { private final NewVirtualFileSystem myFS; // guarded by this - protected Object myChildren; // Either HashMap or VFile[] + private Object myChildren; // Either HashMap or VFile[] public VirtualDirectoryImpl(@NotNull String name, final VirtualDirectoryImpl parent, @NotNull NewVirtualFileSystem fs, final int id) { super(name, parent, id); @@ -379,8 +379,9 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { @NotNull private synchronized Collection getInDbChildren() { - if (myChildren instanceof VirtualFileSystemEntry[]) { - return Arrays.asList((VirtualFile[])myChildren); + VirtualFileSystemEntry[] children = asArray(); + if (children != null) { + return Arrays.asList((VirtualFile[])children); } if (!ourPersistence.wereChildrenAccessed(this)) { @@ -404,13 +405,13 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { @Override @NotNull public synchronized VirtualFile[] getChildren() { - if (myChildren instanceof VirtualFileSystemEntry[]) { - return (VirtualFileSystemEntry[])myChildren; + VirtualFileSystemEntry[] children = asArray(); + if (children != null) { + return children; } Pair pair = PersistentFS.listAll(this); final int[] childrenIds = pair.second; - VirtualFileSystemEntry[] children; if (childrenIds.length == 0) { children = EMPTY_ARRAY; } @@ -454,7 +455,10 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { @Override public NewVirtualFile findChildByIdIfCached(int id) { - final VirtualFile[] a = asArray(); + final VirtualFile[] a; + synchronized (this) { + a = asArray(); + } if (a != null) { for (VirtualFile file : a) { NewVirtualFile withId = (NewVirtualFile)file; @@ -477,12 +481,15 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { return null; } + // MUST BE CALLED UNDER this LOCK @Nullable private VirtualFileSystemEntry[] asArray() { - if (myChildren instanceof VirtualFileSystemEntry[]) return (VirtualFileSystemEntry[])myChildren; + Object children = myChildren; + if (children instanceof VirtualFileSystemEntry[]) return (VirtualFileSystemEntry[])children; return null; } + // MUST BE CALLED UNDER this LOCK @Nullable private Map asMap() { if (myChildren instanceof Map) { @@ -530,7 +537,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { } public synchronized boolean allChildrenLoaded() { - return myChildren instanceof VirtualFileSystemEntry[]; + return asArray() != null; } @NotNull From 1f87b4a9937782b883e471890476ea2166ca24ba Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 16 Mar 2012 16:25:04 +0400 Subject: [PATCH 6/9] supply project name in tests --- .../fixtures/JavaCodeInsightFixtureTestCase.java | 2 +- .../testFramework/fixtures/JavaTestFixtureFactory.java | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java index c2dd1a155a13..4fc029dcd86c 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java @@ -44,7 +44,7 @@ public abstract class JavaCodeInsightFixtureTestCase extends UsefulTestCase{ protected void setUp() throws Exception { super.setUp(); - final TestFixtureBuilder projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(); + final TestFixtureBuilder projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName()); myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(projectBuilder.getFixture()); final JavaModuleFixtureBuilder moduleFixtureBuilder = projectBuilder.addModule(JavaModuleFixtureBuilder.class); moduleFixtureBuilder.addSourceContentRoot(myFixture.getTempDirPath()); diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java index b7b03b1de9df..5ae19176c25b 100644 --- a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java +++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java @@ -15,6 +15,8 @@ */ package com.intellij.testFramework.fixtures; +import org.jetbrains.annotations.NotNull; + /** * @author yole */ @@ -41,8 +43,15 @@ public abstract class JavaTestFixtureFactory { public abstract JavaCodeInsightTestFixture createCodeInsightFixture(IdeaProjectTestFixture projectFixture, TempDirTestFixture tempDirFixture); + /** + * + * @deprecated use {@link JavaTestFixtureFactory#createFixtureBuilder(String)} + */ //also implicitly initializes ourInstance and registers java module fixture builder public static TestFixtureBuilder createFixtureBuilder() { return IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(); } + public static TestFixtureBuilder createFixtureBuilder(@NotNull String name) { + return IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(name); + } } From b60202e290c99498f2da2436adfe1a6bcabcf2b1 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 16 Mar 2012 18:01:35 +0400 Subject: [PATCH 7/9] memory: do not store PsiFiles --- .../daemon/impl/DaemonCodeAnalyzerImpl.java | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java index 4cd590aa5898..252b26675a03 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java @@ -61,6 +61,7 @@ import com.intellij.psi.impl.PsiDocumentManagerImpl; import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.psi.search.scope.packageSet.NamedScopeManager; import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.Alarm; import com.intellij.util.CommonProcessors; import com.intellij.util.Processor; @@ -94,7 +95,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx private final Alarm myAlarm = new Alarm(); private boolean myUpdateByTimerEnabled = true; private final Collection myDisabledHintsFiles = new THashSet(); - private final Collection myDisabledHighlightingFiles = new THashSet(); + private final Collection myDisabledHighlightingFiles = new THashSet(); private final FileStatusMap myFileStatusMap; private DaemonCodeAnalyzerSettings myLastSettings; @@ -122,6 +123,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myFileStatusMap = new FileStatusMap(myProject); myPassExecutorService = new PassExecutorService(myProject) { + @Override protected void afterApplyInformationToEditor(final TextEditorHighlightingPass pass, final FileEditor fileEditor, final ProgressIndicator updateProgress) { @@ -132,6 +134,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @Override protected boolean isDisposed() { return myDisposed || super.isDisposed(); } @@ -283,14 +286,17 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myPassExecutorService.cancelAll(true); } + @Override @NotNull public String getComponentName() { return "DaemonCodeAnalyzer"; } + @Override public void initComponent() { } + @Override public void disposeComponent() { } @@ -309,6 +315,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myFileStatusMap.markAllFilesDirty(); } + @Override public void projectClosed() { assert myInitialized : "Disposing not initialized component"; assert !myDisposed : "Double dispose"; @@ -354,6 +361,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return myScopes; } + @Override public void settingsChanged() { DaemonCodeAnalyzerSettings settings = DaemonCodeAnalyzerSettings.getInstance(); if (settings.isCodeHighlightingChanged(myLastSettings)) { @@ -362,11 +370,13 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx myLastSettings = (DaemonCodeAnalyzerSettings)settings.clone(); } + @Override public void updateVisibleHighlighters(@NotNull Editor editor) { ApplicationManager.getApplication().assertIsDispatchThread(); // no need, will not work anyway } + @Override public void setUpdateByTimerEnabled(boolean value) { myUpdateByTimerEnabled = value; stopProcess(value); @@ -376,6 +386,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return myUpdateByTimerEnabled; } + @Override public void setImportHintsEnabled(@NotNull PsiFile file, boolean value) { VirtualFile vFile = file.getVirtualFile(); if (value) { @@ -388,23 +399,27 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @Override public void resetImportHintsEnabledForProject() { myDisabledHintsFiles.clear(); } + @Override public void setHighlightingEnabled(@NotNull PsiFile file, boolean value) { + VirtualFile virtualFile = PsiUtilCore.getVirtualFile(file); if (value) { - myDisabledHighlightingFiles.remove(file); + myDisabledHighlightingFiles.remove(virtualFile); } else { - myDisabledHighlightingFiles.add(file); + myDisabledHighlightingFiles.add(virtualFile); } } + @Override public boolean isHighlightingAvailable(PsiFile file) { - if (myDisabledHighlightingFiles.contains(file)) return false; - if (file == null || !file.isPhysical()) return false; + if (myDisabledHighlightingFiles.contains(PsiUtilCore.getVirtualFile(file))) return false; + if (file instanceof PsiCompiledElement) return false; final FileType fileType = file.getFileType(); if (fileType == StdFileTypes.GUI_DESIGNER_FORM){ @@ -414,14 +429,17 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return !fileType.isBinary(); } + @Override public boolean isImportHintsEnabled(@NotNull PsiFile file) { return isAutohintsAvailable(file) && !myDisabledHintsFiles.contains(file.getVirtualFile()); } + @Override public boolean isAutohintsAvailable(PsiFile file) { return isHighlightingAvailable(file) && !(file instanceof PsiCompiledElement); } + @Override public void restart() { myFileStatusMap.markAllFilesDirty(); stopProcess(true); @@ -507,6 +525,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx final SeverityRegistrar severityRegistrar = SeverityRegistrar.getInstance(project); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOverlappingWith(startOffset, endOffset, new Processor() { + @Override public boolean process(RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; @@ -529,6 +548,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx final SeverityRegistrar severityRegistrar = SeverityRegistrar.getInstance(project); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(document, project, true); return model.processRangeHighlightersOutside(startOffset, endOffset, new Processor() { + @Override public boolean process(RangeHighlighterEx marker) { Object tt = marker.getErrorStripeTooltip(); if (!(tt instanceof HighlightInfo)) return true; @@ -548,6 +568,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx final boolean includeFixRange, @NotNull final Processor processor) { return processHighlights(document, project, null, 0, document.getTextLength(), new Processor() { + @Override public boolean process(HighlightInfo info) { if (!isOffsetInsideHighlightInfo(offset, info, includeFixRange)) return true; @@ -561,6 +582,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx public HighlightInfo findHighlightByOffset(Document document, final int offset, final boolean includeFixRange) { final List foundInfoList = new SmartList(); processHighlightsNearOffset(document, myProject, HighlightSeverity.INFORMATION, offset, includeFixRange, new Processor() { + @Override public boolean process(HighlightInfo info) { if (!foundInfoList.isEmpty()) { HighlightInfo foundInfo = foundInfoList.get(0); @@ -635,6 +657,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return myLastIntentionHint; } + @Override public void writeExternal(Element parentNode) throws WriteExternalException { Element disableHintsElement = new Element(DISABLE_HINTS_TAG); parentNode.addContent(disableHintsElement); @@ -654,6 +677,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx } } + @Override public void readExternal(Element parentNode) throws InvalidDataException { myDisabledHintsFiles.clear(); @@ -675,12 +699,14 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx private Runnable createUpdateRunnable() { return new Runnable() { + @Override public void run() { if (myDisposed || !myProject.isInitialized()) return; if (PowerSaveMode.isEnabled()) return; Editor activeEditor = FileEditorManager.getInstance(myProject).getSelectedTextEditor(); Runnable runnable = new Runnable() { + @Override public void run() { PassExecutorService.log(myUpdateProgress, null, "Update Runnable. myUpdateByTimerEnabled:",myUpdateByTimerEnabled," something disposed:",PowerSaveMode.isEnabled() || myDisposed || !myProject.isInitialized()," activeEditors:",myProject.isDisposed() ? null : myDaemonListeners.getSelectedEditors()); if (!myUpdateByTimerEnabled) return; @@ -745,6 +771,7 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzer implements JDOMEx return myDaemonListeners.canChangeFileSilently(file); } + @Override public void autoImportReferenceAtCursor(@NotNull Editor editor, @NotNull PsiFile file) { for(ReferenceImporter importer: Extensions.getExtensions(ReferenceImporter.EP_NAME)) { if (importer.autoImportReferenceAtCursor(editor, file)) break; From d3d5ef6ed6e30c6b9cd802b425436a37b1737a60 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 16 Mar 2012 18:04:19 +0400 Subject: [PATCH 8/9] cleanup --- .../ExternalAnnotationsManagerImpl.java | 68 ++++++++++++------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java index b86759580bca..8722fdfd04be 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java @@ -79,14 +79,13 @@ import java.io.IOException; import java.util.*; import java.util.List; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicReference; public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { @NotNull public static final Icon ICON = IconLoader.getIcon("/modules/annotation.png"); private static final Logger LOG = Logger.getInstance("#" + ExternalAnnotationsManagerImpl.class.getName()); @NotNull private final ConcurrentMap> myExternalAnnotations = new ConcurrentWeakValueHashMap>(); - @NotNull private final AtomicReference myHasAnyAnnotationsRoots = new AtomicReference(ThreeState.UNSURE); + @NotNull private volatile ThreeState myHasAnyAnnotationsRoots = ThreeState.UNSURE; @NotNull private static final List NULL = new ArrayList(); private final PsiManager myPsiManager; @@ -94,38 +93,42 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { myPsiManager = psiManager; final MessageBusConnection connection = project.getMessageBus().connect(project); connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() { + @Override public void beforeRootsChange(ModuleRootEvent event) { } + @Override public void rootsChanged(ModuleRootEvent event) { myExternalAnnotations.clear(); - myHasAnyAnnotationsRoots.set(ThreeState.UNSURE); + myHasAnyAnnotationsRoots = ThreeState.UNSURE; } }); } private ThreeState hasAnyAnnotationsRoots() { - if (myHasAnyAnnotationsRoots.get() == ThreeState.UNSURE) { + if (myHasAnyAnnotationsRoots == ThreeState.UNSURE) { final Module[] modules = ModuleManager.getInstance(myPsiManager.getProject()).getModules(); for (Module module : modules) { for (OrderEntry entry : ModuleRootManager.getInstance(module).getOrderEntries()) { final String[] urls = AnnotationOrderRootType.getUrls(entry); if (urls.length > 0) { - myHasAnyAnnotationsRoots.set(ThreeState.YES); + myHasAnyAnnotationsRoots = ThreeState.YES; return ThreeState.YES; } } } - myHasAnyAnnotationsRoots.set(ThreeState.NO); + myHasAnyAnnotationsRoots = ThreeState.NO; } - return myHasAnyAnnotationsRoots.get(); + return myHasAnyAnnotationsRoots; } + @Override @Nullable public PsiAnnotation findExternalAnnotation(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) { return collectExternalAnnotations(listOwner).get(annotationFQN); } + @Override @Nullable public PsiAnnotation[] findExternalAnnotations(@NotNull final PsiModifierListOwner listOwner) { final Map result = collectExternalAnnotations(listOwner); @@ -135,11 +138,11 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { @NotNull private Map collectExternalAnnotations(@NotNull final PsiModifierListOwner listOwner) { if (hasAnyAnnotationsRoots() == ThreeState.NO) return Collections.emptyMap(); - final Map result = new HashMap(); - final List files = findExternalAnnotationsFile(listOwner); + final List files = findExternalAnnotationsFiles(listOwner); if (files == null) { return Collections.emptyMap(); } + final Map result = new HashMap(); for (XmlFile file : files) { if (!file.isValid()) continue; final XmlDocument document = file.getDocument(); @@ -168,7 +171,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { "@" + annotationFQN + (buf.length() > 0 ? "(" + StringUtil.trimStart(buf.toString(), ",") + ")" : ""); try { result.put(annotationFQN, - JavaPsiFacade.getInstance(listOwner.getProject()).getElementFactory().createAnnotationFromText( + JavaPsiFacade.getInstance(myPsiManager.getProject()).getElementFactory().createAnnotationFromText( annotationText, null)); } catch (IncorrectOperationException e) { @@ -186,11 +189,12 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { } + @Override public void annotateExternally(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQName, @NotNull final PsiFile fromFile, final PsiNameValuePair[] value) { - final Project project = listOwner.getProject(); + final Project project = myPsiManager.getProject(); final PsiFile containingFile = listOwner.getContainingFile(); if (!(containingFile instanceof PsiJavaFile)) { return; @@ -215,6 +219,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { return; } SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { setupRootAndAnnotateExternally(entry, project, listOwner, annotationFQName, fromFile, packageName, virtualFile, value); } @@ -240,9 +245,10 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { return; } new WriteCommandAction(project) { + @Override protected void run(final Result result) throws Throwable { appendChosenAnnotationsRoot(entry, file); - final List xmlFiles = findExternalAnnotationsFile(listOwner); + final List xmlFiles = findExternalAnnotationsFiles(listOwner); if (xmlFiles != null) { //file already exists under appeared content root if (!CodeInsightUtilBase.preparePsiElementForWrite(xmlFiles.get(0))) return; annotateExternally(listOwner, annotationFQName, xmlFiles.get(0), fromFile, value); @@ -314,7 +320,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { @NotNull final PsiFile fromFile, final PsiNameValuePair[] value) { final XmlFile[] annotationsXml = new XmlFile[1]; - List xmlFiles = findExternalAnnotationsFile(listOwner); + List xmlFiles = findExternalAnnotationsFiles(listOwner); if (xmlFiles != null) { for (XmlFile xmlFile : xmlFiles) { final VirtualFile vXmlFile = xmlFile.getVirtualFile(); @@ -330,6 +336,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { final List annotationFiles = new ArrayList(xmlFiles); new WriteCommandAction(project) { + @Override protected void run(final Result result) throws Throwable { if (annotationsXml[0] == null) { annotationsXml[0] = createAnnotationsXml(file, packageName); @@ -343,8 +350,9 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { }.execute(); } + @Override public boolean deannotate(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) { - final List files = findExternalAnnotationsFile(listOwner); + final List files = findExternalAnnotationsFiles(listOwner); if (files != null) { for (XmlFile file : files) { if (file.isValid()) { @@ -359,7 +367,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { if (Comparing.strEqual(className, externalName) || Comparing.strEqual(className, oldExternalName)) { for (XmlTag annotationTag : tag.getSubTags()) { if (Comparing.strEqual(annotationTag.getAttributeValue("name"), annotationFQN)) { - if (ReadonlyStatusHandler.getInstance(file.getProject()) + if (ReadonlyStatusHandler.getInstance(myPsiManager.getProject()) .ensureFilesWritable(file.getVirtualFile()).hasReadonlyFiles()) { return false; } @@ -386,11 +394,12 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { return false; } + @Override @NotNull public AnnotationPlace chooseAnnotationsPlace(@NotNull final PsiElement element) { if (!element.isPhysical()) return AnnotationPlace.IN_CODE; //element just created if (!element.getManager().isInProject(element)) return AnnotationPlace.EXTERNAL; - final Project project = element.getProject(); + final Project project = myPsiManager.getProject(); final PsiFile containingFile = element.getContainingFile(); final VirtualFile virtualFile = containingFile.getVirtualFile(); LOG.assertTrue(virtualFile != null); @@ -472,7 +481,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { myExternalAnnotations.clear(); } - private static void annotateExternally(final PsiModifierListOwner listOwner, + private void annotateExternally(final PsiModifierListOwner listOwner, final String annotationFQName, @Nullable final XmlFile xmlFile, @NotNull PsiFile codeUsageFile, @@ -492,7 +501,8 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { break; } } - tag.add(XmlElementFactory.getInstance(xmlFile.getProject()).createTagFromText(createAnnotationTag(annotationFQName, values))); + tag.add(XmlElementFactory.getInstance(myPsiManager.getProject()).createTagFromText( + createAnnotationTag(annotationFQName, values))); return; } } @@ -500,7 +510,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { "\n"; text += createAnnotationTag(annotationFQName, values); text += ""; - rootTag.add(XmlElementFactory.getInstance(xmlFile.getProject()).createTagFromText(text)); + rootTag.add(XmlElementFactory.getInstance(myPsiManager.getProject()).createTagFromText(text)); } } } @@ -520,13 +530,13 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { if (values != null) { text = " \n"; text += StringUtil.join(values, new Function() { + @NonNls @NotNull @Override public String fun(@NotNull PsiNameValuePair pair) { - if (pair.getName() != null) { - return ""; - } - return ""; + return ""; } }, " \n"); text += " "; @@ -572,8 +582,8 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { } @Nullable - private List findExternalAnnotationsFile(@NotNull PsiModifierListOwner listOwner) { - final Project project = listOwner.getProject(); + private List findExternalAnnotationsFiles(@NotNull PsiModifierListOwner listOwner) { + final Project project = myPsiManager.getProject(); final PsiFile containingFile = listOwner.getContainingFile(); if (!(containingFile instanceof PsiJavaFile)) { return null; @@ -672,15 +682,18 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { init(); } + @Override protected String getOkActionName() { return ADD_IN_CODE; } + @Override @NotNull protected String getCancelActionName() { return CommonBundle.getCancelButtonText(); } + @Override @NotNull @SuppressWarnings({"NonStaticInitializer"}) protected Action[] createActions() { @@ -692,6 +705,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { assignMnemonic(externalName, this); } + @Override public void actionPerformed(final ActionEvent e) { if (canBeHidden()) { setToBeShown(toBeShown(), true); @@ -701,20 +715,24 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { }, getCancelAction()}; } + @Override protected boolean isToBeShown() { return CodeStyleSettingsManager.getSettings(myProject).USE_EXTERNAL_ANNOTATIONS; } + @Override protected void setToBeShown(boolean value, boolean onOk) { CodeStyleSettingsManager.getSettings(myProject).USE_EXTERNAL_ANNOTATIONS = value; } + @Override protected JComponent createNorthPanel() { final JPanel northPanel = (JPanel)super.createNorthPanel(); northPanel.add(new JLabel(MESSAGE), BorderLayout.CENTER); return northPanel; } + @Override protected boolean shouldSaveOptionsOnCancel() { return true; } From db49adf62343537ec4a1d8c2f378ae35a15783af Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 19 Mar 2012 10:16:45 +0100 Subject: [PATCH 9/9] IDEA-83009 (Exception without arguments false positive: shouldn't trigger on exception classes with no visible constructors) --- .../siyeh/InspectionGadgetsBundle.properties | 1 + ...ewExceptionWithoutArgumentsInspection.java | 45 +++++++++++++++---- .../NewExceptionWithoutArguments.html | 6 ++- .../NewExceptionWithoutArguments.java | 16 +++++++ .../expected.xml | 11 +++++ ...ceptionWithoutArgumentsInspectionTest.java | 13 ++++++ 6 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/NewExceptionWithoutArguments.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/expected.xml create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspectionTest.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index a1a6f8eab86d..adc47a6ce812 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1960,6 +1960,7 @@ unclear.binary.expression.problem.descriptor=Expression could use clarifying par unclear.binary.expression.quickfix=Add clarifying parentheses new.exception.without.arguments.display.name=Exception constructor called without arguments new.exception.without.arguments.problem.descriptor=new #ref() without arguments #loc +new.exception.without.arguments.ignore.option=Ignore for exceptions that have no constructors with parameters absolute.alignment.in.user.interface.display.name=Absolute alignment used in AWT/Swing code absolute.alignment.in.user.interface.problem.descriptor=Absolute alignment constant {0}.#ref used #loc absolute.alignment.in.user.interface.quickfix=Replace with ''{0}.{1}'' diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspection.java index b6453a340e03..7355df374b26 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspection.java @@ -15,14 +15,22 @@ */ package com.siyeh.ig.errorhandling; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.siyeh.InspectionGadgetsBundle;import com.siyeh.ig.BaseInspection; +import com.intellij.psi.util.InheritanceUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import javax.swing.*; + public class NewExceptionWithoutArgumentsInspection extends BaseInspection { + + @SuppressWarnings("PublicField") + public boolean ignoreWithoutParameters = false; + @Nls @NotNull @Override @@ -36,12 +44,18 @@ public class NewExceptionWithoutArgumentsInspection extends BaseInspection { return InspectionGadgetsBundle.message("new.exception.without.arguments.problem.descriptor"); } + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message("new.exception.without.arguments.ignore.option"), this, + "ignoreWithoutParameters"); + } + @Override public BaseInspectionVisitor buildVisitor() { return new NewExceptionWithoutArgumentsVisitor(); } - private static class NewExceptionWithoutArgumentsVisitor extends BaseInspectionVisitor { + private class NewExceptionWithoutArgumentsVisitor extends BaseInspectionVisitor { @Override public void visitNewExpression(PsiNewExpression expression) { @@ -63,16 +77,29 @@ public class NewExceptionWithoutArgumentsInspection extends BaseInspection { return; } final PsiClass aClass = (PsiClass)target; - final GlobalSearchScope resolveScope = expression.getResolveScope(); - final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(expression.getProject()); - final PsiClass exceptionClass = psiFacade.findClass(CommonClassNames.JAVA_LANG_EXCEPTION, resolveScope); - if (exceptionClass == null) { + if (!InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_LANG_EXCEPTION)) { return; } - if (!aClass.isInheritor(exceptionClass, true)) { - return; + if (ignoreWithoutParameters) { + if (!hasAccessibleConstructorWithParameters(aClass, expression)) return; } registerNewExpressionError(expression); } + + private boolean hasAccessibleConstructorWithParameters(PsiClass aClass, PsiElement context) { + final PsiMethod[] constructors = aClass.getConstructors(); + for (PsiMethod constructor : constructors) { + final PsiParameterList parameterList = constructor.getParameterList(); + final int count = parameterList.getParametersCount(); + if (count <= 0) { + continue; + } + final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper(); + if (resolveHelper.isAccessible(constructor, context, aClass)) { + return true; + } + } + return false; + } } } diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NewExceptionWithoutArguments.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NewExceptionWithoutArguments.html index dd38673c63b7..5ce387634751 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/NewExceptionWithoutArguments.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NewExceptionWithoutArguments.html @@ -1,7 +1,9 @@ -This inspection reports construction of exceptions without arguments. When an exception is constructed without arguments it contains no -information about the fault that happened, which makes debugging needlessly hard. +This inspection reports exception instance creation without any arguments specified. When an exception is constructed +without arguments it contains no information about the fault that happened, which makes debugging needlessly hard. +

+Use the checkbox below to ignore instance creation of exception classes which have no constructors that take arguments.

New in 11, Powered by InspectionGadgets diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/NewExceptionWithoutArguments.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/NewExceptionWithoutArguments.java new file mode 100644 index 000000000000..f563cab3b3c1 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/NewExceptionWithoutArguments.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.errorhandling.new_exception_without_arguments; + +class NewExceptionWithoutArguments { + + void foo() { + throw new RuntimeException(); + } + + void bar() { + throw new MyException(); + } + +} +class MyException extends RuntimeException { + +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/expected.xml new file mode 100644 index 000000000000..3d60c6a05598 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/errorhandling/new_exception_without_arguments/expected.xml @@ -0,0 +1,11 @@ + + + + + NewExceptionWithoutArguments.java + 6 + Exception constructor called without arguments + <code>new RuntimeException()</code> without arguments #loc + + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspectionTest.java new file mode 100644 index 000000000000..fbd585cddfc8 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/errorhandling/NewExceptionWithoutArgumentsInspectionTest.java @@ -0,0 +1,13 @@ +package com.siyeh.ig.errorhandling; + +import com.siyeh.ig.IGInspectionTestCase; + +public class NewExceptionWithoutArgumentsInspectionTest extends IGInspectionTestCase { + + public void test() throws Exception { + final NewExceptionWithoutArgumentsInspection tool = new NewExceptionWithoutArgumentsInspection(); + tool.ignoreWithoutParameters = true; + doTest("com/siyeh/igtest/errorhandling/new_exception_without_arguments", tool); + } + +}