From 098c6318cf01d381d0f0a6ae6367b4bb4b1cbaa7 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Thu, 13 Sep 2018 08:18:27 +0300 Subject: [PATCH] re-implement java global inspection graph using uast --- .../codeInspection/reference/RefClass.java | 42 +- .../codeInspection/reference/RefField.java | 8 + .../reference/RefImplicitConstructor.java | 6 + .../reference/RefJavaElement.java | 39 +- .../reference/RefJavaManager.java | 47 +- .../reference/RefJavaModule.java | 3 +- .../codeInspection/reference/RefJavaUtil.java | 80 +- .../codeInspection/reference/RefMethod.java | 16 +- .../reference/RefParameter.java | 16 +- .../canBeFinal/CanBeFinalAnnotator.java | 28 +- .../canBeFinal/CanBeFinalInspection.java | 25 +- .../UnusedDeclarationInspectionBase.java | 109 +-- .../ex/EntryPointsManagerBase.java | 2 +- ...9RedundantRequiresStatementInspection.java | 8 +- .../reference/RefClassImpl.java | 271 +++--- .../reference/RefFieldImpl.java | 68 +- .../reference/RefImplicitConstructorImpl.java | 25 +- .../reference/RefJavaElementImpl.java | 94 +- .../reference/RefJavaFileImpl.java | 12 +- .../reference/RefJavaManagerImpl.java | 343 ++++---- .../reference/RefJavaModuleImpl.java | 14 +- .../reference/RefJavaUtilImpl.java | 826 +++++++++++------- .../reference/RefMethodImpl.java | 198 +++-- .../reference/RefParameterImpl.java | 119 ++- .../SameReturnValueInspection.java | 26 +- .../UnnecessaryModuleDependencyAnnotator.java | 62 +- .../RedundantThrowsDeclarationInspection.java | 27 +- .../RedundantThrowsGraphAnnotator.java | 2 +- .../visibility/VisibilityInspection.java | 28 +- .../codeInspection/MakeVoidQuickFix.java | 2 +- .../deadCode/DeadHTMLComposer.java | 7 +- .../deadCode/UnusedDeclarationInspection.java | 22 +- .../UnusedDeclarationPresentation.java | 11 +- .../deadCode/UnusedParametersInspection.java | 52 +- .../emptyMethod/EmptyMethodInspection.java | 68 +- .../ex/GlobalJavaInspectionContextImpl.java | 67 +- .../ex/HTMLJavaHTMLComposerImpl.java | 24 +- .../SameParameterValueInspection.java | 6 +- .../unusedReturnValue/UnusedReturnValue.java | 2 +- .../deadCode/instanceOf/expected.xml | 2 + .../deadCode/instanceOf/src/Test.java | 9 + .../referenceParameterList/expected.xml | 4 + .../referenceParameterList/src/Test.java | 9 + .../deadCode/singleton/src/Main.java | 2 +- .../deadCode/singleton/src/Singleton.kt | 5 + .../emptyMethodsHierarchy/expected.xml | 2 +- .../additionalAnnotations/expected.xml | 4 + .../additionalAnnotations/src/Test.java | 9 + .../deadCode/annotationInterface/expected.xml | 9 + .../annotationInterface/src/Test.java | 6 + .../annotationUsedInPackageInfo/expected.xml | 4 + .../annotationUsedInPackageInfo/src/p/A.java | 11 + .../src/p/package-info.java | 2 + .../jvm/deadCode/chainOfCalls/expected.xml | 4 + .../jvm/deadCode/chainOfCalls/src/A.kt | 3 + .../jvm/deadCode/chainOfCalls/src/B.kt | 5 + .../jvm/deadCode/chainOfCalls/src/Main.kt | 3 + .../jvm/deadCode/classLiteralRef/expected.xml | 4 + .../jvm/deadCode/classLiteralRef/src/Test.kt | 10 + .../deadCode/constructorCalls/expected.xml | 4 + .../jvm/deadCode/constructorCalls/src/A.kt | 1 + .../jvm/deadCode/constructorCalls/src/B.kt | 3 + .../deadCode/defaultConstructor/expected.xml | 2 + .../deadCode/defaultConstructor/src/A.java | 18 + .../deadCode/enumInstantiation/expected.xml | 4 + .../jvm/deadCode/junitEntryPoint/expected.xml | 10 + .../jvm/deadCode/junitEntryPoint/src/Test.kt | 7 + .../jvm/deadCode/mutableCalls/expected.xml | 10 + .../jvm/deadCode/mutableCalls/src/A.java | 5 + .../jvm/deadCode/mutableCalls/src/B.kt | 3 + .../jvm/deadCode/mutableCalls/src/C.kt | 9 + .../deadCode/nonJvmReferences/expected.xml | 4 + .../deadCode/nonJvmReferences/ext_src/res.xml | 1 + .../jvm/deadCode/nonJvmReferences/src/Test.kt | 1 + .../expected.xml | 4 + .../src/Interface.java | 3 + .../src/Test.kt | 19 + .../expected.xml | 4 + .../src/Interface.java | 3 + .../reachableFromFieldInitializer/src/Test.kt | 16 + .../deadCode/reachableFromMain/expected.xml | 10 + .../jvm/deadCode/reachableFromMain/src/A.kt | 10 + .../jvm/deadCode/serializable/expected.xml | 3 + .../serializable/ext_src/External.java | 5 + .../jvm/deadCode/serializable/src/Test.java | 6 + .../jvm/deadCode/singleton/expected.xml | 4 + .../jvm/deadCode/singleton/src/Main.java | 5 + .../jvm/deadCode/singleton/src/Singleton.java | 7 + .../jvm/deadCode/staticMethods/expected.xml | 16 + .../jvm/deadCode/staticMethods/src/Test.kt | 12 + .../jvm/deadCode/unusedEnum/expected.xml | 14 + .../jvm/deadCode/unusedEnum/src/Test.java | 3 + .../deadCode/usagesInAnonymous/expected.xml | 4 + .../deadCode/usagesInAnonymous/src/Test.kt | 18 + .../entryPoint/expected.xml | 3 + .../sameParameterValue/entryPoint/src/Test.kt | 4 + .../methodWithSuper/expected.xml | 17 + .../methodWithSuper/src/Test.kt | 17 + .../negativeDouble/expected.xml | 10 + .../negativeDouble/src/Test.kt | 10 + .../sameParameterValue/varargs/expected.xml | 10 + .../sameParameterValue/varargs/src/Test.kt | 36 + .../jvm/sameReturnValue/java/expected.xml | 10 + .../jvm/sameReturnValue/java/src/Test.java | 10 + .../jvm/sameReturnValue/kotlin/expected.xml | 24 + .../jvm/sameReturnValue/kotlin/src/Test.kt | 28 + .../jvm/sameReturnValue/mixed/expected.xml | 17 + .../jvm/sameReturnValue/mixed/src/Bar.kt | 5 + .../jvm/sameReturnValue/mixed/src/Foo.java | 11 + .../sameParameterValue/field/expected.xml | 10 + .../sameParameterValue/field/src/Test.java | 13 + .../SameParameterValueTest.java | 4 + .../codeInspection/UnusedDeclarationTest.java | 8 + .../codeInspection/AnalysisUastUtil.java | 2 + .../intellij.jvm.analysis.kotlin.tests.iml | 1 + .../SameParameterValueInspectionJvmTest.java | 47 + .../SameReturnValueInspectionTest.java | 30 + .../UnusedDeclarationJvmTest.java | 76 ++ .../lang/RefManagerExtension.java | 8 + .../codeInspection/reference/RefElement.java | 9 +- .../codeInspection/reference/RefFile.java | 10 +- .../codeInspection/InspectionEngine.java | 2 +- .../codeInspection/ex/HTMLComposerImpl.java | 6 +- .../reference/RefDirectoryImpl.java | 2 +- .../reference/RefElementImpl.java | 12 +- .../codeInspection/reference/RefFileImpl.java | 6 +- .../reference/RefManagerImpl.java | 21 +- .../ex/InspectionRVContentProviderImpl.java | 2 +- .../codeInspection/ex/QuickFixAction.java | 4 +- .../OfflineDescriptorResolveResult.java | 2 +- .../ui/InspectionResultsView.java | 10 +- .../ui/InspectionResultsViewComparator.java | 4 +- .../ui/InspectionResultsViewUtil.java | 2 +- .../ui/ProblemDescriptionNode.java | 2 +- .../ui/SuppressableInspectionTreeNode.java | 2 +- .../actions/KeyAwareInspectionViewAction.java | 6 +- .../util/resources/misc/registry.properties | 3 + .../MethodReturnAlwaysConstantInspection.java | 21 +- .../ClassWithTooManyDependentsInspection.java | 5 +- ...oManyTransitiveDependenciesInspection.java | 5 +- ...TooManyTransitiveDependentsInspection.java | 3 +- .../CyclicClassDependencyInspection.java | 8 +- .../CyclicClassInitializationInspection.java | 3 +- .../ClassIndependentOfModuleInspection.java | 12 +- .../ClassOnlyUsedInOneModuleInspection.java | 12 +- .../ClassOnlyUsedInOnePackageInspection.java | 11 +- .../ClassUnconnectedToPackageInspection.java | 12 +- .../packaging/DisjointPackageInspection.java | 2 +- .../packaging/ExceptionPackageInspection.java | 7 +- .../src/com/siyeh/ig/psiutils/ClassUtils.java | 28 +- ...ticMethodOnlyUsedInOneClassInspection.java | 9 +- .../src/org/jetbrains/uast/UastUtils.kt | 12 +- .../uast/declarations/UDeclaration.kt | 18 +- .../uast/expressions/UThisExpression.kt | 2 +- .../JavaUObjectLiteralExpression.kt | 10 + 155 files changed, 2550 insertions(+), 1306 deletions(-) create mode 100644 java/java-tests/testData/inspection/deadCode/instanceOf/expected.xml create mode 100644 java/java-tests/testData/inspection/deadCode/instanceOf/src/Test.java create mode 100644 java/java-tests/testData/inspection/deadCode/referenceParameterList/expected.xml create mode 100644 java/java-tests/testData/inspection/deadCode/referenceParameterList/src/Test.java create mode 100644 java/java-tests/testData/inspection/deadCode/singleton/src/Singleton.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/additionalAnnotations/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/additionalAnnotations/src/Test.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/annotationInterface/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/annotationInterface/src/Test.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/src/p/A.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/src/p/package-info.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/A.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/B.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/Main.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/classLiteralRef/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/classLiteralRef/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/src/A.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/src/B.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/defaultConstructor/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/defaultConstructor/src/A.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/enumInstantiation/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/junitEntryPoint/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/junitEntryPoint/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/A.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/B.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/C.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/ext_src/res.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/src/Interface.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/src/Interface.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/reachableFromMain/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/reachableFromMain/src/A.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/serializable/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/serializable/ext_src/External.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/serializable/src/Test.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/singleton/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/singleton/src/Main.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/singleton/src/Singleton.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/staticMethods/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/staticMethods/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/unusedEnum/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/unusedEnum/src/Test.java create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/usagesInAnonymous/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/deadCode/usagesInAnonymous/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/sameParameterValue/entryPoint/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/sameParameterValue/entryPoint/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/sameParameterValue/methodWithSuper/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/sameParameterValue/methodWithSuper/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/sameParameterValue/negativeDouble/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/sameParameterValue/negativeDouble/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/sameParameterValue/varargs/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/sameParameterValue/varargs/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/sameReturnValue/java/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/sameReturnValue/java/src/Test.java create mode 100644 java/java-tests/testData/inspection/jvm/sameReturnValue/kotlin/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/sameReturnValue/kotlin/src/Test.kt create mode 100644 java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/expected.xml create mode 100644 java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/src/Bar.kt create mode 100644 java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/src/Foo.java create mode 100644 java/java-tests/testData/inspection/sameParameterValue/field/expected.xml create mode 100644 java/java-tests/testData/inspection/sameParameterValue/field/src/Test.java create mode 100644 jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/SameParameterValueInspectionJvmTest.java create mode 100644 jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/SameReturnValueInspectionTest.java create mode 100644 jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/UnusedDeclarationJvmTest.java diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java index a3c8d08c6d56..1962762dde5b 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefClass.java @@ -1,23 +1,14 @@ -/* - * Copyright 2000-2013 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; +import com.intellij.lang.jvm.JvmClass; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UClass; +import org.jetbrains.uast.UElement; import java.util.List; import java.util.Set; @@ -63,9 +54,24 @@ public interface RefClass extends RefJavaElement { boolean isLocalClass(); - boolean isSelfInheritor(PsiClass psiClass); + @SuppressWarnings("DeprecatedIsStillUsed") + @Deprecated + default boolean isSelfInheritor(PsiClass psiClass) { + throw new UnsupportedOperationException(); + } + + default boolean isSelfInheritor(UClass uClass) { + return isSelfInheritor((PsiClass) uClass); + } - @Nullable @Override - PsiClass getElement(); + default UClass getUastElement() { + throw new UnsupportedOperationException(); + } + + @Deprecated + @Override + default PsiClass getElement() { + return ObjectUtils.tryCast(getPsiElement(), PsiClass.class); + } } diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefField.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefField.java index 288e27605c01..37465888aed3 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefField.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefField.java @@ -17,6 +17,8 @@ package com.intellij.codeInspection.reference; import com.intellij.openapi.util.Key; import com.intellij.psi.PsiField; +import org.jetbrains.uast.UElement; +import org.jetbrains.uast.UField; /** * A node in the reference graph corresponding to a Java field. @@ -56,6 +58,12 @@ public interface RefField extends RefJavaElement { */ RefClass getOwnerClass(); + @Deprecated @Override PsiField getElement(); + + @Override + default UField getUastElement() { + throw new UnsupportedOperationException(); + } } diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefImplicitConstructor.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefImplicitConstructor.java index 036bdd6aaa2c..3a56eaaf02e7 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefImplicitConstructor.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefImplicitConstructor.java @@ -15,6 +15,8 @@ */ package com.intellij.codeInspection.reference; +import org.jetbrains.annotations.NotNull; + /** * A node in the reference graph corresponding to the implicit constructor of a Java class. * @@ -22,4 +24,8 @@ package com.intellij.codeInspection.reference; * @since 6.0 */ public interface RefImplicitConstructor extends RefMethod { + @NotNull + default RefClass getOwnerClass() { + throw new UnsupportedOperationException(); + } } diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaElement.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaElement.java index d540db04e4f4..653db17960e5 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaElement.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaElement.java @@ -1,29 +1,34 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; +import com.intellij.lang.jvm.JvmElement; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiModifier; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UElement; import java.util.Collection; public interface RefJavaElement extends RefElement { - /** + + @Deprecated + default PsiElement getElement() { + throw new UnsupportedOperationException(); + } + + default PsiElement getPsiElement() { + //noinspection deprecation + return getElement(); + } + + default UElement getUastElement() { + throw new UnsupportedOperationException(); + } + + /** * Returns the collection of references used in this element. * @return the collection of used types */ diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java index 5bedb239dbef..dbc9edf78aea 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaManager.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; @@ -20,12 +6,18 @@ import com.intellij.codeInspection.ex.EntryPointsManager; import com.intellij.codeInspection.lang.RefManagerExtension; import com.intellij.lang.Language; import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.registry.Registry; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiParameter; +import com.intellij.uast.UastMetaLanguage; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.uast.UParameter; + +import java.util.ArrayList; +import java.util.Collection; public abstract class RefJavaManager implements RefManagerExtension { @NonNls public static final String CLASS = "class"; @@ -54,10 +46,13 @@ public abstract class RefJavaManager implements RefManagerExtension getLanguages() { + ArrayList languages = new ArrayList<>(Language.findInstance(UastMetaLanguage.class).getMatchingLanguages()); + // TODO uast is not implemented in case of groovy + languages.removeIf(l -> l.isKindOf("Groovy")); + + // TODO enable it in production when will be ready + if (Registry.is("batch.jvm.inspections") || !ApplicationManager.getApplication().isUnitTestMode()) { + languages.removeIf(l -> l.isKindOf("kotlin")); + } + return languages; + } + @NotNull @Override public Language getLanguage() { diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaModule.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaModule.java index 5c5ffd7a1371..5e0afcb16faa 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaModule.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaModule.java @@ -16,6 +16,7 @@ package com.intellij.codeInspection.reference; import com.intellij.openapi.util.Key; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiJavaModule; import org.jetbrains.annotations.NotNull; @@ -30,7 +31,7 @@ public interface RefJavaModule extends RefElement { Key JAVA_MODULE = Key.create("JAVA_MODULE"); @Override - PsiJavaModule getElement(); + PsiJavaModule getPsiElement(); @NotNull Map> getExportedPackageNames(); diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaUtil.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaUtil.java index 7390d084d819..3d7a48b531dd 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaUtil.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefJavaUtil.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2014 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; @@ -20,10 +6,19 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclaration; +import org.jetbrains.uast.UElement; +import org.jetbrains.uast.UExpression; +import org.jetbrains.uast.UMethod; public abstract class RefJavaUtil { + @Deprecated public abstract void addReferences(@NotNull PsiModifierListOwner psiFrom, @NotNull RefJavaElement ref, @Nullable PsiElement findIn); + public void addReferencesTo(@NotNull UDeclaration decl, @NotNull RefJavaElement ref, @Nullable UElement... findIn) { + throw new UnsupportedOperationException("Should be implemented"); + } + public abstract RefClass getTopLevelClass(@NotNull RefElement refElement); public abstract boolean isInheritor(@NotNull RefClass subClass, RefClass superClass); @@ -32,7 +27,15 @@ public abstract class RefJavaUtil { public abstract String getPackageName(RefEntity refEntity); @Nullable - public abstract RefClass getOwnerClass(RefManager refManager, PsiElement psiElement); + public RefClass getOwnerClass(RefManager refManager, UElement uElement) { + throw new UnsupportedOperationException(); + } + + @Deprecated + @Nullable + public RefClass getOwnerClass(RefManager refManager, PsiElement psiElement) { + throw new UnsupportedOperationException(); + } @Nullable public abstract RefClass getOwnerClass(RefElement refElement); @@ -40,7 +43,7 @@ public abstract class RefJavaUtil { public abstract int compareAccess(String a1, String a2); @NotNull - public abstract String getAccessModifier(@NotNull PsiModifierListOwner psiElement); + public abstract String getAccessModifier(@NotNull PsiModifierListOwner modifiersOwner); public abstract void setAccessModifier(@NotNull RefJavaElement refElement, @NotNull String newAccess); @@ -48,7 +51,14 @@ public abstract class RefJavaUtil { public abstract void setIsFinal(RefJavaElement refElement, boolean isFinal); - public abstract boolean isMethodOnlyCallsSuper(final PsiMethod derivedMethod); + public boolean isMethodOnlyCallsSuper(UMethod derivedMethod) { + throw new UnsupportedOperationException(); + } + + @Deprecated + public boolean isMethodOnlyCallsSuper(PsiMethod derivedMethod) { + throw new UnsupportedOperationException(); + } public static boolean isDeprecated(PsiElement psiResolved) { return psiResolved instanceof PsiDocCommentOwner && ((PsiDocCommentOwner)psiResolved).isDeprecated(); @@ -56,17 +66,39 @@ public abstract class RefJavaUtil { @Nullable public static RefPackage getPackage(RefEntity refEntity) { - while (refEntity != null && !(refEntity instanceof RefPackage)) refEntity = refEntity.getOwner(); + while (refEntity != null && !(refEntity instanceof RefPackage)) refEntity = refEntity.getOwner(); - return (RefPackage)refEntity; - } + return (RefPackage)refEntity; + } public static RefJavaUtil getInstance() { return ServiceManager.getService(RefJavaUtil.class); } - public abstract boolean isCallToSuperMethod(PsiExpression expression, PsiMethod method); + public boolean isCallToSuperMethod(UExpression expression, UMethod method) { + throw new UnsupportedOperationException(); + } - public abstract void addTypeReference(PsiElement psiElement, PsiType psiType, RefManager refManager); - public abstract void addTypeReference(PsiElement psiElement, PsiType psiType, RefManager refManager, @Nullable RefJavaElement refElement); + public void addTypeReference(UElement uElement, PsiType psiType, RefManager refManager) { + throw new UnsupportedOperationException(); + } + + public void addTypeReference(UElement uElement, PsiType psiType, RefManager refManager, @Nullable RefJavaElement refElement) { + throw new UnsupportedOperationException(); + } + + @Deprecated + public boolean isCallToSuperMethod(PsiExpression expression, PsiMethod method) { + throw new UnsupportedOperationException(); + } + + @Deprecated + public void addTypeReference(PsiElement psiElement, PsiType psiType, RefManager refManager) { + throw new UnsupportedOperationException(); + } + + @Deprecated + public void addTypeReference(PsiElement psiElement, PsiType psiType, RefManager refManager, @Nullable RefJavaElement refElement) { + throw new UnsupportedOperationException(); + } } diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefMethod.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefMethod.java index c11179569eb6..7fc079d55a7a 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefMethod.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefMethod.java @@ -17,9 +17,14 @@ package com.intellij.codeInspection.reference; import com.intellij.codeInspection.GlobalInspectionTool; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifierListOwner; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclaration; +import org.jetbrains.uast.UMethod; import java.util.Collection; @@ -155,10 +160,19 @@ public interface RefMethod extends RefJavaElement { * * @return the class instance. */ + @Nullable RefClass getOwnerClass(); + @Deprecated @Override - PsiModifierListOwner getElement(); + default PsiModifierListOwner getElement() { + return ObjectUtils.tryCast(getPsiElement(), PsiModifierListOwner.class); + } + + @Override + default UDeclaration getUastElement() { + throw new UnsupportedOperationException(); + } boolean isCalledOnSubClass(); } diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefParameter.java b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefParameter.java index d297aa26afa5..8ed050df56de 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefParameter.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/reference/RefParameter.java @@ -2,7 +2,9 @@ package com.intellij.codeInspection.reference; import com.intellij.psi.PsiParameter; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UParameter; /** * A node in the reference graph corresponding to a Java method parameter. @@ -11,8 +13,8 @@ import org.jetbrains.annotations.Nullable; * @since 6.0 */ public interface RefParameter extends RefJavaElement { - Object VALUE_IS_NOT_CONST = new Object(); - Object VALUE_UNDEFINED = new Object(); + Object VALUE_IS_NOT_CONST = ObjectUtils.sentinel("VALUE_IS_NOT_CONST"); + Object VALUE_UNDEFINED = ObjectUtils.sentinel("VALUE_UNDEFINED"); /** * Checks if the parameter is used for reading. @@ -67,7 +69,15 @@ public interface RefParameter extends RefJavaElement { void parameterReferenced(final boolean forWriting); @Override - PsiParameter getElement(); + default UParameter getUastElement() { + throw new UnsupportedOperationException(); + } + + @Deprecated + @Override + default PsiParameter getElement() { + return ObjectUtils.tryCast(getPsiElement(), PsiParameter.class); + } default int getUsageCount() { throw new UnsupportedOperationException(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java b/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java index 667621488b90..9684d9eca0c8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalAnnotator.java @@ -20,8 +20,12 @@ import com.intellij.codeInspection.reference.*; import com.intellij.psi.*; import com.intellij.psi.controlFlow.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiTypesUtil; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.uast.UClass; +import org.jetbrains.uast.UTypeReferenceExpression; import java.util.*; @@ -43,15 +47,16 @@ class CanBeFinalAnnotator extends RefGraphAnnotatorEx { ((RefElementImpl)refElement).setFlag(true, CAN_BE_FINAL_MASK); if (refElement instanceof RefClass) { final RefClass refClass = (RefClass)refElement; - final PsiClass psiClass = refClass.getElement(); + final UClass psiClass = refClass.getUastElement(); if (refClass.isEntry()) { ((RefClassImpl)refClass).setFlag(false, CAN_BE_FINAL_MASK); return; } if (psiClass != null && !refClass.isSelfInheritor(psiClass)) { - for (PsiClass psiSuperClass : psiClass.getSupers()) { - if (myManager.belongsToScope(psiSuperClass)) { - RefClass refSuperClass = (RefClass)myManager.getReference(psiSuperClass); + for (UTypeReferenceExpression superRef : psiClass.getUastSuperTypes()) { + PsiElement psi = PsiTypesUtil.getPsiClass(superRef.getType()); + if (myManager.belongsToScope(psi)) { + RefClass refSuperClass = (RefClass)myManager.getReference(psi); if (refSuperClass != null) { ((RefClassImpl)refSuperClass).setFlag(false, CAN_BE_FINAL_MASK); } @@ -64,16 +69,17 @@ class CanBeFinalAnnotator extends RefGraphAnnotatorEx { } else if (refElement instanceof RefMethod) { final RefMethod refMethod = (RefMethod)refElement; - final PsiElement element = refMethod.getElement(); + final PsiElement element = refMethod.getPsiElement(); if (element instanceof PsiMethod) { PsiMethod psiMethod = (PsiMethod)element; + RefClass aClass = refMethod.getOwnerClass(); if (refMethod.isConstructor() || refMethod.isAbstract() || refMethod.isStatic() || - PsiModifier.PRIVATE.equals(refMethod.getAccessModifier()) || refMethod.getOwnerClass().isAnonymous() || - refMethod.getOwnerClass().isInterface()) { + PsiModifier.PRIVATE.equals(refMethod.getAccessModifier()) || (aClass != null && aClass.isAnonymous()) || + (aClass != null && aClass.isInterface())) { ((RefMethodImpl)refMethod).setFlag(false, CAN_BE_FINAL_MASK); } if (PsiModifier.PRIVATE.equals(refMethod.getAccessModifier()) && refMethod.getOwner() != null && - !(refMethod.getOwnerClass().getOwner() instanceof RefElement)) { + !(aClass != null && aClass.getOwner() instanceof RefElement)) { ((RefMethodImpl)refMethod).setFlag(false, CAN_BE_FINAL_MASK); } for (PsiMethod psiSuperMethod : psiMethod.findSuperMethods()) { @@ -87,7 +93,7 @@ class CanBeFinalAnnotator extends RefGraphAnnotatorEx { } } else if (refElement instanceof RefField) { - final PsiElement element = refElement.getElement(); + final PsiElement element = refElement.getPsiElement(); if (element != null && RefUtil.isImplicitWrite(element)) { ((RefElementImpl)refElement).setFlag(false, CAN_BE_FINAL_MASK); } @@ -105,7 +111,7 @@ class CanBeFinalAnnotator extends RefGraphAnnotatorEx { if (!(refWhat instanceof RefField)) return; if (!(refFrom instanceof RefMethod) || !((RefMethod)refFrom).isConstructor() || - ((PsiField)refWhat.getElement()).hasInitializer() || + ((RefField)refWhat).getUastElement().getUastInitializer() != null || ((RefMethod)refFrom).getOwnerClass() != ((RefField)refWhat).getOwnerClass() || ((RefField)refWhat).isStatic()) { if (forWriting && @@ -121,7 +127,7 @@ class CanBeFinalAnnotator extends RefGraphAnnotatorEx { @Override public void onReferencesBuild(RefElement refElement) { if (refElement instanceof RefClass) { - final PsiClass psiClass = (PsiClass)refElement.getElement(); + final PsiClass psiClass = ObjectUtils.tryCast(refElement.getPsiElement(), PsiClass.class); if (psiClass != null) { if (refElement.isEntry()) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java index bdfaf7eb2b58..3bab2d10dd27 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java @@ -26,6 +26,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -119,7 +120,7 @@ public class CanBeFinalInspection extends GlobalJavaBatchInspectionTool { if (refElement.isFinal()) return null; if (!((RefElementImpl)refElement).checkFlag(CanBeFinalAnnotator.CAN_BE_FINAL_MASK)) return null; - final PsiMember psiMember = (PsiMember)refElement.getElement(); + final PsiMember psiMember = ObjectUtils.tryCast(refElement.getPsiElement(), PsiMember.class); if (psiMember == null || !CanBeFinalHandler.allowToBeFinal(psiMember)) return null; PsiIdentifier psiIdentifier = null; @@ -166,26 +167,20 @@ public class CanBeFinalInspection extends GlobalJavaBatchInspectionTool { @Override public void visitMethod(@NotNull final RefMethod refMethod) { if (!refMethod.isStatic() && !PsiModifier.PRIVATE.equals(refMethod.getAccessModifier()) && !(refMethod instanceof RefImplicitConstructor)) { - globalContext.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { - @Override - public boolean process(PsiMethod derivedMethod) { - ((RefElementImpl)refMethod).setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); - problemsProcessor.ignoreElement(refMethod); - return false; - } + globalContext.enqueueDerivedMethodsProcessor(refMethod, derivedMethod -> { + ((RefElementImpl)refMethod).setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); + problemsProcessor.ignoreElement(refMethod); + return false; }); } } @Override public void visitClass(@NotNull final RefClass refClass) { if (!refClass.isAnonymous()) { - globalContext.enqueueDerivedClassesProcessor(refClass, new GlobalJavaInspectionContext.DerivedClassesProcessor() { - @Override - public boolean process(PsiClass inheritor) { - ((RefClassImpl)refClass).setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); - problemsProcessor.ignoreElement(refClass); - return false; - } + globalContext.enqueueDerivedClassesProcessor(refClass, inheritor -> { + ((RefClassImpl)refClass).setFlag(false, CanBeFinalAnnotator.CAN_BE_FINAL_MASK); + problemsProcessor.ignoreElement(refClass); + return false; }); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspectionBase.java index 8940969d6e0a..b8e3a6043c2b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspectionBase.java @@ -36,6 +36,7 @@ import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; +import org.jetbrains.uast.*; import java.util.*; @@ -167,64 +168,64 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { } } - private static boolean isExternalizableNoParameterConstructor(@NotNull PsiMethod method, RefClass refClass) { + private static boolean isExternalizableNoParameterConstructor(@NotNull UMethod method, RefClass refClass) { if (!method.isConstructor()) return false; - if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return false; - final PsiParameterList parameterList = method.getParameterList(); + if (method.getVisibility() != UastVisibility.PUBLIC) return false; + final List parameterList = method.getUastParameters(); if (!parameterList.isEmpty()) return false; - final PsiClass aClass = method.getContainingClass(); + final UClass aClass = UDeclarationKt.getContainingDeclaration(method, UClass.class); return aClass == null || isExternalizable(aClass, refClass); } - private static boolean isSerializationImplicitlyUsedField(@NotNull PsiField field) { + private static boolean isSerializationImplicitlyUsedField(@NotNull UField field) { final String name = field.getName(); if (!HighlightUtilBase.SERIAL_VERSION_UID_FIELD_NAME.equals(name) && !"serialPersistentFields".equals(name)) return false; - if (!field.hasModifierProperty(PsiModifier.STATIC)) return false; - PsiClass aClass = field.getContainingClass(); + if (!field.isStatic()) return false; + UClass aClass = UDeclarationKt.getContainingDeclaration(field, UClass.class); return aClass == null || isSerializable(aClass, null); } - private static boolean isWriteObjectMethod(@NotNull PsiMethod method, RefClass refClass) { + private static boolean isWriteObjectMethod(@NotNull UMethod method, RefClass refClass) { final String name = method.getName(); if (!"writeObject".equals(name)) return false; - PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 1) return false; - if (!equalsToText(parameters[0].getType(), "java.io.ObjectOutputStream")) return false; - if (method.hasModifierProperty(PsiModifier.STATIC)) return false; - PsiClass aClass = method.getContainingClass(); + List parameters = method.getUastParameters(); + if (parameters.size() != 1) return false; + if (!equalsToText(parameters.get(0).getType(), "java.io.ObjectOutputStream")) return false; + if (method.isStatic()) return false; + UClass aClass = UDeclarationKt.getContainingDeclaration(method, UClass.class); return !(aClass != null && !isSerializable(aClass, refClass)); } - private static boolean isReadObjectMethod(@NotNull PsiMethod method, RefClass refClass) { + private static boolean isReadObjectMethod(@NotNull UMethod method, RefClass refClass) { final String name = method.getName(); if (!"readObject".equals(name)) return false; - PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 1) return false; - if (!equalsToText(parameters[0].getType(), "java.io.ObjectInputStream")) return false; - if (method.hasModifierProperty(PsiModifier.STATIC)) return false; - PsiClass aClass = method.getContainingClass(); + List parameters = method.getUastParameters(); + if (parameters.size() != 1) return false; + if (!equalsToText(parameters.get(0).getType(), "java.io.ObjectInputStream")) return false; + if (method.isStatic()) return false; + UClass aClass = UDeclarationKt.getContainingDeclaration(method, UClass.class); return !(aClass != null && !isSerializable(aClass, refClass)); } - private static boolean isWriteReplaceMethod(@NotNull PsiMethod method, RefClass refClass) { + private static boolean isWriteReplaceMethod(@NotNull UMethod method, RefClass refClass) { final String name = method.getName(); if (!"writeReplace".equals(name)) return false; - PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 0) return false; + List parameters = method.getUastParameters(); + if (parameters.size() != 0) return false; if (!equalsToText(method.getReturnType(), CommonClassNames.JAVA_LANG_OBJECT)) return false; - if (method.hasModifierProperty(PsiModifier.STATIC)) return false; - PsiClass aClass = method.getContainingClass(); + if (method.isStatic()) return false; + UClass aClass = UDeclarationKt.getContainingDeclaration(method, UClass.class); return !(aClass != null && !isSerializable(aClass, refClass)); } - private static boolean isReadResolveMethod(@NotNull PsiMethod method, RefClass refClass) { + private static boolean isReadResolveMethod(@NotNull UMethod method, RefClass refClass) { final String name = method.getName(); if (!"readResolve".equals(name)) return false; - PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 0) return false; + List parameters = method.getUastParameters(); + if (parameters.size() != 0) return false; if (!equalsToText(method.getReturnType(), CommonClassNames.JAVA_LANG_OBJECT)) return false; - if (method.hasModifierProperty(PsiModifier.STATIC)) return false; - final PsiClass aClass = method.getContainingClass(); + if (method.isStatic()) return false; + final UClass aClass = UDeclarationKt.getContainingDeclaration(method, UClass.class); return !(aClass != null && !isSerializable(aClass, refClass)); } @@ -232,24 +233,26 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { return type != null && type.equalsToText(text); } - private static boolean isSerializable(PsiClass aClass, @Nullable RefClass refClass) { - final PsiClass serializableClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.io.Serializable", aClass.getResolveScope()); + private static boolean isSerializable(UClass aClass, @Nullable RefClass refClass) { + PsiClass psi = aClass.getPsi(); + final PsiClass serializableClass = JavaPsiFacade.getInstance(psi.getProject()).findClass("java.io.Serializable", psi.getResolveScope()); return serializableClass != null && isSerializable(aClass, refClass, serializableClass); } - private static boolean isExternalizable(@NotNull PsiClass aClass, RefClass refClass) { - final GlobalSearchScope scope = aClass.getResolveScope(); - final PsiClass externalizableClass = JavaPsiFacade.getInstance(aClass.getProject()).findClass("java.io.Externalizable", scope); + private static boolean isExternalizable(@NotNull UClass aClass, RefClass refClass) { + PsiClass psi = aClass.getPsi(); + final PsiClass externalizableClass = JavaPsiFacade.getInstance(psi.getProject()).findClass("java.io.Externalizable", psi.getResolveScope()); return externalizableClass != null && isSerializable(aClass, refClass, externalizableClass); } - private static boolean isSerializable(PsiClass aClass, RefClass refClass, PsiClass serializableClass) { + private static boolean isSerializable(UClass aClass, RefClass refClass, PsiClass serializableClass) { if (aClass == null) return false; - if (aClass.isInheritor(serializableClass, true)) return true; + if (aClass.getJavaPsi().isInheritor(serializableClass, true)) return true; if (refClass != null) { final Set subClasses = refClass.getSubClasses(); for (RefClass subClass : subClasses) { - if (isSerializable(subClass.getElement(), subClass, serializableClass)) return true; + //TODO reimplement + if (isSerializable(subClass.getUastElement(), subClass, serializableClass)) return true; } } return false; @@ -303,7 +306,7 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { } private void findExternalClassReferences(final RefClass refElement) { - final PsiClass psiClass = refElement.getElement(); + final UClass psiClass = refElement.getUastElement(); String qualifiedName = psiClass != null ? psiClass.getQualifiedName() : null; if (qualifiedName != null) { final GlobalSearchScope projectScope = GlobalSearchScope.projectScope(globalContext.getProject()); @@ -339,7 +342,13 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { } public boolean isEntryPoint(@NotNull RefElement owner) { - final PsiElement element = owner.getElement(); + PsiElement element = owner.getPsiElement(); + if (owner instanceof RefJavaElement) { + UElement uElement = ((RefJavaElement)owner).getUastElement(); + if (uElement != null) { + element = uElement.getJavaPsi(); + } + } if (RefUtil.isImplicitUsage(element)) return true; if (element instanceof PsiModifierListOwner) { final EntryPointsManager entryPointsManager = EntryPointsManager.getInstance(element.getProject()); @@ -460,8 +469,8 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { @Override public void visitField(@NotNull final RefField refField) { myProcessedSuspicious.add(refField); - PsiField psiField = refField.getElement(); - if (psiField != null && isSerializationImplicitlyUsedField(psiField)) { + UField uField = refField.getUastElement(); + if (uField != null && isSerializationImplicitlyUsedField(uField)) { getEntryPointsManager(globalContext).addEntryPoint(refField, false); } else { @@ -480,8 +489,8 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { visitClass(refMethod.getOwnerClass()); } else { - PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); - if (psiMethod != null && isSerializablePatternMethod(psiMethod, refMethod.getOwnerClass())) { + UMethod uMethod = (UMethod)refMethod.getUastElement(); + if (uMethod != null && isSerializablePatternMethod(uMethod, refMethod.getOwnerClass())) { getEntryPointsManager(globalContext).addEntryPoint(refMethod, false); } else if (!refMethod.isExternalOverride() && !PsiModifier.PRIVATE.equals(refMethod.getAccessModifier())) { @@ -527,7 +536,7 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { return true; } - private static boolean isSerializablePatternMethod(@NotNull PsiMethod psiMethod, RefClass refClass) { + private static boolean isSerializablePatternMethod(@NotNull UMethod psiMethod, RefClass refClass) { return isReadObjectMethod(psiMethod, refClass) || isWriteObjectMethod(psiMethod, refClass) || isReadResolveMethod(psiMethod, refClass) || isWriteReplaceMethod(psiMethod, refClass) || isExternalizableNoParameterConstructor(psiMethod, refClass); } @@ -598,7 +607,7 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { addInstantiatedClass(method.getOwnerClass()); } else { - ((RefClassImpl)method.getOwnerClass()).setReachable(true); + ((RefElementImpl)method.getOwner()).setReachable(true); } myProcessedMethods.add(method); makeContentReachable((RefJavaElementImpl)method); @@ -662,9 +671,11 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { } } - private void makeClassInitializersReachable(RefClass refClass) { - for (RefElement refCallee : refClass.getOutReferences()) { - refCallee.accept(this); + private void makeClassInitializersReachable(@Nullable RefClass refClass) { + if (refClass != null) { + for (RefElement refCallee : refClass.getOutReferences()) { + refCallee.accept(this); + } } } @@ -678,7 +689,7 @@ public class UnusedDeclarationInspectionBase extends GlobalInspectionTool { } private boolean isClassInstantiated(RefClass refClass) { - return myInstantiatedClasses.contains(refClass); + return refClass == null || refClass.isUtilityClass() || myInstantiatedClasses.contains(refClass); } private int newlyInstantiatedClassesCount() { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerBase.java index 198127b84254..daa713019df2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerBase.java @@ -340,7 +340,7 @@ public abstract class EntryPointsManagerBase extends EntryPointsManager implemen ((RefElementImpl)anEntryPoint).setEntry(false); if (anEntryPoint.isPermanentEntry() && anEntryPoint.isValid()) { - final Project project = anEntryPoint.getElement().getProject(); + final Project project = anEntryPoint.getPsiElement().getProject(); final EntryPointsManager entryPointsManager = getInstance(project); if (this != entryPointsManager) { entryPointsManager.removeEntryPoint(anEntryPoint); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9RedundantRequiresStatementInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9RedundantRequiresStatementInspection.java index a2a8ac22bd56..5326936fd550 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9RedundantRequiresStatementInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/java19modules/Java9RedundantRequiresStatementInspection.java @@ -48,7 +48,7 @@ public class Java9RedundantRequiresStatementInspection extends GlobalJavaBatchIn RefJavaModule refJavaModule = (RefJavaModule)refEntity; RefModule refModule = refJavaModule.getModule(); - PsiJavaModule psiJavaModule = refJavaModule.getElement(); + PsiJavaModule psiJavaModule = refJavaModule.getPsiElement(); if (refModule != null && psiJavaModule != null) { Set moduleImportedPackages = refModule.getUserData(IMPORTED_JAVA_PACKAGES); if (moduleImportedPackages != null) { @@ -203,7 +203,7 @@ public class Java9RedundantRequiresStatementInspection extends GlobalJavaBatchIn public void onReferencesBuild(RefElement refElement) { if (refElement instanceof RefFile) { RefFile refFile = (RefFile)refElement; - PsiFile file = refFile.getElement(); + PsiFile file = refFile.getPsiElement(); if (file instanceof PsiJavaFile) { onJavaFileReferencesBuilt(refFile, (PsiJavaFile)file); } @@ -211,7 +211,7 @@ public class Java9RedundantRequiresStatementInspection extends GlobalJavaBatchIn else if (refElement instanceof RefJavaModule) { RefModule refModule = refElement.getModule(); if (refModule != null) { - setImportedPackages(refModule, refElement.getElement() != null); + setImportedPackages(refModule, refElement.getPsiElement() != null); } } } @@ -256,7 +256,7 @@ public class Java9RedundantRequiresStatementInspection extends GlobalJavaBatchIn private static Set getImportedPackages(@NotNull RefModule refModule, @NotNull RefFile refFile) { Set importedPackages = refModule.getUserData(IMPORTED_JAVA_PACKAGES); if (importedPackages == null) { - PsiJavaModule javaModule = JavaModuleGraphUtil.findDescriptorByElement(refFile.getElement()); + PsiJavaModule javaModule = JavaModuleGraphUtil.findDescriptorByElement(refFile.getPsiElement()); importedPackages = javaModule != null ? new THashSet<>() : DONT_COLLECT_PACKAGES; refModule.putUserData(IMPORTED_JAVA_PACKAGES, importedPackages); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java index 6507c64c727a..a4815c6cd05d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefClassImpl.java @@ -1,39 +1,33 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; import com.intellij.codeInsight.TestFrameworks; +import com.intellij.lang.Language; import com.intellij.lang.injection.InjectedLanguageManager; +import com.intellij.lang.jvm.JvmClass; +import com.intellij.lang.jvm.JvmField; +import com.intellij.lang.jvm.JvmMetaLanguage; +import com.intellij.lang.jvm.JvmModifier; +import com.intellij.lang.jvm.util.JvmInheritanceUtil; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.psi.*; import com.intellij.psi.util.ClassUtil; import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; +import com.siyeh.ig.psiutils.ClassUtils; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; public class RefClassImpl extends RefJavaElementImpl implements RefClass { private static final Set EMPTY_SET = Collections.emptySet(); @@ -59,9 +53,9 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { private List myClassExporters;//guarded by this private final RefModule myRefModule; - RefClassImpl(PsiClass psiClass, RefManager manager) { - super(psiClass, manager); - myRefModule = manager.getRefModule(ModuleUtilCore.findModuleForPsiElement(psiClass)); + RefClassImpl(UClass uClass, PsiElement psi, RefManager manager) { + super(uClass, psi, manager); + myRefModule = manager.getRefModule(ModuleUtilCore.findModuleForPsiElement(psi)); } @Override @@ -70,100 +64,115 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { myDefaultConstructor = null; } - final PsiClass psiClass = getElement(); + UClass uClass = getUastElement(); - LOG.assertTrue(psiClass != null); + LOG.assertTrue(uClass != null); - PsiElement psiParent = psiClass.getParent(); - if (psiParent instanceof PsiFile) { + UElement parent = UDeclarationKt.getContainingDeclaration(uClass); + while (parent != null) { + if (parent instanceof UMethod || parent instanceof UClass || parent instanceof UField) { + break; + } + parent = UDeclarationKt.getContainingDeclaration(uClass); + } + if (parent != null) { + RefElement refParent = getRefManager().getReference(parent.getSourcePsi()); + LOG.assertTrue(refParent != null); + ((RefElementImpl)refParent).add(this); + } else { + PsiFile containingFile = getContainingFile(); if (isSyntheticJSP()) { - final RefFileImpl refFile = (RefFileImpl)getRefManager().getReference(getJspFile(psiClass)); + final PsiFile psiFile = PsiUtilCore.getTemplateLanguageFile(getPsiElement()); + final RefFileImpl refFile = (RefFileImpl)getRefManager().getReference(psiFile); LOG.assertTrue(refFile != null); refFile.add(this); } - else if (psiParent instanceof PsiJavaFile) { - PsiJavaFile psiFile = (PsiJavaFile)psiParent; - String packageName = psiFile.getPackageName(); + else if (isKindOfJvmLanguage(containingFile.getLanguage())) { + String packageName = UastContextKt.toUElement(containingFile, UFile.class).getPackageName(); if (!packageName.isEmpty()) { ((RefPackageImpl)getRefJavaManager().getPackage(packageName)).add(this); } else { ((RefPackageImpl)getRefJavaManager().getDefaultPackage()).add(this); } + } else { + final Module module = ModuleUtilCore.findModuleForPsiElement(containingFile); + LOG.assertTrue(module != null); + final RefModuleImpl refModule = (RefModuleImpl)getRefManager().getRefModule(module); + LOG.assertTrue(refModule != null); + refModule.add(this); } - final Module module = ModuleUtilCore.findModuleForPsiElement(psiClass); - LOG.assertTrue(module != null); - final RefModuleImpl refModule = (RefModuleImpl)getRefManager().getRefModule(module); - LOG.assertTrue(refModule != null); - refModule.add(this); - } - else { - while (!(psiParent instanceof PsiClass || psiParent instanceof PsiMethod || psiParent instanceof PsiField)) { - psiParent = psiParent.getParent(); - } - RefElement refParent = getRefManager().getReference(psiParent); - LOG.assertTrue(refParent != null); - ((RefElementImpl)refParent).add(this); } - setAbstract(psiClass.hasModifierProperty(PsiModifier.ABSTRACT)); + PsiClass javaPsi = uClass.getJavaPsi(); + setAbstract(javaPsi.hasModifier(JvmModifier.ABSTRACT)); + setAnonymous(uClass.getName() == null); - setAnonymous(psiClass instanceof PsiAnonymousClass); - setIsLocal(!(isAnonymous() || psiParent instanceof PsiClass || psiParent instanceof PsiFile)); - setInterface(psiClass.isInterface()); + setIsLocal(!(isAnonymous() || parent instanceof UClass || parent instanceof UFile)); - initializeSuperReferences(psiClass); + setInterface(uClass.isInterface()); - PsiMethod[] psiMethods = psiClass.getMethods(); - PsiField[] psiFields = psiClass.getFields(); + initializeSuperReferences(uClass); - setUtilityClass(psiMethods.length > 0 || psiFields.length > 0); + UMethod[] uMethods = uClass.getMethods(); + UField[] uFields = uClass.getFields(); - for (PsiField psiField : psiFields) { - getRefManager().getReference(psiField); + boolean utilityClass = uMethods.length > 0 || uFields.length > 0; + + for (UField uField : uFields) { + getRefManager().getReference(uField.getSourcePsi()); } if (!isApplet()) { - final PsiClass servlet = getRefJavaManager().getServlet(); - setServlet(servlet != null && psiClass.isInheritor(servlet, true)); + setServlet(JvmInheritanceUtil.isInheritor(javaPsi, getRefJavaManager().getServletQName())); } if (!isApplet() && !isServlet()) { - final boolean isTestClass = TestFrameworks.getInstance().isTestClass(psiClass); - setTestCase(isTestClass); - if (isTestClass) { - for (RefClass refBase : getBaseClasses()) { - ((RefClassImpl)refBase).setTestCase(true); + PsiElement psi = uClass.getSourcePsi(); + if (psi instanceof PsiClass) { + final boolean isTestClass = TestFrameworks.getInstance().isTestClass((PsiClass)psi); + setTestCase(isTestClass); + if (isTestClass) { + for (RefClass refBase : getBaseClasses()) { + ((RefClassImpl)refBase).setTestCase(true); + } } } } RefMethod varargConstructor = null; - for (PsiMethod psiMethod : psiMethods) { - RefMethod refMethod = (RefMethod)getRefManager().getReference(psiMethod); + for (UMethod uMethod : uMethods) { + RefMethod refMethod = ObjectUtils.tryCast(getRefManager().getReference(uMethod.getSourcePsi()), RefMethod.class); if (refMethod != null) { - if (psiMethod.isConstructor()) { - final PsiParameter[] parameters = psiMethod.getParameterList().getParameters(); - if (parameters.length > 0 || !psiMethod.hasModifierProperty(PsiModifier.PRIVATE)) { - setUtilityClass(false); + if (uMethod.isConstructor()) { + final List parameters = uMethod.getUastParameters(); + if (!parameters.isEmpty()|| uMethod.getVisibility() != UastVisibility.PRIVATE) { + utilityClass = false; } addConstructor(refMethod); - if (parameters.length == 0) { + if (parameters.isEmpty()) { setDefaultConstructor((RefMethodImpl)refMethod); } - else if (parameters.length == 1 && parameters[0].isVarArgs()) { - varargConstructor = refMethod; + else if (parameters.size() == 1) { + PsiElement parameterPsi = parameters.get(0).getJavaPsi(); + if (parameterPsi instanceof PsiParameter && ((PsiParameter)parameterPsi).isVarArgs()) { + varargConstructor = refMethod; + } } } else { - if (!psiMethod.hasModifierProperty(PsiModifier.STATIC)) { - setUtilityClass(false); + if (!uMethod.isStatic()) { + utilityClass = false; } } } } + if (!utilityClass) { + utilityClass = ClassUtils.isSingleton(uClass.getJavaPsi()); + } + if (varargConstructor != null && getDefaultConstructor() == null) { setDefaultConstructor((RefMethodImpl)varargConstructor); } @@ -175,53 +184,47 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { } if (isInterface()) { - for (int i = 0; i < psiFields.length && isUtilityClass(); i++) { - PsiField psiField = psiFields[i]; - if (!psiField.hasModifierProperty(PsiModifier.STATIC)) { - setUtilityClass(false); + for (int i = 0; i < uFields.length && isUtilityClass(); i++) { + JvmField psiField = uFields[i]; + if (!psiField.hasModifier(JvmModifier.STATIC)) { + utilityClass = false; } } } + setUtilityClass(utilityClass); final PsiClass applet = getRefJavaManager().getApplet(); - setApplet(applet != null && psiClass.isInheritor(applet, true)); + setApplet(applet != null && JvmInheritanceUtil.isInheritor(uClass, getRefJavaManager().getAppletQName())); + + //TODO what's the purpose? PsiManager psiManager = getRefManager().getPsiManager(); psiManager.dropResolveCaches(); - PsiFile file = psiClass.getContainingFile(); + PsiFile file = getContainingFile(); if (file != null) { InjectedLanguageManager.getInstance(file.getProject()).dropFileCaches(file); } } - private static ServerPageFile getJspFile(PsiClass psiClass) { - final PsiFile psiFile = PsiUtilCore.getTemplateLanguageFile(psiClass); - return psiFile instanceof ServerPageFile ? (ServerPageFile)psiFile : null; - } - - private void initializeSuperReferences(PsiClass psiClass) { - if (!isSelfInheritor(psiClass)) { - for (PsiClass psiSuperClass : psiClass.getSupers()) { - if (getRefManager().belongsToScope(psiSuperClass)) { - RefClassImpl refClass = (RefClassImpl)getRefManager().getReference(psiSuperClass); + private void initializeSuperReferences(UClass uClass) { + if (!isSelfInheritor(uClass)) { + uClass.getUastSuperTypes().stream() + .map(t -> PsiUtil.resolveClassInType(t.getType())) + .filter(Objects::nonNull) + .filter(c -> getRefJavaManager().belongsToScope(c)) + .forEach(c -> { + RefClassImpl refClass = (RefClassImpl)getRefManager().getReference(c); if (refClass != null) { addBaseClass(refClass); refClass.addSubClass(this); } - } - } + }); } } @Override - public boolean isSelfInheritor(PsiClass psiClass) { - return isSelfInheritor(psiClass, new ArrayList<>()); - } - - @Nullable - @Override - public PsiClass getElement() { - return (PsiClass)super.getElement(); + public boolean isSelfInheritor(UClass uClass) { + return isSelfInheritor(uClass, new ArrayList<>()); } @Nullable @@ -230,15 +233,19 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { return myRefModule; } - private static boolean isSelfInheritor(PsiClass psiClass, ArrayList visited) { - if (visited.contains(psiClass)) return true; - - visited.add(psiClass); - for (PsiClass aSuper : psiClass.getSupers()) { - if (isSelfInheritor(aSuper, visited)) return true; + private static boolean isSelfInheritor(UClass uClass, List visited) { + if (visited.contains(uClass)) return true; + visited.add(uClass); + if (uClass.getUastSuperTypes().stream() + .map(t -> PsiUtil.resolveClassInType(t.getType())) + .filter(Objects::nonNull) + .map(c -> UastContextKt.toUElement(c, UClass.class)) + .filter(Objects::nonNull) + .anyMatch(c -> isSelfInheritor(c, visited))) { + return true; } - visited.remove(psiClass); + visited.remove(uClass); return false; } @@ -259,43 +266,46 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { } } + @Override + public UClass getUastElement() { + return UastContextKt.toUElement(getPsiElement(), UClass.class); + } + @NotNull @Override public String getQualifiedName() { - final PsiClass psiClass = getElement(); - if (psiClass == null) return super.getQualifiedName(); - final String qName = psiClass.getQualifiedName(); + final JvmClass jvmClass = getUastElement(); + if (jvmClass == null) return super.getQualifiedName(); + final String qName = jvmClass.getQualifiedName(); if (qName == null) return super.getQualifiedName(); return qName; } @Override public void buildReferences() { - PsiClass psiClass = getElement(); - - if (psiClass != null) { - for (PsiClassInitializer classInitializer : psiClass.getInitializers()) { - RefJavaUtil.getInstance().addReferences(psiClass, this, classInitializer.getBody()); + UClass uClass = getUastElement(); + if (uClass != null) { + for (UClassInitializer classInitializer : uClass.getInitializers()) { + RefJavaUtil.getInstance().addReferencesTo(uClass, this, classInitializer.getUastBody()); } - RefJavaUtil.getInstance().addReferences(psiClass, this, psiClass.getModifierList()); + RefJavaUtil.getInstance().addReferencesTo(uClass, this, ((UAnnotated)uClass).getAnnotations().toArray(new UElement[0])); - PsiField[] psiFields = psiClass.getFields(); - for (PsiField psiField : psiFields) { - getRefManager().getReference(psiField); - final PsiExpression initializer = psiField.getInitializer(); + UField[] uFields = uClass.getFields(); + for (UField uField : uFields) { + getRefManager().getReference(uField.getPsi()); + final UExpression initializer = uField.getUastInitializer(); if (initializer != null) { - RefJavaUtil.getInstance().addReferences(psiClass, this, initializer); + RefJavaUtil.getInstance().addReferencesTo(uClass, this, initializer); } } - PsiMethod[] psiMethods = psiClass.getMethods(); - for (PsiMethod psiMethod : psiMethods) { - getRefManager().getReference(psiMethod); + UMethod[] psiMethods = uClass.getMethods(); + for (UMethod uMethod : psiMethods) { + getRefManager().getReference(uMethod.getSourcePsi()); } - RefJavaUtil.getInstance().addReferences(psiClass, this, psiClass.getExtendsList()); - RefJavaUtil.getInstance().addReferences(psiClass, this, psiClass.getImplementsList()); + RefJavaUtil.getInstance().addReferencesTo(uClass, this, uClass.getUastSuperTypes().toArray(new UElement[0])); getRefManager().fireBuildReferences(this); } @@ -432,13 +442,11 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { @Override public String getExternalName() { - final String[] result = new String[1]; - ApplicationManager.getApplication().runReadAction(() -> {//todo synthetic JSP - final PsiClass psiClass = getElement(); + return ReadAction.compute(() -> {//todo synthetic JSP + final UClass psiClass = getUastElement(); LOG.assertTrue(psiClass != null); - result[0] = PsiFormatUtil.getExternalName(psiClass); + return PsiFormatUtil.getExternalName(psiClass.getJavaPsi()); }); - return result[0]; } @@ -546,6 +554,9 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { setFlag(anInterface, IS_INTERFACE_MASK); } + /** + * typical jvm utility class has only static method or fields. But for example in kotlin utility classes (Objects) follow singleton pattern. + */ private void setUtilityClass(boolean utilityClass) { setFlag(utilityClass, IS_UTILITY_MASK); } @@ -577,5 +588,9 @@ public class RefClassImpl extends RefJavaElementImpl implements RefClass { if (defaultConstructor != null) return defaultConstructor; return super.getContainingEntry(); } + + private static boolean isKindOfJvmLanguage(Language language) { + return Language.findInstance(JvmMetaLanguage.class).getMatchingLanguages().stream().anyMatch(language::is); + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java index a85c4c8d0eef..df6503a4e638 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; import com.intellij.openapi.application.ApplicationManager; @@ -20,9 +6,9 @@ import com.intellij.openapi.application.ReadAction; import com.intellij.psi.*; import com.intellij.psi.util.ClassUtil; import com.intellij.psi.util.PsiFormatUtil; -import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.*; /** * @author max @@ -32,8 +18,8 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField { private static final int USED_FOR_WRITING_MASK = 0x20000; private static final int ASSIGNED_ONLY_IN_INITIALIZER_MASK = 0x40000; - RefFieldImpl(@NotNull RefClass ownerClass, PsiField field, RefManager manager) { - super(field, manager); + RefFieldImpl(@NotNull RefClass ownerClass, UField field, PsiElement psi, RefManager manager) { + super(field, psi, manager); ((RefClassImpl)ownerClass).add(this); @@ -41,27 +27,33 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField { setIsStatic(true); setIsFinal(true); } - if (field instanceof PsiEnumConstant) { + if (field instanceof UEnumConstant) { putUserData(ENUM_CONSTANT, true); } } + @Deprecated @Override public PsiField getElement() { - return (PsiField)super.getElement(); + return (PsiField)super.getPsiElement(); } @Override - protected void markReferenced(RefElementImpl refFrom, PsiElement psiFrom, PsiElement psiWhat, boolean forWriting, boolean forReading, PsiReferenceExpression expressionFrom) { + public UField getUastElement() { + return UastContextKt.toUElement(getPsiElement(), UField.class); + } + + @Override + protected void markReferenced(RefElementImpl refFrom, PsiElement psiFrom, PsiElement psiWhat, boolean forWriting, boolean forReading, UExpression expressionFrom) { addInReference(refFrom); boolean referencedFromClassInitializer = false; if (forWriting && expressionFrom != null) { - PsiClassInitializer initializer = PsiTreeUtil.getParentOfType(expressionFrom, PsiClassInitializer.class); - if (initializer != null && initializer.getParent() instanceof PsiClass && psiFrom == initializer.getParent()) { - PsiExpression qualifierExpression = expressionFrom.getQualifierExpression(); - if (qualifierExpression == null || qualifierExpression instanceof PsiThisExpression && ((PsiThisExpression)qualifierExpression).getQualifier() == null) { + UClassInitializer initializer = UastUtils.getParentOfType(expressionFrom, UClassInitializer.class); + if (initializer != null && psiFrom == UastUtils.getParentOfType(initializer, UClass.class).getSourcePsi()) { + UExpression qualifierExpression = expressionFrom instanceof UQualifiedReferenceExpression ? ((UQualifiedReferenceExpression)expressionFrom).getReceiver() : null; + if (qualifierExpression == null || qualifierExpression instanceof UThisExpression) { referencedFromClassInitializer = true; } } @@ -76,7 +68,7 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField { } setUsedQualifiedOutsidePackageFlag(refFrom, expressionFrom); - getRefManager().fireNodeMarkedReferenced(this, refFrom, referencedFromClassInitializer, forReading, forWriting, expressionFrom); + getRefManager().fireNodeMarkedReferenced(this, refFrom, referencedFromClassInitializer, forReading, forWriting, expressionFrom == null ? null : expressionFrom.getSourcePsi()); } @Override @@ -114,28 +106,28 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField { @Override public void buildReferences() { - PsiField psiField = getElement(); - if (psiField != null) { + UField uField = getUastElement(); + if (uField != null) { final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - refUtil.addReferences(psiField, this, psiField.getInitializer()); - refUtil.addReferences(psiField, this, psiField.getModifierList()); - if (psiField instanceof PsiEnumConstant) { - refUtil.addReferences(psiField, this, psiField); + refUtil.addReferencesTo(uField, this, uField.getUastInitializer()); + refUtil.addReferencesTo(uField, this, ((UAnnotated)uField).getAnnotations().toArray(new UElement[0])); + if (uField instanceof UEnumConstant) { + refUtil.addReferencesTo(uField, this, uField); } - if (psiField.getInitializer() != null || psiField instanceof PsiEnumConstant) { + if (uField.getUastInitializer() != null || uField instanceof UEnumConstant) { setInitializerMasks(); } - else if (RefUtil.isImplicitWrite(psiField)) { + else if (RefUtil.isImplicitWrite(uField.getJavaPsi())) { putUserData(IMPLICITLY_WRITTEN, true); setInitializerMasks(); } - if (RefUtil.isImplicitRead(psiField)) { + if (RefUtil.isImplicitRead(uField.getJavaPsi())) { putUserData(IMPLICITLY_READ, true); } - refUtil.addTypeReference(psiField, psiField.getType(), getRefManager(), this); + refUtil.addTypeReference((UElement)uField, uField.getType(), getRefManager(), this); getRefManager().fireBuildReferences(this); } } @@ -155,8 +147,8 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField { @Override public String getExternalName() { return ReadAction.compute(() -> { - PsiField psiField = getElement(); - return psiField != null ? PsiFormatUtil.getExternalName(psiField) : null; + UField uField = getUastElement(); + return uField != null ? PsiFormatUtil.getExternalName((PsiModifierListOwner)uField.getJavaPsi()) : null; }); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java index f1b1ae4a5ae0..8926462caa25 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java @@ -18,17 +18,18 @@ package com.intellij.codeInspection.reference; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.openapi.application.ReadAction; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiModifierListOwner; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UClass; + +import java.util.Objects; public class RefImplicitConstructorImpl extends RefMethodImpl implements RefImplicitConstructor { - - private final RefClass myOwnerClass; RefImplicitConstructorImpl(@NotNull RefClass ownerClass) { super(InspectionsBundle.message("inspection.reference.implicit.constructor.name", ownerClass.getName()), ownerClass); - myOwnerClass = ownerClass; } @Override @@ -70,7 +71,18 @@ public class RefImplicitConstructorImpl extends RefMethodImpl implements RefImpl @Override public PsiModifierListOwner getElement() { - return getOwnerClass().getElement(); + return Objects.requireNonNull(getOwnerClass()).getElement(); + } + + @Override + public UClass getUastElement() { + return (UClass)super.getUastElement(); + } + + @Nullable + @Override + public PsiElement getPsiElement() { + return Objects.requireNonNull(getOwnerClass()).getPsiElement(); } @Override @@ -78,9 +90,4 @@ public class RefImplicitConstructorImpl extends RefMethodImpl implements RefImpl public PsiFile getContainingFile() { return ((RefClassImpl)getOwnerClass()).getContainingFile(); } - - @Override - public RefClass getOwnerClass() { - return myOwnerClass; - } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java index b76cd27fcbfd..621487b345ac 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaElementImpl.java @@ -1,18 +1,4 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; @@ -24,7 +10,9 @@ import com.intellij.util.ObjectUtils; import com.intellij.util.containers.Stack; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclaration; +import org.jetbrains.uast.UExpression; +import org.jetbrains.uast.UQualifiedReferenceExpression; import javax.swing.*; import java.util.Collection; @@ -55,17 +43,18 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa } } - protected RefJavaElementImpl(PsiModifierListOwner elem, RefManager manager) { - super(getName(elem), elem, manager); + protected RefJavaElementImpl(UDeclaration elem, PsiElement psi, RefManager manager) { + super(getName(elem), psi, manager); - setAccessModifier(RefJavaUtil.getInstance().getAccessModifier(elem)); - final boolean isSynth = elem instanceof PsiMethod && elem instanceof SyntheticElement || elem instanceof PsiSyntheticClass; + PsiModifierListOwner javaPsi = ObjectUtils.notNull(ObjectUtils.tryCast(elem.getJavaPsi(), PsiModifierListOwner.class)); + setAccessModifier(RefJavaUtil.getInstance().getAccessModifier(javaPsi)); + final boolean isSynth = javaPsi instanceof PsiMethod && psi instanceof SyntheticElement || psi instanceof PsiSyntheticClass; if (isSynth) { setSyntheticJSP(true); } - setIsStatic(elem.hasModifierProperty(PsiModifier.STATIC)); - setIsFinal(elem.hasModifierProperty(PsiModifier.FINAL)); + setIsStatic(elem.isStatic()); + setIsFinal(elem.isFinal()); } @Override @@ -82,8 +71,9 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa } @NotNull - private static String getName(PsiElement element) { - if (element instanceof PsiAnonymousClass) { + public static String getName(UDeclaration declaration) { + PsiElement element = declaration.getJavaPsi(); + if (element instanceof PsiAnonymousClass) { PsiAnonymousClass psiAnonymousClass = (PsiAnonymousClass)element; PsiClass psiBaseClass = psiAnonymousClass.getBaseClassType().resolve(); if (psiBaseClass == null) { @@ -107,7 +97,6 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa if (element instanceof PsiNamedElement) { name = ((PsiNamedElement)element).getName(); } - return name == null ? InspectionsBundle.message("inspection.reference.anonymous") : name; } @@ -129,9 +118,6 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa setFlag(isFinal, IS_FINAL_MASK); } - public void setReachable(boolean reachable) { - setFlag(reachable, IS_REACHABLE_MASK); - } @Override public boolean isSyntheticJSP() { @@ -213,10 +199,11 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa void addReference(RefElement refWhat, PsiElement psiWhat, - PsiElement psiFrom, + UDeclaration from, boolean forWriting, boolean forReading, - PsiReferenceExpression expression) { + UExpression expression) { + PsiElement psiFrom = from.getPsi(); if (refWhat != null) { if (refWhat instanceof RefParameter) { if (forWriting) { @@ -227,35 +214,28 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa } } addOutReference(refWhat); - ((RefJavaElementImpl)refWhat).markReferenced(this, psiFrom, psiWhat, forWriting, forReading, expression); + if (refWhat instanceof RefJavaFileImpl) { + ((RefJavaFileImpl)refWhat).addInReference(this); + getRefManager().fireNodeMarkedReferenced(psiWhat, psiFrom); + } else if (refWhat instanceof RefJavaElementImpl) { + ((RefJavaElementImpl)refWhat).markReferenced(this, psiFrom, psiWhat, forWriting, forReading, expression); + } } else { if (psiWhat instanceof PsiMethod) { - final PsiClass containingClass = ((PsiMethod)psiWhat).getContainingClass(); - if (containingClass != null && containingClass.isEnum() && "values".equals(((PsiMethod)psiWhat).getName())) { - for (PsiField enumConstant : containingClass.getFields()) { - if (enumConstant instanceof PsiEnumConstant) { - final RefJavaElementImpl enumConstantReference = (RefJavaElementImpl)getRefManager().getReference(enumConstant); - if (enumConstantReference != null) { - addOutReference(enumConstantReference); - enumConstantReference.markReferenced(this, psiFrom, enumConstant, false, true, expression); - } - } - } - } + markEnumUsedIfValuesMethod((PsiMethod)psiWhat, expression, psiFrom); } getRefManager().fireNodeMarkedReferenced(psiWhat, psiFrom); } } - protected void markReferenced(final RefElementImpl refFrom, PsiElement psiFrom, PsiElement psiWhat, final boolean forWriting, boolean forReading, PsiReferenceExpression expressionFrom) { + protected void markReferenced(final RefElementImpl refFrom, PsiElement psiFrom, PsiElement psiWhat, final boolean forWriting, boolean forReading, UExpression expressionFrom) { addInReference(refFrom); setUsedQualifiedOutsidePackageFlag(refFrom, expressionFrom); - getRefManager().fireNodeMarkedReferenced(this, refFrom, false, forReading, forWriting, expressionFrom); + getRefManager().fireNodeMarkedReferenced(this, refFrom, false, forReading, forWriting, expressionFrom == null ? null : expressionFrom.getSourcePsi()); } - void setUsedQualifiedOutsidePackageFlag(RefElementImpl refFrom, PsiReferenceExpression expressionFrom) { - if (!checkFlag(IS_USED_QUALIFIED_OUTSIDE_PACKAGE_MASK) && expressionFrom != null && - expressionFrom.isQualified() && RefJavaUtil.getPackage(refFrom) != RefJavaUtil.getPackage(this)) { + void setUsedQualifiedOutsidePackageFlag(RefElementImpl refFrom, UExpression expressionFrom) { + if (!checkFlag(IS_USED_QUALIFIED_OUTSIDE_PACKAGE_MASK) && expressionFrom instanceof UQualifiedReferenceExpression && RefJavaUtil.getPackage(refFrom) != RefJavaUtil.getPackage(this)) { setFlag(true, IS_USED_QUALIFIED_OUTSIDE_PACKAGE_MASK); } } @@ -279,7 +259,7 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa @Override public Icon getIcon(final boolean expanded) { if (isSyntheticJSP()) { - final PsiElement element = getElement(); + final PsiElement element = getPsiElement(); if (element != null && element.isValid()) { return IconUtil.getIcon(element.getContainingFile().getVirtualFile(), Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS, element.getProject()); @@ -287,4 +267,20 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa } return super.getIcon(expanded); } + + private void markEnumUsedIfValuesMethod(PsiMethod psiWhat, UExpression expression, PsiElement psiFrom) { + //TODO support kotlin enums + final PsiClass containingClass = psiWhat.getContainingClass(); + if (containingClass != null && containingClass.isEnum() && "values".equals(psiWhat.getName())) { + for (PsiField enumConstant : containingClass.getFields()) { + if (enumConstant instanceof PsiEnumConstant) { + final RefJavaElementImpl enumConstantReference = (RefJavaElementImpl)getRefManager().getReference(enumConstant); + if (enumConstantReference != null) { + addOutReference(enumConstantReference); + enumConstantReference.markReferenced(this, psiFrom, enumConstant, false, true, expression); + } + } + } + } + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaFileImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaFileImpl.java index a838c688b2f3..f25be98e4b13 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaFileImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaFileImpl.java @@ -18,14 +18,18 @@ package com.intellij.codeInspection.reference; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.psi.*; +import com.intellij.util.ObjectUtils; +import org.jetbrains.uast.UFile; +import org.jetbrains.uast.UastContextKt; public class RefJavaFileImpl extends RefFileImpl { private final RefModule myRefModule; - RefJavaFileImpl(PsiJavaFile elem, RefManager manager) { + RefJavaFileImpl(PsiFile elem, RefManager manager) { super(elem, manager, false); myRefModule = manager.getRefModule(ModuleUtilCore.findModuleForPsiElement(elem)); - String packageName = elem.getPackageName(); + UFile file = ObjectUtils.notNull(UastContextKt.toUElement(elem, UFile.class)); + String packageName = file.getPackageName(); if (!packageName.isEmpty()) { ((RefPackageImpl)getRefManager().getExtension(RefJavaManager.MANAGER).getPackage(packageName)).add(this); } else if (myRefModule != null) { @@ -37,9 +41,9 @@ public class RefJavaFileImpl extends RefFileImpl { @Override public void buildReferences() { - PsiJavaFile file = (PsiJavaFile)getElement(); + PsiFile file = getPsiElement(); if (file != null && PsiPackage.PACKAGE_INFO_FILE.equals(file.getName())) { - PsiPackageStatement packageStatement = file.getPackageStatement(); + PsiPackageStatement packageStatement = ((PsiJavaFile)file).getPackageStatement(); if (packageStatement != null) { packageStatement.accept(new JavaRecursiveElementWalkingVisitor() { @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java index 4ca8f07092ac..8ecf176b3e95 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; import com.intellij.codeInsight.ExternalAnnotationsManager; @@ -19,17 +19,24 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; +import com.intellij.psi.impl.light.LightElement; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.uast.UastVisitorAdapter; +import com.intellij.util.ObjectUtils; import gnu.trove.THashMap; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.*; +import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor; +import javax.swing.*; import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Stream; @@ -43,6 +50,7 @@ public class RefJavaManagerImpl extends RefJavaManager { .and(Conditions.instanceOf(PsiFile.class, PsiClass.class, PsiMethod.class, PsiField.class, PsiJavaModule.class), Conditions.notInstanceOf(PsiTypeParameter.class)); private static final Logger LOG = Logger.getInstance(RefJavaManagerImpl.class); + public static final String JAVAX_SERVLET_SERVLET = "javax.servlet.Servlet"; private final PsiMethod myAppMainPattern; private final PsiMethod myAppPremainPattern; private final PsiMethod myAppAgentmainPattern; @@ -64,7 +72,7 @@ public class RefJavaManagerImpl extends RefJavaManager { myAppAgentmainPattern = factory.createMethodFromText("void agentmain(String[] args, java.lang.instrument.Instrumentation i);", null); myApplet = JavaPsiFacade.getInstance(project).findClass("java.applet.Applet", GlobalSearchScope.allScope(project)); - myServlet = JavaPsiFacade.getInstance(project).findClass("javax.servlet.Servlet", GlobalSearchScope.allScope(project)); + myServlet = JavaPsiFacade.getInstance(project).findClass(JAVAX_SERVLET_SERVLET, GlobalSearchScope.allScope(project)); } @Override @@ -122,7 +130,7 @@ public class RefJavaManagerImpl extends RefJavaManager { private static boolean isTestSource(UnusedDeclarationInspectionBase tool, RefElement refElement) { if (tool.isTestEntryPoints()) return true; - final PsiElement element = refElement.getElement(); + final PsiElement element = refElement.getPsiElement(); final VirtualFile file = PsiUtilCore.getVirtualFile(element); return file != null && !ProjectRootManager.getInstance(element.getProject()).getFileIndex().isInTestSourceContent(file); } @@ -186,17 +194,28 @@ public class RefJavaManagerImpl extends RefJavaManager { return myApplet; } + @Override + public String getAppletQName() { + return myApplet.getQualifiedName(); + } + @Override public PsiClass getServlet() { return myServlet; } @Override - public RefParameter getParameterReference(final PsiParameter param, final int index) { + public String getServletQName() { + return JAVAX_SERVLET_SERVLET; + } + + @Override + public RefParameter getParameterReference(UParameter param, int index, RefMethod refMethod) { LOG.assertTrue(myRefManager.isValidPointForReference(), "References may become invalid after process is finished"); - - return myRefManager.getFromRefTableOrCache(param, () -> { - RefParameterImpl ref = new RefParameterImpl(param, index, myRefManager); + + PsiElement psi = param.getSourcePsi(); + return myRefManager.getFromRefTableOrCache(psi, () -> { + RefParameterImpl ref = new RefParameterImpl(param, psi, index, myRefManager, refMethod); ref.initialize(); return ref; }); @@ -242,30 +261,48 @@ public class RefJavaManagerImpl extends RefJavaManager { @Override @Nullable - public RefElement createRefElement(@NotNull final PsiElement elem) { - if (elem instanceof PsiClass) { - return new RefClassImpl((PsiClass)elem, myRefManager); + public RefElement createRefElement(@NotNull final PsiElement psi) { + if (!getLanguages().contains(psi.getLanguage())) { + return null; } - if (elem instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)elem; - final RefElement ref = myRefManager.getReference(method.getContainingClass(), true); - if (ref instanceof RefClass) { - return new RefMethodImpl((RefClass)ref, method, myRefManager); + if (psi instanceof PsiFile) { + return new RefJavaFileImpl((PsiFile)psi, myRefManager); + } + else if (psi instanceof PsiJavaModule) { + return new RefJavaModuleImpl((PsiJavaModule)psi, myRefManager); + } + UElement uElement = UastContextKt.toUElement(psi); + if (uElement instanceof UClass) { + return new RefClassImpl((UClass)uElement, psi, myRefManager); + } + if (uElement instanceof UMethod) { + UMethod method = (UMethod)uElement; + UDeclaration containingUDecl = UDeclarationKt.getContainingDeclaration(method); + PsiElement containingDeclaration = containingUDecl == null ? null : containingUDecl.getSourcePsi(); + if (containingDeclaration instanceof LightElement) { + containingDeclaration = containingDeclaration.getNavigationElement(); + } + final RefElement parentRef; + //TODO strange + if (containingDeclaration == null || containingDeclaration instanceof LightElement) { + parentRef = myRefManager.getReference(psi.getContainingFile(), true); + } + else { + parentRef = myRefManager.getReference(containingDeclaration, true); + } + if (parentRef != null) { + return new RefMethodImpl(parentRef, method, psi, myRefManager); } } - else if (elem instanceof PsiField) { - final PsiField field = (PsiField)elem; - final RefElement ref = myRefManager.getReference(field.getContainingClass(), true); + else if (uElement instanceof UField) { + final UField field = (UField)uElement; + UDeclaration containingUDecl = UDeclarationKt.getContainingDeclaration(field); + PsiElement containingDeclaration = containingUDecl == null ? null : containingUDecl.getSourcePsi(); + final RefElement ref = myRefManager.getReference(containingDeclaration, true); if (ref instanceof RefClass) { - return new RefFieldImpl((RefClass)ref, field, myRefManager); + return new RefFieldImpl((RefClass)ref, field, psi, myRefManager); } } - else if (elem instanceof PsiJavaFile) { - return new RefJavaFileImpl((PsiJavaFile)elem, myRefManager); - } - else if (elem instanceof PsiJavaModule) { - return new RefJavaModuleImpl((PsiJavaModule)elem, myRefManager); - } return null; } @@ -342,7 +379,22 @@ public class RefJavaManagerImpl extends RefJavaManager { public void visitElement(@NotNull final PsiElement element) { PsiElementVisitor projectIterator = myProjectIterator; if (projectIterator == null) { - myProjectIterator = projectIterator = new MyJavaElementVisitor(); + myProjectIterator = projectIterator = new UastVisitorAdapter(new MyJavaElementVisitor(), true) { + @Override + public void visitElement(PsiElement element) { + super.visitElement(element); + if (element instanceof PsiJavaModule) { + visitJavaModule((PsiJavaModule)element); + } + } + + private void visitJavaModule(PsiJavaModule module) { + RefElement refElement = myRefManager.getReference(module); + if (refElement != null) { + ((RefJavaModuleImpl)refElement).buildReferences(); + } + } + }; } element.accept(projectIterator); } @@ -409,113 +461,137 @@ public class RefJavaManagerImpl extends RefJavaManager { return entryPointsManager; } - private class MyJavaElementVisitor extends JavaElementVisitor { + private class MyJavaElementVisitor extends AbstractUastNonRecursiveVisitor { private final RefJavaUtil myRefUtil = RefJavaUtil.getInstance(); private final ExternalAnnotationsManager myExternalAnnotationsManager = ExternalAnnotationsManager.getInstance(myRefManager.getProject()); @Override - public void visitReferenceExpression(PsiReferenceExpression expression) { - visitElement(expression); + public boolean visitFile(@NotNull UFile node) { + RefElement refElement = myRefManager.getReference(node.getSourcePsi()); + if (refElement instanceof RefJavaFileImpl) { + ((RefJavaFileImpl)refElement).buildReferences(); + } + return true; } @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - } + public boolean visitDeclaration(@NotNull UDeclaration node) { + RefElement decl = myRefManager.getReference(node.getSourcePsi()); + if (decl != null) { + ((RefElementImpl)decl).buildReferences(); + } - - @Override - public void visitReferenceParameterList(final PsiReferenceParameterList list) { - super.visitReferenceParameterList(list); - final PsiMember member = PsiTreeUtil.getParentOfType(list, PsiMember.class); - - if (member instanceof PsiTypeParameter) { - final PsiMember owner = ((PsiTypeParameter)member).getOwner(); - if (owner != null) { - for (PsiClassType type : ((PsiTypeParameter)member).getExtendsListTypes()) { - myRefUtil.addTypeReference(owner, type, myRefManager); - } + PsiModifierListOwner javaModifiersListOwner = ObjectUtils.tryCast(node.getJavaPsi(), PsiModifierListOwner.class); + if (javaModifiersListOwner != null) { + PsiAnnotation externalAnnotation = myExternalAnnotationsManager.findExternalAnnotation(javaModifiersListOwner, + BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME); + UAnnotation uAnnotation = UastContextKt.toUElement(externalAnnotation, UAnnotation.class); + if (uAnnotation != null) { + retrieveSuppressions(uAnnotation, node); } } - - final PsiType[] typeArguments = list.getTypeArguments(); - for (PsiType type : typeArguments) { - myRefUtil.addTypeReference(member, type, myRefManager); - } + return true; } @Override - public void visitClass(PsiClass aClass) { - if (!(aClass instanceof PsiTypeParameter)) { - super.visitClass(aClass); - RefElement refClass = myRefManager.getReference(aClass); - if (refClass != null) { - ((RefClassImpl)refClass).buildReferences(); - } - } - } - - @Override - public void visitMethod(final PsiMethod method) { - super.visitMethod(method); - final RefElement refElement = myRefManager.getReference(method); - if (refElement instanceof RefMethodImpl) { - ((RefMethodImpl)refElement).buildReferences(); - } - } - - @Override - public void visitField(final PsiField field) { - super.visitField(field); - final RefElement refElement = myRefManager.getReference(field); - if (refElement instanceof RefFieldImpl) { - ((RefFieldImpl)refElement).buildReferences(); - } - } - - @Override - public void visitDocComment(PsiDocComment comment) { - super.visitDocComment(comment); - final PsiDocTag[] tags = comment.getTags(); - for (PsiDocTag tag : tags) { - if (Comparing.strEqual(tag.getName(), SuppressionUtilCore.SUPPRESS_INSPECTIONS_TAG_NAME)) { - final PsiElement[] dataElements = tag.getDataElements(); - if (dataElements.length > 0) { - final PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(comment, PsiModifierListOwner.class); - if (listOwner != null) { - final RefElementImpl element = (RefElementImpl)myRefManager.getReference(listOwner); - if (element != null) { - String suppression = StringUtil.join(dataElements, PsiElement::getText, ","); - element.addSuppression(suppression); + public boolean visitElement(@NotNull UElement node) { + if (node instanceof UComment) { + PsiElement psi = node.getSourcePsi(); + if (psi instanceof PsiDocComment) { + //TODO support suppressions in kotlin + final PsiDocTag[] tags = ((PsiDocComment)psi).getTags(); + for (PsiDocTag tag : tags) { + if (Comparing.strEqual(tag.getName(), SuppressionUtilCore.SUPPRESS_INSPECTIONS_TAG_NAME)) { + final PsiElement[] dataElements = tag.getDataElements(); + if (dataElements.length > 0) { + final PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(psi, PsiModifierListOwner.class); + if (listOwner != null) { + final RefElementImpl element = (RefElementImpl)myRefManager.getReference(listOwner); + if (element != null) { + String suppression = StringUtil.join(dataElements, PsiElement::getText, ","); + element.addSuppression(suppression); + } + } } } } } } + return super.visitElement(node); } @Override - public void visitAnnotation(PsiAnnotation annotation) { - super.visitAnnotation(annotation); - if (Comparing.strEqual(annotation.getQualifiedName(), BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME)) { - retrieveSuppressions(annotation, PsiTreeUtil.getParentOfType(annotation, PsiModifierListOwner.class)); - } + public boolean visitField(@NotNull UField node) { + visitDeclaration(node); + return false; } - private void retrieveSuppressions(PsiAnnotation annotation, PsiModifierListOwner listOwner) { - if (listOwner != null) { - final RefElementImpl element = (RefElementImpl)myRefManager.getReference(listOwner); + @Override + public boolean visitVariable(@NotNull UVariable variable) { + myRefUtil.addTypeReference((UElement)variable, variable.getType(), myRefManager); + if (variable instanceof UParameter) { + final RefElement reference = myRefManager.getReference(variable.getSourcePsi()); + if (reference instanceof RefParameterImpl) { + ((RefParameterImpl)reference).buildReferences(); + } + } + return false; + } + + @Override + public boolean visitAnnotation(@NotNull UAnnotation annotation) { + String qualifiedName = annotation.getQualifiedName(); + if (Comparing.strEqual(qualifiedName, BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME) || + Comparing.strEqual(qualifiedName, "kotlin.Suppress")) { + UAnnotated annotated = UastUtils.getParentOfType(annotation, UAnnotated.class); + // TODO support kotlin suppressions + if (annotated == null) { + UElement parent = annotation.getUastParent(); + if (parent == null) { + PsiElement sourcePsi = annotation.getSourcePsi(); + if (sourcePsi != null) { + annotated = UastContextKt.toUElement(sourcePsi.getContainingFile(), UFile.class); + } + } + } + retrieveSuppressions(annotation, annotated); + } + return false; + } + + private void retrieveSuppressions(UAnnotation annotation, UAnnotated annotated) { + if (annotated != null) { + PsiElement annotatedSrc = annotated.getSourcePsi(); + final RefElementImpl element = (RefElementImpl)myRefManager.getReference(annotatedSrc); if (element != null) { StringBuilder buf = new StringBuilder(); - final PsiNameValuePair[] nameValuePairs = annotation.getParameterList().getAttributes(); - for (PsiNameValuePair nameValuePair : nameValuePairs) { - buf.append(",").append(nameValuePair.getText().replaceAll("[{}\"\"]", "")); + final List nameValuePairs = annotation.getAttributeValues(); + for (UNamedExpression nameValuePair : nameValuePairs) { + UExpression value = nameValuePair.getExpression(); + if (value instanceof ULiteralExpression) { + Object val = ((ULiteralExpression)value).getValue(); + if (val instanceof String) { + buf.append(",").append(String.valueOf(val).replaceAll("[{}\"\"]", "")); + } + } + else if (value instanceof UCallExpression && ((UCallExpression)value).getKind() == UastCallKind.NESTED_ARRAY_INITIALIZER) { + for (UExpression argument : ((UCallExpression)value).getValueArguments()) { + if (argument instanceof ULiteralExpression) { + Object val = ((ULiteralExpression)argument).getValue(); + if (val instanceof String) { + buf.append(",").append(val); + } + } + } + } } + if (buf.length() > 0) { String suppressId = buf.substring(1); element.addSuppression(suppressId); - if (listOwner instanceof PsiField) { - addSuppressionsForSiblings((PsiField)listOwner, suppressId); + if (annotatedSrc instanceof PsiField) { + addSuppressionsForSiblings((PsiField)annotatedSrc, suppressId); } } } @@ -543,66 +619,5 @@ public class RefJavaManagerImpl extends RefJavaManager { } } - @Override - public void visitVariable(PsiVariable variable) { - super.visitVariable(variable); - myRefUtil.addTypeReference(variable, variable.getType(), myRefManager); - if (variable instanceof PsiParameter) { - final RefElement reference = myRefManager.getReference(variable); - if (reference instanceof RefParameterImpl) { - ((RefParameterImpl)reference).buildReferences(); - } - } - } - - @Override - public void visitInstanceOfExpression(PsiInstanceOfExpression expression) { - super.visitInstanceOfExpression(expression); - final PsiTypeElement typeElement = expression.getCheckType(); - if (typeElement != null) { - myRefUtil.addTypeReference(expression, typeElement.getType(), myRefManager); - } - } - - @Override - public void visitThisExpression(PsiThisExpression expression) { - super.visitThisExpression(expression); - final PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); - if (qualifier != null) { - myRefUtil.addTypeReference(expression, expression.getType(), myRefManager); - } - } - - @Override - public void visitModule(PsiJavaModule javaModule) { - super.visitModule(javaModule); - RefElement refElement = myRefManager.getReference(javaModule); - if (refElement != null) { - ((RefJavaModuleImpl)refElement).buildReferences(); - } - } - - @Override - public void visitJavaFile(PsiJavaFile file) { - super.visitJavaFile(file); - RefElement refElement = myRefManager.getReference(file); - if (refElement != null) { - ((RefJavaFileImpl)refElement).buildReferences(); - } - } - - @Override - public void visitModifierList(PsiModifierList list) { - super.visitModifierList(list); - PsiElement parent = list.getParent(); - if (parent instanceof PsiModifierListOwner) { - PsiModifierListOwner listOwner = (PsiModifierListOwner)parent; - PsiAnnotation externalAnnotation = myExternalAnnotationsManager.findExternalAnnotation(listOwner, - BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME); - if (externalAnnotation != null) { - retrieveSuppressions(externalAnnotation, listOwner); - } - } - } } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java index 114d4eb5c5f3..f738c665bfcf 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaModuleImpl.java @@ -26,6 +26,8 @@ import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclaration; +import org.jetbrains.uast.UastContextKt; import javax.swing.*; import java.util.*; @@ -65,8 +67,8 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { @Nullable @Override - public PsiJavaModule getElement() { - return (PsiJavaModule)super.getElement(); + public PsiJavaModule getPsiElement() { + return (PsiJavaModule)super.getPsiElement(); } @Nullable @@ -175,8 +177,8 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { final RefMethod refConstructor = ((RefClassImpl)refClass).getDefaultConstructor(); if (refConstructor != null) { - final PsiModifierListOwner constructorElement = refConstructor.getElement(); - if (constructorElement != null && constructorElement.hasModifierProperty(PsiModifier.PUBLIC)) { + final PsiElement constructorElement = refConstructor.getPsiElement(); + if (constructorElement instanceof PsiModifierListOwner && ((PsiModifierListOwner)constructorElement).hasModifierProperty(PsiModifier.PUBLIC)) { refTargetElement = refConstructor; targetElement = constructorElement; } @@ -191,7 +193,7 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { } if (refTargetElement != null) { ((RefClassImpl)refInterface) - .addReference(refTargetElement, targetElement, providerInterface, false, true, null); + .addReference(refTargetElement, targetElement, UastContextKt.toUElement(providerInterface, UDeclaration.class), false, true, null); } } } @@ -219,7 +221,7 @@ public class RefJavaModuleImpl extends RefElementImpl implements RefJavaModule { @Override public void buildReferences() { - PsiJavaModule javaModule = getElement(); + PsiJavaModule javaModule = getPsiElement(); if (javaModule != null) { buildRequiresReferences(javaModule); buildExportsReferences(javaModule); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java index dcce31049a9d..e7e7604962e8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaUtilImpl.java @@ -1,274 +1,419 @@ -/* - * Copyright 2000-2014 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. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.MethodSignatureUtil; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.ObjectUtils; import com.intellij.util.VisibilityUtil; import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.*; +import org.jetbrains.uast.visitor.AbstractUastVisitor; -public class RefJavaUtilImpl extends RefJavaUtil{ +import java.util.Collections; +import java.util.List; + +public class RefJavaUtilImpl extends RefJavaUtil { + private static final Logger LOG = Logger.getInstance(RefJavaUtilImpl.class); @Override - public void addReferences(@NotNull final PsiModifierListOwner psiFrom, @NotNull final RefJavaElement ref, @Nullable final PsiElement findIn) { + public void addReferences(@NotNull PsiModifierListOwner psiFrom, @NotNull RefJavaElement ref, @Nullable PsiElement findIn) { + UDeclaration decl = UastContextKt.toUElement(psiFrom, UDeclaration.class); + UElement uFindIn = UastContextKt.toUElement(findIn); + if (decl != null && findIn != null) { + addReferencesTo(decl, ref, new UElement[]{uFindIn}); + } + } + + @Override + public void addReferencesTo(@NotNull final UDeclaration decl, @NotNull final RefJavaElement ref, @Nullable final UElement[] findIn) { final RefJavaElementImpl refFrom = (RefJavaElementImpl)ref; if (findIn == null) { return; } - findIn.accept( - new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - visitElement(reference); - final PsiElement target = reference.resolve(); + for (UElement element : findIn) { + if (element == null) continue; + element.accept(new AbstractUastVisitor() { + @Override + public boolean visitAnnotation(@NotNull UAnnotation node) { + PsiClass javaClass = node.resolve(); + if (javaClass != null) { + final RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(javaClass.getOriginalElement()); + refFrom.addReference(refClass, javaClass.getOriginalElement(), decl, false, true, null); + } + return false; + } - if (target instanceof PsiClass) { - final PsiClass aClass = (PsiClass)target; - final RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(aClass); - refFrom.addReference(refClass, aClass, psiFrom, false, true, null); - } - } + @Override + public boolean visitTypeReferenceExpression(@NotNull UTypeReferenceExpression node) { + PsiType type = node.getType(); + visitTypeRefs(type); + return false; + } - @Override - public void visitLiteralExpression(PsiLiteralExpression expression) { - for (PsiReference reference : expression.getReferences()) { - PsiElement resolve = reference.resolve(); - if (resolve instanceof PsiMember) { - final RefElement refResolved = refFrom.getRefManager().getReference(resolve); - refFrom.addReference(refResolved, resolve, psiFrom, false, true, null); - if (refResolved instanceof RefMethod) { - updateRefMethod(resolve, refResolved, expression, psiFrom, refFrom); - } - } - } - } + private void visitTypeRefs(PsiType type) { + type = type.getDeepComponentType(); + if (type instanceof PsiClassType) { + type.accept(new PsiTypeVisitor() { + @Nullable + @Override + public Void visitClassType(PsiClassType classType) { + for (PsiType parameter : classType.getParameters()) { + parameter.accept(this); + } + UClass target = UastContextKt.toUElement(classType.resolve(), UClass.class); + if (target != null) { + final RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(target.getSourcePsi()); + refFrom.addReference(refClass, target.getSourcePsi(), decl, false, true, null); + } + return null; + } + }); + } + } - @Override public void visitReferenceExpression(PsiReferenceExpression expression) { - visitElement(expression); + @Override + public boolean visitSimpleNameReferenceExpression(@NotNull USimpleNameReferenceExpression node) { + final PsiElement target = node.resolve(); - final JavaResolveResult result = expression.advancedResolve(false); - final PsiElement psiResolved = result.getElement(); + visitReferenceExpression(node); + if (target instanceof PsiClass) { + final PsiClass aClass = (PsiClass)target; + final RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(aClass); + refFrom.addReference(refClass, aClass, decl, false, true, null); + } + return false; + } - RefElement refResolved = refFrom.getRefManager().getReference(psiResolved); - refFrom.addReference( - refResolved, psiResolved, psiFrom, PsiUtil.isAccessedForWriting(expression), - PsiUtil.isAccessedForReading(expression), expression - ); + @Override + public boolean visitLiteralExpression(@NotNull ULiteralExpression node) { + PsiElement sourcePsi = node.getSourcePsi(); + if (sourcePsi != null) { + for (PsiReference reference : sourcePsi.getReferences()) { + PsiElement resolve = reference.resolve(); + if (resolve instanceof PsiMember) { + final RefElement refResolved = refFrom.getRefManager().getReference(resolve); + refFrom.addReference(refResolved, resolve, decl, false, true, null); + if (refResolved instanceof RefMethod) { + updateRefMethod(resolve, refResolved, node, decl, refFrom); + } + } + } + } + return false; + } - if (refResolved instanceof RefMethod) { - updateRefMethod(psiResolved, refResolved, expression, psiFrom, refFrom); - } - - if (psiResolved instanceof PsiMember && result.getCurrentFileResolveScope() instanceof PsiImportStaticStatement) { - final PsiClass containingClass = ((PsiMember)psiResolved).getContainingClass(); - if (containingClass != null) { - RefElement refContainingClass = refFrom.getRefManager().getReference(containingClass); - if (refContainingClass != null) { - refFrom.addReference(refContainingClass, containingClass, psiFrom, false, true, expression); - } - } - } - } + @Override + public boolean visitPrefixExpression(@NotNull UPrefixExpression node) { + visitReferenceExpression(node); + return false; + } + + @Override + public boolean visitPostfixExpression(@NotNull UPostfixExpression node) { + visitReferenceExpression(node); + return false; + } + + @Override + public boolean visitUnaryExpression(@NotNull UUnaryExpression node) { + visitReferenceExpression(node); + return false; + } + + @Override + public boolean visitBinaryExpression(@NotNull UBinaryExpression node) { + visitReferenceExpression(node); + return false; + } + + @Override + public boolean visitQualifiedReferenceExpression(@NotNull UQualifiedReferenceExpression node) { + visitReferenceExpression(node); + return false; + } + + @Override + public boolean visitCallableReferenceExpression(@NotNull UCallableReferenceExpression node) { + visitReferenceExpression(node); + processFunctionalExpression(node, getFunctionalInterfaceType(node)); + return false; + } + + @Override + public boolean visitObjectLiteralExpression(@NotNull UObjectLiteralExpression node) { + visitReferenceExpression(node); + visitClass(node.getDeclaration()); + return false; + } + + @Override + public boolean visitCallExpression(@NotNull UCallExpression node) { + visitReferenceExpression(node); + if (node instanceof UObjectLiteralExpression) { + visitClass(((UObjectLiteralExpression)node).getDeclaration()); + } + if (node.getKind() == UastCallKind.CONSTRUCTOR_CALL) { + PsiMethod resolvedMethod = node.resolve(); + final List argumentList = node.getValueArguments(); + RefMethod refConstructor = processNewLikeConstruct(resolvedMethod, argumentList); + + if (refConstructor == null) { // No explicit constructor referenced. Should use default one. + UReferenceExpression reference = node.getClassReference(); + if (reference != null) { + PsiElement constructorClass = reference.resolve(); + if (constructorClass instanceof PsiClass) { + processClassReference((PsiClass)constructorClass, refFrom, decl, true); + } + } + } + } + try { + node.getTypeArguments().forEach(this::visitTypeRefs); + } + catch (UnsupportedOperationException e) { + //TODO happens somewhere in kotlin plugin. Please assign those exception for Dmitry Batkovich + LOG.error(e); + } + return false; + } + + private void visitReferenceExpression(UExpression node) { + PsiElement psiResolved = null; + if (node instanceof UResolvable) { + psiResolved = ((UResolvable)node).resolve(); + } + else if (node instanceof UBinaryExpression) { + psiResolved = ((UBinaryExpression)node).resolveOperator(); + } + else if (node instanceof UUnaryExpression) { + psiResolved = ((UUnaryExpression)node).resolveOperator(); + } + if (psiResolved == null) { + psiResolved = tryFindKotlinParameter(node, decl); + } + RefElement refResolved = refFrom.getRefManager().getReference(psiResolved); + boolean writing = isAccessedForWriting(node); + boolean reading = isAccessedForReading(node); + refFrom.addReference(refResolved, psiResolved, decl, writing, reading, node); + + if (refResolved instanceof RefMethod) { + updateRefMethod(psiResolved, refResolved, node, decl, refFrom); + } + + if (psiResolved instanceof PsiMember) { + //TODO support kotlin + addClassReferenceForStaticImport(node, (PsiMember)psiResolved, refFrom, decl); + } + } + + @Override + public boolean visitLambdaExpression(@NotNull ULambdaExpression node) { + processFunctionalExpression(node, node.getFunctionalInterfaceType()); + return false; + } - @Override public void visitEnumConstant(PsiEnumConstant enumConstant) { - super.visitEnumConstant(enumConstant); - processNewLikeConstruct(enumConstant.resolveConstructor(), enumConstant.getArgumentList()); - } + private void processFunctionalExpression(UExpression expression, PsiType type) { + PsiElement aClass = PsiUtil.resolveClassInType(type); + if (aClass != null) { + aClass = ((PsiClass)aClass).getSourceElement(); + } + if (aClass != null) { + refFrom.addReference(refFrom.getRefManager().getReference(aClass), aClass, decl, false, true, null); + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(type); + if (interfaceMethod != null) { + refFrom.addReference(refFrom.getRefManager().getReference(interfaceMethod), interfaceMethod, decl, false, true, null); + refFrom.getRefManager().fireNodeMarkedReferenced(interfaceMethod, expression.getSourcePsi()); + } + } + } - @Override public void visitNewExpression(PsiNewExpression newExpr) { - super.visitNewExpression(newExpr); - PsiMethod psiConstructor = newExpr.resolveConstructor(); - final PsiExpressionList argumentList = newExpr.getArgumentList(); + @Nullable + private RefMethod processNewLikeConstruct(final PsiMethod javaConstructor, final List argumentList) { + if (javaConstructor == null) return null; + RefMethodImpl refConstructor = (RefMethodImpl)refFrom.getRefManager().getReference(javaConstructor.getOriginalElement()); + refFrom.addReference(refConstructor, javaConstructor, decl, false, true, null); - RefMethod refConstructor = processNewLikeConstruct(psiConstructor, argumentList); + for (UExpression arg : argumentList) { + arg.accept(this); + } - if (refConstructor == null) { // No explicit constructor referenced. Should use default one. - PsiType newType = newExpr.getType(); - if (newType instanceof PsiClassType) { - processClassReference(PsiUtil.resolveClassInType(newType), refFrom, psiFrom, true); - } - } - } + if (refConstructor != null) { + refConstructor.updateParameterValues(argumentList, javaConstructor); + } + return refConstructor; + } - @Override - public void visitLambdaExpression(PsiLambdaExpression expression) { - super.visitLambdaExpression(expression); - processFunctionalExpression(expression); - } + @Override + public boolean visitClass(@NotNull UClass uClass) { + RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(uClass.getSourcePsi()); + refFrom.addReference(refClass, uClass.getSourcePsi(), decl, false, true, null); + return false; + } - @Override - public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { - super.visitMethodReferenceExpression(expression); - processFunctionalExpression(expression); - } + @Override + public boolean visitReturnExpression(@NotNull UReturnExpression node) { + if (refFrom instanceof RefMethodImpl) { + RefMethodImpl refMethod = (RefMethodImpl)refFrom; + refMethod.updateReturnValueTemplate(node.getReturnExpression()); + } + return false; + } - private void processFunctionalExpression(PsiFunctionalExpression expression) { - final PsiClass aClass = PsiUtil.resolveClassInType(expression.getFunctionalInterfaceType()); - if (aClass != null) { - refFrom.addReference(refFrom.getRefManager().getReference(aClass), aClass, psiFrom, false, true, null); - final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(aClass); - if (interfaceMethod != null) { - refFrom.addReference(refFrom.getRefManager().getReference(interfaceMethod), interfaceMethod, psiFrom, false, true, null); - refFrom.getRefManager().fireNodeMarkedReferenced(interfaceMethod, expression); - } - } - } + @Override + public boolean visitClassLiteralExpression(@NotNull UClassLiteralExpression node) { + final PsiType type = node.getType(); + if (type instanceof PsiClassType) { + processClassReference(((PsiClassType)type).resolve(), refFrom, decl, false); + } + return false; + } - @Nullable - private RefMethod processNewLikeConstruct(final PsiMethod psiConstructor, final PsiExpressionList argumentList) { - RefMethodImpl refConstructor = (RefMethodImpl)refFrom.getRefManager().getReference( - psiConstructor - ); - refFrom.addReference(refConstructor, psiConstructor, psiFrom, false, true, null); + private void processClassReference(final PsiClass psiClass, + final RefJavaElementImpl refFrom, + final UDeclaration from, + boolean defaultConstructorOnly) { + if (psiClass != null) { + RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(psiClass.getNavigationElement()); - if (argumentList != null) { - PsiExpression[] psiParams = argumentList.getExpressions(); - for (PsiExpression param : psiParams) { - param.accept(this); - } + if (refClass != null) { + boolean hasConstructorsMarked = false; - if (refConstructor != null) { - refConstructor.updateParameterValues(psiParams, psiConstructor); - } - } - return refConstructor; - } + if (defaultConstructorOnly) { + RefMethodImpl refDefaultConstructor = (RefMethodImpl)refClass.getDefaultConstructor(); + if (refDefaultConstructor != null) { + refDefaultConstructor.addInReference(refFrom); + refFrom.addOutReference(refDefaultConstructor); + hasConstructorsMarked = true; + } + } + else { + for (RefMethod cons : refClass.getConstructors()) { + if (cons instanceof RefImplicitConstructor) continue; + ((RefMethodImpl)cons).addInReference(refFrom); + refFrom.addOutReference(cons); + hasConstructorsMarked = true; + } + } - @Override public void visitClass(PsiClass psiClass) { - super.visitClass(psiClass); - RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(psiClass); - refFrom.addReference(refClass, psiClass, psiFrom, false, true, null); - } + if (!hasConstructorsMarked) { + refFrom.addReference(refClass, psiClass, from, false, true, null); + } + } + } + } + } + ); + } + } - @Override public void visitReturnStatement(PsiReturnStatement statement) { - super.visitReturnStatement(statement); - - if (refFrom instanceof RefMethodImpl) { - RefMethodImpl refMethod = (RefMethodImpl)refFrom; - refMethod.updateReturnValueTemplate(statement.getReturnValue()); - } - } - - @Override public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { - super.visitClassObjectAccessExpression(expression); - final PsiTypeElement operand = expression.getOperand(); - final PsiType type = operand.getType(); - if (type instanceof PsiClassType) { - processClassReference(((PsiClassType)type).resolve(), refFrom, psiFrom, false); - } - } - - private void processClassReference(final PsiClass psiClass, - final RefJavaElementImpl refFrom, - final PsiModifierListOwner psiFrom, - boolean defaultConstructorOnly) { - if (psiClass != null) { - RefClassImpl refClass = (RefClassImpl)refFrom.getRefManager().getReference(psiClass); - - if (refClass != null) { - boolean hasConstructorsMarked = false; - - if (defaultConstructorOnly) { - RefMethodImpl refDefaultConstructor = (RefMethodImpl)refClass.getDefaultConstructor(); - if (refDefaultConstructor != null) { - refDefaultConstructor.addInReference(refFrom); - refFrom.addOutReference(refDefaultConstructor); - hasConstructorsMarked = true; - } - } - else { - for (RefMethod cons : refClass.getConstructors()) { - if (cons instanceof RefImplicitConstructor) continue; - ((RefMethodImpl)cons).addInReference(refFrom); - refFrom.addOutReference(cons); - hasConstructorsMarked = true; - } - } - - if (!hasConstructorsMarked) { - refFrom.addReference(refClass, psiClass, psiFrom, false, true, null); - } - } + private static void addClassReferenceForStaticImport(UExpression node, + PsiMember psiResolved, + RefJavaElementImpl refFrom, UDeclaration decl) { + PsiElement sourcePsi = node.getSourcePsi(); + if (sourcePsi instanceof PsiReferenceExpression) { + JavaResolveResult result = ((PsiReferenceExpression)sourcePsi).advancedResolve(false); + if (result.getCurrentFileResolveScope() instanceof PsiImportStaticStatement) { + final PsiClass containingClass = psiResolved.getContainingClass(); + if (containingClass != null) { + RefElement refContainingClass = refFrom.getRefManager().getReference(containingClass); + if (refContainingClass != null) { + refFrom.addReference(refContainingClass, containingClass, decl, false, true, node); } } } - ); + } + } + + private static PsiElement tryFindKotlinParameter(@NotNull UExpression node, + @NotNull UDeclaration decl) { + //TODO see KT-25524 + if (node instanceof UCallExpression && "invoke".equals(((UCallExpression)node).getMethodName())) { + UIdentifier identifier = ((UCallExpression)node).getMethodIdentifier(); + if (identifier != null) { + String name = identifier.getName(); + if (decl instanceof UMethod) { + UParameter parameter = ((UMethod)decl).getUastParameters().stream().filter(p -> name.equals(p.getName())).findAny().orElse(null); + if (parameter != null) { + return parameter.getSourcePsi(); + } + } + } + } + return null; } private void updateRefMethod(PsiElement psiResolved, RefElement refResolved, - PsiElement refExpression, - final PsiElement psiFrom, + UExpression refExpression, + final UElement uFrom, final RefElement refFrom) { - PsiMethod psiMethod = (PsiMethod)psiResolved; + UMethod uMethod = ObjectUtils.notNull(UastContextKt.toUElement(psiResolved, UMethod.class)); RefMethodImpl refMethod = (RefMethodImpl)refResolved; - if (refExpression instanceof PsiMethodReferenceExpression) { - PsiType returnType = psiMethod.getReturnType(); - if (!psiMethod.isConstructor() && - !PsiType.VOID.equals(LambdaUtil.getFunctionalInterfaceReturnType((PsiFunctionalExpression)refExpression))) { + if (refExpression instanceof UCallableReferenceExpression) { + PsiType returnType = uMethod.getReturnType(); + if (!uMethod.isConstructor() && + !PsiType.VOID + .equals(LambdaUtil.getFunctionalInterfaceReturnType(getFunctionalInterfaceType((UCallableReferenceExpression)refExpression)))) { refMethod.setReturnValueUsed(true); - addTypeReference(psiFrom, returnType, refFrom.getRefManager()); + addTypeReference(uFrom, returnType, refFrom.getRefManager()); } return; } - if (refExpression instanceof PsiLiteralExpression){ //references in literal expressions - PsiType returnType = psiMethod.getReturnType(); - if (!psiMethod.isConstructor() && !PsiType.VOID.equals(returnType)) { + if (refExpression instanceof ULiteralExpression) { //references in literal expressions + PsiType returnType = uMethod.getReturnType(); + if (!uMethod.isConstructor() && !PsiType.VOID.equals(returnType)) { refMethod.setReturnValueUsed(true); - addTypeReference(psiFrom, returnType, refFrom.getRefManager()); + addTypeReference(uFrom, returnType, refFrom.getRefManager()); } return; } - PsiMethodCallExpression call = PsiTreeUtil.getParentOfType( - refExpression, - PsiMethodCallExpression.class - ); + + UCallExpression call = null; + if (refExpression instanceof UCallExpression) { + call = (UCallExpression)refExpression; + } + else if (refExpression instanceof UQualifiedReferenceExpression) { + call = ObjectUtils.tryCast(((UQualifiedReferenceExpression)refExpression).getSelector(), UCallExpression.class); + } if (call != null) { - PsiType returnType = psiMethod.getReturnType(); - if (!psiMethod.isConstructor() && !PsiType.VOID.equals(returnType)) { - if (!ExpressionUtils.isVoidContext(call)) { + PsiType returnType = uMethod.getReturnType(); + if (!uMethod.isConstructor() && !PsiType.VOID.equals(returnType)) { + PsiExpression expression = ObjectUtils.tryCast(call.getJavaPsi(), PsiExpression.class); + if (expression == null || !ExpressionUtils.isVoidContext(expression)) { refMethod.setReturnValueUsed(true); } - addTypeReference(psiFrom, returnType, refFrom.getRefManager()); + addTypeReference(uFrom, returnType, refFrom.getRefManager()); } - PsiExpressionList argumentList = call.getArgumentList(); + List argumentList = call.getValueArguments(); if (!argumentList.isEmpty()) { - refMethod.updateParameterValues(argumentList.getExpressions(), psiMethod); + refMethod.updateParameterValues(argumentList, psiResolved); } - final PsiExpression psiExpression = call.getMethodExpression().getQualifierExpression(); - if (psiExpression != null) { - final PsiType usedType = psiExpression.getType(); + final UExpression uExpression = call.getReceiver(); + if (uExpression != null) { + final PsiType usedType = uExpression.getExpressionType(); if (usedType != null) { - final String fqName = psiMethod.getContainingClass().getQualifiedName(); - if (fqName != null) { - final PsiClassType methodOwnerType = JavaPsiFacade.getInstance(call.getProject()).getElementFactory() - .createTypeByFQClassName(fqName, GlobalSearchScope.allScope(psiMethod.getProject())); - if (!usedType.equals(methodOwnerType)) { - refMethod.setCalledOnSubClass(true); + UClass containingClass = UDeclarationKt.getContainingDeclaration(uMethod, UClass.class); + final String fqName; + if (containingClass != null) { + fqName = containingClass.getQualifiedName(); + if (fqName != null) { + final PsiClassType methodOwnerType = JavaPsiFacade.getInstance(psiResolved.getProject()).getElementFactory() + .createTypeByFQClassName(fqName, GlobalSearchScope.allScope(psiResolved.getProject())); + if (!usedType.equals(methodOwnerType)) { + refMethod.setCalledOnSubClass(true); + } } } } @@ -276,8 +421,13 @@ public class RefJavaUtilImpl extends RefJavaUtil{ } } - - + private static PsiType getFunctionalInterfaceType(UCallableReferenceExpression expression) { + PsiElement psi = expression.getSourcePsi(); + if (psi instanceof PsiFunctionalExpression) { + return ((PsiFunctionalExpression)psi).getFunctionalInterfaceType(); + } + return null; + } @Override public RefClass getTopLevelClass(@NotNull RefElement refElement) { @@ -316,135 +466,139 @@ public class RefJavaUtilImpl extends RefJavaUtil{ @NotNull @Override public String getAccessModifier(@NotNull PsiModifierListOwner psiElement) { - if (psiElement instanceof PsiParameter) return PsiModifier.PACKAGE_LOCAL; + if (psiElement instanceof PsiParameter) return PsiModifier.PACKAGE_LOCAL; - PsiModifierList list = psiElement.getModifierList(); - String result = PsiModifier.PACKAGE_LOCAL; + PsiModifierList list = psiElement.getModifierList(); + String result = PsiModifier.PACKAGE_LOCAL; - if (list != null) { - if (list.hasModifierProperty(PsiModifier.PRIVATE)) { - result = PsiModifier.PRIVATE; - } - else if (list.hasModifierProperty(PsiModifier.PROTECTED)) { - result = PsiModifier.PROTECTED; - } - else if (list.hasModifierProperty(PsiModifier.PUBLIC)) { - result = PsiModifier.PUBLIC; - } - else if (psiElement.getParent() instanceof PsiClass) { - PsiClass ownerClass = (PsiClass)psiElement.getParent(); - if (ownerClass.isInterface()) { - result = PsiModifier.PUBLIC; - } - if (ownerClass.isEnum() && result.equals(PsiModifier.PACKAGE_LOCAL)) { - result = PsiModifier.PRIVATE; - } - } - } + if (list != null) { + if (list.hasModifierProperty(PsiModifier.PRIVATE)) { + result = PsiModifier.PRIVATE; + } + else if (list.hasModifierProperty(PsiModifier.PROTECTED)) { + result = PsiModifier.PROTECTED; + } + else if (list.hasModifierProperty(PsiModifier.PUBLIC)) { + result = PsiModifier.PUBLIC; + } + else if (psiElement.getParent() instanceof PsiClass) { + PsiClass ownerClass = (PsiClass)psiElement.getParent(); + if (ownerClass.isInterface()) { + result = PsiModifier.PUBLIC; + } + } + } - return result; - } + return result; + } - @Override - @Nullable public RefClass getOwnerClass(RefManager refManager, PsiElement psiElement) { - while (psiElement != null && !(psiElement instanceof PsiClass)) { - psiElement = psiElement.getParent(); - } + @Override + @Nullable + public RefClass getOwnerClass(RefManager refManager, UElement uElement) { + while (uElement != null && !(uElement instanceof UClass)) { + uElement = uElement.getUastParent(); + } - return psiElement != null ? (RefClass)refManager.getReference(psiElement) : null; - } + return uElement != null ? (RefClass)refManager.getReference(uElement.getSourcePsi()) : null; + } - @Override - @Nullable public RefClass getOwnerClass(RefElement refElement) { - RefEntity parent = refElement.getOwner(); + @Override + @Nullable + public RefClass getOwnerClass(RefElement refElement) { + RefEntity parent = refElement.getOwner(); - while (!(parent instanceof RefClass) && parent instanceof RefElement) { - parent = parent.getOwner(); - } + while (!(parent instanceof RefClass) && parent instanceof RefElement) { + parent = parent.getOwner(); + } - if (parent instanceof RefClass) return (RefClass)parent; + if (parent instanceof RefClass) return (RefClass)parent; - return null; - } + return null; + } + @Override + public boolean isMethodOnlyCallsSuper(UMethod method) { + PsiMethod javaMethod = method.getJavaPsi(); + boolean hasStatements = false; + UExpression body = method.getUastBody(); + if (body != null) { + List statements = + body instanceof UBlockExpression ? ((UBlockExpression)body).getExpressions() : Collections.singletonList(body); + for (UExpression expression : statements) { + boolean isCallToSameSuper = false; + if (expression instanceof UReturnExpression) { + UExpression returnExpr = ((UReturnExpression)expression).getReturnExpression(); + isCallToSameSuper = returnExpr == null || isCallToSuperMethod(returnExpr, method); + } + else if (!(expression instanceof UBlockExpression)) { + isCallToSameSuper = isCallToSuperMethod(expression, method); + } - @Override - public boolean isMethodOnlyCallsSuper(PsiMethod method) { - boolean hasStatements = false; - PsiCodeBlock body = method.getBody(); - if (body != null) { - PsiStatement[] statements = body.getStatements(); - for (PsiStatement statement : statements) { - boolean isCallToSameSuper = false; - if (statement instanceof PsiExpressionStatement) { - isCallToSameSuper = isCallToSuperMethod(((PsiExpressionStatement)statement).getExpression(), method); - } - else if (statement instanceof PsiReturnStatement) { - PsiExpression expression = ((PsiReturnStatement)statement).getReturnValue(); - isCallToSameSuper = expression == null || isCallToSuperMethod(expression, method); - } + hasStatements = true; + if (isCallToSameSuper) continue; + return false; + } + } - hasStatements = true; - if (isCallToSameSuper) continue; + if (hasStatements) { + final PsiMethod[] superMethods = javaMethod.findSuperMethods(); + for (PsiMethod superMethod : superMethods) { + if (VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(superMethod.getModifierList()), + VisibilityUtil.getVisibilityModifier(javaMethod.getModifierList())) > 0) { + return false; + } + } + } + return hasStatements; + } - return false; - } - } + @Override + public boolean isCallToSuperMethod(UExpression expression, UMethod method) { + if (expression instanceof UQualifiedReferenceExpression) { + UExpression receiver = ((UQualifiedReferenceExpression)expression).getReceiver(); + UExpression selector = ((UQualifiedReferenceExpression)expression).getSelector(); - if (hasStatements) { - final PsiMethod[] superMethods = method.findSuperMethods(); - for (PsiMethod superMethod : superMethods) { - if (VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(superMethod.getModifierList()), - VisibilityUtil.getVisibilityModifier(method.getModifierList())) > 0) return false; - } - } - return hasStatements; - } + if (receiver instanceof USuperExpression && selector instanceof UCallExpression) { + PsiMethod superMethod = ((UCallExpression)selector).resolve(); + if (superMethod == null || !MethodSignatureUtil.areSignaturesEqual(method.getJavaPsi(), superMethod)) return false; - @Override - public boolean isCallToSuperMethod(PsiExpression expression, PsiMethod method) { - if (expression instanceof PsiMethodCallExpression) { - PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expression; - if (methodCall.getMethodExpression().getQualifierExpression() instanceof PsiSuperExpression) { - PsiMethod superMethod = (PsiMethod)methodCall.getMethodExpression().resolve(); - if (superMethod == null || !MethodSignatureUtil.areSignaturesEqual(method, superMethod)) return false; - PsiExpression[] args = methodCall.getArgumentList().getExpressions(); - PsiParameter[] parms = method.getParameterList().getParameters(); + List args = ((UCallExpression)selector).getValueArguments(); + List params = method.getUastParameters(); - for (int i = 0; i < args.length; i++) { - PsiExpression arg = args[i]; - if (!(arg instanceof PsiReferenceExpression)) return false; - if (!parms[i].equals(((PsiReferenceExpression)arg).resolve())) return false; - } + for (int i = 0; i < args.size(); i++) { + UExpression arg = args.get(i); + if (!(arg instanceof USimpleNameReferenceExpression)) return false; + if (!params.get(i).equals(((USimpleNameReferenceExpression)arg).resolve())) return false; + } - return true; - } - } + return true; + } + } - return false; - } + return false; + } - @Override - public int compareAccess(String a1, String a2) { - return Integer.compare(getAccessNumber(a1), getAccessNumber(a2)); - } + @Override + public int compareAccess(String a1, String a2) { + return Integer.compare(getAccessNumber(a1), getAccessNumber(a2)); + } - @SuppressWarnings("StringEquality") - private static int getAccessNumber(String a) { - if (a == PsiModifier.PRIVATE) { - return 0; - } - if (a == PsiModifier.PACKAGE_LOCAL) { - return 1; - } - if (a == PsiModifier.PROTECTED) { - return 2; - } - if (a == PsiModifier.PUBLIC) return 3; + @SuppressWarnings("StringEquality") + private static int getAccessNumber(String a) { + if (a == PsiModifier.PRIVATE) { + return 0; + } + if (a == PsiModifier.PACKAGE_LOCAL) { + return 1; + } + if (a == PsiModifier.PROTECTED) { + return 2; + } + if (a == PsiModifier.PUBLIC) return 3; - return -1; - } + return -1; + } @Override public void setAccessModifier(@NotNull RefJavaElement refElement, @NotNull String newAccess) { @@ -462,14 +616,14 @@ public class RefJavaUtilImpl extends RefJavaUtil{ } @Override - public void addTypeReference(PsiElement psiElement, PsiType psiType, RefManager refManager) { - addTypeReference(psiElement, psiType, refManager, null); + public void addTypeReference(UElement uElement, PsiType psiType, RefManager refManager) { + addTypeReference(uElement, psiType, refManager, null); } @Override - public void addTypeReference(PsiElement psiElement, PsiType psiType, RefManager refManager, @Nullable RefJavaElement refMethod) { + public void addTypeReference(UElement uElement, PsiType psiType, RefManager refManager, @Nullable RefJavaElement refMethod) { if (psiType != null) { - final RefClass ownerClass = getOwnerClass(refManager, psiElement); + final RefClass ownerClass = getOwnerClass(refManager, uElement); if (ownerClass != null) { psiType = psiType.getDeepComponentType(); if (psiType instanceof PsiClassType) { @@ -484,10 +638,44 @@ public class RefJavaUtilImpl extends RefJavaUtil{ } } else { - ((RefManagerImpl)refManager).fireNodeMarkedReferenced(psiClass, psiElement); + ((RefManagerImpl)refManager).fireNodeMarkedReferenced(psiClass, uElement.getSourcePsi()); } } } } } + + private static boolean isAccessedForWriting(@NotNull UElement expression) { + if (isOnAssignmentLeftHand(expression)) return true; + UElement parent = skipParenthesises(expression); + return isIncrementDecrement(parent); + } + + private static boolean isIncrementDecrement(UElement element) { + if (!(element instanceof UUnaryExpression)) return false; + UastOperator operator = ((UUnaryExpression)element).getOperator(); + return operator == UastPostfixOperator.DEC + || operator == UastPostfixOperator.INC + || operator == UastPrefixOperator.DEC + || operator == UastPrefixOperator.INC; + } + + private static boolean isAccessedForReading(@NotNull UElement expression) { + UElement parent = skipParenthesises(expression); + return !(parent instanceof UBinaryExpression) || + !(((UBinaryExpression)parent).getOperator() instanceof UastBinaryOperator.AssignOperator) || + UastUtils.isChildOf(((UBinaryExpression)parent).getRightOperand(), expression, false); + } + + private static boolean isOnAssignmentLeftHand(@NotNull UElement expression) { + UExpression parent = ObjectUtils.tryCast(skipParenthesises(expression), UExpression.class); + if (parent == null) return false; + return parent instanceof UBinaryExpression + && ((UBinaryExpression)parent).getOperator() instanceof UastBinaryOperator.AssignOperator + && UastUtils.isChildOf(expression, ((UBinaryExpression)parent).getLeftOperand(), false); + } + + private static UElement skipParenthesises(@NotNull UElement expression) { + return UastUtils.skipParentOfType(expression, true, UParenthesizedExpression.class); + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java index 965d869b160c..4e1c364634a2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java @@ -1,20 +1,7 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.reference; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.util.Comparing; @@ -27,6 +14,7 @@ import com.intellij.util.SmartList; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.*; import java.util.*; @@ -57,10 +45,10 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { private RefParameter[] myParameters; //guarded by this private String myReturnValueTemplate; //guarded by this - RefMethodImpl(@NotNull RefClass ownerClass, PsiMethod method, RefManager manager) { - super(method, manager); + RefMethodImpl(@NotNull RefElement ownerClass, UMethod method, PsiElement psi, RefManager manager) { + super(method, psi, manager); - ((RefClassImpl)ownerClass).add(this); + ((RefEntityImpl)ownerClass).add(this); } // To be used only from RefImplicitConstructor. @@ -75,8 +63,9 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { } @Override - public void add(@NotNull RefEntity child) { + public synchronized void add(@NotNull RefEntity child) { if (child instanceof RefParameter) { + ((RefEntityImpl)child).setOwner(this); return; } super.add(child); @@ -97,8 +86,10 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { @Override protected void initialize() { - final PsiMethod method = (PsiMethod)getElement(); + UMethod method = (UMethod)getUastElement(); LOG.assertTrue(method != null); + PsiMethod javaPsi = method.getJavaPsi(); + setConstructor(method.isConstructor()); final PsiType returnType = method.getReturnType(); setFlag(returnType == null || @@ -111,46 +102,53 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { } } + RefClass ownerClass = getOwnerClass(); if (isConstructor()) { - addReference(getOwnerClass(), getOwnerClass().getElement(), method, false, true, null); + LOG.assertTrue(ownerClass != null); + addReference(ownerClass, ownerClass.getPsiElement(), method, false, true, null); } - if (getOwnerClass().isInterface()) { + if (ownerClass != null && ownerClass.isInterface()) { setAbstract(false); } else { - setAbstract(method.hasModifierProperty(PsiModifier.ABSTRACT)); + setAbstract(javaPsi.hasModifierProperty(PsiModifier.ABSTRACT)); } - setAppMain(isAppMain(method, this)); - setLibraryOverride(method.hasModifierProperty(PsiModifier.NATIVE)); + setAppMain(isAppMain(javaPsi, this)); + boolean isNative = javaPsi.hasModifierProperty(PsiModifier.NATIVE); + setLibraryOverride(isNative); - initializeSuperMethods(method); - if (isExternalOverride()) { - ((RefClassImpl)getOwnerClass()).addLibraryOverrideMethod(this); + initializeSuperMethods(javaPsi); + if (ownerClass != null && isExternalOverride()) { + ((RefClassImpl)ownerClass).addLibraryOverrideMethod(this); } @NonNls final String name = method.getName(); - if (getOwnerClass().isTestCase() && name.startsWith("test")) { + if (ownerClass != null && ownerClass.isTestCase() && name.startsWith("test")) { setTestMethod(true); } - PsiParameter[] paramList = method.getParameterList().getParameters(); - if (paramList.length > 0){ - RefParameter[] newParameters = new RefParameterImpl[paramList.length]; - for (int i = 0; i < paramList.length; i++) { - newParameters[i] = getRefJavaManager().getParameterReference(paramList[i], i); + List paramList = method.getUastParameters(); + if (!paramList.isEmpty()){ + RefParameter[] newParameters = new RefParameterImpl[paramList.size()]; + for (int i = 0; i < paramList.size(); i++) { + newParameters[i] = getRefJavaManager().getParameterReference(paramList.get(i), i, this); } synchronized (this) { myParameters = newParameters; } } - if (method.hasModifierProperty(PsiModifier.NATIVE)) { + if (isNative) { updateReturnValueTemplate(null); updateThrowsList(null); } - collectUncaughtExceptions(method); + + PsiElement sourcePsi = method.getSourcePsi(); + if (sourcePsi != null && sourcePsi.getLanguage().isKindOf(JavaLanguage.INSTANCE)) { + collectUncaughtExceptions((PsiMethod)sourcePsi); + } } private static boolean isAppMain(PsiMethod psiMethod, RefMethod refMethod) { @@ -167,35 +165,29 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { return MethodSignatureUtil.areSignaturesEqual(psiMethod, appAgentmainPattern); } - private void checkForSuperCall(PsiMethod method) { + private void checkForSuperCall(UMethod method) { if (isConstructor()) { - PsiCodeBlock body = method.getBody(); + UExpression body = method.getUastBody(); if (body == null) return; - PsiStatement[] statements = body.getStatements(); + + List statements = body instanceof UBlockExpression ? ((UBlockExpression)body).getExpressions() : Collections.singletonList(body); boolean isBaseExplicitlyCalled = false; - if (statements.length > 0) { - PsiStatement first = statements[0]; - if (first instanceof PsiExpressionStatement) { - PsiExpression firstExpression = ((PsiExpressionStatement) first).getExpression(); - if (firstExpression instanceof PsiMethodCallExpression) { - PsiExpression qualifierExpression = ((PsiMethodCallExpression)firstExpression).getMethodExpression().getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression) { - @NonNls String text = qualifierExpression.getText(); - if ("super".equals(text) || text.equals("this")) { - isBaseExplicitlyCalled = true; - } - } - } + if (!statements.isEmpty()) { + UExpression first = statements.get(0); + if (first instanceof UCallExpression && ((UCallExpression)first).getKind() == UastCallKind.CONSTRUCTOR_CALL) { + isBaseExplicitlyCalled = true; } } if (!isBaseExplicitlyCalled) { - for (RefClass superClass : getOwnerClass().getBaseClasses()) { - RefMethodImpl superDefaultConstructor = (RefMethodImpl)superClass.getDefaultConstructor(); - - if (superDefaultConstructor != null) { - superDefaultConstructor.addInReference(this); - addOutReference(superDefaultConstructor); + RefClass ownerClass = getOwnerClass(); + if (ownerClass != null) { + for (RefClass superClass : ownerClass.getBaseClasses()) { + RefMethodImpl superDefaultConstructor = (RefMethodImpl)superClass.getDefaultConstructor(); + if (superDefaultConstructor != null) { + superDefaultConstructor.addInReference(this); + addOutReference(superDefaultConstructor); + } } } } @@ -282,22 +274,21 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { @Override public void buildReferences() { // Work on code block to find what we're referencing... - PsiMethod method = (PsiMethod) getElement(); + UMethod method = (UMethod)getUastElement(); if (method == null) return; - PsiCodeBlock body = method.getBody(); + UExpression body = method.getUastBody(); final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - refUtil.addReferences(method, this, method); + refUtil.addReferencesTo(method, this, method); checkForSuperCall(method); setOnlyCallsSuper(refUtil.isMethodOnlyCallsSuper(method)); - setBodyEmpty(isOnlyCallsSuper() || !isExternalOverride() && (body == null || body.isEmpty())); - - refUtil.addTypeReference(method, method.getReturnType(), getRefManager(), this); + setBodyEmpty(isOnlyCallsSuper() || !isExternalOverride() && isEmptyExpression(body)); + refUtil.addTypeReference((UElement)method, method.getReturnType(), getRefManager(), this); for (RefParameter parameter : getParameters()) { - PsiParameter psiParameter = parameter.getElement(); - if (psiParameter != null) { - refUtil.setIsFinal(parameter, psiParameter.hasModifierProperty(PsiModifier.FINAL)); + UParameter uParameter = parameter.getUastElement(); + if (uParameter != null) { + refUtil.setIsFinal(parameter, uParameter.isFinal()); } } @@ -376,6 +367,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { public boolean isReferenced() { // Directly called from somewhere.. for (RefElement refCaller : getInReferences()) { + //noinspection SuspiciousMethodCalls if (!getDerivedMethods().contains(refCaller)) return true; } @@ -387,6 +379,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { public boolean hasSuspiciousCallers() { // Directly called from somewhere.. for (RefElement refCaller : getInReferences()) { + //noinspection SuspiciousMethodCalls if (((RefElementImpl)refCaller).isSuspicious() && !getDerivedMethods().contains(refCaller)) return true; } @@ -409,9 +402,10 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { return checkFlag(IS_CONSTRUCTOR_MASK); } + @Nullable @Override public RefClass getOwnerClass() { - return (RefClass) getOwner(); + return ObjectUtils.tryCast(getOwner(), RefClass.class); } @NotNull @@ -419,11 +413,11 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { public String getName() { if (isValid()) { return ReadAction.compute(() -> { - PsiMethod psiMethod = (PsiMethod) getElement(); - if (psiMethod instanceof SyntheticElement) { - return psiMethod.getName(); + UMethod uMethod = (UMethod)getUastElement(); + if (uMethod instanceof SyntheticElement) { + return uMethod.getName(); } - return PsiFormatUtil.formatMethod(psiMethod, + return PsiFormatUtil.formatMethod(uMethod.getJavaPsi(), PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_TYPE); @@ -435,9 +429,10 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { @Override public String getExternalName() { return ReadAction.compute(() -> { - final PsiMethod psiMethod = (PsiMethod)getElement(); - LOG.assertTrue(psiMethod != null); - return PsiFormatUtil.getExternalName(psiMethod, true, Integer.MAX_VALUE); + final UMethod uMethod = (UMethod)getUastElement(); + LOG.assertTrue(uMethod != null); + PsiMethod javaMethod = uMethod.getJavaPsi(); + return PsiFormatUtil.getExternalName(javaMethod, true, Integer.MAX_VALUE); }); } @@ -482,7 +477,10 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { @Override public boolean isSuspicious() { - if (isConstructor() && PsiModifier.PRIVATE.equals(getAccessModifier()) && getParameters().length == 0 && getOwnerClass().getConstructors().size() == 1) return false; + if (isConstructor() && + PsiModifier.PRIVATE.equals(getAccessModifier()) && + getParameters().length == 0 && + Objects.requireNonNull(getOwnerClass()).getConstructors().size() == 1) return false; return super.isSuspicious(); } @@ -499,7 +497,8 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { return checkFlag(IS_RETURN_VALUE_USED_MASK); } - void updateReturnValueTemplate(PsiExpression expression) { + void updateReturnValueTemplate(UExpression expression) { + if (expression == null) return; synchronized (this) { if (myReturnValueTemplate == null) return; } @@ -513,25 +512,26 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { else { String newTemplate = null; final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - if (expression instanceof PsiLiteralExpression) { - PsiLiteralExpression psiLiteralExpression = (PsiLiteralExpression)expression; - newTemplate = psiLiteralExpression.getText(); + if (expression instanceof ULiteralExpression) { + ULiteralExpression psiLiteralExpression = (ULiteralExpression)expression; + newTemplate = String.valueOf(psiLiteralExpression.getValue()); } - else if (expression instanceof PsiReferenceExpression) { - PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression; - PsiElement resolved = referenceExpression.resolve(); - if (resolved instanceof PsiField) { - PsiField psiField = (PsiField)resolved; - if (psiField.hasModifierProperty(PsiModifier.STATIC) && - psiField.hasModifierProperty(PsiModifier.FINAL) && - refUtil.compareAccess(refUtil.getAccessModifier(psiField), getAccessModifier()) >= 0) { - newTemplate = PsiFormatUtil.formatVariable(psiField, PsiFormatUtilBase.SHOW_NAME | + else if (expression instanceof UResolvable) { + UResolvable referenceExpression = (UResolvable)expression; + UElement resolved = UResolvableKt.resolveToUElement(referenceExpression); + if (resolved instanceof UField) { + UField uField = (UField)resolved; + PsiField psi = (PsiField)uField.getJavaPsi(); + if (uField.isStatic() && + uField.isFinal() && + refUtil.compareAccess(refUtil.getAccessModifier(psi), getAccessModifier()) >= 0) { + newTemplate = PsiFormatUtil.formatVariable(psi, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_FQ_NAME, PsiSubstitutor.EMPTY); } } } - else if (refUtil.isCallToSuperMethod(expression, (PsiMethod)getElement())) return; + else if (refUtil.isCallToSuperMethod(expression, (UMethod)getUastElement())) return; synchronized (this) { //noinspection StringEquality @@ -545,7 +545,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { } } - void updateParameterValues(PsiExpression[] args, @Nullable PsiElement elementPlace) { + void updateParameterValues(List args, @Nullable PsiElement elementPlace) { if (isExternalOverride()) return; if (!getSuperMethods().isEmpty()) { @@ -554,11 +554,11 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { } } else { final RefParameter[] params = getParameters(); - for (int i = 0; i < Math.min(params.length, args.length); i++) { - ((RefParameterImpl)params[i]).updateTemplateValue(args[i], elementPlace); + for (int i = 0; i < Math.min(params.length, args.size()); i++) { + ((RefParameterImpl)params[i]).updateTemplateValue(args.get(i), elementPlace); } - if (params.length != args.length && params.length > 0) { + if (params.length != args.size() && params.length != 0) { ((RefParameterImpl)params[params.length - 1]).clearTemplateValue(); } } @@ -653,8 +653,8 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { } @Override - public PsiModifierListOwner getElement() { - return (PsiModifierListOwner)super.getElement(); + public UDeclaration getUastElement() { + return UastContextKt.toUElement(getPsiElement(), UMethod.class); } @Override @@ -665,4 +665,10 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { void setCalledOnSubClass(boolean isCalledOnSubClass){ setFlag(isCalledOnSubClass, IS_CALLED_ON_SUBCLASS_MASK); } + + public static boolean isEmptyExpression(@Nullable UExpression expression) { + if (expression == null) return true; + if (expression instanceof UBlockExpression) return ((UBlockExpression)expression).getExpressions().isEmpty(); + return false; + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java index 312508115b69..f97cab286e8b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefParameterImpl.java @@ -3,33 +3,49 @@ package com.intellij.codeInspection.reference; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.util.Comparing; -import com.intellij.psi.*; -import com.intellij.psi.impl.JavaConstantExpressionEvaluator; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifierListOwner; +import com.intellij.psi.PsiResolveHelper; import com.intellij.psi.util.PsiFormatUtil; -import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.*; +import java.util.List; +import java.util.Objects; import java.util.function.Supplier; public class RefParameterImpl extends RefJavaElementImpl implements RefParameter { private static final int USED_FOR_READING_MASK = 0x10000; private static final int USED_FOR_WRITING_MASK = 0x20000; + private final short myIndex; private Object myActualValueTemplate; private int myUsageCount; - RefParameterImpl(PsiParameter parameter, int index, RefManager manager) { - super(parameter, manager); + RefParameterImpl(UParameter parameter, + PsiElement psi, + int index, + RefManager manager, + RefMethod refMethod) { + super(parameter, psi, manager); myIndex = (short)index; myActualValueTemplate = VALUE_UNDEFINED; - final RefElementImpl owner = (RefElementImpl)manager.getReference(PsiTreeUtil.getParentOfType(parameter, PsiMethod.class)); + final RefElementImpl owner = (RefElementImpl)refMethod; if (owner != null) { owner.add(this); } + + //TODO kotlin receiver parameter must be used + if (myIndex == 0 && "$receiver".equals(getName())) { + setUsedForReading(); + } } @Override @@ -50,11 +66,6 @@ public class RefParameterImpl extends RefJavaElementImpl implements RefParameter setFlag(true, USED_FOR_READING_MASK); } - @Override - public PsiParameter getElement() { - return (PsiParameter)super.getElement(); - } - @Override public int getUsageCount() { return myUsageCount; @@ -86,17 +97,20 @@ public class RefParameterImpl extends RefJavaElementImpl implements RefParameter @Override public void buildReferences() { final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - final PsiParameter parameter = getElement(); + final UParameter parameter = getUastElement(); if (parameter != null) { - refUtil.addReferences(parameter, this, parameter.getModifierList()); + List annotations = ((UAnnotated)parameter).getAnnotations(); + refUtil.addReferencesTo(parameter, this, annotations.toArray(new UElement[0])); + UTypeReferenceExpression typeReference = parameter.getTypeReference(); + refUtil.addReferencesTo(parameter, this, typeReference); } } void clearTemplateValue() { myActualValueTemplate = VALUE_IS_NOT_CONST; } - - void updateTemplateValue(PsiExpression expression, @Nullable PsiElement accessPlace) { + + void updateTemplateValue(UExpression expression, @Nullable PsiElement accessPlace) { myUsageCount++; if (myActualValueTemplate == VALUE_IS_NOT_CONST) return; @@ -121,55 +135,64 @@ public class RefParameterImpl extends RefJavaElementImpl implements RefParameter @Override public String getExternalName() { - final String[] result = new String[1]; - final Runnable runnable = () -> { - PsiParameter parameter = getElement(); + return ReadAction.compute(() -> { + UParameter parameter = getUastElement(); LOG.assertTrue(parameter != null); - result[0] = PsiFormatUtil.getExternalName(parameter); - }; + return PsiFormatUtil.getExternalName((PsiModifierListOwner)parameter.getJavaPsi()); + }); + } - ApplicationManager.getApplication().runReadAction(runnable); - - return result[0]; + @Override + public UParameter getUastElement() { + // kotlin receiver parameter (psi <-> uast conversion isn't symmetric) + RefMethod method = ObjectUtils.tryCast(getOwner(), RefMethod.class); + if (method == null) return null; + UMethod uMethod = ObjectUtils.tryCast(method.getUastElement(), UMethod.class); + if (uMethod == null) return null; + List parameters = uMethod.getUastParameters(); + if (parameters.size() <= getIndex()) return null; + return parameters.get(getIndex()); } @Nullable - public static Object getAccessibleExpressionValue(PsiExpression expression, Supplier accessPlace) { - if (expression instanceof PsiReferenceExpression) { - PsiReferenceExpression referenceExpression = (PsiReferenceExpression) expression; - PsiElement resolved = referenceExpression.resolve(); - if (resolved instanceof PsiField) { - PsiField psiField = (PsiField) resolved; + public static Object getAccessibleExpressionValue(UExpression expression, Supplier accessPlace) { + if (expression instanceof UReferenceExpression) { + UReferenceExpression referenceExpression = (UReferenceExpression) expression; + UElement resolved = UResolvableKt.resolveToUElement(referenceExpression); + if (resolved instanceof UField) { + UField uField = (UField) resolved; PsiElement element = accessPlace.get(); - if (psiField.hasModifierProperty(PsiModifier.STATIC) && psiField.hasModifierProperty(PsiModifier.FINAL)) { - if (element == null || !isAccessible(psiField, element)) { + if (uField.isStatic() && uField.isFinal()) { + if (element == null || !isAccessible(uField, element)) { return VALUE_IS_NOT_CONST; } - PsiClass containingClass = psiField.getContainingClass(); - if (containingClass != null && containingClass.getQualifiedName() != null) { - return psiField; + UDeclaration containingClass = UDeclarationKt.getContainingDeclaration(uField); + if (containingClass instanceof UClass && ((UClass) containingClass).getQualifiedName() != null) { + return uField; } } } } - if (expression instanceof PsiLiteralExpression) { - if (((PsiLiteralExpression)expression).getValue() == null) { + if (expression instanceof ULiteralExpression) { + Object value = ((ULiteralExpression)expression).getValue(); + if (value == null) { return null; } //don't unescape/escape to insert into the source file - return expression.getText(); + PsiElement sourcePsi = Objects.requireNonNull(expression.getSourcePsi()); + return value instanceof String ? ("\"" + StringUtil.unquoteString(sourcePsi.getText()) + "\""): value; } - Object constValue = JavaConstantExpressionEvaluator.computeConstantExpression(expression, false); + Object constValue = expression.evaluate(); //JavaConstantExpressionEvaluator.computeConstantExpression(expression, false); return constValue == null ? VALUE_IS_NOT_CONST : constValue instanceof String ? "\"" + constValue + "\"" : constValue; } - private static boolean isAccessible(@NotNull PsiField field, @NotNull PsiElement place) { - PsiClass fieldContainingClass = field.getContainingClass(); - if (fieldContainingClass == null) return false; - String qName = fieldContainingClass.getQualifiedName(); + private static boolean isAccessible(@NotNull UField field, @NotNull PsiElement place) { + UDeclaration fieldContainingClass = UDeclarationKt.getContainingDeclaration(field); + if (!(fieldContainingClass instanceof UClass)) return false; + String qName = ((UClass)fieldContainingClass).getQualifiedName(); if (qName == null) return false; String fieldQName = qName + "." + field.getName(); - return PsiResolveHelper.SERVICE.getInstance(field.getProject()).resolveReferencedVariable(fieldQName, place) != null; + return PsiResolveHelper.SERVICE.getInstance(place.getProject()).resolveReferencedVariable(fieldQName, place) != null; } @Nullable @@ -179,15 +202,15 @@ public class RefParameterImpl extends RefJavaElementImpl implements RefParameter final String method = fqName.substring(0, idx); final RefMethod refMethod = RefMethodImpl.methodFromExternalName(manager, method); if (refMethod != null) { - final PsiMethod element = (PsiMethod)refMethod.getElement(); - final PsiParameterList list = element.getParameterList(); - final PsiParameter[] parameters = list.getParameters(); + final UMethod element = ObjectUtils.tryCast(refMethod.getUastElement(), UMethod.class); + if (element == null) return null; + final List parameters = element.getUastParameters(); int paramIdx = 0; final String paramName = fqName.substring(idx + 1); - for (PsiParameter parameter : parameters) { + for (UParameter parameter : parameters) { final String name = parameter.getName(); if (name != null && name.equals(paramName)) { - return manager.getExtension(RefJavaManager.MANAGER).getParameterReference(parameter, paramIdx); + return manager.getExtension(RefJavaManager.MANAGER).getParameterReference(parameter, paramIdx, refMethod); } paramIdx++; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/sameReturnValue/SameReturnValueInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/sameReturnValue/SameReturnValueInspection.java index 0020b6f19f15..bfabb7578ea8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/sameReturnValue/SameReturnValueInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/sameReturnValue/SameReturnValueInspection.java @@ -19,10 +19,11 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInspection.*; import com.intellij.codeInspection.reference.*; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiModifierListOwner; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclaration; +import org.jetbrains.uast.UElement; /** * @author max @@ -49,9 +50,15 @@ public class SameReturnValueInspection extends GlobalJavaBatchInspectionTool { message = InspectionsBundle.message("inspection.same.return.value.problem.descriptor2", "" + returnValue + ""); } - final PsiModifierListOwner element = refMethod.getElement(); - if (element != null) { - return new ProblemDescriptor[] {manager.createProblemDescriptor(element.getNavigationElement(), message, false, null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING)}; + final UDeclaration decl = refMethod.getUastElement(); + if (decl != null) { + UElement anchor = decl.getUastAnchor(); + if (anchor != null) { + PsiElement psiAnchor = anchor.getSourcePsi(); + if (psiAnchor != null) { + return new ProblemDescriptor[] {manager.createProblemDescriptor(psiAnchor, message, false, null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING)}; + } + } } } } @@ -68,12 +75,9 @@ public class SameReturnValueInspection extends GlobalJavaBatchInspectionTool { if (refEntity instanceof RefElement && processor.getDescriptions(refEntity) != null) { refEntity.accept(new RefJavaVisitor() { @Override public void visitMethod(@NotNull final RefMethod refMethod) { - globalContext.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { - @Override - public boolean process(PsiMethod derivedMethod) { - processor.ignoreElement(refMethod); - return false; - } + globalContext.enqueueDerivedMethodsProcessor(refMethod, derivedMethod -> { + processor.ignoreElement(refMethod); + return false; }); } }); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyAnnotator.java b/java/java-analysis-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyAnnotator.java index b14eaa874758..f044ede7a5cc 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyAnnotator.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/unnecessaryModuleDependency/UnnecessaryModuleDependencyAnnotator.java @@ -13,7 +13,9 @@ import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.uast.*; import java.util.*; @@ -36,7 +38,7 @@ public class UnnecessaryModuleDependencyAnnotator extends RefGraphAnnotator { final RefModule refModule = myManager.getRefModule(fromModule); if (refModule != null) { HashSet modules = new HashSet<>(onModules); - collectRequiredModulesInHierarchy(what, modules); + collectRequiredModulesInHierarchy(myManager.getReference(what), modules); modules.remove(fromModule); getModules(refModule).addAll(modules); } @@ -61,11 +63,10 @@ public class UnnecessaryModuleDependencyAnnotator extends RefGraphAnnotator { @Override public void onInitialize(RefElement refElement) { - PsiElement element = refElement.getElement(); RefModule refModule = refElement.getModule(); if (refModule != null) { HashSet modules = new HashSet<>(); - collectRequiredModulesInHierarchy(element, modules); + collectRequiredModulesInHierarchy(refElement, modules); modules.remove(refModule.getModule()); if (!modules.isEmpty()) { refElement.putUserData(DEPENDENCIES, modules); @@ -74,42 +75,55 @@ public class UnnecessaryModuleDependencyAnnotator extends RefGraphAnnotator { } } - private void collectRequiredModulesInHierarchy(PsiElement element, Set modules) { - if (element instanceof PsiClass) { - processClassHierarchy((PsiClass)element, modules); + private void collectRequiredModulesInHierarchy(RefElement refElement, Set modules) { + if (refElement instanceof RefClass) { + processClassHierarchy(null, (RefClass)refElement, modules); } - else if (element instanceof PsiMethod) { - PsiMethod method = (PsiMethod)element; - Set classes = new HashSet<>(); - processTypeHierarchy(classes, method.getReturnType(), modules); - for (PsiParameter parameter : method.getParameterList().getParameters()) { - processTypeHierarchy(classes, parameter.getType(), modules); + else if (refElement instanceof RefMethod) { + UMethod uMethod = ObjectUtils.tryCast(((RefMethod)refElement).getUastElement(), UMethod.class); + if (uMethod != null) { + Set classes = new HashSet<>(); + processTypeHierarchy(classes, uMethod.getReturnType(), modules); + for (UParameter parameter : uMethod.getUastParameters()) { + processTypeHierarchy(classes, parameter.getType(), modules); + } } } - else if (element instanceof PsiField) { - PsiClass aClass = PsiUtil.resolveClassInType(((PsiField)element).getType()); + else if (refElement instanceof RefField) { + UField element = ((RefField)refElement).getUastElement(); + UClass aClass = UastContextKt.toUElement(PsiUtil.resolveClassInType(element.getType()), UClass.class); if (aClass != null) { - processClassHierarchy(aClass, modules); + processClassHierarchy(aClass, null, modules); } } } private void processTypeHierarchy(Set classes, PsiType returnType, Set modules) { - PsiClass aClass = PsiUtil.resolveClassInType(returnType); + UClass aClass = UastContextKt.toUElement(PsiUtil.resolveClassInType(returnType), UClass.class); if (aClass != null && classes.add(aClass)) { - processClassHierarchy(aClass, modules); + processClassHierarchy(aClass, null, modules); } } - private void processClassHierarchy(PsiClass currentClass, Set modules) { - LinkedHashSet superClasses = new LinkedHashSet<>(); - RefElement refClass = myManager.getReference(currentClass); - if (!(refClass instanceof RefClass)) { - InheritanceUtil.getSuperClasses(currentClass, superClasses, false); + private void processClassHierarchy(UClass uClass, RefClass refClass, Set modules) { + LinkedHashSet superClasses = new LinkedHashSet<>(); + if (refClass == null) { + refClass = ObjectUtils.tryCast(myManager.getReference(uClass.getPsi()), RefClass.class); + } + if (refClass == null) { + PsiClass psiClass = uClass.getJavaPsi(); + PsiManager psiManager = psiClass.getManager(); + InheritanceUtil.processSupers(psiClass, false, s -> { + UClass uc = UastContextKt.toUElement(s, UClass.class); + if (uc != null && psiManager.isInProject(s)) { + superClasses.add(uc); + } + return true; + }); } else { - for (RefClass aClass : ((RefClass)refClass).getBaseClasses()) { - PsiClass superClass = aClass.getElement(); + for (RefClass aClass : refClass.getBaseClasses()) { + UClass superClass = aClass.getUastElement(); if (superClass != null) { superClasses.add(superClass); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsDeclarationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsDeclarationInspection.java index 1308381c5f78..2509229c3a68 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsDeclarationInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsDeclarationInspection.java @@ -17,6 +17,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; import com.intellij.util.Query; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nls; @@ -68,10 +69,11 @@ public class RedundantThrowsDeclarationInspection extends GlobalJavaBatchInspect PsiClass[] unThrown = refMethod.getUnThrownExceptions(); if (unThrown == null) return null; - PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); - if (psiMethod == null) return null; - PsiClassType[] throwsList = psiMethod.getThrowsList().getReferencedTypes(); - PsiJavaCodeReferenceElement[] throwsRefs = psiMethod.getThrowsList().getReferenceElements(); + PsiElement psiMethod = refMethod.getPsiElement(); + if (!(psiMethod instanceof PsiMethod)) return null; + PsiReferenceList list = ((PsiMethod)psiMethod).getThrowsList(); + PsiClassType[] throwsList = list.getReferencedTypes(); + PsiJavaCodeReferenceElement[] throwsRefs = list.getReferenceElements(); List problems = null; final PsiManager psiManager = psiMethod.getManager(); @@ -80,7 +82,7 @@ public class RedundantThrowsDeclarationInspection extends GlobalJavaBatchInspect final String throwsClassName = throwsType.getClassName(); final PsiJavaCodeReferenceElement throwsRef = throwsRefs[i]; if (ExceptionUtil.isUncheckedException(throwsType)) continue; - if (declaredInRemotableMethod(psiMethod, throwsType)) continue; + if (declaredInRemotableMethod((PsiMethod)psiMethod, throwsType)) continue; for (PsiClass s : unThrown) { final PsiClass throwsResolvedType = throwsType.resolve(); @@ -132,12 +134,9 @@ public class RedundantThrowsDeclarationInspection extends GlobalJavaBatchInspect if (processor.getDescriptions(refEntity) != null) { refEntity.accept(new RefJavaVisitor() { @Override public void visitMethod(@NotNull final RefMethod refMethod) { - globalContext.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { - @Override - public boolean process(PsiMethod derivedMethod) { - processor.ignoreElement(refMethod); - return true; - } + globalContext.enqueueDerivedMethodsProcessor(refMethod, derivedMethod -> { + processor.ignoreElement(refMethod); + return true; }); } }); @@ -206,7 +205,7 @@ public class RedundantThrowsDeclarationInspection extends GlobalJavaBatchInspect @Nullable final PsiMethod psiMethod; if (element == null) { LOG.assertTrue(refMethod != null); - psiMethod = (PsiMethod)refMethod.getElement(); + psiMethod = ObjectUtils.tryCast(refMethod.getPsiElement(), PsiMethod.class); } else { psiMethod = (PsiMethod)element; @@ -260,8 +259,8 @@ public class RedundantThrowsDeclarationInspection extends GlobalJavaBatchInspect assert myProcessor != null; for (RefMethod refDerived : refMethod.getDerivedMethods()) { - PsiModifierListOwner method = refDerived.getElement(); - if (method != null) { + PsiElement method = refDerived.getPsiElement(); + if (method instanceof PsiMethod) { removeException(refDerived, exceptionType, refsToDelete, (PsiMethod)method); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsGraphAnnotator.java b/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsGraphAnnotator.java index 876c8fa514fa..0c5c776d4823 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsGraphAnnotator.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/unneededThrows/RedundantThrowsGraphAnnotator.java @@ -22,7 +22,7 @@ public final class RedundantThrowsGraphAnnotator extends RefGraphAnnotatorEx { @Override public void onInitialize(RefElement refElement) { if (refElement instanceof RefMethodImpl) { - PsiElement element = refElement.getElement(); + PsiElement element = refElement.getPsiElement(); if (element instanceof PsiMethod) { PsiMethod method = (PsiMethod)element; final PsiCodeBlock body = method.getBody(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java index 169d050f0f16..63caf943ce00 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java @@ -22,6 +22,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.ui.components.panels.VerticalBox; import com.intellij.usageView.UsageViewTypeLocation; +import com.intellij.util.ObjectUtils; import com.intellij.util.VisibilityUtil; import one.util.streamex.StreamEx; import org.jdom.Element; @@ -29,6 +30,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; +import org.jetbrains.uast.UClass; import javax.swing.*; import java.awt.*; @@ -246,7 +248,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { private static CommonProblemDescriptor[] createDescriptions(RefElement refElement, String access, @NotNull InspectionManager manager, @NotNull GlobalInspectionContext globalContext) { - final PsiElement element = refElement.getElement(); + final PsiElement element = refElement.getPsiElement(); final PsiElement nameIdentifier = element != null ? IdentifierUtil.getNameIdentifier(element) : null; if (nameIdentifier != null) { final String message; @@ -289,7 +291,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { @EntryPointWithVisibilityLevel.VisibilityLevelResult private int getMinVisibilityLevel(@NotNull RefJavaElement refElement) { - PsiElement element = refElement.getElement(); + PsiElement element = refElement.getPsiElement(); if (element instanceof PsiMember) { return getMinVisibilityLevel((PsiMember)element); } @@ -431,7 +433,8 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { if (accessModifier == PsiModifier.PRIVATE) { if (SUGGEST_PRIVATE_FOR_INNERS) { - final PsiClass fromTopLevelElement = fromTopLevel != null ? fromTopLevel.getElement() : null; + //TODO + final PsiClass fromTopLevelElement = fromTopLevel != null ? (PsiClass)fromTopLevel.getPsiElement() : null; if (fromTopLevelElement != null && isInExtendsList(to, fromTopLevelElement.getExtendsList())) return false; if (fromTopLevelElement != null && isInExtendsList(to, fromTopLevelElement.getImplementsList())) return false; if (fromTopLevelElement != null && isInAnnotations(to, fromTopLevelElement)) return false; @@ -444,8 +447,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { if (fromTopLevel == toOwner) { if (from instanceof RefClass && to instanceof RefClass) { - final PsiClass fromClass = ((RefClass)from).getElement(); - LOG.assertTrue(fromClass != null); + PsiClass fromClass = ((RefClass)from).getUastElement().getJavaPsi(); if (isInExtendsList(to, fromClass.getExtendsList())) return false; if (isInExtendsList(to, fromClass.getImplementsList())) return false; } @@ -460,7 +462,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { private static boolean isInAnnotations(final RefJavaElement to, @NotNull final PsiClass fromTopLevelElement) { final PsiModifierList modifierList = fromTopLevelElement.getModifierList(); if (modifierList == null) return false; - final PsiElement toElement = to.getElement(); + final PsiElement toElement = to.getPsiElement(); final boolean [] resolved = {false}; modifierList.accept(new JavaRecursiveElementWalkingVisitor() { @@ -483,7 +485,7 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { final PsiReferenceParameterList parameterList = referenceElement.getParameterList(); if (parameterList != null) { for (PsiType type : parameterList.getTypeArguments()) { - if (extendsList.getManager().areElementsEquivalent(PsiUtil.resolveClassInType(type), to.getElement())) { + if (extendsList.getManager().areElementsEquivalent(PsiUtil.resolveClassInType(type), to.getPsiElement())) { return true; } } @@ -554,16 +556,16 @@ public class VisibilityInspection extends GlobalJavaBatchInspectionTool { final RefMethod defaultConstructor = refClass.getDefaultConstructor(); if (entryPointsManager.isAddNonJavaEntries() && defaultConstructor != null) { - final PsiClass psiClass = refClass.getElement(); + final PsiClass psiClass = ObjectUtils.tryCast(refClass.getPsiElement(), PsiClass.class); String qualifiedName = psiClass != null ? psiClass.getQualifiedName() : null; if (qualifiedName != null) { final Project project = manager.getProject(); PsiSearchHelper.getInstance(project) - .processUsagesInNonJavaFiles(qualifiedName, (file, startOffset, endOffset) -> { - entryPointsManager.addEntryPoint(defaultConstructor, false); - ignoreElement(processor, defaultConstructor); - return false; - }, GlobalSearchScope.projectScope(project)); + .processUsagesInNonJavaFiles(qualifiedName, (file, startOffset, endOffset) -> { + entryPointsManager.addEntryPoint(defaultConstructor, false); + ignoreElement(processor, defaultConstructor); + return false; + }, GlobalSearchScope.projectScope(project)); } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/MakeVoidQuickFix.java b/java/java-impl/src/com/intellij/codeInspection/MakeVoidQuickFix.java index d8d460ece173..f46a13438e59 100644 --- a/java/java-impl/src/com/intellij/codeInspection/MakeVoidQuickFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/MakeVoidQuickFix.java @@ -60,7 +60,7 @@ public class MakeVoidQuickFix implements LocalQuickFix { RefElement refElement = (RefElement)myProcessor.getElement(descriptor); if (refElement instanceof RefMethod && refElement.isValid()) { RefMethod refMethod = (RefMethod)refElement; - psiMethod = (PsiMethod)refMethod.getElement(); + psiMethod = (PsiMethod)refMethod.getPsiElement(); } } else { diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/DeadHTMLComposer.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/DeadHTMLComposer.java index c7086efc2f38..d93fecc6d971 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/DeadHTMLComposer.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/DeadHTMLComposer.java @@ -186,7 +186,7 @@ public class DeadHTMLComposer extends HTMLComposerImpl { buf.append(InspectionsBundle.message("inspection.dead.code.problem.synopsis29.method", nRefs) ); } } - } else if (((RefClassImpl)refClass).isSuspicious()) { + } else if (refClass instanceof RefClassImpl && ((RefClassImpl)refClass).isSuspicious()) { if (method.isAbstract()) { buf.append(InspectionsBundle.message("inspection.dead.code.problem.synopsis14")); } else { @@ -200,7 +200,7 @@ public class DeadHTMLComposer extends HTMLComposerImpl { if (nOwnRefs == 0 && nSuperRefs == 0 && nDerivedRefs == 0) { buf.append(InspectionsBundle.message("inspection.dead.code.problem.synopsis16")); } else if (nDerivedRefs > 0 && nSuperRefs == 0 && nOwnRefs == 0) { - String classOrInterface = HTMLJavaHTMLComposer.getClassOrInterface(refClass, false); + String classOrInterface = refClass == null ? "" : HTMLJavaHTMLComposer.getClassOrInterface(refClass, false); buf.append(InspectionsBundle.message("inspection.dead.code.problem.synopsis21", classOrInterface)); } else if (((RefMethodImpl)method).isSuspiciousRecursive()) { buf.append(InspectionsBundle.message("inspection.dead.code.problem.synopsis17")); @@ -375,7 +375,8 @@ public class DeadHTMLComposer extends HTMLComposerImpl { if (refElement instanceof RefMethod) { RefMethod refMethod = (RefMethod) refElement; - if (!refMethod.isStatic() && !refMethod.isConstructor() && !refMethod.getOwnerClass().isAnonymous()) { + RefClass aClass = refMethod.getOwnerClass(); + if (!refMethod.isStatic() && !refMethod.isConstructor() && (aClass != null && !aClass.isAnonymous())) { for (RefMethod refDerived : refMethod.getDerivedMethods()) { if (((RefMethodImpl)refDerived).isSuspicious()) { if (notInPath(pathToRoot, refDerived)) newChildren.add(refDerived); diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java index 2041b3fa0cb8..d90e9b871985 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java @@ -38,6 +38,10 @@ import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; +import org.jetbrains.uast.UClass; +import org.jetbrains.uast.UDeclaration; +import org.jetbrains.uast.UExpression; +import org.jetbrains.uast.UMethod; import javax.swing.*; import java.awt.*; @@ -248,25 +252,27 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase @Override public void onReferencesBuild(RefElement refElement) { if (refElement instanceof RefClass) { - PsiClass aClass = ((RefClass)refElement).getElement(); - if (aClass != null) { - for (PsiClassInitializer initializer : aClass.getInitializers()) { - findUnusedVariables(initializer.getBody(), refElement, aClass); + UClass uClass = ((RefClass)refElement).getUastElement(); + if (uClass != null) { + for (PsiClassInitializer initializer : uClass.getInitializers()) { + findUnusedVariables(initializer.getBody(), refElement, uClass); } } } else if (refElement instanceof RefMethod) { - PsiElement element = refElement.getElement(); - if (element instanceof PsiMethod) { - PsiCodeBlock body = ((PsiMethod)element).getBody(); + UDeclaration element = ((RefMethod)refElement).getUastElement(); + if (element instanceof UMethod) { + UExpression body = ((UMethod)element).getUastBody(); if (body != null) { - findUnusedVariables(body, refElement, element); + //TODO resolve + findUnusedVariables((PsiCodeBlock)body.getJavaPsi(), refElement, element); } } } } private void findUnusedVariables(PsiCodeBlock body, RefElement refElement, PsiElement element) { + if (body == null) return; Tools tools = myTools.get(getShortName()); if (tools.isEnabled(element)) { InspectionToolWrapper toolWrapper = tools.getInspectionTool(element); diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java index 70ea0f2cb168..65347f9f8f46 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java @@ -38,6 +38,7 @@ import com.intellij.ui.HyperlinkAdapter; import com.intellij.ui.ScrollPaneFactory; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.CharArrayUtil; @@ -242,7 +243,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta return false; } return true; - }).map(e -> e.getElement()) + }).map(e -> e.getPsiElement()) .filter(e -> e != null) .toArray(PsiElement[]::new); SafeDeleteHandler.invoke(project, elements, false, @@ -306,7 +307,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta List deletedRefs = new ArrayList<>(1); final RefFilter filter = getFilter(); for (RefEntity refElement : refElements) { - PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getElement() : null; + PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getPsiElement() : null; if (psiElement == null) continue; if (filter.getElementProblemCount((RefJavaElement)refElement) == 0) continue; @@ -490,8 +491,8 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta if (methodVisibility != null && //todo store in the graph tool.isIgnoreAccessors()) { - final PsiModifierListOwner listOwner = ((RefMethod)element).getElement(); - if (listOwner instanceof PsiMethod && PropertyUtilBase.isSimplePropertyAccessor((PsiMethod)listOwner)) { + final PsiElement psi = element.getPsiElement(); + if (psi instanceof PsiMethod && PropertyUtilBase.isSimplePropertyAccessor((PsiMethod)psi)) { return null; } } @@ -531,7 +532,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta if (refEntity instanceof RefElement) { final CommonProblemDescriptor[] descriptors = getProblemElements().get(refEntity); if (descriptors != null) { - final PsiElement psiElement = ReadAction.compute(() -> ((RefElement)refEntity).getElement()); + final PsiElement psiElement = ReadAction.compute(() -> ((RefElement)refEntity).getPsiElement()); List foreignDescriptors = new ArrayList<>(); for (CommonProblemDescriptor descriptor : descriptors) { if (descriptor instanceof ProblemDescriptor) { diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedParametersInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedParametersInspection.java index 36ff114b1fa9..f2fb92064c4b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedParametersInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedParametersInspection.java @@ -20,6 +20,9 @@ import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclaration; +import org.jetbrains.uast.UElementKt; +import org.jetbrains.uast.UParameter; import java.util.ArrayList; import java.util.List; @@ -42,7 +45,10 @@ class UnusedParametersInspection extends GlobalJavaBatchInspectionTool { if (!(refMethod.isStatic() || refMethod.isConstructor()) && !refMethod.getSuperMethods().isEmpty()) return null; - if ((refMethod.isAbstract() || refMethod.getOwnerClass().isInterface()) && refMethod.getDerivedMethods().isEmpty()) return null; + RefClass aClass = refMethod.getOwnerClass(); + if (aClass != null && ((refMethod.isAbstract() || aClass.isInterface()) && refMethod.getDerivedMethods().isEmpty())) { + return null; + } if (refMethod.isAppMain()) return null; @@ -52,15 +58,15 @@ class UnusedParametersInspection extends GlobalJavaBatchInspectionTool { if (refMethod.isEntry()) return null; - final PsiModifierListOwner element = refMethod.getElement(); + final PsiElement element = refMethod.getUastElement().getJavaPsi(); if (element != null && EntryPointsManager.getInstance(manager.getProject()).isEntryPoint(element)) return null; final List result = new ArrayList<>(); for (RefParameter refParameter : unusedParameters) { - final PsiParameter parameter = refParameter.getElement(); - final PsiIdentifier psiIdentifier = parameter != null ? parameter.getNameIdentifier() : null; - if (psiIdentifier != null) { - result.add(manager.createProblemDescriptor(psiIdentifier, + UParameter parameter = refParameter.getUastElement(); + PsiElement anchor = UElementKt.getSourcePsiElement(parameter.getUastAnchor()); + if (anchor != null) { + result.add(manager.createProblemDescriptor(anchor, InspectionsBundle.message(refMethod.isAbstract() ? "inspection.unused.parameter.composer" : "inspection.unused.parameter.composer1"), new AcceptSuggested(globalContext.getRefManager(), processor, refParameter.getName()), ProblemHighlightType.LIKE_UNUSED_SYMBOL, false)); @@ -86,13 +92,13 @@ class UnusedParametersInspection extends GlobalJavaBatchInspectionTool { public void visitElement(@NotNull RefEntity refEntity) { if (refEntity instanceof RefMethod) { RefMethod refMethod = (RefMethod)refEntity; - final PsiModifierListOwner element = refMethod.getElement(); - if (!refMethod.isStatic() && !refMethod.isConstructor() && !PsiModifier.PRIVATE.equals(refMethod.getAccessModifier())) { - final ArrayList unusedParameters = getUnusedParameters(refMethod); - if (unusedParameters.isEmpty()) return; - if (element instanceof PsiMethod) { - PsiMethod psiMethod = (PsiMethod)element; - PsiMethod[] derived = OverridingMethodsSearch.search(psiMethod).toArray(PsiMethod.EMPTY_ARRAY); + UDeclaration uastElement = refMethod.getUastElement(); + if (uastElement != null) { + PsiMethod element = (PsiMethod) uastElement.getJavaPsi(); + if (element != null && !refMethod.isStatic() && !refMethod.isConstructor() && !PsiModifier.PRIVATE.equals(refMethod.getAccessModifier())) { + final ArrayList unusedParameters = getUnusedParameters(refMethod); + if (unusedParameters.isEmpty()) return; + PsiMethod[] derived = OverridingMethodsSearch.search(element).toArray(PsiMethod.EMPTY_ARRAY); for (final RefParameter refParameter : unusedParameters) { if (refMethod.isAbstract() && derived.length == 0) { refParameter.parameterReferenced(false); @@ -107,16 +113,16 @@ class UnusedParametersInspection extends GlobalJavaBatchInspectionTool { if (parameters.length < idx) continue; PsiParameter psiParameter = parameters[idx]; ReferencesSearch.search(psiParameter, helper.getUseScope(psiParameter), false) - .forEach(new PsiReferenceProcessorAdapter( - new PsiReferenceProcessor() { - @Override - public boolean execute(PsiReference element) { - refParameter.parameterReferenced(false); - processor.ignoreElement(refMethod); - found[0] = true; - return false; - } - })); + .forEach(new PsiReferenceProcessorAdapter( + new PsiReferenceProcessor() { + @Override + public boolean execute(PsiReference element) { + refParameter.parameterReferenced(false); + processor.ignoreElement(refMethod); + found[0] = true; + return false; + } + })); } } } diff --git a/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java b/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java index 02e910f1e371..c202738b9c2b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java @@ -27,6 +27,7 @@ import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.*; import javax.swing.*; import java.awt.*; @@ -75,11 +76,11 @@ public class EmptyMethodInspection extends GlobalJavaBatchInspectionTool { if (refSuper != null && Comparing.strEqual(refMethod.getAccessModifier(), refSuper.getAccessModifier())){ if (Comparing.strEqual(refSuper.getAccessModifier(), PsiModifier.PROTECTED) //protected modificator gives access to method in another package && !Comparing.strEqual(refUtil.getPackageName(refSuper), refUtil.getPackageName(refMethod))) return null; - final PsiModifierListOwner modifierListOwner = refMethod.getElement(); - if (modifierListOwner != null) { - final PsiModifierList list = modifierListOwner.getModifierList(); + PsiModifierListOwner javaPsi = getAsJavaPsi(refMethod); + if (javaPsi != null) { + final PsiModifierList list = javaPsi.getModifierList(); if (list != null) { - final PsiModifierListOwner supMethod = refSuper.getElement(); + final PsiModifierListOwner supMethod = getAsJavaPsi(refSuper); if (supMethod != null) { final PsiModifierList superModifiedList = supMethod.getModifierList(); LOG.assertTrue(superModifiedList != null); @@ -121,30 +122,44 @@ public class EmptyMethodInspection extends GlobalJavaBatchInspectionTool { if (message != null) { final ArrayList fixes = new ArrayList<>(); fixes.add(getFix(processor, needToDeleteHierarchy)); - if (globalContext instanceof GlobalInspectionContextBase && ((GlobalInspectionContextBase)globalContext).getCurrentProfile().getSingleTool() == null) { - SpecialAnnotationsUtilBase.createAddToSpecialAnnotationFixes(refMethod.getElement(), qualifiedName -> { - fixes.add(SpecialAnnotationsUtilBase.createAddToSpecialAnnotationsListQuickFix( - QuickFixBundle.message("fix.add.special.annotation.text", qualifiedName), - QuickFixBundle.message("fix.add.special.annotation.family"), - EXCLUDE_ANNOS, qualifiedName, refMethod.getElement())); - return true; - }); + if (globalContext instanceof GlobalInspectionContextBase && + ((GlobalInspectionContextBase)globalContext).getCurrentProfile().getSingleTool() == null) { + PsiElement psi = refMethod.getPsiElement(); + if (psi instanceof PsiModifierListOwner) { + SpecialAnnotationsUtilBase.createAddToSpecialAnnotationFixes((PsiModifierListOwner)psi, qualifiedName -> { + fixes.add(SpecialAnnotationsUtilBase.createAddToSpecialAnnotationsListQuickFix( + QuickFixBundle.message("fix.add.special.annotation.text", qualifiedName), + QuickFixBundle.message("fix.add.special.annotation.family"), + EXCLUDE_ANNOS, qualifiedName, psi)); + return true; + }); + } } - final ProblemDescriptor descriptor = manager.createProblemDescriptor(refMethod.getElement().getNavigationElement(), message, false, - fixes.toArray(LocalQuickFix.EMPTY_ARRAY), - ProblemHighlightType.GENERIC_ERROR_OR_WARNING); - return new ProblemDescriptor[]{descriptor}; + PsiElement anchor = UDeclarationKt.getAnchorPsi(refMethod.getUastElement()); + if (anchor != null) { + final ProblemDescriptor descriptor = manager.createProblemDescriptor(anchor, message, false, + fixes.toArray(LocalQuickFix.EMPTY_ARRAY), + ProblemHighlightType.GENERIC_ERROR_OR_WARNING); + return new ProblemDescriptor[]{descriptor}; + } } return null; } + private static PsiModifierListOwner getAsJavaPsi(RefMethod refMethod) { + UDeclaration uDeclaration = refMethod.getUastElement(); + if (uDeclaration == null) return null; + PsiElement psi = uDeclaration.getJavaPsi(); + return psi instanceof PsiModifierListOwner ? (PsiModifierListOwner)psi : null; + } + private boolean isBodyEmpty(final RefMethod refMethod) { if (!refMethod.isBodyEmpty()) { return false; } - final PsiModifierListOwner owner = refMethod.getElement(); + final PsiModifierListOwner owner = getAsJavaPsi(refMethod); if (owner == null) { return false; } @@ -199,15 +214,14 @@ public class EmptyMethodInspection extends GlobalJavaBatchInspectionTool { if (refEntity instanceof RefElement && descriptionsProcessor.getDescriptions(refEntity) != null) { refEntity.accept(new RefJavaVisitor() { @Override public void visitMethod(@NotNull final RefMethod refMethod) { - context.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { - @Override - public boolean process(PsiMethod derivedMethod) { - PsiCodeBlock body = derivedMethod.getBody(); - if (body == null || body.isEmpty()) return true; - if (RefJavaUtil.getInstance().isMethodOnlyCallsSuper(derivedMethod)) return true; - descriptionsProcessor.ignoreElement(refMethod); - return false; - } + context.enqueueDerivedMethodsProcessor(refMethod, derivedMethod -> { + UMethod uDerivedMethod = UastContextKt.toUElement(derivedMethod, UMethod.class); + if (uDerivedMethod == null) return true; + UExpression body = uDerivedMethod.getUastBody(); + if (RefMethodImpl.isEmptyExpression(body)) return true; + if (RefJavaUtil.getInstance().isMethodOnlyCallsSuper(uDerivedMethod)) return true; + descriptionsProcessor.ignoreElement(refMethod); + return false; }); } }); @@ -339,7 +353,7 @@ public class EmptyMethodInspection extends GlobalJavaBatchInspectionTool { } private void deleteMethod(RefMethod refMethod, List result) { - PsiElement psiElement = refMethod.getElement(); + PsiElement psiElement = refMethod.getPsiElement(); if (psiElement == null) return; if (!result.contains(psiElement)) result.add(psiElement); } diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java index e6d0360a4758..3ce122e4022d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java @@ -39,6 +39,9 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Processor; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.uast.UClass; +import org.jetbrains.uast.UMethod; +import org.jetbrains.uast.UastContextKt; import java.util.ArrayList; import java.util.Collections; @@ -205,14 +208,13 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext if (myDerivedClassesRequests != null) { final List sortedIDs = getSortedIDs(myDerivedClassesRequests); for (SmartPsiElementPointer sortedID : sortedIDs) { - final PsiClass psiClass = (PsiClass)dereferenceInReadAction(sortedID); - if (psiClass == null) continue; - context.incrementJobDoneAmount(context.getStdJobDescriptors().FIND_EXTERNAL_USAGES, getClassPresentableName(psiClass)); + final UClass uClass = ReadAction.compute(() -> UastContextKt.toUElement(dereferenceInReadAction(sortedID), UClass.class)); + if (uClass == null) continue; + context.incrementJobDoneAmount(context.getStdJobDescriptors().FIND_EXTERNAL_USAGES, getClassPresentableName(uClass)); final List processors = myDerivedClassesRequests.get(sortedID); - LOG.assertTrue(processors != null, psiClass.getClass().getName()); - ClassInheritorsSearch.search(psiClass, searchScope, false) - .forEach(createMembersProcessor(processors, scope)); + LOG.assertTrue(processors != null, uClass.getClass().getName()); + ClassInheritorsSearch.search(uClass.getJavaPsi(), searchScope, false).forEach(createMembersProcessor(processors, scope)); } myDerivedClassesRequests = null; @@ -221,16 +223,15 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext if (myDerivedMethodsRequests != null) { final List sortedIDs = getSortedIDs(myDerivedMethodsRequests); for (SmartPsiElementPointer sortedID : sortedIDs) { - final PsiMethod psiMethod = (PsiMethod)dereferenceInReadAction(sortedID); - if (psiMethod == null) continue; - final RefMethod refMethod = (RefMethod)refManager.getReference(psiMethod); + final UMethod uMethod = ReadAction.compute(() -> UastContextKt.toUElement(dereferenceInReadAction(sortedID), UMethod.class)); + if (uMethod == null) continue; + final RefMethod refMethod = (RefMethod)refManager.getReference(uMethod.getSourcePsi()); context.incrementJobDoneAmount(context.getStdJobDescriptors().FIND_EXTERNAL_USAGES, refManager.getQualifiedName(refMethod)); final List processors = myDerivedMethodsRequests.get(sortedID); - LOG.assertTrue(processors != null, psiMethod.getClass().getName()); - OverridingMethodsSearch.search(psiMethod, searchScope, true) - .forEach(createMembersProcessor(processors, scope)); + LOG.assertTrue(processors != null, uMethod.getClass().getName()); + OverridingMethodsSearch.search(uMethod.getJavaPsi(), searchScope, true).forEach(createMembersProcessor(processors, scope)); } myDerivedMethodsRequests = null; @@ -239,14 +240,14 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext if (myFieldUsagesRequests != null) { final List sortedIDs = getSortedIDs(myFieldUsagesRequests); for (SmartPsiElementPointer sortedID : sortedIDs) { - final PsiField psiField = (PsiField)dereferenceInReadAction(sortedID); - if (psiField == null) continue; + final PsiElement field = dereferenceInReadAction(sortedID); + if (field == null) continue; final List processors = myFieldUsagesRequests.get(sortedID); - LOG.assertTrue(processors != null, psiField.getClass().getName()); - context.incrementJobDoneAmount(context.getStdJobDescriptors().FIND_EXTERNAL_USAGES, refManager.getQualifiedName(refManager.getReference(psiField))); + LOG.assertTrue(processors != null, field.getClass().getName()); + context.incrementJobDoneAmount(context.getStdJobDescriptors().FIND_EXTERNAL_USAGES, refManager.getQualifiedName(refManager.getReference(field))); - ReferencesSearch.search(psiField, searchScope, false) + ReferencesSearch.search(field, searchScope, false) .forEach(new PsiReferenceProcessorAdapter(createReferenceProcessor(processors, context))); } @@ -256,15 +257,15 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext if (myClassUsagesRequests != null) { final List sortedIDs = getSortedIDs(myClassUsagesRequests); for (SmartPsiElementPointer sortedID : sortedIDs) { - final PsiClass psiClass = (PsiClass)dereferenceInReadAction(sortedID); - if (psiClass == null) continue; + final PsiElement classDeclaration = dereferenceInReadAction(sortedID); + if (classDeclaration == null) continue; final List processors = myClassUsagesRequests.get(sortedID); - LOG.assertTrue(processors != null, psiClass.getClass().getName()); - context.incrementJobDoneAmount(context.getStdJobDescriptors().FIND_EXTERNAL_USAGES, getClassPresentableName(psiClass)); + LOG.assertTrue(processors != null, classDeclaration.getClass().getName()); + UClass uClass = ReadAction.compute(() -> UastContextKt.toUElement(classDeclaration, UClass.class)); + context.incrementJobDoneAmount(context.getStdJobDescriptors().FIND_EXTERNAL_USAGES, getClassPresentableName(uClass)); - ReferencesSearch.search(psiClass, searchScope, false) - .forEach(new PsiReferenceProcessorAdapter(createReferenceProcessor(processors, context))); + ReferencesSearch.search(classDeclaration, searchScope, false).forEach(new PsiReferenceProcessorAdapter(createReferenceProcessor(processors, context))); } myClassUsagesRequests = null; @@ -273,25 +274,27 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext if (myMethodUsagesRequests != null) { List sortedIDs = getSortedIDs(myMethodUsagesRequests); for (SmartPsiElementPointer sortedID : sortedIDs) { - final PsiMethod psiMethod = (PsiMethod)dereferenceInReadAction(sortedID); - if (psiMethod == null) continue; + final UMethod uMethod = ReadAction.compute(() -> UastContextKt.toUElement(dereferenceInReadAction(sortedID), UMethod.class)); + if (uMethod == null) continue; final List processors = myMethodUsagesRequests.get(sortedID); - LOG.assertTrue(processors != null, psiMethod.getClass().getName()); - context.incrementJobDoneAmount(context.getStdJobDescriptors().FIND_EXTERNAL_USAGES, refManager.getQualifiedName(refManager.getReference(psiMethod))); + LOG.assertTrue(processors != null, uMethod.getClass().getName()); + context.incrementJobDoneAmount(context.getStdJobDescriptors().FIND_EXTERNAL_USAGES, ReadAction.compute(() -> uMethod.getName())); - MethodReferencesSearch.search(psiMethod, searchScope, true) - .forEach(new PsiReferenceProcessorAdapter(createReferenceProcessor(processors, context))); + PsiMethod javaMethod = ReadAction.compute(() -> uMethod.getJavaPsi()); + if (javaMethod != null) { + MethodReferencesSearch.search(javaMethod, searchScope, true).forEach(new PsiReferenceProcessorAdapter(createReferenceProcessor(processors, context))); + } } myMethodUsagesRequests = null; } } - private static String getClassPresentableName(@NotNull PsiClass psiClass) { + private static String getClassPresentableName(@NotNull UClass uClass) { return ReadAction.compute(() -> { - final String qualifiedName = psiClass.getQualifiedName(); - return qualifiedName != null ? qualifiedName : psiClass.getName(); + final String qualifiedName = uClass.getQualifiedName(); + return qualifiedName != null ? qualifiedName : uClass.getName(); }); } diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/HTMLJavaHTMLComposerImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/HTMLJavaHTMLComposerImpl.java index f39ea8bf9bcf..bb1d8ba631d4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/HTMLJavaHTMLComposerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/HTMLJavaHTMLComposerImpl.java @@ -21,9 +21,13 @@ import com.intellij.codeInspection.HTMLJavaHTMLComposer; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.reference.*; import com.intellij.psi.*; +import com.intellij.util.ObjectUtils; import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclaration; +import org.jetbrains.uast.UField; +import org.jetbrains.uast.UMethod; public class HTMLJavaHTMLComposerImpl extends HTMLJavaHTMLComposer { private final HTMLComposerImpl myComposer; @@ -159,7 +163,7 @@ public class HTMLJavaHTMLComposerImpl extends HTMLJavaHTMLComposer { @Override public void visitField(@NotNull RefField field) { - PsiField psiField = field.getElement(); + PsiField psiField = (PsiField)field.getUastElement().getJavaPsi(); if (psiField != null) { if (field.isStatic()) { buf.append(InspectionsBundle.message("inspection.export.results.static")); @@ -178,7 +182,7 @@ public class HTMLJavaHTMLComposerImpl extends HTMLJavaHTMLComposer { @Override public void visitMethod(@NotNull RefMethod method) { - final PsiModifierListOwner element = method.getElement(); + final PsiModifierListOwner element = (PsiModifierListOwner)method.getUastElement().getJavaPsi(); if (element instanceof PsiClass) { return; } @@ -214,7 +218,7 @@ public class HTMLJavaHTMLComposerImpl extends HTMLJavaHTMLComposer { @Override public void visitFile(@NotNull RefFile file) { - final PsiFile psiFile = file.getElement(); + final PsiFile psiFile = file.getPsiElement(); buf.append(HTMLComposerImpl.B_OPENING); buf.append(psiFile.getName()); buf.append(HTMLComposerImpl.B_CLOSING); @@ -257,9 +261,9 @@ public class HTMLJavaHTMLComposerImpl extends HTMLJavaHTMLComposer { return XmlStringUtil.escapeString(refEntity.getName()); } else if (refEntity instanceof RefMethod) { - PsiMethod psiMethod = (PsiMethod)((RefMethod)refEntity).getElement(); - if (psiMethod != null) { - return psiMethod.getName(); + UMethod uMethod = (UMethod)((RefMethod)refEntity).getUastElement(); + if (uMethod != null) { + return uMethod.getName(); } else { return refEntity.getName(); @@ -280,13 +284,13 @@ public class HTMLJavaHTMLComposerImpl extends HTMLJavaHTMLComposer { if (refElement instanceof RefField) { RefField field = (RefField)refElement; - PsiField psiField = field.getElement(); + UField psiField = field.getUastElement(); buf.append(XmlStringUtil.escapeString(psiField.getType().getPresentableText())); buf.append(HTMLComposerImpl.NBSP); } else if (refElement instanceof RefMethod) { RefMethod method = (RefMethod)refElement; - PsiMethod psiMethod = (PsiMethod)method.getElement(); + UMethod psiMethod = (UMethod)method.getUastElement(); PsiType returnType = psiMethod.getReturnType(); if (returnType != null) { @@ -316,7 +320,7 @@ public class HTMLJavaHTMLComposerImpl extends HTMLJavaHTMLComposer { buf.append(XmlStringUtil.escapeString(refElement.getName())); } else if (refElement instanceof RefMethod) { - PsiMethod psiMethod = (PsiMethod)((RefMethod)refElement).getElement(); + UMethod psiMethod = (UMethod)((RefMethod)refElement).getUastElement(); buf.append(psiMethod.getName()); } else { @@ -326,7 +330,7 @@ public class HTMLJavaHTMLComposerImpl extends HTMLJavaHTMLComposer { buf.append(HTMLComposerImpl.A_CLOSING); if (refElement instanceof RefMethod) { - PsiMethod psiMethod = (PsiMethod)((RefMethod)refElement).getElement(); + UMethod psiMethod = (UMethod)((RefMethod)refElement).getUastElement(); appendMethodParameters(buf, psiMethod, false); } diff --git a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java index c165bc48c752..b3b2c7839734 100644 --- a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java @@ -41,6 +41,8 @@ import com.intellij.util.containers.MultiMap; import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UExpression; +import org.jetbrains.uast.UastContextKt; import javax.swing.*; import javax.swing.event.ChangeEvent; @@ -451,7 +453,7 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool boolean needFurtherProcess = false; for (int i = 0; i < paramValues.length; i++) { Object value = paramValues[i]; - final Object currentArg = getArgValue(arguments[i], method); + final Object currentArg = getArgValue(UastContextKt.toUElement(arguments[i], UExpression.class), method); if (value == VALUE_UNDEFINED) { paramValues[i] = currentArg; if (currentArg != VALUE_IS_NOT_CONST) { @@ -480,7 +482,7 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool }; } - private Object getArgValue(PsiExpression arg, PsiMethod method) { + private Object getArgValue(UExpression arg, PsiMethod method) { return RefParameterImpl.getAccessibleExpressionValue(arg, () -> method); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java index 196c9746cf33..fb801b865749 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedReturnValue/UnusedReturnValue.java @@ -65,7 +65,7 @@ public class UnusedReturnValue extends GlobalJavaBatchInspectionTool{ if (refMethod.isEntry()) return null; if (!refMethod.isReturnValueUsed()) { - final PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); + final PsiMethod psiMethod = (PsiMethod)refMethod.getUastElement().getJavaPsi(); if (psiMethod == null) return null; if (IGNORE_BUILDER_PATTERN && PropertyUtilBase.isSimplePropertySetter(psiMethod)) return null; diff --git a/java/java-tests/testData/inspection/deadCode/instanceOf/expected.xml b/java/java-tests/testData/inspection/deadCode/instanceOf/expected.xml new file mode 100644 index 000000000000..4704d91e891d --- /dev/null +++ b/java/java-tests/testData/inspection/deadCode/instanceOf/expected.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/deadCode/instanceOf/src/Test.java b/java/java-tests/testData/inspection/deadCode/instanceOf/src/Test.java new file mode 100644 index 000000000000..1354c9f2f4f1 --- /dev/null +++ b/java/java-tests/testData/inspection/deadCode/instanceOf/src/Test.java @@ -0,0 +1,9 @@ +public class Test { + public static void main(String[] args) { + A a = (B) new A(); + } +} + +class A {} + +class B extends A {} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/deadCode/referenceParameterList/expected.xml b/java/java-tests/testData/inspection/deadCode/referenceParameterList/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/deadCode/referenceParameterList/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/deadCode/referenceParameterList/src/Test.java b/java/java-tests/testData/inspection/deadCode/referenceParameterList/src/Test.java new file mode 100644 index 000000000000..26bb800446ce --- /dev/null +++ b/java/java-tests/testData/inspection/deadCode/referenceParameterList/src/Test.java @@ -0,0 +1,9 @@ +import java.util.Collections; + +public class RefParamList { + public static void main(String[] args) { + Collections.emptyList(); + } +} + +class XXXXYYYZZZZ {} diff --git a/java/java-tests/testData/inspection/deadCode/singleton/src/Main.java b/java/java-tests/testData/inspection/deadCode/singleton/src/Main.java index 38f90d23111e..1cee07306013 100644 --- a/java/java-tests/testData/inspection/deadCode/singleton/src/Main.java +++ b/java/java-tests/testData/inspection/deadCode/singleton/src/Main.java @@ -1,5 +1,5 @@ public class Main { public static void main(String args[]) { - Singleton.getInstance(); + XXX.Companion.xxx(); } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/deadCode/singleton/src/Singleton.kt b/java/java-tests/testData/inspection/deadCode/singleton/src/Singleton.kt new file mode 100644 index 000000000000..73796ffec08b --- /dev/null +++ b/java/java-tests/testData/inspection/deadCode/singleton/src/Singleton.kt @@ -0,0 +1,5 @@ +class XXX { + companion object { + fun xxx() {} + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/emptyMethod/emptyMethodsHierarchy/expected.xml b/java/java-tests/testData/inspection/emptyMethod/emptyMethodsHierarchy/expected.xml index 54bde1be972d..ab0da4ac8d22 100644 --- a/java/java-tests/testData/inspection/emptyMethod/emptyMethodsHierarchy/expected.xml +++ b/java/java-tests/testData/inspection/emptyMethod/emptyMethodsHierarchy/expected.xml @@ -2,7 +2,7 @@ Derived.java - 15 + 16 Empty method overrides empty method diff --git a/java/java-tests/testData/inspection/jvm/deadCode/additionalAnnotations/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/additionalAnnotations/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/additionalAnnotations/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/additionalAnnotations/src/Test.java b/java/java-tests/testData/inspection/jvm/deadCode/additionalAnnotations/src/Test.java new file mode 100644 index 000000000000..22ee9d72f991 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/additionalAnnotations/src/Test.java @@ -0,0 +1,9 @@ +@Annotated +public class Test { + @Annotated + public void foo(){} + + @Annotated + public int myPublicField; + +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/annotationInterface/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/annotationInterface/expected.xml new file mode 100644 index 000000000000..5aba82f1957e --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/annotationInterface/expected.xml @@ -0,0 +1,9 @@ + + + + Test.java + 5 + Method is never used. + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/annotationInterface/src/Test.java b/java/java-tests/testData/inspection/jvm/deadCode/annotationInterface/src/Test.java new file mode 100644 index 000000000000..d2865d1331aa --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/annotationInterface/src/Test.java @@ -0,0 +1,6 @@ +import java.lang.annotation.*; + +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE}) +public @interface Test { + String value() default ""; +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/src/p/A.java b/java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/src/p/A.java new file mode 100644 index 000000000000..275d71f6a7f9 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/src/p/A.java @@ -0,0 +1,11 @@ +package p; + +public @interface A { + Class val(); + String constant(); +} + +class B {} +class C { + public static final String FOO = ""; +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/src/p/package-info.java b/java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/src/p/package-info.java new file mode 100644 index 000000000000..1bd138d814cc --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/annotationUsedInPackageInfo/src/p/package-info.java @@ -0,0 +1,2 @@ +@A(val = B.class, constant = C.FOO) +package p; \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/A.kt b/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/A.kt new file mode 100644 index 000000000000..56011d5e0e40 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/A.kt @@ -0,0 +1,3 @@ +fun someUtility() { + +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/B.kt b/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/B.kt new file mode 100644 index 000000000000..fb3b0d12faff --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/B.kt @@ -0,0 +1,5 @@ +class B { + fun xxx() { + someUtility() + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/Main.kt b/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/Main.kt new file mode 100644 index 000000000000..b2e25e71a27f --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/chainOfCalls/src/Main.kt @@ -0,0 +1,3 @@ +fun main(args: Array) { + B().xxx() +} diff --git a/java/java-tests/testData/inspection/jvm/deadCode/classLiteralRef/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/classLiteralRef/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/classLiteralRef/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/classLiteralRef/src/Test.kt b/java/java-tests/testData/inspection/jvm/deadCode/classLiteralRef/src/Test.kt new file mode 100644 index 000000000000..db886727b5bc --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/classLiteralRef/src/Test.kt @@ -0,0 +1,10 @@ +class Test(param: String) { + + init { + println("This is used!") + } +} + +fun main(args: Array) { + Test::class.java.getDeclaredConstructor(String::class.java).newInstance("Foo") +} diff --git a/java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/src/A.kt b/java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/src/A.kt new file mode 100644 index 000000000000..87ec6612d29b --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/src/A.kt @@ -0,0 +1 @@ +class A(i: Int) \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/src/B.kt b/java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/src/B.kt new file mode 100644 index 000000000000..8f82852c8517 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/constructorCalls/src/B.kt @@ -0,0 +1,3 @@ +fun main(args: Array) { + System.out.println(A(1)) +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/defaultConstructor/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/defaultConstructor/expected.xml new file mode 100644 index 000000000000..4704d91e891d --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/defaultConstructor/expected.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/defaultConstructor/src/A.java b/java/java-tests/testData/inspection/jvm/deadCode/defaultConstructor/src/A.java new file mode 100644 index 000000000000..4986597a04ce --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/defaultConstructor/src/A.java @@ -0,0 +1,18 @@ +class A { + public A(int... i) { + System.out.println(i); + } +} + +class B extends A { + public static void main(String[] args) { + System.out.println(new B()); + } +} + +class C {} +class D extends C { + public static void main(String[] args) { + System.out.println(new D()); + } +} diff --git a/java/java-tests/testData/inspection/jvm/deadCode/enumInstantiation/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/enumInstantiation/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/enumInstantiation/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/junitEntryPoint/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/junitEntryPoint/expected.xml new file mode 100644 index 000000000000..d99afa977121 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/junitEntryPoint/expected.xml @@ -0,0 +1,10 @@ + + + + Test.kt + 6 + + Method is never used. + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/junitEntryPoint/src/Test.kt b/java/java-tests/testData/inspection/jvm/deadCode/junitEntryPoint/src/Test.kt new file mode 100644 index 000000000000..eb019a22345b --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/junitEntryPoint/src/Test.kt @@ -0,0 +1,7 @@ +object TestSuite { + fun suite() { + // test em all + } + + fun notATest() {} +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/expected.xml new file mode 100644 index 000000000000..8855130766dd --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/expected.xml @@ -0,0 +1,10 @@ + + + + A.java + 2 + unused declaration + Method is never used. + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/A.java b/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/A.java new file mode 100644 index 000000000000..ea87d6240504 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/A.java @@ -0,0 +1,5 @@ +public class A { + public static void xxx() { + BKt.yyy(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/B.kt b/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/B.kt new file mode 100644 index 000000000000..532cb37b4949 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/B.kt @@ -0,0 +1,3 @@ +fun yyy() { + A.xxx() +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/C.kt b/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/C.kt new file mode 100644 index 000000000000..ddc1c3eee5ff --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/mutableCalls/src/C.kt @@ -0,0 +1,9 @@ +object C { + fun xxx() { + yyy() + } + + fun yyy() { + xxx() + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/expected.xml new file mode 100644 index 000000000000..d704d58ed391 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/ext_src/res.xml b/java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/ext_src/res.xml new file mode 100644 index 000000000000..38009bb43e19 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/ext_src/res.xml @@ -0,0 +1 @@ +Test \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/src/Test.kt b/java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/src/Test.kt new file mode 100644 index 000000000000..e19e9bd3f754 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/nonJvmReferences/src/Test.kt @@ -0,0 +1 @@ +object Test {} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/src/Interface.java b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/src/Interface.java new file mode 100644 index 000000000000..7fc48ac44173 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/src/Interface.java @@ -0,0 +1,3 @@ +interface Interface { + int[] getField(); +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/src/Test.kt b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/src/Test.kt new file mode 100644 index 000000000000..f1fb09b41533 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldArrayInitializer/src/Test.kt @@ -0,0 +1,19 @@ +class Test : Interface { + + override fun getField(): IntArray { + return myField + } + + companion object { + var myField = intArrayOf(init()) + + fun init(): Int { + return 1 + } + } +} + +fun main(args: Array) { + val i: Interface = Test() + println(i.field) +} diff --git a/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/src/Interface.java b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/src/Interface.java new file mode 100644 index 000000000000..ca057973f350 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/src/Interface.java @@ -0,0 +1,3 @@ +interface Interface { + int getField(); +} diff --git a/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/src/Test.kt b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/src/Test.kt new file mode 100644 index 000000000000..6c4fa44ce9ff --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromFieldInitializer/src/Test.kt @@ -0,0 +1,16 @@ +class Test : Interface { + var myField = init() + + fun init(): Int { + return 1 + } + + override fun getField(): Int { + return myField + } +} + +fun main(args: Array) { + val i: Interface = Test() + println(i.field) +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/reachableFromMain/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromMain/expected.xml new file mode 100644 index 000000000000..8adee7319b68 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromMain/expected.xml @@ -0,0 +1,10 @@ + + + + A.kt + 4 + unused declaration + Method is never used. + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/reachableFromMain/src/A.kt b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromMain/src/A.kt new file mode 100644 index 000000000000..556bcd29a1b1 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/reachableFromMain/src/A.kt @@ -0,0 +1,10 @@ +class ABC { + companion object { + fun xxx() {} + fun yyy() {} + } +} + +fun main(args: Array) { + ABC.xxx() +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/serializable/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/serializable/expected.xml new file mode 100644 index 000000000000..5e933496b9cf --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/serializable/expected.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/serializable/ext_src/External.java b/java/java-tests/testData/inspection/jvm/deadCode/serializable/ext_src/External.java new file mode 100644 index 000000000000..9e17ba18d453 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/serializable/ext_src/External.java @@ -0,0 +1,5 @@ +public class External { + { + new Test(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/serializable/src/Test.java b/java/java-tests/testData/inspection/jvm/deadCode/serializable/src/Test.java new file mode 100644 index 000000000000..5afb0ecb21d5 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/serializable/src/Test.java @@ -0,0 +1,6 @@ +public class Test implements java.io.Serializable { + private void writeObject(java.io.ObjectOutputStream out) {} + private void readObject(java.io.ObjectInputStream in) {} + public Object writeReplace() { return null; } + public Object readResolve() { return null; } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/singleton/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/singleton/expected.xml new file mode 100644 index 000000000000..d704d58ed391 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/singleton/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/singleton/src/Main.java b/java/java-tests/testData/inspection/jvm/deadCode/singleton/src/Main.java new file mode 100644 index 000000000000..38f90d23111e --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/singleton/src/Main.java @@ -0,0 +1,5 @@ +public class Main { + public static void main(String args[]) { + Singleton.getInstance(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/singleton/src/Singleton.java b/java/java-tests/testData/inspection/jvm/deadCode/singleton/src/Singleton.java new file mode 100644 index 000000000000..24af3895df85 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/singleton/src/Singleton.java @@ -0,0 +1,7 @@ +public class Singleton { + private static Singleton ourInstance = new Singleton(); + + public Singleton getInstance() { + return ourInstance; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/staticMethods/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/staticMethods/expected.xml new file mode 100644 index 000000000000..a581cdba310d --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/staticMethods/expected.xml @@ -0,0 +1,16 @@ + + + + Test.kt + 2 + unused declaration + Method has usage(s) but they all belong to calls chain that has no members reachable from entry points. + + + Test.kt + 7 + unused declaration + Method has one usage but it is not reachable from entry points. + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/staticMethods/src/Test.kt b/java/java-tests/testData/inspection/jvm/deadCode/staticMethods/src/Test.kt new file mode 100644 index 000000000000..d6511e23c49e --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/staticMethods/src/Test.kt @@ -0,0 +1,12 @@ +object A { + fun xxx() { + yyy() + } +} + +fun yyy() { + A.xxx() + B() +} + +class B \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/unusedEnum/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/unusedEnum/expected.xml new file mode 100644 index 000000000000..28d7538c3eb6 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/unusedEnum/expected.xml @@ -0,0 +1,14 @@ + + + + Test.java + 2 + Field has no usages. + + + Test.java + 2 + Field has no usages. + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/unusedEnum/src/Test.java b/java/java-tests/testData/inspection/jvm/deadCode/unusedEnum/src/Test.java new file mode 100644 index 000000000000..3ac12b80e9f7 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/unusedEnum/src/Test.java @@ -0,0 +1,3 @@ +public enum MyEnum { + A, B; +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/deadCode/usagesInAnonymous/expected.xml b/java/java-tests/testData/inspection/jvm/deadCode/usagesInAnonymous/expected.xml new file mode 100644 index 000000000000..79e1a0fd0a57 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/usagesInAnonymous/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/jvm/deadCode/usagesInAnonymous/src/Test.kt b/java/java-tests/testData/inspection/jvm/deadCode/usagesInAnonymous/src/Test.kt new file mode 100644 index 000000000000..27870f3fbe90 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/deadCode/usagesInAnonymous/src/Test.kt @@ -0,0 +1,18 @@ +object MyClass { + + fun method(): String { + return "" + } + + open class Parent constructor(o: Any) { + init { + println(o) + } + } +} + +fun main(args: Array) { + object : MyClass.Parent(MyClass.method()) { + + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/sameParameterValue/entryPoint/expected.xml b/java/java-tests/testData/inspection/jvm/sameParameterValue/entryPoint/expected.xml new file mode 100644 index 000000000000..ec272abeaa3a --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameParameterValue/entryPoint/expected.xml @@ -0,0 +1,3 @@ + + + diff --git a/java/java-tests/testData/inspection/jvm/sameParameterValue/entryPoint/src/Test.kt b/java/java-tests/testData/inspection/jvm/sameParameterValue/entryPoint/src/Test.kt new file mode 100644 index 000000000000..3380fdfdd17f --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameParameterValue/entryPoint/src/Test.kt @@ -0,0 +1,4 @@ +fun main(args: Array?) { + main(null) +} + diff --git a/java/java-tests/testData/inspection/jvm/sameParameterValue/methodWithSuper/expected.xml b/java/java-tests/testData/inspection/jvm/sameParameterValue/methodWithSuper/expected.xml new file mode 100644 index 000000000000..989f486864a8 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameParameterValue/methodWithSuper/expected.xml @@ -0,0 +1,17 @@ + + + + Test.kt + 9 + Actual method parameter is the same constant + Actual value of parameter 'i' is always '10' + + + + Test.kt + 2 + Actual method parameter is the same constant + Actual value of parameter 'i' is always '10' + + + diff --git a/java/java-tests/testData/inspection/jvm/sameParameterValue/methodWithSuper/src/Test.kt b/java/java-tests/testData/inspection/jvm/sameParameterValue/methodWithSuper/src/Test.kt new file mode 100644 index 000000000000..a5bd7b17b92f --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameParameterValue/methodWithSuper/src/Test.kt @@ -0,0 +1,17 @@ +internal class AAA { + fun mmm(i: Int) { + System.out.println(i + 10) + } +} + +internal class BBB : AAA() { + @Override + override fun mmm(i: Int) { + System.out.println(i + 20) + } +} + +fun main(args: Array) { + BBB().mmm(10) + AAA().mmm(10) +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/sameParameterValue/negativeDouble/expected.xml b/java/java-tests/testData/inspection/jvm/sameParameterValue/negativeDouble/expected.xml new file mode 100644 index 000000000000..198cf22f781c --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameParameterValue/negativeDouble/expected.xml @@ -0,0 +1,10 @@ + + + + Test.kt + 2 + Actual method parameter is the same constant + Actual value of parameter 'xxx' is always '-1.111' + + + diff --git a/java/java-tests/testData/inspection/jvm/sameParameterValue/negativeDouble/src/Test.kt b/java/java-tests/testData/inspection/jvm/sameParameterValue/negativeDouble/src/Test.kt new file mode 100644 index 000000000000..51bd063417b8 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameParameterValue/negativeDouble/src/Test.kt @@ -0,0 +1,10 @@ +object Test { + fun someMethod(xxx: Double) { + + } +} + + +fun main(args: Array) { + Test.someMethod(-1.111) +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/sameParameterValue/varargs/expected.xml b/java/java-tests/testData/inspection/jvm/sameParameterValue/varargs/expected.xml new file mode 100644 index 000000000000..0133867878f2 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameParameterValue/varargs/expected.xml @@ -0,0 +1,10 @@ + + + + Test.kt + 23 + Actual method parameter is the same constant + Actual value of parameter 'args' is always 'foo' + + + diff --git a/java/java-tests/testData/inspection/jvm/sameParameterValue/varargs/src/Test.kt b/java/java-tests/testData/inspection/jvm/sameParameterValue/varargs/src/Test.kt new file mode 100644 index 000000000000..3a0c3f3c2a53 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameParameterValue/varargs/src/Test.kt @@ -0,0 +1,36 @@ +class Test { + private fun foo(vararg args: String) {} + + fun bar() { + foo("foo", "bar") + foo("bla") + } +} + +object AnotherDiiferentVarargs { + val TEXT = "text" + val ANOTHER_TEXT = "another text" + + fun printString(input: String, vararg attrs: String) { + System.out.println(input) + for (string in attrs) { + System.out.println(string) + } + } +} + +class TheSame { + private fun foo(vararg args: String) {} + + fun bar() { + foo("foo") + foo("foo") + } +} + +fun main(args: Array) { + Test().bar() + AnotherDiiferentVarargs.printString(AnotherDiiferentVarargs.TEXT, "optional") + AnotherDiiferentVarargs.printString(AnotherDiiferentVarargs.ANOTHER_TEXT) + TheSame().bar() +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/sameReturnValue/java/expected.xml b/java/java-tests/testData/inspection/jvm/sameReturnValue/java/expected.xml new file mode 100644 index 000000000000..5ff621f8286d --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameReturnValue/java/expected.xml @@ -0,0 +1,10 @@ + + + + Test.java + 3 + Method returns the same value + Method always returns <code>0</code> + + + diff --git a/java/java-tests/testData/inspection/jvm/sameReturnValue/java/src/Test.java b/java/java-tests/testData/inspection/jvm/sameReturnValue/java/src/Test.java new file mode 100644 index 000000000000..d4c3e537886f --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameReturnValue/java/src/Test.java @@ -0,0 +1,10 @@ +class Test { + + int xxx() { + return 0; + } + + public static void main(String[] args) { + System.out.println(new Test().xxx()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/sameReturnValue/kotlin/expected.xml b/java/java-tests/testData/inspection/jvm/sameReturnValue/kotlin/expected.xml new file mode 100644 index 000000000000..d3a1dc32fb84 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameReturnValue/kotlin/expected.xml @@ -0,0 +1,24 @@ + + + + Test.kt + 2 + Method returns the same value + Method always returns <code>0</code> + + + + Test.kt + 18 + Method returns the same value + Method always returns <code>foo</code> + + + + Test.kt + 8 + Method returns the same value + Method always returns <code>foo</code> + + + diff --git a/java/java-tests/testData/inspection/jvm/sameReturnValue/kotlin/src/Test.kt b/java/java-tests/testData/inspection/jvm/sameReturnValue/kotlin/src/Test.kt new file mode 100644 index 000000000000..f84cd0a6f7ea --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameReturnValue/kotlin/src/Test.kt @@ -0,0 +1,28 @@ +class Test { + fun xxx(): Int { + return 0 + } +} + +open class A { + open fun xxx(): String { + if (1 > 10) { + return "foo" + } else { + return "foo" + } + } +} + +class B:A() { + override fun xxx(): String { + return "foo" + } +} + + +fun main(args: Array) { + println(Test().xxx()) + println(B().xxx()) + println(A().xxx()) +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/expected.xml b/java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/expected.xml new file mode 100644 index 000000000000..0d570e86a5cb --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/expected.xml @@ -0,0 +1,17 @@ + + + + Foo.java + 3 + Method returns the same value + Method always returns <code>0</code> + + + Bar.kt + 2 + Method returns the same value + Method always returns <code>0</code> + + + + diff --git a/java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/src/Bar.kt b/java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/src/Bar.kt new file mode 100644 index 000000000000..561507913905 --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/src/Bar.kt @@ -0,0 +1,5 @@ +open class Bar { + open fun xxx(): Int { + return 0 + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/src/Foo.java b/java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/src/Foo.java new file mode 100644 index 000000000000..2e651bb5b94b --- /dev/null +++ b/java/java-tests/testData/inspection/jvm/sameReturnValue/mixed/src/Foo.java @@ -0,0 +1,11 @@ +public class Foo extends Bar { + + public int xxx() { + return 0; + } + + public static void main(String[] args) { + System.out.println(new Foo().xxx()); + System.out.println(new Bar().xxx()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/sameParameterValue/field/expected.xml b/java/java-tests/testData/inspection/sameParameterValue/field/expected.xml new file mode 100644 index 000000000000..43173bc2a2a4 --- /dev/null +++ b/java/java-tests/testData/inspection/sameParameterValue/field/expected.xml @@ -0,0 +1,10 @@ + + + + Test.java + 5 + Actual method parameter is the same constant + Actual value of parameter 'val' is always 'Test.DOUBLE_FIELD' + + + diff --git a/java/java-tests/testData/inspection/sameParameterValue/field/src/Test.java b/java/java-tests/testData/inspection/sameParameterValue/field/src/Test.java new file mode 100644 index 000000000000..88007f8a91c3 --- /dev/null +++ b/java/java-tests/testData/inspection/sameParameterValue/field/src/Test.java @@ -0,0 +1,13 @@ +public class Test { + + static final double DOUBLE_FIELD = 1.0 + 0.1; + + static void someMethod(double val) { + + } + + public static void main(String[] args) { + someMethod(DOUBLE_FIELD); + someMethod(Test.DOUBLE_FIELD); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/SameParameterValueTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/SameParameterValueTest.java index dceb58779935..c4dcf4a79fa3 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/SameParameterValueTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/SameParameterValueTest.java @@ -97,4 +97,8 @@ public class SameParameterValueTest extends InspectionTestCase { myTool.minimalUsageCount = previous; } } + + public void testField() { + doTest(getTestDir(), myTool, false, true); + } } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/UnusedDeclarationTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/UnusedDeclarationTest.java index 9416718d94ec..b1c414df1b33 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/UnusedDeclarationTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/UnusedDeclarationTest.java @@ -210,4 +210,12 @@ public class UnusedDeclarationTest extends AbstractUnusedDeclarationTest { public void testStaticImport() { doTest(); } + + public void testInstanceOf() { + doTest(); + } + + public void testReferenceParameterList() { + doTest(); + } } diff --git a/jvm/jvm-analysis-api/src/com/intellij/codeInspection/AnalysisUastUtil.java b/jvm/jvm-analysis-api/src/com/intellij/codeInspection/AnalysisUastUtil.java index fa2a407bdb67..711aded10102 100644 --- a/jvm/jvm-analysis-api/src/com/intellij/codeInspection/AnalysisUastUtil.java +++ b/jvm/jvm-analysis-api/src/com/intellij/codeInspection/AnalysisUastUtil.java @@ -3,6 +3,7 @@ package com.intellij.codeInspection; import com.intellij.openapi.progress.ProgressManager; import com.intellij.psi.*; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -152,4 +153,5 @@ public final class AnalysisUastUtil { return null; } + } diff --git a/jvm/jvm-analysis-kotlin-tests/intellij.jvm.analysis.kotlin.tests.iml b/jvm/jvm-analysis-kotlin-tests/intellij.jvm.analysis.kotlin.tests.iml index f2bd7c7f02cd..d7b5d70109b7 100644 --- a/jvm/jvm-analysis-kotlin-tests/intellij.jvm.analysis.kotlin.tests.iml +++ b/jvm/jvm-analysis-kotlin-tests/intellij.jvm.analysis.kotlin.tests.iml @@ -10,5 +10,6 @@ + \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/SameParameterValueInspectionJvmTest.java b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/SameParameterValueInspectionJvmTest.java new file mode 100644 index 000000000000..ca6b8ce00e07 --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/SameParameterValueInspectionJvmTest.java @@ -0,0 +1,47 @@ +package com.intellij.codeInspection; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInspection.sameParameterValue.SameParameterValueInspection; +import com.intellij.psi.PsiModifier; +import com.intellij.testFramework.InspectionTestCase; + +public class SameParameterValueInspectionJvmTest extends InspectionTestCase { + private final SameParameterValueInspection myGlobalTool = new SameParameterValueInspection(); + + @Override + public void setUp() throws Exception { + super.setUp(); + myGlobalTool.highestModifier = PsiModifier.PUBLIC; + } + + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath() + "/inspection/jvm"; + } + + private String getGlobalTestDir() { + return "sameParameterValue/" + getTestName(true); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + myGlobalTool.highestModifier = PsiModifier.PROTECTED; + } + + public void testEntryPoint() { + doTest(getGlobalTestDir(), myGlobalTool); + } + + public void testMethodWithSuper() { + doTest(getGlobalTestDir(), myGlobalTool); + } + + public void testVarargs() { + doTest(getGlobalTestDir(), myGlobalTool); + } + + public void testNegativeDouble() { + doTest(getGlobalTestDir(), myGlobalTool); + } +} diff --git a/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/SameReturnValueInspectionTest.java b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/SameReturnValueInspectionTest.java new file mode 100644 index 000000000000..15f1f6ba006f --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/SameReturnValueInspectionTest.java @@ -0,0 +1,30 @@ +package com.intellij.codeInspection; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInspection.sameReturnValue.SameReturnValueInspection; +import com.intellij.testFramework.InspectionTestCase; + +public class SameReturnValueInspectionTest extends InspectionTestCase { + private final SameReturnValueInspection myGlobalTool = new SameReturnValueInspection(); + + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath() + "/inspection/jvm"; + } + + private String getGlobalTestDir() { + return "sameReturnValue/" + getTestName(true); + } + + public void testJava() { + doTest(getGlobalTestDir(), myGlobalTool); + } + + public void testKotlin() { + doTest(getGlobalTestDir(), myGlobalTool); + } + + public void testMixed() { + doTest(getGlobalTestDir(), myGlobalTool); + } +} diff --git a/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/UnusedDeclarationJvmTest.java b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/UnusedDeclarationJvmTest.java new file mode 100644 index 000000000000..893363ad7344 --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/UnusedDeclarationJvmTest.java @@ -0,0 +1,76 @@ +package com.intellij.codeInspection; + +import com.intellij.java.codeInspection.AbstractUnusedDeclarationTest; +import com.intellij.java.codeInspection.UnusedDeclarationTest; +import com.intellij.openapi.application.ex.PathManagerEx; + +public class UnusedDeclarationJvmTest extends AbstractUnusedDeclarationTest { + @Override + protected String getTestDataPath() { + return PathManagerEx.getTestDataPath(UnusedDeclarationTest.class) + "/inspection/jvm"; + } + + public void testSingleton() { + myTool.ADD_NONJAVA_TO_ENTRIES = false; + doTest(); + } + + //TODO + public void testDefaultConstructor() { + doTest(); + } + + public void testReachableFromMain() { + myTool.ADD_MAINS_TO_ENTRIES = true; + doTest(); + } + + public void testMutableCalls() { + doTest(); + } + + public void testStaticMethods() { + doTest(); + } + + public void testChainOfCalls() { + doTest(); + } + + public void testReachableFromFieldInitializer() { + doTest(); + } + + public void testReachableFromFieldArrayInitializer() { + doTest(); + } + + public void testJunitEntryPoint() { + doTest(); + } + + public void testConstructorCalls() { + doTest(); + } + + public void testNonJvmReferences() { + doTest(); + } + + //TODO uast kotlin enum support + public void _testEnumInstantiation() { + doTest(); + } + + public void _testEnumValues() { + doTest(); + } + + public void testUsagesInAnonymous() { + doTest(); + } + + public void testClassLiteralRef() { + doTest(); + } +} diff --git a/platform/analysis-api/src/com/intellij/codeInspection/lang/RefManagerExtension.java b/platform/analysis-api/src/com/intellij/codeInspection/lang/RefManagerExtension.java index 17c316f0fd5b..68f203697b83 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/lang/RefManagerExtension.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/lang/RefManagerExtension.java @@ -13,12 +13,20 @@ import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; +import java.util.Collections; import java.util.stream.Stream; public interface RefManagerExtension { @NotNull Key getID(); + @NotNull + default Collection getLanguages() { + return Collections.singleton(getLanguage()); + }; + + @Deprecated @NotNull Language getLanguage(); diff --git a/platform/analysis-api/src/com/intellij/codeInspection/reference/RefElement.java b/platform/analysis-api/src/com/intellij/codeInspection/reference/RefElement.java index a29af3de094a..88cdc52d3ca7 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/reference/RefElement.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/reference/RefElement.java @@ -42,7 +42,14 @@ public interface RefElement extends RefEntity { * * @return the PSI element. */ - PsiElement getElement(); + default PsiElement getPsiElement() { + throw new UnsupportedOperationException(); + } + + @Deprecated + default PsiElement getElement() { + return getPsiElement(); + } SmartPsiElementPointer getPointer(); diff --git a/platform/analysis-api/src/com/intellij/codeInspection/reference/RefFile.java b/platform/analysis-api/src/com/intellij/codeInspection/reference/RefFile.java index 088785e0a45f..513f187a2533 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/reference/RefFile.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/reference/RefFile.java @@ -30,5 +30,13 @@ public interface RefFile extends RefElement { * @return the file for the node. */ @Override - PsiFile getElement(); + default PsiFile getPsiElement() { + return getElement(); + } + + @Deprecated + @Override + default PsiFile getElement() { + throw new UnsupportedOperationException(); + } } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java b/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java index 8eb696a6a87a..12752c336cde 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java @@ -198,7 +198,7 @@ public class InspectionEngine { @Override public void addProblemElement(@Nullable RefEntity refEntity, @NotNull CommonProblemDescriptor... commonProblemDescriptors) { if (!(refEntity instanceof RefElement)) return; - PsiElement element = ((RefElement)refEntity).getElement(); + PsiElement element = ((RefElement)refEntity).getPsiElement(); convertToProblemDescriptors(element, commonProblemDescriptors, descriptors); } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/HTMLComposerImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/HTMLComposerImpl.java index 652bcfe98efc..97b57fc96d05 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/HTMLComposerImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/HTMLComposerImpl.java @@ -102,7 +102,7 @@ public abstract class HTMLComposerImpl extends HTMLComposer { @Nullable private HTMLComposerExtension getLanguageExtension(final RefElement refElement) { - final PsiElement element = refElement.getElement(); + final PsiElement element = refElement.getPsiElement(); return element != null ? myLanguageExtensions.get(element.getLanguage()) : null; } @@ -113,7 +113,7 @@ public abstract class HTMLComposerImpl extends HTMLComposer { } else { refElement.accept(new RefVisitor() { @Override public void visitFile(@NotNull RefFile file) { - final PsiFile psiFile = file.getElement(); + final PsiFile psiFile = file.getPsiElement(); if (psiFile != null) { buf.append(B_OPENING); buf.append(psiFile.getName()); @@ -200,7 +200,7 @@ public abstract class HTMLComposerImpl extends HTMLComposer { buf.append("\">"); String refElementName = refElement.getName(); - final PsiElement element = refElement.getElement(); + final PsiElement element = refElement.getPsiElement(); if (element != null) { VirtualFile file = PsiUtilCore.getVirtualFile(element); if (file != null) { diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefDirectoryImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefDirectoryImpl.java index 5eb16a384c9e..8b1a07fa35af 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefDirectoryImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefDirectoryImpl.java @@ -79,7 +79,7 @@ public class RefDirectoryImpl extends RefElementImpl implements RefDirectory{ @Override public String getExternalName() { - final PsiElement element = getElement(); + final PsiElement element = getPsiElement(); assert element != null; return ((PsiDirectory)element).getVirtualFile().getPath(); } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefElementImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefElementImpl.java index 85cb8c761864..e12d517b6700 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefElementImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefElementImpl.java @@ -86,7 +86,7 @@ public abstract class RefElementImpl extends RefEntityImpl implements RefElement return file != null && file.isPhysical(); } - final PsiElement element = getElement(); + final PsiElement element = getPsiElement(); return element != null && element.isPhysical(); }); } @@ -94,7 +94,7 @@ public abstract class RefElementImpl extends RefEntityImpl implements RefElement @Override @Nullable public Icon getIcon(final boolean expanded) { - final PsiElement element = getElement(); + final PsiElement element = getPsiElement(); if (element != null && element.isValid()) { return element.getIcon(Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS); } @@ -114,7 +114,7 @@ public abstract class RefElementImpl extends RefEntityImpl implements RefElement @Override @Nullable - public PsiElement getElement() { + public PsiElement getPsiElement() { return myID.getElement(); } @@ -140,6 +140,10 @@ public abstract class RefElementImpl extends RefEntityImpl implements RefElement return checkFlag(IS_REACHABLE_MASK); } + public void setReachable(boolean reachable) { + setFlag(reachable, IS_REACHABLE_MASK); + } + @Override public boolean isReferenced() { return !getInReferences().isEmpty(); @@ -231,7 +235,7 @@ public abstract class RefElementImpl extends RefEntityImpl implements RefElement @Nullable public String getURL() { - final PsiElement element = getElement(); + final PsiElement element = getPsiElement(); if (element == null || !element.isPhysical()) return null; final PsiFile containingFile = element.getContainingFile(); if (containingFile == null) return null; diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefFileImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefFileImpl.java index c5c50f9aa8fd..00870aca402b 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefFileImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefFileImpl.java @@ -48,8 +48,8 @@ public class RefFileImpl extends RefElementImpl implements RefFile { } @Override - public PsiFile getElement() { - return (PsiFile)super.getElement(); + public PsiFile getPsiElement() { + return (PsiFile)super.getPsiElement(); } @Override @@ -59,7 +59,7 @@ public class RefFileImpl extends RefElementImpl implements RefFile { @Override public String getExternalName() { - final PsiFile psiFile = getElement(); + final PsiFile psiFile = getPsiElement(); final VirtualFile virtualFile = psiFile != null ? psiFile.getVirtualFile() : null; return virtualFile != null ? virtualFile.getUrl() : getName(); } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java index 96138e2a92f9..6e45f2268cd9 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java @@ -92,10 +92,12 @@ public class RefManagerImpl extends RefManager { myPsiManager = PsiManager.getInstance(project); myRefProject = new RefProjectImpl(this); for (InspectionExtensionsFactory factory : Extensions.getExtensions(InspectionExtensionsFactory.EP_NAME)) { - final RefManagerExtension extension = factory.createRefManagerExtension(this); + final RefManagerExtension extension = factory.createRefManagerExtension(this); if (extension != null) { myExtensions.put(extension.getID(), extension); - myLanguageExtensions.put(extension.getLanguage(), extension); + for (Language language : extension.getLanguages()) { + myLanguageExtensions.put(language, extension); + } } } if (scope != null) { @@ -251,7 +253,7 @@ public class RefManagerImpl extends RefManager { if (refEntity instanceof RefDirectory) { Element fileElement = new Element("file"); - VirtualFile virtualFile = ((PsiDirectory)((RefDirectory)refEntity).getElement()).getVirtualFile(); + VirtualFile virtualFile = ((PsiDirectory)((RefDirectory)refEntity).getPsiElement()).getVirtualFile(); fileElement.addContent(virtualFile.getUrl()); problem.addContent(fileElement); } @@ -410,14 +412,9 @@ public class RefManagerImpl extends RefManager { @Override public PsiNamedElement getContainerElement(@NotNull PsiElement element) { Language language = element.getLanguage(); - return myExtensions - .values() - .stream() - .filter(extension -> extension.getLanguage().equals(language)) - .map(extension -> extension.getElementContainer(element)) - .filter(Objects::nonNull) - .findFirst() - .orElse(null); + RefManagerExtension extension = myLanguageExtensions.get(language); + if (extension == null) return null; + return extension.getElementContainer(element); } private synchronized void registerUnprocessed(VirtualFileWithId virtualFile) { @@ -425,7 +422,7 @@ public class RefManagerImpl extends RefManager { } void removeReference(@NotNull RefElement refElem) { - final PsiElement element = refElem.getElement(); + final PsiElement element = refElem.getPsiElement(); final RefManagerExtension extension = element != null ? getExtension(element.getLanguage()) : null; if (extension != null) { extension.removeReference(refElem); diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java index 5e35ffc737da..9a8ab854236c 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java @@ -53,7 +53,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider if (pointer != null) { VirtualFile vFile = pointer.getVirtualFile(); if (vFile != null && searchScope.contains(vFile)) { - final PsiElement element = ((RefElement)entity).getElement(); + final PsiElement element = ((RefElement)entity).getPsiElement(); if (element != null) { final TextRange range = element.getTextRange(); if (range != null && ((LocalSearchScope)searchScope).containsRange(element.getContainingFile(), range)) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java index bf7833193850..df3b55c9f65d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/QuickFixAction.java @@ -225,7 +225,7 @@ public class QuickFixAction extends AnAction implements CustomComponentAction { private static Set getReadOnlyFiles(@NotNull RefEntity[] refElements) { Set readOnlyFiles = new THashSet<>(); for (RefEntity refElement : refElements) { - PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getElement() : null; + PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getPsiElement() : null; if (psiElement == null || psiElement.getContainingFile() == null) continue; readOnlyFiles.add(psiElement.getContainingFile().getVirtualFile()); } @@ -255,7 +255,7 @@ public class QuickFixAction extends AnAction implements CustomComponentAction { protected static void refreshViews(@NotNull Project project, @NotNull RefEntity[] resolvedElements, @NotNull InspectionToolWrapper toolWrapper) { final Set ignoredElements = new HashSet<>(); for (RefEntity element : resolvedElements) { - final PsiElement psiElement = element instanceof RefElement ? ((RefElement)element).getElement() : null; + final PsiElement psiElement = element instanceof RefElement ? ((RefElement)element).getPsiElement() : null; if (psiElement != null && psiElement.isValid()) { ignoredElements.add(psiElement); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/offlineViewer/OfflineDescriptorResolveResult.java b/platform/lang-impl/src/com/intellij/codeInspection/offlineViewer/OfflineDescriptorResolveResult.java index 75ea70ad12cc..eac90b3ca88b 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/offlineViewer/OfflineDescriptorResolveResult.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/offlineViewer/OfflineDescriptorResolveResult.java @@ -97,7 +97,7 @@ class OfflineDescriptorResolveResult { final InspectionManager inspectionManager = InspectionManager.getInstance(presentation.getContext().getProject()); final OfflineProblemDescriptor offlineProblemDescriptor = offlineDescriptor; if (element instanceof RefElement) { - final PsiElement psiElement = ((RefElement)element).getElement(); + final PsiElement psiElement = ((RefElement)element).getPsiElement(); if (psiElement != null) { ProblemDescriptor descriptor = ProgressManager.getInstance().runProcess( () -> runLocalTool(psiElement, diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java index b8d9449d44e5..26a1541d2e11 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsView.java @@ -389,7 +389,7 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro @Nullable private static Navigatable getOpenFileDescriptor(final RefElement refElement) { - PsiElement psiElement = refElement.getElement(); + PsiElement psiElement = refElement.getPsiElement(); if (psiElement == null) return null; final PsiFile containingFile = psiElement.getContainingFile(); if (containingFile == null) return null; @@ -536,8 +536,8 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro private Pair createBaseRightComponentFor(int problemCount, RefEntity selectedEntity) { if (selectedEntity instanceof RefElement && selectedEntity.isValid() && - !(((RefElement)selectedEntity).getElement() instanceof PsiDirectory)) { - PsiElement selectedElement = ((RefElement)selectedEntity).getElement(); + !(((RefElement)selectedEntity).getPsiElement() instanceof PsiDirectory)) { + PsiElement selectedElement = ((RefElement)selectedEntity).getPsiElement(); if (problemCount == 1) { CommonProblemDescriptor[] descriptors = myTree.getSelectedDescriptors(); if (descriptors.length != 0) { @@ -787,7 +787,7 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro if (!item.isValid()) return null; - PsiElement psiElement = item instanceof RefElement ? ((RefElement)item).getElement() : null; + PsiElement psiElement = item instanceof RefElement ? ((RefElement)item).getPsiElement() : null; if (psiElement == null) return null; final CommonProblemDescriptor problem = refElementNode.getDescriptor(); @@ -872,7 +872,7 @@ public class InspectionResultsView extends JPanel implements Disposable, DataPro RefEntity[] refElements = myTree.getSelectedElements(); List psiElements = new ArrayList<>(); for (RefEntity refElement : refElements) { - PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getElement() : null; + PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getPsiElement() : null; if (psiElement != null && psiElement.isValid()) { psiElements.add(psiElement); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java index 08da798f8713..3d3e5fe2baeb 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java @@ -130,7 +130,7 @@ public class InspectionResultsViewComparator implements Comparator files = new HashSet<>(); for (RefEntity selectedElement : selectedElements) { if (selectedElement instanceof RefElement) { - files.add(((RefElement)selectedElement).getElement()); + files.add(((RefElement)selectedElement).getPsiElement()); } } @@ -120,7 +120,7 @@ public abstract class KeyAwareInspectionViewAction extends InspectionViewActionB Set files = new THashSet<>(); for (RefEntity entity : view.getTree().getSelectedElements()) { if (entity instanceof RefElement && entity.isValid()) { - final PsiElement element = ((RefElement)entity).getElement(); + final PsiElement element = ((RefElement)entity).getPsiElement(); final PsiFile file = element.getContainingFile(); files.add(file); } @@ -172,7 +172,7 @@ public abstract class KeyAwareInspectionViewAction extends InspectionViewActionB final PsiElement psiElement; if (selectedElements.length > 0 && selectedElements[0] instanceof RefElement) { - psiElement = ((RefElement)selectedElements[0]).getElement(); + psiElement = ((RefElement)selectedElements[0]).getPsiElement(); } else { psiElement = null; diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 6149ca8199cb..656993497079 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -1693,6 +1693,9 @@ ide.convert.tool.window.icons.description=Starting version 2018.2 all Platform i java.folding.icons.for.control.flow=true java.folding.icons.for.control.flow.description=Add folding icons to the gutter for control flow statements +batch.jvm.inspections=false +batch.jvm.inspections.description=Enables common batch inspections for Java and Kotlin. + show.new.plugin.page=true show.new.plugin.page.description=Show new plugin page configurable diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MethodReturnAlwaysConstantInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MethodReturnAlwaysConstantInspection.java index b60c95c29c57..b6832ad750df 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MethodReturnAlwaysConstantInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MethodReturnAlwaysConstantInspection.java @@ -26,8 +26,6 @@ import com.siyeh.ig.psiutils.ControlFlowUtils; import com.siyeh.ig.psiutils.MethodInheritanceUtils; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; import java.util.Set; public class MethodReturnAlwaysConstantInspection extends BaseGlobalInspection { @@ -54,7 +52,7 @@ public class MethodReturnAlwaysConstantInspection extends BaseGlobalInspection { return null; } - PsiModifierListOwner element = refMethod.getElement(); + PsiElement element = refMethod.getPsiElement(); if (!(element instanceof PsiMethod)) { return null; } @@ -65,13 +63,17 @@ public class MethodReturnAlwaysConstantInspection extends BaseGlobalInspection { final Set allScopeInheritors = MethodInheritanceUtils.calculateSiblingMethods(refMethod); for (RefMethod siblingMethod : allScopeInheritors) { - final PsiMethod siblingPsiMethod = (PsiMethod)siblingMethod.getElement(); + PsiElement psi = siblingMethod.getPsiElement(); + if (!(psi instanceof PsiMethod)) continue; + final PsiMethod siblingPsiMethod = (PsiMethod)psi; if (siblingPsiMethod.getBody() != null && !alwaysReturnsConstant(siblingPsiMethod)) { return null; } } for (RefMethod siblingRefMethod : allScopeInheritors) { - final PsiMethod siblingMethod = (PsiMethod)siblingRefMethod.getElement(); + PsiElement psi = siblingRefMethod.getPsiElement(); + if (!(psi instanceof PsiMethod)) continue; + final PsiMethod siblingMethod = (PsiMethod)psi; final PsiIdentifier identifier = siblingMethod.getNameIdentifier(); if (identifier == null) { continue; @@ -103,12 +105,9 @@ public class MethodReturnAlwaysConstantInspection extends BaseGlobalInspection { if (refEntity instanceof RefElement && processor.getDescriptions(refEntity) != null) { refEntity.accept(new RefJavaVisitor() { @Override public void visitMethod(@NotNull final RefMethod refMethod) { - globalContext.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { - @Override - public boolean process(PsiMethod derivedMethod) { - processor.ignoreElement(refMethod); - return false; - } + globalContext.enqueueDerivedMethodsProcessor(refMethod, derivedMethod -> { + processor.ignoreElement(refMethod); + return false; }); } }); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyDependentsInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyDependentsInspection.java index 9ed3186612af..41c288f11c80 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyDependentsInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyDependentsInspection.java @@ -23,6 +23,7 @@ import com.intellij.codeInspection.reference.RefClass; import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.ui.SingleIntegerFieldOptionsPanel; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseGlobalInspection; import com.siyeh.ig.psiutils.ClassUtils; @@ -55,8 +56,8 @@ public class ClassWithTooManyDependentsInspection extends BaseGlobalInspection { return null; } final RefClass refClass = (RefClass)refEntity; - final PsiClass aClass = refClass.getElement(); - if (ClassUtils.isInnerClass(aClass)) { + final PsiElement aClass = refClass.getPsiElement(); + if (!(aClass instanceof PsiClass) || ClassUtils.isInnerClass((PsiClass)aClass)) { return null; } final Set dependents = diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyTransitiveDependenciesInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyTransitiveDependenciesInspection.java index c858da97f4ab..ddec7f2594b9 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyTransitiveDependenciesInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyTransitiveDependenciesInspection.java @@ -23,6 +23,7 @@ import com.intellij.codeInspection.reference.RefClass; import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.ui.SingleIntegerFieldOptionsPanel; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseGlobalInspection; import com.siyeh.ig.psiutils.ClassUtils; @@ -56,8 +57,8 @@ public class ClassWithTooManyTransitiveDependenciesInspection return null; } final RefClass refClass = (RefClass)refEntity; - final PsiClass aClass = refClass.getElement(); - if (ClassUtils.isInnerClass(aClass)) { + final PsiElement aClass = refClass.getPsiElement(); + if (!(aClass instanceof PsiClass) || ClassUtils.isInnerClass((PsiClass)aClass)) { return null; } final Set dependencies = diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyTransitiveDependentsInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyTransitiveDependentsInspection.java index 7c92ac6b7f7c..d2f75fbec88d 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyTransitiveDependentsInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/ClassWithTooManyTransitiveDependentsInspection.java @@ -28,6 +28,7 @@ import com.siyeh.ig.BaseGlobalInspection; import com.siyeh.ig.psiutils.ClassUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UClass; import javax.swing.*; import java.util.Set; @@ -56,7 +57,7 @@ public class ClassWithTooManyTransitiveDependentsInspection return null; } final RefClass refClass = (RefClass)refEntity; - final PsiClass aClass = refClass.getElement(); + final UClass aClass = refClass.getUastElement(); if (ClassUtils.isInnerClass(aClass)) { return null; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassDependencyInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassDependencyInspection.java index 3f774dbbc813..cee1adbe34af 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassDependencyInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassDependencyInspection.java @@ -26,6 +26,8 @@ import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseGlobalInspection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclarationKt; +import org.jetbrains.uast.UElement; import java.util.Arrays; import java.util.HashSet; @@ -77,11 +79,7 @@ public class CyclicClassDependencyInspection extends BaseGlobalInspection { errorString = InspectionGadgetsBundle.message("cyclic.class.dependency.problem.descriptor", refEntity.getName(), Integer.valueOf(numMutualDependents)); } - final PsiClass aClass = refClass.getElement(); - if (aClass == null) { - return null; - } - final PsiElement anchor = aClass.getNameIdentifier(); + final PsiElement anchor = UDeclarationKt.getAnchorPsi(refClass.getUastElement()); if (anchor == null) return null; return new CommonProblemDescriptor[]{ inspectionManager.createProblemDescriptor(anchor, errorString, (LocalQuickFix)null, diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassInitializationInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassInitializationInspection.java index 3d9d72074b01..c580d349ecb7 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassInitializationInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassInitializationInspection.java @@ -22,6 +22,7 @@ import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.reference.RefClass; import com.intellij.codeInspection.reference.RefEntity; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseGlobalInspection; import org.jetbrains.annotations.NotNull; @@ -50,7 +51,7 @@ public class CyclicClassInitializationInspection extends BaseGlobalInspection { return null; } final RefClass refClass = (RefClass)refEntity; - final PsiClass aClass = refClass.getElement(); + final PsiClass aClass = refClass.getUastElement().getJavaPsi(); if (aClass.getContainingClass() != null) { return null; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/modularization/ClassIndependentOfModuleInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/modularization/ClassIndependentOfModuleInspection.java index 94ef39be9280..f557a6137ce0 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/modularization/ClassIndependentOfModuleInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/modularization/ClassIndependentOfModuleInspection.java @@ -22,6 +22,7 @@ import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.reference.*; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiIdentifier; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseGlobalInspection; @@ -29,6 +30,8 @@ import com.siyeh.ig.dependency.DependencyUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclarationKt; +import org.jetbrains.uast.UElement; import java.util.Set; @@ -72,13 +75,10 @@ public class ClassIndependentOfModuleInspection extends BaseGlobalInspection { return null; } } - final PsiClass aClass = refClass.getElement(); - final PsiIdentifier identifier = aClass.getNameIdentifier(); - if (identifier == null) { - return null; - } + PsiElement anchorPsi = UDeclarationKt.getAnchorPsi(refClass.getUastElement()); + if (anchorPsi == null) return null; return new CommonProblemDescriptor[]{ - manager.createProblemDescriptor(identifier, + manager.createProblemDescriptor(anchorPsi, InspectionGadgetsBundle.message( "class.independent.of.module.problem.descriptor"), true, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/modularization/ClassOnlyUsedInOneModuleInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/modularization/ClassOnlyUsedInOneModuleInspection.java index b1697848c3d9..33c2ba3b0d26 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/modularization/ClassOnlyUsedInOneModuleInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/modularization/ClassOnlyUsedInOneModuleInspection.java @@ -25,6 +25,7 @@ import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.reference.RefModule; import com.intellij.codeInspection.reference.RefPackage; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiIdentifier; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseGlobalInspection; @@ -32,6 +33,8 @@ import com.siyeh.ig.dependency.DependencyUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UClass; +import org.jetbrains.uast.UDeclarationKt; import java.util.Set; @@ -96,14 +99,11 @@ public class ClassOnlyUsedInOneModuleInspection extends BaseGlobalInspection { if (otherModule == null) { return null; } - final PsiClass aClass = refClass.getElement(); - final PsiIdentifier identifier = aClass.getNameIdentifier(); - if (identifier == null) { - return null; - } + PsiElement anchorPsi = UDeclarationKt.getAnchorPsi(refClass.getUastElement()); + if (anchorPsi == null) return null; final String moduleName = otherModule.getName(); return new CommonProblemDescriptor[]{ - manager.createProblemDescriptor(identifier, + manager.createProblemDescriptor(anchorPsi, InspectionGadgetsBundle.message( "class.only.used.in.one.module.problem.descriptor", moduleName), diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ClassOnlyUsedInOnePackageInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ClassOnlyUsedInOnePackageInspection.java index 1f53a74f239f..1c16011c41ef 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ClassOnlyUsedInOnePackageInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ClassOnlyUsedInOnePackageInspection.java @@ -22,6 +22,7 @@ import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.reference.*; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiIdentifier; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseGlobalInspection; @@ -29,6 +30,7 @@ import com.siyeh.ig.dependency.DependencyUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclarationKt; import java.util.Set; @@ -89,14 +91,11 @@ public class ClassOnlyUsedInOnePackageInspection extends BaseGlobalInspection { if (otherPackage == null) { return null; } - final PsiClass aClass = refClass.getElement(); - final PsiIdentifier identifier = aClass.getNameIdentifier(); - if (identifier == null) { - return null; - } + PsiElement anchorPsi = UDeclarationKt.getAnchorPsi(refClass.getUastElement()); + if (anchorPsi == null) return null; final String packageName = otherPackage.getName(); return new CommonProblemDescriptor[]{ - manager.createProblemDescriptor(identifier, + manager.createProblemDescriptor(anchorPsi, InspectionGadgetsBundle.message( "class.only.used.in.one.package.problem.descriptor", packageName), diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ClassUnconnectedToPackageInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ClassUnconnectedToPackageInspection.java index a333739180a6..7c47a7cac13f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ClassUnconnectedToPackageInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ClassUnconnectedToPackageInspection.java @@ -24,12 +24,15 @@ import com.intellij.codeInspection.reference.RefClass; import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.reference.RefPackage; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiIdentifier; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseGlobalInspection; import com.siyeh.ig.dependency.DependencyUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UDeclarationKt; +import org.jetbrains.uast.UElement; import java.util.Set; @@ -72,13 +75,10 @@ public class ClassUnconnectedToPackageInspection extends BaseGlobalInspection { return null; } } - final PsiClass aClass = refClass.getElement(); - final PsiIdentifier identifier = aClass.getNameIdentifier(); - if (identifier == null) { - return null; - } + PsiElement anchorPsi = UDeclarationKt.getAnchorPsi(refClass.getUastElement()); + if (anchorPsi == null) return null; return new CommonProblemDescriptor[]{ - manager.createProblemDescriptor(identifier, + manager.createProblemDescriptor(anchorPsi, InspectionGadgetsBundle.message( "class.unconnected.to.package.problem.descriptor"), true, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/DisjointPackageInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/DisjointPackageInspection.java index e5f1e1516692..a4c150ad37f7 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/DisjointPackageInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/DisjointPackageInspection.java @@ -60,7 +60,7 @@ public class DisjointPackageInspection extends BaseGlobalInspection { if (!(child instanceof RefClass)) { continue; } - final PsiClass psiClass = ((RefClass)child).getElement(); + final PsiClass psiClass = ((RefClass)child).getUastElement().getJavaPsi(); if (ClassUtils.isInnerClass(psiClass)) { continue; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ExceptionPackageInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ExceptionPackageInspection.java index f718aab3dfbc..83d201dac965 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ExceptionPackageInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/packaging/ExceptionPackageInspection.java @@ -23,12 +23,14 @@ import com.intellij.codeInspection.reference.RefClass; import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.reference.RefPackage; import com.intellij.psi.CommonClassNames; +import com.intellij.psi.PsiClass; import com.intellij.psi.util.InheritanceUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseGlobalInspection; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.uast.UClass; import java.util.List; @@ -64,7 +66,10 @@ public class ExceptionPackageInspection extends BaseGlobalInspection { continue; } classSeen = true; - if (!InheritanceUtil.isInheritor(refClass.getElement(), CommonClassNames.JAVA_LANG_THROWABLE)) { + UClass uClass = refClass.getUastElement(); + if (uClass == null) return null; + PsiClass psiClass = uClass.getJavaPsi(); + if (!InheritanceUtil.isInheritor(psiClass, CommonClassNames.JAVA_LANG_THROWABLE)) { return null; } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java index 3750f7d4b6a2..9629b9dcf98e 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java @@ -17,21 +17,20 @@ package com.siyeh.ig.psiutils; import com.intellij.codeInspection.concurrencyAnnotations.JCiPUtil; import com.intellij.psi.*; +import com.intellij.psi.impl.light.LightElement; import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.Processor; import com.intellij.util.Query; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -338,10 +337,18 @@ public class ClassUtils { } private static PsiField getIfOneStaticSelfInstance(PsiClass aClass) { - final Stream fieldStream = Stream.concat(Arrays.stream(aClass.getFields()), - Arrays.stream(aClass.getInnerClasses()) - .filter(innerClass -> innerClass.hasModifierProperty(PsiModifier.STATIC)) - .flatMap(innerClass -> Arrays.stream(innerClass.getFields()))); + Stream fieldStream = Arrays.stream(aClass.getFields()); + + StreamEx enclosingClassFields = + StreamEx.iterate(aClass.getContainingClass(), Objects::nonNull, c -> c.getContainingClass()).filter(Objects::nonNull) + .flatMap(c -> Stream.of(c.getFields())); + fieldStream = Stream.concat(fieldStream, enclosingClassFields); + + fieldStream = Stream.concat(fieldStream, + Arrays.stream(aClass.getInnerClasses()) + .filter(innerClass -> innerClass.hasModifierProperty(PsiModifier.STATIC)) + .flatMap(innerClass -> Arrays.stream(innerClass.getFields()))); + final List fields = fieldStream.filter(field -> resolveToSingletonField(aClass, field)).limit(2).collect(Collectors.toList()); return fields.size() == 1 ? fields.get(0) : null; } @@ -351,7 +358,9 @@ public class ClassUtils { return false; } final PsiClass targetClass = PsiUtil.resolveClassInClassTypeOnly(field.getType()); - return aClass.equals(targetClass); + PsiElement toCmp1 = aClass.isPhysical() ? aClass : aClass.getNavigationElement(); + PsiElement toCmp2 = targetClass == null || targetClass.isPhysical() ? targetClass : targetClass.getNavigationElement(); + return Objects.equals(toCmp1, toCmp2); } @NotNull @@ -373,6 +382,7 @@ public class ClassUtils { } private static boolean newOnlyAssignsToStaticSelfInstance(PsiMethod method, final PsiField field) { + if (field instanceof LightElement) return true; final Query search = MethodReferencesSearch.search(method, field.getUseScope(), false); final NewOnlyAssignedToFieldProcessor processor = new NewOnlyAssignedToFieldProcessor(field); search.forEach(processor); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/StaticMethodOnlyUsedInOneClassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/StaticMethodOnlyUsedInOneClassInspection.java index fa0562b12aa1..f83baf34dee8 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/StaticMethodOnlyUsedInOneClassInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/StaticMethodOnlyUsedInOneClassInspection.java @@ -31,6 +31,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.intellij.util.ObjectUtils; import com.intellij.util.Processor; import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; @@ -103,7 +104,7 @@ public class StaticMethodOnlyUsedInOneClassInspection extends BaseGlobalInspecti return null; } if (usageClass == null) { - final PsiClass aClass = containingClass.getElement(); + final PsiClass aClass = ObjectUtils.tryCast(containingClass.getPsiElement(), PsiClass.class); if (aClass != null) { final SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(manager.getProject()); method.putUserData(MARKER, smartPointerManager.createSmartPsiElementPointer(aClass)); @@ -117,11 +118,11 @@ public class StaticMethodOnlyUsedInOneClassInspection extends BaseGlobalInspecti if (ignoreTestClasses && usageClass.isTestCase()) { return null; } - final PsiClass psiClass = usageClass.getElement(); + final PsiClass psiClass = ObjectUtils.tryCast(usageClass.getPsiElement(), PsiClass.class); if (psiClass == null) { return null; } - final PsiMethod psiMethod = (PsiMethod)method.getElement(); + final PsiMethod psiMethod = ObjectUtils.tryCast(method.getPsiElement(), PsiMethod.class); if (psiMethod == null) { return null; } @@ -167,7 +168,7 @@ public class StaticMethodOnlyUsedInOneClassInspection extends BaseGlobalInspecti return true; } else { - final PsiIdentifier identifier = ((PsiMethod)((RefMethod)refEntity).getElement()).getNameIdentifier(); + final PsiElement identifier = ((RefMethod)refEntity).getUastElement().getUastAnchor().getSourcePsi(); final ProblemDescriptor problemDescriptor = createProblemDescriptor(manager, identifier, containingClass); problemDescriptionsProcessor.addProblemElement(refEntity, problemDescriptor); ref.set(containingClass); diff --git a/uast/uast-common/src/org/jetbrains/uast/UastUtils.kt b/uast/uast-common/src/org/jetbrains/uast/UastUtils.kt index d61d8e1ac0d9..4d846afab06c 100644 --- a/uast/uast-common/src/org/jetbrains/uast/UastUtils.kt +++ b/uast/uast-common/src/org/jetbrains/uast/UastUtils.kt @@ -38,6 +38,16 @@ fun UElement.getParentOfType(parentClass: Class, st } } +fun UElement.skipParentOfType(strict: Boolean, vararg parentClasses: Class): UElement? { + var element = (if (strict) uastParent else this) ?: return null + while (true) { + if (!parentClasses.any { it.isInstance(element) }) { + return element + } + element = element.uastParent ?: return null + } +} + fun UElement.getParentOfType( parentClass: Class, strict: Boolean = true, @@ -126,7 +136,7 @@ fun UElement.isChildOf(probablyParent: UElement?, strict: Boolean = false): Bool } if (probablyParent == null) return false - return isChildOf(if (strict) this else uastParent, probablyParent) + return isChildOf(if (strict) uastParent else this, probablyParent) } /** diff --git a/uast/uast-common/src/org/jetbrains/uast/declarations/UDeclaration.kt b/uast/uast-common/src/org/jetbrains/uast/declarations/UDeclaration.kt index 047ffba76be8..45fe06d78b65 100644 --- a/uast/uast-common/src/org/jetbrains/uast/declarations/UDeclaration.kt +++ b/uast/uast-common/src/org/jetbrains/uast/declarations/UDeclaration.kt @@ -67,7 +67,23 @@ interface UDeclarationEx : UDeclaration { override val javaPsi: PsiModifierListOwner } -fun UElement.getContainingDeclaration(): UDeclaration? = withContainingElements.filterIsInstance().firstOrNull() +/** + * @since 2018.3 + */ +fun UElement?.getContainingDeclaration(): UDeclaration? = this?.withContainingElements?.drop(1)?.filterIsInstance()?.firstOrNull() + +fun UElement?.getContainingDeclaration(cls: Class): T? { + val element = this?.withContainingElements?.drop(1)?.filterIsInstance()?.firstOrNull() + return if (element != null && cls.isInstance(element)) { + element as T + } else { + null + } +} + +fun UDeclaration?.getAnchorPsi():PsiElement? { + return this?.uastAnchor?.sourcePsi +} /** * A base interface for every [UElement] which have a name identifier. As analogy to [PsiNameIdentifierOwner] diff --git a/uast/uast-common/src/org/jetbrains/uast/expressions/UThisExpression.kt b/uast/uast-common/src/org/jetbrains/uast/expressions/UThisExpression.kt index ffdf686ba1bc..2d4f56c56da9 100644 --- a/uast/uast-common/src/org/jetbrains/uast/expressions/UThisExpression.kt +++ b/uast/uast-common/src/org/jetbrains/uast/expressions/UThisExpression.kt @@ -22,7 +22,7 @@ import org.jetbrains.uast.visitor.UastVisitor /** * Represents a `this` expression. - * Qualified `this` is not supported at the moment. + * TODO Qualified `this` is not supported at the moment. */ interface UThisExpression : UInstanceExpression { override fun asLogString(): String = log("label = $label") diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUObjectLiteralExpression.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUObjectLiteralExpression.kt index cc73da6ff47f..be53d22d38cb 100644 --- a/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUObjectLiteralExpression.kt +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/JavaUObjectLiteralExpression.kt @@ -20,6 +20,8 @@ import com.intellij.psi.PsiNewExpression import com.intellij.psi.PsiType import com.intellij.psi.ResolveResult import org.jetbrains.uast.* +import org.jetbrains.uast.visitor.UastTypedVisitor +import org.jetbrains.uast.visitor.UastVisitor class JavaUObjectLiteralExpression( override val psi: PsiNewExpression, @@ -51,4 +53,12 @@ class JavaUObjectLiteralExpression( override fun multiResolve(): Iterable = psi.classReference?.multiResolve(false)?.asIterable() ?: emptyList() + + override fun accept(visitor: UastVisitor) { + super.accept(visitor) + } + + override fun accept(visitor: UastTypedVisitor, data: D): R { + return super.accept(visitor, data) + } } \ No newline at end of file