Snapshot f5ae6e3be7e12e1ef9e12f48fe3a674266288e4e from master branch of git://git.jetbrains.org/idea/community.git
Change-Id: I756af70fb2910aa2687e94e28338fb9727bce518
diff --git a/java/openapi/openapi.iml b/java/openapi/openapi.iml
index 0f0db7c..e83bce3 100644
--- a/java/openapi/openapi.iml
+++ b/java/openapi/openapi.iml
@@ -26,6 +26,7 @@
<orderEntry type="module" module-name="resources-en" exported="" />
<orderEntry type="module" module-name="java-psi-api" exported="" />
<orderEntry type="module" module-name="java-indexing-api" exported="" />
+ <orderEntry type="module" module-name="java-analysis-api" exported="" />
</component>
<component name="copyright">
<option name="body" value="/* * Copyright (c) $today.year Your Corporation. All Rights Reserved. */" />
diff --git a/java/openapi/src/com/intellij/codeInspection/BaseJavaLocalInspectionTool.java b/java/openapi/src/com/intellij/codeInspection/BaseJavaLocalInspectionTool.java
index 898efb5..129dc58 100644
--- a/java/openapi/src/com/intellij/codeInspection/BaseJavaLocalInspectionTool.java
+++ b/java/openapi/src/com/intellij/codeInspection/BaseJavaLocalInspectionTool.java
@@ -16,10 +16,8 @@
package com.intellij.codeInspection;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
-import com.intellij.psi.*;
-import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
* Implement this abstract class in order to provide new inspection tool functionality. The major API limitation here is
@@ -30,94 +28,7 @@
*
* @see GlobalInspectionTool
*/
-public abstract class BaseJavaLocalInspectionTool extends LocalInspectionTool implements CustomSuppressableInspectionTool {
- /**
- * Override this to report problems at method level.
- *
- * @param method to check.
- * @param manager InspectionManager to ask for ProblemDescriptors from.
- * @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
- * @return <code>null</code> if no problems found or not applicable at method level.
- */
- @Nullable
- public ProblemDescriptor[] checkMethod(@NotNull PsiMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) {
- return null;
- }
-
- /**
- * Override this to report problems at class level.
- *
- * @param aClass to check.
- * @param manager InspectionManager to ask for ProblemDescriptors from.
- * @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
- * @return <code>null</code> if no problems found or not applicable at class level.
- */
- @Nullable
- public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
- return null;
- }
-
- /**
- * Override this to report problems at field level.
- *
- * @param field to check.
- * @param manager InspectionManager to ask for ProblemDescriptors from.
- * @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
- * @return <code>null</code> if no problems found or not applicable at field level.
- */
- @Nullable
- public ProblemDescriptor[] checkField(@NotNull PsiField field, @NotNull InspectionManager manager, boolean isOnTheFly) {
- return null;
- }
-
- /**
- * Override this to report problems at file level.
- *
- * @param file to check.
- * @param manager InspectionManager to ask for ProblemDescriptors from.
- * @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
- * @return <code>null</code> if no problems found or not applicable at file level.
- */
- @Override
- @Nullable
- public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
- return null;
- }
-
- @Override
- @NotNull
- public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
- return new JavaElementVisitor() {
- @Override public void visitMethod(PsiMethod method) {
- addDescriptors(checkMethod(method, holder.getManager(), isOnTheFly));
- }
-
- @Override public void visitClass(PsiClass aClass) {
- addDescriptors(checkClass(aClass, holder.getManager(), isOnTheFly));
- }
-
- @Override public void visitField(PsiField field) {
- addDescriptors(checkField(field, holder.getManager(), isOnTheFly));
- }
-
- @Override public void visitFile(PsiFile file) {
- addDescriptors(checkFile(file, holder.getManager(), isOnTheFly));
- }
- private void addDescriptors(final ProblemDescriptor[] descriptors) {
- if (descriptors != null) {
- for (ProblemDescriptor descriptor : descriptors) {
- holder.registerProblem(descriptor);
- }
- }
- }
- };
- }
-
- @Override
- public PsiNamedElement getProblemElement(final PsiElement psiElement) {
- return PsiTreeUtil.getNonStrictParentOfType(psiElement, PsiFile.class, PsiClass.class, PsiMethod.class, PsiField.class);
- }
-
+public abstract class BaseJavaLocalInspectionTool extends AbstractBaseJavaLocalInspectionTool implements CustomSuppressableInspectionTool {
@Override
public SuppressIntentionAction[] getSuppressActions(final PsiElement element) {
return SuppressManager.getInstance().createSuppressActions(HighlightDisplayKey.find(getShortName()));
@@ -129,12 +40,6 @@
}
public static boolean isSuppressedFor(@NotNull PsiElement element, @NotNull LocalInspectionTool tool) {
- final SuppressManager manager = SuppressManager.getInstance();
- String alternativeId;
- String id;
- return manager.isSuppressedFor(element, id = tool.getID()) ||
- (alternativeId = tool.getAlternativeID()) != null &&
- !alternativeId.equals(id) &&
- manager.isSuppressedFor(element, alternativeId);
+ return BaseJavaBatchLocalInspectionTool.isSuppressedFor(element, tool);
}
}
diff --git a/java/openapi/src/com/intellij/codeInspection/SuppressManager.java b/java/openapi/src/com/intellij/codeInspection/SuppressManager.java
index 8b60d46..df9cfdd 100644
--- a/java/openapi/src/com/intellij/codeInspection/SuppressManager.java
+++ b/java/openapi/src/com/intellij/codeInspection/SuppressManager.java
@@ -22,48 +22,31 @@
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.openapi.components.ServiceManager;
-import com.intellij.psi.*;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiCodeBlock;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiLiteralExpression;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import java.util.Collection;
-
-public abstract class SuppressManager {
+public abstract class SuppressManager implements BatchSuppressManager {
public static final String SUPPRESS_INSPECTIONS_ANNOTATION_NAME = "java.lang.SuppressWarnings";
public static SuppressManager getInstance() {
return ServiceManager.getService(SuppressManager.class);
}
- @NotNull
- public abstract SuppressIntentionAction[] createSuppressActions(@NotNull HighlightDisplayKey key);
-
- public abstract boolean isSuppressedFor(@NotNull PsiElement element, final String toolId);
-
- public abstract PsiElement getElementMemberSuppressedIn(@NotNull PsiDocCommentOwner owner, final String inspectionToolID);
-
- @Nullable
- public abstract PsiElement getAnnotationMemberSuppressedIn(@NotNull PsiModifierListOwner owner, String inspectionToolID);
-
- @Nullable
- public abstract PsiElement getDocCommentToolSuppressedIn(@NotNull PsiDocCommentOwner owner, String inspectionToolID);
-
- @NotNull
- public abstract Collection<String> getInspectionIdsSuppressedInAnnotation(@NotNull PsiModifierListOwner owner);
-
- @Nullable
- public abstract String getSuppressedInspectionIdsIn(@NotNull PsiElement element);
-
- @Nullable
- public abstract PsiElement getElementToolSuppressedIn(@NotNull PsiElement place, String toolId);
-
- public abstract boolean canHave15Suppressions(@NotNull PsiElement file);
-
- public abstract boolean alreadyHas14Suppressions(@NotNull PsiDocCommentOwner commentOwner);
-
public static boolean isSuppressedInspectionName(PsiLiteralExpression expression) {
PsiAnnotation annotation = PsiTreeUtil.getParentOfType(expression, PsiAnnotation.class, true, PsiCodeBlock.class, PsiField.class);
return annotation != null && SUPPRESS_INSPECTIONS_ANNOTATION_NAME.equals(annotation.getQualifiedName());
}
+
+ @NotNull
+ @Override
+ public SuppressQuickFix[] createBatchSuppressActions(@NotNull HighlightDisplayKey key) {
+ return BatchSuppressManager.SERVICE.getInstance().createBatchSuppressActions(key);
+ }
+
+ @NotNull
+ public abstract SuppressIntentionAction[] createSuppressActions(@NotNull HighlightDisplayKey key);
}
\ No newline at end of file
diff --git a/java/openapi/src/com/intellij/openapi/module/LanguageLevelUtil.java b/java/openapi/src/com/intellij/openapi/module/LanguageLevelUtil.java
index 0ee5397..1fa919b 100644
--- a/java/openapi/src/com/intellij/openapi/module/LanguageLevelUtil.java
+++ b/java/openapi/src/com/intellij/openapi/module/LanguageLevelUtil.java
@@ -15,11 +15,8 @@
*/
package com.intellij.openapi.module;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.projectRoots.JavaSdk;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
-import com.intellij.openapi.roots.LanguageLevelModuleExtension;
-import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import org.jetbrains.annotations.NotNull;
@@ -27,19 +24,11 @@
/**
* @author yole
*/
-public class LanguageLevelUtil {
+public class LanguageLevelUtil extends EffectiveLanguageLevelUtil {
private LanguageLevelUtil() {
}
@NotNull
- public static LanguageLevel getEffectiveLanguageLevel(@NotNull final Module module) {
- ApplicationManager.getApplication().assertReadAccessAllowed();
- LanguageLevel level = LanguageLevelModuleExtension.getInstance(module).getLanguageLevel();
- if (level != null) return level;
- return LanguageLevelProjectExtension.getInstance(module.getProject()).getLanguageLevel();
- }
-
- @NotNull
public static LanguageLevel getLanguageLevelForFile(final VirtualFile file) {
if (file == null) return LanguageLevel.HIGHEST;
diff --git a/java/openapi/src/com/intellij/openapi/roots/LanguageLevelModuleExtension.java b/java/openapi/src/com/intellij/openapi/roots/LanguageLevelModuleExtension.java
deleted file mode 100644
index e6db187..0000000
--- a/java/openapi/src/com/intellij/openapi/roots/LanguageLevelModuleExtension.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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.
- */
-
-/*
- * User: anna
- * Date: 27-Dec-2007
- */
-package com.intellij.openapi.roots;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.WriteExternalException;
-import com.intellij.pom.java.LanguageLevel;
-import org.jdom.Element;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.Nullable;
-
-public class LanguageLevelModuleExtension extends ModuleExtension<LanguageLevelModuleExtension> {
- @NonNls private static final String LANGUAGE_LEVEL_ELEMENT_NAME = "LANGUAGE_LEVEL";
- private Module myModule;
- private final boolean myWritable;
- private static final Logger LOG = Logger.getInstance("#" + LanguageLevelModuleExtension.class.getName());
-
- public static LanguageLevelModuleExtension getInstance(final Module module) {
- return ModuleRootManager.getInstance(module).getModuleExtension(LanguageLevelModuleExtension.class);
- }
-
- private LanguageLevel myLanguageLevel;
- private final LanguageLevelModuleExtension mySource;
-
- public LanguageLevelModuleExtension(Module module) {
- myModule = module;
- mySource = null;
- myWritable = false;
- }
-
- public LanguageLevelModuleExtension(final LanguageLevelModuleExtension source, boolean writable) {
- myWritable = writable;
- myModule = source.myModule;
- myLanguageLevel = source.myLanguageLevel;
- mySource = source;
- }
-
- public void setLanguageLevel(final LanguageLevel languageLevel) {
- LOG.assertTrue(myWritable, "Writable model can be retrieved from writable ModifiableRootModel");
- myLanguageLevel = languageLevel;
- }
-
- @Nullable
- public LanguageLevel getLanguageLevel() {
- return myLanguageLevel;
- }
-
- @Override
- public void readExternal(final Element element) throws InvalidDataException {
- final String languageLevel = element.getAttributeValue(LANGUAGE_LEVEL_ELEMENT_NAME);
- if (languageLevel != null) {
- try {
- myLanguageLevel = LanguageLevel.valueOf(languageLevel);
- }
- catch (IllegalArgumentException e) {
- //bad value was stored
- }
- }
- }
-
- @Override
- public void writeExternal(final Element element) throws WriteExternalException {
- if (myLanguageLevel != null) {
- element.setAttribute(LANGUAGE_LEVEL_ELEMENT_NAME, myLanguageLevel.toString());
- }
- }
-
- @Override
- public ModuleExtension getModifiableModel(final boolean writable) {
- return new LanguageLevelModuleExtension(this, writable);
- }
-
- @Override
- public void commit() {
- if (mySource != null && mySource.myLanguageLevel != myLanguageLevel) {
- if (myModule.isLoaded()) { //do not reload project for non-committed modules: j2me|project imports
- if (mySource.myLanguageLevel != myLanguageLevel) {
- final LanguageLevelProjectExtension languageLevelProjectExtension =
- LanguageLevelProjectExtension.getInstance(myModule.getProject());
- final LanguageLevel projectLanguageLevel = languageLevelProjectExtension.getLanguageLevel();
- final boolean explicit2ImplicitProjectLevel = myLanguageLevel == null && mySource.myLanguageLevel == projectLanguageLevel;
- final boolean implicit2ExplicitProjectLevel = mySource.myLanguageLevel == null && myLanguageLevel == projectLanguageLevel;
- if (!(explicit2ImplicitProjectLevel || implicit2ExplicitProjectLevel)) {
- languageLevelProjectExtension.reloadProjectOnLanguageLevelChange(myLanguageLevel == null ? projectLanguageLevel : myLanguageLevel, true);
- }
- }
- }
- mySource.myLanguageLevel = myLanguageLevel;
- }
- }
-
- @Override
- public boolean isChanged() {
- return mySource != null && mySource.myLanguageLevel != myLanguageLevel;
- }
-
- @Override
- public void dispose() {
- myModule = null;
- myLanguageLevel = null;
- }
-}
\ No newline at end of file
diff --git a/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java b/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java
deleted file mode 100644
index 2852584..0000000
--- a/java/openapi/src/com/intellij/psi/util/RedundantCastUtil.java
+++ /dev/null
@@ -1,629 +0,0 @@
-/*
- * 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.
- */
-package com.intellij.psi.util;
-
-import com.intellij.codeInsight.AnnotationUtil;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.Comparing;
-import com.intellij.openapi.util.Ref;
-import com.intellij.psi.*;
-import com.intellij.psi.codeStyle.CodeStyleManager;
-import com.intellij.psi.tree.IElementType;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.IncorrectOperationException;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * @author max
- * Date: Mar 24, 2002
- */
-public class RedundantCastUtil {
- private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.redundantCast.RedundantCastUtil");
-
- private RedundantCastUtil() { }
-
- @NotNull
- public static List<PsiTypeCastExpression> getRedundantCastsInside(PsiElement where) {
- MyCollectingVisitor visitor = new MyCollectingVisitor();
- if (where instanceof PsiEnumConstant) {
- where.accept(visitor);
- } else {
- where.acceptChildren(visitor);
- }
- return new ArrayList<PsiTypeCastExpression>(visitor.myFoundCasts);
- }
-
- public static boolean isCastRedundant (PsiTypeCastExpression typeCast) {
- PsiElement parent = typeCast.getParent();
- while(parent instanceof PsiParenthesizedExpression) parent = parent.getParent();
- if (parent instanceof PsiExpressionList) parent = parent.getParent();
- if (parent instanceof PsiReferenceExpression) parent = parent.getParent();
- MyIsRedundantVisitor visitor = new MyIsRedundantVisitor(false);
- parent.accept(visitor);
- return visitor.isRedundant;
- }
-
- @Nullable
- private static PsiExpression deparenthesizeExpression(PsiExpression arg) {
- while (arg instanceof PsiParenthesizedExpression) arg = ((PsiParenthesizedExpression) arg).getExpression();
- return arg;
- }
-
- public static void removeCast(PsiTypeCastExpression castExpression) {
- if (castExpression == null) return;
- PsiExpression operand = castExpression.getOperand();
- if (operand instanceof PsiParenthesizedExpression) {
- final PsiParenthesizedExpression parExpr = (PsiParenthesizedExpression)operand;
- operand = parExpr.getExpression();
- }
- if (operand == null) return;
-
- PsiElement toBeReplaced = castExpression;
-
- PsiElement parent = castExpression.getParent();
- while (parent instanceof PsiParenthesizedExpression) {
- toBeReplaced = parent;
- parent = parent.getParent();
- }
-
- try {
- toBeReplaced.replace(operand);
- }
- catch (IncorrectOperationException e) {
- LOG.error(e);
- }
- }
-
- private static class MyCollectingVisitor extends MyIsRedundantVisitor {
- private final Set<PsiTypeCastExpression> myFoundCasts = new HashSet<PsiTypeCastExpression>();
-
- private MyCollectingVisitor() {
- super(true);
- }
-
- @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
- expression.acceptChildren(this);
- }
-
- @Override public void visitClass(PsiClass aClass) {
- // avoid multiple visit
- }
-
- @Override public void visitMethod(PsiMethod method) {
- // avoid multiple visit
- }
-
- @Override public void visitField(PsiField field) {
- // avoid multiple visit
- }
-
- @Override
- protected void addToResults(@NotNull PsiTypeCastExpression typeCast){
- if (!isTypeCastSemantic(typeCast)) {
- myFoundCasts.add(typeCast);
- }
- }
- }
-
- private static class MyIsRedundantVisitor extends JavaRecursiveElementVisitor {
- private boolean isRedundant = false;
- private final boolean myRecursive;
-
- private MyIsRedundantVisitor(final boolean recursive) {
- myRecursive = recursive;
- }
-
- @Override
- public void visitElement(final PsiElement element) {
- if (myRecursive) {
- super.visitElement(element);
- }
- }
-
- protected void addToResults(@NotNull PsiTypeCastExpression typeCast){
- if (!isTypeCastSemantic(typeCast)) {
- isRedundant = true;
- }
- }
-
- @Override public void visitAssignmentExpression(PsiAssignmentExpression expression) {
- processPossibleTypeCast(expression.getRExpression(), expression.getLExpression().getType());
- super.visitAssignmentExpression(expression);
- }
-
- @Override public void visitVariable(PsiVariable variable) {
- processPossibleTypeCast(variable.getInitializer(), variable.getType());
- super.visitVariable(variable);
- }
-
- @Override public void visitReturnStatement(PsiReturnStatement statement) {
- final PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class);
- if (method != null) {
- final PsiType returnType = method.getReturnType();
- final PsiExpression returnValue = statement.getReturnValue();
- if (returnValue != null) {
- processPossibleTypeCast(returnValue, returnType);
- }
- }
- super.visitReturnStatement(statement);
- }
-
- @Override
- public void visitPolyadicExpression(PsiPolyadicExpression expression) {
- IElementType tokenType = expression.getOperationTokenType();
- PsiExpression[] operands = expression.getOperands();
- if (operands.length >= 2) {
- PsiType lType = operands[0].getType();
- processBinaryExpressionOperand(deparenthesizeExpression(operands[0]), operands[1].getType(), tokenType);
- for (int i = 1; i < operands.length; i++) {
- PsiExpression operand = deparenthesizeExpression(operands[i]);
- if (operand == null) continue;
- processBinaryExpressionOperand(operand, lType, tokenType);
- lType = TypeConversionUtil.calcTypeForBinaryExpression(lType, operand.getType(), tokenType, true);
- }
- }
- super.visitPolyadicExpression(expression);
- }
-
- private void processBinaryExpressionOperand(final PsiExpression operand,
- final PsiType otherType,
- final IElementType binaryToken) {
- if (operand instanceof PsiTypeCastExpression) {
- PsiTypeCastExpression typeCast = (PsiTypeCastExpression)operand;
- PsiExpression toCast = typeCast.getOperand();
- if (toCast != null && TypeConversionUtil.isBinaryOperatorApplicable(binaryToken, toCast.getType(), otherType, false)) {
- addToResults(typeCast);
- }
- }
- }
-
- private void processPossibleTypeCast(PsiExpression rExpr, @Nullable PsiType lType) {
- rExpr = deparenthesizeExpression(rExpr);
- if (rExpr instanceof PsiTypeCastExpression) {
- PsiExpression castOperand = ((PsiTypeCastExpression)rExpr).getOperand();
- if (castOperand != null) {
- PsiType operandType = castOperand.getType();
- if (operandType != null) {
- if (lType != null && TypeConversionUtil.isAssignable(lType, operandType, false)) {
- addToResults((PsiTypeCastExpression)rExpr);
- }
- }
- }
- }
- }
-
- @Override public void visitMethodCallExpression(PsiMethodCallExpression expression) {
- processCall(expression);
-
- checkForVirtual(expression);
- super.visitMethodCallExpression(expression);
- }
-
- private void checkForVirtual(PsiMethodCallExpression methodCall) {
- PsiReferenceExpression methodExpr = methodCall.getMethodExpression();
- PsiExpression qualifier = methodExpr.getQualifierExpression();
- if (!(qualifier instanceof PsiParenthesizedExpression)) return;
- PsiExpression operand = ((PsiParenthesizedExpression)qualifier).getExpression();
- if (!(operand instanceof PsiTypeCastExpression)) return;
- PsiTypeCastExpression typeCast = (PsiTypeCastExpression)operand;
- PsiExpression castOperand = typeCast.getOperand();
- if (castOperand == null) return;
-
- PsiType type = castOperand.getType();
- if (type == null) return;
- if (type instanceof PsiPrimitiveType) return;
-
- final JavaResolveResult resolveResult = methodExpr.advancedResolve(false);
- PsiMethod targetMethod = (PsiMethod)resolveResult.getElement();
- if (targetMethod == null) return;
- if (targetMethod.hasModifierProperty(PsiModifier.STATIC)) return;
-
- try {
- PsiManager manager = methodExpr.getManager();
- PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
-
- final PsiExpression expressionFromText = factory.createExpressionFromText(methodCall.getText(), methodCall);
- if (!(expressionFromText instanceof PsiMethodCallExpression)) return;
- PsiMethodCallExpression newCall = (PsiMethodCallExpression)expressionFromText;
- PsiExpression newQualifier = newCall.getMethodExpression().getQualifierExpression();
- PsiExpression newOperand = ((PsiTypeCastExpression)((PsiParenthesizedExpression)newQualifier).getExpression()).getOperand();
- newQualifier.replace(newOperand);
-
- final JavaResolveResult newResult = newCall.getMethodExpression().advancedResolve(false);
- if (!newResult.isValidResult()) return;
- final PsiMethod newTargetMethod = (PsiMethod)newResult.getElement();
- final PsiType newReturnType = newResult.getSubstitutor().substitute(newTargetMethod.getReturnType());
- final PsiType oldReturnType = resolveResult.getSubstitutor().substitute(targetMethod.getReturnType());
- if (Comparing.equal(newReturnType, oldReturnType)) {
- if (newTargetMethod.equals(targetMethod) ||
- (newTargetMethod.getSignature(newResult.getSubstitutor()).equals(targetMethod.getSignature(resolveResult.getSubstitutor())) &&
- !(newTargetMethod.isDeprecated() && !targetMethod.isDeprecated()) && // see SCR11555, SCR14559
- areThrownExceptionsCompatible(targetMethod, newTargetMethod))) {
- addToResults(typeCast);
- }
- }
- }
- catch (IncorrectOperationException ignore) { }
- }
-
- private static boolean areThrownExceptionsCompatible(final PsiMethod targetMethod, final PsiMethod newTargetMethod) {
- final PsiClassType[] oldThrowsTypes = targetMethod.getThrowsList().getReferencedTypes();
- final PsiClassType[] newThrowsTypes = newTargetMethod.getThrowsList().getReferencedTypes();
- for (final PsiClassType throwsType : newThrowsTypes) {
- if (!isExceptionThrown(throwsType, oldThrowsTypes)) return false;
- }
- return true;
- }
-
- private static boolean isExceptionThrown(PsiClassType exceptionType, PsiClassType[] thrownTypes) {
- for (final PsiClassType type : thrownTypes) {
- if (type.equals(exceptionType)) return true;
- }
- return false;
- }
-
- @Override public void visitNewExpression(PsiNewExpression expression) {
- processCall(expression);
- super.visitNewExpression(expression);
- }
-
- @Override
- public void visitEnumConstant(PsiEnumConstant enumConstant) {
- processCall(enumConstant);
- super.visitEnumConstant(enumConstant);
- }
-
- @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
- //expression.acceptChildren(this);
- }
-
- private void processCall(PsiCall expression){
- PsiExpressionList argumentList = expression.getArgumentList();
- if (argumentList == null) return;
- PsiExpression[] args = argumentList.getExpressions();
- PsiMethod oldMethod = expression.resolveMethod();
- if (oldMethod == null) return;
- PsiParameter[] parameters = oldMethod.getParameterList().getParameters();
-
- try {
- for (int i = 0; i < args.length; i++) {
- final PsiExpression arg = deparenthesizeExpression(args[i]);
- if (arg instanceof PsiTypeCastExpression) {
- PsiTypeCastExpression cast = (PsiTypeCastExpression)arg;
- if (i == args.length - 1 && args.length == parameters.length && parameters[i].isVarArgs()) {
- //do not mark cast to resolve ambiguity for calling varargs method with inexact argument
- continue;
- }
- PsiCall newCall = (PsiCall) expression.copy();
- final PsiExpressionList argList = newCall.getArgumentList();
- LOG.assertTrue(argList != null);
- PsiExpression[] newArgs = argList.getExpressions();
- PsiTypeCastExpression castExpression = (PsiTypeCastExpression) deparenthesizeExpression(newArgs[i]);
- PsiExpression castOperand = castExpression.getOperand();
- if (castOperand == null) return;
- castExpression.replace(castOperand);
- if (newCall instanceof PsiEnumConstant) {
- // do this manually, because PsiEnumConstantImpl.resolveMethodGenerics() will assert (no containing class for the copy)
- final PsiEnumConstant enumConstant = (PsiEnumConstant)expression;
- PsiClass containingClass = enumConstant.getContainingClass();
- final JavaPsiFacade facade = JavaPsiFacade.getInstance(enumConstant.getProject());
- final PsiClassType type = facade.getElementFactory().createType(containingClass);
- final JavaResolveResult newResult = facade.getResolveHelper().resolveConstructor(type, newCall.getArgumentList(), enumConstant);
- if (oldMethod.equals(newResult.getElement()) && newResult.isValidResult()) {
- addToResults(cast);
- }
- } else {
- final JavaResolveResult newResult = newCall.resolveMethodGenerics();
- if (oldMethod.equals(newResult.getElement()) && newResult.isValidResult() &&
- Comparing.equal(((PsiCallExpression)newCall).getType(), ((PsiCallExpression)expression).getType())) {
- addToResults(cast);
- }
- }
- }
- }
- }
- catch (IncorrectOperationException e) {
- return;
- }
-
- for (PsiExpression arg : args) {
- if (arg instanceof PsiTypeCastExpression) {
- PsiExpression castOperand = ((PsiTypeCastExpression)arg).getOperand();
- if (castOperand != null) {
- castOperand.accept(this);
- }
- }
- else {
- arg.accept(this);
- }
- }
- }
-
- @Override public void visitTypeCastExpression(PsiTypeCastExpression typeCast) {
- PsiExpression operand = typeCast.getOperand();
- if (operand == null) return;
-
- PsiElement expr = deparenthesizeExpression(operand);
-
- final PsiType topCastType = typeCast.getType();
- if (expr instanceof PsiTypeCastExpression) {
- PsiTypeElement typeElement = ((PsiTypeCastExpression)expr).getCastType();
- if (typeElement == null) return;
- PsiType castType = typeElement.getType();
- final PsiExpression innerOperand = ((PsiTypeCastExpression)expr).getOperand();
- final PsiType operandType = innerOperand != null ? innerOperand.getType() : null;
- if (!(castType instanceof PsiPrimitiveType)) {
- if (operandType != null && topCastType != null && TypeConversionUtil.areTypesConvertible(operandType, topCastType)) {
- addToResults((PsiTypeCastExpression)expr);
- }
- } else if (PsiPrimitiveType.getUnboxedType(operandType) == topCastType) {
- addToResults((PsiTypeCastExpression)expr);
- }
- }
- else {
- PsiElement parent = typeCast.getParent();
- if (parent instanceof PsiConditionalExpression) {
- //branches need to be of the same type
- final PsiType operandType = operand.getType();
- final PsiType conditionalType = ((PsiConditionalExpression)parent).getType();
- if (!Comparing.equal(operandType, conditionalType)) {
- if (!PsiUtil.isLanguageLevel5OrHigher(typeCast)) {
- return;
- }
- if (!checkResolveAfterRemoveCast(parent)) return;
- }
- } else if (parent instanceof PsiSynchronizedStatement && (expr instanceof PsiExpression && ((PsiExpression)expr).getType() instanceof PsiPrimitiveType)) {
- return;
- } else if (expr instanceof PsiLambdaExpression || expr instanceof PsiMethodReferenceExpression) {
- if (parent instanceof PsiParenthesizedExpression && parent.getParent() instanceof PsiReferenceExpression) {
- return;
- }
-
- final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(typeCast, true);
- if (topCastType != null && functionalInterfaceType != null && !TypeConversionUtil.isAssignable(topCastType, functionalInterfaceType, false)) return;
- }
- processAlreadyHasTypeCast(typeCast);
- }
- super.visitTypeCastExpression(typeCast);
- }
-
- private static boolean checkResolveAfterRemoveCast(PsiElement parent) {
- PsiElement grandPa = parent.getParent();
- if (grandPa instanceof PsiExpressionList) {
- PsiExpression[] expressions = ((PsiExpressionList)grandPa).getExpressions();
- int idx = ArrayUtil.find(expressions, parent);
- PsiElement grandGrandPa = grandPa.getParent();
- if (grandGrandPa instanceof PsiCall) {
- PsiElement resolve = ((PsiCall)grandGrandPa).resolveMethod();
- if (resolve instanceof PsiMethod) {
- PsiCall expression = (PsiCall)grandGrandPa.copy();
- PsiExpressionList argumentList = expression.getArgumentList();
- LOG.assertTrue(argumentList != null);
- PsiExpression toReplace = argumentList.getExpressions()[idx];
- if (toReplace instanceof PsiConditionalExpression) {
- PsiExpression thenExpression = ((PsiConditionalExpression)toReplace).getThenExpression();
- PsiExpression elseExpression = ((PsiConditionalExpression)toReplace).getElseExpression();
- if (thenExpression instanceof PsiTypeCastExpression) {
- final PsiExpression thenOperand = ((PsiTypeCastExpression)thenExpression).getOperand();
- if (thenOperand != null) {
- thenExpression.replace(thenOperand);
- }
- } else if (elseExpression instanceof PsiTypeCastExpression) {
- final PsiExpression elseOperand = ((PsiTypeCastExpression)elseExpression).getOperand();
- if (elseOperand != null) {
- elseExpression.replace(elseOperand);
- }
- }
- }
- if (expression.resolveMethod() != resolve) {
- return false;
- }
- }
- }
- }
- return true;
- }
-
- private void processAlreadyHasTypeCast(PsiTypeCastExpression typeCast){
- PsiElement parent = typeCast.getParent();
- while(parent instanceof PsiParenthesizedExpression) parent = parent.getParent();
- if (parent instanceof PsiExpressionList) return; // do not replace in arg lists - should be handled by parent
- if (parent instanceof PsiReturnStatement) return;
- if (parent instanceof PsiTypeCastExpression) return;
-
- if (isTypeCastSemantic(typeCast)) return;
-
- PsiTypeElement typeElement = typeCast.getCastType();
- if (typeElement == null) return;
- final PsiType castTo = typeElement.getType();
- final PsiType opType = typeCast.getOperand().getType();
- if (opType == null) return;
- if (parent instanceof PsiReferenceExpression) {
- if (castTo instanceof PsiClassType && opType instanceof PsiPrimitiveType) return; //explicit boxing
- //Check accessibility
- if (opType instanceof PsiClassType) {
- final PsiReferenceExpression refExpression = (PsiReferenceExpression)parent;
- PsiElement element = refExpression.resolve();
- if (!(element instanceof PsiMember)) return;
- PsiClass accessClass = ((PsiClassType)opType).resolve();
- if (accessClass == null) return;
- if (!JavaPsiFacade.getInstance(parent.getProject()).getResolveHelper().isAccessible((PsiMember)element, typeCast, accessClass)) return;
- if (!isCastRedundantInRefExpression(refExpression, typeCast.getOperand())) return;
- }
- }
-
- if (arrayAccessAtTheLeftSideOfAssignment(parent)) {
- if (TypeConversionUtil.isAssignable(opType, castTo, false) && opType.getArrayDimensions() == castTo.getArrayDimensions()) {
- addToResults(typeCast);
- }
- }
- else {
- if (TypeConversionUtil.isAssignable(castTo, opType, false)) {
- addToResults(typeCast);
- }
- }
- }
-
- private static boolean arrayAccessAtTheLeftSideOfAssignment(PsiElement element) {
- PsiAssignmentExpression assignment = PsiTreeUtil.getParentOfType(element, PsiAssignmentExpression.class, false, PsiMember.class);
- if (assignment == null) return false;
- PsiExpression lExpression = assignment.getLExpression();
- return PsiTreeUtil.isAncestor(lExpression, element, false) && lExpression instanceof PsiArrayAccessExpression;
- }
- }
-
- private static boolean isCastRedundantInRefExpression (final PsiReferenceExpression refExpression, final PsiExpression castOperand) {
- final PsiElement resolved = refExpression.resolve();
- final Ref<Boolean> result = new Ref<Boolean>(Boolean.FALSE);
- CodeStyleManager.getInstance(refExpression.getProject()).performActionWithFormatterDisabled(new Runnable() {
- @Override
- public void run() {
- try {
- final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(refExpression.getProject()).getElementFactory();
- final PsiExpression copyExpression = elementFactory.createExpressionFromText(refExpression.getText(), refExpression);
- if (copyExpression instanceof PsiReferenceExpression) {
- final PsiReferenceExpression copy = (PsiReferenceExpression)copyExpression;
- final PsiExpression qualifier = copy.getQualifierExpression();
- if (qualifier != null) {
- qualifier.replace(castOperand);
- result.set(Boolean.valueOf(copy.resolve() == resolved));
- }
- }
- }
- catch (IncorrectOperationException ignore) { }
- }
- });
- return result.get().booleanValue();
- }
-
- /** @deprecated use {@link #isTypeCastSemantic(PsiTypeCastExpression)} (to remove in IDEA 14) */
- @SuppressWarnings({"UnusedDeclaration", "SpellCheckingInspection"})
- public static boolean isTypeCastSemantical(PsiTypeCastExpression typeCast) {
- return isTypeCastSemantic(typeCast);
- }
-
- public static boolean isTypeCastSemantic(PsiTypeCastExpression typeCast) {
- PsiExpression operand = typeCast.getOperand();
- if (operand == null) return false;
-
- if (isInPolymorphicCall(typeCast)) return true;
-
- PsiType opType = operand.getType();
- PsiTypeElement typeElement = typeCast.getCastType();
- if (typeElement == null) return false;
-
- PsiType castType = typeElement.getType();
- if (castType instanceof PsiPrimitiveType) {
- if (opType instanceof PsiPrimitiveType) {
- return !opType.equals(castType); // let's suppose all not equal primitive casts are necessary
- }
- final PsiPrimitiveType unboxedOpType = PsiPrimitiveType.getUnboxedType(opType);
- if (unboxedOpType != null && !unboxedOpType.equals(castType) ) {
- return true;
- }
- }
- else if (castType instanceof PsiClassType && ((PsiClassType)castType).hasParameters()) {
- if (opType instanceof PsiClassType && ((PsiClassType)opType).isRaw()) return true;
- } else if (castType instanceof PsiClassType && ((PsiClassType)castType).isRaw()) {
- if (opType instanceof PsiClassType && ((PsiClassType)opType).hasParameters()) return true;
- }
-
- if (operand instanceof PsiLambdaExpression || operand instanceof PsiMethodReferenceExpression) {
- if (castType instanceof PsiClassType && InheritanceUtil.isInheritor(PsiUtil.resolveClassInType(castType), CommonClassNames.JAVA_IO_SERIALIZABLE)) return true;
- if (castType instanceof PsiIntersectionType) {
- boolean redundant = false;
- final PsiType[] conjuncts = ((PsiIntersectionType)castType).getConjuncts();
- for (int i = 1; i < conjuncts.length; i++) {
- PsiType conjunct = conjuncts[i];
- if (TypeConversionUtil.isAssignable(conjuncts[0], conjunct)) {
- redundant = true;
- break;
- }
- }
- if (!redundant) {
- return true;
- }
- }
- }
-
- PsiElement parent = typeCast.getParent();
- while(parent instanceof PsiParenthesizedExpression) parent = parent.getParent();
-
- if (parent instanceof PsiBinaryExpression) {
- PsiBinaryExpression expression = (PsiBinaryExpression)parent;
- PsiExpression firstOperand = expression.getLOperand();
- PsiExpression otherOperand = expression.getROperand();
- if (PsiTreeUtil.isAncestor(otherOperand, typeCast, false)) {
- PsiExpression temp = otherOperand;
- otherOperand = firstOperand;
- firstOperand = temp;
- }
- if (firstOperand != null && otherOperand != null && wrapperCastChangeSemantics(firstOperand, otherOperand, operand)) {
- return true;
- }
- } else if (parent instanceof PsiConditionalExpression) {
- if (opType instanceof PsiPrimitiveType && !(((PsiConditionalExpression)parent).getType() instanceof PsiPrimitiveType)) {
- if (PsiPrimitiveType.getUnboxedType(PsiTypesUtil.getExpectedTypeByParent((PsiExpression)parent)) != null) {
- return true;
- }
- }
- }
- return false;
- }
-
- private static boolean wrapperCastChangeSemantics(PsiExpression operand, PsiExpression otherOperand, PsiExpression toCast) {
- boolean isPrimitiveComparisonWithCast = TypeConversionUtil.isPrimitiveAndNotNull(operand.getType()) ||
- TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType());
- boolean isPrimitiveComparisonWithoutCast = TypeConversionUtil.isPrimitiveAndNotNull(toCast.getType()) ||
- TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType());
- // wrapper casted to primitive vs wrapper comparison
- return isPrimitiveComparisonWithCast != isPrimitiveComparisonWithoutCast;
- }
-
- // see http://download.java.net/jdk7/docs/api/java/lang/invoke/MethodHandle.html#sigpoly
- public static boolean isInPolymorphicCall(final PsiTypeCastExpression typeCast) {
- if (!PsiUtil.isLanguageLevel7OrHigher(typeCast)) return false;
-
- // return type
- final PsiExpression operand = typeCast.getOperand();
- if (operand instanceof PsiMethodCallExpression) {
- if (isPolymorphicMethod((PsiMethodCallExpression)operand)) return true;
- }
-
- // argument type
- final PsiElement exprList = typeCast.getParent();
- if (exprList instanceof PsiExpressionList) {
- final PsiElement methodCall = exprList.getParent();
- if (methodCall instanceof PsiMethodCallExpression) {
- if (isPolymorphicMethod((PsiMethodCallExpression)methodCall)) return true;
- }
- }
-
- return false;
- }
-
- private static boolean isPolymorphicMethod(PsiMethodCallExpression expression) {
- final PsiElement method = expression.getMethodExpression().resolve();
- return method instanceof PsiMethod &&
- AnnotationUtil.isAnnotated((PsiMethod)method, CommonClassNames.JAVA_LANG_INVOKE_MH_POLYMORPHIC, false, true);
- }
-}