From 533686a01ab1b3de45262e77fdc20400842cf1ba Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Tue, 11 Sep 2012 13:25:59 +0200 Subject: [PATCH 01/17] recreate content of project/module files if it was truncated to 0 size (PY-7543) --- .../impl/stores/FileBasedStorage.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java index e025f0305978..14d4a8172d73 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java @@ -256,6 +256,9 @@ public class FileBasedStorage extends XmlElementStorage { LOG.info("Document was not loaded for " + myFileSpec + " file is " + (file == null ? "null" : "directory")); return null; } + else if (file.getLength() == 0) { + return processReadException(null); + } else { return loadDocumentImpl(file); } @@ -269,12 +272,15 @@ public class FileBasedStorage extends XmlElementStorage { } @Nullable - private Document processReadException(final Exception e) { - myBlockSavingTheContent = isProjectOrModuleFile(); + private Document processReadException(@Nullable final Exception e) { + boolean contentTruncated = e == null; + myBlockSavingTheContent = isProjectOrModuleFile() && !contentTruncated; if (!ApplicationManager.getApplication().isUnitTestMode() && !ApplicationManager.getApplication().isHeadlessEnvironment()) { - LOG.info(e); - final String message = "Cannot load settings from file '" + myFile.getPath() + "': " + e.getLocalizedMessage() + "\n" + - getInvalidContentMessage(); + if (e != null) { + LOG.info(e); + } + final String message = "Cannot load settings from file '" + myFile.getPath() + "': " + (e == null ? "content truncated" : e.getLocalizedMessage()) + "\n" + + getInvalidContentMessage(contentTruncated); Notifications.Bus.notify( new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "Load Settings", message, NotificationType.WARNING)); } @@ -286,8 +292,8 @@ public class FileBasedStorage extends XmlElementStorage { return myIsProjectSettings || myFileSpec.equals("$MODULE_FILE$"); } - private String getInvalidContentMessage() { - return isProjectOrModuleFile() ? "Please correct the file content" : "File content will be recreated"; + private String getInvalidContentMessage(boolean contentTruncated) { + return isProjectOrModuleFile() && !contentTruncated ? "Please correct the file content" : "File content will be recreated"; } private static Document loadDocumentImpl(final VirtualFile file) throws IOException, JDOMException { From 98d9a90f7fd4d534df6481365bacb90d00fe5524 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 11 Sep 2012 19:26:23 +0400 Subject: [PATCH 02/17] IDEA-91365 'Open task' dropdown only drops down once --- .../intellij/tasks/actions/SwitchTaskAction.java | 14 ++++++++++++-- .../intellij/tasks/actions/SwitchTaskCombo.java | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskAction.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskAction.java index 857e49ace87c..f2954c5b2b26 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskAction.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskAction.java @@ -17,10 +17,12 @@ package com.intellij.tasks.actions; import com.intellij.ide.DataManager; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.*; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.LocalChangeList; @@ -52,11 +54,11 @@ public class SwitchTaskAction extends BaseTaskAction { DataContext dataContext = e.getDataContext(); final Project project = PlatformDataKeys.PROJECT.getData(dataContext); assert project != null; - final ListPopupImpl popup = createPopup(dataContext, true); + final ListPopupImpl popup = createPopup(dataContext, null, true); popup.showCenteredInCurrentWindow(project); } - public static ListPopupImpl createPopup(final DataContext dataContext, boolean withTitle) { + public static ListPopupImpl createPopup(final DataContext dataContext, @Nullable final Runnable onDispose, boolean withTitle) { final Project project = PlatformDataKeys.PROJECT.getData(dataContext); final Ref shiftPressed = Ref.create(false); final Ref componentRef = Ref.create(); @@ -98,6 +100,14 @@ public class SwitchTaskAction extends BaseTaskAction { }; final ListPopupImpl popup = (ListPopupImpl)JBPopupFactory.getInstance().createListPopup(step); + if (onDispose != null) { + Disposer.register(popup, new Disposable() { + @Override + public void dispose() { + onDispose.run(); + } + }); + } componentRef.set(popup.getComponent()); if (items.size() <= 2) { return popup; diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java index a975a0e52e68..300981ef56ea 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java @@ -66,7 +66,7 @@ public class SwitchTaskCombo extends ComboBoxAction implements DumbAware { @Override protected JBPopup createPopup(Runnable onDispose) { - return SwitchTaskAction.createPopup(DataManager.getInstance().getDataContext(this), false); + return SwitchTaskAction.createPopup(DataManager.getInstance().getDataContext(this), onDispose, false); } }; } From 2092fb60b465f78c897bc1ba32a18335ba236a44 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 11 Sep 2012 11:57:22 +0400 Subject: [PATCH 03/17] Cleanup --- .../openapi/vfs/VirtualFileManager.java | 36 +++++++++---------- .../intellij/openapi/vfs/LocalFileSystem.java | 1 - .../vfs/impl/local/LocalFileSystemImpl.java | 1 - 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileManager.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileManager.java index ef25cece390e..b13f019c2e98 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileManager.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,14 +25,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * Manages virtual file systems + * Manages virtual file systems. * * @see VirtualFileSystem - * @see LocalFileSystem - * @see JarFileSystem */ -public abstract class VirtualFileManager implements ModificationTracker{ - public static final Topic VFS_CHANGES = new Topic("NewVirtualFileSystem changes", BulkFileListener.class); +public abstract class VirtualFileManager implements ModificationTracker { + public static final Topic VFS_CHANGES = + new Topic("NewVirtualFileSystem changes", BulkFileListener.class); /** * Gets the instance of VirtualFileManager. @@ -40,7 +39,7 @@ public abstract class VirtualFileManager implements ModificationTracker{ * @return VirtualFileManager */ @NotNull - public static VirtualFileManager getInstance(){ + public static VirtualFileManager getInstance() { return ApplicationManager.getApplication().getComponent(VirtualFileManager.class); } @@ -55,12 +54,12 @@ public abstract class VirtualFileManager implements ModificationTracker{ /** * Refreshes the cached file system information from the physical file system. - *

+ *

* This method should be only called within write-action. * See {@link com.intellij.openapi.application.Application#runWriteAction}. * * @param asynchronous if true then the operation will be performed in a separate thread, - * otherwise will be performed immediately + * otherwise will be performed immediately */ public abstract void refresh(boolean asynchronous); @@ -88,14 +87,14 @@ public abstract class VirtualFileManager implements ModificationTracker{ /** * Refreshes only the part of the file system needed for searching the file by the given URL and finds file * by the given URL.
- * + *

* This method is useful when the file was created externally and you need to find {@link VirtualFile} * corresponding to it.

- * + *

* This method should be only called within write-action. * See {@link com.intellij.openapi.application.Application#runWriteAction}. * - * @param url the URL + * @param url the URL * @return {@link VirtualFile} if the file was found, null otherwise * @see VirtualFileSystem#findFileByPath * @see VirtualFileSystem#refreshAndFindFileByPath @@ -106,7 +105,7 @@ public abstract class VirtualFileManager implements ModificationTracker{ /** * Adds listener to the file system. * - * @param listener the listener + * @param listener the listener * @see VirtualFileListener */ public abstract void addVirtualFileListener(@NotNull VirtualFileListener listener); @@ -116,7 +115,7 @@ public abstract class VirtualFileManager implements ModificationTracker{ /** * Removes listener form the file system. * - * @param listener the listener + * @param listener the listener */ public abstract void removeVirtualFileListener(@NotNull VirtualFileListener listener); @@ -125,11 +124,11 @@ public abstract class VirtualFileManager implements ModificationTracker{ * file systems. * * @param protocol the protocol - * @param path the path + * @param path the path * @return URL */ @NotNull - public static String constructUrl(@NotNull String protocol, @NotNull String path){ + public static String constructUrl(@NotNull String protocol, @NotNull String path) { return protocol + "://" + path; } @@ -141,7 +140,7 @@ public abstract class VirtualFileManager implements ModificationTracker{ * @see VirtualFileSystem#getProtocol */ @Nullable - public static String extractProtocol(@NotNull String url){ + public static String extractProtocol(@NotNull String url) { int index = url.indexOf("://"); if (index < 0) return null; return url.substring(0, index); @@ -155,13 +154,14 @@ public abstract class VirtualFileManager implements ModificationTracker{ * @return path */ @NotNull - public static String extractPath(@NotNull String url){ + public static String extractPath(@NotNull String url) { int index = url.indexOf("://"); if (index < 0) return url; return url.substring(index + "://".length()); } public abstract void addVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener); + public abstract void addVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener, @NotNull Disposable parentDisposable); public abstract void removeVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener); diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/LocalFileSystem.java b/platform/platform-api/src/com/intellij/openapi/vfs/LocalFileSystem.java index f51427ad4718..8fedd7a80e6e 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/LocalFileSystem.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/LocalFileSystem.java @@ -130,7 +130,6 @@ public abstract class LocalFileSystem extends NewVirtualFileSystem { /** @deprecated implementation details (to remove in IDEA 13) */ @SuppressWarnings({"UnusedDeclaration"}) - @NotNull String getFileSystemRootPath(); /** @deprecated implementation details (to remove in IDEA 13) */ diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemImpl.java index 22feebe11af3..edb25b41e47a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemImpl.java @@ -83,7 +83,6 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap /** @deprecated implementation details (to remove in IDEA 13) */ @Override - @NotNull public String getFileSystemRootPath() { return myFSRootPath; } From 4cbe87de0207ce6b17f6dc15b0e5f162da687170 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 11 Sep 2012 17:25:13 +0400 Subject: [PATCH 04/17] Highlight misplaced reference parameter lists --- .../impl/analysis/GenericsHighlightUtil.java | 46 +++++++---- .../impl/analysis/HighlightVisitorImpl.java | 9 ++- .../projectRoots/JavaVersionServiceImpl.java | 13 +++- .../src/messages/JavaErrorMessages.properties | 4 +- .../genericsHighlighting/Fields.java | 10 +++ .../daemon/GenericsHighlightingTest.java | 77 +++++++++++-------- 6 files changed, 102 insertions(+), 57 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/Fields.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index c1564f92743d..2f0c71494d01 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -51,11 +51,12 @@ import java.util.*; */ public class GenericsHighlightUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.analysis.GenericsHighlightUtil"); + private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance(); - private GenericsHighlightUtil() { - } + private GenericsHighlightUtil() { } + @Nullable public static HighlightInfo checkInferredTypeArguments(PsiMethod genericMethod, PsiMethodCallExpression call, PsiSubstitutor substitutor) { @@ -67,7 +68,8 @@ public class GenericsHighlightUtil { PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes(); for (PsiClassType type : extendsTypes) { PsiType extendsType = substitutor.substitute(type); - if (substituted instanceof PsiWildcardType && TypeConversionUtil.erasure(extendsType).equals(TypeConversionUtil.erasure(((PsiWildcardType)substituted).getExtendsBound()))) { + if (substituted instanceof PsiWildcardType && + TypeConversionUtil.erasure(extendsType).equals(TypeConversionUtil.erasure(((PsiWildcardType)substituted).getExtendsBound()))) { PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound(); if (extendsBound instanceof PsiClassType) { PsiType[] parameters = ((PsiClassType)extendsBound).getParameters(); @@ -103,7 +105,7 @@ public class GenericsHighlightUtil { } @Nullable - public static HighlightInfo checkParameterizedReferenceTypeArguments(PsiElement resolved, + public static HighlightInfo checkParameterizedReferenceTypeArguments(final PsiElement resolved, final PsiJavaCodeReferenceElement referenceElement, final PsiSubstitutor substitutor) { if (!(resolved instanceof PsiTypeParameterListOwner)) return null; @@ -116,18 +118,14 @@ public class GenericsHighlightUtil { final PsiReferenceParameterList referenceParameterList, final PsiSubstitutor substitutor, boolean registerIntentions) { - if (referenceParameterList != null) { - HighlightInfo info = HighlightUtil.checkGenericsFeature(referenceParameterList, referenceParameterList.getTypeParameterElements().length); - if (info != null) return info; - } - PsiDiamondType.DiamondInferenceResult inferenceResult = null; PsiTypeElement[] referenceElements = null; if (referenceParameterList != null) { referenceElements = referenceParameterList.getTypeParameterElements(); if (referenceElements.length == 1 && referenceElements[0].getType() instanceof PsiDiamondType) { if (!typeParameterListOwner.hasTypeParameters()) { - return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElements[0], "Diamond operator is not applicable for non-parameterized types"); + final String description = JavaErrorMessages.message("generics.diamond.not.applicable"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElements[0], description); } inferenceResult = ((PsiDiamondType)referenceElements[0].getType()).resolveInferredTypes(); final String errorMessage = inferenceResult.getErrorMessage(); @@ -165,9 +163,9 @@ public class GenericsHighlightUtil { if (description != null) { final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceParameterList, description); if (registerIntentions) { - PsiElement pparent = referenceParameterList.getParent().getParent(); - if (pparent instanceof PsiTypeElement) { - PsiElement variable = pparent.getParent(); + PsiElement grandParent = referenceParameterList.getParent().getParent(); + if (grandParent instanceof PsiTypeElement) { + PsiElement variable = grandParent.getParent(); if (variable instanceof PsiVariable) { if (targetParametersNum == 0) { QuickFixAction.registerQuickFixAction(highlightInfo, new RemoveTypeArgumentsFix(variable)); @@ -1029,7 +1027,7 @@ public class GenericsHighlightUtil { MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst(); if (superMethod == null) { HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, overrideAnnotation, - JavaErrorMessages.message("method.doesnot.override.super")); + JavaErrorMessages.message("method.does.not.override.super")); PullAsAbstractUpFix.registerQuickFix(highlightInfo, method); return highlightInfo; } @@ -1245,6 +1243,26 @@ public class GenericsHighlightUtil { return list; } + @Nullable + public static HighlightInfo checkParametersAllowed(PsiReferenceParameterList refParamList) { + HighlightInfo info = HighlightUtil.checkGenericsFeature(refParamList, refParamList.getTypeParameterElements().length); + if (info != null) return info; + + if (refParamList.getTextLength() != 0) { + final PsiElement parent = refParamList.getParent(); + if (parent instanceof PsiReferenceExpression) { + final PsiElement grandParent = parent.getParent(); + if (!(grandParent instanceof PsiMethodCallExpression)) { + final String message = JavaErrorMessages.message("generics.reference.parameters.not.allowed"); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, refParamList, message); + } + } + } + + return null; + } + + @Nullable public static HighlightInfo checkParametersOnRaw(PsiReferenceParameterList refParamList) { if (refParamList.getTypeArguments().length == 0) return null; JavaResolveResult resolveResult = 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 3dc1cb631d88..8efd04e45da3 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 @@ -982,16 +982,17 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } - @Override public void visitReferenceParameterList(PsiReferenceParameterList list) { - myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list)); + @Override + public void visitReferenceParameterList(PsiReferenceParameterList list) { + myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list)); + if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list)); } @Override public void visitReturnStatement(PsiReturnStatement statement) { try { myHolder.add(HighlightUtil.checkReturnStatementType(statement)); } - catch (IndexNotReadyException ignore) { - } + catch (IndexNotReadyException ignore) { } } @Override public void visitStatement(PsiStatement statement) { diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/JavaVersionServiceImpl.java b/java/java-impl/src/com/intellij/openapi/projectRoots/JavaVersionServiceImpl.java index 6a32170dd12a..675da490028b 100644 --- a/java/java-impl/src/com/intellij/openapi/projectRoots/JavaVersionServiceImpl.java +++ b/java/java-impl/src/com/intellij/openapi/projectRoots/JavaVersionServiceImpl.java @@ -17,21 +17,26 @@ package com.intellij.openapi.projectRoots; import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; /** - * User: anna - * Date: 3/28/12 + * @author anna + * @since 3/28/12 */ public class JavaVersionServiceImpl extends JavaVersionService { private JavaSdkVersion myTestVersion = null; - public void setTestVersion(JavaSdkVersion testVersion) { + @TestOnly + public void setTestVersion(@Nullable JavaSdkVersion testVersion) { myTestVersion = testVersion; } @Override public boolean isAtLeast(PsiElement element, JavaSdkVersion version) { - if (ApplicationManager.getApplication().isUnitTestMode()) return myTestVersion != null && myTestVersion.isAtLeast(version); + if (ApplicationManager.getApplication().isUnitTestMode()) { + return myTestVersion != null && myTestVersion.isAtLeast(version); + } return JavaSdkVersionUtil.isAtLeast(element, version); } } diff --git a/java/java-psi-impl/src/messages/JavaErrorMessages.properties b/java/java-psi-impl/src/messages/JavaErrorMessages.properties index f74c309f2cc4..597334998586 100644 --- a/java/java-psi-impl/src/messages/JavaErrorMessages.properties +++ b/java/java-psi-impl/src/messages/JavaErrorMessages.properties @@ -62,6 +62,8 @@ generics.type.argument.cannot.be.of.primitive.type=Type argument cannot be of pr generics.unchecked.assignment=Unchecked assignment: ''{0}'' to ''{1}'' generics.unchecked.cast=Unchecked cast: ''{0}'' to ''{1}'' generics.unchecked.call.to.member.of.raw.type=Unchecked call to ''{0}'' as a member of raw type ''{1}'' +generics.diamond.not.applicable=Diamond operator is not applicable for non-parameterized types +generics.reference.parameters.not.allowed=Reference parameters are not allowed here foreach.not.applicable=foreach not applicable to type ''{0}''. illegal.to.access.static.member.from.enum.constructor.or.instance.initializer=It is illegal to access static member ''{0}'' from enum constructor or instance initializer enum.types.cannot.be.instantiated=Enum types cannot be instantiated @@ -74,7 +76,7 @@ generics.cannot.catch.type.parameters=Cannot catch type parameters generics.cannot.instanceof.type.parameters=Class or array expected illegal.generic.type.for.instanceof=Illegal generic type for instanceof cannot.select.dot.class.from.type.variable=Cannot select from a type variable -method.doesnot.override.super=Method does not override method from its superclass +method.does.not.override.super=Method does not override method from its superclass call.to.super.is.not.allowed.in.enum.constructor=Call to super is not allowed in enum constructor vararg.not.last.parameter=Vararg parameter must be the last in the list modifiers.for.enum.constants=No modifiers allowed for enum constants diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/Fields.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/Fields.java new file mode 100644 index 000000000000..168e4e718115 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/Fields.java @@ -0,0 +1,10 @@ +import java.util.*; + +class C { + static final List EMPTY = new ArrayList(0); + + void m() { + List list = C.EMPTY; + System.out.println(list); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java index 191c956e498d..06941dbb4cba 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.intellij.codeInsight.daemon; import com.intellij.codeInspection.LocalInspectionTool; @@ -62,33 +77,30 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testExceptions() throws Exception { doTest(false); } public void testExplicitMethodParameters() throws Exception { doTest(false); } public void testExplicitMethodParameters1() throws Exception { doTest(false); } - public void testInferenceWithBounds() throws Exception {doTest(false);} - public void testInferenceWithSuperBounds() throws Exception {doTest(false);} - public void testInferenceWithUpperBoundPromotion() throws Exception {doTest(false);} - public void testVariance() throws Exception {doTest(false);} - public void testForeachTypes() throws Exception {doTest(false);} - public void testRawOverridingMethods() throws Exception {doTest(false);} - public void testAutoboxing() throws Exception {doTest(false);} - public void testAutoboxingMethods() throws Exception {doTest(false);} - public void testAutoboxingConstructors() throws Exception {doTest(false);} + public void testInferenceWithBounds() throws Exception { doTest(false); } + public void testInferenceWithSuperBounds() throws Exception { doTest(false); } + public void testInferenceWithUpperBoundPromotion() throws Exception { doTest(false); } + public void testVariance() throws Exception { doTest(false); } + public void testForeachTypes() throws Exception { doTest(false); } + public void testRawOverridingMethods() throws Exception { doTest(false); } + public void testAutoboxing() throws Exception { doTest(false); } + public void testAutoboxingMethods() throws Exception { doTest(false); } + public void testAutoboxingConstructors() throws Exception { doTest(false); } public void testEnumWithAbstractMethods() throws Exception { doTest(false); } public void testEnum() throws Exception { doTest(false); } public void testSameErasure() throws Exception { doTest(false); } - public void testMethods() throws Exception { doTest(false); } + public void testFields() throws Exception { doTest(false); } public void testStaticImports() throws Exception { doTest(true); } public void testUncheckedCasts() throws Exception { doTest(true); } public void testUncheckedOverriding() throws Exception { doTest(true); } public void testWildcardTypes() throws Exception { doTest(true); } public void testConvertibleTypes() throws Exception { doTest(true); } - public void testIntersectionTypes() throws Exception { doTest(true); } public void testVarargs() throws Exception { doTest(true); } public void testTypeArgsOnRaw() throws Exception { doTest(false); } public void testConditionalExpression() throws Exception { doTest(false); } - public void testUnused() throws Exception { doTest(true); } - public void testIDEADEV7337() throws Exception { doTest(true); } public void testIDEADEV10459() throws Exception { doTest(true); } public void testIDEADEV12951() throws Exception { doTest(true); } @@ -101,7 +113,6 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testIDEADEV25778() throws Exception { doTest(true); } public void testIDEADEV57343() throws Exception { doTest(false); } public void testSOE() throws Exception { doTest(true); } - public void testGenericExtendException() throws Exception { doTest(false); } public void testSameErasureDifferentReturnTypes() throws Exception { doTest17Incompatibility(); } public void testSameErasureDifferentReturnTypesJdk14() throws Exception { doTest(false); } @@ -118,27 +129,25 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testInnerClassRef() throws Exception { doTest(false); } public void testPrivateInnerClassRef() throws Exception { doTest(false); } public void testWideningCastToTypeParam() throws Exception { doTest(false); } - public void testCapturedWildcardAssignments() throws Exception { doTest(false);} + public void testCapturedWildcardAssignments() throws Exception { doTest(false); } public void testTypeParameterBoundVisibility() throws Exception { doTest17Incompatibility(); } - public void testTypeParameterBoundVisibilityJdk14() throws Exception { doTest(false);} - - public void testUncheckedWarningsLevel6() throws Exception { doTest(true);} - public void testIDEA77991() throws Exception { doTest(false);} - public void testIDEA80386() throws Exception { doTest(false);} - - public void testIDEA66311() throws Exception { doTest17Incompatibility();} - public void testIDEA88895() throws Exception { doTest17Incompatibility();} - public void testIDEA66311_16() throws Exception { doTest(false);} - public void testIDEA76283() throws Exception {doTest(false);} - public void testIDEA74899() throws Exception {doTest(false);} - public void testIDEA63291() throws Exception {doTest(false);} - public void testIDEA72912() throws Exception {doTest(false);} - public void testIllegalGenericTypeInInstanceof() throws Exception {doTest(false);} - public void testIDEA57339() throws Exception {doTest(false);} - public void testIDEA57340() throws Exception {doTest(false);} - public void testIDEA89771() throws Exception {doTest(false);} - public void testIDEA89801() throws Exception {doTest(false);} - public void testInconvertibleTypes() throws Exception {doTest(false);} + public void testTypeParameterBoundVisibilityJdk14() throws Exception { doTest(false); } + public void testUncheckedWarningsLevel6() throws Exception { doTest(true); } + public void testIDEA77991() throws Exception { doTest(false); } + public void testIDEA80386() throws Exception { doTest(false); } + public void testIDEA66311() throws Exception { doTest17Incompatibility(); } + public void testIDEA88895() throws Exception { doTest17Incompatibility(); } + public void testIDEA66311_16() throws Exception { doTest(false); } + public void testIDEA76283() throws Exception { doTest(false); } + public void testIDEA74899() throws Exception { doTest(false); } + public void testIDEA63291() throws Exception { doTest(false); } + public void testIDEA72912() throws Exception { doTest(false); } + public void testIllegalGenericTypeInInstanceof() throws Exception { doTest(false); } + public void testIDEA57339() throws Exception { doTest(false); } + public void testIDEA57340() throws Exception { doTest(false); } + public void testIDEA89771() throws Exception { doTest(false); } + public void testIDEA89801() throws Exception { doTest(false); } + public void testInconvertibleTypes() throws Exception { doTest(false); } public void testJavaUtilCollections_NoVerify() throws Exception { PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule())); From 2415da14684503e1f8a0e498ab9230d8ab6c735f Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 11 Sep 2012 18:31:33 +0400 Subject: [PATCH 05/17] Duplicate logging dropped; cleanup --- .../openapi/components/impl/stores/XmlElementStorage.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java index 700c9e97f943..9433a6bba8d2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java @@ -163,9 +163,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { if (document != null) { loadState(result, document.getRootElement()); } - else { - LOG.info("Document was not loaded for " + myFileSpec); - } if (!myIsProjectSettings && useProvidersData) { for (RoamingType roamingType : RoamingType.values()) { @@ -173,11 +170,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { try { if (myStreamProvider.isEnabled()) { final Document sharedDocument = StorageUtil.loadDocument(myStreamProvider.loadContent(myFileSpec, roamingType)); - if (sharedDocument != null) { filterComponentsDisabledForRoaming(sharedDocument.getRootElement(), roamingType); filterOutOfDateComponents(sharedDocument.getRootElement()); - loadState(result, sharedDocument.getRootElement()); } } @@ -186,11 +181,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable { LOG.warn(e); } } - } } - return result; } From 03c3ce3d686fd984bb240d2d01054a5efca53449 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 11 Sep 2012 17:41:33 +0200 Subject: [PATCH 06/17] IDEA-91011 (Cast to concrete class shall have an option to ignore equals() method) --- .../siyeh/InspectionGadgetsBundle.properties | 1 + .../CastToConcreteClassInspection.java | 89 ++++++++++++------- .../ig/abstraction/ConcreteClassUtil.java | 25 +++--- .../CastToConcreteClass.html | 4 +- .../CastToConcreteClass.java | 23 +++++ .../cast_to_concrete_class/expected.xml | 23 +++++ .../CastToConcreteClassInspectionTest.java | 12 +++ 7 files changed, 131 insertions(+), 46 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/cast_to_concrete_class/CastToConcreteClass.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/cast_to_concrete_class/expected.xml create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/abstraction/CastToConcreteClassInspectionTest.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 9de82e4a9d56..5b20b359f9ea 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1932,6 +1932,7 @@ simplifiable.equals.expression.display.name=Unnecessary 'null' check before 'equ simplifiable.equals.expression.problem.descriptor=Unnecessary ''null'' check before ''{0}()'' call #loc simplifiable.equals.expression.quickfix=Flip ''.{0}()'' and remove unnecessary ''null'' check cast.to.concrete.class.option=Ignore casts to an abstract class type +cast.to.concrete.class.ignore.equals.option=Ignore in equals() instanceof.interfaces.option=Ignore instanceof abstract class instance.variable.of.concrete.class.option=Ignore instance fields whose type is an abstract class local.variable.of.concrete.class.option=Ignore local variables whose type is an abstract class diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java index 75e19fed6b7d..345a6e19c47a 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/CastToConcreteClassInspection.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. @@ -15,43 +15,45 @@ */ package com.siyeh.ig.abstraction; -import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; +import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.MethodUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import javax.swing.JComponent; +import javax.swing.*; public class CastToConcreteClassInspection extends BaseInspection { @SuppressWarnings("PublicField") public boolean ignoreAbstractClasses = false; + @SuppressWarnings("PublicField") + public boolean ignoreInEquals = true; + @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "cast.to.concrete.class.display.name"); + return InspectionGadgetsBundle.message("cast.to.concrete.class.display.name"); } @Override @NotNull protected String buildErrorString(Object... infos) { - final PsiElement typeElement = (PsiElement)infos[0]; - return InspectionGadgetsBundle.message( - "cast.to.concrete.class.problem.descriptor", - typeElement.getText()); + final PsiType type= (PsiType)infos[0]; + return InspectionGadgetsBundle.message("cast.to.concrete.class.problem.descriptor", type.getPresentableText()); } @Override public JComponent createOptionsPanel() { - return new SingleCheckboxOptionsPanel( - InspectionGadgetsBundle.message( - "cast.to.concrete.class.option"), - this, "ignoreAbstractClasses"); + final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this); + panel.addCheckbox(InspectionGadgetsBundle.message("cast.to.concrete.class.option"), "ignoreAbstractClasses"); + panel.addCheckbox(InspectionGadgetsBundle.message("cast.to.concrete.class.ignore.equals.option"), "ignoreInEquals"); + return panel; } @Override @@ -59,49 +61,68 @@ public class CastToConcreteClassInspection extends BaseInspection { return new CastToConcreteClassVisitor(); } - private class CastToConcreteClassVisitor - extends BaseInspectionVisitor { + private class CastToConcreteClassVisitor extends BaseInspectionVisitor { @Override - public void visitTypeCastExpression( - @NotNull PsiTypeCastExpression expression) { + public void visitTypeCastExpression(@NotNull PsiTypeCastExpression expression) { super.visitTypeCastExpression(expression); final PsiTypeElement typeElement = expression.getCastType(); if (typeElement == null) { return; } - if (!ConcreteClassUtil.typeIsConcreteClass(typeElement, - ignoreAbstractClasses)) { + if (!ConcreteClassUtil.typeIsConcreteClass(typeElement, ignoreAbstractClasses)) { return; } - registerError(typeElement, typeElement); + if (ignoreInEquals) { + final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, true, PsiClass.class); + if (MethodUtils.isEquals(method)) { + return; + } + } + registerError(typeElement, typeElement.getType()); } @Override - public void visitMethodCallExpression( - PsiMethodCallExpression expression) { + public void visitMethodCallExpression(PsiMethodCallExpression expression) { super.visitMethodCallExpression(expression); - final PsiReferenceExpression methodExpression = - expression.getMethodExpression(); + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); @NonNls final String referenceName = methodExpression.getReferenceName(); if (!"cast".equals(referenceName)) { return; } - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); - if (!(qualifier instanceof PsiClassObjectAccessExpression)) { + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { return; } - final PsiClassObjectAccessExpression classObjectAccessExpression = - (PsiClassObjectAccessExpression)qualifier; - final PsiTypeElement operand = - classObjectAccessExpression.getOperand(); - if (!ConcreteClassUtil.typeIsConcreteClass(operand, - ignoreAbstractClasses)) { + final PsiType type = qualifier.getType(); + if (!(type instanceof PsiClassType)) { return; } - registerMethodCallError(expression, operand); + final PsiClassType classType = (PsiClassType)type; + final PsiClass aClass = classType.resolve(); + if (aClass == null) { + return; + } + final String className = aClass.getQualifiedName(); + if (!CommonClassNames.JAVA_LANG_CLASS.equals(className)) { + return; + } + final PsiType[] parameters = classType.getParameters(); + if (parameters.length != 1) { + return; + } + final PsiType parameter = parameters[0]; + if (!ConcreteClassUtil.typeIsConcreteClass(parameter, ignoreAbstractClasses)) { + return; + } + if (ignoreInEquals) { + final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, true, PsiClass.class); + if (MethodUtils.isEquals(method)) { + return; + } + } + registerMethodCallError(expression, parameter); } } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ConcreteClassUtil.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ConcreteClassUtil.java index 32d6c8eef81e..44554566a439 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ConcreteClassUtil.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/ConcreteClassUtil.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. @@ -21,30 +21,33 @@ import org.jetbrains.annotations.Nullable; class ConcreteClassUtil { - private ConcreteClassUtil() { - } + private ConcreteClassUtil() {} - public static boolean typeIsConcreteClass( - @Nullable PsiTypeElement typeElement, - boolean ignoreCastToAbstractClass) { + public static boolean typeIsConcreteClass(@Nullable PsiTypeElement typeElement, boolean ignoreCastToAbstractClass) { if (typeElement == null) { return false; } final PsiType type = typeElement.getType(); + return typeIsConcreteClass(type, ignoreCastToAbstractClass); + } + + public static boolean typeIsConcreteClass(@Nullable PsiType type, boolean ignoreCastToAbstractClass) { + if (type == null) { + return false; + } final PsiType baseType = type.getDeepComponentType(); if (!(baseType instanceof PsiClassType)) { return false; } - final PsiClass aClass = ((PsiClassType)baseType).resolve(); + final PsiClassType classType = (PsiClassType)baseType; + final PsiClass aClass = classType.resolve(); if (aClass == null) { return false; } - if (ignoreCastToAbstractClass && - aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + if (ignoreCastToAbstractClass && aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { return false; } - if (aClass.isInterface() || aClass.isEnum() || - aClass.isAnnotationType()) { + if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType()) { return false; } if (aClass instanceof PsiTypeParameter) { diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CastToConcreteClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CastToConcreteClass.html index 069e856eb04d..585311f920e2 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/CastToConcreteClass.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CastToConcreteClass.html @@ -5,7 +5,9 @@ Such declarations may represent a failure of abstraction, and may make testing m Declarations whose classes come from system or third-party libraries will not be reported by this inspection.

-Use the checkbox below to have this inspection ignore casts to abstract classes. +Use the first checkbox below to have this inspection ignore casts to abstract classes. +

+Use the second checkbox below to have this inspection ignore casts inside equals() methods.

Powered by InspectionGadgets diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/cast_to_concrete_class/CastToConcreteClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/cast_to_concrete_class/CastToConcreteClass.java new file mode 100644 index 000000000000..a4868a962999 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/cast_to_concrete_class/CastToConcreteClass.java @@ -0,0 +1,23 @@ +package com.siyeh.igtest.abstraction.cast_to_concrete_class; + +class CastToConcreteClass { + + private String field; + + @Override + public boolean equals(Object obj) { + try { + CastToConcreteClass c = (CastToConcreteClass)obj; + return c.field.equals(field); + } catch (ClassCastException e) { + return false; + } + } + + void foo(Object o) { + CastToConcreteClass c = (CastToConcreteClass)o; + CastToConcreteClass c2 = CastToConcreteClass.class.cast(o); + final Class aClass = CastToConcreteClass.class; + final CastToConcreteClass c3 = aClass.cast(o); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/cast_to_concrete_class/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/cast_to_concrete_class/expected.xml new file mode 100644 index 000000000000..76af465c4b12 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/cast_to_concrete_class/expected.xml @@ -0,0 +1,23 @@ + + + + CastToConcreteClass.java + 18 + Cast to a concrete class + Cast to concrete class <code>CastToConcreteClass</code> #loc + + + + CastToConcreteClass.java + 19 + Cast to a concrete class + Cast to concrete class <code>CastToConcreteClass</code> #loc + + + + CastToConcreteClass.java + 21 + Cast to a concrete class + Cast to concrete class <code>CastToConcreteClass</code> #loc + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/abstraction/CastToConcreteClassInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/abstraction/CastToConcreteClassInspectionTest.java new file mode 100644 index 000000000000..bd9e6e35ba9a --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/abstraction/CastToConcreteClassInspectionTest.java @@ -0,0 +1,12 @@ +package com.siyeh.ig.abstraction; + +import com.siyeh.ig.IGInspectionTestCase; + +public class CastToConcreteClassInspectionTest extends IGInspectionTestCase { + + public void test() throws Exception { + final CastToConcreteClassInspection tool = new CastToConcreteClassInspection(); + tool.ignoreInEquals = true; + doTest("com/siyeh/igtest/abstraction/cast_to_concrete_class", tool); + } +} \ No newline at end of file From b4a776676cac4835a10e227f4aa91168d2a2045b Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Tue, 11 Sep 2012 20:24:08 +0400 Subject: [PATCH 07/17] EA-38977 - assert: FoldingModelImpl.expandFoldRegion Don't update fold regions from thread over than EDT --- .../folding/impl/CodeFoldingManagerImpl.java | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java index 6a33a45fc5ee..10999a526730 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/CodeFoldingManagerImpl.java @@ -227,31 +227,25 @@ public class CodeFoldingManagerImpl extends CodeFoldingManager implements Projec if (runnable != null) { runnable.run(); } - - UIUtil.invokeLaterIfNeeded(new Runnable() { + if (myProject.isDisposed() || editor.isDisposed()) return; + foldingModel.runBatchFoldingOperation(new Runnable() { @Override public void run() { - if (myProject.isDisposed() || editor.isDisposed()) return; - foldingModel.runBatchFoldingOperation(new Runnable() { - @Override - public void run() { - DocumentFoldingInfo documentFoldingInfo = getDocumentFoldingInfo(document); - Editor[] editors = EditorFactory.getInstance().getEditors(document, myProject); - for (Editor otherEditor : editors) { - if (otherEditor == editor) continue; - documentFoldingInfo.loadFromEditor(otherEditor); - break; - } - documentFoldingInfo.setToEditor(editor); + DocumentFoldingInfo documentFoldingInfo = getDocumentFoldingInfo(document); + Editor[] editors = EditorFactory.getInstance().getEditors(document, myProject); + for (Editor otherEditor : editors) { + if (otherEditor == editor) continue; + documentFoldingInfo.loadFromEditor(otherEditor); + break; + } + documentFoldingInfo.setToEditor(editor); - documentFoldingInfo.clear(); - } - }); + documentFoldingInfo.clear(); } }); } }; - editor.getFoldingModel().runBatchFoldingOperationDoNotCollapseCaret(operation); + UIUtil.invokeLaterIfNeeded(operation); } @Override From d68883c9e310cb98eb03037400e2863225a694f6 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 11 Sep 2012 20:30:27 +0400 Subject: [PATCH 08/17] fixed PY-7524 Dragged/pasted code in wrong location fixed PY-7470 Smart copy-paste unindents next line (in place insert) --- .../editorActions/CopyPasteIndentProcessor.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java index 2367d066745b..983e61a99a9d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java @@ -108,11 +108,7 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor Date: Tue, 11 Sep 2012 15:08:35 +0400 Subject: [PATCH 09/17] allow hiding project generators --- .../platform/HideableProjectGenerator.java | 23 +++++++++++++++++++ .../platform/NewDirectoryProjectDialog.java | 5 ++++ 2 files changed, 28 insertions(+) create mode 100644 platform/platform-impl/src/com/intellij/platform/HideableProjectGenerator.java diff --git a/platform/platform-impl/src/com/intellij/platform/HideableProjectGenerator.java b/platform/platform-impl/src/com/intellij/platform/HideableProjectGenerator.java new file mode 100644 index 000000000000..79ee56808839 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/platform/HideableProjectGenerator.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.platform; + +/** + * @author Dennis.Ushakov + */ +public interface HideableProjectGenerator { + boolean isHidden(); +} diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java index ed63d326c25b..c5ff7cf862c7 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java @@ -79,6 +79,11 @@ public class NewDirectoryProjectDialog extends DialogWrapper { List primaryGenerators = ContainerUtil.newArrayList(); List otherGenerators = ContainerUtil.newArrayList(); for (DirectoryProjectGenerator generator : generators) { + if (generator instanceof HideableProjectGenerator) { + if (((HideableProjectGenerator)generator).isHidden()) { + continue; + } + } boolean primary = true; if (generator instanceof WebProjectGenerator) { primary = ((WebProjectGenerator) generator).isPrimaryGenerator(); From 3719f4d04f073f24a7961eda2fcf2b88b2fcee3a Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 11 Sep 2012 16:04:12 +0200 Subject: [PATCH 10/17] IDEA-91334 Event log default icon should be 13x13 --- platform/icons/src/ide/noNotifications13.png | Bin 0 -> 350 bytes .../src/META-INF/PlatformExtensions.xml | 2 +- .../util/src/com/intellij/icons/AllIcons.java | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 platform/icons/src/ide/noNotifications13.png diff --git a/platform/icons/src/ide/noNotifications13.png b/platform/icons/src/ide/noNotifications13.png new file mode 100644 index 0000000000000000000000000000000000000000..ed7019d0ce8ec7a4a3717a2f8a13633491506f51 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@q#X;^)4C~IxyaaOClDyqr82*Fc zg1yTp14TFsJR*x37`TN&n2}-D90{Nxdx@v7EBhTzZeBg^=O!0`@(hwCt`Q~9`MJ5N zc_j?aMX8A;sVNHOnI#zt?w-B@;f;LaKt($}T^vI+&aa(h$aly zTpptLTy}|QTxiPp$(HHxNYy*}xLPNRQ%v!Hp00i_>zopr09@UCH2?qr literal 0 HcmV?d00001 diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 1f6d6a7799cf..5cd2c5549709 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -244,7 +244,7 @@ Date: Tue, 11 Sep 2012 17:15:31 +0200 Subject: [PATCH 11/17] don't report constant conditions containing call chains --- .../dataFlow/ControlFlowAnalyzer.java | 5 +- .../dataFlow/DataFlowInspection.java | 181 ++++++++++-------- .../dataFlow/StandardInstructionVisitor.java | 13 ++ .../dataFlow/value/DfaVariableValue.java | 19 +- .../ChainedFinalFieldAccessorsDfa.java | 2 - .../src/messages/InspectionsBundle.properties | 2 +- 6 files changed, 133 insertions(+), 89 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index 405c6f637197..9ec332a8405b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -1526,15 +1526,16 @@ class ControlFlowAnalyzer extends JavaElementVisitor { return null; } + boolean isCall = expression instanceof PsiMethodCallExpression; PsiExpression qualifier = refExpr.getQualifierExpression(); if (qualifier == null) { - return myFactory.getVarFactory().createVariableValue(var, false, null); + return myFactory.getVarFactory().createVariableValue(var, false, null, isCall); } if (var instanceof PsiField && var.hasModifierProperty(PsiModifier.FINAL)) { DfaVariableValue qualifierValue = createChainedVariableValue(qualifier); if (qualifierValue != null) { - return myFactory.getVarFactory().createVariableValue(var, false, qualifierValue); + return myFactory.getVarFactory().createVariableValue(var, false, qualifierValue, isCall || qualifierValue.isViaMethods()); } } return null; diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java index 31fd7d552009..8b49b808dc1e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java @@ -147,16 +147,13 @@ public class DataFlowInspection extends BaseLocalInspectionTool { Pair, Set> constConditions = runner.getConstConditionalExpressions(); Set trueSet = constConditions.getFirst(); Set falseSet = constConditions.getSecond(); - Set npeSet = runner.getNPEInstructions(); - Set cceSet = runner.getCCEInstructions(); - Set redundantInstanceofs = StandardDataFlowRunner.getRedundantInstanceofs(runner, visitor); ArrayList allProblems = new ArrayList(); allProblems.addAll(trueSet); allProblems.addAll(falseSet); - allProblems.addAll(npeSet); - allProblems.addAll(cceSet); - allProblems.addAll(redundantInstanceofs); + allProblems.addAll(runner.getNPEInstructions()); + allProblems.addAll(runner.getCCEInstructions()); + allProblems.addAll(StandardDataFlowRunner.getRedundantInstanceofs(runner, visitor)); Collections.sort(allProblems, new Comparator() { public int compare(Instruction i1, Instruction i2) { @@ -168,82 +165,105 @@ public class DataFlowInspection extends BaseLocalInspectionTool { for (Instruction instruction : allProblems) { if (instruction instanceof MethodCallInstruction) { - MethodCallInstruction mcInstruction = (MethodCallInstruction)instruction; - if (mcInstruction.getCallExpression() instanceof PsiMethodCallExpression) { - PsiMethodCallExpression callExpression = (PsiMethodCallExpression)mcInstruction.getCallExpression(); - LocalQuickFix[] fix = createNPEFixes(callExpression.getMethodExpression().getQualifierExpression(), callExpression); - - holder.registerProblem(callExpression, - InspectionsBundle.message("dataflow.message.npe.method.invocation"), - fix); - } + reportCallMayProduceNpe(holder, (MethodCallInstruction)instruction); } else if (instruction instanceof FieldReferenceInstruction) { - FieldReferenceInstruction frInstruction = (FieldReferenceInstruction)instruction; - PsiElement elementToAssert = frInstruction.getElementToAssert(); - PsiExpression expression = frInstruction.getExpression(); - if (expression instanceof PsiArrayAccessExpression) { - LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression); - holder.registerProblem(expression, - InspectionsBundle.message("dataflow.message.npe.array.access"), - fix); - } - else { - LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression); - holder.registerProblem(elementToAssert, - InspectionsBundle.message("dataflow.message.npe.field.access"), - fix); - } + reportFieldAccessMayProduceNpe(holder, (FieldReferenceInstruction)instruction); } else if (instruction instanceof TypeCastInstruction) { - TypeCastInstruction tcInstruction = (TypeCastInstruction)instruction; - PsiTypeCastExpression typeCast = tcInstruction.getCastExpression(); - holder.registerProblem(typeCast.getCastType(), - InspectionsBundle.message("dataflow.message.cce", typeCast.getOperand().getText())); + reportCastMayFail(holder, (TypeCastInstruction)instruction); } else if (instruction instanceof BranchingInstruction) { - PsiElement psiAnchor = ((BranchingInstruction)instruction).getPsiAnchor(); - boolean underBinary = isAtRHSOfBooleanAnd(psiAnchor); - if (instruction instanceof InstanceofInstruction && visitor.isInstanceofRedundant((InstanceofInstruction)instruction)) { - if (visitor.canBeNull((BinopInstruction)instruction)) { - holder.registerProblem(psiAnchor, - InspectionsBundle.message("dataflow.message.redundant.instanceof"), - new RedundantInstanceofFix()); - } - else { - final LocalQuickFix localQuickFix = createSimplifyBooleanExpressionFix(psiAnchor, true); - holder.registerProblem(psiAnchor, - InspectionsBundle.message(underBinary ? "dataflow.message.constant.condition.whenriched" : "dataflow.message.constant.condition", Boolean.toString(true)), - localQuickFix == null ? null : new LocalQuickFix[]{localQuickFix}); - } - } - else if (psiAnchor instanceof PsiSwitchLabelStatement) { - if (falseSet.contains(instruction)) { - holder.registerProblem(psiAnchor, - InspectionsBundle.message("dataflow.message.unreachable.switch.label")); - } - } - else if (psiAnchor != null && !reportedAnchors.contains(psiAnchor) && !isCompileConstantInIfCondition(psiAnchor)) { - boolean evaluatesToTrue = trueSet.contains(instruction); - if (onTheLeftSideOfConditionalAssignemnt(psiAnchor)) { - holder.registerProblem( - psiAnchor, - InspectionsBundle.message("dataflow.message.pointless.assignment.expression", Boolean.toString(evaluatesToTrue)), - createSimplifyToAssignmentFix() - ); - } - else if (shouldReportConditionAlwaysTrueOrFalse(psiAnchor, evaluatesToTrue)) { - final LocalQuickFix fix = createSimplifyBooleanExpressionFix(psiAnchor, evaluatesToTrue); - String message = InspectionsBundle.message(underBinary ? - "dataflow.message.constant.condition.whenriched" : - "dataflow.message.constant.condition", Boolean.toString(evaluatesToTrue)); - holder.registerProblem(psiAnchor, message, fix == null ? null : new LocalQuickFix[]{fix}); - } - reportedAnchors.add(psiAnchor); - } + handleBranchingInstruction(holder, visitor, trueSet, falseSet, reportedAnchors, (BranchingInstruction)instruction); } } + reportNullableArguments(runner, holder); + reportNullableAssignments(runner, holder); + reportUnboxedNullables(runner, holder); + reportNullableReturns(runner, holder); + } + + private static void reportCallMayProduceNpe(ProblemsHolder holder, MethodCallInstruction mcInstruction) { + if (mcInstruction.getCallExpression() instanceof PsiMethodCallExpression) { + PsiMethodCallExpression callExpression = (PsiMethodCallExpression)mcInstruction.getCallExpression(); + LocalQuickFix[] fix = createNPEFixes(callExpression.getMethodExpression().getQualifierExpression(), callExpression); + + holder.registerProblem(callExpression, + InspectionsBundle.message("dataflow.message.npe.method.invocation"), + fix); + } + } + + private static void reportFieldAccessMayProduceNpe(ProblemsHolder holder, FieldReferenceInstruction frInstruction) { + PsiElement elementToAssert = frInstruction.getElementToAssert(); + PsiExpression expression = frInstruction.getExpression(); + if (expression instanceof PsiArrayAccessExpression) { + LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression); + holder.registerProblem(expression, + InspectionsBundle.message("dataflow.message.npe.array.access"), + fix); + } + else { + LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression); + holder.registerProblem(elementToAssert, + InspectionsBundle.message("dataflow.message.npe.field.access"), + fix); + } + } + + private static void reportCastMayFail(ProblemsHolder holder, TypeCastInstruction instruction) { + PsiTypeCastExpression typeCast = instruction.getCastExpression(); + holder.registerProblem(typeCast.getCastType(), + InspectionsBundle.message("dataflow.message.cce", typeCast.getOperand().getText())); + } + + private void handleBranchingInstruction(ProblemsHolder holder, + StandardInstructionVisitor visitor, + Set trueSet, + Set falseSet, HashSet reportedAnchors, BranchingInstruction instruction) { + PsiElement psiAnchor = instruction.getPsiAnchor(); + boolean underBinary = isAtRHSOfBooleanAnd(psiAnchor); + if (instruction instanceof InstanceofInstruction && visitor.isInstanceofRedundant((InstanceofInstruction)instruction)) { + if (visitor.canBeNull((BinopInstruction)instruction)) { + holder.registerProblem(psiAnchor, + InspectionsBundle.message("dataflow.message.redundant.instanceof"), + new RedundantInstanceofFix()); + } + else { + final LocalQuickFix localQuickFix = createSimplifyBooleanExpressionFix(psiAnchor, true); + holder.registerProblem(psiAnchor, + InspectionsBundle.message(underBinary ? "dataflow.message.constant.condition.when.reached" : "dataflow.message.constant.condition", Boolean.toString(true)), + localQuickFix == null ? null : new LocalQuickFix[]{localQuickFix}); + } + } + else if (psiAnchor instanceof PsiSwitchLabelStatement) { + if (falseSet.contains(instruction)) { + holder.registerProblem(psiAnchor, + InspectionsBundle.message("dataflow.message.unreachable.switch.label")); + } + } + else if (psiAnchor != null && !reportedAnchors.contains(psiAnchor) && !isCompileConstantInIfCondition(psiAnchor)) { + boolean evaluatesToTrue = trueSet.contains(instruction); + if (onTheLeftSideOfConditionalAssignemnt(psiAnchor)) { + holder.registerProblem( + psiAnchor, + InspectionsBundle.message("dataflow.message.pointless.assignment.expression", Boolean.toString(evaluatesToTrue)), + createSimplifyToAssignmentFix() + ); + } + else if (shouldReportConditionAlwaysTrueOrFalse(psiAnchor, evaluatesToTrue) && !visitor.silenceConstantCondition(instruction)) { + final LocalQuickFix fix = createSimplifyBooleanExpressionFix(psiAnchor, evaluatesToTrue); + String message = InspectionsBundle.message(underBinary ? + "dataflow.message.constant.condition.when.reached" : + "dataflow.message.constant.condition", Boolean.toString(evaluatesToTrue)); + holder.registerProblem(psiAnchor, message, fix == null ? null : new LocalQuickFix[]{fix}); + } + reportedAnchors.add(psiAnchor); + } + } + + private static void reportNullableArguments(StandardDataFlowRunner runner, ProblemsHolder holder) { Set exprs = runner.getNullableArguments(); for (PsiExpression expr : exprs) { final String text = isNullLiteralExpression(expr) @@ -252,22 +272,25 @@ public class DataFlowInspection extends BaseLocalInspectionTool { LocalQuickFix[] fixes = createNPEFixes(expr, expr); holder.registerProblem(expr, text, fixes); } + } - exprs = runner.getNullableAssignments(); - for (PsiExpression expr : exprs) { + private static void reportNullableAssignments(StandardDataFlowRunner runner, ProblemsHolder holder) { + for (PsiExpression expr : runner.getNullableAssignments()) { final String text = isNullLiteralExpression(expr) ? InspectionsBundle.message("dataflow.message.assigning.null") : InspectionsBundle.message("dataflow.message.assigning.nullable"); holder.registerProblem(expr, text); } + } - exprs = runner.getUnboxedNullables(); - for (PsiExpression expr : exprs) { + private static void reportUnboxedNullables(StandardDataFlowRunner runner, ProblemsHolder holder) { + for (PsiExpression expr : runner.getUnboxedNullables()) { holder.registerProblem(expr, InspectionsBundle.message("dataflow.message.unboxing")); } + } - final Set statements = runner.getNullableReturns(); - for (PsiReturnStatement statement : statements) { + private static void reportNullableReturns(StandardDataFlowRunner runner, ProblemsHolder holder) { + for (PsiReturnStatement statement : runner.getNullableReturns()) { final PsiExpression expr = statement.getReturnValue(); if (runner.isInNotNullMethod()) { final String text = isNullLiteralExpression(expr) diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 7d7d19813359..f73bcf4b67ce 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -36,6 +36,7 @@ import java.util.Set; public class StandardInstructionVisitor extends InstructionVisitor { private final Set myReachable = new THashSet(); private final Set myCanBeNullInInstanceof = new THashSet(); + private final Set myNotToReportReachability = new THashSet(); private final Set myUsefulInstanceofs = new THashSet(); private final FactoryMap myParametersNotNull = new FactoryMap() { @Override @@ -298,7 +299,11 @@ public class StandardInstructionVisitor extends InstructionVisitor { return null; } + if (isViaMethods(dfaLeft) || isViaMethods(dfaRight)) { + myNotToReportReachability.add(instruction); + } myCanBeNullInInstanceof.add(instruction); + ArrayList states = new ArrayList(); final DfaMemoryState trueCopy = memState.createCopy(); @@ -328,6 +333,10 @@ public class StandardInstructionVisitor extends InstructionVisitor { return states.toArray(new DfaInstructionState[states.size()]); } + private static boolean isViaMethods(DfaValue dfa) { + return dfa instanceof DfaVariableValue && ((DfaVariableValue)dfa).isViaMethods(); + } + private void handleInstanceof(InstanceofInstruction instruction, DfaValue dfaRight, DfaValue dfaLeft) { if ((dfaLeft instanceof DfaTypeValue || dfaLeft instanceof DfaNotNullValue) && dfaRight instanceof DfaTypeValue) { final PsiType leftType; @@ -397,4 +406,8 @@ public class StandardInstructionVisitor extends InstructionVisitor { public boolean canBeNull(BinopInstruction instruction) { return myCanBeNullInInstanceof.contains(instruction); } + + public boolean silenceConstantCondition(BranchingInstruction instruction) { + return instruction instanceof BinopInstruction && myNotToReportReachability.contains(instruction); + } } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java index 2a2b9005d819..bddc40d1c32a 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/value/DfaVariableValue.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.List; public class DfaVariableValue extends DfaValue { + public static class Factory { private final DfaVariableValue mySharedInstance; private final HashMap> myStringToObject; @@ -46,12 +47,13 @@ public class DfaVariableValue extends DfaValue { } public DfaVariableValue createVariableValue(PsiVariable myVariable, boolean isNegated) { - return createVariableValue(myVariable, isNegated, null); + return createVariableValue(myVariable, isNegated, null, false); } - public DfaVariableValue createVariableValue(PsiVariable myVariable, boolean isNegated, @Nullable DfaVariableValue qualifier) { + public DfaVariableValue createVariableValue(PsiVariable myVariable, boolean isNegated, @Nullable DfaVariableValue qualifier, boolean viaMethods) { mySharedInstance.myVariable = myVariable; mySharedInstance.myIsNegated = isNegated; mySharedInstance.myQualifier = qualifier; + mySharedInstance.myViaMethods = viaMethods; String id = mySharedInstance.toString(); ArrayList conditions = myStringToObject.get(id); @@ -65,7 +67,7 @@ public class DfaVariableValue extends DfaValue { } } - DfaVariableValue result = new DfaVariableValue(myVariable, isNegated, myFactory, qualifier); + DfaVariableValue result = new DfaVariableValue(myVariable, isNegated, myFactory, qualifier, viaMethods); if (qualifier != null) { myQualifiersToChainedVariables.putValue(qualifier, result); } @@ -87,12 +89,14 @@ public class DfaVariableValue extends DfaValue { private PsiVariable myVariable; @Nullable private DfaVariableValue myQualifier; private boolean myIsNegated; + private boolean myViaMethods; - private DfaVariableValue(PsiVariable variable, boolean isNegated, DfaValueFactory factory, @Nullable DfaVariableValue qualifier) { + private DfaVariableValue(PsiVariable variable, boolean isNegated, DfaValueFactory factory, @Nullable DfaVariableValue qualifier, boolean viaMethods) { super(factory); myVariable = variable; myIsNegated = isNegated; myQualifier = qualifier; + myViaMethods = viaMethods; } private DfaVariableValue(DfaValueFactory factory) { @@ -111,7 +115,7 @@ public class DfaVariableValue extends DfaValue { } public DfaVariableValue createNegated() { - return myFactory.getVarFactory().createVariableValue(myVariable, !myIsNegated, myQualifier); + return myFactory.getVarFactory().createVariableValue(myVariable, !myIsNegated, myQualifier, myViaMethods); } @SuppressWarnings({"HardCodedStringLiteral"}) @@ -123,6 +127,7 @@ public class DfaVariableValue extends DfaValue { private boolean hardEquals(DfaVariableValue aVar) { return aVar.myVariable == myVariable && aVar.myIsNegated == myIsNegated && + aVar.myViaMethods == myViaMethods && (myQualifier == null ? aVar.myQualifier == null : myQualifier.hardEquals(aVar.myQualifier)); } @@ -130,4 +135,8 @@ public class DfaVariableValue extends DfaValue { public DfaVariableValue getQualifier() { return myQualifier; } + + public boolean isViaMethods() { + return myViaMethods; + } } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ChainedFinalFieldAccessorsDfa.java b/java/java-tests/testData/inspection/dataFlow/fixture/ChainedFinalFieldAccessorsDfa.java index 5eb2ef10dcc4..e166ce3f8cd7 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ChainedFinalFieldAccessorsDfa.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ChainedFinalFieldAccessorsDfa.java @@ -15,11 +15,9 @@ public class BrokenAlignment { if (data.inner() != null) { System.out.println(data.inner().hashCode()); System.out.println(data.inner().getText().hashCode()); - /* if (data.inner() != null) { System.out.println(data.inner().hashCode()); } - */ data = new Data(null, null); System.out.println(data.inner().hashCode()); diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 771d65997918..4100c767f268 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -59,7 +59,7 @@ dataflow.message.npe.field.access=Dereference of #ref #loc may prod dataflow.message.cce=Casting {0} to #ref #loc may produce java.lang.ClassCastException dataflow.message.redundant.instanceof=Condition #ref #loc is redundant and can be replaced with != null dataflow.message.constant.condition=Condition #ref #loc is always {0} -dataflow.message.constant.condition.whenriched=Condition #ref #loc is always {0} when reached +dataflow.message.constant.condition.when.reached=Condition #ref #loc is always {0} when reached dataflow.message.unreachable.switch.label=Switch label#ref #loc is unreachable dataflow.message.pointless.assignment.expression=Condition #ref #loc at the left side of assignment expression is always {0}. Can be simplified to normal assignment dataflow.message.passing.null.argument=Passing null argument to parameter annotated as @NotNull From 48e283aaf32e28fdba837b38f0a1d4b586e8c4e2 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 11 Sep 2012 21:55:52 +0200 Subject: [PATCH 12/17] performance and cleanup --- .../com/siyeh/ig/fixes/MakeClassFinalFix.java | 100 +++++++++++++++ ...allDuringObjectConstructionInspection.java | 118 ++++++------------ .../src/com/siyeh/ig/psiutils/ClassUtils.java | 8 -- 3 files changed, 135 insertions(+), 91 deletions(-) create mode 100644 plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MakeClassFinalFix.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MakeClassFinalFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MakeClassFinalFix.java new file mode 100644 index 000000000000..f50d434bb1e9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MakeClassFinalFix.java @@ -0,0 +1,100 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.fixes; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiModifierList; +import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.ui.ConflictsDialog; +import com.intellij.refactoring.util.RefactoringUIUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.Processor; +import com.intellij.util.Query; +import com.intellij.util.containers.MultiMap; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.InspectionGadgetsFix; +import org.jetbrains.annotations.NotNull; + +/** +* @author Bas Leijdekkers +*/ +public class MakeClassFinalFix extends InspectionGadgetsFix { + + private final String className; + + public MakeClassFinalFix(PsiClass aClass) { + className = aClass.getName(); + } + + @Override + @NotNull + public String getName() { + return InspectionGadgetsBundle.message( + "make.class.final.fix.name", className); + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { + final PsiElement element = descriptor.getPsiElement(); + final PsiClass containingClass = PsiTreeUtil.getParentOfType(element, PsiClass.class); + if (containingClass == null) { + return; + } + final PsiModifierList modifierList = containingClass.getModifierList(); + if (modifierList == null) { + return; + } + final MultiMap conflicts = new MultiMap(); + final Query search = ClassInheritorsSearch.search(containingClass); + search.forEach(new Processor() { + @Override + public boolean process(PsiClass aClass) { + conflicts.putValue(containingClass, RefactoringUIUtil.getDescription(containingClass, false) + + " will no longer be overridable by " + RefactoringUIUtil.getDescription(aClass, false)); + return true; + } + }); + final boolean conflictsDialogOK; + if (!conflicts.isEmpty()) { + final ConflictsDialog conflictsDialog = new ConflictsDialog(element.getProject(), conflicts, new Runnable() { + @Override + public void run() { + final AccessToken token = WriteAction.start(); + try { + modifierList.setModifierProperty(PsiModifier.FINAL, true); + } + finally { + token.finish(); + } + } + }); + conflictsDialog.show(); + conflictsDialogOK = conflictsDialog.isOK(); + } else { + conflictsDialogOK = true; + } + if (conflictsDialogOK) { + modifierList.setModifierProperty(PsiModifier.FINAL, true); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/OverridableMethodCallDuringObjectConstructionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/OverridableMethodCallDuringObjectConstructionInspection.java index 5a1fee9cf6f0..a5ea7d61ce29 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/OverridableMethodCallDuringObjectConstructionInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/OverridableMethodCallDuringObjectConstructionInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 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. @@ -25,82 +25,44 @@ import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.fixes.MakeClassFinalFix; import com.siyeh.ig.psiutils.ClassUtils; import com.siyeh.ig.psiutils.CloneUtils; import com.siyeh.ig.psiutils.MethodUtils; import org.jetbrains.annotations.NotNull; -public class OverridableMethodCallDuringObjectConstructionInspection - extends BaseInspection { +public class OverridableMethodCallDuringObjectConstructionInspection extends BaseInspection { + @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "overridable.method.call.in.constructor.display.name"); + return InspectionGadgetsBundle.message("overridable.method.call.in.constructor.display.name"); } + @Override @NotNull public String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "overridable.method.call.in.constructor.problem.descriptor"); + return InspectionGadgetsBundle.message("overridable.method.call.in.constructor.problem.descriptor"); } + @Override @NotNull protected InspectionGadgetsFix[] buildFixes(Object... infos) { - final PsiMethodCallExpression methodCallExpression = - (PsiMethodCallExpression)infos[0]; - final PsiClass callClass = - ClassUtils.getContainingClass(methodCallExpression); + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)infos[0]; + final PsiClass callClass = ClassUtils.getContainingClass(methodCallExpression); final PsiMethod method = methodCallExpression.resolveMethod(); if (method == null) { return InspectionGadgetsFix.EMPTY_ARRAY; } final PsiClass containingClass = method.getContainingClass(); - if (!containingClass.equals(callClass) || - MethodUtils.isOverridden(method)) { + if (containingClass == null || !containingClass.equals(callClass) || MethodUtils.isOverridden(method)) { return InspectionGadgetsFix.EMPTY_ARRAY; } final String methodName = method.getName(); - if (!ClassUtils.isOverridden(containingClass)) { - return new InspectionGadgetsFix[]{ - new MakeClassFinalFix(containingClass), - new MakeMethodFinalFix(methodName)}; - } - else { - return new InspectionGadgetsFix[]{ - new MakeMethodFinalFix(methodName)}; - } - } - - private static class MakeClassFinalFix extends InspectionGadgetsFix { - - private final String className; - - MakeClassFinalFix(PsiClass aClass) { - className = aClass.getName(); - } - - @NotNull - public String getName() { - return InspectionGadgetsBundle.message( - "make.class.final.fix.name", className); - } - - protected void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { - final PsiElement element = descriptor.getPsiElement(); - final PsiClass containingClass = - PsiTreeUtil.getParentOfType(element, PsiClass.class); - if (containingClass == null) { - return; - } - final PsiModifierList modifierList = - containingClass.getModifierList(); - if (modifierList == null) { - return; - } - modifierList.setModifierProperty(PsiModifier.FINAL, true); - } + return new InspectionGadgetsFix[]{ + new MakeClassFinalFix(containingClass), + new MakeMethodFinalFix(methodName) + }; } private static class MakeMethodFinalFix extends InspectionGadgetsFix { @@ -111,42 +73,40 @@ public class OverridableMethodCallDuringObjectConstructionInspection this.methodName = methodName; } + @Override @NotNull public String getName() { return InspectionGadgetsBundle.message( "make.method.final.fix.name", methodName); } - protected void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiElement methodName = descriptor.getPsiElement(); final PsiElement methodExpression = methodName.getParent(); - final PsiMethodCallExpression methodCall = - (PsiMethodCallExpression)methodExpression.getParent(); + final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)methodExpression.getParent(); final PsiMethod method = methodCall.resolveMethod(); - assert method != null; + if (method == null) { + return; + } final PsiModifierList modifierList = method.getModifierList(); modifierList.setModifierProperty(PsiModifier.FINAL, true); } } + @Override public BaseInspectionVisitor buildVisitor() { return new OverridableMethodCallInConstructorVisitor(); } - private static class OverridableMethodCallInConstructorVisitor - extends BaseInspectionVisitor { + private static class OverridableMethodCallInConstructorVisitor extends BaseInspectionVisitor { @Override - public void visitMethodCallExpression( - @NotNull PsiMethodCallExpression call) { + public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) { super.visitMethodCallExpression(call); - final PsiMember member = - PsiTreeUtil.getParentOfType(call, PsiMethod.class, - PsiClassInitializer.class); + final PsiMember member = PsiTreeUtil.getParentOfType(call, PsiMethod.class, PsiClassInitializer.class); if (member instanceof PsiClassInitializer) { - final PsiClassInitializer classInitializer = - (PsiClassInitializer)member; + final PsiClassInitializer classInitializer = (PsiClassInitializer)member; if (classInitializer.hasModifierProperty(PsiModifier.STATIC)) { return; } @@ -160,13 +120,10 @@ public class OverridableMethodCallDuringObjectConstructionInspection else { return; } - final PsiReferenceExpression methodExpression = - call.getMethodExpression(); - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); if (qualifier != null) { - if (!(qualifier instanceof PsiThisExpression - || qualifier instanceof PsiSuperExpression)) { + if (!(qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression)) { return; } } @@ -177,15 +134,12 @@ public class OverridableMethodCallDuringObjectConstructionInspection if (containingClass.hasModifierProperty(PsiModifier.FINAL)) { return; } - final PsiMethod calledMethod = - (PsiMethod)methodExpression.resolve(); + final PsiMethod calledMethod = (PsiMethod)methodExpression.resolve(); if (calledMethod == null || !PsiUtil.canBeOverriden(calledMethod)) { return; } - final PsiClass calledMethodClass = - calledMethod.getContainingClass(); - if (calledMethodClass == null || - !calledMethodClass.equals(containingClass)) { + final PsiClass calledMethodClass = calledMethod.getContainingClass(); + if (calledMethodClass == null || !calledMethodClass.equals(containingClass)) { return; } registerMethodCallError(call, call); @@ -198,12 +152,10 @@ public class OverridableMethodCallDuringObjectConstructionInspection if (CloneUtils.isClone(method)) { return true; } - if (MethodUtils.simpleMethodMatches(method, null, "void", - "readObject", "java.io.ObjectInputStream")) { + if (MethodUtils.simpleMethodMatches(method, null, "void", "readObject", "java.io.ObjectInputStream")) { return true; } - return MethodUtils.simpleMethodMatches(method, null, "void", - "readObjectNoData"); + return MethodUtils.simpleMethodMatches(method, null, "void", "readObjectNoData"); } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ClassUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ClassUtils.java index a6ff23024bce..03ab992bc0a0 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ClassUtils.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/ClassUtils.java @@ -16,10 +16,8 @@ package com.siyeh.ig.psiutils; import com.intellij.psi.*; -import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.util.Query; import org.jetbrains.annotations.Nullable; import java.util.HashSet; @@ -223,10 +221,4 @@ public class ClassUtils { return inSamePackage(baseClass, referencedClass); } } - - public static boolean isOverridden(PsiClass aClass) { - final Query query = ClassInheritorsSearch.search(aClass); - final PsiClass result = query.findFirst(); - return result != null; - } } \ No newline at end of file From e8f211bdd9b2443a339e529af490075c1a2c64ff Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 11 Sep 2012 18:08:07 +0400 Subject: [PATCH 13/17] extract method: detect used lambda params in selection (IDEA-91345) --- .../psi/controlFlow/LocalsControlFlowPolicy.java | 15 ++++++++------- .../refactoring/extractMethod/OneLineLambda.java | 5 +++++ .../extractMethod/OneLineLambda_after.java | 9 +++++++++ .../intellij/refactoring/ExtractMethodTest.java | 4 ++++ 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 java/java-tests/testData/refactoring/extractMethod/OneLineLambda.java create mode 100644 java/java-tests/testData/refactoring/extractMethod/OneLineLambda_after.java diff --git a/java/java-impl/src/com/intellij/psi/controlFlow/LocalsControlFlowPolicy.java b/java/java-impl/src/com/intellij/psi/controlFlow/LocalsControlFlowPolicy.java index dc106dbcc9de..2ef15db7e70d 100644 --- a/java/java-impl/src/com/intellij/psi/controlFlow/LocalsControlFlowPolicy.java +++ b/java/java-impl/src/com/intellij/psi/controlFlow/LocalsControlFlowPolicy.java @@ -40,13 +40,14 @@ public class LocalsControlFlowPolicy implements ControlFlowPolicy { @Nullable private PsiVariable checkCodeFragment(PsiElement refElement) { - PsiElement codeFragement; - if (refElement instanceof PsiParameter - && ((PsiParameter)refElement).getDeclarationScope() instanceof PsiMethod){ - codeFragement = ((PsiMethod)((PsiParameter)refElement).getDeclarationScope()).getBody(); - } - else{ - codeFragement = ControlFlowUtil.findCodeFragment(refElement); + PsiElement codeFragement = ControlFlowUtil.findCodeFragment(refElement); + if (refElement instanceof PsiParameter) { + final PsiElement declarationScope = ((PsiParameter)refElement).getDeclarationScope(); + if (declarationScope instanceof PsiMethod){ + codeFragement = ((PsiMethod)declarationScope).getBody(); + } else if (declarationScope instanceof PsiLambdaExpression) { + codeFragement = ((PsiLambdaExpression)declarationScope).getBody(); + } } if (codeFragement == null) return null; if (myCodeFragment.getContainingFile() == codeFragement.getContainingFile() && //In order for jsp includes to work diff --git a/java/java-tests/testData/refactoring/extractMethod/OneLineLambda.java b/java/java-tests/testData/refactoring/extractMethod/OneLineLambda.java new file mode 100644 index 000000000000..db109ef4b5cd --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/OneLineLambda.java @@ -0,0 +1,5 @@ +class Test { + public void foo() { + Comparable c = o -> o.indexOf("foo"); + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/OneLineLambda_after.java b/java/java-tests/testData/refactoring/extractMethod/OneLineLambda_after.java new file mode 100644 index 000000000000..c5196b4e9ced --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/OneLineLambda_after.java @@ -0,0 +1,9 @@ +class Test { + public void foo() { + Comparable c = o -> newMethod(o); + } + + private int newMethod(String o) { + return o.indexOf("foo"); + } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index 776fedc344f9..81e598136243 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -540,6 +540,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTest(); } + public void testOneLineLambda() throws Exception { + doTest(); + } + private void doTestDisabledParam() throws PrepareFailedException { final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); settings.ELSE_ON_NEW_LINE = true; From ee5acf1fcd50d39a71dc89ab39787bc75ff45711 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 11 Sep 2012 20:04:04 +0400 Subject: [PATCH 14/17] distinguish different file roots in file pointers (IDEA-91353) --- .../psi/impl/smartPointers/FileElementInfo.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java index 628dd65c6005..f8d65182518c 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/FileElementInfo.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.smartPointers; +import com.intellij.lang.Language; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.project.Project; @@ -32,13 +33,19 @@ import org.jetbrains.annotations.NotNull; class FileElementInfo implements SmartPointerElementInfo { protected final VirtualFile myVirtualFile; protected final Project myProject; + protected final Language myLanguage; public FileElementInfo(@NotNull PsiFile file) { - this(file.getProject(), file.getVirtualFile()); + this(file.getProject(), file.getVirtualFile(), file.getLanguage()); } protected FileElementInfo(@NotNull Project project, VirtualFile virtualFile) { + this(project, virtualFile, null); + } + + protected FileElementInfo(@NotNull Project project, VirtualFile virtualFile, Language lang) { myVirtualFile = virtualFile; myProject = project; + myLanguage = lang; } @Override @@ -60,7 +67,7 @@ class FileElementInfo implements SmartPointerElementInfo { @Override public PsiElement restoreElement() { - return SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject); + return SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject, myLanguage); } @Override From 9ddff21a9c31fb97af352845228bf1fed1fe9a75 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 11 Sep 2012 20:51:28 +0400 Subject: [PATCH 15/17] inline inside lambda body (IDEA-91371) --- .../inline/InlineLocalHandler.java | 6 ++++- .../LocalVarInsideLambdaBody1.java | 24 +++++++++++++++++++ .../LocalVarInsideLambdaBody1.java.after | 23 ++++++++++++++++++ .../refactoring/inline/InlineLocalTest.java | 4 ++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/refactoring/inlineLocal/LocalVarInsideLambdaBody1.java create mode 100644 java/java-tests/testData/refactoring/inlineLocal/LocalVarInsideLambdaBody1.java.after diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java index 75f9a4d40575..91f642fc6546 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java @@ -95,7 +95,11 @@ public class InlineLocalHandler extends JavaInlineActionHandler { while (innerClass != containingClass && innerClass != null) { final PsiClass parentPsiClass = PsiTreeUtil.getParentOfType(innerClass, PsiClass.class, true); if (parentPsiClass == containingClass) { - innerClassesWithUsages.add(innerClass); + if (innerClass instanceof PsiLambdaExpression && PsiTreeUtil.isAncestor(innerClass, local, false)) { + innerClassesWithUsages.add(((PsiLambdaExpression)innerClass).getBody()); + } else { + innerClassesWithUsages.add(innerClass); + } innerClassUsages.add(element); } innerClass = parentPsiClass; diff --git a/java/java-tests/testData/refactoring/inlineLocal/LocalVarInsideLambdaBody1.java b/java/java-tests/testData/refactoring/inlineLocal/LocalVarInsideLambdaBody1.java new file mode 100644 index 000000000000..46c97bd3ab76 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/LocalVarInsideLambdaBody1.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +public class Test2 { + { + Runnable r = () -> { + final String p = "hello"; + System.out.println(p); + }; + } +} + diff --git a/java/java-tests/testData/refactoring/inlineLocal/LocalVarInsideLambdaBody1.java.after b/java/java-tests/testData/refactoring/inlineLocal/LocalVarInsideLambdaBody1.java.after new file mode 100644 index 000000000000..66ef507a8a08 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineLocal/LocalVarInsideLambdaBody1.java.after @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +public class Test2 { + { + Runnable r = () -> { + System.out.println("hello"); + }; + } +} + diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java index 45103653238f..0b1c432113e1 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineLocalTest.java @@ -158,6 +158,10 @@ public class InlineLocalTest extends LightCodeInsightTestCase { doTest(true); } + public void testLocalVarInsideLambdaBody1() throws Exception { + doTest(true); + } + private void doTest(final boolean inlineDef, String conflictMessage) throws Exception { try { doTest(inlineDef); From 943d901fffdcd54589d917ceafde9886cfb8d9da Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 11 Sep 2012 23:37:55 +0400 Subject: [PATCH 16/17] lambda: do not accept ? as type argument for return value (IDEA-91369) --- .../src/com/intellij/psi/LambdaUtil.java | 34 +++++++++++++++++-- .../lambda/highlighting/ReturnValue.java | 22 ++++++++++++ .../ReplaceLambdaWithAnonymousIntention.java | 5 ++- 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 64d5b1246585..30e0ebc579cb 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -113,13 +113,43 @@ public class LambdaUtil { @Nullable public static String checkInterfaceFunctional(PsiType functionalInterfaceType) { - final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(functionalInterfaceType); + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); + final PsiClass aClass = resolveResult.getElement(); if (aClass != null) { + if (checkReturnTypeApplicable(resolveResult, aClass)) { + return "No instance of type " + functionalInterfaceType.getPresentableText() + " exists so that lambda expression can be type-checked"; + } return checkInterfaceFunctional(aClass); } return null; } - + + private static boolean checkReturnTypeApplicable(PsiClassType.ClassResolveResult resolveResult, final PsiClass aClass) { + final MethodSignature methodSignature = getFunction(aClass); + if (methodSignature == null) return false; + + for (PsiTypeParameter parameter : aClass.getTypeParameters()) { + if (parameter.getExtendsListTypes().length == 0) continue; + boolean depends = false; + final PsiType substitution = resolveResult.getSubstitutor().substitute(parameter); + if (substitution instanceof PsiWildcardType && !((PsiWildcardType)substitution).isBounded()) { + for (PsiType paramType : methodSignature.getParameterTypes()) { + if (depends(paramType, parameter, new TypeParamsChecker((PsiMethod)null, aClass){ + @Override + public boolean startedInference() { + return true; + } + })) { + depends = true; + break; + } + } + if (!depends) return true; + } + } + return false; + } + @Nullable public static String checkInterfaceFunctional(@NotNull PsiClass psiClass) { if (psiClass instanceof PsiTypeParameter) return null; //should be logged as cyclic inference diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnValue.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnValue.java index 5bfdab7f6cbe..39ba57fcdc17 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnValue.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/ReturnValue.java @@ -40,4 +40,26 @@ class Test1 { } }; } +} + +class Test2 { + interface X { + T foo(); + } + + { + X x = () -> 123; + X x1 = () -> 123; + + } +} + +class Test3 { + interface X { + T foo(); + } + + { + X x = () -> 123; + } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceLambdaWithAnonymousIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceLambdaWithAnonymousIntention.java index 54984a6e1813..d863676f656f 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceLambdaWithAnonymousIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/types/ReplaceLambdaWithAnonymousIntention.java @@ -173,7 +173,10 @@ public class ReplaceLambdaWithAnonymousIntention extends Intention { if (disabled[0]) return false; } final PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType(); - return functionalInterfaceType != null && LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) != null && LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType); + return functionalInterfaceType != null && + LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) != null && + LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType) && + LambdaUtil.checkInterfaceFunctional(functionalInterfaceType) == null; } return false; } From f13fdb06c6813260703e834baae6c16576ad7537 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 11 Sep 2012 22:08:59 +0200 Subject: [PATCH 17/17] IDEA-91138 (UtilityClassWithoutPrivateConstructor - add corresponding inspection for class not being final) --- .../InspectionGadgets/src/META-INF/plugin.xml | 4 + .../siyeh/InspectionGadgetsBundle.properties | 3 + .../NonFinalUtilityClassInspection.java | 73 +++++++++++++++++++ .../com/siyeh/ig/fixes/MakeClassFinalFix.java | 12 ++- .../NonFinalUtilityClass.html | 10 +++ .../NonFinalUtilityClass.java | 10 +++ .../non_final_utility_class/expected.xml | 9 +++ .../NonFinalUtilityClassInspectionTest.java | 10 +++ 8 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NonFinalUtilityClassInspection.java create mode 100644 plugins/InspectionGadgets/src/inspectionDescriptions/NonFinalUtilityClass.html create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/non_final_utility_class/NonFinalUtilityClass.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/non_final_utility_class/expected.xml create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/NonFinalUtilityClassInspectionTest.java diff --git a/plugins/InspectionGadgets/src/META-INF/plugin.xml b/plugins/InspectionGadgets/src/META-INF/plugin.xml index 3f20b8e73e80..92a7411c19b7 100644 --- a/plugins/InspectionGadgets/src/META-INF/plugin.xml +++ b/plugins/InspectionGadgets/src/META-INF/plugin.xml @@ -469,6 +469,10 @@ key="non.final.field.in.enum.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.class.structure" enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.classlayout.NonFinalFieldInEnumInspection"/> + #ref is not final +0.will.no.longer.be.overridable.by.1={0} will no longer be overridable by {1} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NonFinalUtilityClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NonFinalUtilityClassInspection.java new file mode 100644 index 000000000000..0f6498eebb94 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/classlayout/NonFinalUtilityClassInspection.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.classlayout; + +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiModifier; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import com.siyeh.ig.fixes.MakeClassFinalFix; +import com.siyeh.ig.psiutils.UtilityClassUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class NonFinalUtilityClassInspection extends BaseInspection { + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("non.final.utility.class.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("non.final.utility.class.problem.descriptor"); + } + + @Nullable + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + return new MakeClassFinalFix((PsiClass)infos[0]); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new NonFinalUtilityClassVisitor(); + } + + private static class NonFinalUtilityClassVisitor extends BaseInspectionVisitor { + + @Override + public void visitClass(@NotNull PsiClass aClass) { + // no call to super, so that it doesn't drill down to inner classes + if (!UtilityClassUtil.isUtilityClass(aClass)) { + return; + } + if (aClass.hasModifierProperty(PsiModifier.FINAL)) { + return; + } + registerClassError(aClass, aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MakeClassFinalFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MakeClassFinalFix.java index f50d434bb1e9..4abf7a9dd66d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MakeClassFinalFix.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/MakeClassFinalFix.java @@ -64,13 +64,21 @@ public class MakeClassFinalFix extends InspectionGadgetsFix { if (modifierList == null) { return; } + if (!isOnTheFly()) { + if (ClassInheritorsSearch.search(containingClass).findFirst() != null) { + return; + } + modifierList.setModifierProperty(PsiModifier.FINAL, true); + return; + } final MultiMap conflicts = new MultiMap(); final Query search = ClassInheritorsSearch.search(containingClass); search.forEach(new Processor() { @Override public boolean process(PsiClass aClass) { - conflicts.putValue(containingClass, RefactoringUIUtil.getDescription(containingClass, false) + - " will no longer be overridable by " + RefactoringUIUtil.getDescription(aClass, false)); + conflicts.putValue(containingClass, InspectionGadgetsBundle + .message("0.will.no.longer.be.overridable.by.1", RefactoringUIUtil.getDescription(containingClass, false), + RefactoringUIUtil.getDescription(aClass, false))); return true; } }); diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonFinalUtilityClass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonFinalUtilityClass.html new file mode 100644 index 000000000000..de9ba5b222cd --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonFinalUtilityClass.html @@ -0,0 +1,10 @@ + + +This inspection reports utility classes which are not final. +Utility classes have all fields and methods declared static. Giving such classes making them final + prevents them from being inadvertently subclassed. + +

+New in 12, Powered by InspectionGadgets + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/non_final_utility_class/NonFinalUtilityClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/non_final_utility_class/NonFinalUtilityClass.java new file mode 100644 index 000000000000..d77cc0ebe49e --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/non_final_utility_class/NonFinalUtilityClass.java @@ -0,0 +1,10 @@ +package com.siyeh.igtest.classlayout.non_final_utility_class; + + +class NonFinalUtilityClass { + + public static void foo() {} +} +final class FinalUtilityClass { + public static void foo() {} +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/non_final_utility_class/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/non_final_utility_class/expected.xml new file mode 100644 index 000000000000..d068fb96fbc6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/classlayout/non_final_utility_class/expected.xml @@ -0,0 +1,9 @@ + + + + NonFinalUtilityClass.java + 4 + Utility class is not final + Utility class <code>NonFinalUtilityClass</code> is not final + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/NonFinalUtilityClassInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/NonFinalUtilityClassInspectionTest.java new file mode 100644 index 000000000000..c299d768cbf8 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/NonFinalUtilityClassInspectionTest.java @@ -0,0 +1,10 @@ +package com.siyeh.ig.classlayout; + +import com.siyeh.ig.IGInspectionTestCase; + +public class NonFinalUtilityClassInspectionTest extends IGInspectionTestCase { + + public void test() throws Exception { + doTest("com/siyeh/igtest/classlayout/non_final_utility_class", new NonFinalUtilityClassInspection()); + } +} \ No newline at end of file