mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-10-01 09:03:31 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+32
-14
@@ -51,11 +51,12 @@ import java.util.*;
|
||||
*/
|
||||
public class GenericsHighlightUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.analysis.GenericsHighlightUtil");
|
||||
|
||||
private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance();
|
||||
|
||||
private GenericsHighlightUtil() {
|
||||
}
|
||||
private GenericsHighlightUtil() { }
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkInferredTypeArguments(PsiMethod genericMethod,
|
||||
PsiMethodCallExpression call,
|
||||
PsiSubstitutor substitutor) {
|
||||
@@ -67,7 +68,8 @@ public class GenericsHighlightUtil {
|
||||
PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
|
||||
for (PsiClassType type : extendsTypes) {
|
||||
PsiType extendsType = substitutor.substitute(type);
|
||||
if (substituted instanceof PsiWildcardType && TypeConversionUtil.erasure(extendsType).equals(TypeConversionUtil.erasure(((PsiWildcardType)substituted).getExtendsBound()))) {
|
||||
if (substituted instanceof PsiWildcardType &&
|
||||
TypeConversionUtil.erasure(extendsType).equals(TypeConversionUtil.erasure(((PsiWildcardType)substituted).getExtendsBound()))) {
|
||||
PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound();
|
||||
if (extendsBound instanceof PsiClassType) {
|
||||
PsiType[] parameters = ((PsiClassType)extendsBound).getParameters();
|
||||
@@ -103,7 +105,7 @@ public class GenericsHighlightUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkParameterizedReferenceTypeArguments(PsiElement resolved,
|
||||
public static HighlightInfo checkParameterizedReferenceTypeArguments(final PsiElement resolved,
|
||||
final PsiJavaCodeReferenceElement referenceElement,
|
||||
final PsiSubstitutor substitutor) {
|
||||
if (!(resolved instanceof PsiTypeParameterListOwner)) return null;
|
||||
@@ -116,18 +118,14 @@ public class GenericsHighlightUtil {
|
||||
final PsiReferenceParameterList referenceParameterList,
|
||||
final PsiSubstitutor substitutor,
|
||||
boolean registerIntentions) {
|
||||
if (referenceParameterList != null) {
|
||||
HighlightInfo info = HighlightUtil.checkGenericsFeature(referenceParameterList, referenceParameterList.getTypeParameterElements().length);
|
||||
if (info != null) return info;
|
||||
}
|
||||
|
||||
PsiDiamondType.DiamondInferenceResult inferenceResult = null;
|
||||
PsiTypeElement[] referenceElements = null;
|
||||
if (referenceParameterList != null) {
|
||||
referenceElements = referenceParameterList.getTypeParameterElements();
|
||||
if (referenceElements.length == 1 && referenceElements[0].getType() instanceof PsiDiamondType) {
|
||||
if (!typeParameterListOwner.hasTypeParameters()) {
|
||||
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElements[0], "Diamond operator is not applicable for non-parameterized types");
|
||||
final String description = JavaErrorMessages.message("generics.diamond.not.applicable");
|
||||
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceElements[0], description);
|
||||
}
|
||||
inferenceResult = ((PsiDiamondType)referenceElements[0].getType()).resolveInferredTypes();
|
||||
final String errorMessage = inferenceResult.getErrorMessage();
|
||||
@@ -165,9 +163,9 @@ public class GenericsHighlightUtil {
|
||||
if (description != null) {
|
||||
final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, referenceParameterList, description);
|
||||
if (registerIntentions) {
|
||||
PsiElement pparent = referenceParameterList.getParent().getParent();
|
||||
if (pparent instanceof PsiTypeElement) {
|
||||
PsiElement variable = pparent.getParent();
|
||||
PsiElement grandParent = referenceParameterList.getParent().getParent();
|
||||
if (grandParent instanceof PsiTypeElement) {
|
||||
PsiElement variable = grandParent.getParent();
|
||||
if (variable instanceof PsiVariable) {
|
||||
if (targetParametersNum == 0) {
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, new RemoveTypeArgumentsFix(variable));
|
||||
@@ -1029,7 +1027,7 @@ public class GenericsHighlightUtil {
|
||||
MethodSignatureBackedByPsiMethod superMethod = SuperMethodsSearch.search(method, null, true, false).findFirst();
|
||||
if (superMethod == null) {
|
||||
HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, overrideAnnotation,
|
||||
JavaErrorMessages.message("method.doesnot.override.super"));
|
||||
JavaErrorMessages.message("method.does.not.override.super"));
|
||||
PullAsAbstractUpFix.registerQuickFix(highlightInfo, method);
|
||||
return highlightInfo;
|
||||
}
|
||||
@@ -1245,6 +1243,26 @@ public class GenericsHighlightUtil {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkParametersAllowed(PsiReferenceParameterList refParamList) {
|
||||
HighlightInfo info = HighlightUtil.checkGenericsFeature(refParamList, refParamList.getTypeParameterElements().length);
|
||||
if (info != null) return info;
|
||||
|
||||
if (refParamList.getTextLength() != 0) {
|
||||
final PsiElement parent = refParamList.getParent();
|
||||
if (parent instanceof PsiReferenceExpression) {
|
||||
final PsiElement grandParent = parent.getParent();
|
||||
if (!(grandParent instanceof PsiMethodCallExpression)) {
|
||||
final String message = JavaErrorMessages.message("generics.reference.parameters.not.allowed");
|
||||
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, refParamList, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static HighlightInfo checkParametersOnRaw(PsiReferenceParameterList refParamList) {
|
||||
if (refParamList.getTypeArguments().length == 0) return null;
|
||||
JavaResolveResult resolveResult = null;
|
||||
|
||||
+5
-4
@@ -982,16 +982,17 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitReferenceParameterList(PsiReferenceParameterList list) {
|
||||
myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list));
|
||||
@Override
|
||||
public void visitReferenceParameterList(PsiReferenceParameterList list) {
|
||||
myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list));
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list));
|
||||
}
|
||||
|
||||
@Override public void visitReturnStatement(PsiReturnStatement statement) {
|
||||
try {
|
||||
myHolder.add(HighlightUtil.checkReturnStatementType(statement));
|
||||
}
|
||||
catch (IndexNotReadyException ignore) {
|
||||
}
|
||||
catch (IndexNotReadyException ignore) { }
|
||||
}
|
||||
|
||||
@Override public void visitStatement(PsiStatement statement) {
|
||||
|
||||
@@ -1526,15 +1526,16 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean isCall = expression instanceof PsiMethodCallExpression;
|
||||
PsiExpression qualifier = refExpr.getQualifierExpression();
|
||||
if (qualifier == null) {
|
||||
return myFactory.getVarFactory().createVariableValue(var, false, null);
|
||||
return myFactory.getVarFactory().createVariableValue(var, false, null, isCall);
|
||||
}
|
||||
|
||||
if (var instanceof PsiField && var.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
DfaVariableValue qualifierValue = createChainedVariableValue(qualifier);
|
||||
if (qualifierValue != null) {
|
||||
return myFactory.getVarFactory().createVariableValue(var, false, qualifierValue);
|
||||
return myFactory.getVarFactory().createVariableValue(var, false, qualifierValue, isCall || qualifierValue.isViaMethods());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -147,16 +147,13 @@ public class DataFlowInspection extends BaseLocalInspectionTool {
|
||||
Pair<Set<Instruction>, Set<Instruction>> constConditions = runner.getConstConditionalExpressions();
|
||||
Set<Instruction> trueSet = constConditions.getFirst();
|
||||
Set<Instruction> falseSet = constConditions.getSecond();
|
||||
Set<Instruction> npeSet = runner.getNPEInstructions();
|
||||
Set<Instruction> cceSet = runner.getCCEInstructions();
|
||||
Set<Instruction> redundantInstanceofs = StandardDataFlowRunner.getRedundantInstanceofs(runner, visitor);
|
||||
|
||||
ArrayList<Instruction> allProblems = new ArrayList<Instruction>();
|
||||
allProblems.addAll(trueSet);
|
||||
allProblems.addAll(falseSet);
|
||||
allProblems.addAll(npeSet);
|
||||
allProblems.addAll(cceSet);
|
||||
allProblems.addAll(redundantInstanceofs);
|
||||
allProblems.addAll(runner.getNPEInstructions());
|
||||
allProblems.addAll(runner.getCCEInstructions());
|
||||
allProblems.addAll(StandardDataFlowRunner.getRedundantInstanceofs(runner, visitor));
|
||||
|
||||
Collections.sort(allProblems, new Comparator<Instruction>() {
|
||||
public int compare(Instruction i1, Instruction i2) {
|
||||
@@ -168,82 +165,105 @@ public class DataFlowInspection extends BaseLocalInspectionTool {
|
||||
|
||||
for (Instruction instruction : allProblems) {
|
||||
if (instruction instanceof MethodCallInstruction) {
|
||||
MethodCallInstruction mcInstruction = (MethodCallInstruction)instruction;
|
||||
if (mcInstruction.getCallExpression() instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression callExpression = (PsiMethodCallExpression)mcInstruction.getCallExpression();
|
||||
LocalQuickFix[] fix = createNPEFixes(callExpression.getMethodExpression().getQualifierExpression(), callExpression);
|
||||
|
||||
holder.registerProblem(callExpression,
|
||||
InspectionsBundle.message("dataflow.message.npe.method.invocation"),
|
||||
fix);
|
||||
}
|
||||
reportCallMayProduceNpe(holder, (MethodCallInstruction)instruction);
|
||||
}
|
||||
else if (instruction instanceof FieldReferenceInstruction) {
|
||||
FieldReferenceInstruction frInstruction = (FieldReferenceInstruction)instruction;
|
||||
PsiElement elementToAssert = frInstruction.getElementToAssert();
|
||||
PsiExpression expression = frInstruction.getExpression();
|
||||
if (expression instanceof PsiArrayAccessExpression) {
|
||||
LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression);
|
||||
holder.registerProblem(expression,
|
||||
InspectionsBundle.message("dataflow.message.npe.array.access"),
|
||||
fix);
|
||||
}
|
||||
else {
|
||||
LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression);
|
||||
holder.registerProblem(elementToAssert,
|
||||
InspectionsBundle.message("dataflow.message.npe.field.access"),
|
||||
fix);
|
||||
}
|
||||
reportFieldAccessMayProduceNpe(holder, (FieldReferenceInstruction)instruction);
|
||||
}
|
||||
else if (instruction instanceof TypeCastInstruction) {
|
||||
TypeCastInstruction tcInstruction = (TypeCastInstruction)instruction;
|
||||
PsiTypeCastExpression typeCast = tcInstruction.getCastExpression();
|
||||
holder.registerProblem(typeCast.getCastType(),
|
||||
InspectionsBundle.message("dataflow.message.cce", typeCast.getOperand().getText()));
|
||||
reportCastMayFail(holder, (TypeCastInstruction)instruction);
|
||||
}
|
||||
else if (instruction instanceof BranchingInstruction) {
|
||||
PsiElement psiAnchor = ((BranchingInstruction)instruction).getPsiAnchor();
|
||||
boolean underBinary = isAtRHSOfBooleanAnd(psiAnchor);
|
||||
if (instruction instanceof InstanceofInstruction && visitor.isInstanceofRedundant((InstanceofInstruction)instruction)) {
|
||||
if (visitor.canBeNull((BinopInstruction)instruction)) {
|
||||
holder.registerProblem(psiAnchor,
|
||||
InspectionsBundle.message("dataflow.message.redundant.instanceof"),
|
||||
new RedundantInstanceofFix());
|
||||
}
|
||||
else {
|
||||
final LocalQuickFix localQuickFix = createSimplifyBooleanExpressionFix(psiAnchor, true);
|
||||
holder.registerProblem(psiAnchor,
|
||||
InspectionsBundle.message(underBinary ? "dataflow.message.constant.condition.whenriched" : "dataflow.message.constant.condition", Boolean.toString(true)),
|
||||
localQuickFix == null ? null : new LocalQuickFix[]{localQuickFix});
|
||||
}
|
||||
}
|
||||
else if (psiAnchor instanceof PsiSwitchLabelStatement) {
|
||||
if (falseSet.contains(instruction)) {
|
||||
holder.registerProblem(psiAnchor,
|
||||
InspectionsBundle.message("dataflow.message.unreachable.switch.label"));
|
||||
}
|
||||
}
|
||||
else if (psiAnchor != null && !reportedAnchors.contains(psiAnchor) && !isCompileConstantInIfCondition(psiAnchor)) {
|
||||
boolean evaluatesToTrue = trueSet.contains(instruction);
|
||||
if (onTheLeftSideOfConditionalAssignemnt(psiAnchor)) {
|
||||
holder.registerProblem(
|
||||
psiAnchor,
|
||||
InspectionsBundle.message("dataflow.message.pointless.assignment.expression", Boolean.toString(evaluatesToTrue)),
|
||||
createSimplifyToAssignmentFix()
|
||||
);
|
||||
}
|
||||
else if (shouldReportConditionAlwaysTrueOrFalse(psiAnchor, evaluatesToTrue)) {
|
||||
final LocalQuickFix fix = createSimplifyBooleanExpressionFix(psiAnchor, evaluatesToTrue);
|
||||
String message = InspectionsBundle.message(underBinary ?
|
||||
"dataflow.message.constant.condition.whenriched" :
|
||||
"dataflow.message.constant.condition", Boolean.toString(evaluatesToTrue));
|
||||
holder.registerProblem(psiAnchor, message, fix == null ? null : new LocalQuickFix[]{fix});
|
||||
}
|
||||
reportedAnchors.add(psiAnchor);
|
||||
}
|
||||
handleBranchingInstruction(holder, visitor, trueSet, falseSet, reportedAnchors, (BranchingInstruction)instruction);
|
||||
}
|
||||
}
|
||||
|
||||
reportNullableArguments(runner, holder);
|
||||
reportNullableAssignments(runner, holder);
|
||||
reportUnboxedNullables(runner, holder);
|
||||
reportNullableReturns(runner, holder);
|
||||
}
|
||||
|
||||
private static void reportCallMayProduceNpe(ProblemsHolder holder, MethodCallInstruction mcInstruction) {
|
||||
if (mcInstruction.getCallExpression() instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression callExpression = (PsiMethodCallExpression)mcInstruction.getCallExpression();
|
||||
LocalQuickFix[] fix = createNPEFixes(callExpression.getMethodExpression().getQualifierExpression(), callExpression);
|
||||
|
||||
holder.registerProblem(callExpression,
|
||||
InspectionsBundle.message("dataflow.message.npe.method.invocation"),
|
||||
fix);
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportFieldAccessMayProduceNpe(ProblemsHolder holder, FieldReferenceInstruction frInstruction) {
|
||||
PsiElement elementToAssert = frInstruction.getElementToAssert();
|
||||
PsiExpression expression = frInstruction.getExpression();
|
||||
if (expression instanceof PsiArrayAccessExpression) {
|
||||
LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression);
|
||||
holder.registerProblem(expression,
|
||||
InspectionsBundle.message("dataflow.message.npe.array.access"),
|
||||
fix);
|
||||
}
|
||||
else {
|
||||
LocalQuickFix[] fix = createNPEFixes((PsiExpression)elementToAssert, expression);
|
||||
holder.registerProblem(elementToAssert,
|
||||
InspectionsBundle.message("dataflow.message.npe.field.access"),
|
||||
fix);
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportCastMayFail(ProblemsHolder holder, TypeCastInstruction instruction) {
|
||||
PsiTypeCastExpression typeCast = instruction.getCastExpression();
|
||||
holder.registerProblem(typeCast.getCastType(),
|
||||
InspectionsBundle.message("dataflow.message.cce", typeCast.getOperand().getText()));
|
||||
}
|
||||
|
||||
private void handleBranchingInstruction(ProblemsHolder holder,
|
||||
StandardInstructionVisitor visitor,
|
||||
Set<Instruction> trueSet,
|
||||
Set<Instruction> falseSet, HashSet<PsiElement> reportedAnchors, BranchingInstruction instruction) {
|
||||
PsiElement psiAnchor = instruction.getPsiAnchor();
|
||||
boolean underBinary = isAtRHSOfBooleanAnd(psiAnchor);
|
||||
if (instruction instanceof InstanceofInstruction && visitor.isInstanceofRedundant((InstanceofInstruction)instruction)) {
|
||||
if (visitor.canBeNull((BinopInstruction)instruction)) {
|
||||
holder.registerProblem(psiAnchor,
|
||||
InspectionsBundle.message("dataflow.message.redundant.instanceof"),
|
||||
new RedundantInstanceofFix());
|
||||
}
|
||||
else {
|
||||
final LocalQuickFix localQuickFix = createSimplifyBooleanExpressionFix(psiAnchor, true);
|
||||
holder.registerProblem(psiAnchor,
|
||||
InspectionsBundle.message(underBinary ? "dataflow.message.constant.condition.when.reached" : "dataflow.message.constant.condition", Boolean.toString(true)),
|
||||
localQuickFix == null ? null : new LocalQuickFix[]{localQuickFix});
|
||||
}
|
||||
}
|
||||
else if (psiAnchor instanceof PsiSwitchLabelStatement) {
|
||||
if (falseSet.contains(instruction)) {
|
||||
holder.registerProblem(psiAnchor,
|
||||
InspectionsBundle.message("dataflow.message.unreachable.switch.label"));
|
||||
}
|
||||
}
|
||||
else if (psiAnchor != null && !reportedAnchors.contains(psiAnchor) && !isCompileConstantInIfCondition(psiAnchor)) {
|
||||
boolean evaluatesToTrue = trueSet.contains(instruction);
|
||||
if (onTheLeftSideOfConditionalAssignemnt(psiAnchor)) {
|
||||
holder.registerProblem(
|
||||
psiAnchor,
|
||||
InspectionsBundle.message("dataflow.message.pointless.assignment.expression", Boolean.toString(evaluatesToTrue)),
|
||||
createSimplifyToAssignmentFix()
|
||||
);
|
||||
}
|
||||
else if (shouldReportConditionAlwaysTrueOrFalse(psiAnchor, evaluatesToTrue) && !visitor.silenceConstantCondition(instruction)) {
|
||||
final LocalQuickFix fix = createSimplifyBooleanExpressionFix(psiAnchor, evaluatesToTrue);
|
||||
String message = InspectionsBundle.message(underBinary ?
|
||||
"dataflow.message.constant.condition.when.reached" :
|
||||
"dataflow.message.constant.condition", Boolean.toString(evaluatesToTrue));
|
||||
holder.registerProblem(psiAnchor, message, fix == null ? null : new LocalQuickFix[]{fix});
|
||||
}
|
||||
reportedAnchors.add(psiAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportNullableArguments(StandardDataFlowRunner runner, ProblemsHolder holder) {
|
||||
Set<PsiExpression> exprs = runner.getNullableArguments();
|
||||
for (PsiExpression expr : exprs) {
|
||||
final String text = isNullLiteralExpression(expr)
|
||||
@@ -252,22 +272,25 @@ public class DataFlowInspection extends BaseLocalInspectionTool {
|
||||
LocalQuickFix[] fixes = createNPEFixes(expr, expr);
|
||||
holder.registerProblem(expr, text, fixes);
|
||||
}
|
||||
}
|
||||
|
||||
exprs = runner.getNullableAssignments();
|
||||
for (PsiExpression expr : exprs) {
|
||||
private static void reportNullableAssignments(StandardDataFlowRunner runner, ProblemsHolder holder) {
|
||||
for (PsiExpression expr : runner.getNullableAssignments()) {
|
||||
final String text = isNullLiteralExpression(expr)
|
||||
? InspectionsBundle.message("dataflow.message.assigning.null")
|
||||
: InspectionsBundle.message("dataflow.message.assigning.nullable");
|
||||
holder.registerProblem(expr, text);
|
||||
}
|
||||
}
|
||||
|
||||
exprs = runner.getUnboxedNullables();
|
||||
for (PsiExpression expr : exprs) {
|
||||
private static void reportUnboxedNullables(StandardDataFlowRunner runner, ProblemsHolder holder) {
|
||||
for (PsiExpression expr : runner.getUnboxedNullables()) {
|
||||
holder.registerProblem(expr, InspectionsBundle.message("dataflow.message.unboxing"));
|
||||
}
|
||||
}
|
||||
|
||||
final Set<PsiReturnStatement> statements = runner.getNullableReturns();
|
||||
for (PsiReturnStatement statement : statements) {
|
||||
private static void reportNullableReturns(StandardDataFlowRunner runner, ProblemsHolder holder) {
|
||||
for (PsiReturnStatement statement : runner.getNullableReturns()) {
|
||||
final PsiExpression expr = statement.getReturnValue();
|
||||
if (runner.isInNotNullMethod()) {
|
||||
final String text = isNullLiteralExpression(expr)
|
||||
|
||||
+13
@@ -36,6 +36,7 @@ import java.util.Set;
|
||||
public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
private final Set<BinopInstruction> myReachable = new THashSet<BinopInstruction>();
|
||||
private final Set<BinopInstruction> myCanBeNullInInstanceof = new THashSet<BinopInstruction>();
|
||||
private final Set<BinopInstruction> myNotToReportReachability = new THashSet<BinopInstruction>();
|
||||
private final Set<InstanceofInstruction> myUsefulInstanceofs = new THashSet<InstanceofInstruction>();
|
||||
private final FactoryMap<MethodCallInstruction, boolean[]> myParametersNotNull = new FactoryMap<MethodCallInstruction, boolean[]>() {
|
||||
@Override
|
||||
@@ -298,7 +299,11 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isViaMethods(dfaLeft) || isViaMethods(dfaRight)) {
|
||||
myNotToReportReachability.add(instruction);
|
||||
}
|
||||
myCanBeNullInInstanceof.add(instruction);
|
||||
|
||||
ArrayList<DfaInstructionState> states = new ArrayList<DfaInstructionState>();
|
||||
|
||||
final DfaMemoryState trueCopy = memState.createCopy();
|
||||
@@ -328,6 +333,10 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
return states.toArray(new DfaInstructionState[states.size()]);
|
||||
}
|
||||
|
||||
private static boolean isViaMethods(DfaValue dfa) {
|
||||
return dfa instanceof DfaVariableValue && ((DfaVariableValue)dfa).isViaMethods();
|
||||
}
|
||||
|
||||
private void handleInstanceof(InstanceofInstruction instruction, DfaValue dfaRight, DfaValue dfaLeft) {
|
||||
if ((dfaLeft instanceof DfaTypeValue || dfaLeft instanceof DfaNotNullValue) && dfaRight instanceof DfaTypeValue) {
|
||||
final PsiType leftType;
|
||||
@@ -397,4 +406,8 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
public boolean canBeNull(BinopInstruction instruction) {
|
||||
return myCanBeNullInInstanceof.contains(instruction);
|
||||
}
|
||||
|
||||
public boolean silenceConstantCondition(BranchingInstruction instruction) {
|
||||
return instruction instanceof BinopInstruction && myNotToReportReachability.contains(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-5
@@ -33,6 +33,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DfaVariableValue extends DfaValue {
|
||||
|
||||
public static class Factory {
|
||||
private final DfaVariableValue mySharedInstance;
|
||||
private final HashMap<String,ArrayList<DfaVariableValue>> myStringToObject;
|
||||
@@ -46,12 +47,13 @@ public class DfaVariableValue extends DfaValue {
|
||||
}
|
||||
|
||||
public DfaVariableValue createVariableValue(PsiVariable myVariable, boolean isNegated) {
|
||||
return createVariableValue(myVariable, isNegated, null);
|
||||
return createVariableValue(myVariable, isNegated, null, false);
|
||||
}
|
||||
public DfaVariableValue createVariableValue(PsiVariable myVariable, boolean isNegated, @Nullable DfaVariableValue qualifier) {
|
||||
public DfaVariableValue createVariableValue(PsiVariable myVariable, boolean isNegated, @Nullable DfaVariableValue qualifier, boolean viaMethods) {
|
||||
mySharedInstance.myVariable = myVariable;
|
||||
mySharedInstance.myIsNegated = isNegated;
|
||||
mySharedInstance.myQualifier = qualifier;
|
||||
mySharedInstance.myViaMethods = viaMethods;
|
||||
|
||||
String id = mySharedInstance.toString();
|
||||
ArrayList<DfaVariableValue> conditions = myStringToObject.get(id);
|
||||
@@ -65,7 +67,7 @@ public class DfaVariableValue extends DfaValue {
|
||||
}
|
||||
}
|
||||
|
||||
DfaVariableValue result = new DfaVariableValue(myVariable, isNegated, myFactory, qualifier);
|
||||
DfaVariableValue result = new DfaVariableValue(myVariable, isNegated, myFactory, qualifier, viaMethods);
|
||||
if (qualifier != null) {
|
||||
myQualifiersToChainedVariables.putValue(qualifier, result);
|
||||
}
|
||||
@@ -87,12 +89,14 @@ public class DfaVariableValue extends DfaValue {
|
||||
private PsiVariable myVariable;
|
||||
@Nullable private DfaVariableValue myQualifier;
|
||||
private boolean myIsNegated;
|
||||
private boolean myViaMethods;
|
||||
|
||||
private DfaVariableValue(PsiVariable variable, boolean isNegated, DfaValueFactory factory, @Nullable DfaVariableValue qualifier) {
|
||||
private DfaVariableValue(PsiVariable variable, boolean isNegated, DfaValueFactory factory, @Nullable DfaVariableValue qualifier, boolean viaMethods) {
|
||||
super(factory);
|
||||
myVariable = variable;
|
||||
myIsNegated = isNegated;
|
||||
myQualifier = qualifier;
|
||||
myViaMethods = viaMethods;
|
||||
}
|
||||
|
||||
private DfaVariableValue(DfaValueFactory factory) {
|
||||
@@ -111,7 +115,7 @@ public class DfaVariableValue extends DfaValue {
|
||||
}
|
||||
|
||||
public DfaVariableValue createNegated() {
|
||||
return myFactory.getVarFactory().createVariableValue(myVariable, !myIsNegated, myQualifier);
|
||||
return myFactory.getVarFactory().createVariableValue(myVariable, !myIsNegated, myQualifier, myViaMethods);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"HardCodedStringLiteral"})
|
||||
@@ -123,6 +127,7 @@ public class DfaVariableValue extends DfaValue {
|
||||
private boolean hardEquals(DfaVariableValue aVar) {
|
||||
return aVar.myVariable == myVariable &&
|
||||
aVar.myIsNegated == myIsNegated &&
|
||||
aVar.myViaMethods == myViaMethods &&
|
||||
(myQualifier == null ? aVar.myQualifier == null : myQualifier.hardEquals(aVar.myQualifier));
|
||||
}
|
||||
|
||||
@@ -130,4 +135,8 @@ public class DfaVariableValue extends DfaValue {
|
||||
public DfaVariableValue getQualifier() {
|
||||
return myQualifier;
|
||||
}
|
||||
|
||||
public boolean isViaMethods() {
|
||||
return myViaMethods;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,21 +17,26 @@ package com.intellij.openapi.projectRoots;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: 3/28/12
|
||||
* @author anna
|
||||
* @since 3/28/12
|
||||
*/
|
||||
public class JavaVersionServiceImpl extends JavaVersionService {
|
||||
private JavaSdkVersion myTestVersion = null;
|
||||
|
||||
public void setTestVersion(JavaSdkVersion testVersion) {
|
||||
@TestOnly
|
||||
public void setTestVersion(@Nullable JavaSdkVersion testVersion) {
|
||||
myTestVersion = testVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAtLeast(PsiElement element, JavaSdkVersion version) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) return myTestVersion != null && myTestVersion.isAtLeast(version);
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return myTestVersion != null && myTestVersion.isAtLeast(version);
|
||||
}
|
||||
return JavaSdkVersionUtil.isAtLeast(element, version);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,13 +40,14 @@ public class LocalsControlFlowPolicy implements ControlFlowPolicy {
|
||||
|
||||
@Nullable
|
||||
private PsiVariable checkCodeFragment(PsiElement refElement) {
|
||||
PsiElement codeFragement;
|
||||
if (refElement instanceof PsiParameter
|
||||
&& ((PsiParameter)refElement).getDeclarationScope() instanceof PsiMethod){
|
||||
codeFragement = ((PsiMethod)((PsiParameter)refElement).getDeclarationScope()).getBody();
|
||||
}
|
||||
else{
|
||||
codeFragement = ControlFlowUtil.findCodeFragment(refElement);
|
||||
PsiElement codeFragement = ControlFlowUtil.findCodeFragment(refElement);
|
||||
if (refElement instanceof PsiParameter) {
|
||||
final PsiElement declarationScope = ((PsiParameter)refElement).getDeclarationScope();
|
||||
if (declarationScope instanceof PsiMethod){
|
||||
codeFragement = ((PsiMethod)declarationScope).getBody();
|
||||
} else if (declarationScope instanceof PsiLambdaExpression) {
|
||||
codeFragement = ((PsiLambdaExpression)declarationScope).getBody();
|
||||
}
|
||||
}
|
||||
if (codeFragement == null) return null;
|
||||
if (myCodeFragment.getContainingFile() == codeFragement.getContainingFile() && //In order for jsp includes to work
|
||||
|
||||
@@ -95,7 +95,11 @@ public class InlineLocalHandler extends JavaInlineActionHandler {
|
||||
while (innerClass != containingClass && innerClass != null) {
|
||||
final PsiClass parentPsiClass = PsiTreeUtil.getParentOfType(innerClass, PsiClass.class, true);
|
||||
if (parentPsiClass == containingClass) {
|
||||
innerClassesWithUsages.add(innerClass);
|
||||
if (innerClass instanceof PsiLambdaExpression && PsiTreeUtil.isAncestor(innerClass, local, false)) {
|
||||
innerClassesWithUsages.add(((PsiLambdaExpression)innerClass).getBody());
|
||||
} else {
|
||||
innerClassesWithUsages.add(innerClass);
|
||||
}
|
||||
innerClassUsages.add(element);
|
||||
}
|
||||
innerClass = parentPsiClass;
|
||||
|
||||
@@ -113,13 +113,43 @@ public class LambdaUtil {
|
||||
|
||||
@Nullable
|
||||
public static String checkInterfaceFunctional(PsiType functionalInterfaceType) {
|
||||
final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(functionalInterfaceType);
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
final PsiClass aClass = resolveResult.getElement();
|
||||
if (aClass != null) {
|
||||
if (checkReturnTypeApplicable(resolveResult, aClass)) {
|
||||
return "No instance of type " + functionalInterfaceType.getPresentableText() + " exists so that lambda expression can be type-checked";
|
||||
}
|
||||
return checkInterfaceFunctional(aClass);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static boolean checkReturnTypeApplicable(PsiClassType.ClassResolveResult resolveResult, final PsiClass aClass) {
|
||||
final MethodSignature methodSignature = getFunction(aClass);
|
||||
if (methodSignature == null) return false;
|
||||
|
||||
for (PsiTypeParameter parameter : aClass.getTypeParameters()) {
|
||||
if (parameter.getExtendsListTypes().length == 0) continue;
|
||||
boolean depends = false;
|
||||
final PsiType substitution = resolveResult.getSubstitutor().substitute(parameter);
|
||||
if (substitution instanceof PsiWildcardType && !((PsiWildcardType)substitution).isBounded()) {
|
||||
for (PsiType paramType : methodSignature.getParameterTypes()) {
|
||||
if (depends(paramType, parameter, new TypeParamsChecker((PsiMethod)null, aClass){
|
||||
@Override
|
||||
public boolean startedInference() {
|
||||
return true;
|
||||
}
|
||||
})) {
|
||||
depends = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!depends) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String checkInterfaceFunctional(@NotNull PsiClass psiClass) {
|
||||
if (psiClass instanceof PsiTypeParameter) return null; //should be logged as cyclic inference
|
||||
|
||||
@@ -62,6 +62,8 @@ generics.type.argument.cannot.be.of.primitive.type=Type argument cannot be of pr
|
||||
generics.unchecked.assignment=Unchecked assignment: ''{0}'' to ''{1}''
|
||||
generics.unchecked.cast=Unchecked cast: ''{0}'' to ''{1}''
|
||||
generics.unchecked.call.to.member.of.raw.type=Unchecked call to ''{0}'' as a member of raw type ''{1}''
|
||||
generics.diamond.not.applicable=Diamond operator is not applicable for non-parameterized types
|
||||
generics.reference.parameters.not.allowed=Reference parameters are not allowed here
|
||||
foreach.not.applicable=foreach not applicable to type ''{0}''.
|
||||
illegal.to.access.static.member.from.enum.constructor.or.instance.initializer=It is illegal to access static member ''{0}'' from enum constructor or instance initializer
|
||||
enum.types.cannot.be.instantiated=Enum types cannot be instantiated
|
||||
@@ -74,7 +76,7 @@ generics.cannot.catch.type.parameters=Cannot catch type parameters
|
||||
generics.cannot.instanceof.type.parameters=Class or array expected
|
||||
illegal.generic.type.for.instanceof=Illegal generic type for instanceof
|
||||
cannot.select.dot.class.from.type.variable=Cannot select from a type variable
|
||||
method.doesnot.override.super=Method does not override method from its superclass
|
||||
method.does.not.override.super=Method does not override method from its superclass
|
||||
call.to.super.is.not.allowed.in.enum.constructor=Call to super is not allowed in enum constructor
|
||||
vararg.not.last.parameter=Vararg parameter must be the last in the list
|
||||
modifiers.for.enum.constants=No modifiers allowed for enum constants
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import java.util.*;
|
||||
|
||||
class C {
|
||||
static final List EMPTY = new ArrayList(0);
|
||||
|
||||
void m() {
|
||||
List<String> list = C.<error descr="Reference parameters are not allowed here"><String></error>EMPTY;
|
||||
System.out.println(list);
|
||||
}
|
||||
}
|
||||
+22
@@ -40,4 +40,26 @@ class Test1 {
|
||||
}
|
||||
}</error>;
|
||||
}
|
||||
}
|
||||
|
||||
class Test2 {
|
||||
interface X<T extends Number> {
|
||||
T foo();
|
||||
}
|
||||
|
||||
{
|
||||
X<?> x = <error descr="No instance of type X<?> exists so that lambda expression can be type-checked">() -> 123</error>;
|
||||
X<? extends Number> x1 = () -> 123;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Test3 {
|
||||
interface X<T> {
|
||||
T foo();
|
||||
}
|
||||
|
||||
{
|
||||
X<?> x = () -> 123;
|
||||
}
|
||||
}
|
||||
-2
@@ -15,11 +15,9 @@ public class BrokenAlignment {
|
||||
if (data.inner() != null) {
|
||||
System.out.println(data.inner().hashCode());
|
||||
System.out.println(<warning descr="Method invocation 'data.inner().getText().hashCode()' may produce 'java.lang.NullPointerException'">data.inner().getText().hashCode()</warning>);
|
||||
/*
|
||||
if (data.inner() != null) {
|
||||
System.out.println(data.inner().hashCode());
|
||||
}
|
||||
*/
|
||||
|
||||
data = new Data(null, null);
|
||||
System.out.println(<warning descr="Method invocation 'data.inner().hashCode()' may produce 'java.lang.NullPointerException'">data.inner().hashCode()</warning>);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class Test {
|
||||
public void foo() {
|
||||
Comparable<String> c = o -> <selection>o.indexOf("foo")</selection>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class Test {
|
||||
public void foo() {
|
||||
Comparable<String> c = o -> newMethod(o);
|
||||
}
|
||||
|
||||
private int newMethod(String o) {
|
||||
return o.indexOf("foo");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
public class Test2 {
|
||||
{
|
||||
Runnable r = () -> {
|
||||
final String p = "hello";
|
||||
System.out.println(<caret>p);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
public class Test2 {
|
||||
{
|
||||
Runnable r = () -> {
|
||||
System.out.println("hello");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+43
-34
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight.daemon;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
@@ -62,33 +77,30 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testExceptions() throws Exception { doTest(false); }
|
||||
public void testExplicitMethodParameters() throws Exception { doTest(false); }
|
||||
public void testExplicitMethodParameters1() throws Exception { doTest(false); }
|
||||
public void testInferenceWithBounds() throws Exception {doTest(false);}
|
||||
public void testInferenceWithSuperBounds() throws Exception {doTest(false);}
|
||||
public void testInferenceWithUpperBoundPromotion() throws Exception {doTest(false);}
|
||||
public void testVariance() throws Exception {doTest(false);}
|
||||
public void testForeachTypes() throws Exception {doTest(false);}
|
||||
public void testRawOverridingMethods() throws Exception {doTest(false);}
|
||||
public void testAutoboxing() throws Exception {doTest(false);}
|
||||
public void testAutoboxingMethods() throws Exception {doTest(false);}
|
||||
public void testAutoboxingConstructors() throws Exception {doTest(false);}
|
||||
public void testInferenceWithBounds() throws Exception { doTest(false); }
|
||||
public void testInferenceWithSuperBounds() throws Exception { doTest(false); }
|
||||
public void testInferenceWithUpperBoundPromotion() throws Exception { doTest(false); }
|
||||
public void testVariance() throws Exception { doTest(false); }
|
||||
public void testForeachTypes() throws Exception { doTest(false); }
|
||||
public void testRawOverridingMethods() throws Exception { doTest(false); }
|
||||
public void testAutoboxing() throws Exception { doTest(false); }
|
||||
public void testAutoboxingMethods() throws Exception { doTest(false); }
|
||||
public void testAutoboxingConstructors() throws Exception { doTest(false); }
|
||||
public void testEnumWithAbstractMethods() throws Exception { doTest(false); }
|
||||
public void testEnum() throws Exception { doTest(false); }
|
||||
public void testSameErasure() throws Exception { doTest(false); }
|
||||
|
||||
public void testMethods() throws Exception { doTest(false); }
|
||||
public void testFields() throws Exception { doTest(false); }
|
||||
public void testStaticImports() throws Exception { doTest(true); }
|
||||
public void testUncheckedCasts() throws Exception { doTest(true); }
|
||||
public void testUncheckedOverriding() throws Exception { doTest(true); }
|
||||
public void testWildcardTypes() throws Exception { doTest(true); }
|
||||
public void testConvertibleTypes() throws Exception { doTest(true); }
|
||||
|
||||
public void testIntersectionTypes() throws Exception { doTest(true); }
|
||||
public void testVarargs() throws Exception { doTest(true); }
|
||||
public void testTypeArgsOnRaw() throws Exception { doTest(false); }
|
||||
public void testConditionalExpression() throws Exception { doTest(false); }
|
||||
|
||||
public void testUnused() throws Exception { doTest(true); }
|
||||
|
||||
public void testIDEADEV7337() throws Exception { doTest(true); }
|
||||
public void testIDEADEV10459() throws Exception { doTest(true); }
|
||||
public void testIDEADEV12951() throws Exception { doTest(true); }
|
||||
@@ -101,7 +113,6 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testIDEADEV25778() throws Exception { doTest(true); }
|
||||
public void testIDEADEV57343() throws Exception { doTest(false); }
|
||||
public void testSOE() throws Exception { doTest(true); }
|
||||
|
||||
public void testGenericExtendException() throws Exception { doTest(false); }
|
||||
public void testSameErasureDifferentReturnTypes() throws Exception { doTest17Incompatibility(); }
|
||||
public void testSameErasureDifferentReturnTypesJdk14() throws Exception { doTest(false); }
|
||||
@@ -118,27 +129,25 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testInnerClassRef() throws Exception { doTest(false); }
|
||||
public void testPrivateInnerClassRef() throws Exception { doTest(false); }
|
||||
public void testWideningCastToTypeParam() throws Exception { doTest(false); }
|
||||
public void testCapturedWildcardAssignments() throws Exception { doTest(false);}
|
||||
public void testCapturedWildcardAssignments() throws Exception { doTest(false); }
|
||||
public void testTypeParameterBoundVisibility() throws Exception { doTest17Incompatibility(); }
|
||||
public void testTypeParameterBoundVisibilityJdk14() throws Exception { doTest(false);}
|
||||
|
||||
public void testUncheckedWarningsLevel6() throws Exception { doTest(true);}
|
||||
public void testIDEA77991() throws Exception { doTest(false);}
|
||||
public void testIDEA80386() throws Exception { doTest(false);}
|
||||
|
||||
public void testIDEA66311() throws Exception { doTest17Incompatibility();}
|
||||
public void testIDEA88895() throws Exception { doTest17Incompatibility();}
|
||||
public void testIDEA66311_16() throws Exception { doTest(false);}
|
||||
public void testIDEA76283() throws Exception {doTest(false);}
|
||||
public void testIDEA74899() throws Exception {doTest(false);}
|
||||
public void testIDEA63291() throws Exception {doTest(false);}
|
||||
public void testIDEA72912() throws Exception {doTest(false);}
|
||||
public void testIllegalGenericTypeInInstanceof() throws Exception {doTest(false);}
|
||||
public void testIDEA57339() throws Exception {doTest(false);}
|
||||
public void testIDEA57340() throws Exception {doTest(false);}
|
||||
public void testIDEA89771() throws Exception {doTest(false);}
|
||||
public void testIDEA89801() throws Exception {doTest(false);}
|
||||
public void testInconvertibleTypes() throws Exception {doTest(false);}
|
||||
public void testTypeParameterBoundVisibilityJdk14() throws Exception { doTest(false); }
|
||||
public void testUncheckedWarningsLevel6() throws Exception { doTest(true); }
|
||||
public void testIDEA77991() throws Exception { doTest(false); }
|
||||
public void testIDEA80386() throws Exception { doTest(false); }
|
||||
public void testIDEA66311() throws Exception { doTest17Incompatibility(); }
|
||||
public void testIDEA88895() throws Exception { doTest17Incompatibility(); }
|
||||
public void testIDEA66311_16() throws Exception { doTest(false); }
|
||||
public void testIDEA76283() throws Exception { doTest(false); }
|
||||
public void testIDEA74899() throws Exception { doTest(false); }
|
||||
public void testIDEA63291() throws Exception { doTest(false); }
|
||||
public void testIDEA72912() throws Exception { doTest(false); }
|
||||
public void testIllegalGenericTypeInInstanceof() throws Exception { doTest(false); }
|
||||
public void testIDEA57339() throws Exception { doTest(false); }
|
||||
public void testIDEA57340() throws Exception { doTest(false); }
|
||||
public void testIDEA89771() throws Exception { doTest(false); }
|
||||
public void testIDEA89801() throws Exception { doTest(false); }
|
||||
public void testInconvertibleTypes() throws Exception { doTest(false); }
|
||||
|
||||
public void testJavaUtilCollections_NoVerify() throws Exception {
|
||||
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));
|
||||
|
||||
@@ -540,6 +540,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testOneLineLambda() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTestDisabledParam() throws PrepareFailedException {
|
||||
final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject());
|
||||
settings.ELSE_ON_NEW_LINE = true;
|
||||
|
||||
@@ -158,6 +158,10 @@ public class InlineLocalTest extends LightCodeInsightTestCase {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
public void testLocalVarInsideLambdaBody1() throws Exception {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
private void doTest(final boolean inlineDef, String conflictMessage) throws Exception {
|
||||
try {
|
||||
doTest(inlineDef);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,14 +25,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Manages virtual file systems
|
||||
* Manages virtual file systems.
|
||||
*
|
||||
* @see VirtualFileSystem
|
||||
* @see LocalFileSystem
|
||||
* @see JarFileSystem
|
||||
*/
|
||||
public abstract class VirtualFileManager implements ModificationTracker{
|
||||
public static final Topic<BulkFileListener> VFS_CHANGES = new Topic<BulkFileListener>("NewVirtualFileSystem changes", BulkFileListener.class);
|
||||
public abstract class VirtualFileManager implements ModificationTracker {
|
||||
public static final Topic<BulkFileListener> VFS_CHANGES =
|
||||
new Topic<BulkFileListener>("NewVirtualFileSystem changes", BulkFileListener.class);
|
||||
|
||||
/**
|
||||
* Gets the instance of <code>VirtualFileManager</code>.
|
||||
@@ -40,7 +39,7 @@ public abstract class VirtualFileManager implements ModificationTracker{
|
||||
* @return <code>VirtualFileManager</code>
|
||||
*/
|
||||
@NotNull
|
||||
public static VirtualFileManager getInstance(){
|
||||
public static VirtualFileManager getInstance() {
|
||||
return ApplicationManager.getApplication().getComponent(VirtualFileManager.class);
|
||||
}
|
||||
|
||||
@@ -55,12 +54,12 @@ public abstract class VirtualFileManager implements ModificationTracker{
|
||||
|
||||
/**
|
||||
* Refreshes the cached file system information from the physical file system.
|
||||
* <p>
|
||||
* <p/>
|
||||
* This method should be only called within write-action.
|
||||
* See {@link com.intellij.openapi.application.Application#runWriteAction}.
|
||||
*
|
||||
* @param asynchronous if <code>true</code> then the operation will be performed in a separate thread,
|
||||
* otherwise will be performed immediately
|
||||
* otherwise will be performed immediately
|
||||
*/
|
||||
public abstract void refresh(boolean asynchronous);
|
||||
|
||||
@@ -88,14 +87,14 @@ public abstract class VirtualFileManager implements ModificationTracker{
|
||||
/**
|
||||
* Refreshes only the part of the file system needed for searching the file by the given URL and finds file
|
||||
* by the given URL.<br>
|
||||
*
|
||||
* <p/>
|
||||
* This method is useful when the file was created externally and you need to find <code>{@link VirtualFile}</code>
|
||||
* corresponding to it.<p>
|
||||
*
|
||||
* <p/>
|
||||
* This method should be only called within write-action.
|
||||
* See {@link com.intellij.openapi.application.Application#runWriteAction}.
|
||||
*
|
||||
* @param url the URL
|
||||
* @param url the URL
|
||||
* @return <code>{@link VirtualFile}</code> if the file was found, <code>null</code> otherwise
|
||||
* @see VirtualFileSystem#findFileByPath
|
||||
* @see VirtualFileSystem#refreshAndFindFileByPath
|
||||
@@ -106,7 +105,7 @@ public abstract class VirtualFileManager implements ModificationTracker{
|
||||
/**
|
||||
* Adds listener to the file system.
|
||||
*
|
||||
* @param listener the listener
|
||||
* @param listener the listener
|
||||
* @see VirtualFileListener
|
||||
*/
|
||||
public abstract void addVirtualFileListener(@NotNull VirtualFileListener listener);
|
||||
@@ -116,7 +115,7 @@ public abstract class VirtualFileManager implements ModificationTracker{
|
||||
/**
|
||||
* Removes listener form the file system.
|
||||
*
|
||||
* @param listener the listener
|
||||
* @param listener the listener
|
||||
*/
|
||||
public abstract void removeVirtualFileListener(@NotNull VirtualFileListener listener);
|
||||
|
||||
@@ -125,11 +124,11 @@ public abstract class VirtualFileManager implements ModificationTracker{
|
||||
* file systems.
|
||||
*
|
||||
* @param protocol the protocol
|
||||
* @param path the path
|
||||
* @param path the path
|
||||
* @return URL
|
||||
*/
|
||||
@NotNull
|
||||
public static String constructUrl(@NotNull String protocol, @NotNull String path){
|
||||
public static String constructUrl(@NotNull String protocol, @NotNull String path) {
|
||||
return protocol + "://" + path;
|
||||
}
|
||||
|
||||
@@ -141,7 +140,7 @@ public abstract class VirtualFileManager implements ModificationTracker{
|
||||
* @see VirtualFileSystem#getProtocol
|
||||
*/
|
||||
@Nullable
|
||||
public static String extractProtocol(@NotNull String url){
|
||||
public static String extractProtocol(@NotNull String url) {
|
||||
int index = url.indexOf("://");
|
||||
if (index < 0) return null;
|
||||
return url.substring(0, index);
|
||||
@@ -155,13 +154,14 @@ public abstract class VirtualFileManager implements ModificationTracker{
|
||||
* @return path
|
||||
*/
|
||||
@NotNull
|
||||
public static String extractPath(@NotNull String url){
|
||||
public static String extractPath(@NotNull String url) {
|
||||
int index = url.indexOf("://");
|
||||
if (index < 0) return url;
|
||||
return url.substring(index + "://".length());
|
||||
}
|
||||
|
||||
public abstract void addVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener);
|
||||
|
||||
public abstract void addVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener, @NotNull Disposable parentDisposable);
|
||||
|
||||
public abstract void removeVirtualFileManagerListener(@NotNull VirtualFileManagerListener listener);
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 350 B |
+12
-5
@@ -108,11 +108,7 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor<IndentTr
|
||||
final int offset = getLineStartSafeOffset(initialDocument, lineNumber);
|
||||
final int caretColumn = caretOffset - offset;
|
||||
|
||||
if (bounds.getStartOffset() != offset) { //selection
|
||||
startLine += 1;
|
||||
toIndent = Math.abs(bounds.getStartOffset() - offset);
|
||||
}
|
||||
else {
|
||||
if (bounds.getStartOffset() == offset) {
|
||||
String toString = initialDocument.getText(TextRange.create(offset, initialDocument.getLineEndOffset(lineNumber)));
|
||||
toIndent = StringUtil.findFirst(toString, new CharFilter() {
|
||||
@Override
|
||||
@@ -124,6 +120,12 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor<IndentTr
|
||||
toIndent = caretColumn;
|
||||
}
|
||||
}
|
||||
else if (isNotApplicable(initialDocument, offset))
|
||||
return;
|
||||
else { // selection
|
||||
startLine += 1;
|
||||
toIndent = Math.abs(bounds.getStartOffset() - offset);
|
||||
}
|
||||
}
|
||||
|
||||
// actual difference in indentation level
|
||||
@@ -141,6 +143,11 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor<IndentTr
|
||||
}
|
||||
indented.set(Boolean.TRUE);
|
||||
}
|
||||
|
||||
private boolean isNotApplicable(DocumentImpl initialDocument, int offset) {
|
||||
return caretOffset < initialDocument.getTextLength() && !StringUtil
|
||||
.isEmptyOrSpaces(initialDocument.getText(TextRange.create(offset, caretOffset)));
|
||||
}
|
||||
});
|
||||
//System.out.println("--- after indent ---\n" + document.getText());
|
||||
}
|
||||
|
||||
+12
-18
@@ -227,31 +227,25 @@ public class CodeFoldingManagerImpl extends CodeFoldingManager implements Projec
|
||||
if (runnable != null) {
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
if (myProject.isDisposed() || editor.isDisposed()) return;
|
||||
foldingModel.runBatchFoldingOperation(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (myProject.isDisposed() || editor.isDisposed()) return;
|
||||
foldingModel.runBatchFoldingOperation(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DocumentFoldingInfo documentFoldingInfo = getDocumentFoldingInfo(document);
|
||||
Editor[] editors = EditorFactory.getInstance().getEditors(document, myProject);
|
||||
for (Editor otherEditor : editors) {
|
||||
if (otherEditor == editor) continue;
|
||||
documentFoldingInfo.loadFromEditor(otherEditor);
|
||||
break;
|
||||
}
|
||||
documentFoldingInfo.setToEditor(editor);
|
||||
DocumentFoldingInfo documentFoldingInfo = getDocumentFoldingInfo(document);
|
||||
Editor[] editors = EditorFactory.getInstance().getEditors(document, myProject);
|
||||
for (Editor otherEditor : editors) {
|
||||
if (otherEditor == editor) continue;
|
||||
documentFoldingInfo.loadFromEditor(otherEditor);
|
||||
break;
|
||||
}
|
||||
documentFoldingInfo.setToEditor(editor);
|
||||
|
||||
documentFoldingInfo.clear();
|
||||
}
|
||||
});
|
||||
documentFoldingInfo.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
editor.getFoldingModel().runBatchFoldingOperationDoNotCollapseCaret(operation);
|
||||
UIUtil.invokeLaterIfNeeded(operation);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.smartPointers;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -32,13 +33,19 @@ import org.jetbrains.annotations.NotNull;
|
||||
class FileElementInfo implements SmartPointerElementInfo {
|
||||
protected final VirtualFile myVirtualFile;
|
||||
protected final Project myProject;
|
||||
protected final Language myLanguage;
|
||||
|
||||
public FileElementInfo(@NotNull PsiFile file) {
|
||||
this(file.getProject(), file.getVirtualFile());
|
||||
this(file.getProject(), file.getVirtualFile(), file.getLanguage());
|
||||
}
|
||||
protected FileElementInfo(@NotNull Project project, VirtualFile virtualFile) {
|
||||
this(project, virtualFile, null);
|
||||
}
|
||||
|
||||
protected FileElementInfo(@NotNull Project project, VirtualFile virtualFile, Language lang) {
|
||||
myVirtualFile = virtualFile;
|
||||
myProject = project;
|
||||
myLanguage = lang;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,7 +67,7 @@ class FileElementInfo implements SmartPointerElementInfo {
|
||||
|
||||
@Override
|
||||
public PsiElement restoreElement() {
|
||||
return SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject);
|
||||
return SelfElementInfo.restoreFileFromVirtual(myVirtualFile, myProject, myLanguage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -130,7 +130,6 @@ public abstract class LocalFileSystem extends NewVirtualFileSystem {
|
||||
|
||||
/** @deprecated implementation details (to remove in IDEA 13) */
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
@NotNull
|
||||
String getFileSystemRootPath();
|
||||
|
||||
/** @deprecated implementation details (to remove in IDEA 13) */
|
||||
|
||||
+13
-7
@@ -256,6 +256,9 @@ public class FileBasedStorage extends XmlElementStorage {
|
||||
LOG.info("Document was not loaded for " + myFileSpec + " file is " + (file == null ? "null" : "directory"));
|
||||
return null;
|
||||
}
|
||||
else if (file.getLength() == 0) {
|
||||
return processReadException(null);
|
||||
}
|
||||
else {
|
||||
return loadDocumentImpl(file);
|
||||
}
|
||||
@@ -269,12 +272,15 @@ public class FileBasedStorage extends XmlElementStorage {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Document processReadException(final Exception e) {
|
||||
myBlockSavingTheContent = isProjectOrModuleFile();
|
||||
private Document processReadException(@Nullable final Exception e) {
|
||||
boolean contentTruncated = e == null;
|
||||
myBlockSavingTheContent = isProjectOrModuleFile() && !contentTruncated;
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode() && !ApplicationManager.getApplication().isHeadlessEnvironment()) {
|
||||
LOG.info(e);
|
||||
final String message = "Cannot load settings from file '" + myFile.getPath() + "': " + e.getLocalizedMessage() + "\n" +
|
||||
getInvalidContentMessage();
|
||||
if (e != null) {
|
||||
LOG.info(e);
|
||||
}
|
||||
final String message = "Cannot load settings from file '" + myFile.getPath() + "': " + (e == null ? "content truncated" : e.getLocalizedMessage()) + "\n" +
|
||||
getInvalidContentMessage(contentTruncated);
|
||||
Notifications.Bus.notify(
|
||||
new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "Load Settings", message, NotificationType.WARNING));
|
||||
}
|
||||
@@ -286,8 +292,8 @@ public class FileBasedStorage extends XmlElementStorage {
|
||||
return myIsProjectSettings || myFileSpec.equals("$MODULE_FILE$");
|
||||
}
|
||||
|
||||
private String getInvalidContentMessage() {
|
||||
return isProjectOrModuleFile() ? "Please correct the file content" : "File content will be recreated";
|
||||
private String getInvalidContentMessage(boolean contentTruncated) {
|
||||
return isProjectOrModuleFile() && !contentTruncated ? "Please correct the file content" : "File content will be recreated";
|
||||
}
|
||||
|
||||
private static Document loadDocumentImpl(final VirtualFile file) throws IOException, JDOMException {
|
||||
|
||||
-7
@@ -163,9 +163,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
|
||||
if (document != null) {
|
||||
loadState(result, document.getRootElement());
|
||||
}
|
||||
else {
|
||||
LOG.info("Document was not loaded for " + myFileSpec);
|
||||
}
|
||||
|
||||
if (!myIsProjectSettings && useProvidersData) {
|
||||
for (RoamingType roamingType : RoamingType.values()) {
|
||||
@@ -173,11 +170,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
|
||||
try {
|
||||
if (myStreamProvider.isEnabled()) {
|
||||
final Document sharedDocument = StorageUtil.loadDocument(myStreamProvider.loadContent(myFileSpec, roamingType));
|
||||
|
||||
if (sharedDocument != null) {
|
||||
filterComponentsDisabledForRoaming(sharedDocument.getRootElement(), roamingType);
|
||||
filterOutOfDateComponents(sharedDocument.getRootElement());
|
||||
|
||||
loadState(result, sharedDocument.getRootElement());
|
||||
}
|
||||
}
|
||||
@@ -186,11 +181,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -83,7 +83,6 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap
|
||||
|
||||
/** @deprecated implementation details (to remove in IDEA 13) */
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFileSystemRootPath() {
|
||||
return myFSRootPath;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.platform;
|
||||
|
||||
/**
|
||||
* @author Dennis.Ushakov
|
||||
*/
|
||||
public interface HideableProjectGenerator {
|
||||
boolean isHidden();
|
||||
}
|
||||
@@ -79,6 +79,11 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
|
||||
List<DirectoryProjectGenerator> primaryGenerators = ContainerUtil.newArrayList();
|
||||
List<DirectoryProjectGenerator> otherGenerators = ContainerUtil.newArrayList();
|
||||
for (DirectoryProjectGenerator generator : generators) {
|
||||
if (generator instanceof HideableProjectGenerator) {
|
||||
if (((HideableProjectGenerator)generator).isHidden()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
boolean primary = true;
|
||||
if (generator instanceof WebProjectGenerator) {
|
||||
primary = ((WebProjectGenerator) generator).isPrimaryGenerator();
|
||||
|
||||
@@ -59,7 +59,7 @@ dataflow.message.npe.field.access=Dereference of <code>#ref</code> #loc may prod
|
||||
dataflow.message.cce=Casting <code>{0}</code> to <code>#ref</code> #loc may produce <code>java.lang.ClassCastException</code>
|
||||
dataflow.message.redundant.instanceof=Condition <code>#ref</code> #loc is redundant and can be replaced with <code>!= null</code>
|
||||
dataflow.message.constant.condition=Condition <code>#ref</code> #loc is always <code>{0}</code>
|
||||
dataflow.message.constant.condition.whenriched=Condition <code>#ref</code> #loc is always <code>{0}</code> when reached
|
||||
dataflow.message.constant.condition.when.reached=Condition <code>#ref</code> #loc is always <code>{0}</code> when reached
|
||||
dataflow.message.unreachable.switch.label=Switch label<code>#ref</code> #loc is unreachable
|
||||
dataflow.message.pointless.assignment.expression=Condition <code>#ref</code> #loc at the left side of assignment expression is always <code>{0}</code>. Can be simplified to normal assignment
|
||||
dataflow.message.passing.null.argument=Passing <code>null</code> argument to parameter annotated as @NotNull
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
<virtualFileSystem key="https" implementationClass="com.intellij.openapi.vfs.impl.http.HttpsFileSystem"/>
|
||||
|
||||
<toolWindow id="Event Log" anchor="bottom" secondary="true"
|
||||
icon="AllIcons.Ide.Notifications"
|
||||
icon="AllIcons.Ide.NoNotifications13"
|
||||
factoryClass="com.intellij.notification.EventLogToolWindowFactory"/>
|
||||
|
||||
<projectService serviceInterface="com.intellij.openapi.wm.impl.ProjectFrameBounds"
|
||||
|
||||
@@ -557,6 +557,7 @@ public class AllIcons {
|
||||
public static final Icon Recording_stop = IconLoader.getIcon("/ide/macro/recording_stop.png"); // 16x16
|
||||
|
||||
}
|
||||
public static final Icon NoNotifications13 = IconLoader.getIcon("/ide/noNotifications13.png"); // 13x13
|
||||
public static final Icon Notifications = IconLoader.getIcon("/ide/notifications.png"); // 16x16
|
||||
public static final Icon Pipette = IconLoader.getIcon("/ide/pipette.png"); // 18x18
|
||||
public static final Icon Pipette_rollover = IconLoader.getIcon("/ide/pipette_rollover.png"); // 18x18
|
||||
|
||||
@@ -469,6 +469,10 @@
|
||||
key="non.final.field.in.enum.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.class.structure" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.classlayout.NonFinalFieldInEnumInspection"/>
|
||||
<localInspection language="JAVA" shortName="NonFinalUtilityClass" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="non.final.utility.class.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.class.structure" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.classlayout.NonFinalUtilityClassInspection"/>
|
||||
<localInspection language="JAVA" shortName="NoopMethodInAbstractClass" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="noop.method.in.abstract.class.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.class.structure" enabledByDefault="false" level="WARNING"
|
||||
|
||||
@@ -1932,6 +1932,7 @@ simplifiable.equals.expression.display.name=Unnecessary 'null' check before 'equ
|
||||
simplifiable.equals.expression.problem.descriptor=Unnecessary ''null'' check before ''{0}()'' call #loc
|
||||
simplifiable.equals.expression.quickfix=Flip ''.{0}()'' and remove unnecessary ''null'' check
|
||||
cast.to.concrete.class.option=Ignore casts to an abstract class type
|
||||
cast.to.concrete.class.ignore.equals.option=Ignore in equals()
|
||||
instanceof.interfaces.option=Ignore instanceof abstract class
|
||||
instance.variable.of.concrete.class.option=Ignore instance fields whose type is an abstract class
|
||||
local.variable.of.concrete.class.option=Ignore local variables whose type is an abstract class
|
||||
@@ -1994,3 +1995,6 @@ none=none
|
||||
private=private
|
||||
package.local.private=package local & private
|
||||
protected.package.local.private=protected, package local & private
|
||||
non.final.utility.class.display.name=Utility class is not final
|
||||
non.final.utility.class.problem.descriptor=Utility class <code>#ref</code> is not final
|
||||
0.will.no.longer.be.overridable.by.1={0} will no longer be overridable by {1}
|
||||
|
||||
+55
-34
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,43 +15,45 @@
|
||||
*/
|
||||
package com.siyeh.ig.abstraction;
|
||||
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.MethodUtils;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.*;
|
||||
|
||||
public class CastToConcreteClassInspection extends BaseInspection {
|
||||
|
||||
@SuppressWarnings("PublicField")
|
||||
public boolean ignoreAbstractClasses = false;
|
||||
|
||||
@SuppressWarnings("PublicField")
|
||||
public boolean ignoreInEquals = true;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"cast.to.concrete.class.display.name");
|
||||
return InspectionGadgetsBundle.message("cast.to.concrete.class.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
final PsiElement typeElement = (PsiElement)infos[0];
|
||||
return InspectionGadgetsBundle.message(
|
||||
"cast.to.concrete.class.problem.descriptor",
|
||||
typeElement.getText());
|
||||
final PsiType type= (PsiType)infos[0];
|
||||
return InspectionGadgetsBundle.message("cast.to.concrete.class.problem.descriptor", type.getPresentableText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel(
|
||||
InspectionGadgetsBundle.message(
|
||||
"cast.to.concrete.class.option"),
|
||||
this, "ignoreAbstractClasses");
|
||||
final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this);
|
||||
panel.addCheckbox(InspectionGadgetsBundle.message("cast.to.concrete.class.option"), "ignoreAbstractClasses");
|
||||
panel.addCheckbox(InspectionGadgetsBundle.message("cast.to.concrete.class.ignore.equals.option"), "ignoreInEquals");
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,49 +61,68 @@ public class CastToConcreteClassInspection extends BaseInspection {
|
||||
return new CastToConcreteClassVisitor();
|
||||
}
|
||||
|
||||
private class CastToConcreteClassVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
private class CastToConcreteClassVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitTypeCastExpression(
|
||||
@NotNull PsiTypeCastExpression expression) {
|
||||
public void visitTypeCastExpression(@NotNull PsiTypeCastExpression expression) {
|
||||
super.visitTypeCastExpression(expression);
|
||||
final PsiTypeElement typeElement = expression.getCastType();
|
||||
if (typeElement == null) {
|
||||
return;
|
||||
}
|
||||
if (!ConcreteClassUtil.typeIsConcreteClass(typeElement,
|
||||
ignoreAbstractClasses)) {
|
||||
if (!ConcreteClassUtil.typeIsConcreteClass(typeElement, ignoreAbstractClasses)) {
|
||||
return;
|
||||
}
|
||||
registerError(typeElement, typeElement);
|
||||
if (ignoreInEquals) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, true, PsiClass.class);
|
||||
if (MethodUtils.isEquals(method)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registerError(typeElement, typeElement.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(
|
||||
PsiMethodCallExpression expression) {
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
super.visitMethodCallExpression(expression);
|
||||
final PsiReferenceExpression methodExpression =
|
||||
expression.getMethodExpression();
|
||||
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
|
||||
@NonNls
|
||||
final String referenceName = methodExpression.getReferenceName();
|
||||
if (!"cast".equals(referenceName)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression qualifier =
|
||||
methodExpression.getQualifierExpression();
|
||||
if (!(qualifier instanceof PsiClassObjectAccessExpression)) {
|
||||
final PsiExpression qualifier = methodExpression.getQualifierExpression();
|
||||
if (qualifier == null) {
|
||||
return;
|
||||
}
|
||||
final PsiClassObjectAccessExpression classObjectAccessExpression =
|
||||
(PsiClassObjectAccessExpression)qualifier;
|
||||
final PsiTypeElement operand =
|
||||
classObjectAccessExpression.getOperand();
|
||||
if (!ConcreteClassUtil.typeIsConcreteClass(operand,
|
||||
ignoreAbstractClasses)) {
|
||||
final PsiType type = qualifier.getType();
|
||||
if (!(type instanceof PsiClassType)) {
|
||||
return;
|
||||
}
|
||||
registerMethodCallError(expression, operand);
|
||||
final PsiClassType classType = (PsiClassType)type;
|
||||
final PsiClass aClass = classType.resolve();
|
||||
if (aClass == null) {
|
||||
return;
|
||||
}
|
||||
final String className = aClass.getQualifiedName();
|
||||
if (!CommonClassNames.JAVA_LANG_CLASS.equals(className)) {
|
||||
return;
|
||||
}
|
||||
final PsiType[] parameters = classType.getParameters();
|
||||
if (parameters.length != 1) {
|
||||
return;
|
||||
}
|
||||
final PsiType parameter = parameters[0];
|
||||
if (!ConcreteClassUtil.typeIsConcreteClass(parameter, ignoreAbstractClasses)) {
|
||||
return;
|
||||
}
|
||||
if (ignoreInEquals) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, true, PsiClass.class);
|
||||
if (MethodUtils.isEquals(method)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registerMethodCallError(expression, parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,30 +21,33 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class ConcreteClassUtil {
|
||||
|
||||
private ConcreteClassUtil() {
|
||||
}
|
||||
private ConcreteClassUtil() {}
|
||||
|
||||
public static boolean typeIsConcreteClass(
|
||||
@Nullable PsiTypeElement typeElement,
|
||||
boolean ignoreCastToAbstractClass) {
|
||||
public static boolean typeIsConcreteClass(@Nullable PsiTypeElement typeElement, boolean ignoreCastToAbstractClass) {
|
||||
if (typeElement == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiType type = typeElement.getType();
|
||||
return typeIsConcreteClass(type, ignoreCastToAbstractClass);
|
||||
}
|
||||
|
||||
public static boolean typeIsConcreteClass(@Nullable PsiType type, boolean ignoreCastToAbstractClass) {
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiType baseType = type.getDeepComponentType();
|
||||
if (!(baseType instanceof PsiClassType)) {
|
||||
return false;
|
||||
}
|
||||
final PsiClass aClass = ((PsiClassType)baseType).resolve();
|
||||
final PsiClassType classType = (PsiClassType)baseType;
|
||||
final PsiClass aClass = classType.resolve();
|
||||
if (aClass == null) {
|
||||
return false;
|
||||
}
|
||||
if (ignoreCastToAbstractClass &&
|
||||
aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
if (ignoreCastToAbstractClass && aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
return false;
|
||||
}
|
||||
if (aClass.isInterface() || aClass.isEnum() ||
|
||||
aClass.isAnnotationType()) {
|
||||
if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType()) {
|
||||
return false;
|
||||
}
|
||||
if (aClass instanceof PsiTypeParameter) {
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.fixes.MakeClassFinalFix;
|
||||
import com.siyeh.ig.psiutils.UtilityClassUtil;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class NonFinalUtilityClassInspection extends BaseInspection {
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message("non.final.utility.class.display.name");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("non.final.utility.class.problem.descriptor");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new MakeClassFinalFix((PsiClass)infos[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new NonFinalUtilityClassVisitor();
|
||||
}
|
||||
|
||||
private static class NonFinalUtilityClassVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
// no call to super, so that it doesn't drill down to inner classes
|
||||
if (!UtilityClassUtil.isUtilityClass(aClass)) {
|
||||
return;
|
||||
}
|
||||
if (aClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass, aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.siyeh.ig.fixes;
|
||||
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiModifier;
|
||||
import com.intellij.psi.PsiModifierList;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.ui.ConflictsDialog;
|
||||
import com.intellij.refactoring.util.RefactoringUIUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.Query;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class MakeClassFinalFix extends InspectionGadgetsFix {
|
||||
|
||||
private final String className;
|
||||
|
||||
public MakeClassFinalFix(PsiClass aClass) {
|
||||
className = aClass.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"make.class.final.fix.name", className);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
final PsiClass containingClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
|
||||
if (containingClass == null) {
|
||||
return;
|
||||
}
|
||||
final PsiModifierList modifierList = containingClass.getModifierList();
|
||||
if (modifierList == null) {
|
||||
return;
|
||||
}
|
||||
if (!isOnTheFly()) {
|
||||
if (ClassInheritorsSearch.search(containingClass).findFirst() != null) {
|
||||
return;
|
||||
}
|
||||
modifierList.setModifierProperty(PsiModifier.FINAL, true);
|
||||
return;
|
||||
}
|
||||
final MultiMap<PsiElement, String> conflicts = new MultiMap();
|
||||
final Query<PsiClass> search = ClassInheritorsSearch.search(containingClass);
|
||||
search.forEach(new Processor<PsiClass>() {
|
||||
@Override
|
||||
public boolean process(PsiClass aClass) {
|
||||
conflicts.putValue(containingClass, InspectionGadgetsBundle
|
||||
.message("0.will.no.longer.be.overridable.by.1", RefactoringUIUtil.getDescription(containingClass, false),
|
||||
RefactoringUIUtil.getDescription(aClass, false)));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
final boolean conflictsDialogOK;
|
||||
if (!conflicts.isEmpty()) {
|
||||
final ConflictsDialog conflictsDialog = new ConflictsDialog(element.getProject(), conflicts, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final AccessToken token = WriteAction.start();
|
||||
try {
|
||||
modifierList.setModifierProperty(PsiModifier.FINAL, true);
|
||||
}
|
||||
finally {
|
||||
token.finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
conflictsDialog.show();
|
||||
conflictsDialogOK = conflictsDialog.isOK();
|
||||
} else {
|
||||
conflictsDialogOK = true;
|
||||
}
|
||||
if (conflictsDialogOK) {
|
||||
modifierList.setModifierProperty(PsiModifier.FINAL, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
-83
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2008 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,82 +25,44 @@ import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.fixes.MakeClassFinalFix;
|
||||
import com.siyeh.ig.psiutils.ClassUtils;
|
||||
import com.siyeh.ig.psiutils.CloneUtils;
|
||||
import com.siyeh.ig.psiutils.MethodUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class OverridableMethodCallDuringObjectConstructionInspection
|
||||
extends BaseInspection {
|
||||
public class OverridableMethodCallDuringObjectConstructionInspection extends BaseInspection {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"overridable.method.call.in.constructor.display.name");
|
||||
return InspectionGadgetsBundle.message("overridable.method.call.in.constructor.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"overridable.method.call.in.constructor.problem.descriptor");
|
||||
return InspectionGadgetsBundle.message("overridable.method.call.in.constructor.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected InspectionGadgetsFix[] buildFixes(Object... infos) {
|
||||
final PsiMethodCallExpression methodCallExpression =
|
||||
(PsiMethodCallExpression)infos[0];
|
||||
final PsiClass callClass =
|
||||
ClassUtils.getContainingClass(methodCallExpression);
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)infos[0];
|
||||
final PsiClass callClass = ClassUtils.getContainingClass(methodCallExpression);
|
||||
final PsiMethod method = methodCallExpression.resolveMethod();
|
||||
if (method == null) {
|
||||
return InspectionGadgetsFix.EMPTY_ARRAY;
|
||||
}
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
if (!containingClass.equals(callClass) ||
|
||||
MethodUtils.isOverridden(method)) {
|
||||
if (containingClass == null || !containingClass.equals(callClass) || MethodUtils.isOverridden(method)) {
|
||||
return InspectionGadgetsFix.EMPTY_ARRAY;
|
||||
}
|
||||
final String methodName = method.getName();
|
||||
if (!ClassUtils.isOverridden(containingClass)) {
|
||||
return new InspectionGadgetsFix[]{
|
||||
new MakeClassFinalFix(containingClass),
|
||||
new MakeMethodFinalFix(methodName)};
|
||||
}
|
||||
else {
|
||||
return new InspectionGadgetsFix[]{
|
||||
new MakeMethodFinalFix(methodName)};
|
||||
}
|
||||
}
|
||||
|
||||
private static class MakeClassFinalFix extends InspectionGadgetsFix {
|
||||
|
||||
private final String className;
|
||||
|
||||
MakeClassFinalFix(PsiClass aClass) {
|
||||
className = aClass.getName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"make.class.final.fix.name", className);
|
||||
}
|
||||
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor)
|
||||
throws IncorrectOperationException {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
final PsiClass containingClass =
|
||||
PsiTreeUtil.getParentOfType(element, PsiClass.class);
|
||||
if (containingClass == null) {
|
||||
return;
|
||||
}
|
||||
final PsiModifierList modifierList =
|
||||
containingClass.getModifierList();
|
||||
if (modifierList == null) {
|
||||
return;
|
||||
}
|
||||
modifierList.setModifierProperty(PsiModifier.FINAL, true);
|
||||
}
|
||||
return new InspectionGadgetsFix[]{
|
||||
new MakeClassFinalFix(containingClass),
|
||||
new MakeMethodFinalFix(methodName)
|
||||
};
|
||||
}
|
||||
|
||||
private static class MakeMethodFinalFix extends InspectionGadgetsFix {
|
||||
@@ -111,42 +73,40 @@ public class OverridableMethodCallDuringObjectConstructionInspection
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"make.method.final.fix.name", methodName);
|
||||
}
|
||||
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor)
|
||||
throws IncorrectOperationException {
|
||||
@Override
|
||||
protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
|
||||
final PsiElement methodName = descriptor.getPsiElement();
|
||||
final PsiElement methodExpression = methodName.getParent();
|
||||
final PsiMethodCallExpression methodCall =
|
||||
(PsiMethodCallExpression)methodExpression.getParent();
|
||||
final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)methodExpression.getParent();
|
||||
final PsiMethod method = methodCall.resolveMethod();
|
||||
assert method != null;
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
final PsiModifierList modifierList = method.getModifierList();
|
||||
modifierList.setModifierProperty(PsiModifier.FINAL, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new OverridableMethodCallInConstructorVisitor();
|
||||
}
|
||||
|
||||
private static class OverridableMethodCallInConstructorVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
private static class OverridableMethodCallInConstructorVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(
|
||||
@NotNull PsiMethodCallExpression call) {
|
||||
public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) {
|
||||
super.visitMethodCallExpression(call);
|
||||
final PsiMember member =
|
||||
PsiTreeUtil.getParentOfType(call, PsiMethod.class,
|
||||
PsiClassInitializer.class);
|
||||
final PsiMember member = PsiTreeUtil.getParentOfType(call, PsiMethod.class, PsiClassInitializer.class);
|
||||
if (member instanceof PsiClassInitializer) {
|
||||
final PsiClassInitializer classInitializer =
|
||||
(PsiClassInitializer)member;
|
||||
final PsiClassInitializer classInitializer = (PsiClassInitializer)member;
|
||||
if (classInitializer.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
return;
|
||||
}
|
||||
@@ -160,13 +120,10 @@ public class OverridableMethodCallDuringObjectConstructionInspection
|
||||
else {
|
||||
return;
|
||||
}
|
||||
final PsiReferenceExpression methodExpression =
|
||||
call.getMethodExpression();
|
||||
final PsiExpression qualifier =
|
||||
methodExpression.getQualifierExpression();
|
||||
final PsiReferenceExpression methodExpression = call.getMethodExpression();
|
||||
final PsiExpression qualifier = methodExpression.getQualifierExpression();
|
||||
if (qualifier != null) {
|
||||
if (!(qualifier instanceof PsiThisExpression
|
||||
|| qualifier instanceof PsiSuperExpression)) {
|
||||
if (!(qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -177,15 +134,12 @@ public class OverridableMethodCallDuringObjectConstructionInspection
|
||||
if (containingClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
return;
|
||||
}
|
||||
final PsiMethod calledMethod =
|
||||
(PsiMethod)methodExpression.resolve();
|
||||
final PsiMethod calledMethod = (PsiMethod)methodExpression.resolve();
|
||||
if (calledMethod == null || !PsiUtil.canBeOverriden(calledMethod)) {
|
||||
return;
|
||||
}
|
||||
final PsiClass calledMethodClass =
|
||||
calledMethod.getContainingClass();
|
||||
if (calledMethodClass == null ||
|
||||
!calledMethodClass.equals(containingClass)) {
|
||||
final PsiClass calledMethodClass = calledMethod.getContainingClass();
|
||||
if (calledMethodClass == null || !calledMethodClass.equals(containingClass)) {
|
||||
return;
|
||||
}
|
||||
registerMethodCallError(call, call);
|
||||
@@ -198,12 +152,10 @@ public class OverridableMethodCallDuringObjectConstructionInspection
|
||||
if (CloneUtils.isClone(method)) {
|
||||
return true;
|
||||
}
|
||||
if (MethodUtils.simpleMethodMatches(method, null, "void",
|
||||
"readObject", "java.io.ObjectInputStream")) {
|
||||
if (MethodUtils.simpleMethodMatches(method, null, "void", "readObject", "java.io.ObjectInputStream")) {
|
||||
return true;
|
||||
}
|
||||
return MethodUtils.simpleMethodMatches(method, null, "void",
|
||||
"readObjectNoData");
|
||||
return MethodUtils.simpleMethodMatches(method, null, "void", "readObjectNoData");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,8 @@
|
||||
package com.siyeh.ig.psiutils;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.Query;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -223,10 +221,4 @@ public class ClassUtils {
|
||||
return inSamePackage(baseClass, referencedClass);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isOverridden(PsiClass aClass) {
|
||||
final Query<PsiClass> query = ClassInheritorsSearch.search(aClass);
|
||||
final PsiClass result = query.findFirst();
|
||||
return result != null;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,9 @@ Such declarations may represent a failure of abstraction, and may make testing m
|
||||
Declarations whose classes come from system or third-party libraries will not be reported by this inspection.
|
||||
<!-- tooltip end -->
|
||||
<p>
|
||||
Use the checkbox below to have this inspection ignore casts to abstract classes.
|
||||
Use the first checkbox below to have this inspection ignore casts to abstract classes.
|
||||
<p>
|
||||
Use the second checkbox below to have this inspection ignore casts inside <code>equals()</code> methods.
|
||||
<p>
|
||||
<small>Powered by InspectionGadgets</small>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports utility classes which are not final.
|
||||
Utility classes have all fields and methods declared <b>static</b>. Giving such classes making them <b>final</b>
|
||||
prevents them from being inadvertently subclassed.
|
||||
<!-- tooltip end -->
|
||||
<p>
|
||||
<small>New in 12, Powered by InspectionGadgets</small>
|
||||
</body>
|
||||
</html>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.siyeh.igtest.abstraction.cast_to_concrete_class;
|
||||
|
||||
class CastToConcreteClass {
|
||||
|
||||
private String field;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
try {
|
||||
CastToConcreteClass c = (CastToConcreteClass)obj;
|
||||
return c.field.equals(field);
|
||||
} catch (ClassCastException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void foo(Object o) {
|
||||
CastToConcreteClass c = (CastToConcreteClass)o;
|
||||
CastToConcreteClass c2 = CastToConcreteClass.class.cast(o);
|
||||
final Class<CastToConcreteClass> aClass = CastToConcreteClass.class;
|
||||
final CastToConcreteClass c3 = aClass.cast(o);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>CastToConcreteClass.java</file>
|
||||
<line>18</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cast to a concrete class</problem_class>
|
||||
<description>Cast to concrete class <code>CastToConcreteClass</code> #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>CastToConcreteClass.java</file>
|
||||
<line>19</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cast to a concrete class</problem_class>
|
||||
<description>Cast to concrete class <code>CastToConcreteClass</code> #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>CastToConcreteClass.java</file>
|
||||
<line>21</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cast to a concrete class</problem_class>
|
||||
<description>Cast to concrete class <code>CastToConcreteClass</code> #loc</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.siyeh.igtest.classlayout.non_final_utility_class;
|
||||
|
||||
|
||||
class NonFinalUtilityClass {
|
||||
|
||||
public static void foo() {}
|
||||
}
|
||||
final class FinalUtilityClass {
|
||||
public static void foo() {}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>NonFinalUtilityClass.java</file>
|
||||
<line>4</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Utility class is not final</problem_class>
|
||||
<description>Utility class <code>NonFinalUtilityClass</code> is not final</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.siyeh.ig.abstraction;
|
||||
|
||||
import com.siyeh.ig.IGInspectionTestCase;
|
||||
|
||||
public class CastToConcreteClassInspectionTest extends IGInspectionTestCase {
|
||||
|
||||
public void test() throws Exception {
|
||||
final CastToConcreteClassInspection tool = new CastToConcreteClassInspection();
|
||||
tool.ignoreInEquals = true;
|
||||
doTest("com/siyeh/igtest/abstraction/cast_to_concrete_class", tool);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.siyeh.ig.classlayout;
|
||||
|
||||
import com.siyeh.ig.IGInspectionTestCase;
|
||||
|
||||
public class NonFinalUtilityClassInspectionTest extends IGInspectionTestCase {
|
||||
|
||||
public void test() throws Exception {
|
||||
doTest("com/siyeh/igtest/classlayout/non_final_utility_class", new NonFinalUtilityClassInspection());
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -173,7 +173,10 @@ public class ReplaceLambdaWithAnonymousIntention extends Intention {
|
||||
if (disabled[0]) return false;
|
||||
}
|
||||
final PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType();
|
||||
return functionalInterfaceType != null && LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) != null && LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType);
|
||||
return functionalInterfaceType != null &&
|
||||
LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) != null &&
|
||||
LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType) &&
|
||||
LambdaUtil.checkInterfaceFunctional(functionalInterfaceType) == null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
package com.intellij.tasks.actions;
|
||||
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.popup.*;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList;
|
||||
@@ -52,11 +54,11 @@ public class SwitchTaskAction extends BaseTaskAction {
|
||||
DataContext dataContext = e.getDataContext();
|
||||
final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
|
||||
assert project != null;
|
||||
final ListPopupImpl popup = createPopup(dataContext, true);
|
||||
final ListPopupImpl popup = createPopup(dataContext, null, true);
|
||||
popup.showCenteredInCurrentWindow(project);
|
||||
}
|
||||
|
||||
public static ListPopupImpl createPopup(final DataContext dataContext, boolean withTitle) {
|
||||
public static ListPopupImpl createPopup(final DataContext dataContext, @Nullable final Runnable onDispose, boolean withTitle) {
|
||||
final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
|
||||
final Ref<Boolean> shiftPressed = Ref.create(false);
|
||||
final Ref<JComponent> componentRef = Ref.create();
|
||||
@@ -98,6 +100,14 @@ public class SwitchTaskAction extends BaseTaskAction {
|
||||
};
|
||||
|
||||
final ListPopupImpl popup = (ListPopupImpl)JBPopupFactory.getInstance().createListPopup(step);
|
||||
if (onDispose != null) {
|
||||
Disposer.register(popup, new Disposable() {
|
||||
@Override
|
||||
public void dispose() {
|
||||
onDispose.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
componentRef.set(popup.getComponent());
|
||||
if (items.size() <= 2) {
|
||||
return popup;
|
||||
|
||||
@@ -66,7 +66,7 @@ public class SwitchTaskCombo extends ComboBoxAction implements DumbAware {
|
||||
|
||||
@Override
|
||||
protected JBPopup createPopup(Runnable onDispose) {
|
||||
return SwitchTaskAction.createPopup(DataManager.getInstance().getDataContext(this), false);
|
||||
return SwitchTaskAction.createPopup(DataManager.getInstance().getDataContext(this), onDispose, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user