diff options
author | Tor Norbye <tnorbye@google.com> | 2013-07-08 11:26:24 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2013-07-08 11:26:24 -0700 |
commit | c1ace1f7e1e49c81bb4b75377c99f07be340abfe (patch) | |
tree | 9d0db96bd3d86ddfec80e7e3554cad9dcc066553 /java/java-impl/src | |
parent | c6218e46d5d2017e987ecdbd99b318a95c42abc0 (diff) | |
download | idea-c1ace1f7e1e49c81bb4b75377c99f07be340abfe.tar.gz |
Snapshot aea001abfc1b38fec3a821bcd5174cc77dc75787 from master branch of git://git.jetbrains.org/idea/community.git
Change-Id: Icdea2a2bd7ad43b4d05967b1f0479db3bda1c93c
Diffstat (limited to 'java/java-impl/src')
110 files changed, 1985 insertions, 1903 deletions
diff --git a/java/java-impl/src/com/intellij/application/options/CodeStyleGenerationConfigurable.java b/java/java-impl/src/com/intellij/application/options/CodeStyleGenerationConfigurable.java index 44ccf4985b95..aebfb44da1ca 100644 --- a/java/java-impl/src/com/intellij/application/options/CodeStyleGenerationConfigurable.java +++ b/java/java-impl/src/com/intellij/application/options/CodeStyleGenerationConfigurable.java @@ -18,8 +18,10 @@ package com.intellij.application.options; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.ToolbarDecorator; @@ -230,18 +232,18 @@ public class CodeStyleGenerationConfigurable implements Configurable { reset(mySettings); } - public void apply(CodeStyleSettings settings) { + public void apply(CodeStyleSettings settings) throws ConfigurationException { settings.PREFER_LONGER_NAMES = myCbPreferLongerNames.isSelected(); - settings.FIELD_NAME_PREFIX = myFieldPrefixField.getText().trim(); - settings.STATIC_FIELD_NAME_PREFIX = myStaticFieldPrefixField.getText().trim(); - settings.PARAMETER_NAME_PREFIX = myParameterPrefixField.getText().trim(); - settings.LOCAL_VARIABLE_NAME_PREFIX = myLocalVariablePrefixField.getText().trim(); + settings.FIELD_NAME_PREFIX = setPrefixSuffix(myFieldPrefixField.getText(), true); + settings.STATIC_FIELD_NAME_PREFIX = setPrefixSuffix(myStaticFieldPrefixField.getText(), true); + settings.PARAMETER_NAME_PREFIX = setPrefixSuffix(myParameterPrefixField.getText(), true); + settings.LOCAL_VARIABLE_NAME_PREFIX = setPrefixSuffix(myLocalVariablePrefixField.getText(), true); - settings.FIELD_NAME_SUFFIX = myFieldSuffixField.getText().trim(); - settings.STATIC_FIELD_NAME_SUFFIX = myStaticFieldSuffixField.getText().trim(); - settings.PARAMETER_NAME_SUFFIX = myParameterSuffixField.getText().trim(); - settings.LOCAL_VARIABLE_NAME_SUFFIX = myLocalVariableSuffixField.getText().trim(); + settings.FIELD_NAME_SUFFIX = setPrefixSuffix(myFieldSuffixField.getText(), false); + settings.STATIC_FIELD_NAME_SUFFIX = setPrefixSuffix(myStaticFieldSuffixField.getText(), false); + settings.PARAMETER_NAME_SUFFIX = setPrefixSuffix(myParameterSuffixField.getText(), false); + settings.LOCAL_VARIABLE_NAME_SUFFIX = setPrefixSuffix(myLocalVariableSuffixField.getText(), false); settings.LINE_COMMENT_AT_FIRST_COLUMN = myCbLineCommentAtFirstColumn.isSelected(); settings.BLOCK_COMMENT_AT_FIRST_COLUMN = myCbBlockCommentAtFirstColumn.isSelected(); @@ -260,7 +262,16 @@ public class CodeStyleGenerationConfigurable implements Configurable { } } - public void apply() { + private static String setPrefixSuffix(String text, boolean prefix) throws ConfigurationException { + text = text.trim(); + if (text.isEmpty()) return text; + if (!StringUtil.isJavaIdentifier(text)) { + throw new ConfigurationException("Not a valid java identifier part in " + (prefix ? "prefix" : "suffix") + " \'" + text + "\'"); + } + return text; + } + + public void apply() throws ConfigurationException { apply(mySettings); } diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypeInfo.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypeInfo.java index 650a6b00bdd5..7fe0abca8018 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypeInfo.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypeInfo.java @@ -44,9 +44,5 @@ public interface ExpectedTypeInfo { ExpectedTypeInfo[] intersect(ExpectedTypeInfo info); - boolean isArrayTypeInfo(); - TailType getTailType(); - - boolean isInsertExplicitTypeParams(); } diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypeInfoImpl.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypeInfoImpl.java index 0751887a2409..619b6477388b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypeInfoImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypeInfoImpl.java @@ -28,13 +28,6 @@ public class ExpectedTypeInfoImpl implements ExpectedTypeInfo { private final PsiType type; private final PsiType defaultType; - private boolean myInsertExplicitTypeParams; - - int getDimCount() { - return dimCount; - } - - private final int dimCount; @Override public int getKind() { @@ -59,29 +52,11 @@ public class ExpectedTypeInfoImpl implements ExpectedTypeInfo { private PsiMethod myCalledMethod; - public ExpectedTypeInfoImpl(@NotNull PsiType type, int kind, int dimCount, @NotNull PsiType defaultType, @NotNull TailType myTailType) { + public ExpectedTypeInfoImpl(@NotNull PsiType type, int kind, @NotNull PsiType defaultType, @NotNull TailType myTailType) { this.type = type; this.kind = kind; this.myTailType = myTailType; - this.dimCount = dimCount; - - if (type == defaultType && type instanceof PsiClassType) { - final PsiClassType psiClassType = (PsiClassType)type; - final PsiClass psiClass = psiClassType.resolve(); - if (psiClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) { - final PsiType[] parameters = psiClassType.getParameters(); - PsiTypeParameter[] typeParameters = psiClass.getTypeParameters(); - if (parameters.length == 1 && parameters[0] instanceof PsiWildcardType && typeParameters.length == 1) { - final PsiType bound = ((PsiWildcardType)parameters[0]).getExtendsBound(); - if (bound instanceof PsiClassType) { - defaultType = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory() - .createType(psiClass, PsiSubstitutor.EMPTY.put(typeParameters[0], bound)); - } - } - } - } - this.defaultType = defaultType; PsiUtil.ensureValidType(type); @@ -100,30 +75,13 @@ public class ExpectedTypeInfoImpl implements ExpectedTypeInfo { @Override @NotNull public PsiType getType () { - PsiType t = type; - int dims = dimCount; - - while (dims-- > 0) t = t.createArrayType(); - return t; + return type; } @Override @NotNull public PsiType getDefaultType () { - PsiType t = defaultType; - int dims = dimCount; - - while (dims-- > 0) t = t.createArrayType(); - return t; - } - - @Override - public boolean isInsertExplicitTypeParams() { - return myInsertExplicitTypeParams; - } - - public void setInsertExplicitTypeParams(final boolean insertExplicitTypeParams) { - this.myInsertExplicitTypeParams = insertExplicitTypeParams; + return defaultType; } public boolean equals(final Object o) { @@ -132,20 +90,18 @@ public class ExpectedTypeInfoImpl implements ExpectedTypeInfo { final ExpectedTypeInfoImpl that = (ExpectedTypeInfoImpl)o; - if (dimCount != that.dimCount) return false; if (kind != that.kind) return false; - if (defaultType != null ? !defaultType.equals(that.defaultType) : that.defaultType != null) return false; + if (!defaultType.equals(that.defaultType)) return false; if (myTailType != null ? !myTailType.equals(that.myTailType) : that.myTailType != null) return false; - if (type != null ? !type.equals(that.type) : that.type != null) return false; + if (!type.equals(that.type)) return false; return true; } public int hashCode() { int result; - result = (type != null ? type.hashCode() : 0); - result = 31 * result + (defaultType != null ? defaultType.hashCode() : 0); - result = 31 * result + dimCount; + result = (type.hashCode()); + result = 31 * result + (defaultType.hashCode()); result = 31 * result + kind; result = 31 * result + (myTailType != null ? myTailType.hashCode() : 0); return result; @@ -158,17 +114,15 @@ public class ExpectedTypeInfoImpl implements ExpectedTypeInfo { @SuppressWarnings({"HardCodedStringLiteral"}) public String toString() { - return "ExpectedTypeInfo[type='" + type + "' kind='" + kind + "' dims='" + dimCount+ "']"; + return "ExpectedTypeInfo[type='" + type + "' kind='" + kind + "']"; } @Override public ExpectedTypeInfo[] intersect(ExpectedTypeInfo info) { ExpectedTypeInfoImpl info1 = (ExpectedTypeInfoImpl)info; - LOG.assertTrue(!(type instanceof PsiArrayType) && !(info1.type instanceof PsiArrayType)); if (kind == TYPE_STRICTLY) { if (info1.kind == TYPE_STRICTLY) { - if (dimCount != info1.dimCount) return ExpectedTypeInfo.EMPTY_ARRAY; if (info1.type.equals(type)) return new ExpectedTypeInfoImpl[] {this}; } else { @@ -177,12 +131,10 @@ public class ExpectedTypeInfoImpl implements ExpectedTypeInfo { } else if (kind == TYPE_OR_SUBTYPE) { if (info1.kind == TYPE_STRICTLY) { - if (dimCount != info1.dimCount) return ExpectedTypeInfo.EMPTY_ARRAY; if (type.isAssignableFrom(info1.type)) return new ExpectedTypeInfoImpl[] {info1}; } else if (info1.kind == TYPE_OR_SUBTYPE) { - PsiType type = dimCount == info1.dimCount ? this.type : getType(); - PsiType otherType = dimCount == info1.dimCount ? info1.type : info1.getType(); + PsiType otherType = info1.type; if (type.isAssignableFrom(otherType)) return new ExpectedTypeInfoImpl[] {info1}; else if (otherType.isAssignableFrom(type)) return new ExpectedTypeInfoImpl[] {this}; } @@ -192,17 +144,14 @@ public class ExpectedTypeInfoImpl implements ExpectedTypeInfo { } else if (kind == TYPE_OR_SUPERTYPE) { if (info1.kind == TYPE_STRICTLY) { - if (dimCount != info1.dimCount) return ExpectedTypeInfo.EMPTY_ARRAY; if (info1.type.isAssignableFrom(type)) return new ExpectedTypeInfoImpl[] {info1}; } else if (info1.kind == TYPE_OR_SUBTYPE) { - PsiType type = dimCount == info1.dimCount ? this.type : getType(); - PsiType otherType = dimCount == info1.dimCount ? info1.type : info1.getType(); + PsiType otherType = info1.type; if (otherType.isAssignableFrom(type)) return new ExpectedTypeInfoImpl[] {this}; } else if (info1.kind == TYPE_OR_SUPERTYPE) { - PsiType type = dimCount == info1.dimCount ? this.type : getType(); - PsiType otherType = dimCount == info1.dimCount ? info1.type : info1.getType(); + PsiType otherType = info1.type; if (type.isAssignableFrom(otherType)) return new ExpectedTypeInfoImpl[] {this}; else if (otherType.isAssignableFrom(type)) return new ExpectedTypeInfoImpl[] {info1}; } @@ -216,10 +165,4 @@ public class ExpectedTypeInfoImpl implements ExpectedTypeInfo { return ExpectedTypeInfo.EMPTY_ARRAY; } - - @Override - public boolean isArrayTypeInfo () { - return dimCount > 0; - } - } diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java index ebc4714f3084..6a3d3f69df01 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java @@ -52,7 +52,7 @@ import java.util.*; * @author ven */ public class ExpectedTypesProvider { - private static final ExpectedTypeInfo VOID_EXPECTED = new ExpectedTypeInfoImpl(PsiType.VOID, ExpectedTypeInfo.TYPE_OR_SUBTYPE, 0, PsiType.VOID, + private static final ExpectedTypeInfo VOID_EXPECTED = new ExpectedTypeInfoImpl(PsiType.VOID, ExpectedTypeInfo.TYPE_OR_SUBTYPE, PsiType.VOID, TailType.SEMICOLON); private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.ExpectedTypesProvider"); @@ -91,13 +91,7 @@ public class ExpectedTypesProvider { @NotNull private static ExpectedTypeInfoImpl createInfoImpl(@NotNull PsiType type, int kind, PsiType defaultType, @NotNull TailType tailType) { - int dims = 0; - while (type instanceof PsiArrayType && defaultType instanceof PsiArrayType) { - type = ((PsiArrayType) type).getComponentType(); - defaultType = ((PsiArrayType) defaultType).getComponentType(); - dims++; - } - return new ExpectedTypeInfoImpl(type, kind, dims, defaultType, tailType); + return new ExpectedTypeInfoImpl(type, kind, defaultType, tailType); } @NotNull @@ -139,7 +133,7 @@ public class ExpectedTypesProvider { for (ExpectedTypeInfo info : infos) { ExpectedTypeInfoImpl infoImpl = (ExpectedTypeInfoImpl)info; - if (infoImpl.getDefaultType() instanceof PsiClassType && infoImpl.getDimCount() == 0) { + if (infoImpl.getDefaultType() instanceof PsiClassType) { JavaResolveResult result = ((PsiClassType)infoImpl.getDefaultType()).resolveGenerics(); PsiClass aClass = (PsiClass)result.getElement(); if (aClass instanceof PsiAnonymousClass) { @@ -155,10 +149,10 @@ public class ExpectedTypesProvider { } if (infoImpl.kind == ExpectedTypeInfo.TYPE_OR_SUPERTYPE) { - processAllSuperTypes(infoImpl.getType(), infoImpl.getDimCount(), visitor, project, set); + processAllSuperTypes(infoImpl.getType(), visitor, project, set); } else if (infoImpl.getKind() == ExpectedTypeInfo.TYPE_OR_SUBTYPE) { - if (infoImpl.getType() instanceof PsiPrimitiveType && infoImpl.getDimCount() == 0) { + if (infoImpl.getType() instanceof PsiPrimitiveType) { processPrimitiveTypeAndSubtypes((PsiPrimitiveType)infoImpl.getType(), visitor, set); } //else too expensive to search @@ -183,7 +177,7 @@ public class ExpectedTypesProvider { } } - public static void processAllSuperTypes(@NotNull PsiType type, int dimCount, @NotNull PsiTypeVisitor<PsiType> visitor, @NotNull Project project, @NotNull Set<PsiType> set) { + public static void processAllSuperTypes(@NotNull PsiType type, @NotNull PsiTypeVisitor<PsiType> visitor, @NotNull Project project, @NotNull Set<PsiType> set) { if (type instanceof PsiPrimitiveType) { if (type.equals(PsiType.BOOLEAN) || type.equals(PsiType.VOID) || type.equals(PsiType.NULL)) return; @@ -205,12 +199,8 @@ public class ExpectedTypesProvider { if (type instanceof PsiClassType) { PsiType[] superTypes = type.getSuperTypes(); for (PsiType superType : superTypes) { - PsiType wrappedType = superType; - for (int j = 0; j < dimCount; j++) { - wrappedType = wrappedType.createArrayType(); - } - processType(wrappedType, visitor, set); - processAllSuperTypes(superType, dimCount, visitor, project, set); + processType(superType, visitor, set); + processAllSuperTypes(superType, visitor, project, set); } } } @@ -864,7 +854,6 @@ public class ExpectedTypesProvider { ExpectedTypeInfo[] types = getExpectedTypes(expr, myForCompletion); for (ExpectedTypeInfo info : types) { ExpectedTypeInfoImpl infoImpl = (ExpectedTypeInfoImpl)info; - infoImpl.setInsertExplicitTypeParams(true); infoImpl.myTailType = TailType.COND_EXPR_COLON; } myResult = types; @@ -874,9 +863,6 @@ public class ExpectedTypesProvider { LOG.error(Arrays.asList(expr.getChildren()) + "; " + myExpr); } myResult = getExpectedTypes(expr, myForCompletion); - for (ExpectedTypeInfo info : myResult) { - ((ExpectedTypeInfoImpl)info).setInsertExplicitTypeParams(true); - } } } @@ -1038,7 +1024,6 @@ public class ExpectedTypesProvider { PsiType defaultType = getDefaultType(method, substitutor, parameterType, argument, args, index); ExpectedTypeInfoImpl info = createInfoImpl(parameterType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, defaultType, tailType); - info.setInsertExplicitTypeParams(true); info.setCalledMethod(method); NullableComputable<String> propertyName = getPropertyName(parameter); info.expectedName = propertyName; @@ -1048,7 +1033,6 @@ public class ExpectedTypesProvider { //Then we may still want to call with array argument final PsiArrayType arrayType = parameterType.createArrayType(); ExpectedTypeInfoImpl info1 = createInfoImpl(arrayType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, arrayType, tailType); - info1.setInsertExplicitTypeParams(true); info1.setCalledMethod(method); info1.expectedName = propertyName; array.add(info1); diff --git a/java/java-impl/src/com/intellij/codeInsight/TargetElementUtil.java b/java/java-impl/src/com/intellij/codeInsight/TargetElementUtil.java index 7ed00857bbaf..f9efd108ed48 100644 --- a/java/java-impl/src/com/intellij/codeInsight/TargetElementUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/TargetElementUtil.java @@ -21,6 +21,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.xml.XmlAttribute; @@ -299,7 +300,7 @@ public class TargetElementUtil extends TargetElementUtilBase { return super.acceptImplementationForReference(reference, element); } - private static class PsiElementFindProcessor<T extends PsiElement> implements Processor<T> { + private static class PsiElementFindProcessor<T extends PsiClass> implements Processor<T> { private final T myElement; public PsiElementFindProcessor(T t) { @@ -308,6 +309,7 @@ public class TargetElementUtil extends TargetElementUtilBase { @Override public boolean process(T t) { + if (InheritanceUtil.isInheritorOrSelf(t, myElement, true)) return false; return !myElement.getManager().areElementsEquivalent(myElement, t); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java index ba8486b69c2a..a9167f297091 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java @@ -21,6 +21,7 @@ import com.intellij.codeInsight.TailTypes; import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupItem; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; import com.intellij.codeInsight.lookup.TailTypeDecorator; import com.intellij.patterns.ElementPattern; import com.intellij.patterns.PsiJavaElementPattern; @@ -612,6 +613,17 @@ public class JavaCompletionData extends JavaAwareCompletionData { return; } + boolean afterNew = psiElement().afterLeaf( + psiElement().withText(PsiKeyword.NEW).andNot(psiElement().afterLeaf(PsiKeyword.THROW, "."))).accepts(position); + if (afterNew) { + PsiElementFactory factory = JavaPsiFacade.getElementFactory(position.getProject()); + for (String primitiveType : PRIMITIVE_TYPES) { + result.addElement(PsiTypeLookupItem.createLookupItem(factory.createTypeFromText(primitiveType + "[]", null), null)); + } + result.addElement(PsiTypeLookupItem.createLookupItem(factory.createTypeFromText("void[]", null), null)); + return; + } + boolean inCast = psiElement() .afterLeaf(psiElement().withText("(").withParent(psiElement(PsiParenthesizedExpression.class, PsiTypeCastExpression.class))) .accepts(position); @@ -619,8 +631,6 @@ public class JavaCompletionData extends JavaAwareCompletionData { boolean typeFragment = position.getContainingFile() instanceof PsiTypeCodeFragment && PsiTreeUtil.prevVisibleLeaf(position) == null; boolean declaration = DECLARATION_START.accepts(position); boolean expressionPosition = isExpressionPosition(position); - boolean afterNew = psiElement().afterLeaf( - psiElement().withText(PsiKeyword.NEW).andNot(psiElement().afterLeaf(PsiKeyword.THROW, "."))).accepts(position); boolean inGenerics = PsiTreeUtil.getParentOfType(position, PsiReferenceParameterList.class) != null; if (START_FOR.accepts(position) || isInsideParameterList(position) || @@ -629,7 +639,6 @@ public class JavaCompletionData extends JavaAwareCompletionData { inCast || declaration || typeFragment || - afterNew || expressionPosition || isStatementPosition(position)) { for (String primitiveType : PRIMITIVE_TYPES) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java index ee6de0545115..1de9f59cc67a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionSorting.java @@ -34,6 +34,7 @@ import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; @@ -260,7 +261,17 @@ public class JavaCompletionSorting { public PreferDefaultTypeWeigher(ExpectedTypeInfo[] expectedTypes, CompletionParameters parameters) { super("defaultType"); - myExpectedTypes = expectedTypes; + myExpectedTypes = expectedTypes == null ? null : ContainerUtil.map2Array(expectedTypes, ExpectedTypeInfo.class, new Function<ExpectedTypeInfo, ExpectedTypeInfo>() { + @Override + public ExpectedTypeInfo fun(ExpectedTypeInfo info) { + PsiType type = removeClassWildcard(info.getType()); + PsiType defaultType = removeClassWildcard(info.getDefaultType()); + if (type == info.getType() && defaultType == info.getDefaultType()) { + return info; + } + return new ExpectedTypeInfoImpl(type, info.getKind(), defaultType, info.getTailType()); + } + }); myParameters = parameters; final Pair<PsiClass,Integer> pair = TypeArgumentCompletionProvider.getTypeParameterInfo(parameters.getPosition()); @@ -293,7 +304,7 @@ public class JavaCompletionSorting { } for (final ExpectedTypeInfo expectedInfo : myExpectedTypes) { - final PsiType defaultType = expectedInfo.getDefaultType(); + final PsiType defaultType = expectedInfo.getDefaultType(); final PsiType expectedType = expectedInfo.getType(); if (!expectedType.isValid()) { return MyResult.normal; @@ -316,6 +327,16 @@ public class JavaCompletionSorting { return MyResult.normal; } + private static PsiType removeClassWildcard(PsiType type) { + if (type instanceof PsiClassType) { + final PsiClass psiClass = ((PsiClassType)type).resolve(); + if (psiClass != null && CommonClassNames.JAVA_LANG_CLASS.equals(psiClass.getQualifiedName())) { + return GenericsUtil.eliminateWildcards(type); + } + } + return type; + } + private enum MyResult { expectedNoSelect, exactlyDefault, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java index 75dc0904af12..9e18f7bf8448 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java @@ -29,6 +29,7 @@ import com.intellij.openapi.editor.EditorModificationUtil; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; @@ -38,10 +39,13 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.filters.TrueFilter; import com.intellij.psi.impl.JavaConstantExpressionEvaluator; import com.intellij.psi.javadoc.*; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ProcessingContext; +import com.intellij.util.Processor; +import com.intellij.util.SystemProperties; import com.intellij.util.text.CharArrayUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -120,18 +124,19 @@ public class JavaDocCompletionContributor extends CompletionContributor { @Override protected void addCompletions(@NotNull final CompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) { - List<String> ret = new ArrayList<String>(); + final List<String> ret = new ArrayList<String>(); final PsiElement position = parameters.getPosition(); final PsiDocComment comment = PsiTreeUtil.getParentOfType(position, PsiDocComment.class); + assert comment != null; final PsiElement parent = comment.getContext(); final boolean isInline = position.getContext() instanceof PsiInlineDocTag; - final JavadocManager manager = JavadocManager.SERVICE.getInstance(position.getProject()); - final JavadocTagInfo[] infos = manager.getTagInfos(parent); - for (JavadocTagInfo info : infos) { - if (info.getName().equals(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) continue; - if (isInline != (info.isInline())) continue; - ret.add(info.getName()); + for (JavadocTagInfo info : JavadocManager.SERVICE.getInstance(position.getProject()).getTagInfos(parent)) { + String tagName = info.getName(); + if (tagName.equals(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) continue; + if (isInline != info.isInline()) continue; + ret.add(tagName); + addSpecialTags(ret, comment, tagName); } InspectionProfile inspectionProfile = @@ -149,11 +154,43 @@ public class JavaDocCompletionContributor extends CompletionContributor { result.addElement(TailTypeDecorator.withTail(LookupElementBuilder.create(s), TailType.INSERT_SPACE)); } } + result.stopHere(); // no word completions at this point } - @SuppressWarnings({"HardCodedStringLiteral"}) - public String toString() { - return "javadoc-tag-chooser"; + private static void addSpecialTags(final List<String> result, PsiDocComment comment, String tagName) { + if ("author".equals(tagName)) { + result.add(tagName + " " + SystemProperties.getUserName()); + return; + } + + if ("param".equals(tagName)) { + PsiMethod psiMethod = PsiTreeUtil.getParentOfType(comment, PsiMethod.class); + if (psiMethod != null) { + PsiDocTag[] tags = comment.getTags(); + for (PsiParameter param : psiMethod.getParameterList().getParameters()) { + if (!JavaDocLocalInspection.isFound(tags, param)) { + result.add(tagName + " " + param.getName()); + } + } + } + return; + } + + if ("see".equals(tagName)) { + PsiMember member = PsiTreeUtil.getParentOfType(comment, PsiMember.class); + if (member instanceof PsiClass) { + InheritanceUtil.processSupers((PsiClass)member, false, new Processor<PsiClass>() { + @Override + public boolean process(PsiClass psiClass) { + String name = psiClass.getQualifiedName(); + if (StringUtil.isNotEmpty(name) && !CommonClassNames.JAVA_LANG_OBJECT.equals(name)) { + result.add("see " + name); + } + return true; + } + }); + } + } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index ac7099363487..5e7af80e7d0d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -378,11 +378,11 @@ public class JavaSmartCompletionContributor extends CompletionContributor { final PsiClassType classType = factory .createTypeByFQClassName(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION, position.getResolveScope()); final List<ExpectedTypeInfo> result = new SmartList<ExpectedTypeInfo>(); - result.add(new ExpectedTypeInfoImpl(classType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, 0, classType, TailType.SEMICOLON)); + result.add(new ExpectedTypeInfoImpl(classType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, classType, TailType.SEMICOLON)); final PsiMethod method = PsiTreeUtil.getContextOfType(position, PsiMethod.class, true); if (method != null) { for (final PsiClassType type : method.getThrowsList().getReferencedTypes()) { - result.add(new ExpectedTypeInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, 0, type, TailType.SEMICOLON)); + result.add(new ExpectedTypeInfoImpl(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, type, TailType.SEMICOLON)); } } return result.toArray(new ExpectedTypeInfo[result.size()]); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/JavaAwareInspectionProfileCoverter.java b/java/java-impl/src/com/intellij/codeInsight/daemon/JavaAwareInspectionProfileCoverter.java index e79fdbe14ed9..5caad6166995 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/JavaAwareInspectionProfileCoverter.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/JavaAwareInspectionProfileCoverter.java @@ -20,9 +20,8 @@ */ package com.intellij.codeInsight.daemon; -import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.ModifiableModel; -import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; +import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection; import com.intellij.profile.codeInspection.InspectionProfileManager; import org.jdom.Element; @@ -53,8 +52,8 @@ public class JavaAwareInspectionProfileCoverter extends InspectionProfileConvert super.fillErrorLevels(profile); //javadoc attributes - final InspectionProfileEntry inspectionTool = profile.getInspectionTool(JavaDocLocalInspection.SHORT_NAME, null); - JavaDocLocalInspection inspection = (JavaDocLocalInspection)((LocalInspectionToolWrapper)inspectionTool).getTool(); + final InspectionToolWrapper toolWrapper = profile.getInspectionTool(JavaDocLocalInspection.SHORT_NAME, null); + JavaDocLocalInspection inspection = (JavaDocLocalInspection)toolWrapper.getTool(); inspection.myAdditionalJavadocTags = myAdditionalJavadocTags; } }
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java index a36521fbe936..43a7037397ff 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/PostHighlightingPass.java @@ -139,7 +139,7 @@ public class PostHighlightingPass extends TextEditorHighlightingPass { VirtualFile virtualFile = viewProvider.getVirtualFile(); myInLibrary = fileIndex.isInLibraryClasses(virtualFile) || fileIndex.isInLibrarySource(virtualFile); - myRefCountHolder = RefCountHolder.endUsing(myFile); + myRefCountHolder = RefCountHolder.endUsing(myFile, progress); if (myRefCountHolder == null || !myRefCountHolder.retrieveUnusedReferencesInfo(progress, new Runnable() { @Override public void run() { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java index 0fd26857ab86..892eec196986 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RecursiveCallLineMarkerProvider.java @@ -63,7 +63,7 @@ public class RecursiveCallLineMarkerProvider implements LineMarkerProvider { public static boolean isRecursiveMethodCall(@NotNull PsiMethodCallExpression methodCall) { final PsiMethod method = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class); - if (method == null) { + if (method == null || !method.getName().equals(methodCall.getMethodExpression().getReferenceName())) { return false; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java index 6fd6ba54a888..175c1332db46 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/RefCountHolder.java @@ -18,7 +18,6 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.UserDataHolderEx; import com.intellij.psi.*; @@ -34,11 +33,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.ref.SoftReference; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.*; import java.util.concurrent.atomic.AtomicReference; public class RefCountHolder { @@ -55,34 +50,35 @@ public class RefCountHolder { private volatile ProgressIndicator analyzedUnder; private static class HolderReference extends SoftReference<RefCountHolder> { - @SuppressWarnings("UnusedDeclaration") - private volatile RefCountHolder myHardRef; // to prevent gc - // number of live references to RefCountHolder. Once it reaches zero, hard ref is cleared - // the counter is used instead of a flag because multiple passes can be running simultaneously (one actual and several canceled winding down) - // and there is a chance they overlap the usage of RCH - private final AtomicInteger myRefCount = new AtomicInteger(); + // Map holding hard references to RefCountHolder for each highlighting pass (identified by its progress indicator) + // there can be multiple passes running simultaneously (one actual and several passes just canceled and winding down but still alive) + // so there is a chance they overlap the usage of RCH + // As soon as everybody finished using RCH, map become empty and the RefCountHolder is eligible for gc + private final Map<ProgressIndicator, RefCountHolder> map = new ConcurrentHashMap<ProgressIndicator, RefCountHolder>(); public HolderReference(@NotNull RefCountHolder holder) { super(holder); - myHardRef = holder; } - private void changeLivenessBy(int delta) { - if (myRefCount.addAndGet(delta) == 0) { - myHardRef = null; - } - else if (myHardRef == null) { - myHardRef = get(); - } + private void acquire(@NotNull ProgressIndicator indicator) { + RefCountHolder holder = get(); + assert holder != null: "no way"; + map.put(indicator, holder); + holder = get(); + assert holder != null: "can't be!"; + } + + private RefCountHolder release(@NotNull ProgressIndicator indicator) { + return map.remove(indicator); } } private static final Key<HolderReference> REF_COUNT_HOLDER_IN_FILE_KEY = Key.create("REF_COUNT_HOLDER_IN_FILE_KEY"); - @NotNull - private static Pair<RefCountHolder, HolderReference> getInstance(@NotNull PsiFile file, boolean create) { + + private static RefCountHolder getInstance(@NotNull PsiFile file, @NotNull ProgressIndicator indicator, boolean acquire) { HolderReference ref = file.getUserData(REF_COUNT_HOLDER_IN_FILE_KEY); RefCountHolder holder = ref == null ? null : ref.get(); - if (holder == null && create) { + if (holder == null && acquire) { holder = new RefCountHolder(file); HolderReference newRef = new HolderReference(holder); while (true) { @@ -99,31 +95,30 @@ public class RefCountHolder { } } } - return Pair.create(holder, ref); + if (ref != null) { + if (acquire) { + ref.acquire(indicator); + } + else { + ref.release(indicator); + } + } + return holder; } @NotNull - public static RefCountHolder startUsing(@NotNull PsiFile file) { - Pair<RefCountHolder, HolderReference> pair = getInstance(file, true); - HolderReference reference = pair.second; - reference.changeLivenessBy(1); // make sure RefCountHolder won't be gced during highlighting - log("startUsing: " + pair.first.myState+" for "+file); - return pair.first; + public static RefCountHolder startUsing(@NotNull PsiFile file, @NotNull ProgressIndicator indicator) { + return getInstance(file, indicator, true); } @Nullable("might be gced") - public static RefCountHolder endUsing(@NotNull PsiFile file) { - Pair<RefCountHolder, HolderReference> pair = getInstance(file, false); - HolderReference reference = pair.second; - reference.changeLivenessBy(-1); // no longer needed, can be cleared - RefCountHolder holder = pair.first; - log("endUsing: " + (holder == null ? null : holder.myState)+" for "+file); - return holder; + public static RefCountHolder endUsing(@NotNull PsiFile file, @NotNull ProgressIndicator indicator) { + return getInstance(file, indicator, false); } private RefCountHolder(@NotNull PsiFile file) { myFile = file; - log("c: created: " + myState.get()+" for "+file); + log("c: created: ", myState.get(), " for ", file); } private void clear() { @@ -284,10 +279,10 @@ public class RefCountHolder { ProgressIndicator old = myState.get(); if (old != VIRGIN && old != READY) return false; if (!myState.compareAndSet(old, indicator)) { - log("a: failed to change " + old + "->" + indicator); + log("a: failed to change ", old, "->", indicator); return false; } - log("a: changed " + old + "->" + indicator); + log("a: changed ", old, "->", indicator); analyzedUnder = null; boolean completed = false; try { @@ -308,22 +303,22 @@ public class RefCountHolder { ProgressIndicator resultState = completed ? READY : VIRGIN; boolean set = myState.compareAndSet(indicator, resultState); assert set : myState.get(); - log("a: changed after analyze" + indicator + "->" + resultState); + log("a: changed after analyze", indicator, "->", resultState); } return true; } - private static void log(@NonNls String s) { - //System.err.println("RFC: "+s); + private static void log(@NonNls Object... s) { + //System.err.println("RFC: "+ Arrays.asList(s)); } public boolean retrieveUnusedReferencesInfo(@NotNull ProgressIndicator indicator, @NotNull Runnable analyze) { ProgressIndicator old = myState.get(); if (!myState.compareAndSet(READY, indicator)) { - log("r: failed to change " + old + "->" + indicator); + log("r: failed to change ", old, "->", indicator); return false; } - log("r: changed " + old + "->" + indicator); + log("r: changed ", old, "->", indicator); try { if (analyzedUnder != indicator) { return false; @@ -333,7 +328,7 @@ public class RefCountHolder { finally { boolean set = myState.compareAndSet(indicator, READY); assert set : myState.get(); - log("r: changed back " + indicator + "->" + READY); + log("r: changed back ", indicator, "->", READY); } return true; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index 1d74a2f3dcf4..48e10ee31035 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -40,6 +40,7 @@ import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashSet; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -384,8 +385,10 @@ public class GenericsHighlightUtil { } @Nullable - public static HighlightInfo checkElementInTypeParameterExtendsList(PsiReferenceList referenceList, JavaResolveResult resolveResult, PsiElement element) { - PsiClass aClass = (PsiClass)referenceList.getParent(); + public static HighlightInfo checkElementInTypeParameterExtendsList(@NotNull PsiReferenceList referenceList, + @NotNull PsiClass aClass, + @NotNull JavaResolveResult resolveResult, + @NotNull PsiElement element) { final PsiJavaCodeReferenceElement[] referenceElements = referenceList.getReferenceElements(); PsiClass extendFrom = (PsiClass)resolveResult.getElement(); if (extendFrom == null) return null; @@ -462,7 +465,7 @@ public class GenericsHighlightUtil { return null; } - public static HighlightInfo checkOverrideEquivalentMethods(final PsiClass aClass) { + public static HighlightInfo checkOverrideEquivalentMethods(@NotNull PsiClass aClass) { final Collection<HierarchicalMethodSignature> signaturesWithSupers = aClass.getVisibleSignatures(); PsiManager manager = aClass.getManager(); Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods = @@ -520,10 +523,10 @@ public class GenericsHighlightUtil { } @Nullable - private static HighlightInfo checkSameErasureNotSubSignatureInner(final HierarchicalMethodSignature signature, - final PsiManager manager, - final PsiClass aClass, - final Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods) { + private static HighlightInfo checkSameErasureNotSubSignatureInner(@NotNull HierarchicalMethodSignature signature, + @NotNull PsiManager manager, + @NotNull PsiClass aClass, + @NotNull Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods) { PsiMethod method = signature.getMethod(); JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); if (!facade.getResolveHelper().isAccessible(method, aClass, null)) return null; @@ -549,10 +552,11 @@ public class GenericsHighlightUtil { if (superSignature.isRaw() && !signature.isRaw()) { final PsiType[] parameterTypes = signature.getParameterTypes(); - PsiType[] types = superSignature.getParameterTypes(); - for (int i = 0; i < types.length; i++) { - if (!Comparing.equal(parameterTypes[i], TypeConversionUtil.erasure(types[i]))) { - return getSameErasureMessage(false, method, superSignature.getMethod(), HighlightNamesUtil.getClassDeclarationTextRange(aClass)); + PsiType[] erasedTypes = superSignature.getErasedParameterTypes(); + for (int i = 0; i < erasedTypes.length; i++) { + if (!Comparing.equal(parameterTypes[i], erasedTypes[i])) { + return getSameErasureMessage(false, method, superSignature.getMethod(), + HighlightNamesUtil.getClassDeclarationTextRange(aClass)); } } } @@ -601,10 +605,10 @@ public class GenericsHighlightUtil { !(checkEqualsSuper && Arrays.equals(superSignature.getParameterTypes(), signatureToCheck.getParameterTypes())) && !atLeast17) { int idx = 0; - final PsiType[] parameterTypes = signatureToCheck.getParameterTypes(); - boolean erasure = parameterTypes.length > 0; + final PsiType[] erasedTypes = signatureToCheck.getErasedParameterTypes(); + boolean erasure = erasedTypes.length > 0; for (PsiType type : superSignature.getParameterTypes()) { - erasure &= Comparing.equal(type, TypeConversionUtil.erasure(parameterTypes[idx])); + erasure &= Comparing.equal(type, erasedTypes[idx]); idx++; } @@ -624,9 +628,9 @@ public class GenericsHighlightUtil { } } - private static HighlightInfo getSameErasureMessage(final boolean sameClass, final PsiMethod method, final PsiMethod superMethod, + private static HighlightInfo getSameErasureMessage(final boolean sameClass, @NotNull PsiMethod method, @NotNull PsiMethod superMethod, TextRange textRange) { - @NonNls final String key = sameClass ? "generics.methods.have.same.erasure" : + @NonNls final String key = sameClass ? "generics.methods.have.same.erasure" : method.hasModifierProperty(PsiModifier.STATIC) ? "generics.methods.have.same.erasure.hide" : "generics.methods.have.same.erasure.override"; @@ -1275,7 +1279,7 @@ public class GenericsHighlightUtil { if (resolve instanceof PsiClass) { final PsiClass containingClass = ((PsiClass)resolve).getContainingClass(); if (containingClass != null) { - if (psiClass.isInheritor(containingClass, true) || + if (psiClass.isInheritor(containingClass, true) || unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(containingClass, ((PsiClass)resolve).getExtendsList()) || unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(containingClass, ((PsiClass)resolve).getImplementsList())) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(((PsiClass)resolve).getName() + " is not accessible in current context").range(ref).create(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index 4f6f0996ad29..ae32b61b8e45 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -55,10 +55,7 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; +import java.util.*; public class HighlightClassUtil { private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance(); @@ -94,19 +91,32 @@ public class HighlightClassUtil { static HighlightInfo checkClassWithAbstractMethods(PsiClass aClass, PsiElement implementsFixElement, TextRange range) { PsiMethod abstractMethod = ClassUtil.getAnyAbstractMethod(aClass); - if (abstractMethod == null || abstractMethod.getContainingClass() == null) { + if (abstractMethod == null) { return null; } + + final PsiClass superClass = abstractMethod.getContainingClass(); + if (superClass == null) { + return null; + } + String baseClassName = HighlightUtil.formatClass(aClass, false); String methodName = JavaHighlightUtil.formatMethod(abstractMethod); String message = JavaErrorMessages.message(aClass instanceof PsiEnumConstantInitializer || implementsFixElement instanceof PsiEnumConstant ? "enum.constant.should.implement.method" : "class.must.be.abstract", baseClassName, methodName, - HighlightUtil.formatClass(abstractMethod.getContainingClass(), false)); + HighlightUtil.formatClass(superClass, false)); HighlightInfo errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(range).descriptionAndTooltip(message).create(); - if (ClassUtil.getAnyMethodToImplement(aClass) != null) { - QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createImplementMethodsFix(implementsFixElement)); + final PsiMethod anyMethodToImplement = ClassUtil.getAnyMethodToImplement(aClass); + if (anyMethodToImplement != null) { + if (!anyMethodToImplement.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) || + JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, superClass)) { + QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createImplementMethodsFix(implementsFixElement)); + } else { + QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createModifierListFix(anyMethodToImplement, PsiModifier.PROTECTED, true, true)); + QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createModifierListFix(anyMethodToImplement, PsiModifier.PUBLIC, true, true)); + } } if (!(aClass instanceof PsiAnonymousClass) && HighlightUtil.getIncompatibleModifier(PsiModifier.ABSTRACT, aClass.getModifierList()) == null) { @@ -985,7 +995,7 @@ public class HighlightClassUtil { if (classReference == null) return; final PsiClass psiClass = (PsiClass)classReference.resolve(); if (psiClass == null) return; - final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, psiClass); + final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, psiClass, false); if (chooser == null) return; final List<PsiMethodMember> selectedElements = chooser.getSelectedElements(); @@ -999,12 +1009,17 @@ public class HighlightClassUtil { newExpression = (PsiNewExpression)startElement.replace(newExpression); final PsiClass psiClass = newExpression.getAnonymousClass(); if (psiClass == null) return; - PsiClassType baseClassType = ((PsiAnonymousClass)psiClass).getBaseClassType(); - PsiClass resolve = baseClassType.resolve(); - if (resolve == null) return; - PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(resolve, psiClass, PsiSubstitutor.EMPTY); + Map<PsiClass, PsiSubstitutor> subst = new HashMap<PsiClass, PsiSubstitutor>(); for (PsiMethodMember selectedElement : selectedElements) { - selectedElement.setSubstitutor(superClassSubstitutor); + final PsiClass baseClass = selectedElement.getElement().getContainingClass(); + if (baseClass != null) { + PsiSubstitutor substitutor = subst.get(baseClass); + if (substitutor == null) { + substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, psiClass, PsiSubstitutor.EMPTY); + subst.put(baseClass, substitutor); + } + selectedElement.setSubstitutor(substitutor); + } } OverrideImplementUtil.overrideOrImplementMethodsInRightPlace(editor, psiClass, selectedElements, chooser.isCopyJavadoc(), chooser.isInsertOverrideAnnotation()); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 80f4b1715a1c..2d1a4db5ff7d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -35,6 +35,7 @@ import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.util.*; import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.ui.ColorUtil; +import com.intellij.util.containers.MostlySingularMultiMap; import com.intellij.util.ui.UIUtil; import com.intellij.xml.util.XmlStringUtil; import org.intellij.lang.annotations.Language; @@ -833,18 +834,15 @@ public class HighlightMethodUtil { } @Nullable - static HighlightInfo checkDuplicateMethod(PsiClass aClass, PsiMethod method) { + static HighlightInfo checkDuplicateMethod(PsiClass aClass, + @NotNull PsiMethod method, + @NotNull MostlySingularMultiMap<MethodSignature, PsiMethod> duplicateMethods) { if (aClass == null || method instanceof ExternallyDefinedPsiElement) return null; MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY); - int methodCount = 0; - final PsiMethod[] methodsByName = aClass.findMethodsByName(method.getName(), false); - for (PsiMethod other : methodsByName) { - if (other instanceof ExternallyDefinedPsiElement) continue; - if (other == method || - other.isConstructor() == method.isConstructor() && other.getSignature(PsiSubstitutor.EMPTY).equals(methodSignature)) { - methodCount++; - if (methodCount > 1) break; - } + int methodCount = 1; + List<PsiMethod> methods = (List<PsiMethod>)duplicateMethods.get(methodSignature); + if (methods.size() > 1) { + methodCount++; } if (methodCount == 1 && aClass.isEnum() && @@ -874,6 +872,7 @@ public class HighlightMethodUtil { if (hasNoBody) { if (isExtension) { description = JavaErrorMessages.message("extension.method.should.have.a.body"); + additionalFixes.add(new AddMethodBodyFix(method)); } else if (isInterface && isStatic) { description = "Static methods in interfaces should have a body"; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 94508dfe2352..e7b3d6b4bbc9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -2516,7 +2516,7 @@ public class HighlightUtil extends HighlightUtilBase { PsiClass aClass = (PsiClass)resolved; if (refGrandParent instanceof PsiClass) { if (refGrandParent instanceof PsiTypeParameter) { - highlightInfo = GenericsHighlightUtil.checkElementInTypeParameterExtendsList(referenceList, resolveResult, ref); + highlightInfo = GenericsHighlightUtil.checkElementInTypeParameterExtendsList(referenceList, (PsiClass)refGrandParent, resolveResult, ref); } else { highlightInfo = HighlightClassUtil.checkExtendsClassAndImplementsInterface(referenceList, resolveResult, ref); 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 1c0e2ecf342b..c705951fe395 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 @@ -39,11 +39,9 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspClass; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTagValue; -import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; -import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.psi.util.*; import com.intellij.psi.xml.XmlAttributeValue; +import com.intellij.util.containers.MostlySingularMultiMap; import gnu.trove.THashMap; import gnu.trove.TObjectIntHashMap; import org.jetbrains.annotations.NotNull; @@ -82,11 +80,27 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } } }; + private final Map<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>> myDuplicateMethods = new THashMap<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>>(); public HighlightVisitorImpl(@NotNull PsiResolveHelper resolveHelper) { myResolveHelper = resolveHelper; } + @NotNull + private MostlySingularMultiMap<MethodSignature, PsiMethod> getDuplicateMethods(PsiClass aClass) { + MostlySingularMultiMap<MethodSignature, PsiMethod> signatures = myDuplicateMethods.get(aClass); + if (signatures == null) { + signatures = new MostlySingularMultiMap<MethodSignature, PsiMethod>(); + for (PsiMethod method : aClass.getMethods()) { + MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY); + signatures.add(signature, method); + } + + myDuplicateMethods.put(aClass, signatures); + } + return signatures; + } + @Override @NotNull public HighlightVisitorImpl clone() { @@ -130,12 +144,13 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh Project project = file.getProject(); DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(project); FileStatusMap fileStatusMap = ((DaemonCodeAnalyzerImpl)daemonCodeAnalyzer).getFileStatusMap(); - RefCountHolder refCountHolder = RefCountHolder.startUsing(file); + ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + if (indicator == null) throw new IllegalStateException("Must be run under progress"); + RefCountHolder refCountHolder = RefCountHolder.startUsing(file, indicator); myRefCountHolder = refCountHolder; Document document = PsiDocumentManager.getInstance(project).getDocument(file); TextRange dirtyScope = document == null ? file.getTextRange() : fileStatusMap.getFileDirtyScope(document, Pass.UPDATE_ALL); - ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); - success = indicator != null && refCountHolder.analyze(file, dirtyScope, action, indicator); + success = refCountHolder.analyze(file, dirtyScope, action, indicator); } else { myRefCountHolder = null; @@ -152,6 +167,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh myRefCountHolder = null; myFile = null; myHolder = null; + myDuplicateMethods.clear(); } return success; @@ -775,7 +791,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh } PsiClass aClass = method.getContainingClass(); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodMustHaveBody(method, aClass)); - if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass))); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkConstructorCallsBaseClassConstructor(method, myRefCountHolder, myResolveHelper)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkStaticMethodOverride(method)); } @@ -932,7 +948,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkCannotPassInner(ref)); if (resolved != null && parent instanceof PsiReferenceList) { - if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkElementInReferenceList(ref, (PsiReferenceList)parent, result)); + if (!myHolder.hasErrorResults()) { + PsiReferenceList referenceList = (PsiReferenceList)parent; + myHolder.add(HighlightUtil.checkElementInReferenceList(ref, referenceList, result)); + } } if (parent instanceof PsiAnonymousClass && ref.equals(((PsiAnonymousClass)parent).getBaseClassReference())) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeArgumentsConditionalFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeArgumentsConditionalFix.java index 4457e5d47c40..0057749d056b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeArgumentsConditionalFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeArgumentsConditionalFix.java @@ -102,8 +102,8 @@ public class AddTypeArgumentsConditionalFix implements IntentionAction { return true; } - public static void register(HighlightInfo highlightInfo, PsiExpression expression, PsiType lType) { - if (expression instanceof PsiConditionalExpression) { + public static void register(HighlightInfo highlightInfo, PsiExpression expression, @NotNull PsiType lType) { + if (lType != PsiType.NULL && expression instanceof PsiConditionalExpression) { final PsiExpression thenExpression = ((PsiConditionalExpression)expression).getThenExpression(); final PsiExpression elseExpression = ((PsiConditionalExpression)expression).getElseExpression(); if (thenExpression != null && elseExpression != null) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java index ad63c638f5d0..667143b2da35 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java @@ -134,7 +134,7 @@ public class CreateFromUsageUtils { JVMElementFactory factory = JVMElementFactories.getFactory(aClass.getLanguage(), aClass.getProject()); - LOG.assertTrue(!aClass.isInterface(), "Interface bodies should be already set up"); + LOG.assertTrue(!aClass.isInterface() || method.hasModifierProperty(PsiModifier.DEFAULT), "Interface bodies should be already set up"); FileType fileType = FileTypeManager.getInstance().getFileTypeByExtension(template.getExtension()); Properties properties = new Properties(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java index 24ba71dc024c..919c6b447259 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateLocalFromUsageFix.java @@ -54,8 +54,11 @@ public class CreateLocalFromUsageFix extends CreateVarFromUsageFix { if (!super.isAvailableImpl(offset)) return false; if(myReferenceExpression.isQualified()) return false; PsiElement scope = PsiTreeUtil.getParentOfType(myReferenceExpression, PsiModifierListOwner.class); + if (scope instanceof PsiAnonymousClass) { + scope = PsiTreeUtil.getParentOfType(scope, PsiModifierListOwner.class, true); + } return scope instanceof PsiMethod || scope instanceof PsiClassInitializer || - scope instanceof PsiLocalVariable || scope instanceof PsiAnonymousClass; + scope instanceof PsiLocalVariable; } @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java index f9c9b7b7373c..5e632738fa5c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImplementMethodsFix.java @@ -28,16 +28,13 @@ import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiEnumConstant; -import com.intellij.psi.PsiFile; +import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.List; +import java.util.*; public class ImplementMethodsFix extends LocalQuickFixAndIntentionActionOnPsiElement { public ImplementMethodsFix(PsiElement aClass) { @@ -75,7 +72,7 @@ public class ImplementMethodsFix extends LocalQuickFixAndIntentionActionOnPsiEle if (editor == null || !FileModificationService.getInstance().prepareFileForWrite(myPsiElement.getContainingFile())) return; if (myPsiElement instanceof PsiEnumConstant) { - final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, ((PsiEnumConstant)myPsiElement).getContainingClass()); + final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, ((PsiEnumConstant)myPsiElement).getContainingClass(), true); if (chooser == null) return; final List<PsiMethodMember> selectedElements = chooser.getSelectedElements(); @@ -103,10 +100,14 @@ public class ImplementMethodsFix extends LocalQuickFixAndIntentionActionOnPsiEle @Nullable - protected static MemberChooser<PsiMethodMember> chooseMethodsToImplement(Editor editor, PsiElement startElement, PsiClass aClass) { + protected static MemberChooser<PsiMethodMember> chooseMethodsToImplement(Editor editor, + PsiElement startElement, + PsiClass aClass, + boolean implemented) { FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT); + final Collection<CandidateInfo> overrideImplement = OverrideImplementExploreUtil.getMapToOverrideImplement(aClass, true, implemented).values(); return OverrideImplementUtil - .showOverrideImplementChooser(editor, startElement, true, OverrideImplementExploreUtil.getMethodsToOverrideImplement(aClass, true), Collections.<CandidateInfo>emptyList()); + .showOverrideImplementChooser(editor, startElement, true, overrideImplement, ContainerUtil.<CandidateInfo>newArrayList()); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java index a2bebf63ac18..2e23f7ef65e4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFix.java @@ -107,6 +107,7 @@ public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceEleme return super.getRequiredMemberName(reference); } + @NotNull @Override protected List<PsiClass> filterByContext(@NotNull List<PsiClass> candidates, @NotNull PsiJavaCodeReferenceElement ref) { PsiElement typeElement = ref.getParent(); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java index e34ad1820c89..bfb7c45bf3c8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ImportClassFixBase.java @@ -184,6 +184,7 @@ public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiRefe return null; } + @NotNull protected List<PsiClass> filterByContext(@NotNull List<PsiClass> candidates, @NotNull T ref) { return candidates; } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java index 6ac2e5d9e37e..0d710688eec1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java @@ -141,6 +141,7 @@ public class ModifierFix extends LocalQuickFixAndIntentionActionOnPsiElement { final PsiModifierList myModifierList = (PsiModifierList)startElement; final PsiVariable variable = myVariable == null ? null : myVariable.getElement(); if (!FileModificationService.getInstance().preparePsiElementForWrite(myModifierList)) return; + if (variable != null && !FileModificationService.getInstance().preparePsiElementForWrite(variable)) return; final List<PsiModifierList> modifierLists = new ArrayList<PsiModifierList>(); final PsiFile containingFile = myModifierList.getContainingFile(); final PsiModifierList modifierList; @@ -180,8 +181,6 @@ public class ModifierFix extends LocalQuickFixAndIntentionActionOnPsiElement { })); } - if (!FileModificationService.getInstance().prepareFileForWrite(containingFile)) return; - if (!modifierLists.isEmpty()) { if (Messages.showYesNoDialog(project, QuickFixBundle.message("change.inheritors.visibility.warning.text"), diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java index e08b1a9d8073..7f906c1c233f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -51,7 +51,7 @@ public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> imple return null; } - final ArrayList<ReferenceTransferableData.ReferenceData> array = new ArrayList<ReferenceTransferableData.ReferenceData>(); + final ArrayList<ReferenceData> array = new ArrayList<ReferenceData>(); for (int j = 0; j < startOffsets.length; j++) { final int startOffset = startOffsets[j]; for (final PsiElement element : CollectHighlightsUtil.getElementsInRange(file, startOffset, endOffsets[j])) { @@ -63,10 +63,10 @@ public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> imple return null; } - return new ReferenceTransferableData(array.toArray(new ReferenceTransferableData.ReferenceData[array.size()])); + return new ReferenceTransferableData(array.toArray(new ReferenceData[array.size()])); } - protected abstract void addReferenceData(PsiFile file, int startOffset, PsiElement element, ArrayList<ReferenceTransferableData.ReferenceData> to); + protected abstract void addReferenceData(PsiFile file, int startOffset, PsiElement element, ArrayList<ReferenceData> to); @Override @Nullable @@ -74,7 +74,7 @@ public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> imple ReferenceTransferableData referenceData = null; if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE != CodeInsightSettings.NO) { try { - final DataFlavor flavor = ReferenceTransferableData.ReferenceData.getDataFlavor(); + final DataFlavor flavor = ReferenceData.getDataFlavor(); if (flavor != null) { referenceData = (ReferenceTransferableData)content.getTransferData(flavor); } @@ -109,7 +109,7 @@ public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> imple } PsiDocumentManager.getInstance(project).commitAllDocuments(); - final ReferenceTransferableData.ReferenceData[] referenceData = value.getData(); + final ReferenceData[] referenceData = value.getData(); final TRef[] refs = findReferencesToRestore(file, bounds, referenceData); if (CodeInsightSettings.getInstance().ADD_IMPORTS_ON_PASTE == CodeInsightSettings.ASK) { askReferencesToRestore(project, refs, referenceData); @@ -124,12 +124,12 @@ public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> imple } protected static void addReferenceData(final PsiElement element, - final ArrayList<ReferenceTransferableData.ReferenceData> array, + final ArrayList<ReferenceData> array, final int startOffset, final String qClassName, @Nullable final String staticMemberName) { final TextRange range = element.getTextRange(); array.add( - new ReferenceTransferableData.ReferenceData( + new ReferenceData( range.getStartOffset() - startOffset, range.getEndOffset() - startOffset, qClassName, staticMemberName)); @@ -137,13 +137,13 @@ public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> imple protected abstract TRef[] findReferencesToRestore(PsiFile file, RangeMarker bounds, - ReferenceTransferableData.ReferenceData[] referenceData); + ReferenceData[] referenceData); - protected abstract void restoreReferences(ReferenceTransferableData.ReferenceData[] referenceData, + protected abstract void restoreReferences(ReferenceData[] referenceData, TRef[] refs); private static void askReferencesToRestore(Project project, PsiElement[] refs, - ReferenceTransferableData.ReferenceData[] referenceData) { + ReferenceData[] referenceData) { PsiManager manager = PsiManager.getInstance(project); ArrayList<Object> array = new ArrayList<Object>(); @@ -152,7 +152,7 @@ public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> imple PsiElement ref = refs[i]; if (ref != null) { LOG.assertTrue(ref.isValid()); - ReferenceTransferableData.ReferenceData data = referenceData[i]; + ReferenceData data = referenceData[i]; PsiClass refClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(data.qClassName, ref.getResolveScope()); if (refClass == null) continue; diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaCopyPasteReferenceProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaCopyPasteReferenceProcessor.java index 85ea365e0670..51edddd250aa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaCopyPasteReferenceProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/JavaCopyPasteReferenceProcessor.java @@ -30,7 +30,7 @@ public class JavaCopyPasteReferenceProcessor extends CopyPasteReferenceProcessor private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.editorActions.JavaCopyPasteReferenceProcessor"); @Override - protected void addReferenceData(PsiFile file, int startOffset, PsiElement element, ArrayList<ReferenceTransferableData.ReferenceData> to) { + protected void addReferenceData(PsiFile file, int startOffset, PsiElement element, ArrayList<ReferenceData> to) { if (element instanceof PsiJavaCodeReferenceElement) { if (!((PsiJavaCodeReferenceElement)element).isQualified()) { final JavaResolveResult resolveResult = ((PsiJavaCodeReferenceElement)element).advancedResolve(false); @@ -61,13 +61,13 @@ public class JavaCopyPasteReferenceProcessor extends CopyPasteReferenceProcessor @Override protected PsiJavaCodeReferenceElement[] findReferencesToRestore(PsiFile file, RangeMarker bounds, - ReferenceTransferableData.ReferenceData[] referenceData) { + ReferenceData[] referenceData) { PsiManager manager = file.getManager(); final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); PsiResolveHelper helper = facade.getResolveHelper(); PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[referenceData.length]; for (int i = 0; i < referenceData.length; i++) { - ReferenceTransferableData.ReferenceData data = referenceData[i]; + ReferenceData data = referenceData[i]; PsiClass refClass = facade.findClass(data.qClassName, file.getResolveScope()); if (refClass == null) continue; @@ -105,14 +105,14 @@ public class JavaCopyPasteReferenceProcessor extends CopyPasteReferenceProcessor } @Override - protected void restoreReferences(ReferenceTransferableData.ReferenceData[] referenceData, + protected void restoreReferences(ReferenceData[] referenceData, PsiJavaCodeReferenceElement[] refs) { for (int i = 0; i < refs.length; i++) { PsiJavaCodeReferenceElement reference = refs[i]; if (reference == null || !reference.isValid()) continue; try { PsiManager manager = reference.getManager(); - ReferenceTransferableData.ReferenceData refData = referenceData[i]; + ReferenceData refData = referenceData[i]; PsiClass refClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(refData.qClassName, reference.getResolveScope()); if (refClass != null) { if (refData.staticMemberName == null) { diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/ReferenceData.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/ReferenceData.java new file mode 100644 index 000000000000..8cc6f8dd2202 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/ReferenceData.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.editorActions; + +import org.jetbrains.annotations.NonNls; + +import java.awt.datatransfer.DataFlavor; +import java.io.Serializable; + +/** +* @author Denis Fokin +*/ +public class ReferenceData implements Cloneable, Serializable { + public static @NonNls DataFlavor ourFlavor; + + public int startOffset; + public int endOffset; + public final String qClassName; + public final String staticMemberName; + + public ReferenceData(int startOffset, int endOffset, String qClassName, String staticMemberDescriptor) { + this.startOffset = startOffset; + this.endOffset = endOffset; + this.qClassName = qClassName; + this.staticMemberName = staticMemberDescriptor; + } + + @Override + public Object clone() { + try{ + return super.clone(); + } + catch(CloneNotSupportedException e){ + throw new RuntimeException(); + } + } + + public static DataFlavor getDataFlavor() { + if (ourFlavor != null) { + return ourFlavor; + } + try { + ourFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=" + ReferenceData.class.getName(), "ReferenceData"); + } + catch (NoClassDefFoundError e) { + return null; + } + catch (IllegalArgumentException e) { + return null; + } + return ourFlavor; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/ReferenceTransferableData.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/ReferenceTransferableData.java index 8b2e56e7deb5..76c37546888b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/ReferenceTransferableData.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/ReferenceTransferableData.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -15,8 +15,6 @@ */ package com.intellij.codeInsight.editorActions; -import org.jetbrains.annotations.NonNls; - import java.awt.datatransfer.DataFlavor; import java.io.Serializable; @@ -70,46 +68,4 @@ public class ReferenceTransferableData implements TextBlockTransferableData, Clo public ReferenceData[] getData() { return myReferenceDatas; } - - public static class ReferenceData implements Cloneable, Serializable { - public static @NonNls DataFlavor ourFlavor; - - public int startOffset; - public int endOffset; - public final String qClassName; - public final String staticMemberName; - - public ReferenceData(int startOffset, int endOffset, String qClassName, String staticMemberDescriptor) { - this.startOffset = startOffset; - this.endOffset = endOffset; - this.qClassName = qClassName; - this.staticMemberName = staticMemberDescriptor; - } - - @Override - public Object clone() { - try{ - return super.clone(); - } - catch(CloneNotSupportedException e){ - throw new RuntimeException(); - } - } - - public static DataFlavor getDataFlavor() { - if (ourFlavor != null) { - return ourFlavor; - } - try { - ourFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=" + ReferenceData.class.getName(), "ReferenceData"); - } - catch (NoClassDefFoundError e) { - return null; - } - catch (IllegalArgumentException e) { - return null; - } - return ourFlavor; - } - } } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateGetterHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateGetterHandler.java index d7aca706b64f..1306e20718ae 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateGetterHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateGetterHandler.java @@ -37,7 +37,7 @@ public class GenerateGetterHandler extends GenerateGetterSetterHandlerBase { protected GenerationInfo[] generateMemberPrototypes(PsiClass aClass, ClassMember original) throws IncorrectOperationException { if (original instanceof PropertyClassMember) { final PropertyClassMember propertyClassMember = (PropertyClassMember)original; - final GenerationInfo[] getters = propertyClassMember.generateGetters(); + final GenerationInfo[] getters = propertyClassMember.generateGetters(aClass); if (getters != null) { return getters; } 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 5a8eea42ae5f..a58dfe3dae2a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateMembersUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.generation; +import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; @@ -22,6 +23,7 @@ import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; @@ -30,6 +32,7 @@ import com.intellij.psi.codeStyle.*; import com.intellij.psi.impl.light.LightTypeElement; import com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; @@ -42,10 +45,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; public class GenerateMembersUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.generation.GenerateMembersUtil"); @@ -266,7 +266,17 @@ public class GenerateMembersUtil { substituteTypeParameters(factory, target, sourceMethod.getTypeParameterList(), resultMethod.getTypeParameterList(), substitutor, sourceMethod); substituteReturnType(PsiManager.getInstance(project), resultMethod, sourceMethod.getReturnType(), collisionResolvedSubstitutor); substituteParameters(factory, codeStyleManager, sourceMethod.getParameterList(), resultMethod.getParameterList(), collisionResolvedSubstitutor, target); - substituteThrows(factory, sourceMethod.getThrowsList(), resultMethod.getThrowsList(), collisionResolvedSubstitutor, sourceMethod); + final List<PsiClassType> thrownTypes = ExceptionUtil.collectSubstituted(collisionResolvedSubstitutor, sourceMethod.getThrowsList().getReferencedTypes()); + if (target instanceof PsiClass) { + final PsiClass[] supers = ((PsiClass)target).getSupers(); + for (PsiClass aSuper : supers) { + final PsiMethod psiMethod = aSuper.findMethodBySignature(sourceMethod, true); + if (psiMethod != null && psiMethod != sourceMethod) { + ExceptionUtil.retainExceptions(thrownTypes, ExceptionUtil.collectSubstituted(TypeConversionUtil.getSuperClassSubstitutor(aSuper, (PsiClass)target, PsiSubstitutor.EMPTY), psiMethod.getThrowsList().getReferencedTypes())); + } + } + } + substituteThrows(factory, resultMethod.getThrowsList(), collisionResolvedSubstitutor, sourceMethod, thrownTypes); return resultMethod; } catch (IncorrectOperationException e) { @@ -400,11 +410,11 @@ public class GenerateMembersUtil { } private static void substituteThrows(@NotNull JVMElementFactory factory, - @NotNull PsiReferenceList sourceThrowsList, @NotNull PsiReferenceList targetThrowsList, - @NotNull PsiSubstitutor substitutor, - @NotNull PsiMethod sourceMethod) { - for (PsiClassType thrownType : sourceThrowsList.getReferencedTypes()) { + @NotNull PsiSubstitutor substitutor, + @NotNull PsiMethod sourceMethod, + List<PsiClassType> thrownTypes) { + for (PsiClassType thrownType : thrownTypes) { targetThrowsList.add(factory.createReferenceElementByType((PsiClassType)substituteType(substitutor, thrownType, sourceMethod))); } } @@ -504,7 +514,7 @@ public class GenerateMembersUtil { PsiModifierList targetModifierList = targetParam.getModifierList(); if (sourceModifierList != null && targetModifierList != null) { if (sourceParam.getLanguage() == targetParam.getLanguage()) { - targetModifierList.replace(sourceModifierList); + targetModifierList = (PsiModifierList)targetModifierList.replace(sourceModifierList); } else { JVMElementFactory factory = JVMElementFactories.requireFactory(targetParam.getLanguage(), targetParam.getProject()); @@ -515,6 +525,30 @@ public class GenerateMembersUtil { targetModifierList.setModifierProperty(m, sourceParam.hasModifierProperty(m)); } } + processAnnotations(sourceModifierList.getProject(), targetModifierList, targetModifierList.getResolveScope()); + } + } + + private static void processAnnotations(Project project, PsiModifierList modifierList, GlobalSearchScope moduleScope) { + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + final Set<String> toRemove = new HashSet<String>(); + for (PsiAnnotation annotation : modifierList.getAnnotations()) { + final String qualifiedName = annotation.getQualifiedName(); + if (qualifiedName != null) { + for (OverrideImplementsAnnotationsHandler handler : Extensions.getExtensions(OverrideImplementsAnnotationsHandler.EP_NAME)) { + final String[] annotations2Remove = handler.annotationsToRemove(project, qualifiedName); + Collections.addAll(toRemove, annotations2Remove); + if (moduleScope != null && psiFacade.findClass(qualifiedName, moduleScope) == null) { + toRemove.add(qualifiedName); + } + } + } + } + for (String fqn : toRemove) { + final PsiAnnotation psiAnnotation = modifierList.findAnnotation(fqn); + if (psiAnnotation != null) { + psiAnnotation.delete(); + } } } } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateSetterHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateSetterHandler.java index e33f1b8bb004..76a2251807ab 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateSetterHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateSetterHandler.java @@ -29,7 +29,7 @@ public class GenerateSetterHandler extends GenerateGetterSetterHandlerBase { protected GenerationInfo[] generateMemberPrototypes(PsiClass aClass, ClassMember original) throws IncorrectOperationException { if (original instanceof PropertyClassMember) { final PropertyClassMember propertyClassMember = (PropertyClassMember)original; - final GenerationInfo[] getters = propertyClassMember.generateSetters(); + final GenerationInfo[] getters = propertyClassMember.generateSetters(aClass); if (getters != null) { return getters; } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GetterSetterPrototypeProvider.java b/java/java-impl/src/com/intellij/codeInsight/generation/GetterSetterPrototypeProvider.java index 727bd8143dd9..521445725ef0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GetterSetterPrototypeProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GetterSetterPrototypeProvider.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.generation; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; +import com.intellij.psi.PsiClass; import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; @@ -31,6 +32,17 @@ public abstract class GetterSetterPrototypeProvider { public abstract boolean canGeneratePrototypeFor(PsiField field); public abstract PsiMethod[] generateGetters(PsiField field); public abstract PsiMethod[] generateSetters(PsiField field); + public PsiMethod[] findGetters(PsiClass psiClass, String propertyName) { + return null; + } + + public String suggestGetterName(String propertyName) { + return null; + } + + public boolean isSimpleGetter(PsiMethod method, String oldPropertyName) { + return false; + } public abstract boolean isReadOnly(PsiField field); @@ -51,4 +63,27 @@ public abstract class GetterSetterPrototypeProvider { } return field.hasModifierProperty(PsiModifier.FINAL); } + + public static PsiMethod[] findGetters(PsiClass aClass, String propertyName, boolean isStatic) { + if (!isStatic) { + for (GetterSetterPrototypeProvider provider : Extensions.getExtensions(EP_NAME)) { + final PsiMethod[] getterSetter = provider.findGetters(aClass, propertyName); + if (getterSetter != null) return getterSetter; + } + } + final PsiMethod propertyGetterSetter = PropertyUtil.findPropertyGetter(aClass, propertyName, isStatic, false); + if (propertyGetterSetter != null) { + return new PsiMethod[] {propertyGetterSetter}; + } + return null; + } + + public static String suggestNewGetterName(String oldPropertyName, String newPropertyName, PsiMethod method) { + for (GetterSetterPrototypeProvider provider : Extensions.getExtensions(EP_NAME)) { + if (provider.isSimpleGetter(method, oldPropertyName)) { + return provider.suggestGetterName(newPropertyName); + } + } + return null; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java index 68c3684ff662..53630f602ef1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/OverrideImplementUtil.java @@ -435,17 +435,6 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { Collection<CandidateInfo> secondary = toImplement || aClass.isInterface() ? ContainerUtil.<CandidateInfo>newArrayList() : getMethodsToOverrideImplement(aClass, true); - if (toImplement && PsiUtil.isLanguageLevel8OrHigher(aClass)) { - for (Iterator<CandidateInfo> iterator = candidates.iterator(); iterator.hasNext(); ) { - CandidateInfo candidate = iterator.next(); - PsiElement element = candidate.getElement(); - if (element instanceof PsiMethod && ((PsiMethod)element).hasModifierProperty(PsiModifier.DEFAULT)) { - iterator.remove(); - secondary.add(candidate); - } - } - } - final MemberChooser<PsiMethodMember> chooser = showOverrideImplementChooser(editor, aClass, toImplement, candidates, secondary); if (chooser == null) return; @@ -461,6 +450,9 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { }.execute(); } + /** + * @param candidates, secondary should allow modifications + */ @Nullable public static MemberChooser<PsiMethodMember> showOverrideImplementChooser(Editor editor, final PsiElement aClass, @@ -468,6 +460,17 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { final Collection<CandidateInfo> candidates, Collection<CandidateInfo> secondary) { + if (toImplement && PsiUtil.isLanguageLevel8OrHigher(aClass)) { + for (Iterator<CandidateInfo> iterator = candidates.iterator(); iterator.hasNext(); ) { + CandidateInfo candidate = iterator.next(); + PsiElement element = candidate.getElement(); + if (element instanceof PsiMethod && ((PsiMethod)element).hasModifierProperty(PsiModifier.DEFAULT)) { + iterator.remove(); + secondary.add(candidate); + } + } + } + final JavaOverrideImplementMemberChooser chooser = JavaOverrideImplementMemberChooser.create(aClass, toImplement, candidates, secondary); if (chooser == null) { @@ -612,7 +615,7 @@ public class OverrideImplementUtil extends OverrideImplementExploreUtil { finally { PsiFile psiFile = psiClass.getContainingFile(); - Editor editor = fileEditorManager.openTextEditor(new OpenFileDescriptor(psiFile.getProject(), psiFile.getVirtualFile()), false); + Editor editor = fileEditorManager.openTextEditor(new OpenFileDescriptor(psiFile.getProject(), psiFile.getVirtualFile()), true); if (editor != null && !results.isEmpty()) { results.get(0).positionCaret(editor, true); editor.getScrollingModel().scrollToCaret(ScrollType.CENTER); diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/PropertyClassMember.java b/java/java-impl/src/com/intellij/codeInsight/generation/PropertyClassMember.java index 006e5e539932..7c5378f8286f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/PropertyClassMember.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/PropertyClassMember.java @@ -15,6 +15,7 @@ */ package com.intellij.codeInsight.generation; +import com.intellij.psi.PsiClass; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nullable; @@ -25,13 +26,15 @@ import org.jetbrains.annotations.Nullable; public interface PropertyClassMember extends EncapsulatableClassMember { /** * @return PsiElement or TemplateGenerationInfo + * @param aClass */ @Nullable - GenerationInfo[] generateGetters() throws IncorrectOperationException; + GenerationInfo[] generateGetters(PsiClass aClass) throws IncorrectOperationException; /** * @return PsiElement or TemplateGenerationInfo + * @param aClass */ @Nullable - GenerationInfo[] generateSetters() throws IncorrectOperationException; + GenerationInfo[] generateSetters(PsiClass aClass) throws IncorrectOperationException; } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/PsiFieldMember.java b/java/java-impl/src/com/intellij/codeInsight/generation/PsiFieldMember.java index a4817c51c320..a14108b0fdd2 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/PsiFieldMember.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/PsiFieldMember.java @@ -42,38 +42,37 @@ public class PsiFieldMember extends PsiElementClassMember<PsiField> implements P @Nullable @Override public GenerationInfo generateGetter() throws IncorrectOperationException { - final GenerationInfo[] infos = generateGetters(); + final GenerationInfo[] infos = generateGetters(getElement().getContainingClass()); return infos != null && infos.length > 0 ? infos[0] : null; } @Nullable @Override - public GenerationInfo[] generateGetters() throws IncorrectOperationException { - final PsiField field = getElement(); - return createGenerateInfos(field, GetterSetterPrototypeProvider.generateGetterSetters(field, true)); + public GenerationInfo[] generateGetters(PsiClass aClass) throws IncorrectOperationException { + return createGenerateInfos(aClass, GetterSetterPrototypeProvider.generateGetterSetters(getElement(), true)); } @Nullable @Override public GenerationInfo generateSetter() throws IncorrectOperationException { - final GenerationInfo[] infos = generateSetters(); + final GenerationInfo[] infos = generateSetters(getElement().getContainingClass()); return infos != null && infos.length > 0 ? infos[0] : null; } @Override @Nullable - public GenerationInfo[] generateSetters() { + public GenerationInfo[] generateSetters(PsiClass aClass) { final PsiField field = getElement(); if (GetterSetterPrototypeProvider.isReadOnlyProperty(field)) { return null; } - return createGenerateInfos(field, GetterSetterPrototypeProvider.generateGetterSetters(field, false)); + return createGenerateInfos(aClass, GetterSetterPrototypeProvider.generateGetterSetters(field, false)); } - private static GenerationInfo[] createGenerateInfos(PsiField field, PsiMethod[] prototypes) { + private static GenerationInfo[] createGenerateInfos(PsiClass aClass, PsiMethod[] prototypes) { final List<GenerationInfo> methods = new ArrayList<GenerationInfo>(); for (PsiMethod prototype : prototypes) { - final PsiMethod method = createMethodIfNotExists(field, prototype); + final PsiMethod method = createMethodIfNotExists(aClass, prototype); if (method != null) { methods.add(new PsiGenerationInfo(method)); } @@ -82,8 +81,7 @@ public class PsiFieldMember extends PsiElementClassMember<PsiField> implements P } @Nullable - private static PsiMethod createMethodIfNotExists(final PsiField field, final PsiMethod template) { - final PsiClass aClass = field.getContainingClass(); + private static PsiMethod createMethodIfNotExists(PsiClass aClass, final PsiMethod template) { PsiMethod existing = aClass.findMethodBySignature(template, false); if (existing == null) { if (template != null) { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/actions/GenerateCreateUIAction.java b/java/java-impl/src/com/intellij/codeInsight/generation/actions/GenerateCreateUIAction.java index dee80a6a682d..16ec3cc9b1de 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/actions/GenerateCreateUIAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/actions/GenerateCreateUIAction.java @@ -17,6 +17,7 @@ package com.intellij.codeInsight.generation.actions; import com.intellij.psi.*; import com.intellij.psi.util.PsiTypesUtil; +import com.intellij.util.containers.HashSet; /** * @author Konstantin Bulenkov @@ -27,12 +28,12 @@ public class GenerateCreateUIAction extends BaseGenerateAction { } @Override - protected boolean isValidForClass(PsiClass targetClass) { + public boolean isValidForClass(PsiClass targetClass) { final PsiModifierList list = targetClass.getModifierList(); return list != null && !list.hasModifierProperty(PsiModifier.ABSTRACT) && !hasCreateUIMethod(targetClass) - && isComponentUI(targetClass); + && isComponentUI(targetClass, new HashSet<PsiClass>()); } private static boolean hasCreateUIMethod(PsiClass aClass) { @@ -49,8 +50,9 @@ public class GenerateCreateUIAction extends BaseGenerateAction { return false; } - private static boolean isComponentUI(PsiClass aClass) { + private static boolean isComponentUI(PsiClass aClass, HashSet<PsiClass> classes) { while (aClass != null) { + if (!classes.add(aClass)) return false; if ("javax.swing.plaf.ComponentUI".equals(aClass.getQualifiedName())) { return true; } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java index c9a13f65e8a1..e757ddeacc17 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.generation.surroundWith; import com.intellij.codeInsight.CodeInsightBundle; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorModificationUtil; @@ -28,6 +29,8 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; class JavaWithTryFinallySurrounder extends JavaStatementsSurrounder{ + private static final Logger LOG = Logger.getInstance("#" + JavaWithTryFinallySurrounder.class.getName()); + @Override public String getTemplateDescription() { return CodeInsightBundle.message("surround.with.try.finally.template"); @@ -67,7 +70,9 @@ class JavaWithTryFinallySurrounder extends JavaStatementsSurrounder{ final Document document = editor.getDocument(); PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document); editor.getSelectionModel().removeSelection(); - final PsiStatement firstTryStmt = tryBlock.getStatements()[0]; + final PsiStatement[] tryBlockStatements = tryBlock.getStatements(); + LOG.assertTrue(tryBlockStatements.length > 0, tryBlock.getText()); + final PsiStatement firstTryStmt = tryBlockStatements[0]; final int indent = firstTryStmt.getTextOffset() - document.getLineStartOffset(document.getLineNumber(firstTryStmt.getTextOffset())); EditorModificationUtil.insertStringAtCaret(editor, StringUtil.repeat(" ", indent), false, true); return new TextRange(editor.getCaretModel().getOffset(), editor.getCaretModel().getOffset()); diff --git a/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightSuppressedWarningsHandler.java b/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightSuppressedWarningsHandler.java index 2e92545483f9..9d6fe8845a82 100644 --- a/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightSuppressedWarningsHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightSuppressedWarningsHandler.java @@ -25,11 +25,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.LocalInspectionsPass; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.InspectionProfile; -import com.intellij.codeInspection.InspectionProfileEntry; -import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; -import com.intellij.codeInspection.ex.InspectionManagerEx; -import com.intellij.codeInspection.ex.InspectionProfileImpl; -import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; +import com.intellij.codeInspection.ex.*; import com.intellij.codeInspection.reference.RefManagerImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; @@ -122,20 +118,20 @@ public class HighlightSuppressedWarningsHandler extends HighlightUsagesHandlerBa if (!(value instanceof String)) { continue; } - final InspectionProfileEntry toolById = ((InspectionProfileImpl)inspectionProfile).getToolById((String)value, target); - if (!(toolById instanceof LocalInspectionToolWrapper)) { + InspectionToolWrapper toolWrapperById = ((InspectionProfileImpl)inspectionProfile).getToolById((String)value, target); + if (!(toolWrapperById instanceof LocalInspectionToolWrapper)) { continue; } - final LocalInspectionToolWrapper tool = ((LocalInspectionToolWrapper)toolById).createCopy(); + final LocalInspectionToolWrapper toolWrapper = ((LocalInspectionToolWrapper)toolWrapperById).createCopy(); final InspectionManagerEx managerEx = (InspectionManagerEx)InspectionManager.getInstance(project); final GlobalInspectionContextImpl context = managerEx.createNewGlobalContext(false); - tool.initialize(context); + toolWrapper.initialize(context); ((RefManagerImpl)context.getRefManager()).inspectionReadActionStarted(); ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); Runnable inspect = new Runnable() { @Override public void run() { - pass.doInspectInBatch(managerEx, Collections.<LocalInspectionToolWrapper>singletonList(tool)); + pass.doInspectInBatch(managerEx, Collections.<LocalInspectionToolWrapper>singletonList(toolWrapper)); } }; if (indicator == null) { diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConcatenationToMessageFormatAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConcatenationToMessageFormatAction.java index 544440fa3e21..9bc47e30f1fa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConcatenationToMessageFormatAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConcatenationToMessageFormatAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -25,7 +25,6 @@ import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiConcatenationUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -60,7 +59,7 @@ public class ConcatenationToMessageFormatAction implements IntentionAction { if (concatenation == null) return; StringBuilder formatString = new StringBuilder(); List<PsiExpression> args = new ArrayList<PsiExpression>(); - buildMessageFormatString(concatenation, formatString, args); + PsiConcatenationUtil.buildFormatString(concatenation, formatString, args, false); final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); PsiMethodCallExpression call = (PsiMethodCallExpression) @@ -87,47 +86,6 @@ public class ConcatenationToMessageFormatAction implements IntentionAction { concatenation.replace(call); } - public static void buildMessageFormatString(PsiExpression expression, - StringBuilder formatString, - List<PsiExpression> args) - throws IncorrectOperationException { - PsiConcatenationUtil.buildFormatString(expression, formatString, args, false); - - } - - private static void appendArgument(List<PsiExpression> args, PsiExpression argument, StringBuilder formatString) throws IncorrectOperationException { - formatString.append("{").append(args.size()).append("}"); - args.add(getBoxedArgument(argument)); - } - - private static PsiExpression getBoxedArgument(PsiExpression arg) throws IncorrectOperationException { - arg = PsiUtil.deparenthesizeExpression(arg); - assert arg != null; - if (PsiUtil.isLanguageLevel5OrHigher(arg)) { - return arg; - } - final PsiType type = arg.getType(); - if (!(type instanceof PsiPrimitiveType) || type.equals(PsiType.NULL)) { - return arg; - } - final PsiPrimitiveType primitiveType = (PsiPrimitiveType)type; - final String boxedQName = primitiveType.getBoxedTypeName(); - if (boxedQName == null) { - return arg; - } - final GlobalSearchScope resolveScope = arg.getResolveScope(); - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(arg.getProject()); - final PsiJavaCodeReferenceElement ref = factory.createReferenceElementByFQClassName(boxedQName, resolveScope); - final PsiNewExpression newExpr = (PsiNewExpression)factory.createExpressionFromText("new A(b)", null); - final PsiElement classRef = newExpr.getClassReference(); - assert classRef != null; - classRef.replace(ref); - final PsiExpressionList argumentList = newExpr.getArgumentList(); - assert argumentList != null; - argumentList.getExpressions()[0].replace(arg); - return newExpr; - } - @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { if (PsiUtil.getLanguageLevel(file).compareTo(LanguageLevel.JDK_1_4) < 0) return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java index 51089f5263b2..7b6961145926 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/SplitDeclarationAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -18,6 +18,7 @@ package com.intellij.codeInsight.intention.impl; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; @@ -42,6 +43,7 @@ public class SplitDeclarationAction extends PsiElementBaseIntentionAction { if (element instanceof PsiCompiledElement) return false; if (!element.getManager().isInProject(element)) return false; + if (!element.getLanguage().isKindOf(JavaLanguage.INSTANCE)) return false; final PsiElement context = PsiTreeUtil.getParentOfType(element, PsiDeclarationStatement.class, PsiClass.class); if (context instanceof PsiDeclarationStatement) { diff --git a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocExternalFilter.java b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocExternalFilter.java index 1713f6ba0454..cac3b57eb90d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocExternalFilter.java +++ b/java/java-impl/src/com/intellij/codeInsight/javadoc/JavaDocExternalFilter.java @@ -59,7 +59,7 @@ public class JavaDocExternalFilter extends AbstractExternalFilter { protected static @NonNls final Pattern ourAnchorsuffix = Pattern.compile("#(.*)$"); protected static @NonNls final Pattern ourHTMLFilesuffix = Pattern.compile("/([^/]*[.][hH][tT][mM][lL]?)$"); private static @NonNls final Pattern ourHREFselector = Pattern.compile("<A.*?HREF=\"([^>\"]*)\"", Pattern.CASE_INSENSITIVE|Pattern.DOTALL); - private static @NonNls final Pattern ourMethodHeading = Pattern.compile("<H3>(.+?)</H3>", Pattern.CASE_INSENSITIVE|Pattern.DOTALL); + private static @NonNls final Pattern ourMethodHeading = Pattern.compile("<H[34]>(.+?)</H[34]>", Pattern.CASE_INSENSITIVE|Pattern.DOTALL); protected static @NonNls final String DOC_ELEMENT_PROTOCOL = "doc_element://"; @NonNls protected static final String H2 = "</H2>"; @NonNls protected static final String HTML_CLOSE = "</HTML>"; diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java index 9fa4834de1c5..db14ecafdff3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java @@ -169,8 +169,9 @@ public class VariableLookupItem extends LookupItem<PsiVariable> implements Typed PsiClass containingClass = field.getContainingClass(); if (containingClass != null && containingClass.getName() != null) { - context.getDocument().insertString(context.getStartOffset(), "."); + OffsetKey oldStart = context.trackOffset(context.getStartOffset(), true); JavaCompletionUtil.insertClassReference(containingClass, file, context.getStartOffset()); + context.getDocument().insertString(context.getOffsetMap().getOffset(oldStart), "."); PsiDocumentManager.getInstance(context.getProject()).commitDocument(context.getDocument()); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/template/macro/MacroUtil.java b/java/java-impl/src/com/intellij/codeInsight/template/macro/MacroUtil.java index 059c0471eebb..6010a7a4b41f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/macro/MacroUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/macro/MacroUtil.java @@ -27,11 +27,13 @@ import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Set; public class MacroUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.template.macro.MacroUtil"); @@ -158,11 +160,15 @@ public class MacroUtil { return new PsiVariable[0]; } + final Set<String> usedNames = ContainerUtil.newHashSet(); final List<PsiVariable> list = new ArrayList<PsiVariable>(); VariablesProcessor varproc = new VariablesProcessor(prefix, true, list) { @Override public boolean execute(@NotNull PsiElement pe, ResolveState state) { if (pe instanceof PsiVariable) { + if (!usedNames.add(((PsiVariable)pe).getName())) { + return false; + } //exclude variables that are initialized in 'place' final PsiExpression initializer = ((PsiVariable)pe).getInitializer(); if (initializer != null && PsiTreeUtil.isAncestor(initializer, place, false)) return true; diff --git a/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java b/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java index f65d58051522..354af57cf7d1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/RedundantSuppressInspection.java @@ -19,10 +19,8 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInsight.daemon.impl.RemoveSuppressWarningAction; import com.intellij.codeInspection.ex.*; -import com.intellij.codeInspection.reference.RefClass; -import com.intellij.codeInspection.reference.RefElement; -import com.intellij.codeInspection.reference.RefJavaVisitor; -import com.intellij.codeInspection.reference.RefManagerImpl; +import com.intellij.codeInspection.reference.*; +import com.intellij.codeInspection.ui.InspectionToolPresentation; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -116,7 +114,7 @@ public class RedundantSuppressInspection extends GlobalInspectionTool{ return checkElement(psiClass, manager, project); } - public CommonProblemDescriptor[] checkElement(@NotNull final PsiElement psiElement, @NotNull InspectionManager manager, @NotNull Project project) { + public CommonProblemDescriptor[] checkElement(@NotNull final PsiElement psiElement, @NotNull final InspectionManager manager, @NotNull Project project) { final Map<PsiElement, Collection<String>> suppressedScopes = new THashMap<PsiElement, Collection<String>>(); psiElement.accept(new JavaRecursiveElementWalkingVisitor() { @Override public void visitModifierList(PsiModifierList list) { @@ -141,7 +139,7 @@ public class RedundantSuppressInspection extends GlobalInspectionTool{ private void checkElement(final PsiElement owner) { String idsString = SuppressManager.getInstance().getSuppressedInspectionIdsIn(owner); - if (idsString != null && idsString.length() != 0) { + if (idsString != null && !idsString.isEmpty()) { List<String> ids = StringUtil.split(idsString, ","); if (IGNORE_ALL && (ids.contains(SuppressionUtil.ALL) || ids.contains(SuppressionUtil.ALL.toLowerCase()))) return; Collection<String> suppressed = suppressedScopes.get(owner); @@ -162,27 +160,29 @@ public class RedundantSuppressInspection extends GlobalInspectionTool{ if (suppressedScopes.values().isEmpty()) return null; // have to visit all file from scratch since inspections can be written in any perversive way including checkFile() overriding - Collection<InspectionTool> suppressedTools = new THashSet<InspectionTool>(); - InspectionTool[] tools = getInspectionTools(psiElement, manager); + Collection<InspectionToolWrapper> suppressedTools = new THashSet<InspectionToolWrapper>(); + InspectionToolWrapper[] toolWrappers = getInspectionTools(psiElement, manager); for (Collection<String> ids : suppressedScopes.values()) { for (Iterator<String> iterator = ids.iterator(); iterator.hasNext(); ) { final String shortName = iterator.next().trim(); - for (InspectionTool tool : tools) { - if (tool instanceof LocalInspectionToolWrapper && ((LocalInspectionToolWrapper)tool).getTool().getID().equals(shortName)) { - if (!((LocalInspectionToolWrapper)tool).isUnfair()) { - suppressedTools.add(tool); - } else { + for (InspectionToolWrapper toolWrapper : toolWrappers) { + if (toolWrapper instanceof LocalInspectionToolWrapper && ((LocalInspectionToolWrapper)toolWrapper).getTool().getID().equals(shortName)) { + if (((LocalInspectionToolWrapper)toolWrapper).isUnfair()) { iterator.remove(); break; } + else { + suppressedTools.add(toolWrapper); + } } - else if (tool.getShortName().equals(shortName)) { + else if (toolWrapper.getShortName().equals(shortName)) { //ignore global unused as it won't be checked anyway - if (!(tool instanceof LocalInspectionToolWrapper) && !(tool instanceof GlobalInspectionToolWrapper)) { + if (toolWrapper instanceof LocalInspectionToolWrapper || toolWrapper instanceof GlobalInspectionToolWrapper) { + suppressedTools.add(toolWrapper); + } + else { iterator.remove(); break; - } else { - suppressedTools.add(tool); } } } @@ -190,31 +190,44 @@ public class RedundantSuppressInspection extends GlobalInspectionTool{ } final AnalysisScope scope = new AnalysisScope(psiElement.getContainingFile()); - final InspectionManagerEx inspectionManagerEx = ((InspectionManagerEx)InspectionManager.getInstance(project)); - GlobalInspectionContextImpl globalContext = inspectionManagerEx.createNewGlobalContext(false); + final InspectionManagerEx inspectionManagerEx = (InspectionManagerEx)InspectionManager.getInstance(project); + final GlobalInspectionContextImpl globalContext = inspectionManagerEx.createNewGlobalContext(false); globalContext.setCurrentScope(scope); - final RefManagerImpl refManager = ((RefManagerImpl)globalContext.getRefManager()); + final RefManagerImpl refManager = (RefManagerImpl)globalContext.getRefManager(); refManager.inspectionReadActionStarted(); final List<ProblemDescriptor> result; try { result = new ArrayList<ProblemDescriptor>(); - for (InspectionTool tool : suppressedTools) { - String toolId = tool instanceof LocalInspectionToolWrapper ? ((LocalInspectionToolWrapper)tool).getTool().getID() : tool.getShortName(); - tool.initialize(globalContext); + for (InspectionToolWrapper toolWrapper : suppressedTools) { + String toolId = toolWrapper instanceof LocalInspectionToolWrapper ? ((LocalInspectionToolWrapper)toolWrapper).getTool().getID() : toolWrapper.getShortName(); + toolWrapper.initialize(globalContext); Collection<CommonProblemDescriptor> descriptors; - if (tool instanceof LocalInspectionToolWrapper) { - LocalInspectionToolWrapper local = (LocalInspectionToolWrapper)tool; + final InspectionToolPresentation presentation = globalContext.getPresentation(toolWrapper); + if (toolWrapper instanceof LocalInspectionToolWrapper) { + LocalInspectionToolWrapper local = (LocalInspectionToolWrapper)toolWrapper; if (local.isUnfair()) continue; //cant't work with passes other than LocalInspectionPass - local.processFile(psiElement.getContainingFile(), false, manager); - descriptors = local.getProblemDescriptors(); + List<ProblemDescriptor> results = local.getTool().processFile(psiElement.getContainingFile(), manager); + InspectionToolPresentation toolPresentation = globalContext.getPresentation(local); + LocalDescriptorsUtil.addProblemDescriptors(results, toolPresentation, false, globalContext, local.getTool()); + descriptors = presentation.getProblemDescriptors(); } - else if (tool instanceof GlobalInspectionToolWrapper) { - GlobalInspectionToolWrapper global = (GlobalInspectionToolWrapper)tool; - if (global.getTool().isGraphNeeded()) { + else if (toolWrapper instanceof GlobalInspectionToolWrapper) { + final GlobalInspectionToolWrapper global = (GlobalInspectionToolWrapper)toolWrapper; + GlobalInspectionTool globalTool = global.getTool(); + if (globalTool.isGraphNeeded()) { refManager.findAllDeclarations(); } - global.processFile(scope, manager, globalContext, false); - descriptors = global.getProblemDescriptors(); + final InspectionToolPresentation toolPresentation = globalContext.getPresentation(global); + globalContext.getRefManager().iterate(new RefVisitor() { + @Override public void visitElement(@NotNull RefEntity refEntity) { + CommonProblemDescriptor[] + descriptors1 = global.getTool().checkElement(refEntity, scope, manager, globalContext, toolPresentation); + if (descriptors1 != null) { + toolPresentation.addProblemElement(refEntity, false, descriptors1); + } + } + }); + descriptors = presentation.getProblemDescriptors(); } else { continue; @@ -283,9 +296,8 @@ public class RedundantSuppressInspection extends GlobalInspectionTool{ return result.toArray(new ProblemDescriptor[result.size()]); } - protected InspectionTool[] getInspectionTools(PsiElement psiElement, InspectionManager manager) { - final ModifiableModel - model = InspectionProjectProfileManager.getInstance(manager.getProject()).getInspectionProfile().getModifiableModel(); + protected InspectionToolWrapper[] getInspectionTools(PsiElement psiElement, @NotNull InspectionManager manager) { + ModifiableModel model = InspectionProjectProfileManager.getInstance(manager.getProject()).getInspectionProfile().getModifiableModel(); InspectionProfileWrapper profile = new InspectionProfileWrapper((InspectionProfile)model); profile.init(manager.getProject()); diff --git a/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java b/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java index 35a997fc3b9c..105bee1c4449 100644 --- a/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java @@ -177,7 +177,8 @@ public class CanBeFinalInspection extends GlobalJavaInspectionTool { } @Override - protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, @NotNull final GlobalJavaInspectionContext globalContext, + protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, + @NotNull final GlobalJavaInspectionContext globalContext, @NotNull final ProblemDescriptionsProcessor problemsProcessor) { for (RefElement entryPoint : globalContext.getEntryPointsManager(manager).getEntryPoints()) { problemsProcessor.ignoreElement(entryPoint); diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java index 348d3dfc5fa5..c22571a65287 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspection.java @@ -46,6 +46,7 @@ public class DataFlowInspection extends DataFlowInspectionBase { } private class OptionsPanel extends JPanel { + private final JCheckBox myIgnoreAssertions; private final JCheckBox mySuggestNullables; private final JCheckBox myDontReportTrueAsserts; @@ -77,6 +78,15 @@ public class DataFlowInspection extends DataFlowInspectionBase { DONT_REPORT_TRUE_ASSERT_STATEMENTS = myDontReportTrueAsserts.isSelected(); } }); + + myIgnoreAssertions = new JCheckBox("Ignore assert statements"); + myIgnoreAssertions.setSelected(IGNORE_ASSERT_STATEMENTS); + myIgnoreAssertions.getModel().addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent e) { + IGNORE_ASSERT_STATEMENTS = myIgnoreAssertions.isSelected(); + } + }); gc.insets = new Insets(0, 0, 0, 0); gc.gridy = 0; @@ -121,6 +131,9 @@ public class DataFlowInspection extends DataFlowInspectionBase { gc.insets.left = 0; gc.gridy++; add(myDontReportTrueAsserts, gc); + + gc.gridy++; + add(myIgnoreAssertions, gc); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/DeadHTMLComposer.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/DeadHTMLComposer.java index 9b5cb309cc3b..88f56186fc8e 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/DeadHTMLComposer.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/DeadHTMLComposer.java @@ -28,8 +28,8 @@ import com.intellij.codeInspection.HTMLJavaHTMLComposer; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ex.DescriptorComposer; import com.intellij.codeInspection.ex.HTMLComposerImpl; -import com.intellij.codeInspection.ex.InspectionTool; import com.intellij.codeInspection.reference.*; +import com.intellij.codeInspection.ui.InspectionToolPresentation; import com.intellij.codeInspection.ui.InspectionTreeNode; import com.intellij.codeInspection.ui.RefElementNode; import org.jetbrains.annotations.NonNls; @@ -41,11 +41,11 @@ import java.util.Iterator; import java.util.Set; public class DeadHTMLComposer extends HTMLComposerImpl { - private final InspectionTool myTool; + private final InspectionToolPresentation myToolPresentation; private final HTMLJavaHTMLComposer myComposer; - public DeadHTMLComposer(@NotNull InspectionTool tool) { - myTool = tool; + public DeadHTMLComposer(@NotNull InspectionToolPresentation presentation) { + myToolPresentation = presentation; myComposer = getExtension(HTMLJavaHTMLComposer.COMPOSER); } @@ -64,7 +64,7 @@ public class DeadHTMLComposer extends HTMLComposerImpl { //noinspection HardCodedStringLiteral buf.append("<br><br>"); - appendResolution(buf, refElement, DescriptorComposer.quickFixTexts(refElement, myTool)); + appendResolution(buf, refElement, DescriptorComposer.quickFixTexts(refElement, myToolPresentation)); refElement.accept(new RefJavaVisitor() { @Override public void visitClass(@NotNull RefClass aClass) { appendClassInstantiations(buf, aClass); @@ -339,7 +339,7 @@ public class DeadHTMLComposer extends HTMLComposerImpl { } private void appendCallesList(RefElement element, StringBuffer buf, Set<RefElement> mentionedElements, boolean appendCallees){ - final Set<RefElement> possibleChildren = getPossibleChildren(new RefElementNode(element, myTool), element); + final Set<RefElement> possibleChildren = getPossibleChildren(new RefElementNode(element, myToolPresentation), element); if (!possibleChildren.isEmpty()) { if (appendCallees){ appendHeading(buf, InspectionsBundle.message("inspection.export.results.callees")); diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java new file mode 100644 index 000000000000..531c88c03f62 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInspection.deadCode; + +import com.intellij.codeInspection.InspectionsBundle; +import com.intellij.codeInspection.ex.*; +import com.intellij.codeInspection.reference.RefElement; +import com.intellij.codeInspection.reference.RefEntity; +import com.intellij.codeInspection.ui.InspectionNode; +import com.intellij.codeInspection.ui.InspectionTreeNode; +import com.intellij.codeInspection.util.RefFilter; +import org.jetbrains.annotations.NotNull; + +public class DummyEntryPointsPresentation extends UnusedDeclarationPresentation { + private static final RefEntryPointFilter myFilter = new RefEntryPointFilter(); + private QuickFixAction[] myQuickFixActions; + + public DummyEntryPointsPresentation(UnusedDeclarationInspection inspection, @NotNull InspectionToolWrapper toolWrapper) { + super(toolWrapper); + } + + @Override + public RefFilter getFilter() { + return myFilter; + } + + @Override + public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) { + if (myQuickFixActions == null) { + myQuickFixActions = new QuickFixAction[]{new MoveEntriesToSuspicious(getToolWrapper())}; + } + return myQuickFixActions; + } + + private class MoveEntriesToSuspicious extends QuickFixAction { + private MoveEntriesToSuspicious(@NotNull InspectionToolWrapper toolWrapper) { + super(InspectionsBundle.message("inspection.dead.code.remove.from.entry.point.quickfix"), null, null, toolWrapper); + } + + @Override + protected boolean applyFix(RefEntity[] refElements) { + final EntryPointsManager entryPointsManager = + getContext().getExtension(GlobalJavaInspectionContextImpl.CONTEXT).getEntryPointsManager(getContext().getRefManager()); + for (RefEntity refElement : refElements) { + if (refElement instanceof RefElement) { + entryPointsManager.removeEntryPoint((RefElement)refElement); + } + } + + return true; + } + } + + @NotNull + @Override + public InspectionNode createToolNode(@NotNull GlobalInspectionContextImpl context, @NotNull InspectionNode node, + @NotNull InspectionRVContentProvider provider, + @NotNull InspectionTreeNode parentNode, + boolean showStructure) { + return node; + } + + @Override + @NotNull + public HTMLComposerImpl getComposer() { + return new DeadHTMLComposer(this); + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsTool.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsTool.java index 1b8ef7435111..524f3338fad1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsTool.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsTool.java @@ -19,39 +19,31 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.codeInspection.GlobalInspectionContext; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.ex.*; -import com.intellij.codeInspection.reference.RefElement; -import com.intellij.codeInspection.reference.RefEntity; -import com.intellij.codeInspection.util.RefFilter; -import org.jdom.Element; +import com.intellij.codeInspection.ProblemDescriptionsProcessor; +import com.intellij.codeInspection.ex.InspectionPresentationProvider; +import com.intellij.codeInspection.ex.InspectionToolWrapper; +import com.intellij.codeInspection.ex.JobDescriptor; +import com.intellij.codeInspection.ui.InspectionToolPresentation; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author max */ -public class DummyEntryPointsTool extends FilteringInspectionTool { - private static final RefEntryPointFilter myFilter = new RefEntryPointFilter(); - private QuickFixAction[] myQuickFixActions; - - public DummyEntryPointsTool(@NotNull UnusedDeclarationInspection owner) { - initialize(owner.getContext()); +public class DummyEntryPointsTool extends UnusedDeclarationInspection implements InspectionPresentationProvider { + public DummyEntryPointsTool() { } @Override - public RefFilter getFilter() { - return myFilter; + public void runInspection(@NotNull AnalysisScope scope, + @NotNull InspectionManager manager, + @NotNull GlobalInspectionContext globalContext, + @NotNull ProblemDescriptionsProcessor problemDescriptionsProcessor) { } + @Nullable @Override - public void runInspection(@NotNull AnalysisScope scope, @NotNull final InspectionManager manager) {} - - @Override - public void exportResults(@NotNull Element parentNode, @NotNull RefEntity refEntity) { - } - - @Override - @NotNull - public JobDescriptor[] getJobDescriptors(@NotNull GlobalInspectionContext globalInspectionContext) { + public JobDescriptor[] getAdditionalJobs() { return JobDescriptor.EMPTY_ARRAY; } @@ -73,34 +65,9 @@ public class DummyEntryPointsTool extends FilteringInspectionTool { return ""; } - @Override @NotNull - public HTMLComposerImpl getComposer() { - return new DeadHTMLComposer(this); - } - @Override - public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) { - if (myQuickFixActions == null) { - myQuickFixActions = new QuickFixAction[]{new MoveEntriesToSuspicious()}; - } - return myQuickFixActions; - } - - private class MoveEntriesToSuspicious extends QuickFixAction { - private MoveEntriesToSuspicious() { - super(InspectionsBundle.message("inspection.dead.code.remove.from.entry.point.quickfix"), null, null, DummyEntryPointsTool.this); - } - - @Override - protected boolean applyFix(RefElement[] refElements) { - final EntryPointsManager entryPointsManager = - getContext().getExtension(GlobalJavaInspectionContextImpl.CONTEXT).getEntryPointsManager(getContext().getRefManager()); - for (RefElement refElement : refElements) { - entryPointsManager.removeEntryPoint(refElement); - } - - return true; - } + public InspectionToolPresentation createPresentation(@NotNull InspectionToolWrapper toolWrapper) { + return new DummyEntryPointsPresentation(this, toolWrapper); } } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/RefUnreachableFilter.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/RefUnreachableFilter.java index 5984cf16b71a..b00d7490ecc7 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/RefUnreachableFilter.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/RefUnreachableFilter.java @@ -24,17 +24,19 @@ */ package com.intellij.codeInspection.deadCode; -import com.intellij.codeInspection.ex.InspectionTool; +import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; import com.intellij.codeInspection.reference.*; import com.intellij.codeInspection.util.RefFilter; import org.jetbrains.annotations.NotNull; public class RefUnreachableFilter extends RefFilter { @NotNull - protected InspectionTool myTool; + protected UnusedDeclarationInspection myTool; + @NotNull protected final GlobalInspectionContextImpl myContext; - public RefUnreachableFilter(@NotNull InspectionTool tool) { + public RefUnreachableFilter(@NotNull UnusedDeclarationInspection tool, @NotNull GlobalInspectionContextImpl context) { myTool = tool; + myContext = context; } @Override @@ -42,7 +44,7 @@ public class RefUnreachableFilter extends RefFilter { if (refElement instanceof RefParameter) return 0; if (refElement.isSyntheticJSP()) return 0; if (!(refElement instanceof RefMethod || refElement instanceof RefClass || refElement instanceof RefField)) return 0; - if (!myTool.getContext().isToCheckMember(refElement, myTool)) return 0; + if (!myContext.isToCheckMember(refElement, myTool)) return 0; return ((RefElementImpl)refElement).isSuspicious() ? 1 : 0; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnreferencedFilter.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnreferencedFilter.java index 32dc52252e95..923e5777f6d1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnreferencedFilter.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnreferencedFilter.java @@ -24,13 +24,13 @@ */ package com.intellij.codeInspection.deadCode; -import com.intellij.codeInspection.ex.InspectionTool; +import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; import com.intellij.codeInspection.reference.*; import org.jetbrains.annotations.NotNull; public class UnreferencedFilter extends RefUnreachableFilter { - public UnreferencedFilter(@NotNull InspectionTool tool) { - super(tool); + public UnreferencedFilter(@NotNull UnusedDeclarationInspection tool, @NotNull GlobalInspectionContextImpl context) { + super(tool, context); } @Override @@ -39,7 +39,7 @@ public class UnreferencedFilter extends RefUnreachableFilter { if (refElement.isEntry() || !((RefElementImpl)refElement).isSuspicious() || refElement.isSyntheticJSP()) return 0; if (!(refElement instanceof RefMethod || refElement instanceof RefClass || refElement instanceof RefField)) return 0; - if (!myTool.getContext().isToCheckMember(refElement, myTool)) return 0; + if (!myContext.isToCheckMember(refElement, myTool)) return 0; if (refElement instanceof RefField) { RefField refField = (RefField) refElement; diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java index fa341a05bd20..7799cc205f67 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java @@ -31,27 +31,17 @@ import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.daemon.GroupNames; import com.intellij.codeInsight.daemon.ImplicitUsageProvider; import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtilBase; -import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.*; import com.intellij.codeInspection.reference.*; -import com.intellij.codeInspection.ui.EntryPointsNode; -import com.intellij.codeInspection.ui.InspectionNode; -import com.intellij.codeInspection.ui.InspectionTreeNode; +import com.intellij.codeInspection.ui.InspectionToolPresentation; import com.intellij.codeInspection.util.RefFilter; -import com.intellij.icons.AllIcons; -import com.intellij.lang.annotation.HighlightSeverity; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.extensions.ExtensionPoint; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.InvalidDataException; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.*; import com.intellij.psi.impl.PsiClassImplUtil; @@ -59,15 +49,9 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiNonJavaFileReferenceProcessor; import com.intellij.psi.search.PsiSearchHelper; import com.intellij.psi.util.PsiMethodUtil; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtilCore; -import com.intellij.refactoring.safeDelete.SafeDeleteHandler; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.SeparatorFactory; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.HashMap; -import com.intellij.util.text.CharArrayUtil; -import com.intellij.util.text.DateFormatUtil; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -77,40 +61,27 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; import java.util.*; import java.util.List; -public class UnusedDeclarationInspection extends FilteringInspectionTool { +public class UnusedDeclarationInspection extends GlobalInspectionTool implements InspectionPresentationProvider { public boolean ADD_MAINS_TO_ENTRIES = true; public boolean ADD_APPLET_TO_ENTRIES = true; public boolean ADD_SERVLET_TO_ENTRIES = true; public boolean ADD_NONJAVA_TO_ENTRIES = true; - private HashSet<RefElement> myProcessedSuspicious = null; + private Set<RefElement> myProcessedSuspicious = null; private int myPhase; - private final QuickFixAction[] myQuickFixActions; public static final String DISPLAY_NAME = InspectionsBundle.message("inspection.dead.code.display.name"); - private WeakUnreferencedFilter myFilter; - private DeadHTMLComposer myComposer; @NonNls public static final String SHORT_NAME = "UnusedDeclaration"; @NonNls private static final String ALTERNATIVE_ID = "unused"; - private static final String COMMENT_OUT_QUICK_FIX = InspectionsBundle.message("inspection.dead.code.comment.quickfix"); - private static final String DELETE_QUICK_FIX = InspectionsBundle.message("inspection.dead.code.safe.delete.quickfix"); - - @NonNls private static final String DELETE = "delete"; - @NonNls private static final String COMMENT = "comment"; - @NonNls private static final String [] HINTS = {COMMENT, DELETE}; - public final EntryPoint[] myExtensions; private static final Logger LOG = Logger.getInstance("#" + UnusedDeclarationInspection.class.getName()); + private GlobalInspectionContextImpl myContext; public UnusedDeclarationInspection() { - - myQuickFixActions = new QuickFixAction[]{new PermanentDeleteAction(), new CommentOutBin(), new MoveToEntries()}; ExtensionPoint<EntryPoint> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.DEAD_CODE_TOOL); final EntryPoint[] deadCodeAddins = new EntryPoint[point.getExtensions().length]; EntryPoint[] extensions = point.getExtensions(); @@ -132,10 +103,8 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { myExtensions = deadCodeAddins; } - @Override - public void initialize(@NotNull final GlobalInspectionContextImpl context) { - super.initialize(context); - ((EntryPointsManagerImpl)getEntryPointsManager()).setAddNonJavaEntries(ADD_NONJAVA_TO_ENTRIES); + private GlobalInspectionContextImpl getContext() { + return myContext; } private class OptionsPanel extends JPanel { @@ -368,9 +337,13 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { } @Override - public void runInspection(@NotNull final AnalysisScope scope, @NotNull final InspectionManager manager) { - getRefManager().iterate(new RefJavaVisitor() { - @Override public void visitElement(@NotNull final RefEntity refEntity) { + public void runInspection(@NotNull final AnalysisScope scope, + @NotNull InspectionManager manager, + @NotNull final GlobalInspectionContext globalContext, + @NotNull ProblemDescriptionsProcessor problemDescriptionsProcessor) { + globalContext.getRefManager().iterate(new RefJavaVisitor() { + @Override + public void visitElement(@NotNull final RefEntity refEntity) { if (refEntity instanceof RefJavaElement) { final RefElementImpl refElement = (RefElementImpl)refEntity; if (!refElement.isSuspicious()) return; @@ -379,7 +352,7 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { if (file == null) return; final boolean isSuppressed = refElement.isSuppressed(getShortName(), ALTERNATIVE_ID); - if (!getContext().isToCheckFile(file, UnusedDeclarationInspection.this) || isSuppressed) { + if (!((GlobalInspectionContextImpl)globalContext).isToCheckFile(file, UnusedDeclarationInspection.this) || isSuppressed) { if (isSuppressed || !scope.contains(file)) { getEntryPointsManager().addEntryPoint(refElement, false); } @@ -387,13 +360,15 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { } refElement.accept(new RefJavaVisitor() { - @Override public void visitMethod(@NotNull RefMethod method) { + @Override + public void visitMethod(@NotNull RefMethod method) { if (isAddMainsEnabled() && method.isAppMain()) { getEntryPointsManager().addEntryPoint(method, false); } } - @Override public void visitClass(@NotNull RefClass aClass) { + @Override + public void visitClass(@NotNull RefClass aClass) { if (isAddAppletEnabled() && aClass.isApplet() || isAddServletEnabled() && aClass.isServlet()) { getEntryPointsManager().addEntryPoint(aClass, false); @@ -406,19 +381,21 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { if (isAddNonJavaUsedEnabled()) { checkForReachables(); + final StrictUnreferencedFilter strictUnreferencedFilter = new StrictUnreferencedFilter(this, + (GlobalInspectionContextImpl)globalContext); ProgressManager.getInstance().runProcess(new Runnable() { @Override public void run() { - final RefFilter filter = new StrictUnreferencedFilter(UnusedDeclarationInspection.this); - final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(getRefManager().getProject()); - getRefManager().iterate(new RefJavaVisitor() { - @Override public void visitElement(@NotNull final RefEntity refEntity) { - if (refEntity instanceof RefClass && filter.accepts((RefClass)refEntity)) { + final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(globalContext.getRefManager().getProject()); + globalContext.getRefManager().iterate(new RefJavaVisitor() { + @Override + public void visitElement(@NotNull final RefEntity refEntity) { + if (refEntity instanceof RefClass && strictUnreferencedFilter.accepts((RefClass)refEntity)) { findExternalClassReferences((RefClass)refEntity); } else if (refEntity instanceof RefMethod) { RefMethod refMethod = (RefMethod)refEntity; - if (refMethod.isConstructor() && filter.accepts(refMethod)) { + if (refMethod.isConstructor() && strictUnreferencedFilter.accepts(refMethod)) { findExternalClassReferences(refMethod.getOwnerClass()); } } @@ -436,7 +413,7 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { return false; } }, - GlobalSearchScope.projectScope(getContext().getProject())); + GlobalSearchScope.projectScope(globalContext.getProject())); } } }); @@ -514,9 +491,10 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { return false; } + private static class StrictUnreferencedFilter extends UnreferencedFilter { - private StrictUnreferencedFilter(@NotNull InspectionTool tool) { - super(tool); + private StrictUnreferencedFilter(@NotNull UnusedDeclarationInspection tool, @NotNull GlobalInspectionContextImpl context) { + super(tool, context); } @Override @@ -527,34 +505,25 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { } } - private static class WeakUnreferencedFilter extends UnreferencedFilter { - private WeakUnreferencedFilter(@NotNull InspectionTool tool) { - super(tool); - } - - @Override - public int getElementProblemCount(final RefJavaElement refElement) { - final int problemCount = super.getElementProblemCount(refElement); - if (problemCount > - 1) return problemCount; - if (!((RefElementImpl)refElement).hasSuspiciousCallers() || ((RefJavaElementImpl)refElement).isSuspiciousRecursive()) return 1; - return 0; - } - } - @Override - public boolean queryExternalUsagesRequests(@NotNull final InspectionManager manager) { + public boolean queryExternalUsagesRequests(@NotNull InspectionManager manager, + @NotNull GlobalInspectionContext globalContext, + @NotNull ProblemDescriptionsProcessor problemDescriptionsProcessor) { checkForReachables(); - final RefFilter filter = myPhase == 1 ? new StrictUnreferencedFilter(this) : new RefUnreachableFilter(this); + final RefFilter filter = myPhase == 1 ? new StrictUnreferencedFilter(this, (GlobalInspectionContextImpl)globalContext) : + new RefUnreachableFilter(this, (GlobalInspectionContextImpl)globalContext); final boolean[] requestAdded = {false}; - getRefManager().iterate(new RefJavaVisitor() { - @Override public void visitElement(@NotNull RefEntity refEntity) { + globalContext.getRefManager().iterate(new RefJavaVisitor() { + @Override + public void visitElement(@NotNull RefEntity refEntity) { if (!(refEntity instanceof RefJavaElement)) return; if (refEntity instanceof RefClass && ((RefClass)refEntity).isAnonymous()) return; - RefJavaElement refElement= (RefJavaElement)refEntity; + RefJavaElement refElement = (RefJavaElement)refEntity; if (filter.accepts(refElement) && !myProcessedSuspicious.contains(refElement)) { refEntity.accept(new RefJavaVisitor() { - @Override public void visitField(@NotNull final RefField refField) { + @Override + public void visitField(@NotNull final RefField refField) { myProcessedSuspicious.add(refField); PsiField psiField = refField.getElement(); if (isSerializationImplicitlyUsedField(psiField)) { @@ -572,7 +541,8 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { } } - @Override public void visitMethod(@NotNull final RefMethod refMethod) { + @Override + public void visitMethod(@NotNull final RefMethod refMethod) { myProcessedSuspicious.add(refMethod); if (refMethod instanceof RefImplicitConstructor) { visitClass(refMethod.getOwnerClass()); @@ -593,7 +563,8 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { } } - @Override public void visitClass(@NotNull final RefClass refClass) { + @Override + public void visitClass(@NotNull final RefClass refClass) { myProcessedSuspicious.add(refClass); if (!refClass.isAnonymous()) { getJavaContext().enqueueDerivedClassesProcessor(refClass, new GlobalJavaInspectionContext.DerivedClassesProcessor() { @@ -654,295 +625,24 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { } } - public GlobalJavaInspectionContext getJavaContext() { + private GlobalJavaInspectionContext getJavaContext() { return getContext().getExtension(GlobalJavaInspectionContext.CONTEXT); } - @Override - public RefFilter getFilter() { - if (myFilter == null) { - myFilter = new WeakUnreferencedFilter(this); - } - return myFilter; - } - - @Override - @NotNull - public HTMLComposerImpl getComposer() { - if (myComposer == null) { - myComposer = new DeadHTMLComposer(this); - } - return myComposer; - } - - @Override - public void exportResults(@NotNull final Element parentNode, @NotNull RefEntity refEntity) { - if (!(refEntity instanceof RefJavaElement)) return; - final WeakUnreferencedFilter filter = new WeakUnreferencedFilter(this); - if (!getIgnoredRefElements().contains(refEntity) && filter.accepts((RefJavaElement)refEntity)) { - if (refEntity instanceof RefImplicitConstructor) refEntity = ((RefImplicitConstructor)refEntity).getOwnerClass(); - Element element = refEntity.getRefManager().export(refEntity, parentNode, -1); - if (element == null) return; - @NonNls Element problemClassElement = new Element(InspectionsBundle.message("inspection.export.results.problem.element.tag")); - - final RefElement refElement = (RefElement)refEntity; - final HighlightSeverity severity = getCurrentSeverity(refElement); - final String attributeKey = - getTextAttributeKey(refElement.getRefManager().getProject(), severity, ProblemHighlightType.LIKE_UNUSED_SYMBOL); - problemClassElement.setAttribute("severity", severity.myName); - problemClassElement.setAttribute("attribute_key", attributeKey); - - problemClassElement.addContent(InspectionsBundle.message("inspection.export.results.dead.code")); - element.addContent(problemClassElement); - - @NonNls Element hintsElement = new Element("hints"); - - for (String hint : HINTS) { - @NonNls Element hintElement = new Element("hint"); - hintElement.setAttribute("value", hint); - hintsElement.addContent(hintElement); - } - element.addContent(hintsElement); - - - Element descriptionElement = new Element(InspectionsBundle.message("inspection.export.results.description.tag")); - StringBuffer buf = new StringBuffer(); - DeadHTMLComposer.appendProblemSynopsis((RefElement)refEntity, buf); - descriptionElement.addContent(buf.toString()); - element.addContent(descriptionElement); - } - } - - @Override - public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) { - return myQuickFixActions; - } - - @NotNull - @Override - public JobDescriptor[] getJobDescriptors(@NotNull GlobalInspectionContext context) { - return new JobDescriptor[]{context.getStdJobDescriptors().BUILD_GRAPH, - context.getStdJobDescriptors().FIND_EXTERNAL_USAGES}; - } - - private static void commentOutDead(PsiElement psiElement) { - PsiFile psiFile = psiElement.getContainingFile(); - - if (psiFile != null) { - Document doc = PsiDocumentManager.getInstance(psiElement.getProject()).getDocument(psiFile); - if (doc != null) { - TextRange textRange = psiElement.getTextRange(); - String date = DateFormatUtil.formatDateTime(new Date()); - - int startOffset = textRange.getStartOffset(); - CharSequence chars = doc.getCharsSequence(); - while (CharArrayUtil.regionMatches(chars, startOffset, InspectionsBundle.message("inspection.dead.code.comment"))) { - int line = doc.getLineNumber(startOffset) + 1; - if (line < doc.getLineCount()) { - startOffset = doc.getLineStartOffset(line); - startOffset = CharArrayUtil.shiftForward(chars, startOffset, " \t"); - } - } - - int endOffset = textRange.getEndOffset(); - - int line1 = doc.getLineNumber(startOffset); - int line2 = doc.getLineNumber(endOffset - 1); - - if (line1 == line2) { - doc.insertString(startOffset, InspectionsBundle.message("inspection.dead.code.date.comment", date)); - } - else { - for (int i = line1; i <= line2; i++) { - doc.insertString(doc.getLineStartOffset(i), "//"); - } - - doc.insertString(doc.getLineStartOffset(Math.min(line2 + 1, doc.getLineCount() - 1)), - InspectionsBundle.message("inspection.dead.code.stop.comment", date)); - doc.insertString(doc.getLineStartOffset(line1), InspectionsBundle.message("inspection.dead.code.start.comment", date)); - } - } - } - } - - @Override @Nullable - public IntentionAction findQuickFixes(final CommonProblemDescriptor descriptor, final String hint) { - if (descriptor instanceof ProblemDescriptor) { - if (DELETE.equals(hint)) { - return new PermanentDeleteFix(((ProblemDescriptor)descriptor).getPsiElement()); - } - if (COMMENT.equals(hint)) { - return new CommentOutFix(((ProblemDescriptor)descriptor).getPsiElement()); - } - } - return null; - } - - private class PermanentDeleteAction extends QuickFixAction { - private PermanentDeleteAction() { - super(DELETE_QUICK_FIX, AllIcons.Actions.Cancel, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), UnusedDeclarationInspection.this); - } - - @Override - protected boolean applyFix(final RefElement[] refElements) { - if (!super.applyFix(refElements)) return false; - final ArrayList<PsiElement> psiElements = new ArrayList<PsiElement>(); - for (RefElement refElement : refElements) { - PsiElement psiElement = refElement.getElement(); - if (psiElement == null) continue; - if (getFilter().getElementProblemCount((RefJavaElement)refElement) == 0) continue; - psiElements.add(psiElement); - } - - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - final Project project = getContext().getProject(); - SafeDeleteHandler.invoke(project, PsiUtilCore.toPsiElementArray(psiElements), false, new Runnable() { - @Override - public void run() { - removeElements(refElements, project, UnusedDeclarationInspection.this); - } - }); - } - }); - - return false; //refresh after safe delete dialog is closed - } - } - - private static class PermanentDeleteFix implements IntentionAction { - private final PsiElement myElement; - - private PermanentDeleteFix(final PsiElement element) { - myElement = element; - } - - @Override - @NotNull - public String getText() { - return DELETE_QUICK_FIX; - } - - @Override - @NotNull - public String getFamilyName() { - return getText(); - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return true; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - if (myElement != null && myElement.isValid()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - SafeDeleteHandler - .invoke(myElement.getProject(), new PsiElement[]{PsiTreeUtil.getParentOfType(myElement, PsiModifierListOwner.class)}, false); - } - }); - } - } - - @Override - public boolean startInWriteAction() { - return true; - } - } - - private class CommentOutBin extends QuickFixAction { - private CommentOutBin() { - super(COMMENT_OUT_QUICK_FIX, null, KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, SystemInfo.isMac ? InputEvent.META_MASK : InputEvent.CTRL_MASK), - UnusedDeclarationInspection.this); - } - - @Override - protected boolean applyFix(RefElement[] refElements) { - if (!super.applyFix(refElements)) return false; - ArrayList<RefElement> deletedRefs = new ArrayList<RefElement>(1); - for (RefElement refElement : refElements) { - PsiElement psiElement = refElement.getElement(); - if (psiElement == null) continue; - if (getFilter().getElementProblemCount((RefJavaElement)refElement) == 0) continue; - commentOutDead(psiElement); - refElement.getRefManager().removeRefElement(refElement, deletedRefs); - } - - EntryPointsManager entryPointsManager = getEntryPointsManager(); - for (RefElement refElement : deletedRefs) { - entryPointsManager.removeEntryPoint(refElement); - } - - return true; - } - } - - private static class CommentOutFix implements IntentionAction { - private final PsiElement myElement; - - private CommentOutFix(final PsiElement element) { - myElement = element; - } - - @Override - @NotNull - public String getText() { - return COMMENT_OUT_QUICK_FIX; - } - - @Override - @NotNull - public String getFamilyName() { - return getText(); - } - - @Override - public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - return true; - } - - @Override - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - if (myElement != null && myElement.isValid()) { - commentOutDead(PsiTreeUtil.getParentOfType(myElement, PsiModifierListOwner.class)); - } - } - - @Override - public boolean startInWriteAction() { - return true; - } + @Override + public JobDescriptor[] getAdditionalJobs() { + return new JobDescriptor[]{getContext().getStdJobDescriptors().BUILD_GRAPH, getContext().getStdJobDescriptors().FIND_EXTERNAL_USAGES}; } - private class MoveToEntries extends QuickFixAction { - private MoveToEntries() { - super(InspectionsBundle.message("inspection.dead.code.entry.point.quickfix"), null, KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), UnusedDeclarationInspection.this); - } - @Override - protected boolean applyFix(RefElement[] refElements) { - final EntryPointsManager entryPointsManager = getEntryPointsManager(); - for (RefElement refElement : refElements) { - entryPointsManager.addEntryPoint(refElement, true); - } - - return true; - } - - - } - - private void checkForReachables() { + void checkForReachables() { CodeScanner codeScanner = new CodeScanner(); // Cleanup previous reachability information. - getRefManager().iterate(new RefJavaVisitor() { - @Override public void visitElement(@NotNull RefEntity refEntity) { + getContext().getRefManager().iterate(new RefJavaVisitor() { + @Override + public void visitElement(@NotNull RefEntity refEntity) { if (refEntity instanceof RefJavaElement) { final RefJavaElementImpl refElement = (RefJavaElementImpl)refEntity; if (!getContext().isToCheckMember(refElement, UnusedDeclarationInspection.this)) return; @@ -1094,17 +794,27 @@ public class UnusedDeclarationInspection extends FilteringInspectionTool { } } + + @NotNull @Override - public void updateContent() { - checkForReachables(); - super.updateContent(); + public InspectionToolPresentation createPresentation(@NotNull InspectionToolWrapper toolWrapper) { + return new UnusedDeclarationPresentation(toolWrapper); + } + + @Override + public void initialize(@NotNull GlobalInspectionContext context) { + super.initialize(context); + myContext = (GlobalInspectionContextImpl)context; } @Override - public InspectionNode createToolNode(@NotNull final InspectionRVContentProvider provider, final InspectionTreeNode parentNode, final boolean showStructure) { - final InspectionNode toolNode = super.createToolNode(provider, parentNode, showStructure); - final EntryPointsNode entryPointsNode = new EntryPointsNode(this); - provider.appendToolNodeContent(entryPointsNode, toolNode, showStructure); - return entryPointsNode; + public void cleanup() { + super.cleanup(); + myContext = null; + } + + @Override + public boolean isGraphNeeded() { + return true; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java new file mode 100644 index 000000000000..29f0578073ff --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java @@ -0,0 +1,523 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInspection.deadCode; + +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.*; +import com.intellij.codeInspection.ex.*; +import com.intellij.codeInspection.reference.*; +import com.intellij.codeInspection.ui.*; +import com.intellij.codeInspection.util.RefFilter; +import com.intellij.icons.AllIcons; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vcs.FileStatus; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiModifierListOwner; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilCore; +import com.intellij.refactoring.safeDelete.SafeDeleteHandler; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.HashSet; +import com.intellij.util.text.CharArrayUtil; +import com.intellij.util.text.DateFormatUtil; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.*; + +public class UnusedDeclarationPresentation extends DefaultInspectionToolPresentation { + private Map<String, Set<RefEntity>> myPackageContents = new HashMap<String, Set<RefEntity>>(); + + private Map<String, Set<RefEntity>> myOldPackageContents = null; + + private final Set<RefEntity> myIgnoreElements = new HashSet<RefEntity>(); + private WeakUnreferencedFilter myFilter; + private DeadHTMLComposer myComposer; + @NonNls private static final String DELETE = "delete"; + @NonNls private static final String COMMENT = "comment"; + @NonNls private static final String [] HINTS = {COMMENT, DELETE}; + + public UnusedDeclarationPresentation(@NotNull InspectionToolWrapper toolWrapper) { + super(toolWrapper); + myQuickFixActions = createQuickFixes(toolWrapper); + } + + public RefFilter getFilter() { + if (myFilter == null) { + myFilter = new WeakUnreferencedFilter(getTool(), getContext()); + } + return myFilter; + } + private static class WeakUnreferencedFilter extends UnreferencedFilter { + private WeakUnreferencedFilter(@NotNull UnusedDeclarationInspection tool, @NotNull GlobalInspectionContextImpl context) { + super(tool, context); + } + + @Override + public int getElementProblemCount(final RefJavaElement refElement) { + final int problemCount = super.getElementProblemCount(refElement); + if (problemCount > - 1) return problemCount; + if (!((RefElementImpl)refElement).hasSuspiciousCallers() || ((RefJavaElementImpl)refElement).isSuspiciousRecursive()) return 1; + return 0; + } + } + + @NotNull + UnusedDeclarationInspection getTool() { + return (UnusedDeclarationInspection)getToolWrapper().getTool(); + } + + + @Override + @NotNull + public HTMLComposerImpl getComposer() { + if (myComposer == null) { + myComposer = new DeadHTMLComposer(this); + } + return myComposer; + } + + @Override + public void exportResults(@NotNull final Element parentNode, @NotNull RefEntity refEntity) { + if (!(refEntity instanceof RefJavaElement)) return; + final RefFilter filter = getFilter(); + if (!getIgnoredRefElements().contains(refEntity) && filter.accepts((RefJavaElement)refEntity)) { + refEntity = getRefManager().getRefinedElement(refEntity); + Element element = refEntity.getRefManager().export(refEntity, parentNode, -1); + if (element == null) return; + @NonNls Element problemClassElement = new Element(InspectionsBundle.message("inspection.export.results.problem.element.tag")); + + final RefElement refElement = (RefElement)refEntity; + final HighlightSeverity severity = getSeverity(refElement, getContext(), getToolWrapper()); + final String attributeKey = + getTextAttributeKey(refElement.getRefManager().getProject(), severity, ProblemHighlightType.LIKE_UNUSED_SYMBOL); + problemClassElement.setAttribute("severity", severity.myName); + problemClassElement.setAttribute("attribute_key", attributeKey); + + problemClassElement.addContent(InspectionsBundle.message("inspection.export.results.dead.code")); + element.addContent(problemClassElement); + + @NonNls Element hintsElement = new Element("hints"); + + for (String hint : HINTS) { + @NonNls Element hintElement = new Element("hint"); + hintElement.setAttribute("value", hint); + hintsElement.addContent(hintElement); + } + element.addContent(hintsElement); + + + Element descriptionElement = new Element(InspectionsBundle.message("inspection.export.results.description.tag")); + StringBuffer buf = new StringBuffer(); + DeadHTMLComposer.appendProblemSynopsis((RefElement)refEntity, buf); + descriptionElement.addContent(buf.toString()); + element.addContent(descriptionElement); + } + } + + @Override + public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements) { + return myQuickFixActions; + } + + final QuickFixAction[] myQuickFixActions; + + @NotNull + private QuickFixAction[] createQuickFixes(@NotNull InspectionToolWrapper toolWrapper) { + return new QuickFixAction[]{new PermanentDeleteAction(toolWrapper), new CommentOutBin(toolWrapper), new MoveToEntries(toolWrapper)}; + } + private static final String DELETE_QUICK_FIX = InspectionsBundle.message("inspection.dead.code.safe.delete.quickfix"); + + class PermanentDeleteAction extends QuickFixAction { + PermanentDeleteAction(@NotNull InspectionToolWrapper toolWrapper) { + super(DELETE_QUICK_FIX, AllIcons.Actions.Cancel, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), toolWrapper); + } + + @Override + protected boolean applyFix(final RefEntity[] refElements) { + if (!super.applyFix(refElements)) return false; + final ArrayList<PsiElement> psiElements = new ArrayList<PsiElement>(); + for (RefEntity refElement : refElements) { + PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getElement() : null; + if (psiElement == null) continue; + if (getFilter().getElementProblemCount((RefJavaElement)refElement) == 0) continue; + psiElements.add(psiElement); + } + + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final Project project = getContext().getProject(); + SafeDeleteHandler.invoke(project, PsiUtilCore.toPsiElementArray(psiElements), false, new Runnable() { + @Override + public void run() { + removeElements(refElements, project, myToolWrapper); + } + }); + } + }); + + return false; //refresh after safe delete dialog is closed + } + } + + private EntryPointsManager getEntryPointsManager() { + return getContext().getExtension(GlobalJavaInspectionContext.CONTEXT).getEntryPointsManager(getContext().getRefManager()); + } + + class MoveToEntries extends QuickFixAction { + MoveToEntries(@NotNull InspectionToolWrapper toolWrapper) { + super(InspectionsBundle.message("inspection.dead.code.entry.point.quickfix"), null, KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), toolWrapper); + } + + @Override + protected boolean applyFix(RefEntity[] refElements) { + final EntryPointsManager entryPointsManager = getEntryPointsManager(); + for (RefEntity refElement : refElements) { + if (refElement instanceof RefElement) { + entryPointsManager.addEntryPoint((RefElement)refElement, true); + } + } + + return true; + } + } + + class CommentOutBin extends QuickFixAction { + CommentOutBin(@NotNull InspectionToolWrapper toolWrapper) { + super(COMMENT_OUT_QUICK_FIX, null, KeyStroke.getKeyStroke(KeyEvent.VK_SLASH, SystemInfo.isMac ? InputEvent.META_MASK : InputEvent.CTRL_MASK), + toolWrapper); + } + + @Override + protected boolean applyFix(RefEntity[] refElements) { + if (!super.applyFix(refElements)) return false; + ArrayList<RefElement> deletedRefs = new ArrayList<RefElement>(1); + for (RefEntity refElement : refElements) { + PsiElement psiElement = refElement instanceof RefElement ? ((RefElement)refElement).getElement() : null; + if (psiElement == null) continue; + if (getFilter().getElementProblemCount((RefJavaElement)refElement) == 0) continue; + commentOutDead(psiElement); + refElement.getRefManager().removeRefElement((RefElement)refElement, deletedRefs); + } + + EntryPointsManager entryPointsManager = getEntryPointsManager(); + for (RefElement refElement : deletedRefs) { + entryPointsManager.removeEntryPoint(refElement); + } + + return true; + } + } + + private static final String COMMENT_OUT_QUICK_FIX = InspectionsBundle.message("inspection.dead.code.comment.quickfix"); + private static class CommentOutFix implements IntentionAction { + private final PsiElement myElement; + + private CommentOutFix(final PsiElement element) { + myElement = element; + } + + @Override + @NotNull + public String getText() { + return COMMENT_OUT_QUICK_FIX; + } + + @Override + @NotNull + public String getFamilyName() { + return getText(); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return true; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + if (myElement != null && myElement.isValid()) { + commentOutDead(PsiTreeUtil.getParentOfType(myElement, PsiModifierListOwner.class)); + } + } + + @Override + public boolean startInWriteAction() { + return true; + } + } + private static void commentOutDead(PsiElement psiElement) { + PsiFile psiFile = psiElement.getContainingFile(); + + if (psiFile != null) { + Document doc = PsiDocumentManager.getInstance(psiElement.getProject()).getDocument(psiFile); + if (doc != null) { + TextRange textRange = psiElement.getTextRange(); + String date = DateFormatUtil.formatDateTime(new Date()); + + int startOffset = textRange.getStartOffset(); + CharSequence chars = doc.getCharsSequence(); + while (CharArrayUtil.regionMatches(chars, startOffset, InspectionsBundle.message("inspection.dead.code.comment"))) { + int line = doc.getLineNumber(startOffset) + 1; + if (line < doc.getLineCount()) { + startOffset = doc.getLineStartOffset(line); + startOffset = CharArrayUtil.shiftForward(chars, startOffset, " \t"); + } + } + + int endOffset = textRange.getEndOffset(); + + int line1 = doc.getLineNumber(startOffset); + int line2 = doc.getLineNumber(endOffset - 1); + + if (line1 == line2) { + doc.insertString(startOffset, InspectionsBundle.message("inspection.dead.code.date.comment", date)); + } + else { + for (int i = line1; i <= line2; i++) { + doc.insertString(doc.getLineStartOffset(i), "//"); + } + + doc.insertString(doc.getLineStartOffset(Math.min(line2 + 1, doc.getLineCount() - 1)), + InspectionsBundle.message("inspection.dead.code.stop.comment", date)); + doc.insertString(doc.getLineStartOffset(line1), InspectionsBundle.message("inspection.dead.code.start.comment", date)); + } + } + } + } + + @NotNull + @Override + public InspectionNode createToolNode(@NotNull GlobalInspectionContextImpl context, + @NotNull InspectionNode node, + @NotNull InspectionRVContentProvider provider, + @NotNull InspectionTreeNode parentNode, + boolean showStructure) { + final EntryPointsNode entryPointsNode = new EntryPointsNode(context); + InspectionToolWrapper dummyToolWrapper = entryPointsNode.getToolWrapper(); + InspectionToolPresentation presentation = context.getPresentation(dummyToolWrapper); + presentation.updateContent(); + provider.appendToolNodeContent(context, entryPointsNode, node, showStructure); + return entryPointsNode; + } + + @Override + public void initialize(@NotNull GlobalInspectionContextImpl context) { + super.initialize(context); + ((EntryPointsManagerImpl)getEntryPointsManager()).setAddNonJavaEntries(getTool().ADD_NONJAVA_TO_ENTRIES); + } + + @Override + public void updateContent() { + getTool().checkForReachables(); + myPackageContents = new HashMap<String, Set<RefEntity>>(); + getContext().getRefManager().iterate(new RefJavaVisitor() { + @Override public void visitElement(@NotNull RefEntity refEntity) { + if (!(refEntity instanceof RefJavaElement)) return;//dead code doesn't work with refModule | refPackage + RefJavaElement refElement = (RefJavaElement)refEntity; + if (!(getContext().getUIOptions().FILTER_RESOLVED_ITEMS && getIgnoredRefElements().contains(refElement)) && refElement.isValid() && getFilter().accepts(refElement)) { + String packageName = RefJavaUtil.getInstance().getPackageName(refEntity); + Set<RefEntity> content = myPackageContents.get(packageName); + if (content == null) { + content = new HashSet<RefEntity>(); + myPackageContents.put(packageName, content); + } + content.add(refEntity); + } + } + }); + } + + @Override + public boolean hasReportedProblems() { + final GlobalInspectionContextImpl context = getContext(); + if (context != null && context.getUIOptions().SHOW_ONLY_DIFF){ + return containsOnlyDiff(myPackageContents) || + myOldPackageContents != null && containsOnlyDiff(myOldPackageContents); + } + if (!myPackageContents.isEmpty()) return true; + return isOldProblemsIncluded() && !myOldPackageContents.isEmpty(); + } + + private boolean containsOnlyDiff(@NotNull Map<String, Set<RefEntity>> packageContents) { + for (String packageName : packageContents.keySet()) { + final Set<RefEntity> refElements = packageContents.get(packageName); + if (refElements != null){ + for (RefEntity refElement : refElements) { + if (getElementStatus(refElement) != FileStatus.NOT_CHANGED){ + return true; + } + } + } + } + return false; + } + + @Override + public Map<String, Set<RefEntity>> getContent() { + return myPackageContents; + } + + @Override + public Map<String, Set<RefEntity>> getOldContent() { + return myOldPackageContents; + } + + @Override + public void ignoreCurrentElement(RefEntity refEntity) { + if (refEntity == null) return; + myIgnoreElements.add(refEntity); + } + + @Override + public void amnesty(RefEntity refEntity) { + myIgnoreElements.remove(refEntity); + } + + @Override + public void cleanup() { + super.cleanup(); + myOldPackageContents = null; + myPackageContents.clear(); + myIgnoreElements.clear(); + } + + + @Override + public void finalCleanup() { + super.finalCleanup(); + myOldPackageContents = null; + } + + @Override + public boolean isGraphNeeded() { + return true; + } + + @Override + public boolean isElementIgnored(final RefEntity element) { + for (RefEntity entity : myIgnoreElements) { + if (Comparing.equal(entity, element)) { + return true; + } + } + return false; + } + + + @NotNull + @Override + public FileStatus getElementStatus(final RefEntity element) { + final GlobalInspectionContextImpl context = getContext(); + if (context != null && context.getUIOptions().SHOW_DIFF_WITH_PREVIOUS_RUN){ + if (myOldPackageContents != null){ + final boolean old = RefUtil.contains(element, collectRefElements(myOldPackageContents)); + final boolean current = RefUtil.contains(element, collectRefElements(myPackageContents)); + return calcStatus(old, current); + } + return FileStatus.ADDED; + } + return FileStatus.NOT_CHANGED; + } + + @Override + @NotNull + public Collection<RefEntity> getIgnoredRefElements() { + return myIgnoreElements; + } + + private static Set<RefEntity> collectRefElements(Map<String, Set<RefEntity>> packageContents) { + Set<RefEntity> allAvailable = new HashSet<RefEntity>(); + for (Set<RefEntity> elements : packageContents.values()) { + allAvailable.addAll(elements); + } + return allAvailable; + } + + @Override + @Nullable + public IntentionAction findQuickFixes(@NotNull final CommonProblemDescriptor descriptor, final String hint) { + if (descriptor instanceof ProblemDescriptor) { + if (DELETE.equals(hint)) { + return new PermanentDeleteFix(((ProblemDescriptor)descriptor).getPsiElement()); + } + if (COMMENT.equals(hint)) { + return new CommentOutFix(((ProblemDescriptor)descriptor).getPsiElement()); + } + } + return null; + } + + + private static class PermanentDeleteFix implements IntentionAction { + private final PsiElement myElement; + + private PermanentDeleteFix(final PsiElement element) { + myElement = element; + } + + @Override + @NotNull + public String getText() { + return DELETE_QUICK_FIX; + } + + @Override + @NotNull + public String getFamilyName() { + return getText(); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + return true; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + if (myElement != null && myElement.isValid()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + SafeDeleteHandler + .invoke(myElement.getProject(), new PsiElement[]{PsiTreeUtil.getParentOfType(myElement, PsiModifierListOwner.class)}, false); + } + }); + } + } + + @Override + public boolean startInWriteAction() { + return true; + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java b/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java index 479272842951..a2a95d734ec2 100644 --- a/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/emptyMethod/EmptyMethodInspection.java @@ -202,7 +202,8 @@ public class EmptyMethodInspection extends GlobalJavaInspectionTool { } @Override - protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, @NotNull final GlobalJavaInspectionContext context, + protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, + @NotNull final GlobalJavaInspectionContext context, @NotNull final ProblemDescriptionsProcessor descriptionsProcessor) { manager.iterate(new RefJavaVisitor() { @Override public void visitElement(@NotNull RefEntity refEntity) { diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/FilteringInspectionTool.java b/java/java-impl/src/com/intellij/codeInspection/ex/FilteringInspectionTool.java deleted file mode 100644 index 71a49a4bed30..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/ex/FilteringInspectionTool.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInspection.ex; - -import com.intellij.codeInsight.daemon.HighlightDisplayKey; -import com.intellij.codeInspection.SuppressIntentionAction; -import com.intellij.codeInspection.SuppressManager; -import com.intellij.codeInspection.reference.RefEntity; -import com.intellij.codeInspection.reference.RefJavaElement; -import com.intellij.codeInspection.reference.RefJavaUtil; -import com.intellij.codeInspection.reference.RefJavaVisitor; -import com.intellij.codeInspection.util.RefFilter; -import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.vcs.FileStatus; -import com.intellij.util.containers.HashMap; -import com.intellij.util.containers.HashSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; - -/** - * @author max - */ -public abstract class FilteringInspectionTool extends InspectionTool { - public abstract RefFilter getFilter(); - private Map<String, Set<RefEntity>> myPackageContents = new HashMap<String, Set<RefEntity>>(); - - private Map<String, Set<RefEntity>> myOldPackageContents = null; - - private final Set<RefEntity> myIgnoreElements = new HashSet<RefEntity>(); - - @Override - public void updateContent() { - myPackageContents = new HashMap<String, Set<RefEntity>>(); - getContext().getRefManager().iterate(new RefJavaVisitor() { - @Override public void visitElement(@NotNull RefEntity refEntity) { - if (!(refEntity instanceof RefJavaElement)) return;//dead code doesn't work with refModule | refPackage - RefJavaElement refElement = (RefJavaElement)refEntity; - if (!(getContext().getUIOptions().FILTER_RESOLVED_ITEMS && myIgnoreElements.contains(refElement)) && refElement.isValid() && getFilter().accepts(refElement)) { - String packageName = RefJavaUtil.getInstance().getPackageName(refEntity); - Set<RefEntity> content = myPackageContents.get(packageName); - if (content == null) { - content = new HashSet<RefEntity>(); - myPackageContents.put(packageName, content); - } - content.add(refEntity); - } - } - }); - } - - @Override - public boolean hasReportedProblems() { - final GlobalInspectionContextImpl context = getContext(); - if (context != null && context.getUIOptions().SHOW_ONLY_DIFF){ - return containsOnlyDiff(myPackageContents) || - myOldPackageContents != null && containsOnlyDiff(myOldPackageContents); - } - if (!myPackageContents.isEmpty()) return true; - return isOldProblemsIncluded() && !myOldPackageContents.isEmpty(); - } - - private boolean containsOnlyDiff(@NotNull Map<String, Set<RefEntity>> packageContents) { - for (String packageName : packageContents.keySet()) { - final Set<RefEntity> refElements = packageContents.get(packageName); - if (refElements != null){ - for (RefEntity refElement : refElements) { - if (getElementStatus(refElement) != FileStatus.NOT_CHANGED){ - return true; - } - } - } - } - return false; - } - - @Override - public Map<String, Set<RefEntity>> getContent() { - return myPackageContents; - } - - @Override - public Map<String, Set<RefEntity>> getOldContent() { - return myOldPackageContents; - } - - @Override - public void ignoreCurrentElement(RefEntity refEntity) { - if (refEntity == null) return; - myIgnoreElements.add(refEntity); - } - - @Override - public void amnesty(RefEntity refEntity) { - myIgnoreElements.remove(refEntity); - } - - @Override - public void cleanup() { - super.cleanup(); - myOldPackageContents = null; - myPackageContents.clear(); - myIgnoreElements.clear(); - } - - - @Override - public void finalCleanup() { - super.finalCleanup(); - myOldPackageContents = null; - } - - @Override - public boolean isGraphNeeded() { - return true; - } - - @Override - public boolean isElementIgnored(final RefEntity element) { - for (RefEntity entity : myIgnoreElements) { - if (Comparing.equal(entity, element)) { - return true; - } - } - return false; - } - - - @NotNull - @Override - public FileStatus getElementStatus(final RefEntity element) { - final GlobalInspectionContextImpl context = getContext(); - if (context != null && context.getUIOptions().SHOW_DIFF_WITH_PREVIOUS_RUN){ - if (myOldPackageContents != null){ - final boolean old = contains(element, collectRefElements(myOldPackageContents)); - final boolean current = contains(element, collectRefElements(myPackageContents)); - return calcStatus(old, current); - } - return FileStatus.ADDED; - } - return FileStatus.NOT_CHANGED; - } - - @NotNull - @Override - public Collection<RefEntity> getIgnoredRefElements() { - return myIgnoreElements; - } - - private static Set<RefEntity> collectRefElements(Map<String, Set<RefEntity>> packageContents) { - Set<RefEntity> allAvailable = new HashSet<RefEntity>(); - for (Set<RefEntity> elements : packageContents.values()) { - allAvailable.addAll(elements); - } - return allAvailable; - } - - @Override - @Nullable - public SuppressIntentionAction[] getSuppressActions() { - return SuppressManager.getInstance().createSuppressActions(HighlightDisplayKey.find(getShortName())); - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java index 86ff16ca9553..cd706652c019 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/GlobalJavaInspectionContextImpl.java @@ -25,6 +25,7 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.codeInspection.*; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; import com.intellij.codeInspection.reference.*; +import com.intellij.codeInspection.ui.InspectionToolPresentation; import com.intellij.lang.StdLanguages; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -68,8 +69,8 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext public void enqueueClassUsagesProcessor(RefClass refClass, UsagesProcessor p) { if (myClassUsagesRequests == null) myClassUsagesRequests = new THashMap<SmartPsiElementPointer, List<UsagesProcessor>>(); enqueueRequestImpl(refClass, myClassUsagesRequests, p); - } + } @Override public void enqueueDerivedClassesProcessor(RefClass refClass, DerivedClassesProcessor p) { if (myDerivedClassesRequests == null) myDerivedClassesRequests = new THashMap<SmartPsiElementPointer, List<DerivedClassesProcessor>>(); @@ -101,7 +102,7 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext } @SuppressWarnings({"UseOfSystemOutOrSystemErr"}) - public static boolean isInspectionsEnabled(final boolean online, Project project) { + public static boolean isInspectionsEnabled(final boolean online, @NotNull Project project) { final Module[] modules = ModuleManager.getInstance(project).getModules(); if (online) { if (modules.length == 0) { @@ -413,12 +414,14 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext } @Override - public void performPreRunActivities(final List<Tools> globalTools, final List<Tools> localTools, - final GlobalInspectionContext context) { + public void performPreRunActivities(@NotNull final List<Tools> globalTools, + @NotNull final List<Tools> localTools, + @NotNull final GlobalInspectionContext context) { getEntryPointsManager(context.getRefManager()).resolveEntryPoints(context.getRefManager()); + // UnusedDeclarationInspection should run first for (int i = 0; i < globalTools.size(); i++) { - InspectionProfileEntry tool = globalTools.get(i).getTool(); - if (UnusedDeclarationInspection.SHORT_NAME.equals(tool.getShortName())) { + InspectionToolWrapper toolWrapper = globalTools.get(i).getTool(); + if (UnusedDeclarationInspection.SHORT_NAME.equals(toolWrapper.getShortName())) { Collections.swap(globalTools, i, 0); break; } @@ -428,17 +431,22 @@ public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext @Override - public void performPostRunActivities(List<InspectionProfileEntry> needRepeatSearchRequest, final GlobalInspectionContext context) { + public void performPostRunActivities(@NotNull List<InspectionToolWrapper> needRepeatSearchRequest, @NotNull final GlobalInspectionContext context) { JobDescriptor progress = context.getStdJobDescriptors().FIND_EXTERNAL_USAGES; progress.setTotalAmount(getRequestCount()); do { processSearchRequests(context); - InspectionProfileEntry[] requestors = needRepeatSearchRequest.toArray(new InspectionProfileEntry[needRepeatSearchRequest.size()]); - for (InspectionProfileEntry requestor : requestors) { - if (requestor instanceof InspectionTool && - !((InspectionTool)requestor).queryExternalUsagesRequests(InspectionManager.getInstance(context.getProject()))) { - needRepeatSearchRequest.remove(requestor); + InspectionToolWrapper[] requestors = needRepeatSearchRequest.toArray(new InspectionToolWrapper[needRepeatSearchRequest.size()]); + InspectionManager inspectionManager = InspectionManager.getInstance(context.getProject()); + for (InspectionToolWrapper toolWrapper : requestors) { + boolean result = false; + if (toolWrapper instanceof GlobalInspectionToolWrapper) { + InspectionToolPresentation presentation = ((GlobalInspectionContextImpl)context).getPresentation(toolWrapper); + result = ((GlobalInspectionToolWrapper)toolWrapper).getTool().queryExternalUsagesRequests(inspectionManager, context, presentation); + } + if (!result) { + needRepeatSearchRequest.remove(toolWrapper); } } int oldSearchRequestCount = progress.getTotalAmount(); diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/JavaInspectionExtensionsFactory.java b/java/java-impl/src/com/intellij/codeInspection/ex/JavaInspectionExtensionsFactory.java index 21cf2f85b54e..d5f607ec819f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/JavaInspectionExtensionsFactory.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/JavaInspectionExtensionsFactory.java @@ -31,6 +31,7 @@ import com.intellij.codeInspection.reference.RefManager; import com.intellij.codeInspection.reference.RefManagerImpl; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class JavaInspectionExtensionsFactory extends InspectionExtensionsFactory { @@ -62,7 +63,7 @@ public class JavaInspectionExtensionsFactory extends InspectionExtensionsFactory } @Override - public boolean isProjectConfiguredToRunInspections(final Project project, final boolean online) { + public boolean isProjectConfiguredToRunInspections(@NotNull final Project project, final boolean online) { return GlobalJavaInspectionContextImpl.isInspectionsEnabled(online, project); } }
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java index 5d9bd6c2fa1a..7dd92822237d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/reference/RefImplicitConstructorImpl.java @@ -92,6 +92,6 @@ public class RefImplicitConstructorImpl extends RefMethodImpl implements RefImpl @Override public RefClass getOwnerClass() { - return myOwnerClass == null ? super.getOwnerClass() : myOwnerClass; + return myOwnerClass; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java index bf78af21296d..8ebd6ab6a87b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java @@ -110,7 +110,7 @@ public class RefJavaManagerImpl extends RefJavaManager { @Override protected Ref<UnusedDeclarationInspection> compute(PsiFile file, RefManagerImpl refManager) { Tools tools = ((GlobalInspectionContextImpl)refManager.getContext()).getTools().get(UnusedDeclarationInspection.SHORT_NAME); - InspectionToolWrapper toolWrapper = tools != null ? (InspectionToolWrapper)tools.getEnabledTool(file) : null; + InspectionToolWrapper toolWrapper = tools == null ? null : tools.getEnabledTool(file); InspectionProfileEntry tool = toolWrapper == null ? null : toolWrapper.getTool(); return Ref.create(tool instanceof UnusedDeclarationInspection ? (UnusedDeclarationInspection)tool : null); } @@ -283,8 +283,9 @@ public class RefJavaManagerImpl extends RefJavaManager { return null; } + @NotNull @Override - public RefEntity getRefinedElement(final RefEntity ref) { + public RefEntity getRefinedElement(@NotNull final RefEntity ref) { if (ref instanceof RefImplicitConstructor) { return ((RefImplicitConstructor)ref).getOwnerClass(); } @@ -312,7 +313,7 @@ public class RefJavaManagerImpl extends RefJavaManager { } @Override - public void export(final RefEntity refEntity, final Element element) { + public void export(@NotNull final RefEntity refEntity, @NotNull final Element element) { if (refEntity instanceof RefElement) { final SmartPsiElementPointer pointer = ((RefElement)refEntity).getPointer(); if (pointer != null) { diff --git a/java/java-impl/src/com/intellij/codeInspection/ui/EntryPointsNode.java b/java/java-impl/src/com/intellij/codeInspection/ui/EntryPointsNode.java index 51063602a763..7363d43c104b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ui/EntryPointsNode.java +++ b/java/java-impl/src/com/intellij/codeInspection/ui/EntryPointsNode.java @@ -16,7 +16,9 @@ package com.intellij.codeInspection.ui; import com.intellij.codeInspection.deadCode.DummyEntryPointsTool; -import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection; +import com.intellij.codeInspection.ex.GlobalInspectionContextImpl; +import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper; +import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.icons.AllIcons; import org.jetbrains.annotations.NotNull; @@ -26,9 +28,14 @@ import javax.swing.*; * @author max */ public class EntryPointsNode extends InspectionNode { - public EntryPointsNode(@NotNull UnusedDeclarationInspection tool) { - super(new DummyEntryPointsTool(tool)); - getTool().updateContent(); + public EntryPointsNode(@NotNull GlobalInspectionContextImpl context) { + super(createDummyWrapper(context)); + } + + private static InspectionToolWrapper createDummyWrapper(@NotNull GlobalInspectionContextImpl context) { + InspectionToolWrapper toolWrapper = new GlobalInspectionToolWrapper(new DummyEntryPointsTool()); + toolWrapper.initialize(context); + return toolWrapper; } @Override diff --git a/java/java-impl/src/com/intellij/codeInspection/util/XMLExportUtl.java b/java/java-impl/src/com/intellij/codeInspection/util/XMLExportUtl.java deleted file mode 100644 index 6854148aa5f0..000000000000 --- a/java/java-impl/src/com/intellij/codeInspection/util/XMLExportUtl.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: May 23, 2002 - * Time: 2:36:58 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ -package com.intellij.codeInspection.util; - -import com.intellij.codeInspection.InspectionsBundle; -import com.intellij.codeInspection.reference.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.javadoc.PsiDocComment; -import com.intellij.psi.javadoc.PsiDocTag; -import com.intellij.psi.util.PsiFormatUtil; -import org.jdom.Element; - -@SuppressWarnings({"HardCodedStringLiteral"}) -@Deprecated -public class XMLExportUtl { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.util.XMLExportUtl"); - - private XMLExportUtl() { - } - - public static Element createElement(RefEntity refEntity, Element parentNode, int actualLine, final TextRange range) { - refEntity = refEntity.getRefManager().getRefinedElement(refEntity); - - Element problem = new Element("problem"); - - if (refEntity instanceof RefElement) { - final RefElement refElement = (RefElement)refEntity; - PsiElement psiElement = refElement.getElement(); - PsiFile psiFile = psiElement.getContainingFile(); - - Element fileElement = new Element("file"); - Element lineElement = new Element("line"); - final VirtualFile virtualFile = psiFile.getVirtualFile(); - LOG.assertTrue(virtualFile != null); - fileElement.addContent(virtualFile.getUrl()); - - if (actualLine == -1) { - final Document document = PsiDocumentManager.getInstance(refElement.getRefManager().getProject()).getDocument(psiFile); - LOG.assertTrue(document != null); - lineElement.addContent(String.valueOf(document.getLineNumber(psiElement.getTextOffset()) + 1)); - } - else { - lineElement.addContent(String.valueOf(actualLine)); - } - - problem.addContent(fileElement); - problem.addContent(lineElement); - appendModule(problem, refElement.getModule()); - } - else if (refEntity instanceof RefModule) { - final RefModule refModule = (RefModule)refEntity; - final VirtualFile moduleFile = refModule.getModule().getModuleFile(); - final Element fileElement = new Element("file"); - fileElement.addContent(moduleFile != null? moduleFile.getUrl() : refEntity.getName()); - problem.addContent(fileElement); - appendModule(problem, refModule); - appendFakePackage(problem); - } else if (refEntity instanceof RefPackage) { - Element packageElement = new Element("package"); - packageElement.addContent(refEntity.getName()); - problem.addContent(packageElement); - } - - new SmartRefElementPointerImpl(refEntity, true).writeExternal(problem); - - if (refEntity instanceof RefMethod) { - RefMethod refMethod = (RefMethod)refEntity; - appendMethod(refMethod, problem); - } - else if (refEntity instanceof RefField) { - RefField refField = (RefField)refEntity; - appendField(refField, problem); - } - else if (refEntity instanceof RefClass) { - RefClass refClass = (RefClass)refEntity; - appendClass(refClass, problem); - } else if (refEntity instanceof RefFile) { - appendFakePackage(problem); - } - parentNode.addContent(problem); - - return problem; - } - - private static void appendModule(final Element problem, final RefModule refModule) { - if (refModule != null) { - Element moduleElement = new Element("module"); - moduleElement.addContent(refModule.getName()); - problem.addContent(moduleElement); - } - } - - private static void appendFakePackage(final Element problem) { - final Element fakePackage = new Element("package"); - fakePackage.addContent(InspectionsBundle.message("inspection.export.results.default")); - problem.addContent(fakePackage); - } - - private static void appendClass(RefClass refClass, Element parentNode) { - PsiClass psiClass = refClass.getElement(); - PsiDocComment psiDocComment = psiClass.getDocComment(); - - PsiFile psiFile = psiClass.getContainingFile(); - - if (psiFile instanceof PsiJavaFile) { - String packageName = ((PsiJavaFile)psiFile).getPackageName(); - Element packageElement = new Element("package"); - packageElement.addContent(packageName.length() > 0 ? packageName : InspectionsBundle.message("inspection.export.results.default")); - parentNode.addContent(packageElement); - } - - Element classElement = new Element("class"); - if (psiDocComment != null) { - PsiDocTag[] tags = psiDocComment.getTags(); - for (PsiDocTag tag : tags) { - if ("author".equals(tag.getName()) && tag.getValueElement() != null) { - classElement.setAttribute("author", tag.getValueElement().getText()); - } - } - } - - String name = PsiFormatUtil.formatClass(psiClass, PsiFormatUtil.SHOW_NAME); - Element nameElement = new Element("name"); - nameElement.addContent(name); - classElement.addContent(nameElement); - - Element displayName = new Element("display_name"); - displayName.addContent(refClass.getQualifiedName()); - classElement.addContent(displayName); - - parentNode.addContent(classElement); - - RefClass topClass = RefJavaUtil.getInstance().getTopLevelClass(refClass); - if (topClass != refClass) { - appendClass(topClass, classElement); - } - } - - private static void appendMethod(final RefMethod refMethod, Element parentNode) { - Element methodElement = new Element(refMethod.isConstructor() ? "constructor" : "method"); - - PsiMethod psiMethod = (PsiMethod)refMethod.getElement(); - String name = PsiFormatUtil.formatMethod(psiMethod, PsiSubstitutor.EMPTY, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_FQ_NAME | - PsiFormatUtil.SHOW_TYPE | PsiFormatUtil.SHOW_PARAMETERS, - PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE); - - Element shortNameElement = new Element("name"); - shortNameElement.addContent(name); - methodElement.addContent(shortNameElement); - - Element displayName = new Element("name"); - displayName.addContent(refMethod.getQualifiedName()); - methodElement.addContent(displayName); - - appendClass(RefJavaUtil.getInstance().getTopLevelClass(refMethod), methodElement); - - parentNode.addContent(methodElement); - } - - private static void appendField(final RefField refField, Element parentNode) { - Element fieldElement = new Element("field"); - PsiField psiField = refField.getElement(); - String name = PsiFormatUtil.formatVariable(psiField, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_TYPE, PsiSubstitutor.EMPTY); - - Element shortNameElement = new Element("name"); - shortNameElement.addContent(name); - fieldElement.addContent(shortNameElement); - - Element displayName = new Element("display_name"); - displayName.addContent(refField.getQualifiedName()); - fieldElement.addContent(displayName); - - appendClass(RefJavaUtil.getInstance().getTopLevelClass(refField), fieldElement); - - parentNode.addContent(fieldElement); - } -} diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java index 6dd3558b6817..1862d7edc0ef 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/BaseConvertToLocalQuickFix.java @@ -46,7 +46,7 @@ import java.util.Set; * @author Danila Ponomarenko */ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implements LocalQuickFix { - private static final Logger LOG = Logger.getInstance(BaseConvertToLocalQuickFix.class); + protected static final Logger LOG = Logger.getInstance(BaseConvertToLocalQuickFix.class); @Override @NotNull @@ -89,10 +89,14 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen } @Nullable - private PsiElement moveDeclaration(@NotNull Project project, @NotNull V variable) { + protected PsiElement moveDeclaration(@NotNull Project project, @NotNull V variable) { final Collection<PsiReference> references = ReferencesSearch.search(variable).findAll(); if (references.isEmpty()) return null; + return moveDeclaration(project, variable, references, true); + } + + protected PsiElement moveDeclaration(Project project, V variable, final Collection<PsiReference> references, boolean delete) { final PsiCodeBlock anchorBlock = findAnchorBlock(references); if (anchorBlock == null) return null; //was assert, but need to fix the case when obsolete inspection highlighting is left if (!CodeInsightUtil.preparePsiElementsForWrite(anchorBlock)) return null; @@ -113,6 +117,7 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen anchorAssignmentExpression.getRExpression(), variable, refsSet, + delete, new NotNullFunction<PsiDeclarationStatement, PsiElement>() { @NotNull @Override @@ -132,6 +137,7 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen variable.getInitializer(), variable, references, + delete, new NotNullFunction<PsiDeclarationStatement, PsiElement>() { @NotNull @Override @@ -147,7 +153,7 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen @Nullable final PsiExpression initializer, @NotNull final V variable, @NotNull final Collection<PsiReference> references, - @NotNull final NotNullFunction<PsiDeclarationStatement, PsiElement> action) { + final boolean delete, @NotNull final NotNullFunction<PsiDeclarationStatement, PsiElement> action) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); return ApplicationManager.getApplication().runWriteAction( @@ -155,9 +161,11 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen @Override public PsiElement compute() { final PsiElement newDeclaration = moveDeclaration(elementFactory, localName, variable, initializer, action, references); - beforeDelete(project, variable, newDeclaration); - variable.normalizeDeclaration(); - variable.delete(); + if (delete) { + beforeDelete(project, variable, newDeclaration); + variable.normalizeDeclaration(); + variable.delete(); + } return newDeclaration; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java index 8eb519864e91..c82e779e84e1 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -25,6 +25,7 @@ import com.intellij.codeInspection.ex.BaseLocalInspectionTool; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.lang.java.JavaCommenter; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; @@ -36,6 +37,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.controlFlow.*; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.util.RefactoringUtil; @@ -47,10 +49,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.util.Collection; -import java.util.LinkedHashSet; +import java.util.*; import java.util.List; -import java.util.Set; /** * @author ven @@ -271,6 +271,63 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { private static class ConvertFieldToLocalQuickFix extends BaseConvertToLocalQuickFix<PsiField> { + @Nullable + @Override + protected PsiElement moveDeclaration(@NotNull final Project project, @NotNull final PsiField variable) { + final Map<PsiCodeBlock, Collection<PsiReference>> refs = new HashMap<PsiCodeBlock, Collection<PsiReference>>(); + groupByCodeBlocks(ReferencesSearch.search(variable).findAll(), refs); + PsiElement element = null; + for (Collection<PsiReference> psiReferences : refs.values()) { + element = super.moveDeclaration(project, variable, psiReferences, false); + } + if (element != null) { + final PsiElement finalElement = element; + Runnable runnable = new Runnable() { + public void run() { + beforeDelete(project, variable, finalElement); + variable.normalizeDeclaration(); + variable.delete(); + } + }; + ApplicationManager.getApplication().runWriteAction(runnable); + } + return element; + } + + private static void groupByCodeBlocks(final Collection<PsiReference> allReferences, Map<PsiCodeBlock, Collection<PsiReference>> refs) { + for (PsiReference psiReference : allReferences) { + final PsiElement element = psiReference.getElement(); + final PsiCodeBlock block = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class); + LOG.assertTrue(block != null); + Collection<PsiReference> references = refs.get(block); + if (references == null) { + references = new ArrayList<PsiReference>(); + if (findExistentBlock(refs, psiReference, block, references)) continue; + refs.put(block, references); + } + references.add(psiReference); + } + } + + private static boolean findExistentBlock(Map<PsiCodeBlock, Collection<PsiReference>> refs, + PsiReference psiReference, + PsiCodeBlock block, + Collection<PsiReference> references) { + for (Iterator<PsiCodeBlock> iterator = refs.keySet().iterator(); iterator.hasNext(); ) { + PsiCodeBlock codeBlock = iterator.next(); + if (PsiTreeUtil.isAncestor(codeBlock, block, false)) { + refs.get(codeBlock).add(psiReference); + return true; + } + else if (PsiTreeUtil.isAncestor(block, codeBlock, false)) { + references.addAll(refs.get(codeBlock)); + iterator.remove(); + break; + } + } + return false; + } + @Override @Nullable protected PsiField getVariable(@NotNull ProblemDescriptor descriptor) { diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java index 66980e986cc2..a0fb322bd5c4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/ParameterCanBeLocalInspection.java @@ -153,11 +153,12 @@ public class ParameterCanBeLocalInspection extends BaseJavaLocalInspectionTool { @Override protected PsiElement applyChanges(@NotNull final Project project, - @NotNull final String localName, - @Nullable final PsiExpression initializer, - @NotNull final PsiParameter parameter, - @NotNull final Collection<PsiReference> references, - @NotNull final NotNullFunction<PsiDeclarationStatement, PsiElement> action) { + @NotNull final String localName, + @Nullable final PsiExpression initializer, + @NotNull final PsiParameter parameter, + @NotNull final Collection<PsiReference> references, + boolean delete, + @NotNull final NotNullFunction<PsiDeclarationStatement, PsiElement> action) { final PsiElement scope = parameter.getDeclarationScope(); if (scope instanceof PsiMethod) { final PsiMethod method = (PsiMethod)scope; diff --git a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityExtension.java b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityExtension.java index 4036509945b7..ab0a63ebdff5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityExtension.java +++ b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityExtension.java @@ -17,7 +17,8 @@ package com.intellij.codeInspection.visibility; import com.intellij.codeInspection.ProblemDescriptionsProcessor; import com.intellij.codeInspection.reference.RefManager; +import org.jetbrains.annotations.NotNull; public interface VisibilityExtension { - void fillIgnoreList(RefManager refManager, ProblemDescriptionsProcessor processor); + void fillIgnoreList(@NotNull RefManager refManager, @NotNull ProblemDescriptionsProcessor processor); }
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java index 112c379b712c..88ff09b295a6 100644 --- a/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/visibility/VisibilityInspection.java @@ -403,7 +403,8 @@ public class VisibilityInspection extends GlobalJavaInspectionTool { @Override - protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, @NotNull final GlobalJavaInspectionContext globalContext, + protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, + @NotNull final GlobalJavaInspectionContext globalContext, @NotNull final ProblemDescriptionsProcessor processor) { final EntryPointsManager entryPointsManager = globalContext.getEntryPointsManager(manager); for (RefElement entryPoint : entryPointsManager.getEntryPoints()) { diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyNodeDescriptor.java b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyNodeDescriptor.java index c5847afc8a01..866e2cea0f5b 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyNodeDescriptor.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallHierarchyNodeDescriptor.java @@ -40,6 +40,7 @@ import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.ui.LayeredIcon; +import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; @@ -51,12 +52,11 @@ public final class CallHierarchyNodeDescriptor extends HierarchyNodeDescriptor i private final List<PsiReference> myReferences = new ArrayList<PsiReference>(); private final boolean myNavigateToReference; - public CallHierarchyNodeDescriptor( - final Project project, - final HierarchyNodeDescriptor parentDescriptor, - final PsiElement element, - final boolean isBase, - final boolean navigateToReference){ + public CallHierarchyNodeDescriptor(@NotNull Project project, + final HierarchyNodeDescriptor parentDescriptor, + @NotNull PsiElement element, + final boolean isBase, + final boolean navigateToReference) { super(project, parentDescriptor, element, isBase); myNavigateToReference = navigateToReference; } diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallerMethodsTreeStructure.java b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallerMethodsTreeStructure.java index 16ed3e93c250..b8770edc969f 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallerMethodsTreeStructure.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallerMethodsTreeStructure.java @@ -27,6 +27,7 @@ import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; +import org.jetbrains.annotations.NotNull; import java.util.HashSet; import java.util.Map; @@ -38,7 +39,7 @@ public final class CallerMethodsTreeStructure extends HierarchyTreeStructure { /** * Should be called in read action */ - public CallerMethodsTreeStructure(final Project project, final PsiMethod method, final String scopeType) { + public CallerMethodsTreeStructure(@NotNull Project project, @NotNull PsiMethod method, final String scopeType) { super(project, new CallHierarchyNodeDescriptor(project, null, method, true, false)); myScopeType = scopeType; } diff --git a/java/java-impl/src/com/intellij/ide/highlighter/JavaClsStructureViewBuilderProvider.java b/java/java-impl/src/com/intellij/ide/highlighter/JavaClsStructureViewBuilderProvider.java index 3d4f103cce09..7361877b7e69 100644 --- a/java/java-impl/src/com/intellij/ide/highlighter/JavaClsStructureViewBuilderProvider.java +++ b/java/java-impl/src/com/intellij/ide/highlighter/JavaClsStructureViewBuilderProvider.java @@ -27,6 +27,7 @@ import com.intellij.ide.structureView.impl.java.JavaFileTreeModel; import com.intellij.lang.Language; import com.intellij.lang.LanguageStructureViewBuilder; import com.intellij.lang.PsiStructureViewFactory; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileTypes.ContentBasedFileSubstitutor; import com.intellij.openapi.fileTypes.FileType; @@ -39,6 +40,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class JavaClsStructureViewBuilderProvider implements StructureViewBuilderProvider { + @Override @Nullable public StructureViewBuilder getStructureViewBuilder(@NotNull final FileType fileType, @NotNull final VirtualFile file, @NotNull final Project project) { @@ -58,9 +60,10 @@ public class JavaClsStructureViewBuilderProvider implements StructureViewBuilder final PsiJavaFile javaFile = (PsiJavaFile)psiFile; if (javaFile == null) return null; return new TreeBasedStructureViewBuilder() { + @Override @NotNull - public StructureViewModel createStructureViewModel() { - return new JavaFileTreeModel(javaFile); + public StructureViewModel createStructureViewModel(@Nullable Editor editor) { + return new JavaFileTreeModel(javaFile, editor); } }; } diff --git a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeModel.java b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeModel.java index d9c25eb53e28..962bf5f2c436 100644 --- a/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeModel.java +++ b/java/java-impl/src/com/intellij/ide/structureView/impl/java/JavaFileTreeModel.java @@ -23,9 +23,11 @@ import com.intellij.ide.util.treeView.smartTree.Filter; import com.intellij.ide.util.treeView.smartTree.Grouper; import com.intellij.ide.util.treeView.smartTree.NodeProvider; import com.intellij.ide.util.treeView.smartTree.Sorter; +import com.intellij.openapi.editor.Editor; import com.intellij.psi.*; import com.intellij.ui.PlaceHolder; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.Collection; @@ -36,11 +38,12 @@ public class JavaFileTreeModel extends TextEditorBasedStructureViewModel impleme private final PsiClassOwner myFile; private String myPlace; - public JavaFileTreeModel(@NotNull PsiClassOwner file) { - super(file); + public JavaFileTreeModel(@NotNull PsiClassOwner file, @Nullable Editor editor) { + super(editor, file); myFile = file; } + @Override @NotNull public Filter[] getFilters() { return new Filter[]{new FieldsFilter(), @@ -53,20 +56,24 @@ public class JavaFileTreeModel extends TextEditorBasedStructureViewModel impleme return NODE_PROVIDERS; } + @Override @NotNull public Grouper[] getGroupers() { return new Grouper[]{new SuperTypesGrouper(), new PropertiesGrouper()}; } + @Override @NotNull public StructureViewTreeElement getRoot() { return new JavaFileTreeElement(myFile); } + @Override public boolean shouldEnterElement(final Object element) { return element instanceof PsiClass; } + @Override @NotNull public Sorter[] getSorters() { return new Sorter[] { @@ -76,15 +83,18 @@ public class JavaFileTreeModel extends TextEditorBasedStructureViewModel impleme Sorter.ALPHA_SORTER}; } + @Override protected PsiFile getPsiFile() { return myFile; } + @Override public boolean isAlwaysShowsPlus(StructureViewTreeElement element) { Object value = element.getValue(); return value instanceof PsiClass || value instanceof PsiFile; } + @Override public boolean isAlwaysLeaf(StructureViewTreeElement element) { Object value = element.getValue(); return value instanceof PsiMethod || value instanceof PsiField; @@ -113,6 +123,7 @@ public class JavaFileTreeModel extends TextEditorBasedStructureViewModel impleme return false; } + @Override @NotNull protected Class[] getSuitableClasses() { return new Class[]{PsiClass.class, PsiMethod.class, PsiField.class, PsiJavaFile.class}; diff --git a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java index e42aff93b76e..402e7f54e0dc 100644 --- a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java +++ b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java @@ -19,18 +19,20 @@ import com.intellij.ide.util.DefaultPsiElementCellRenderer; import com.intellij.navigation.ChooseByNameContributor; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; public class DefaultSymbolNavigationContributor implements ChooseByNameContributor { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.DefaultSymbolNavigationContributor"); @@ -52,45 +54,41 @@ public class DefaultSymbolNavigationContributor implements ChooseByNameContribut GlobalSearchScope scope = includeNonProjectItems ? GlobalSearchScope.allScope(project) : GlobalSearchScope.projectScope(project); PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project); - PsiMethod[] methods = cache.getMethodsByName(name, scope); - methods = filterInheritedMethods(methods); - PsiField[] fields = cache.getFieldsByName(name, scope); - PsiClass[] classes = cache.getClassesByName(name, scope); - List<PsiMember> result = new ArrayList<PsiMember>(); - ContainerUtil.addAll(result, methods); - ContainerUtil.addAll(result, fields); - ContainerUtil.addAll(result, classes); - filterOutNonOpenable(result); + for (PsiMethod method : cache.getMethodsByName(name, scope)) { + if (!method.isConstructor() && isOpenable(method) && !hasSuperMethod(method)) { + result.add(method); + } + } + for (PsiField field : cache.getFieldsByName(name, scope)) { + if (isOpenable(field)) { + result.add(field); + } + } + for (PsiClass aClass : cache.getClassesByName(name, scope)) { + if (isOpenable(aClass)) { + result.add(aClass); + } + } PsiMember[] array = result.toArray(new PsiMember[result.size()]); Arrays.sort(array, MyComparator.INSTANCE); return array; } - private static void filterOutNonOpenable(List<PsiMember> members) { - ListIterator<PsiMember> it = members.listIterator(); - while (it.hasNext()) { - PsiMember member = it.next(); - if (isNonOpenable(member)) { - it.remove(); - } - } + private static boolean isOpenable(PsiMember member) { + return member.getContainingFile().getVirtualFile() != null; } - private static boolean isNonOpenable(PsiMember member) { - return member.getContainingFile().getVirtualFile() == null; - } + private static boolean hasSuperMethod(PsiMethod method) { + PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) return false; - private static PsiMethod[] filterInheritedMethods(PsiMethod[] methods) { - ArrayList<PsiMethod> list = new ArrayList<PsiMethod>(methods.length); - for (PsiMethod method : methods) { - ProgressManager.checkCanceled(); - if (method.isConstructor()) continue; - PsiMethod[] supers = method.findSuperMethods(); - if (supers.length > 0) continue; - list.add(method); + for (PsiMethod candidate : containingClass.findMethodsByName(method.getName(), true)) { + if (candidate.getContainingClass() != containingClass && PsiSuperMethodImplUtil.isSuperMethodSmart(method, candidate)) { + return true; + } } - return list.toArray(new PsiMethod[list.size()]); + return false; } private static class MyComparator implements Comparator<PsiModifierListOwner>{ diff --git a/java/java-impl/src/com/intellij/lang/java/JavaStructureViewBuilderFactory.java b/java/java-impl/src/com/intellij/lang/java/JavaStructureViewBuilderFactory.java index a353cff157f5..e8d4eba8a8ed 100644 --- a/java/java-impl/src/com/intellij/lang/java/JavaStructureViewBuilderFactory.java +++ b/java/java-impl/src/com/intellij/lang/java/JavaStructureViewBuilderFactory.java @@ -24,6 +24,7 @@ import com.intellij.ide.structureView.StructureViewModel; import com.intellij.ide.structureView.TreeBasedStructureViewBuilder; import com.intellij.ide.structureView.impl.java.JavaFileTreeModel; import com.intellij.lang.PsiStructureViewFactory; +import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiJavaFile; import org.jetbrains.annotations.NotNull; @@ -37,8 +38,8 @@ public class JavaStructureViewBuilderFactory implements PsiStructureViewFactory return new TreeBasedStructureViewBuilder() { @Override @NotNull - public StructureViewModel createStructureViewModel() { - return new JavaFileTreeModel((PsiJavaFile)psiFile); + public StructureViewModel createStructureViewModel(@Nullable Editor editor) { + return new JavaFileTreeModel((PsiJavaFile)psiFile, editor); } @Override diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java index e81e167d3c45..1376f44c07ca 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java @@ -296,7 +296,12 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor { } else if (myRole1 == ChildRole.FIELD) { int lines = Math.max(getLinesAroundField(), getLinesAroundMethod()) + 1; - myResult = Spacing.createSpacing(0, mySettings.SPACE_BEFORE_CLASS_LBRACE ? 1 : 0, 0, true, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE, + // IJ has been keeping initialization block which starts at the same line as a field for a while. + // However, it's not convenient for a situation when particular code is created via PSI - it's easier to not bothering + // with whitespace elements when inserting, say, new initialization blocks. That's why we don't enforce new line + // only during explicit reformatting ('Reformat' action). + int minLineFeeds = FormatterUtil.isFormatterCalledExplicitly() ? 0 : 1; + myResult = Spacing.createSpacing(0, mySettings.SPACE_BEFORE_CLASS_LBRACE ? 1 : 0, 1, true, mySettings.KEEP_BLANK_LINES_BEFORE_RBRACE, lines); } else if (myRole1 == ChildRole.CLASS) { diff --git a/java/java-impl/src/com/intellij/psi/impl/PackagePrefixElementFinder.java b/java/java-impl/src/com/intellij/psi/impl/PackagePrefixElementFinder.java index 7f58413a051f..0f2df2db49ab 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PackagePrefixElementFinder.java +++ b/java/java-impl/src/com/intellij/psi/impl/PackagePrefixElementFinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -68,7 +68,7 @@ public class PackagePrefixElementFinder extends PsiElementFinder implements Dumb final String qualifiedName = psiPackage.getQualifiedName(); for (final String prefix : myPackagePrefixIndex.getAllPackagePrefixes(scope)) { - if (StringUtil.isEmpty(qualifiedName) || StringUtil.startsWithConcatenationOf(prefix, qualifiedName, ".")) { + if (StringUtil.isEmpty(qualifiedName) || StringUtil.startsWithConcatenation(prefix, qualifiedName, ".")) { final int i = prefix.indexOf('.', qualifiedName.length() + 1); String childName = i >= 0 ? prefix.substring(0, i) : prefix; if (!packagesMap.containsKey(childName)) { @@ -83,7 +83,7 @@ public class PackagePrefixElementFinder extends PsiElementFinder implements Dumb public boolean packagePrefixExists(String packageQName) { for (final String prefix : myPackagePrefixIndex.getAllPackagePrefixes(null)) { - if (StringUtil.startsWithConcatenationOf(prefix, packageQName, ".") || prefix.equals(packageQName)) { + if (StringUtil.startsWithConcatenation(prefix, packageQName, ".") || prefix.equals(packageQName)) { return true; } } diff --git a/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java b/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java index a80ffad06db3..57f919f9e63e 100644 --- a/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java +++ b/java/java-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfoFactory.java @@ -20,6 +20,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.source.PsiFileWithStubSupport; import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.stubs.StubTree; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.psi.xml.XmlTag; import com.intellij.xml.util.XmlTagUtil; import org.jetbrains.annotations.NotNull; @@ -55,7 +56,7 @@ public class AnchorElementInfoFactory implements SmartPointerElementInfoFactory @Nullable static PsiElement getAnchor(PsiElement element) { - LOG.assertTrue(element.isValid()); + PsiUtilCore.ensureValid(element); PsiElement anchor = null; if (element instanceof PsiClass) { if (element instanceof PsiAnonymousClass) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java index 15716567cab7..39a8cdc7a516 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/ImportHelper.java @@ -124,7 +124,7 @@ public class ImportHelper{ } public static void collectOnDemandImports(List<Pair<String, Boolean>> resultList, - final Set<String> classesOrPackagesToImportOnDemand, + final Set<String> classesOrPackagesToImportOnDemand, final CodeStyleSettings settings) { TObjectIntHashMap<String> packageToCountMap = new TObjectIntHashMap<String>(); TObjectIntHashMap<String> classToCountMap = new TObjectIntHashMap<String>(); @@ -132,7 +132,7 @@ public class ImportHelper{ String name = pair.getFirst(); Boolean isStatic = pair.getSecond(); String packageOrClassName = getPackageOrClassName(name); - if (packageOrClassName.length() == 0) continue; + if (packageOrClassName.isEmpty()) continue; if (isStatic) { int count = classToCountMap.get(packageOrClassName); classToCountMap.put(packageOrClassName, count + 1); @@ -209,12 +209,12 @@ public class ImportHelper{ String name = pair.getFirst(); Boolean isStatic = pair.getSecond(); String prefix = getPackageOrClassName(name); - if (prefix.length() == 0) continue; + if (prefix.isEmpty()) continue; final boolean isImplicitlyImported = implicitlyImportedPackages.contains(prefix); if (!onDemandImports.contains(prefix) && !isImplicitlyImported) continue; String shortName = PsiNameHelper.getShortClassName(name); - String thisPackageClass = thisPackageName.length() > 0 ? thisPackageName + "." + shortName : shortName; + String thisPackageClass = !thisPackageName.isEmpty() ? thisPackageName + "." + shortName : shortName; if (JavaPsiFacade.getInstance(manager.getProject()).findClass(thisPackageClass, resolveScope) != null) { namesToUseSingle.add(name); continue; @@ -303,7 +303,7 @@ public class ImportHelper{ conflicts.addAll(inter); } } - if (!conflicts.isEmpty()) { + if (!conflicts.isEmpty() && !(file instanceof PsiCompiledElement)) { file.accept(new JavaRecursiveElementVisitor() { @Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { @@ -382,7 +382,7 @@ public class ImportHelper{ } boolean useOnDemand = true; - if (packageName.length() == 0){ + if (packageName.isEmpty()){ useOnDemand = false; } @@ -640,7 +640,7 @@ public class ImportHelper{ int limitCount = isStaticImportNeeded ? settings.NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND : settings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND; if (classCount >= limitCount) return true; - if (packageName.length() == 0) return false; + if (packageName.isEmpty()) return false; PackageEntryTable table = settings.PACKAGES_TO_USE_IMPORT_ON_DEMAND; return table != null && table.contains(packageName); } @@ -839,21 +839,23 @@ public class ImportHelper{ final boolean[] hasResolveProblem = {false}; // do not visit imports for (PsiClass aClass : file.getClasses()) { - aClass.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { - String name = reference.getReferenceName(); - Pair<String, Boolean> pair = unresolvedNames.get(name); - if (reference.multiResolve(false).length == 0) { - hasResolveProblem[0] = true; - if (pair != null) { - namesToImport.add(pair); - unresolvedNames.remove(name); + if (!(aClass instanceof PsiCompiledElement)) { + aClass.accept(new JavaRecursiveElementWalkingVisitor() { + @Override + public void visitReferenceElement(PsiJavaCodeReferenceElement reference) { + String name = reference.getReferenceName(); + Pair<String, Boolean> pair = unresolvedNames.get(name); + if (reference.multiResolve(false).length == 0) { + hasResolveProblem[0] = true; + if (pair != null) { + namesToImport.add(pair); + unresolvedNames.remove(name); + } } + super.visitReferenceElement(reference); } - super.visitReferenceElement(reference); - } - }); + }); + } } if (hasResolveProblem[0]) { namesToImport.addAll(unresolvedOnDemand); @@ -872,7 +874,7 @@ public class ImportHelper{ public static boolean hasPackage(@NotNull String className, @NotNull String packageName){ if (!className.startsWith(packageName)) return false; if (className.length() == packageName.length()) return false; - if (packageName.length() > 0 && className.charAt(packageName.length()) != '.') return false; + if (!packageName.isEmpty() && className.charAt(packageName.length()) != '.') return false; return className.indexOf('.', packageName.length() + 1) < 0; } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDClassComment.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDClassComment.java index ad0e0d5b353c..354e8533c298 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDClassComment.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDClassComment.java @@ -15,9 +15,11 @@ */ package com.intellij.psi.impl.source.codeStyle.javadoc; -import org.jetbrains.annotations.NonNls; +import com.intellij.util.containers.ContainerUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; +import java.util.List; /** * Class comment @@ -25,51 +27,45 @@ import java.util.ArrayList; * @author Dmitry Skavish */ public class JDClassComment extends JDParamListOwnerComment { - public JDClassComment(CommentFormatter formatter) { + private List<String> myAuthorsList; + private String myVersion; + + public JDClassComment(@NotNull CommentFormatter formatter) { super(formatter); } - private ArrayList authorsList; - private String version; - @Override - protected void generateSpecial(String prefix, @NonNls StringBuffer sb) { + protected void generateSpecial(@NotNull String prefix, @NotNull StringBuilder sb) { super.generateSpecial(prefix, sb); - if (!isNull(authorsList)) { - for (Object aAuthorsList : authorsList) { - String s = (String)aAuthorsList; + if (!isNull(myAuthorsList)) { + JDTag tag = JDTag.AUTHOR; + for (String author : myAuthorsList) { sb.append(prefix); - sb.append("@author "); - sb.append(myFormatter.getParser().splitIntoCLines(s, prefix + " ", false)); + sb.append(tag.getWithEndWhitespace()); + sb.append(myFormatter.getParser().formatJDTagDescription(author, tag.getDescriptionPrefix(prefix))); } } - if (!isNull(version)) { + if (!isNull(myVersion)) { sb.append(prefix); - sb.append("@version "); - sb.append(myFormatter.getParser().splitIntoCLines(version, prefix + " ", false)); + JDTag tag = JDTag.VERSION; + sb.append(tag.getWithEndWhitespace()); + sb.append(myFormatter.getParser().formatJDTagDescription(myVersion, tag.getDescriptionPrefix(prefix))); } } - public void addAuthor(String author) { - if (authorsList == null) { - authorsList = new ArrayList(); + public void addAuthor(@NotNull String author) { + if (myAuthorsList == null) { + myAuthorsList = ContainerUtilRt.newArrayList(); } - authorsList.add(author); - } - - public ArrayList getAuthorsList() { - return authorsList; - } - - public void setAuthorsList(ArrayList authorsList) { - this.authorsList = authorsList; + myAuthorsList.add(author); } + @Nullable public String getVersion() { - return version; + return myVersion; } - public void setVersion(String version) { - this.version = version; + public void setVersion(@NotNull String version) { + this.myVersion = version; } }
\ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java index cedc9647c49e..28dc6a359942 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDComment.java @@ -15,9 +15,11 @@ */ package com.intellij.psi.impl.source.codeStyle.javadoc; -import org.jetbrains.annotations.NonNls; +import com.intellij.util.containers.ContainerUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; +import java.util.List; /** * @author max @@ -27,43 +29,42 @@ import java.util.ArrayList; * @author Dmitry Skavish */ public class JDComment { - protected CommentFormatter myFormatter; + protected final CommentFormatter myFormatter; - String description; - protected ArrayList unknownList; - protected ArrayList seeAlsoList; - protected String since; - String deprecated; + private String myDescription; + private List<String> myUnknownList; + private List<String> mySeeAlsoList; + private String mySince; + private String myDeprecated; - //protected LinkedHashMap xdocTagMap = new LinkedHashMap(); - - public JDComment(CommentFormatter formatter) { + public JDComment(@NotNull CommentFormatter formatter) { myFormatter = formatter; } - protected static boolean isNull(String s) { + protected static boolean isNull(@Nullable String s) { return s == null || s.trim().length() == 0; } - protected static boolean isNull(ArrayList l) { + protected static boolean isNull(@Nullable List<?> l) { return l == null || l.size() == 0; } - public String generate(String indent) { + @Nullable + public String generate(@NotNull String indent) { final String prefix; + if (myFormatter.getSettings().JD_LEADING_ASTERISKS_ARE_ENABLED) { prefix = indent + " * "; } else { prefix = indent; } - @NonNls StringBuffer sb = new StringBuffer(); -// sb.append("/**\n"); - + StringBuilder sb = new StringBuilder(); int start = sb.length(); - if (!isNull(description)) { - sb.append(myFormatter.getParser().splitIntoCLines(description, prefix)); + if (!isNull(myDescription)) { + sb.append(prefix); + sb.append(myFormatter.getParser().formatJDTagDescription(myDescription, prefix)); if (myFormatter.getSettings().JD_ADD_BLANK_AFTER_DESCRIPTION) { sb.append(prefix); @@ -73,48 +74,40 @@ public class JDComment { generateSpecial(prefix, sb); - if (!isNull(unknownList) && myFormatter.getSettings().JD_KEEP_INVALID_TAGS) { - for (Object aUnknownList : unknownList) { - String s = (String)aUnknownList; - sb.append(myFormatter.getParser().splitIntoCLines(s, prefix)); + if (!isNull(myUnknownList) && myFormatter.getSettings().JD_KEEP_INVALID_TAGS) { + for (String aUnknownList : myUnknownList) { + sb.append(prefix); + sb.append(myFormatter.getParser().formatJDTagDescription(aUnknownList, prefix)); } } - /* - if( xdocTagMap.size() > 0 ) { - Iterator it = xdocTagMap.values().iterator(); - while( it.hasNext() ) { - ArrayList list = (ArrayList) it.next(); - for( int i = 0; i<list.size(); i++ ) { - XDTag tag = (XDTag) list.get(i); - tag.append(sb, prefix); - if( myFormatter.getSettings().add_blank_after_xdoclet_tag ) { - sb.append(prefix); - sb.append('\n'); - } - } - } - }*/ - - if (!isNull(seeAlsoList)) { - for (Object aSeeAlsoList : seeAlsoList) { - String s = (String)aSeeAlsoList; + if (!isNull(mySeeAlsoList)) { + JDTag tag = JDTag.SEE; + for (String aSeeAlsoList : mySeeAlsoList) { sb.append(prefix); - sb.append("@see "); - sb.append(myFormatter.getParser().splitIntoCLines(s, prefix + " ", false)); + sb.append(tag.getWithEndWhitespace()); + StringBuilder tagDescription = myFormatter.getParser() + .formatJDTagDescription(aSeeAlsoList, prefix, true, tag.getDescriptionPrefix(prefix).length()); + sb.append(tagDescription); } } - if (!isNull(since)) { + if (!isNull(mySince)) { + JDTag tag = JDTag.SINCE; sb.append(prefix); - sb.append("@since "); - sb.append(myFormatter.getParser().splitIntoCLines(since, prefix + " ", false)); + sb.append(tag.getWithEndWhitespace()); + StringBuilder tagDescription = myFormatter.getParser() + .formatJDTagDescription(mySince, prefix, true, tag.getDescriptionPrefix(prefix).length()); + sb.append(tagDescription); } - if (deprecated != null) { + if (myDeprecated != null) { + JDTag tag = JDTag.DEPRECATED; sb.append(prefix); - sb.append("@deprecated "); - sb.append(myFormatter.getParser().splitIntoCLines(deprecated, prefix + " ", false)); + sb.append(tag.getWithEndWhitespace()); + StringBuilder tagDescription = myFormatter.getParser() + .formatJDTagDescription(myDeprecated, prefix, true, tag.getDescriptionPrefix(prefix).length()); + sb.append(tagDescription); } if (sb.length() == start) return null; @@ -139,77 +132,37 @@ public class JDComment { return sb.toString(); } - protected void generateSpecial(String prefix, StringBuffer sb) { - } - - public void addSeeAlso(String seeAlso) { - if (seeAlsoList == null) { - seeAlsoList = new ArrayList(); - } - seeAlsoList.add(seeAlso); + protected void generateSpecial(@NotNull String prefix, @NotNull StringBuilder sb) { } - public void addUnknownTag(String unknownTag) { - if (unknownList == null) { - unknownList = new ArrayList(); + public void addSeeAlso(@NotNull String seeAlso) { + if (mySeeAlsoList == null) { + mySeeAlsoList = ContainerUtilRt.newArrayList(); } - unknownList.add(unknownTag); + mySeeAlsoList.add(seeAlso); } -/* - public void addXDocTag( XDTag tag ) { - getXdocTagList(tag.getNamespaceDesc()).add(tag); - } - - public ArrayList getXdocTagList( String nsName ) { - ArrayList list = (ArrayList) xdocTagMap.get(nsName); - if( list == null ) { - list = new ArrayList(); - xdocTagMap.put(nsName, list); - } - return list; - } - public ArrayList getXdocTagList( XDNamespaceDesc desc ) { - return getXdocTagList(desc.getName()); + public void addUnknownTag(@NotNull String unknownTag) { + if (myUnknownList == null) { + myUnknownList = ContainerUtilRt.newArrayList(); } -*/ - public ArrayList getSeeAlsoList() { - return seeAlsoList; - } - - public void setUnknownList(ArrayList unknownList) { - this.unknownList = unknownList; - } - - public void setSeeAlsoList(ArrayList seeAlsoList) { - this.seeAlsoList = seeAlsoList; - } - - public ArrayList getUnknownList() { - return unknownList; - } - - public String getSince() { - return since; - } - - public void setSince(String since) { - this.since = since; + myUnknownList.add(unknownTag); } - public String getDeprecated() { - return deprecated; + public void setSince(@Nullable String since) { + this.mySince = since; } - public void setDeprecated(String deprecated) { - this.deprecated = deprecated; + public void setDeprecated(@Nullable String deprecated) { + this.myDeprecated = deprecated; } + @Nullable public String getDescription() { - return description; + return myDescription; } - public void setDescription(String description) { - this.description = description; + public void setDescription(@Nullable String description) { + this.myDescription = description; } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDMethodComment.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDMethodComment.java index 6fd664b1add7..0059b2f1274f 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDMethodComment.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDMethodComment.java @@ -15,9 +15,11 @@ */ package com.intellij.psi.impl.source.codeStyle.javadoc; -import org.jetbrains.annotations.NonNls; +import com.intellij.util.containers.ContainerUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; +import java.util.List; /** * Method comment @@ -25,26 +27,23 @@ import java.util.ArrayList; * @author Dmitry Skavish */ public class JDMethodComment extends JDParamListOwnerComment { - public JDMethodComment(CommentFormatter formatter) { + private String myReturnTag; + private List<NameDesc> myThrowsList; + + public JDMethodComment(@NotNull CommentFormatter formatter) { super(formatter); } - private String returnTag; - private ArrayList<NameDesc> throwsList; - - private static final @NonNls String THROWS_TAG = "@throws "; - private static final @NonNls String EXCEPTION_TAG = "@exception "; - @Override - protected void generateSpecial(String prefix, @NonNls StringBuffer sb) { - + protected void generateSpecial(@NotNull String prefix, @NotNull StringBuilder sb) { super.generateSpecial(prefix, sb); - if (returnTag != null) { - if (returnTag.trim().length() != 0 || myFormatter.getSettings().JD_KEEP_EMPTY_RETURN) { + if (myReturnTag != null) { + if (myFormatter.getSettings().JD_KEEP_EMPTY_RETURN || myReturnTag.trim().length() != 0) { + JDTag tag = JDTag.RETURN; sb.append(prefix); - sb.append("@return "); - sb.append(myFormatter.getParser().splitIntoCLines(returnTag, prefix + " ", false)); + sb.append(tag.getWithEndWhitespace()); + sb.append(myFormatter.getParser().formatJDTagDescription(myReturnTag, prefix, true, tag.getDescriptionPrefix(prefix).length())); if (myFormatter.getSettings().JD_ADD_BLANK_AFTER_RETURN) { sb.append(prefix); sb.append('\n'); @@ -52,48 +51,24 @@ public class JDMethodComment extends JDParamListOwnerComment { } } - if (throwsList != null) { - String tag = myFormatter.getSettings().JD_USE_THROWS_NOT_EXCEPTION ? THROWS_TAG : EXCEPTION_TAG; - generateList(prefix, sb, throwsList, tag, + if (myThrowsList != null) { + JDTag tag = myFormatter.getSettings().JD_USE_THROWS_NOT_EXCEPTION ? JDTag.THROWS : JDTag.EXCEPTION; + generateList(prefix, sb, myThrowsList, tag.getWithEndWhitespace(), myFormatter.getSettings().JD_ALIGN_EXCEPTION_COMMENTS, - myFormatter.getSettings().JD_MIN_EXCEPTION_NAME_LENGTH, - myFormatter.getSettings().JD_MAX_EXCEPTION_NAME_LENGTH, myFormatter.getSettings().JD_KEEP_EMPTY_EXCEPTION, myFormatter.getSettings().JD_PARAM_DESCRIPTION_ON_NEW_LINE ); } } - public String getReturnTag() { - return returnTag; - } - - public void setReturnTag(String returnTag) { - this.returnTag = returnTag; - } - - public void removeThrow(NameDesc nd) { - if (throwsList == null) return; - throwsList.remove(nd); + public void setReturnTag(@NotNull String returnTag) { + this.myReturnTag = returnTag; } - public ArrayList<NameDesc> getThrowsList() { - return throwsList; - } - - public void addThrow(String className, String description) { - if (throwsList == null) { - throwsList = new ArrayList<NameDesc>(); + public void addThrow(@NotNull String className, @Nullable String description) { + if (myThrowsList == null) { + myThrowsList = ContainerUtilRt.newArrayList(); } - throwsList.add(new NameDesc(className, description)); - } - - public NameDesc getThrow(String name) { - return getNameDesc(name, throwsList); + myThrowsList.add(new NameDesc(className, description)); } - - public void setThrowsList(ArrayList<NameDesc> throwsList) { - this.throwsList = throwsList; - } - } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParamListOwnerComment.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParamListOwnerComment.java index 64af28761b09..c004bc9adbb1 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParamListOwnerComment.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParamListOwnerComment.java @@ -22,28 +22,28 @@ package com.intellij.psi.impl.source.codeStyle.javadoc; import com.intellij.formatting.IndentInfo; import com.intellij.ide.highlighter.JavaFileType; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; -import org.jetbrains.annotations.NonNls; +import com.intellij.util.containers.ContainerUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; +import java.util.List; -public class JDParamListOwnerComment extends JDComment{ - protected ArrayList<NameDesc> parmsList; - private static final @NonNls String PARAM_TAG = "@param "; +public class JDParamListOwnerComment extends JDComment { + protected List<NameDesc> myParamsList; - public JDParamListOwnerComment(CommentFormatter formatter) { + public JDParamListOwnerComment(@NotNull CommentFormatter formatter) { super(formatter); } @Override - protected void generateSpecial(String prefix, StringBuffer sb) { - if (parmsList != null) { + protected void generateSpecial(@NotNull String prefix, @NotNull StringBuilder sb) { + if (myParamsList != null) { int before = sb.length(); - generateList(prefix, sb, parmsList, PARAM_TAG, + generateList(prefix, sb, myParamsList, JDTag.PARAM.getWithEndWhitespace(), myFormatter.getSettings().JD_ALIGN_PARAM_COMMENTS, - myFormatter.getSettings().JD_MIN_PARM_NAME_LENGTH, - myFormatter.getSettings().JD_MAX_PARM_NAME_LENGTH, myFormatter.getSettings().JD_KEEP_EMPTY_PARAMETER, myFormatter.getSettings().JD_PARAM_DESCRIPTION_ON_NEW_LINE ); @@ -56,35 +56,25 @@ public class JDParamListOwnerComment extends JDComment{ } } - public NameDesc getParameter(String name) { - return getNameDesc(name, parmsList); + @Nullable + public NameDesc getParameter(@Nullable String name) { + return getNameDesc(name, myParamsList); } - public void removeParameter(NameDesc nd) { - if (parmsList == null) return; - parmsList.remove(nd); - } - - public ArrayList<NameDesc> getParmsList() { - return parmsList; - } - - public void addParameter(String name, String description) { - if (parmsList == null) { - parmsList = new ArrayList<NameDesc>(); + public void addParameter(@NotNull String name, @Nullable String description) { + if (myParamsList == null) { + myParamsList = ContainerUtilRt.newArrayList(); } - parmsList.add(new NameDesc(name, description)); + myParamsList.add(new NameDesc(name, description)); } - public void setParmsList(ArrayList<NameDesc> parmsList) { - this.parmsList = parmsList; - } - - static NameDesc getNameDesc(String name, ArrayList<NameDesc> list) { + @Nullable + private static NameDesc getNameDesc(@Nullable String name, @Nullable List<NameDesc> list) { if (list == null) return null; - for (Object aList : list) { - NameDesc parameter = (NameDesc)aList; - if (parameter.name.equals(name)) return parameter; + for (NameDesc aList : list) { + if (aList.name.equals(name)) { + return aList; + } } return null; } @@ -93,59 +83,56 @@ public class JDParamListOwnerComment extends JDComment{ * Generates parameters or exceptions * */ - protected void generateList(String prefix, StringBuffer sb, ArrayList<NameDesc> list, String tag, boolean align_comments, - int min_name_length, int max_name_length, boolean generate_empty_tags, boolean wrapDescription) + protected void generateList(@NotNull String prefix, + @NotNull StringBuilder sb, + @NotNull List<NameDesc> list, + @NotNull String tag, + boolean align_comments, + boolean generate_empty_tags, + boolean wrapDescription) { CodeStyleSettings settings = myFormatter.getSettings(); CommonCodeStyleSettings.IndentOptions indentOptions = settings.getIndentOptions(JavaFileType.INSTANCE); String continuationIndent = new IndentInfo(0, indentOptions.CONTINUATION_INDENT_SIZE, 0).generateNewWhiteSpace(indentOptions); + int max = 0; - if (align_comments && ! wrapDescription) { - for (Object aList : list) { - NameDesc nd = (NameDesc)aList; - int l = nd.name.length(); + + if (align_comments && !wrapDescription) { + for (NameDesc nd: list) { + int currentLength = nd.name.length(); if (isNull(nd.desc) && !generate_empty_tags) continue; - if (l > max && l <= max_name_length) max = l; + //finding longest parameter length + if (currentLength > max) { + max = currentLength; + } } } - max = Math.max(max, min_name_length); - - // create filler - StringBuffer fill = new StringBuffer(prefix.length() + tag.length() + max + 1); + StringBuilder fill = new StringBuilder(prefix.length() + tag.length() + max + 1); fill.append(prefix); - int k = max + 1 + tag.length(); - for (int i = 0; i < k; i++) fill.append(' '); + StringUtil.repeatSymbol(fill, ' ', max + 1 + tag.length()); String wrapParametersPrefix = prefix + continuationIndent; - - for (Object aList1 : list) { - NameDesc nd = (NameDesc)aList1; + for (NameDesc nd : list) { if (isNull(nd.desc) && !generate_empty_tags) continue; if (wrapDescription && !isNull(nd.desc)) { sb.append(prefix).append(tag).append(nd.name).append("\n"); - sb.append(myFormatter.getParser().splitIntoCLines(nd.desc, wrapParametersPrefix)); + sb.append(wrapParametersPrefix); + sb.append(myFormatter.getParser().formatJDTagDescription(nd.desc, wrapParametersPrefix)); } else if (align_comments) { sb.append(prefix); sb.append(tag); sb.append(nd.name); - - if (nd.name.length() > max_name_length) { - sb.append('\n'); - sb.append(myFormatter.getParser().splitIntoCLines(nd.desc, fill, true)); - } - else { - int len = max - nd.name.length() + 1; - for (int j = 0; j < len; j++) { - sb.append(' '); - } - sb.append(myFormatter.getParser().splitIntoCLines(nd.desc, fill, false)); - } + int spacesNumber = max + 1 - nd.name.length(); + StringUtil.repeatSymbol(sb, ' ', Math.max(0, spacesNumber)); + sb.append(myFormatter.getParser().formatJDTagDescription(nd.desc, fill)); } else { - sb.append(myFormatter.getParser().splitIntoCLines(tag + nd.name + " " + nd.desc, prefix, true)); + sb.append(prefix); + String description = (nd.desc == null) ? "" : nd.desc; + sb.append(myFormatter.getParser().formatJDTagDescription(tag + nd.name + " " + description, prefix)); } } } -}
\ No newline at end of file +} diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java index 1f7d047acc7a..859e848d3304 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDParser.java @@ -16,8 +16,9 @@ package com.intellij.psi.impl.source.codeStyle.javadoc; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.CodeStyleSettings; -import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -26,27 +27,31 @@ import java.util.StringTokenizer; /** * Javadoc parser - * + * * @author Dmitry Skavish */ public class JDParser { - + private static final String PRE_TAG_START = "<pre>"; private static final String PRE_TAG_END = "</pre>"; - + private static final String P_END_TAG = "</p>"; + private static final String P_START_TAG = "<p>"; + private static final String SELF_CLOSED_P_TAG = "<p/>"; + private final CodeStyleSettings mySettings; - public JDParser(CodeStyleSettings settings) { + public JDParser(@NotNull CodeStyleSettings settings) { mySettings = settings; } private static final char lineSeparator = '\n'; - public JDComment parse(String text, JDComment c) { + @NotNull + public JDComment parse(@Nullable String text, @NotNull JDComment c) { if (text == null) return c; - ArrayList<Boolean> markers = new ArrayList<Boolean>(); - ArrayList<String> l = toArray(text, "\n", markers); + List<Boolean> markers = new ArrayList<Boolean>(); + List<String> l = toArray(text, "\n", markers); if (l == null) return c; int size = l.size(); if (size == 0) return c; @@ -73,7 +78,7 @@ public class JDParser { l.set(i, line); } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); String tag = null; for (int i = 0; i <= size; i++) { String line = i == size ? null : l.get(i); @@ -126,42 +131,22 @@ public class JDParser { } /** - * Breaks the specified string by lineseparator into array of strings - * - * @param s the specified string - * @return array of strings (lines) - */ - public ArrayList<String> toArrayByNL(String s) { - return toArray(s, "\n", null); - } - - /** - * Breaks the specified string by comma into array of strings - * - * @param s the specified string - * @return list of strings - */ - public ArrayList<String> toArrayByComma(String s) { - return toArray(s, ",", null); - } - - /** * Breaks the specified string by the specified separators into array of strings - * + * * @param s the specified string * @param separators the specified separators * @param markers if this parameter is not null then it will be filled with Boolean values: - * true if the correspoding line in returned list is inside <pre> tag, + * true if the corresponding line in returned list is inside <pre> tag, * false if it is outside * @return array of strings (lines) */ - @SuppressWarnings({"HardCodedStringLiteral"}) - private ArrayList<String> toArray(String s, String separators, ArrayList<Boolean> markers) { + @Nullable + private List<String> toArray(@Nullable String s, @NotNull String separators, @Nullable List<Boolean> markers) { if (s == null) return null; s = s.trim(); if (s.length() == 0) return null; boolean p2nl = markers != null && mySettings.JD_P_AT_EMPTY_LINES; - ArrayList<String> list = new ArrayList<String>(); + List<String> list = new ArrayList<String>(); StringTokenizer st = new StringTokenizer(s, separators, true); boolean first = true; int preCount = 0; @@ -170,7 +155,7 @@ public class JDParser { String token = st.nextToken(); curPos += token.length(); - if (separators.indexOf(token) >= 0) { + if (separators.contains(token)) { if (!first) { list.add(""); if (markers != null) markers.add(Boolean.valueOf(preCount > 0)); @@ -180,7 +165,7 @@ public class JDParser { else { first = true; if (p2nl) { - if (isParaTag(token) && s.indexOf("</p>", curPos) < 0) { + if (isParaTag(token) && s.indexOf(P_END_TAG, curPos) < 0) { list.add(""); markers.add(Boolean.valueOf(preCount > 0)); continue; @@ -191,9 +176,9 @@ public class JDParser { list.add(token); if (markers != null) { - if (token.indexOf("<pre>") >= 0) preCount++; + if (token.contains(PRE_TAG_START)) preCount++; markers.add(Boolean.valueOf(preCount > 0)); - if (token.indexOf("</pre>") >= 0) preCount--; + if (token.contains(PRE_TAG_END)) preCount--; } } @@ -201,56 +186,30 @@ public class JDParser { return list; } - @SuppressWarnings({"HardCodedStringLiteral"}) - private boolean isParaTag(final String token) { + private static boolean isParaTag(@NotNull final String token) { String withoutWS = removeWhiteSpacesFrom(token).toLowerCase(); - return withoutWS.equals("<p/>") || withoutWS.equals("<p>"); + return withoutWS.equals(SELF_CLOSED_P_TAG) || withoutWS.equals(P_START_TAG); } - private String removeWhiteSpacesFrom(final String token) { - final StringBuffer result = new StringBuffer(); + @NotNull + private static String removeWhiteSpacesFrom(@NotNull final String token) { + final StringBuilder result = new StringBuilder(); for (char c : token.toCharArray()) { if (c != ' ') result.append(c); } return result.toString(); } - public static String toLines(ArrayList l) { - if (l == null || l.size() == 0) return null; - StringBuffer sb = new StringBuffer(); - for (Object aL : l) { - String s = (String)aL; - if (sb.length() > 0) { - sb.append(lineSeparator); - } - sb.append(s); - } - return sb.toString(); - } - - public static String toCommaSeparated(ArrayList<String> l) { - if (l == null || l.size() == 0) return null; - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < l.size(); i++) { - String s = l.get(i); - if (i != 0) { - sb.append(", "); - } - sb.append(s); - } - return sb.toString(); - } - /** - * Processes all lines (char sequences separated by line feed symbol) from the given string slitting them if necessary - * ensuring that every returned line contains less symbols than the given width. - * + * Processes all lines (char sequences separated by line feed symbol) from the given string slitting them if necessary + * ensuring that every returned line contains less symbols than the given width. + * * @param s the specified string * @param width width of the wrapped text * @return array of strings (lines) */ @Nullable - private List<String> toArrayWrapping(String s, int width) { + private List<String> toArrayWrapping(@Nullable String s, int width) { List<String> list = new ArrayList<String>(); List<Pair<String, Boolean>> pairs = splitToParagraphs(s); if (pairs == null) { @@ -305,7 +264,7 @@ public class JDParser { /** * Processes given string and produces on its basis set of pairs like <code>'(string; flag)'</code> where <code>'string'</code> * is interested line and <code>'flag'</code> indicates if it is wrapped to {@code <pre>} tag. - * + * * @param s string to process * @return processing result */ @@ -313,15 +272,16 @@ public class JDParser { private List<Pair<String, Boolean>> splitToParagraphs(@Nullable String s) { if (s == null) return null; s = s.trim(); - if (s == null /* just to make inspection happy*/ || s.isEmpty()) return null; + if (s.isEmpty()) return null; List<Pair<String, Boolean>> result = new ArrayList<Pair<String, Boolean>>(); - + StringBuilder sb = new StringBuilder(); - ArrayList<Boolean> markers = new ArrayList<Boolean>(); - ArrayList<String> list = toArray(s, "\n", markers); + List<Boolean> markers = new ArrayList<Boolean>(); + List<String> list = toArray(s, "\n", markers); Boolean[] marks = markers.toArray(new Boolean[markers.size()]); markers.clear(); + assert list != null; for (int i = 0; i < list.size(); i++) { String s1 = list.get(i); if (marks[i].booleanValue()) { @@ -353,27 +313,17 @@ public class JDParser { } return result; } - - static abstract class TagParser { + + abstract static class TagParser { abstract boolean parse(String tag, String line, JDComment c); } - private static final @NonNls String SEE_TAG = "see"; - private static final @NonNls String SINCE_TAG = "since"; - private static final @NonNls String VERSION_TAG = "version"; - private static final @NonNls String DEPRECATED_TAG = "deprecated"; - private static final @NonNls String RETURN_TAG = "return"; - private static final @NonNls String PARAM_TAG = "param"; - private static final @NonNls String THROWS_TAG = "throws"; - private static final @NonNls String EXCEPTION_TAG = "exception"; - private static final @NonNls String AUTHOR_TAG = "author"; - private static final TagParser[] tagParsers = { new TagParser() { @Override boolean parse(String tag, String line, JDComment c) { - boolean isMyTag = SEE_TAG.equals(tag); + boolean isMyTag = JDTag.SEE.tagEqual(tag); if (isMyTag) { c.addSeeAlso(line); } @@ -383,7 +333,7 @@ public class JDParser { new TagParser() { @Override boolean parse(String tag, String line, JDComment c) { - boolean isMyTag = SINCE_TAG.equals(tag); + boolean isMyTag = JDTag.SINCE.tagEqual(tag); if (isMyTag) { c.setSince(line); } @@ -393,7 +343,7 @@ public class JDParser { new TagParser() { @Override boolean parse(String tag, String line, JDComment c) { - boolean isMyTag = c instanceof JDClassComment && VERSION_TAG.equals(tag); + boolean isMyTag = c instanceof JDClassComment && JDTag.VERSION.tagEqual(tag); if (isMyTag) { ((JDClassComment)c).setVersion(line); } @@ -403,7 +353,7 @@ public class JDParser { new TagParser() { @Override boolean parse(String tag, String line, JDComment c) { - boolean isMyTag = DEPRECATED_TAG.equals(tag); + boolean isMyTag = JDTag.DEPRECATED.tagEqual(tag); if (isMyTag) { c.setDeprecated(line); } @@ -413,7 +363,7 @@ public class JDParser { new TagParser() { @Override boolean parse(String tag, String line, JDComment c) { - boolean isMyTag = c instanceof JDMethodComment && RETURN_TAG.equals(tag); + boolean isMyTag = c instanceof JDMethodComment && JDTag.RETURN.tagEqual(tag); if (isMyTag) { JDMethodComment mc = (JDMethodComment)c; mc.setReturnTag(line); @@ -424,7 +374,7 @@ public class JDParser { new TagParser() { @Override boolean parse(String tag, String line, JDComment c) { - boolean isMyTag = c instanceof JDParamListOwnerComment && PARAM_TAG.equals(tag); + boolean isMyTag = c instanceof JDParamListOwnerComment && JDTag.PARAM.tagEqual(tag); if (isMyTag) { JDParamListOwnerComment mc = (JDParamListOwnerComment)c; int idx; @@ -447,7 +397,7 @@ public class JDParser { new TagParser() { @Override boolean parse(String tag, String line, JDComment c) { - boolean isMyTag = c instanceof JDMethodComment && (THROWS_TAG.equals(tag) || EXCEPTION_TAG.equals(tag)); + boolean isMyTag = c instanceof JDMethodComment && (JDTag.THROWS.tagEqual(tag) || JDTag.EXCEPTION.tagEqual(tag)); if (isMyTag) { JDMethodComment mc = (JDMethodComment)c; int idx; @@ -470,7 +420,7 @@ public class JDParser { new TagParser() { @Override boolean parse(String tag, String line, JDComment c) { - boolean isMyTag = c instanceof JDClassComment && AUTHOR_TAG.equals(tag); + boolean isMyTag = c instanceof JDClassComment && JDTag.AUTHOR.tagEqual(tag); if (isMyTag) { JDClassComment cl = (JDClassComment)c; cl.addAuthor(line.trim()); @@ -478,33 +428,72 @@ public class JDParser { return isMyTag; } }, -/* new TagParser() { - boolean parse( String tag, String line, JDComment c ) { - XDTag xdtag = XDTag.parse(tag, line); - if( xdtag != null ) { - c.addXDocTag(xdtag); - } - return xdtag != null; - } - },*/ }; - protected StringBuffer splitIntoCLines(String s, String prefix) { - return splitIntoCLines(s, prefix, true); + /** + * @see JDParser#formatJDTagDescription(String, CharSequence, boolean, int) + */ + @NotNull + protected StringBuilder formatJDTagDescription(@Nullable String s, @NotNull CharSequence prefix) { + return formatJDTagDescription(s, prefix, false, 0); } - protected StringBuffer splitIntoCLines(String s, String prefix, boolean add_prefix_to_first_line) { - return splitIntoCLines(s, new StringBuffer(prefix), add_prefix_to_first_line); + private static boolean lineHasUnclosedPreTag(@NotNull String line) { + return StringUtil.getOccurrenceCount(line, PRE_TAG_START) > StringUtil.getOccurrenceCount(line, PRE_TAG_END); } - protected StringBuffer splitIntoCLines(String s, StringBuffer prefix, boolean add_prefix_to_first_line) { - @NonNls StringBuffer sb = new StringBuffer(); - if (add_prefix_to_first_line) { - sb.append(prefix); + /** + * Returns formatted JavaDoc tag description, according to selected configuration + * @param str JavaDoc tag description + * @param prefix JavaDoc prefix(like " * ") which will be appended to every new line + * @param firstLineShorter flag if first line should be shorter (has another prefix length than other lines) + * @param firstLinePrefixLength first line prefix length + * @return formatted JavaDoc tag description + */ + @NotNull + protected StringBuilder formatJDTagDescription(@Nullable String str, + @NotNull CharSequence prefix, + boolean firstLineShorter, + int firstLinePrefixLength) + { + StringBuilder sb = new StringBuilder(); + List<String> list; + + //If wrap comments selected, comments should be wrapped by the right margin + if (mySettings.WRAP_COMMENTS) { + list = toArrayWrapping(str, mySettings.RIGHT_MARGIN - prefix.length()); + + if (firstLineShorter + && list != null && !list.isEmpty() + && list.get(0).length() > mySettings.RIGHT_MARGIN - firstLinePrefixLength) + { + list = new ArrayList<String>(); + //want the first line to be shorter, according to it's prefix + String firstLine = toArrayWrapping(str, mySettings.RIGHT_MARGIN - firstLinePrefixLength).get(0); + //so now first line is exactly same width we need + list.add(firstLine); + str = str.substring(firstLine.length()); + //actually there is one more problem - when first line has unclosed <pre> tag, substring should be processed if it's inside <pre> + boolean unclosedPreTag = lineHasUnclosedPreTag(firstLine); + if (unclosedPreTag) { + str = PRE_TAG_START + str.replaceAll("^\\s+", ""); + } + + //getting all another lines according to their prefix + List<String> subList = toArrayWrapping(str, mySettings.RIGHT_MARGIN - prefix.length()); + + //removing pre tag + if (unclosedPreTag) { + String firstLineTagRemoved = subList.get(0).substring(PRE_TAG_START.length()); + subList.set(0, firstLineTagRemoved); + } + list.addAll(subList); + } + } + else { + list = toArray(str, "\n", new ArrayList<Boolean>()); } - List<String> list = mySettings.WRAP_COMMENTS - ? toArrayWrapping(s, mySettings.RIGHT_MARGIN - prefix.length()) - : toArray(s, "\n", new ArrayList<Boolean>()); + if (list == null) { sb.append('\n'); } @@ -515,11 +504,11 @@ public class JDParser { if (line.length() == 0 && !mySettings.JD_KEEP_EMPTY_LINES) continue; if (i != 0) sb.append(prefix); if (line.length() == 0 && mySettings.JD_P_AT_EMPTY_LINES && !insidePreTag) { - sb.append("<p/>"); + sb.append(SELF_CLOSED_P_TAG); } else { sb.append(line); - + // We want to track if we're inside <pre>...</pre> in order to not generate <p/> there. if (PRE_TAG_START.equals(line)) { insidePreTag = true; diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDTag.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDTag.java new file mode 100644 index 000000000000..1b3514533179 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/JDTag.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.impl.source.codeStyle.javadoc; + +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: Lepenkin Y. + * Date: 7/1/13 + * Time: 4:15 PM + */ +public enum JDTag { + SEE("see"), + AUTHOR("author"), + VERSION("version"), + THROWS("throws"), + EXCEPTION("exception"), + RETURN("return"), + PARAM("param"), + SINCE("since"), + DEPRECATED("deprecated"); + + + @NotNull private final String myTag; + + JDTag(@NotNull String tag) { + this.myTag = tag; + } + + @NotNull + public String getDescriptionPrefix(@NotNull String prefix) { + return prefix + StringUtil.repeatSymbol(' ', getWithEndWhitespace().length()); + } + + @NotNull + public String getWithEndWhitespace() { + return "@" + myTag + " "; + } + + public boolean tagEqual(@Nullable String tag) { + return myTag.equals(tag); + } +} diff --git a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/NameDesc.java b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/NameDesc.java index d7de91b90ecc..6e8ee10d4ad5 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/NameDesc.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/codeStyle/javadoc/NameDesc.java @@ -15,29 +15,25 @@ */ package com.intellij.psi.impl.source.codeStyle.javadoc; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + /** * * @author Dmitry Skavish */ public class NameDesc { + @NotNull public final String name; + @Nullable public final String desc; - public String name; - public String desc; - private String type; - - public NameDesc(String name, String desc) { - this.name = name; - this.desc = desc; - } - - public NameDesc(String name, String desc, String type) { + public NameDesc(@NotNull String name, @Nullable String desc) { this.name = name; this.desc = desc; - this.type = type; } + @NotNull + @Override public String toString() { - if (type == null) return name; - return name + ": " + type; + return name; } } diff --git a/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java b/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java index 5f6072a2bb91..cd8613dd05e5 100644 --- a/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java +++ b/java/java-impl/src/com/intellij/refactoring/OptimizeImportsRefactoringHelper.java @@ -39,12 +39,9 @@ public class OptimizeImportsRefactoringHelper implements RefactoringHelper<Set<P Set<PsiJavaFile> javaFiles = new HashSet<PsiJavaFile>(); for (UsageInfo usage : usages) { if (usage.isNonCodeUsage) continue; - final PsiElement element = usage.getElement(); - if (element != null) { - final PsiFile file = element.getContainingFile(); - if (file instanceof PsiJavaFile) { - javaFiles.add((PsiJavaFile)file); - } + final PsiFile file = usage.getFile(); + if (file instanceof PsiJavaFile) { + javaFiles.add((PsiJavaFile)file); } } return javaFiles; diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDetector.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDetector.java index 6faaf8e509e8..eba4ae956627 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDetector.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDetector.java @@ -111,8 +111,9 @@ public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetec public String extractSignature(PsiElement element, @NotNull ChangeInfo initialChangeInfo) { final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class, false); if (method != null && isInsideMethodSignature(element, method) && method == initialChangeInfo.getMethod()) { - final TextRange signatureRange = getSignatureRange(method); - return element.getContainingFile().getText().substring(signatureRange.getStartOffset(), signatureRange.getEndOffset()); + final PsiCodeBlock body = method.getBody(); + final TextRange signatureRange = new TextRange(0, body != null ? body.getStartOffsetInParent() : method.getTextLength()); + return signatureRange.substring(method.getText()); } else if (element instanceof PsiIdentifier && element.getParent() instanceof PsiNamedElement) { return element.getText(); } diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java index 647cd09f0806..d46fa203f7e0 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java @@ -30,7 +30,6 @@ import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.ValidationInfo; -import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; @@ -50,13 +49,13 @@ import com.intellij.refactoring.util.CanonicalTypes; import com.intellij.refactoring.util.RefactoringMessageUtil; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.ui.*; -import com.intellij.ui.components.JBLabel; import com.intellij.ui.table.JBTable; import com.intellij.ui.table.TableView; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.*; import com.intellij.util.ui.DialogUtil; import com.intellij.util.ui.UIUtil; +import com.intellij.util.ui.table.JBListTable; import com.intellij.util.ui.table.JBTableRow; import com.intellij.util.ui.table.JBTableRowEditor; import org.jetbrains.annotations.NotNull; @@ -228,7 +227,6 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase<Paramet @Override protected JComponent getRowPresentation(ParameterTableModelItemBase<ParameterInfoImpl> item, boolean selected, final boolean focused) { - final JPanel panel = new JPanel(new BorderLayout()); final String typeText = item.typeCodeFragment.getText(); final String separator = StringUtil.repeatSymbol(' ', getTypesMaxLength() - typeText.length() + 1); String text = typeText + separator + item.parameter.getName(); @@ -246,28 +244,7 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase<Paramet if (!StringUtil.isEmpty(tail)) { text += " //" + tail; } - final EditorTextField field = new EditorTextField(" " + text, getProject(), getFileType()) { - @Override - protected boolean shouldHaveBorder() { - return false; - } - }; - - Font font = EditorColorsManager.getInstance().getGlobalScheme().getFont(EditorFontType.PLAIN); - font = new Font(font.getFontName(), font.getStyle(), 12); - field.setFont(font); - - if (selected && focused) { - panel.setBackground(UIUtil.getTableSelectionBackground()); - field.setAsRendererWithSelection(UIUtil.getTableSelectionBackground(), UIUtil.getTableSelectionForeground()); - } else { - panel.setBackground(UIUtil.getTableBackground()); - if (selected && !focused) { - panel.setBorder(new DottedBorder(UIUtil.getTableForeground())); - } - } - panel.add(field, BorderLayout.WEST); - return panel; + return JBListTable.createEditorTextFieldPresentation(getProject(), getFileType(), " " + text, selected, focused); } private int getTypesMaxLength() { @@ -311,43 +288,20 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase<Paramet private EditorTextField myDefaultValueEditor; private JCheckBox myAnyVar; - class MyDocumentListener extends DocumentAdapter { - private int myColumn; - - private MyDocumentListener(int column) { - myColumn = column; - } - - @Override - public void documentChanged(DocumentEvent e) { - fireDocumentChanged(e, myColumn); - } - } - @Override public void prepareEditor(JTable table, int row) { setLayout(new BorderLayout()); - final JPanel typePanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 4, 2, true, false)); final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(item.typeCodeFragment); myTypeEditor = new EditorTextField(document, getProject(), getFileType()); myTypeEditor.addDocumentListener(mySignatureUpdater); - final JBLabel typeLabel = new JBLabel("Type:", UIUtil.ComponentStyle.SMALL); - IJSwingUtilities.adjustComponentsOnMac(typeLabel, myTypeEditor); - typePanel.add(typeLabel); - typePanel.add(myTypeEditor); myTypeEditor.setPreferredWidth(t.getWidth() / 2); - myTypeEditor.addDocumentListener(new MyDocumentListener(0)); - add(typePanel, BorderLayout.WEST); + myTypeEditor.addDocumentListener(new RowEditorChangeListener(0)); + add(createLabeledPanel("Type:", myTypeEditor), BorderLayout.WEST); - final JPanel namePanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 4, 2, true, false)); myNameEditor = new EditorTextField(item.parameter.getName(), getProject(), getFileType()); myNameEditor.addDocumentListener(mySignatureUpdater); - myNameEditor.addDocumentListener(new MyDocumentListener(1)); - final JBLabel nameLabel = new JBLabel("Name:", UIUtil.ComponentStyle.SMALL); - IJSwingUtilities.adjustComponentsOnMac(nameLabel, myNameEditor); - namePanel.add(nameLabel); - namePanel.add(myNameEditor); - add(namePanel, BorderLayout.CENTER); + myNameEditor.addDocumentListener(new RowEditorChangeListener(1)); + add(createLabeledPanel("Name:", myNameEditor), BorderLayout.CENTER); new TextFieldCompletionProvider() { @Override @@ -377,17 +331,12 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase<Paramet if (!item.isEllipsisType() && item.parameter.getOldIndex() == -1) { final JPanel additionalPanel = new JPanel(new BorderLayout()); - final JPanel defaultValuePanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 4, 2, true, false)); final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(item.defaultValueCodeFragment); myDefaultValueEditor = new EditorTextField(doc, getProject(), getFileType()); ((PsiExpressionCodeFragment)item.defaultValueCodeFragment).setExpectedType(getRowType(item)); - final JBLabel defaultValueLabel = new JBLabel("Default value:", UIUtil.ComponentStyle.SMALL); - IJSwingUtilities.adjustComponentsOnMac(defaultValueLabel, myDefaultValueEditor); - defaultValuePanel.add(defaultValueLabel); - defaultValuePanel.add(myDefaultValueEditor); myDefaultValueEditor.setPreferredWidth(t.getWidth() / 2); - myDefaultValueEditor.addDocumentListener(new MyDocumentListener(2)); - additionalPanel.add(defaultValuePanel, BorderLayout.WEST); + myDefaultValueEditor.addDocumentListener(new RowEditorChangeListener(2)); + additionalPanel.add(createLabeledPanel("Default value:", myDefaultValueEditor), BorderLayout.WEST); if (!isGenerateDelegate()) { myAnyVar = new JCheckBox("&Use Any Var"); diff --git a/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java index 34c4308de8c7..c3a8d7279c2c 100644 --- a/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/convertToInstanceMethod/ConvertToInstanceMethodProcessor.java @@ -187,7 +187,7 @@ public class ConvertToInstanceMethodProcessor extends BaseRefactoringProcessor { myTypeParameterReplacements = buildTypeParameterReplacements(); List<PsiClass> inheritors = new ArrayList<PsiClass>(); - RefactoringUtil.sortDepthFirstRightLeftOrder(usages); + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); // Process usages for (final UsageInfo usage : usages) { diff --git a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java index a081ff233ca6..b6e3be4b86bd 100644 --- a/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/copy/CopyClassesHandler.java @@ -37,6 +37,7 @@ import com.intellij.refactoring.MoveDestination; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesProcessor; import com.intellij.util.ArrayUtil; +import com.intellij.util.ArrayUtilRt; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -183,14 +184,16 @@ public class CopyClassesHandler extends CopyHandlerDelegateBase { String className = null; boolean openInEditor = true; if (copyOneClass(classes)) { - final String commonPath = ArrayUtil.find(elements, classes.values().iterator().next()) == -1 ? normalizeRelativeMap(relativePathsMap) : null; + final String commonPath = + ArrayUtilRt.find(elements, classes.values().iterator().next()) == -1 ? normalizeRelativeMap(relativePathsMap) : null; CopyClassDialog dialog = new CopyClassDialog(classes.values().iterator().next()[0], defaultTargetDirectory, project, false){ @Override protected String getQualifiedName() { - if (commonPath != null && !commonPath.isEmpty()) { - return StringUtil.getQualifiedName(super.getQualifiedName(), commonPath.replaceAll("/", ".")); + final String qualifiedName = super.getQualifiedName(); + if (commonPath != null && !commonPath.isEmpty() && !qualifiedName.endsWith(commonPath)) { + return StringUtil.getQualifiedName(qualifiedName, commonPath.replaceAll("/", ".")); } - return super.getQualifiedName(); + return qualifiedName; } }; dialog.setTitle(RefactoringBundle.message("copy.handler.copy.class")); diff --git a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java index 180e28dd0e6d..fc87374b6ad3 100644 --- a/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/encapsulateFields/EncapsulateFieldsProcessor.java @@ -299,7 +299,7 @@ public class EncapsulateFieldsProcessor extends BaseRefactoringProcessor { for (List<MyUsageInfo> usageInfos : usagesInFiles.values()) { //this is to avoid elements to become invalid as a result of processUsage final MyUsageInfo[] infos = usageInfos.toArray(new MyUsageInfo[usageInfos.size()]); - RefactoringUtil.sortDepthFirstRightLeftOrder(infos); + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(infos); for (MyUsageInfo info : infos) { processUsage(info); diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java index 317117537ac7..41aa79b7057f 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java @@ -42,10 +42,8 @@ import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.InlineUtil; import com.intellij.refactoring.util.RefactoringMessageDialog; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.Processor; -import com.intellij.util.Query; +import com.intellij.util.*; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -195,7 +193,7 @@ public class InlineLocalHandler extends JavaInlineActionHandler { } } - final PsiElement writeAccess = checkRefsInAugmentedAssignmentOrUnaryModified(refsToInline); + final PsiElement writeAccess = checkRefsInAugmentedAssignmentOrUnaryModified(refsToInline, defToInline); if (writeAccess != null) { HighlightManager.getInstance(project).addOccurrenceHighlights(editor, new PsiElement[]{writeAccess}, writeAttributes, true, null); String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("variable.is.accessed.for.writing", localName)); @@ -234,10 +232,11 @@ public class InlineLocalHandler extends JavaInlineActionHandler { final Runnable runnable = new Runnable() { public void run() { try{ - PsiExpression[] exprs = new PsiExpression[refsToInline.length]; + SmartPsiElementPointer<PsiExpression>[] exprs = new SmartPsiElementPointer[refsToInline.length]; + final SmartPointerManager pointerManager = SmartPointerManager.getInstance(project); for(int idx = 0; idx < refsToInline.length; idx++){ PsiJavaCodeReferenceElement refElement = (PsiJavaCodeReferenceElement)refsToInline[idx]; - exprs[idx] = InlineUtil.inlineVariable(local, defToInline, refElement); + exprs[idx] = pointerManager.createSmartPsiElementPointer(InlineUtil.inlineVariable(local, defToInline, refElement)); } if (!isInliningVariableInitializer(defToInline)) { @@ -251,12 +250,17 @@ public class InlineLocalHandler extends JavaInlineActionHandler { } if (editor != null && !ApplicationManager.getApplication().isUnitTestMode()) { - highlightManager.addOccurrenceHighlights(editor, exprs, attributes, true, null); + highlightManager.addOccurrenceHighlights(editor, ContainerUtil.convert(exprs, new PsiExpression[refsToInline.length], new Function<SmartPsiElementPointer<PsiExpression>, PsiExpression>() { + @Override + public PsiExpression fun(SmartPsiElementPointer<PsiExpression> pointer) { + return pointer.getElement(); + } + }), attributes, true, null); WindowManager.getInstance().getStatusBar(project).setInfo(RefactoringBundle.message("press.escape.to.remove.the.highlighting")); } - for (final PsiExpression expr : exprs) { - InlineUtil.tryToInlineArrayCreationForVarargs(expr); + for (final SmartPsiElementPointer<PsiExpression> expr : exprs) { + InlineUtil.tryToInlineArrayCreationForVarargs(expr.getElement()); } } catch (IncorrectOperationException e){ @@ -273,12 +277,13 @@ public class InlineLocalHandler extends JavaInlineActionHandler { } @Nullable - public static PsiElement checkRefsInAugmentedAssignmentOrUnaryModified(final PsiElement[] refsToInline) { + public static PsiElement checkRefsInAugmentedAssignmentOrUnaryModified(final PsiElement[] refsToInline, PsiElement defToInline) { for (PsiElement element : refsToInline) { PsiElement parent = element.getParent(); if (parent instanceof PsiArrayAccessExpression) { if (((PsiArrayAccessExpression)parent).getIndexExpression() == element) continue; + if (defToInline instanceof PsiExpression && !(defToInline instanceof PsiNewExpression)) continue; element = parent; parent = parent.getParent(); } diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java index 1659cac04161..a82994d44cf4 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java @@ -404,7 +404,7 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { } } else { - RefactoringUtil.sortDepthFirstRightLeftOrder(usages); + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); if (myMethod.isConstructor()) { for (UsageInfo usage : usages) { PsiElement element = usage.getElement(); diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineParameterHandler.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineParameterHandler.java index e22f0b86e2cd..58d4d1eb282d 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineParameterHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineParameterHandler.java @@ -125,7 +125,7 @@ public class InlineParameterHandler extends JavaInlineActionHandler { if (rExpr != null) { final PsiElement[] refs = DefUseUtil.getRefs(codeBlock, psiParameter, refExpr); - if (InlineLocalHandler.checkRefsInAugmentedAssignmentOrUnaryModified(refs) == null) { + if (InlineLocalHandler.checkRefsInAugmentedAssignmentOrUnaryModified(refs, def) == null) { new WriteCommandAction(project) { @Override protected void run(Result result) throws Throwable { diff --git a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java index 818b8c387416..ab340a596947 100644 --- a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java @@ -32,10 +32,7 @@ import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.inlineSuperClass.usageInfo.*; import com.intellij.refactoring.memberPushDown.PushDownConflicts; import com.intellij.refactoring.memberPushDown.PushDownProcessor; -import com.intellij.refactoring.util.DocCommentPolicy; -import com.intellij.refactoring.util.FixableUsageInfo; -import com.intellij.refactoring.util.FixableUsagesRefactoringProcessor; -import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.refactoring.util.*; import com.intellij.refactoring.util.classMembers.MemberInfo; import com.intellij.refactoring.util.classMembers.MemberInfoStorage; import com.intellij.usageView.UsageInfo; @@ -290,7 +287,7 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori } else { super.performRefactoring(pushDownUsages); } - RefactoringUtil.sortDepthFirstRightLeftOrder(usages); + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); for (UsageInfo usageInfo : usages) { if (!(usageInfo instanceof ReplaceExtendsListUsageInfo || usageInfo instanceof RemoveImportUsageInfo)) { try { diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java index 8f0f5fb556e9..ba3ba8a2c7bd 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterProcessor.java @@ -382,7 +382,7 @@ public class IntroduceParameterProcessor extends BaseRefactoringProcessor implem } ChangeContextUtil.clearContextInfo(myParameterInitializer); - // Replacing expression occurences + // Replacing expression occurrences for (UsageInfo usage : usages) { if (usage instanceof ChangedMethodCallInfo) { PsiElement element = usage.getElement(); 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 740c2cc15b3c..9d64136b35a3 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -134,12 +134,18 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase { } else { int selection; - PsiExpression expression = expressions.get(0); - if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).resolve() instanceof PsiLocalVariable) { - selection = 1; - } - else { - selection = -1; + if (statementsInRange.length == 1 && + statementsInRange[0] instanceof PsiExpressionStatement && + PsiUtilCore.hasErrorElementChild(statementsInRange[0])) { + selection = expressions.indexOf(((PsiExpressionStatement)statementsInRange[0]).getExpression()); + } else { + PsiExpression expression = expressions.get(0); + if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).resolve() instanceof PsiLocalVariable) { + selection = 1; + } + else { + selection = -1; + } } IntroduceTargetChooser.showChooser(editor, expressions, new Pass<PsiExpression>(){ diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java index eb5938ce3c66..c3562db8e73a 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/JavaVariableInplaceIntroducer.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.template.TemplateBuilderImpl; import com.intellij.openapi.actionSystem.Shortcut; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.command.impl.StartMarkAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; @@ -29,9 +30,11 @@ import com.intellij.openapi.keymap.KeymapManager; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.vfs.ReadonlyStatusHandler; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.psi.scope.processor.VariablesProcessor; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.TypeConversionUtil; @@ -105,6 +108,11 @@ public class JavaVariableInplaceIntroducer extends InplaceVariableIntroducer<Psi } @Override + protected StartMarkAction startRename() throws StartMarkAction.AlreadyStartedException { + return StartMarkAction.start(myEditor, myProject, getCommandName()); + } + + @Override protected void beforeTemplateStart() { super.beforeTemplateStart(); final ResolveSnapshotProvider resolveSnapshotProvider = VariableInplaceRenamer.INSTANCE.forLanguage(myScope.getLanguage()); @@ -169,6 +177,7 @@ public class JavaVariableInplaceIntroducer extends InplaceVariableIntroducer<Psi myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); } if (myExpressionText != null) { + if (!ReadonlyStatusHandler.ensureDocumentWritable(myProject, InjectedLanguageUtil.getTopLevelEditor(myEditor).getDocument())) return; ApplicationManager.getApplication().runWriteAction(new Runnable() { public void run() { final PsiDeclarationStatement element = myPointer.getElement(); diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveJavaFileHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveJavaFileHandler.java index 530660b5f016..de994d90819c 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveJavaFileHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveClassesOrPackages/MoveJavaFileHandler.java @@ -94,7 +94,8 @@ public class MoveJavaFileHandler extends MoveFileHandler { final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(containingDirectory); if (aPackage != null) { final String qualifiedName = aPackage.getQualifiedName(); - final PsiPackageStatement packageStatement = qualifiedName.length() > 0 + final PsiNameHelper helper = JavaPsiFacade.getInstance(file.getProject()).getNameHelper(); + final PsiPackageStatement packageStatement = !StringUtil.isEmptyOrSpaces(qualifiedName) && helper.isQualifiedName(qualifiedName) ? JavaPsiFacade.getElementFactory(file.getProject()).createPackageStatement(qualifiedName) : null; if (file instanceof PsiJavaFile) { diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerImpl.java b/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerImpl.java index fe37b7d3cf82..c33cc48b6864 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerImpl.java @@ -34,14 +34,16 @@ public class MoveInnerImpl { public static final String REFACTORING_NAME = RefactoringBundle.message("move.inner.to.upper.level.title"); - public static void doMove(final Project project, PsiElement[] elements, final MoveCallback moveCallback) { + public static void doMove(final Project project, PsiElement[] elements, final MoveCallback moveCallback, @Nullable PsiElement targetContainer) { if (elements.length != 1) return; final PsiClass aClass = (PsiClass) elements[0]; boolean condition = aClass.getContainingClass() != null; LOG.assertTrue(condition); if (!CommonRefactoringUtil.checkReadOnlyStatus(project, aClass)) return; - final PsiElement targetContainer = getTargetContainer(aClass, true); + if (targetContainer == null) { + targetContainer = getTargetContainer(aClass, true); + } if (targetContainer == null) return; final MoveInnerDialog dialog = new MoveInnerDialog( diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerProcessor.java index 35ca3e256ee2..ddff1f089669 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerProcessor.java @@ -164,7 +164,7 @@ public class MoveInnerProcessor extends BaseRefactoringProcessor { if (myParameterNameOuterClass != null) { // pass outer as a parameter field = factory.createField(myFieldNameOuterClass, factory.createType(myOuterClass)); - field = (PsiField)myInnerClass.add(field); + field = addOuterField(field); myInnerClass = field.getContainingClass(); addFieldInitializationToConstructors(myInnerClass, field, myParameterNameOuterClass); } @@ -296,6 +296,19 @@ public class MoveInnerProcessor extends BaseRefactoringProcessor { } } + private PsiField addOuterField(PsiField field) { + final PsiMember[] members = PsiTreeUtil.getChildrenOfType(myInnerClass, PsiMember.class); + if (members != null) { + for (PsiMember member : members) { + if (!member.hasModifierProperty(PsiModifier.STATIC)) { + return (PsiField)myInnerClass.addBefore(field, member); + } + } + } + + return (PsiField)myInnerClass.add(field); + } + protected void performPsiSpoilingRefactoring() { if (myNonCodeUsages != null) { RenameUtil.renameNonCodeUsages(myProject, myNonCodeUsages); diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerToUpperHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerToUpperHandler.java index f807e89d4c64..706fc7954b27 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerToUpperHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerToUpperHandler.java @@ -17,6 +17,7 @@ package com.intellij.refactoring.move.moveInner; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiClass; @@ -35,9 +36,7 @@ public class MoveInnerToUpperHandler extends MoveHandlerDelegate { public boolean canMove(final PsiElement[] elements, @Nullable final PsiElement targetContainer) { if (elements.length != 1) return false; PsiElement element = elements [0]; - return isNonStaticInnerClass(element) && - (targetContainer == null || targetContainer.equals(MoveInnerImpl.getTargetContainer((PsiClass)elements[0], false))); - + return isNonStaticInnerClass(element); } private static boolean isNonStaticInnerClass(final PsiElement element) { @@ -46,7 +45,7 @@ public class MoveInnerToUpperHandler extends MoveHandlerDelegate { } public void doMove(final Project project, final PsiElement[] elements, final PsiElement targetContainer, final MoveCallback callback) { - MoveInnerImpl.doMove(project, elements, callback); + MoveInnerImpl.doMove(project, elements, callback, targetContainer); } public boolean tryToMove(final PsiElement element, final Project project, final DataContext dataContext, final PsiReference reference, @@ -60,7 +59,7 @@ public class MoveInnerToUpperHandler extends MoveHandlerDelegate { RefactoringBundle.message("move.title"), null); return true; } - MoveInnerImpl.doMove(project, new PsiElement[]{aClass}, null); + MoveInnerImpl.doMove(project, new PsiElement[]{aClass}, null, LangDataKeys.TARGET_PSI_ELEMENT.getData(dataContext)); return true; } return false; diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerToUpperOrMembersHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerToUpperOrMembersHandler.java index 823ee22a1687..2ad1d53f55b6 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerToUpperOrMembersHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveInner/MoveInnerToUpperOrMembersHandler.java @@ -17,6 +17,7 @@ package com.intellij.refactoring.move.moveInner; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; @@ -39,8 +40,7 @@ public class MoveInnerToUpperOrMembersHandler extends MoveHandlerDelegate { public boolean canMove(final PsiElement[] elements, @Nullable final PsiElement targetContainer) { if (elements.length != 1) return false; PsiElement element = elements [0]; - return isStaticInnerClass(element) && - (targetContainer == null || targetContainer.equals(MoveInnerImpl.getTargetContainer((PsiClass)elements[0], false))); + return isStaticInnerClass(element); } private static boolean isStaticInnerClass(final PsiElement element) { @@ -64,13 +64,14 @@ public class MoveInnerToUpperOrMembersHandler extends MoveHandlerDelegate { final Editor editor) { if (isStaticInnerClass(element) && !JavaMoveClassesOrPackagesHandler.isReferenceInAnonymousClass(reference)) { FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.move.moveInner"); + final PsiElement targetContainer = LangDataKeys.TARGET_PSI_ELEMENT.getData(dataContext); PsiClass aClass = (PsiClass) element; SelectInnerOrMembersRefactoringDialog dialog = new SelectInnerOrMembersRefactoringDialog(aClass, project); dialog.show(); if (dialog.isOK()) { final MoveHandlerDelegate moveHandlerDelegate = dialog.getRefactoringHandler(); if (moveHandlerDelegate != null) { - moveHandlerDelegate.doMove(project, new PsiElement[] { aClass }, null, null); + moveHandlerDelegate.doMove(project, new PsiElement[] { aClass }, targetContainer, null); } } return true; diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java index ea39904f5a1d..4dda4d75a304 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveJavaMemberHandler.java @@ -193,7 +193,7 @@ public class MoveJavaMemberHandler implements MoveMemberHandler { } } else { // no qualifier - if (usage.qualifierClass != null && PsiTreeUtil.getParentOfType(refExpr, PsiSwitchLabelStatement.class) == null) { + if (usage.qualifierClass != null && (!usage.qualifierClass.isEnum() || PsiTreeUtil.getParentOfType(refExpr, PsiSwitchLabelStatement.class) == null)) { changeQualifier(refExpr, usage.qualifierClass, usage.member); } } diff --git a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersProcessor.java b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersProcessor.java index 3f4f59a0412e..cc594a37c107 100644 --- a/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/move/moveMembers/MoveMembersProcessor.java @@ -116,7 +116,7 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor { PsiElement ref = psiReference.getElement(); final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(ref.getLanguage()); MoveMembersUsageInfo usage = null; - if (handler != null) { + if (handler != null && myTargetClass != null) { usage = handler.getUsage(member, psiReference, myMembersToMove, myTargetClass); } if (usage != null) { diff --git a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaVariableProcessor.java b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaVariableProcessor.java index 7e485dc00ca3..8c2f68887c71 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaVariableProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaVariableProcessor.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.rename; +import com.intellij.codeInsight.generation.GetterSetterPrototypeProvider; import com.intellij.lang.StdLanguages; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -43,10 +44,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; public class RenameJavaVariableProcessor extends RenameJavaMemberProcessor { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.rename.RenameJavaVariableProcessor"); @@ -150,7 +148,9 @@ public class RenameJavaVariableProcessor extends RenameJavaMemberProcessor { String newPropertyName = manager.variableNameToPropertyName(newName, VariableKind.FIELD); boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); - PsiMethod getter = PropertyUtil.findPropertyGetter(aClass, propertyName, isStatic, false); + + PsiMethod[] getters = GetterSetterPrototypeProvider.findGetters(aClass, propertyName, isStatic); + PsiMethod setter = PropertyUtil.findPropertySetter(aClass, propertyName, isStatic, false); boolean shouldRenameSetterParameter = false; @@ -161,22 +161,31 @@ public class RenameJavaVariableProcessor extends RenameJavaMemberProcessor { shouldRenameSetterParameter = parameterName.equals(setterParameter.getName()); } - String newGetterName = ""; - - if (getter != null) { - String getterId = getter.getName(); - newGetterName = PropertyUtil.suggestGetterName(newPropertyName, field.getType(), getterId); - if (newGetterName.equals(getterId)) { - getter = null; - newGetterName = null; - } else { - for (PsiMethod method : getter.findDeepestSuperMethods()) { - if (method instanceof PsiCompiledElement) { - getter = null; - break; + if (getters != null) { + List<PsiMethod> validGetters = new ArrayList<PsiMethod>(); + for (PsiMethod getter : getters) { + String newGetterName = GetterSetterPrototypeProvider.suggestNewGetterName(propertyName, newPropertyName, getter); + String getterId = null; + if (newGetterName == null) { + getterId = getter.getName(); + newGetterName = PropertyUtil.suggestGetterName(newPropertyName, field.getType(), getterId); + } + if (newGetterName.equals(getterId)) { + continue; + } + else { + boolean valid = true; + for (PsiMethod method : getter.findDeepestSuperMethods()) { + if (method instanceof PsiCompiledElement) { + valid = false; + break; + } } + if (!valid) continue; } + validGetters.add(getter); } + getters = validGetters.isEmpty() ? null : validGetters.toArray(new PsiMethod[validGetters.size()]); } String newSetterName = ""; @@ -201,14 +210,20 @@ public class RenameJavaVariableProcessor extends RenameJavaMemberProcessor { } } - if ((getter != null || setter != null) && askToRenameAccesors(getter, setter, newName, project)) { - getter = null; + if ((getters != null || setter != null) && askToRenameAccesors(getters != null ? getters[0] : null, setter, newName, project)) { + getters = null; setter = null; shouldRenameSetterParameter = false; } - if (getter != null) { - addOverriddenAndImplemented(getter, newGetterName, allRenames); + if (getters != null) { + for (PsiMethod getter : getters) { + String newGetterName = GetterSetterPrototypeProvider.suggestNewGetterName(propertyName, newPropertyName, getter); + if (newGetterName == null) { + newGetterName = PropertyUtil.suggestGetterName(newPropertyName, field.getType(), getter.getName()); + } + addOverriddenAndImplemented(getter, newGetterName, allRenames); + } } if (setter != null) { diff --git a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java index 7f8ae6d46b99..ac7a6d9ece69 100644 --- a/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java @@ -16,6 +16,7 @@ package com.intellij.refactoring.safeDelete; import com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableUtil; +import com.intellij.codeInsight.generation.GetterSetterPrototypeProvider; import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter; import com.intellij.ide.util.SuperMethodWarningUtil; import com.intellij.openapi.application.ApplicationManager; @@ -187,21 +188,30 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { PsiClass aClass = field.getContainingClass(); if (aClass != null) { boolean isStatic = field.hasModifierProperty(PsiModifier.STATIC); - PsiMethod getter = PropertyUtil.findPropertyGetter(aClass, propertyName, isStatic, false); - if (allElementsToDelete.contains(getter) || getter != null && !getter.isPhysical()) getter = null; + PsiMethod[] getters = GetterSetterPrototypeProvider.findGetters(aClass, propertyName, isStatic); + if (getters != null) { + final List<PsiMethod> validGetters = new ArrayList<PsiMethod>(1); + for (PsiMethod getter : getters) { + if (!allElementsToDelete.contains(getter) && (getter != null && getter.isPhysical())) { + validGetters.add(getter); + } + } + getters = validGetters.isEmpty() ? null : validGetters.toArray(new PsiMethod[validGetters.size()]); + } + PsiMethod setter = PropertyUtil.findPropertySetter(aClass, propertyName, isStatic, false); if (allElementsToDelete.contains(setter) || setter != null && !setter.isPhysical()) setter = null; - if (askUser && (getter != null || setter != null)) { + if (askUser && (getters != null || setter != null)) { final String message = - RefactoringMessageUtil.getGetterSetterMessage(field.getName(), RefactoringBundle.message("delete.title"), getter, setter); - if (Messages.showYesNoDialog(project, message, RefactoringBundle.message("safe.delete.title"), Messages.getQuestionIcon()) != 0) { - getter = null; + RefactoringMessageUtil.getGetterSetterMessage(field.getName(), RefactoringBundle.message("delete.title"), getters != null ? getters[0] : null, setter); + if (!ApplicationManager.getApplication().isUnitTestMode() && Messages.showYesNoDialog(project, message, RefactoringBundle.message("safe.delete.title"), Messages.getQuestionIcon()) != 0) { + getters = null; setter = null; } } List<PsiElement> elements = new ArrayList<PsiElement>(); if (setter != null) elements.add(setter); - if (getter != null) elements.add(getter); + if (getters != null) Collections.addAll(elements, getters); return elements; } } diff --git a/java/java-impl/src/com/intellij/refactoring/turnRefsToSuper/TurnRefsToSuperProcessorBase.java b/java/java-impl/src/com/intellij/refactoring/turnRefsToSuper/TurnRefsToSuperProcessorBase.java index 45b0b1ad5d1e..53c1b70bcf1a 100644 --- a/java/java-impl/src/com/intellij/refactoring/turnRefsToSuper/TurnRefsToSuperProcessorBase.java +++ b/java/java-impl/src/com/intellij/refactoring/turnRefsToSuper/TurnRefsToSuperProcessorBase.java @@ -451,7 +451,6 @@ public abstract class TurnRefsToSuperProcessorBase extends BaseRefactoringProces else if (declScope instanceof PsiForeachStatement) { final PsiExpression iteratedValue = ((PsiForeachStatement)declScope).getIteratedValue(); addLink(type, iteratedValue); - addLink(iteratedValue, type); } else if (declScope instanceof PsiMethod) { final PsiMethod method = (PsiMethod)declScope; diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java index b0c8feace4ec..10604955089a 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java @@ -96,13 +96,12 @@ public class TypeMigrationLabeler { final PsiElement element = p.getFirst().retrieve(); LOG.assertTrue(element != null); final PsiType type = ((PsiExpression)element).getType(); - report[j++] = "Cannot convert type of expression <b>" + - StringUtil.escapeXml(element.getText()) + - "</b>" + - " from <b>" + - StringUtil.escapeXml(type.getCanonicalText()) + - "</b> to <b>" + StringUtil.escapeXml(p.getSecond().getCanonicalText()) + - "</b><br>"; + report[j++] = "Cannot convert type of expression <b>" + StringUtil.escapeXml(element.getText()) + "</b>" + + (type != null + ? " from <b>" + StringUtil.escapeXml(type.getCanonicalText()) + "</b>" + + " to <b>" + StringUtil.escapeXml(p.getSecond().getCanonicalText()) + "</b>" + : "") + + "<br>"; } return report; @@ -539,7 +538,6 @@ public class TypeMigrationLabeler { } void markFailedConversion(final Pair<PsiType, PsiType> typePair, final PsiExpression expression) { - LOG.assertTrue(expression.getType() != null); LOG.assertTrue(typePair.getSecond() != null); myFailedConversions.add(new Pair<PsiAnchor, PsiType>(PsiAnchor.create(expression), typePair.getSecond())); } diff --git a/java/java-impl/src/com/intellij/refactoring/util/FixableUsagesRefactoringProcessor.java b/java/java-impl/src/com/intellij/refactoring/util/FixableUsagesRefactoringProcessor.java index 2c5fc9f2adab..4ad49a90bb81 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/FixableUsagesRefactoringProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/util/FixableUsagesRefactoringProcessor.java @@ -38,7 +38,7 @@ public abstract class FixableUsagesRefactoringProcessor extends BaseRefactoringP } protected void performRefactoring(UsageInfo[] usageInfos) { - RefactoringUtil.sortDepthFirstRightLeftOrder(usageInfos); + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usageInfos); for (UsageInfo usageInfo : usageInfos) { if (usageInfo instanceof FixableUsageInfo) { try { diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java index 80a4a91bb84a..ca905b0f252d 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java @@ -172,22 +172,6 @@ public class RefactoringUtil { } } - //order of usages accross different files is irrelevant - public static void sortDepthFirstRightLeftOrder(final UsageInfo[] usages) { - Arrays.sort(usages, new Comparator<UsageInfo>() { - public int compare(final UsageInfo usage1, final UsageInfo usage2) { - final PsiElement element1 = usage1.getElement(); - final PsiElement element2 = usage2.getElement(); - if (element1 == null) { - if (element2 == null) return 0; - return 1; - } - if (element2 == null) return -1; - return element2.getTextRange().getStartOffset() - element1.getTextRange().getStartOffset(); - } - }); - } - @Nullable public static String suggestNewOverriderName(String oldOverriderName, String oldBaseName, String newBaseName) { if (oldOverriderName.equals(oldBaseName)) { |