diff options
author | Tor Norbye <tnorbye@google.com> | 2013-04-03 16:27:26 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2013-04-03 16:27:26 -0700 |
commit | d1a59a0799588a226d255d9b45c4825b19651554 (patch) | |
tree | c9759b94ddad742db08b6662f52a62e0401491c1 /java/java-impl/src/com/intellij | |
parent | 2bd2b7c2623d4266384e890271869efc044aabff (diff) | |
download | idea-d1a59a0799588a226d255d9b45c4825b19651554.tar.gz |
Snapshot dc7fe9a777db5bc87a5b1ad4bfe40a547fc7d49a from master branch of git://git.jetbrains.org/idea/community.git
Change-Id: Iae1c655b8958fc7603a78c675e4a4b942a1fccd4
Diffstat (limited to 'java/java-impl/src/com/intellij')
8 files changed, 198 insertions, 23 deletions
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java index 98b582f73545..69398342cff4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/AnnotationsHighlightUtil.java @@ -30,6 +30,7 @@ import com.intellij.patterns.ElementPattern; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.PsiClassReferenceType; +import com.intellij.psi.impl.source.PsiImmediateClassType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; @@ -38,6 +39,7 @@ import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -172,10 +174,38 @@ public class AnnotationsHighlightUtil { PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); if (nameRef == null) continue; PsiElement aClass = nameRef.resolve(); - if (resolved.equals(aClass)) { + if (!resolved.equals(aClass)) continue; + + if (!PsiUtil.isLanguageLevel8OrHigher(annotationToCheck)) { String description = JavaErrorMessages.message("annotation.duplicate.annotation"); return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); } + + PsiClass annotationType = (PsiClass)resolved; + PsiAnnotation metaAnno = PsiImplUtil.findAnnotation(annotationType.getModifierList(), CommonClassNames.JAVA_LANG_ANNOTATION_REPEATABLE); + if (metaAnno == null) { + String explanation = JavaErrorMessages.message("annotation.non.repeatable", annotationType.getQualifiedName()); + String description = JavaErrorMessages.message("annotation.duplicate.explained", explanation); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); + } + + String explanation = doCheckRepeatableAnnotation(metaAnno); + if (explanation != null) { + String description = JavaErrorMessages.message("annotation.duplicate.explained", explanation); + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create(); + } + + PsiClass collector = getRepeatableCollector(metaAnno); + if (collector != null) { + String collectorName = collector.getQualifiedName(); + if (collectorName != null) { + PsiAnnotation collectorAnno = owner.findAnnotation(collectorName); + if (collectorAnno != null) { + String description = JavaErrorMessages.message("annotation.collector.wrong.place", collectorName); + return annotationError(collectorAnno, description); + } + } + } } return null; @@ -458,9 +488,11 @@ public class AnnotationsHighlightUtil { public static HighlightInfo checkTargetAnnotationDuplicates(PsiAnnotation annotation) { PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); if (nameRef == null) return null; + PsiElement resolved = nameRef.resolve(); - if (!(resolved instanceof PsiClass) || - !CommonClassNames.TARGET_ANNOTATION_FQ_NAME.equals(((PsiClass) resolved).getQualifiedName())) return null; + if (!(resolved instanceof PsiClass) || !CommonClassNames.JAVA_LANG_ANNOTATION_TARGET.equals(((PsiClass)resolved).getQualifiedName())) { + return null; + } PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes(); if (attributes.length < 1) return null; @@ -483,6 +515,7 @@ public class AnnotationsHighlightUtil { return null; } + @Nullable public static HighlightInfo checkFunctionalInterface(PsiAnnotation annotation) { final String errorMessage = LambdaUtil.checkFunctionalInterface(annotation); if (errorMessage != null) { @@ -491,6 +524,90 @@ public class AnnotationsHighlightUtil { return null; } + @Nullable + public static HighlightInfo checkRepeatableAnnotation(PsiAnnotation annotation) { + String qualifiedName = annotation.getQualifiedName(); + if (!CommonClassNames.JAVA_LANG_ANNOTATION_REPEATABLE.equals(qualifiedName)) return null; + + String description = doCheckRepeatableAnnotation(annotation); + if (description != null) { + PsiAnnotationMemberValue collectorRef = PsiImplUtil.findAttributeValue(annotation, null); + if (collectorRef != null) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(collectorRef).descriptionAndTooltip(description).create(); + } + } + + return null; + } + + @Nullable + private static String doCheckRepeatableAnnotation(PsiAnnotation annotation) { + PsiAnnotationOwner owner = annotation.getOwner(); + if (!(owner instanceof PsiModifierList)) return null; + PsiElement target = ((PsiModifierList)owner).getParent(); + if (!(target instanceof PsiClass) || !((PsiClass)target).isAnnotationType()) return null; + PsiClass collector = getRepeatableCollector(annotation); + if (collector == null) return null; + + PsiMethod[] methods = collector.findMethodsByName("value", false); + if (methods.length == 0) { + return JavaErrorMessages.message("annotation.container.no.value", collector.getQualifiedName()); + } + + if (methods.length == 1) { + PsiType expected = new PsiImmediateClassType((PsiClass)target, PsiSubstitutor.EMPTY).createArrayType(); + if (!expected.equals(methods[0].getReturnType())) { + return JavaErrorMessages.message("annotation.container.bad.type", collector.getQualifiedName(), HighlightUtil.formatType(expected)); + } + } + + RetentionPolicy targetPolicy = getRetentionPolicy((PsiClass)target); + if (targetPolicy != null) { + RetentionPolicy collectorPolicy = getRetentionPolicy(collector); + if (collectorPolicy != null && targetPolicy.compareTo(collectorPolicy) > 0) { + return JavaErrorMessages.message("annotation.container.low.retention", collector.getQualifiedName(), collectorPolicy); + } + } + + return null; + } + + @Nullable + private static PsiClass getRepeatableCollector(PsiAnnotation annotation) { + PsiAnnotationMemberValue collectorRef = PsiImplUtil.findAttributeValue(annotation, null); + if (!(collectorRef instanceof PsiClassObjectAccessExpression)) return null; + PsiType collectorType = ((PsiClassObjectAccessExpression)collectorRef).getOperand().getType(); + if (!(collectorType instanceof PsiClassType)) return null; + PsiClass collector = ((PsiClassType)collectorType).resolve(); + if (collector == null || !collector.isAnnotationType()) return null; + return collector; + } + + @Nullable + private static RetentionPolicy getRetentionPolicy(PsiClass annotation) { + PsiModifierList modifierList = annotation.getModifierList(); + if (modifierList != null) { + PsiAnnotation retentionAnno = modifierList.findAnnotation(CommonClassNames.JAVA_LANG_ANNOTATION_RETENTION); + if (retentionAnno == null) return RetentionPolicy.CLASS; + + PsiAnnotationMemberValue policyRef = PsiImplUtil.findAttributeValue(retentionAnno, null); + if (policyRef instanceof PsiReference) { + PsiElement field = ((PsiReference)policyRef).resolve(); + if (field instanceof PsiEnumConstant) { + String name = ((PsiEnumConstant)field).getName(); + try { + return RetentionPolicy.valueOf(name); + } + catch (Exception e) { + LOG.warn("Unknown policy: " + name); + } + } + } + } + + return null; + } + public static class AnnotationReturnTypeVisitor extends PsiTypeVisitor<Boolean> { public static final AnnotationReturnTypeVisitor INSTANCE = new AnnotationReturnTypeVisitor(); @Override @@ -514,15 +631,15 @@ public class AnnotationsHighlightUtil { public Boolean visitClassType(PsiClassType classType) { if (classType.getParameters().length > 0) { PsiClassType rawType = classType.rawType(); - if (rawType.equalsToText("java.lang.Class")) { - return Boolean.TRUE; - } - return Boolean.FALSE; + return rawType.equalsToText(CommonClassNames.JAVA_LANG_CLASS); } + PsiClass aClass = classType.resolve(); - if (aClass != null && (aClass.isAnnotationType() || aClass.isEnum())) return Boolean.TRUE; + if (aClass != null && (aClass.isAnnotationType() || aClass.isEnum())) { + return Boolean.TRUE; + } - return classType.equalsToText("java.lang.Class") || classType.equalsToText("java.lang.String") ? Boolean.TRUE : Boolean.FALSE; + return classType.equalsToText(CommonClassNames.JAVA_LANG_CLASS) || classType.equalsToText(CommonClassNames.JAVA_LANG_STRING); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 3b6ef960f407..9e6f8a85cedb 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -183,6 +183,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkForeignInnerClassesUsed(annotation)); if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkFunctionalInterface(annotation)); + if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkRepeatableAnnotation(annotation)); } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java index dfc477ac173d..79c7dd9ecca0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java @@ -311,7 +311,6 @@ public class SimplifyBooleanExpressionFix implements IntentionAction { } catch (IncorrectOperationException e) { resultExpression = null; - LOG.error("lExpr: " + lExpr.getText() + "; op: " + javaToken.getText() + "; rExpr: " + operand.getText() + "; top: " + expression.getText()); } } else { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java index 98d8894c7034..f12fe42d4824 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -477,7 +477,7 @@ public class GenerateMembersUtil { else { JVMElementFactory factory = JVMElementFactories.requireFactory(targetParam.getLanguage(), targetParam.getProject()); for (PsiAnnotation annotation : sourceModifierList.getAnnotations()) { - targetModifierList.add(factory.createAnnotationFromText(annotation.getText(), targetParam)); + targetModifierList.add(factory.createAnnotationFromText(annotation.getText(), sourceParam)); } for (@PsiModifier.ModifierConstant String m : PsiModifier.MODIFIERS) { targetModifierList.setModifierProperty(m, sourceParam.hasModifierProperty(m)); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldCentralPanel.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldCentralPanel.java index 68d5e99cc536..da5be799dace 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldCentralPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldCentralPanel.java @@ -15,15 +15,19 @@ */ package com.intellij.refactoring.introduceField; +import com.intellij.codeInsight.TestFrameworks; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.ui.TypeSelectorManager; import com.intellij.ui.NonFocusableCheckBox; import com.intellij.ui.StateRestoringCheckBox; +import com.intellij.util.Processor; import org.jetbrains.annotations.TestOnly; import javax.swing.*; @@ -93,7 +97,7 @@ public abstract class IntroduceFieldCentralPanel { refElement instanceof PsiParameter || (refElement instanceof PsiField && !((PsiField)refElement).hasInitializer())) && !PsiTreeUtil.isAncestor(initializer, refElement, true)) { - return updateInitializationPlaceModel(); + return updateInitializationPlaceModel(initializedInSetUp(refElement)); } } } @@ -104,6 +108,28 @@ public abstract class IntroduceFieldCentralPanel { return true; } + private boolean initializedInSetUp(PsiElement refElement) { + if (refElement instanceof PsiField && hasSetUpChoice()) { + final PsiMethod setUpMethod = TestFrameworks.getInstance().findSetUpMethod(((PsiField)refElement).getContainingClass()); + if (setUpMethod != null) { + final Processor<PsiReference> initializerSearcher = new Processor<PsiReference>() { + @Override + public boolean process(PsiReference reference) { + final PsiElement referenceElement = reference.getElement(); + if (referenceElement instanceof PsiExpression) { + return !PsiUtil.isAccessedForWriting((PsiExpression)referenceElement); + } + return true; + } + }; + if (!ReferencesSearch.search(refElement, new LocalSearchScope(setUpMethod)).forEach(initializerSearcher)) { + return true; + } + } + } + return false; + } + public abstract BaseExpressionToFieldHandler.InitializationPlace getInitializerPlace(); protected abstract void initializeInitializerPlace(PsiExpression initializerExpression, BaseExpressionToFieldHandler.InitializationPlace ourLastInitializerPlace); @@ -279,5 +305,7 @@ public abstract class IntroduceFieldCentralPanel { } } - protected abstract boolean updateInitializationPlaceModel(); + protected abstract boolean updateInitializationPlaceModel(boolean initializedInsetup); + + protected abstract boolean hasSetUpChoice(); } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialogPanel.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialogPanel.java index a184983897ba..ad5ccbc6fa18 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialogPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldDialogPanel.java @@ -195,14 +195,25 @@ public class IntroduceFieldDialogPanel extends IntroduceFieldCentralPanel { } @Override - protected boolean updateInitializationPlaceModel() { + protected boolean updateInitializationPlaceModel(boolean initializedInSetup) { myRbInFieldDeclaration.setEnabled(false); myRbInConstructor.setEnabled(false); - if (myRbInSetUp != null) myRbInSetUp.setEnabled(false); enableFinal(false); + if (myRbInSetUp != null){ + if (!initializedInSetup) { + myRbInSetUp.setEnabled(false); + } else { + return true; + } + } return false; } + @Override + protected boolean hasSetUpChoice() { + return myRbInSetUp != null; + } + public void setInitializeInFieldDeclaration() { myRbInFieldDeclaration.setSelected(true); } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPopupPanel.java b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPopupPanel.java index e0e26cbaf4dd..0583a16b5bdb 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPopupPanel.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceField/IntroduceFieldPopupPanel.java @@ -66,7 +66,7 @@ public class IntroduceFieldPopupPanel extends IntroduceFieldCentralPanel { } final PsiMethod setUpMethod = TestFrameworks.getInstance().findSetUpMethod(myParentClass); - final boolean setupEnabled = myInitialisersPlaceModel.getIndexOf(BaseExpressionToFieldHandler.InitializationPlace.IN_SETUP_METHOD) > -1; + final boolean setupEnabled = hasSetUpChoice(); if (ourLastInitializerPlace == BaseExpressionToFieldHandler.InitializationPlace.IN_SETUP_METHOD && setupEnabled && (myInitializerExpression != null && PsiTreeUtil.isAncestor(setUpMethod, myInitializerExpression, false) || TestFrameworks.getInstance().isTestClass(myParentClass))) { @@ -187,13 +187,22 @@ public class IntroduceFieldPopupPanel extends IntroduceFieldCentralPanel { } @Override - protected boolean updateInitializationPlaceModel() { + protected boolean updateInitializationPlaceModel(boolean initializedInSetup) { myInitialisersPlaceModel.removeElement(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION); myInitialisersPlaceModel.removeElement(BaseExpressionToFieldHandler.InitializationPlace.IN_CONSTRUCTOR); - myInitialisersPlaceModel.removeElement(BaseExpressionToFieldHandler.InitializationPlace.IN_SETUP_METHOD); + if (!initializedInSetup) { + myInitialisersPlaceModel.removeElement(BaseExpressionToFieldHandler.InitializationPlace.IN_SETUP_METHOD); + } else { + return true; + } return false; } + @Override + protected boolean hasSetUpChoice() { + return myInitialisersPlaceModel.getIndexOf(BaseExpressionToFieldHandler.InitializationPlace.IN_SETUP_METHOD) > -1; + } + public void setInitializeInFieldDeclaration() { LOG.assertTrue(myInitializerCombo != null); myInitializerCombo.setSelectedItem(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION); diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index 3423cca5bd30..b2aa15916b26 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -197,12 +197,22 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { PsiExpression expression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class); while (expression != null) { if (!expressions.contains(expression) && !(expression instanceof PsiParenthesizedExpression) && !(expression instanceof PsiSuperExpression) && expression.getType() != PsiType.VOID) { - if (expression instanceof PsiMethodReferenceExpression || - !(expression instanceof PsiReferenceExpression && - (expression.getParent() instanceof PsiMethodCallExpression || ((PsiReferenceExpression)expression).resolve() instanceof PsiClass)) && - !(expression instanceof PsiAssignmentExpression)) { + if (expression instanceof PsiMethodReferenceExpression) { expressions.add(expression); } + else if (!(expression instanceof PsiAssignmentExpression)) { + if (!(expression instanceof PsiReferenceExpression)) { + expressions.add(expression); + } + else { + if (!(expression.getParent() instanceof PsiMethodCallExpression)) { + final PsiElement resolve = ((PsiReferenceExpression)expression).resolve(); + if (!(resolve instanceof PsiClass) && !(resolve instanceof PsiPackage)) { + expressions.add(expression); + } + } + } + } } expression = PsiTreeUtil.getParentOfType(expression, PsiExpression.class); } |