From bcc709fe57d338378e314c135825f8dd499d6a33 Mon Sep 17 00:00:00 2001 From: "Maxim.Medvedev" Date: Fri, 18 May 2012 13:17:27 +0400 Subject: [PATCH 01/63] npe --- .../plugins/groovy/findUsages/LiteralConstructorReference.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorReference.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorReference.java index 3cce2e414f6e..364620fcec53 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorReference.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/LiteralConstructorReference.java @@ -144,7 +144,7 @@ public class LiteralConstructorReference extends PsiReferenceBase.Poly Date: Fri, 18 May 2012 14:34:56 +0400 Subject: [PATCH 02/63] IDEA-63669 Groovy: [ .. ].property is the same as [ .. ]*.property --- .../findUsages/GDKSuperMethodSearcher.java | 3 +- .../lang/psi/api/GroovyResolveResult.java | 13 +- .../groovy/lang/psi/api/SpreadState.java | 55 +++++ .../groovy/lang/psi/impl/GrSpreadType.java | 78 +++++++ .../psi/impl/GroovyResolveResultImpl.java | 36 ++-- .../GrConstructorInvocationImpl.java | 2 +- .../CompleteReferenceExpression.java | 12 +- .../GrReferenceExpressionImpl.java | 191 ++++++++++-------- .../expressions/GrReferenceResolveUtil.java | 106 +++++----- .../statements/expressions/TypesUtil.java | 51 ++++- .../DefaultCallExpressionTypeCalculator.java | 65 +++--- .../expressions/path/GrDGMTypeCalculator.java | 49 +---- .../expressions/path/GrIndexPropertyImpl.java | 2 +- .../enumConstant/GrEnumConstantImpl.java | 4 +- .../types/GrCodeReferenceElementImpl.java | 2 +- .../groovy/lang/psi/util/GdkMethodUtil.java | 12 +- .../plugins/groovy/lang/psi/util/PsiUtil.java | 2 +- .../groovy/lang/resolve/ResolveUtil.java | 54 ++--- .../processors/AccessorResolverProcessor.java | 4 +- .../processors/MethodResolverProcessor.java | 7 +- .../resolve/processors/ResolverProcessor.java | 4 +- .../lang/resolve/ResolveMethodTest.groovy | 2 +- .../lang/resolve/TypeInferenceTest.groovy | 51 +++++ 23 files changed, 518 insertions(+), 287 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/SpreadState.java create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrSpreadType.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GDKSuperMethodSearcher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GDKSuperMethodSearcher.java index 3e604a744937..3f4182719b1d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GDKSuperMethodSearcher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GDKSuperMethodSearcher.java @@ -61,7 +61,8 @@ public class GDKSuperMethodSearcher implements QueryExecutor SPREAD_STATE = Key.create("Spread state"); + + private final PsiType containerType; + @Nullable private final SpreadState innerState; + + public SpreadState(PsiType type, @Nullable SpreadState state) { + containerType = type; + innerState = state; + } + + public PsiType getContainerType() { + return containerType; + } + + @Nullable + public SpreadState getInnerState() { + return innerState; + } + + public static SpreadState create(PsiType type, @Nullable SpreadState state) { + return new SpreadState(type, state); + } + + public static PsiType apply(PsiType item, @Nullable SpreadState state, Project project) { + if (state == null) return item; + return apply(TypesUtil.createSimilarCollection(state.getContainerType(), project, item), state.getInnerState(), project); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrSpreadType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrSpreadType.java new file mode 100644 index 000000000000..99b1556901de --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrSpreadType.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.lang.psi.impl; + +import com.intellij.openapi.project.Project; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiClassType; +import com.intellij.psi.PsiType; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; + +/** + * @author Max Medvedev + */ +public class GrSpreadType extends GrLiteralClassType { + + private PsiType myType; + + public GrSpreadType(PsiType original, PsiType containerType, GlobalSearchScope scope) { + this(original, containerType, LanguageLevel.JDK_1_5, scope, JavaPsiFacade.getInstance(scope.getProject())); + } + + public GrSpreadType(PsiType original, PsiType containerType, LanguageLevel languageLevel, GlobalSearchScope scope, JavaPsiFacade facade) { + super(languageLevel, scope, facade); + + final Project project = facade.getProject(); + myType = TypesUtil.createSimilarCollection(containerType, project, original); + } + + @NotNull + @Override + protected String getJavaClassName() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @NotNull + @Override + public String getClassName() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @NotNull + @Override + public PsiType[] getParameters() { + return new PsiType[0]; //To change body of implemented methods use File | Settings | File Templates. + } + + @NotNull + @Override + public PsiClassType setLanguageLevel(@NotNull LanguageLevel languageLevel) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public String getInternalCanonicalText() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public boolean isValid() { + return false; //To change body of implemented methods use File | Settings | File Templates. + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java index e8b06b9c8eee..0f4521128023 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyResolveResultImpl.java @@ -16,10 +16,12 @@ package org.jetbrains.plugins.groovy.lang.psi.impl; import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; /** * @author ven @@ -31,28 +33,30 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { private final PsiSubstitutor mySubstitutor; private final boolean myIsInvokedOnProperty; - private GroovyPsiElement myCurrentFileResolveContext; + private final GroovyPsiElement myCurrentFileResolveContext; + private final SpreadState mySpreadState; - public GroovyResolveResultImpl(PsiElement element, boolean isAccessible) { - this(element, null, PsiSubstitutor.EMPTY, isAccessible, true); + public GroovyResolveResultImpl(@NotNull PsiElement element, boolean isAccessible) { + this(element, null, null, PsiSubstitutor.EMPTY, isAccessible, true, false); } - public GroovyResolveResultImpl(PsiElement element, - @Nullable GroovyPsiElement context, - PsiSubstitutor substitutor, + public GroovyResolveResultImpl(@NotNull PsiElement element, + @Nullable GroovyPsiElement resolveContext, + @Nullable SpreadState spreadState, + @NotNull PsiSubstitutor substitutor, boolean isAccessible, boolean staticsOK) { - this(element, context, substitutor, isAccessible, staticsOK, false); + this(element, resolveContext, spreadState, substitutor, isAccessible, staticsOK, false); } public GroovyResolveResultImpl(PsiClassType.ClassResolveResult classResolveResult) { - this(classResolveResult.getElement(), null, classResolveResult.getSubstitutor(), classResolveResult.isAccessible(), - classResolveResult.isStaticsScopeCorrect()); + this(classResolveResult.getElement(), null, null, classResolveResult.getSubstitutor(), classResolveResult.isAccessible(), classResolveResult.isStaticsScopeCorrect(), false); } - public GroovyResolveResultImpl(PsiElement element, - GroovyPsiElement resolveContext, - PsiSubstitutor substitutor, + public GroovyResolveResultImpl(@NotNull PsiElement element, + @Nullable GroovyPsiElement resolveContext, + @Nullable SpreadState spreadState, + @NotNull PsiSubstitutor substitutor, boolean isAccessible, boolean staticsOK, boolean isInvokedOnProperty) { @@ -62,8 +66,10 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { mySubstitutor = substitutor; myIsStaticsOK = staticsOK; myIsInvokedOnProperty = isInvokedOnProperty; + mySpreadState = spreadState; } + @NotNull public PsiSubstitutor getSubstitutor() { return mySubstitutor; } @@ -108,6 +114,7 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { return result; } + @Nullable public GroovyPsiElement getCurrentFileResolveContext() { return myCurrentFileResolveContext; } @@ -116,6 +123,11 @@ public class GroovyResolveResultImpl implements GroovyResolveResult { return myIsInvokedOnProperty; } + @Override + public SpreadState getSpreadState() { + return mySpreadState; + } + @Override public String toString() { return "GroovyResolveResultImpl{" + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java index b1eb3ea33932..e6c630bef390 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/GrConstructorInvocationImpl.java @@ -95,7 +95,7 @@ public class GrConstructorInvocationImpl extends GrCallImpl implements GrConstru } public GroovyResolveResult[] multiResolveClass() { - return new GroovyResolveResult[]{new GroovyResolveResultImpl(getDelegatedClass(), this, PsiSubstitutor.EMPTY, true, true)}; + return new GroovyResolveResult[]{new GroovyResolveResultImpl(getDelegatedClass(), this, null, PsiSubstitutor.EMPTY, true, true)}; } public PsiMethod resolveMethod() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java index 080bc3d9e4cc..75e809c5b795 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java @@ -35,6 +35,7 @@ import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; @@ -117,7 +118,7 @@ public class CompleteReferenceExpression { getVariantsFromQualifierForSpreadOperator(refExpr, processor, qualifier); } } - ResolveUtil.processCategoryMembers(refExpr, processor); + ResolveUtil.processCategoryMembers(refExpr, processor, ResolveState.initial()); } private static void getVariantsFromQualifierForSpreadOperator(GrReferenceExpression refExpr, @@ -206,8 +207,8 @@ public class CompleteReferenceExpression { final GrPropertyForCompletion field = new GrPropertyForCompletion(method, name, type); if (resolveResult != null) { - return new GroovyResolveResultImpl(field, resolveResult.getCurrentFileResolveContext(), resolveResult.getSubstitutor(), - resolveResult.isAccessible(), resolveResult.isStaticsOK()); + return new GroovyResolveResultImpl(field, resolveResult.getCurrentFileResolveContext(), resolveResult.getSpreadState(), + resolveResult.getSubstitutor(), resolveResult.isAccessible(), resolveResult.isStaticsOK(), false); } else { return new GroovyResolveResultImpl(field, true); @@ -377,12 +378,13 @@ public class CompleteReferenceExpression { boolean isAccessible = isAccessible(namedElement); final GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT); + final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE); boolean isStaticsOK = isStaticsOK(namedElement, resolveContext, myParameters.getInvocationCount() <= 1); PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY); if (substitutor == null) substitutor = PsiSubstitutor.EMPTY; - consume(new GroovyResolveResultImpl(namedElement, resolveContext, substitutor, isAccessible, isStaticsOK)); + consume(new GroovyResolveResultImpl(namedElement, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK)); return true; } @@ -407,7 +409,7 @@ public class CompleteReferenceExpression { element = ((GrReflectedMethod)element).getBaseMethod(); if (!myProcessedMethodWithOptionalParams.add((GrMethod)element)) return; - result = new GroovyResolveResultImpl(element, result.getCurrentFileResolveContext(), + result = new GroovyResolveResultImpl(element, result.getCurrentFileResolveContext(), result.getSpreadState(), result.getSubstitutor(), result.isAccessible(), result.isStaticsOK(), result.isInvokedOnProperty()); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 8cdc0970c303..6c54eeebb8d3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -42,6 +42,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; @@ -64,7 +65,8 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.List; -import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mAT; +import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mMEMBER_POINTER; /** * @author ilyas @@ -121,7 +123,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl accessorResults = new ArrayList(); for (String accessorName : accessorNames) { - AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, getThisType(), getTypeArguments()); + AccessorResolverProcessor accessorResolver = + new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, getThisType(), getTypeArguments()); GrReferenceResolveUtil.resolveImpl(accessorResolver, this); final GroovyResolveResult[] candidates = accessorResolver.getCandidates(); @@ -198,7 +202,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl>() { - @Override - public Result> compute() { - return Result.create(doResolveByShape(false, null), PsiModificationTracker.MODIFICATION_COUNT); - } - }); + return CachedValuesManager.getManager(getProject()) + .getCachedValue(this, new CachedValueProvider>() { + @Override + public Result> compute() { + return Result.create(doResolveByShape(false, null), PsiModificationTracker.MODIFICATION_COUNT); + } + }); } private Pair doResolveByShape(boolean allVariants, @Nullable GrExpression upToArgument) { @@ -329,7 +334,10 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl() { @Override public Result compute() { - GroovyResolveResult[] value = RecursionManager.doPreventingRecursion(GrReferenceExpressionImpl.this, true, new Computable() { - @Override - public GroovyResolveResult[] compute() { - return doPolyResolve(false, false); - } - }); + GroovyResolveResult[] value = + RecursionManager.doPreventingRecursion(GrReferenceExpressionImpl.this, true, new Computable() { + @Override + public GroovyResolveResult[] compute() { + return doPolyResolve(false, false); + } + }); if (value == null) { value = GroovyResolveResult.EMPTY_ARRAY; } @@ -459,8 +468,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl 1) { PsiParameter last = parameters[parameters.length - 1]; - return TypesUtil.substituteBoxAndNormalizeType(last.getType(), candidate.getSubstitutor(), this); + return TypesUtil.substituteBoxAndNormalizeType(last.getType(), candidate.getSubstitutor(), candidate.getSpreadState(), this); } } return null; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java index be8c8d08977b..afd5148ac5c0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/typedef/enumConstant/GrEnumConstantImpl.java @@ -102,8 +102,7 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant { } public GroovyResolveResult[] multiResolveClass() { - final PsiClass psiClass = getContainingClass(); - GroovyResolveResult result = new GroovyResolveResultImpl(psiClass, this, PsiSubstitutor.EMPTY, true, true); + GroovyResolveResult result = new GroovyResolveResultImpl(getContainingClass(), this, null, PsiSubstitutor.EMPTY, true, true); return new GroovyResolveResult[]{result}; } @@ -135,7 +134,6 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant { public GrExpression[] getExpressionArguments() { final GrArgumentList argumentList = getArgumentList(); return argumentList == null ? GrExpression.EMPTY_ARRAY : argumentList.getExpressionArguments(); - } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java index 239e24f42bc7..0aed67b8c24e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/types/GrCodeReferenceElementImpl.java @@ -376,7 +376,7 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImplp ''', "$JAVA_UTIL_MAP<$JAVA_LANG_STRING,$JAVA_LANG_STRING>") } + void testSpread1() { + myFixture.addClass('''\ +class A { + String getString() {return "a";} +}''') + doTest('''\ +[new A()].string +''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>") + } + + void testSpread2() { + + myFixture.addClass('''\ +class A { + String getString() {return "a";} +}''') + doTest('''\ +class Cat { + static getFoo(String b) {2} +} +use(Cat) { + [new A()].string.foo +} +''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>") + } + + void testSpread3() { + myFixture.addClass('''\ +class A { + String getString() {return "a";} +}''') + doTest('''\ +[[new A()]].string +''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>>") + } + + void testSpread4() { + myFixture.addClass('''\ +class A { + String getString() {return "a";} +}''') + doTest('''\ +class Cat { + static getFoo(String b) {2} +} + +use(Cat){ + [[new A()]].string.foo +} +''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>>") + } private void doTest(String text, String type) { def file = myFixture.configureByText('_.groovy', text) From 00ffec389c6ab63fcccbf02f175328b8eec84b95 Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Fri, 18 May 2012 14:58:18 +0400 Subject: [PATCH 03/63] include tag --- .../AndroidDesignerEditorPanel.java | 7 +- .../android/designer/model/ModelParser.java | 3 +- ...deComponent.java => RadIncludeLayout.java} | 36 +++++-- .../designer/model/RadViewComponent.java | 4 + .../designer/model/views-meta-model.xml | 7 +- .../propertyTable/IncludeLayoutProperty.java | 89 +++++++++++++++++ .../propertyTable/editors/ResourceEditor.java | 99 +++++++++++-------- 7 files changed, 191 insertions(+), 54 deletions(-) rename plugins/android-designer/src/com/intellij/android/designer/model/{RadIncludeComponent.java => RadIncludeLayout.java} (50%) create mode 100644 plugins/android-designer/src/com/intellij/android/designer/propertyTable/IncludeLayoutProperty.java diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java index 676a3e3f970f..6255d57e7c42 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java @@ -22,6 +22,7 @@ import com.intellij.android.designer.actions.ProfileAction; import com.intellij.android.designer.componentTree.AndroidTreeDecorator; import com.intellij.android.designer.model.ModelParser; import com.intellij.android.designer.model.PropertyParser; +import com.intellij.android.designer.model.RadIncludeLayout; import com.intellij.android.designer.model.RadViewComponent; import com.intellij.android.designer.profile.ProfileManager; import com.intellij.designer.DesignerToolWindowManager; @@ -441,7 +442,11 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { @NotNull @Override public RadComponent create() throws Exception { - return ModelParser.createComponent(null, paletteItem.getMetaModel()); + RadViewComponent component = ModelParser.createComponent(null, paletteItem.getMetaModel()); + if (component instanceof RadIncludeLayout) { + ((RadIncludeLayout)component).configure(getModule()); + } + return component; } }; } diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java b/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java index 82b217020b22..104585082d1d 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/ModelParser.java @@ -177,7 +177,8 @@ public class ModelParser extends XmlRecursiveElementVisitor { addComponentTag(container.getTag(), newComponent, insertBefore == null ? null : insertBefore.getTag(), new Computable() { @Override public String compute() { - return newComponent.getMetaModel().getCreation(); + String creation = newComponent.getMetaModel().getCreation(); + return creation == null ? newComponent.getCreationXml() : creation; } }); diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java similarity index 50% rename from plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeComponent.java rename to plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java index d8305c0db939..febad7a1c2ad 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadIncludeLayout.java @@ -16,7 +16,11 @@ package com.intellij.android.designer.model; import com.intellij.android.designer.propertyTable.IdProperty; +import com.intellij.android.designer.propertyTable.IncludeLayoutProperty; +import com.intellij.android.designer.propertyTable.editors.ResourceDialog; import com.intellij.designer.propertyTable.Property; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.ui.DialogWrapper; import org.jetbrains.android.dom.attrs.AttributeDefinition; import org.jetbrains.android.dom.attrs.AttributeFormat; @@ -27,20 +31,38 @@ import java.util.List; /** * @author Alexander Lobas */ -public class RadIncludeComponent extends RadViewComponent { - private final List myProperties = new ArrayList(); +public class RadIncludeLayout extends RadViewComponent { + private static final Property LAYOUT_PROPERTY = new IncludeLayoutProperty(); + private static final Property ID_PROPERTY = new IdProperty("id", new AttributeDefinition("id", Arrays.asList(AttributeFormat.Reference))); - public RadIncludeComponent() { - IdProperty idProperty = new IdProperty("id", new AttributeDefinition("id", Arrays.asList(AttributeFormat.Reference))); - idProperty.setImportant(true); - myProperties.add(idProperty); + static { + LAYOUT_PROPERTY.setImportant(true); + ID_PROPERTY.setImportant(true); + } + + @Override + public String getCreationXml() { + return ""; + } + + public void configure(Module module) throws Exception { + ResourceDialog dialog = new ResourceDialog(module, IncludeLayoutProperty.TYPES); + dialog.show(); + + if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + setClientProperty(IncludeLayoutProperty.NAME, dialog.getResourceName()); + } + else { + throw new Exception(); + } } @Override public void setProperties(List properties) { if (!properties.isEmpty()) { properties = new ArrayList(properties); - properties.addAll(myProperties); + properties.add(LAYOUT_PROPERTY); + properties.add(ID_PROPERTY); } super.setProperties(properties); } diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java index 6e81f9f11c92..a472aa3aaf51 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java @@ -61,6 +61,10 @@ public class RadViewComponent extends RadVisualComponent { } } + public String getCreationXml() { + throw new UnsupportedOperationException(); + } + public ViewInfo getViewInfo() { return myViewInfo; } diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index 421c4cc74d9e..3f765a78f624 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -19,11 +19,11 @@ - - + @@ -1398,6 +1398,9 @@ + + + \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IncludeLayoutProperty.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IncludeLayoutProperty.java new file mode 100644 index 000000000000..e6505db292d0 --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/IncludeLayoutProperty.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.propertyTable; + +import com.android.resources.ResourceType; +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.android.designer.propertyTable.editors.ResourceEditor; +import com.intellij.android.designer.propertyTable.renderers.ResourceRenderer; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.propertyTable.Property; +import com.intellij.designer.propertyTable.PropertyEditor; +import com.intellij.designer.propertyTable.PropertyRenderer; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.android.dom.attrs.AttributeFormat; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +/** + * @author Alexander Lobas + */ +public class IncludeLayoutProperty extends Property { + public static final String NAME = "layout:xml"; + public static ResourceType[] TYPES = new ResourceType[]{ResourceType.LAYOUT}; + private static final Set FORMATS = EnumSet.of(AttributeFormat.Reference); + + private final PropertyRenderer myRenderer = new ResourceRenderer(FORMATS); + private final PropertyEditor myEditor = new ResourceEditor(TYPES, FORMATS, null); + + public IncludeLayoutProperty() { + super(null, NAME); + } + + @Override + public Property createForNewPresentation(@Nullable Property parent, @NotNull String name) { + return null; + } + + @Override + public Object getValue(RadViewComponent component) throws Exception { + String layout = component.getTag().getAttributeValue("layout"); + return layout == null ? "" : layout; + } + + @Override + public void setValue(final RadViewComponent component, final Object value) throws Exception { + if (!StringUtil.isEmpty((String)value)) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + component.getTag().setAttribute("layout", (String)value); + } + }); + } + } + + @Override + public boolean availableFor(List components) { + return false; + } + + @NotNull + @Override + public PropertyRenderer getRenderer() { + return myRenderer; + } + + @Override + public PropertyEditor getEditor() { + return myEditor; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceEditor.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceEditor.java index 835a98e3831f..f9ee6a52239c 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceEditor.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceEditor.java @@ -38,40 +38,16 @@ import java.util.Set; * @author Alexander Lobas */ public class ResourceEditor extends PropertyEditor { - private ResourceType[] myTypes; + private final ResourceType[] myTypes; private ComponentWithBrowseButton myEditor; private RadComponent myRootComponent; public ResourceEditor(Set formats, String[] values) { - Set types = EnumSet.noneOf(ResourceType.class); - for (AttributeFormat format : formats) { - switch (format) { - case Boolean: - types.add(ResourceType.BOOL); - break; - case Color: - types.add(ResourceType.COLOR); - types.add(ResourceType.DRAWABLE); - break; - case Dimension: - types.add(ResourceType.DIMEN); - break; - case Integer: - types.add(ResourceType.INTEGER); - break; - case String: - types.add(ResourceType.STRING); - break; - case Reference: - types.add(ResourceType.COLOR); - types.add(ResourceType.DRAWABLE); - types.add(ResourceType.STRING); - types.add(ResourceType.ID); - types.add(ResourceType.STYLE); - break; - } - } - myTypes = types.toArray(new ResourceType[types.size()]); + this(convertTypes(formats), formats, values); + } + + public ResourceEditor(ResourceType[] types, Set formats, String[] values) { + myTypes = types; if (formats.contains(AttributeFormat.Enum) || formats.contains(AttributeFormat.Boolean)) { ComboboxWithBrowseButton editor = new ComboboxWithBrowseButton(); @@ -118,14 +94,7 @@ public class ResourceEditor extends PropertyEditor { myEditor.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - PropertyParser parser = myRootComponent.getClientProperty(PropertyParser.KEY); - ResourceDialog dialog = parser.createResourceDialog(myTypes); - dialog.show(); - - if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { - getComboText().setText(dialog.getResourceName()); - fireValueCommitted(true, true); - } + showDialog(); } }); myEditor.addFocusListener(new FocusAdapter() { @@ -136,6 +105,39 @@ public class ResourceEditor extends PropertyEditor { }); } + private static ResourceType[] convertTypes(Set formats) { + Set types = EnumSet.noneOf(ResourceType.class); + for (AttributeFormat format : formats) { + switch (format) { + case Boolean: + types.add(ResourceType.BOOL); + break; + case Color: + types.add(ResourceType.COLOR); + types.add(ResourceType.DRAWABLE); + break; + case Dimension: + types.add(ResourceType.DIMEN); + break; + case Integer: + types.add(ResourceType.INTEGER); + break; + case String: + types.add(ResourceType.STRING); + break; + case Reference: + types.add(ResourceType.COLOR); + types.add(ResourceType.DRAWABLE); + types.add(ResourceType.STRING); + types.add(ResourceType.ID); + types.add(ResourceType.STYLE); + break; + } + } + + return types.toArray(new ResourceType[types.size()]); + } + @NotNull @Override public JComponent getComponent(@NotNull RadComponent rootComponent, @Nullable RadComponent component, Object value) { @@ -151,6 +153,22 @@ public class ResourceEditor extends PropertyEditor { return value == StringsComboEditor.UNSET || StringUtil.isEmpty(value) ? null : value; } + @Override + public void updateUI() { + SwingUtilities.updateComponentTreeUI(myEditor); + } + + private void showDialog() { + PropertyParser parser = myRootComponent.getClientProperty(PropertyParser.KEY); + ResourceDialog dialog = parser.createResourceDialog(myTypes); + dialog.show(); + + if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + getComboText().setText(dialog.getResourceName()); + fireValueCommitted(true, true); + } + } + private JTextField getComboText() { JComponent component = myEditor.getChildComponent(); if (component instanceof JTextField) { @@ -159,9 +177,4 @@ public class ResourceEditor extends PropertyEditor { JComboBox combo = (JComboBox)component; return (JTextField)combo.getEditor().getEditorComponent(); } - - @Override - public void updateUI() { - SwingUtilities.updateComponentTreeUI(myEditor); - } } \ No newline at end of file From 8aa66c1911f9185f1709f5b0d28a1102f91ed3a2 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 18 May 2012 14:59:56 +0400 Subject: [PATCH 04/63] non-negative range asserted --- .../codeInsight/editorActions/moveUpDown/LineRange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-api/src/com/intellij/codeInsight/editorActions/moveUpDown/LineRange.java b/platform/lang-api/src/com/intellij/codeInsight/editorActions/moveUpDown/LineRange.java index b9fba8d2bf57..cce3cd8c39e3 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/editorActions/moveUpDown/LineRange.java +++ b/platform/lang-api/src/com/intellij/codeInsight/editorActions/moveUpDown/LineRange.java @@ -33,7 +33,7 @@ public class LineRange { public LineRange(final int startLine, final int endLine) { this.startLine = startLine; this.endLine = endLine; - LOG.assertTrue(startLine > 0, "Negative start line"); + LOG.assertTrue(startLine >= 0, "Negative start line"); if (startLine > endLine) { LOG.error("start > end: start=" + startLine+"; end="+endLine); } From a20df07c6dd3427e19debd569a8d87e7e095d788 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 18 May 2012 13:41:12 +0200 Subject: [PATCH 05/63] looks like CoreEnvironment tests still don't mix well with standard ones --- .../testSrc/com/intellij/core/CoreModuleManagerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java b/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java index e25ae7ab4100..3e3e6e7eea6e 100644 --- a/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java @@ -38,5 +38,7 @@ public class CoreModuleManagerTest extends UsefulTestCase { final ModuleManager moduleManager = ModuleManager.getInstance(env.getProject()); final Module[] modules = moduleManager.getModules(); assertEquals(1, modules.length); + + // } } From 56311ae33e2cf3dc0d63b6e6bdde1414cd9ef491 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 18 May 2012 13:00:19 +0400 Subject: [PATCH 06/63] inline to anonymous: wrap code with code block when needed (IDEA-86007) --- ...InlineToAnonymousConstructorProcessor.java | 22 +++++++++++++--- .../inlineToAnonymousClass/Braces.java | 26 +++++++++++++++++++ .../inlineToAnonymousClass/Braces.java.after | 22 ++++++++++++++++ .../inline/InlineToAnonymousClassTest.java | 4 +++ 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java create mode 100644 java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java.after diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousConstructorProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousConstructorProcessor.java index 31fbe26be597..b762395a7a2a 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousConstructorProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousConstructorProcessor.java @@ -57,11 +57,11 @@ class InlineToAnonymousConstructorProcessor { psiElement().withText(PsiKeyword.THIS))); private final PsiClass myClass; - private final PsiNewExpression myNewExpression; + private PsiNewExpression myNewExpression; private final PsiType mySuperType; private final Map myFieldInitializers = new HashMap(); private final Map myLocalsForParameters = new HashMap(); - private final PsiStatement myNewStatement; + private PsiStatement myNewStatement; private final PsiElementFactory myElementFactory; private PsiMethod myConstructor; private PsiExpressionList myConstructorArguments; @@ -263,7 +263,23 @@ class InlineToAnonymousConstructorProcessor { final PsiDeclarationStatement declaration = myElementFactory.createVariableDeclarationStatement(localName, type, initializer); PsiVariable variable = (PsiVariable)declaration.getDeclaredElements()[0]; PsiUtil.setModifierProperty(variable, PsiModifier.FINAL, true); - myNewStatement.getParent().addBefore(declaration, myNewStatement); + final PsiElement parent = myNewStatement.getParent(); + if (parent instanceof PsiCodeBlock) { + variable = (PsiVariable)((PsiDeclarationStatement)parent.addBefore(declaration, myNewStatement)).getDeclaredElements()[0]; + } + else { + final int offsetInStatement = myNewExpression.getTextRange().getStartOffset() - myNewStatement.getTextRange().getStartOffset(); + final PsiBlockStatement blockStatement = (PsiBlockStatement)myElementFactory.createStatementFromText("{}", null); + PsiCodeBlock block = blockStatement.getCodeBlock(); + block.add(declaration); + block.add(myNewStatement); + block = ((PsiBlockStatement)myNewStatement.replace(blockStatement)).getCodeBlock(); + + variable = (PsiVariable)((PsiDeclarationStatement)block.getStatements()[0]).getDeclaredElements()[0]; + myNewStatement = block.getStatements()[1]; + myNewExpression = PsiTreeUtil.getParentOfType(myNewStatement.findElementAt(offsetInStatement), PsiNewExpression.class); + } + return variable; } catch (IncorrectOperationException e) { diff --git a/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java b/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java new file mode 100644 index 000000000000..fc3eddbb1b9c --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java @@ -0,0 +1,26 @@ +public class Demo { + + static class MyParent { + private final String value; + + MyParent(String value) { + this.value = value; + } + } + + static class MyChild extends MyParent { + MyChild(String value) { + super(value); + } + } + + public static void main(String[] args) { + + String value = "something"; + final MyParent p; + if (true) + p = new MyChild(value); + else + p = new MyParent("value"); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java.after b/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java.after new file mode 100644 index 000000000000..8a2d39edbd07 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineToAnonymousClass/Braces.java.after @@ -0,0 +1,22 @@ +public class Demo { + + static class MyParent { + private final String value; + + MyParent(String value) { + this.value = value; + } + } + + public static void main(String[] args) { + + String value = "something"; + final MyParent p; + if (true) { + final String value1 = value; + p = new MyParent(value1); + } + else + p = new MyParent("value"); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java index f9edb4b24490..469acd2a150f 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java @@ -226,6 +226,10 @@ public class InlineToAnonymousClassTest extends LightRefactoringTestCase { doTest(false, true); } + public void testBraces() throws Exception { + doTest(false, false); + } + public void testNoInlineAbstract() throws Exception { doTestNoInline("Abstract classes cannot be inlined"); } From bbca2280a9ecdec406ca323b64655cfacde424cd Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 18 May 2012 13:56:00 +0200 Subject: [PATCH 07/63] cleanup --- platform/core-impl/src/com/intellij/core/CoreEnvironment.java | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java index 19ef4406fc54..b103821ea144 100644 --- a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java +++ b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java @@ -135,7 +135,6 @@ public class CoreEnvironment { registerExtensionPoint(Extensions.getRootArea(), BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint.class); myFileIndexFacade = new MockFileIndexFacade(myProject); - final MutablePicoContainer projectContainer = myProject.getPicoContainer(); PsiModificationTrackerImpl modificationTracker = new PsiModificationTrackerImpl(myProject); myProject.registerService(PsiModificationTracker.class, modificationTracker); From 5ff4cccc451109004a5b700dcd1257e53b8152ca Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Fri, 18 May 2012 16:03:49 +0400 Subject: [PATCH 08/63] Shuffle Names action --- plugins/devkit/resources/META-INF/plugin.xml | 5 + .../src/actions/ShuffleNamesAction.java | 130 ++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 plugins/devkit/src/actions/ShuffleNamesAction.java diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index f7bd8c9d1061..1a57d95de8a0 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -120,6 +120,11 @@ + + + + diff --git a/plugins/devkit/src/actions/ShuffleNamesAction.java b/plugins/devkit/src/actions/ShuffleNamesAction.java new file mode 100644 index 000000000000..5cf7dde89b25 --- /dev/null +++ b/plugins/devkit/src/actions/ShuffleNamesAction.java @@ -0,0 +1,130 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.devkit.actions; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessorEx; +import com.intellij.openapi.command.UndoConfirmationPolicy; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiRecursiveElementWalkingVisitor; +import com.intellij.psi.impl.source.tree.LeafPsiElement; +import gnu.trove.THashMap; + +import java.util.*; + +/** + * @author gregsh + */ +public class ShuffleNamesAction extends AnAction { + @Override + public void update(AnActionEvent e) { + Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext()); + PsiFile file = LangDataKeys.PSI_FILE.getData(e.getDataContext()); + e.getPresentation().setEnabled(editor != null && file != null); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext()); + PsiFile file = LangDataKeys.PSI_FILE.getData(e.getDataContext()); + if (editor == null || file == null) return; + final Project project = file.getProject(); + CommandProcessorEx commandProcessor = (CommandProcessorEx)CommandProcessorEx.getInstance(); + Object commandToken = commandProcessor.startCommand(project, e.getPresentation().getText(), e.getPresentation().getText(), UndoConfirmationPolicy.DEFAULT); + AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass()); + try { + shuffleIds(file, editor); + } + finally { + token.finish(); + commandProcessor.finishCommand(project, commandToken, null); + } + } + + private static boolean shuffleIds(PsiFile file, Editor editor) { + final Map map = new THashMap(); + final StringBuilder sb = new StringBuilder(); + final StringBuilder quote = new StringBuilder(); + final ArrayList split = new ArrayList(100); + file.acceptChildren(new PsiRecursiveElementWalkingVisitor() { + @Override + public void visitElement(PsiElement element) { + if (element instanceof LeafPsiElement) { + String type = ((LeafPsiElement)element).getElementType().toString(); + String text = element.getText(); + if (text.isEmpty()) return; + + for (int i=0, len=text.length(); i 0; + boolean isNumber = false; + if (isQuoted || type.equals("ID") || type.contains("IDENT") && !"ts".equals(text) || + (isNumber = text.matches("[0-9]+"))) { + String replacement = map.get(text); + if (replacement == null) { + split.addAll(Arrays.asList((isQuoted? text.substring(quote.length(), text.length()-quote.length()).replace("''", "") : text).split(""))); + if (!isNumber) { + for (ListIterator it = split.listIterator(); it.hasNext(); ) { + String s = it.next(); + if (s.isEmpty()) { + it.remove(); + continue; + } + int c = s.charAt(0); + int cap = c & 32; + c &= ~cap; + c = (char) ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 7) % 26 + 'A') : c) | cap; + it.set(String.valueOf((char)c)); + } + } + Collections.shuffle(split); + if (isNumber && "0".equals(split.get(0))) { + split.set(0, "1"); + } + replacement = StringUtil.join(split, ""); + if (isQuoted) { + replacement = quote + replacement + quote.reverse(); + } + map.put(text, replacement); + } + text = replacement; + } + sb.append(text); + quote.setLength(0); + split.clear(); + } + super.visitElement(element); + } + }); + editor.getDocument().setText(sb.toString()); + return true; + } +} From 36c3ac8b980fcf82298990f1effa6ad0cba3875d Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 18 May 2012 14:06:47 +0200 Subject: [PATCH 09/63] register extensions area and extension points for module; register some more components --- .../openapi/components/ExtensionAreas.java | 26 +++++++++++++++++++ .../com/intellij/core/CoreEnvironment.java | 13 +++++----- .../src/com/intellij/mock/MockProject.java | 3 ++- .../openapi/module/impl/ModuleImpl.java | 3 ++- .../intellij/ide/plugins/PluginManager.java | 9 +++---- .../openapi/project/impl/ProjectImpl.java | 3 ++- .../intellij/core/CoreModuleManagerTest.java | 6 ++++- .../src/com/intellij/core/CoreModule.java | 24 +++++++++++++++++ .../core/ProjectModelEnvironment.java | 18 +++++++++++-- 9 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 platform/core-api/src/com/intellij/openapi/components/ExtensionAreas.java diff --git a/platform/core-api/src/com/intellij/openapi/components/ExtensionAreas.java b/platform/core-api/src/com/intellij/openapi/components/ExtensionAreas.java new file mode 100644 index 000000000000..f539a84ae79a --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/components/ExtensionAreas.java @@ -0,0 +1,26 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.components; + +import org.jetbrains.annotations.NonNls; + +/** + * @author yole + */ +public class ExtensionAreas { + @NonNls public static final String IDEA_PROJECT = "IDEA_PROJECT"; + @NonNls public static final String IDEA_MODULE = "IDEA_MODULE"; +} diff --git a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java index b103821ea144..c8855ac881b8 100644 --- a/platform/core-impl/src/com/intellij/core/CoreEnvironment.java +++ b/platform/core-impl/src/com/intellij/core/CoreEnvironment.java @@ -21,6 +21,7 @@ import com.intellij.mock.*; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.extensions.ExtensionPoint; @@ -97,7 +98,7 @@ public class CoreEnvironment { myLocalFileSystem = new CoreLocalFileSystem(); myJarFileSystem = new CoreJarFileSystem(); - Extensions.registerAreaClass("IDEA_PROJECT", null); + Extensions.registerAreaClass(ExtensionAreas.IDEA_PROJECT, null); myProject = new MockProject(myApplication.getPicoContainer(), myParentDisposable); final MutablePicoContainer appContainer = myApplication.getPicoContainer(); @@ -198,7 +199,7 @@ public class CoreEnvironment { addExplicitExtension(LanguageParserDefinitions.INSTANCE, definition.getFileNodeType().getLanguage(), definition); } - protected void registerComponentInstance(final MutablePicoContainer container, final Class key, final T implementation) { + public static void registerComponentInstance(final MutablePicoContainer container, final Class key, final T implementation) { container.unregisterComponent(key); container.registerComponentInstance(key, implementation); } @@ -234,20 +235,20 @@ public class CoreEnvironment { }); } - protected void registerExtensionPoint(final ExtensionsArea area, final ExtensionPointName extensionPointName, - final Class aClass) { + public static void registerExtensionPoint(final ExtensionsArea area, final ExtensionPointName extensionPointName, + final Class aClass) { final String name = extensionPointName.getName(); registerExtensionPoint(area, name, aClass); } - protected void registerExtensionPoint(ExtensionsArea area, String name, Class aClass) { + public static void registerExtensionPoint(ExtensionsArea area, String name, Class aClass) { if (!area.hasExtensionPoint(name)) { ExtensionPoint.Kind kind = aClass.isInterface() || (aClass.getModifiers() & Modifier.ABSTRACT) != 0 ? ExtensionPoint.Kind.INTERFACE : ExtensionPoint.Kind.BEAN_CLASS; area.registerExtensionPoint(name, aClass.getName(), kind); } } - protected void registerProjectExtensionPoint(final ExtensionPointName extensionPointName, + public void registerProjectExtensionPoint(final ExtensionPointName extensionPointName, final Class aClass) { registerExtensionPoint(Extensions.getArea(myProject), extensionPointName, aClass); } diff --git a/platform/core-impl/src/com/intellij/mock/MockProject.java b/platform/core-impl/src/com/intellij/mock/MockProject.java index 5810005314b4..7ca777d7229b 100644 --- a/platform/core-impl/src/com/intellij/mock/MockProject.java +++ b/platform/core-impl/src/com/intellij/mock/MockProject.java @@ -16,6 +16,7 @@ package com.intellij.mock; import com.intellij.openapi.Disposable; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; @@ -35,7 +36,7 @@ public class MockProject extends MockComponentManager implements Project { public MockProject(PicoContainer parent, @NotNull Disposable parentDisposable) { super(parent, parentDisposable); - Extensions.instantiateArea("IDEA_PROJECT", this, null); + Extensions.instantiateArea(ExtensionAreas.IDEA_PROJECT, this, null); Disposer.register(parentDisposable, new Disposable() { @Override public void dispose() { diff --git a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java index 9931d53c3dc3..dc377069df0a 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleImpl.java @@ -20,6 +20,7 @@ import com.intellij.ide.highlighter.ModuleFileType; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.PluginManager; import com.intellij.openapi.application.impl.ApplicationInfoImpl; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.components.impl.ComponentManagerImpl; import com.intellij.openapi.components.impl.ModulePathMacroManager; import com.intellij.openapi.components.impl.stores.IComponentStore; @@ -85,7 +86,7 @@ public class ModuleImpl extends ComponentManagerImpl implements ModuleEx { } protected void bootstrapPicoContainer() { - Extensions.instantiateArea(PluginManager.AREA_IDEA_MODULE, this, (AreaInstance)getParentComponentManager()); + Extensions.instantiateArea(ExtensionAreas.IDEA_MODULE, this, (AreaInstance)getParentComponentManager()); super.bootstrapPicoContainer(); getPicoContainer().registerComponentImplementation(IComponentStore.class, ModuleStoreImpl.class); getPicoContainer().registerComponentImplementation(ModulePathMacroManager.class); diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java index 9f2c57e529c6..b93eb4736d10 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import com.intellij.notification.Notifications; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.extensions.LogProvider; @@ -74,8 +75,6 @@ import java.util.zip.ZipInputStream; @SuppressWarnings({"UseOfSystemOutOrSystemErr", "CallToPrintStackTrace"}) // No logger is loaded at this time so we have to use these. public class PluginManager { - @NonNls public static final String AREA_IDEA_PROJECT = "IDEA_PROJECT"; - @NonNls public static final String AREA_IDEA_MODULE = "IDEA_MODULE"; @NonNls private static final String PROPERTY_PLUGIN_PATH = "plugin.path"; private static final Object PLUGIN_CLASSES_LOCK = new Object(); private static String myPluginError = null; @@ -318,8 +317,8 @@ public class PluginManager { private static void configureExtensions() { Extensions.setLogProvider(new IdeaLogProvider()); - Extensions.registerAreaClass(AREA_IDEA_PROJECT, null); - Extensions.registerAreaClass(AREA_IDEA_MODULE, AREA_IDEA_PROJECT); + Extensions.registerAreaClass(ExtensionAreas.IDEA_PROJECT, null); + Extensions.registerAreaClass(ExtensionAreas.IDEA_MODULE, ExtensionAreas.IDEA_PROJECT); } private static boolean shouldLoadPlugins() { diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java index 57507f41f83c..8052dec5cd3d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java @@ -26,6 +26,7 @@ import com.intellij.openapi.application.PathMacros; import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.application.impl.ApplicationInfoImpl; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.components.StorageScheme; import com.intellij.openapi.components.TrackingPathMacroSubstitutor; @@ -131,7 +132,7 @@ public class ProjectImpl extends ComponentManagerImpl implements ProjectEx { @Override protected void bootstrapPicoContainer() { - Extensions.instantiateArea(PluginManager.AREA_IDEA_PROJECT, this, null); + Extensions.instantiateArea(ExtensionAreas.IDEA_PROJECT, this, null); super.bootstrapPicoContainer(); final MutablePicoContainer picoContainer = getPicoContainer(); diff --git a/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java b/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java index 3e3e6e7eea6e..ee9aa2126b95 100644 --- a/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java +++ b/platform/platform-tests/testSrc/com/intellij/core/CoreModuleManagerTest.java @@ -18,6 +18,8 @@ package com.intellij.core; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.roots.ContentEntry; +import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.UsefulTestCase; @@ -39,6 +41,8 @@ public class CoreModuleManagerTest extends UsefulTestCase { final Module[] modules = moduleManager.getModules(); assertEquals(1, modules.length); - // + ModuleRootManager rootManager = ModuleRootManager.getInstance(modules[0]); + final ContentEntry[] contentEntries = rootManager.getContentEntries(); + assertEquals(1, contentEntries.length); } } diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreModule.java b/platform/projectModel-impl/src/com/intellij/core/CoreModule.java index 544d79398992..df90be24e440 100644 --- a/platform/projectModel-impl/src/com/intellij/core/CoreModule.java +++ b/platform/projectModel-impl/src/com/intellij/core/CoreModule.java @@ -17,9 +17,18 @@ package com.intellij.core; import com.intellij.mock.MockComponentManager; import com.intellij.openapi.Disposable; +import com.intellij.openapi.components.ExtensionAreas; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.impl.ModuleEx; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleExtension; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.impl.DirectoryIndex; +import com.intellij.openapi.roots.impl.ModuleRootManagerImpl; +import com.intellij.openapi.roots.impl.ProjectRootManagerImpl; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; @@ -34,6 +43,21 @@ public class CoreModule extends MockComponentManager implements ModuleEx { super(project.getPicoContainer(), parentDisposable); myProject = project; myPath = moduleFilePath; + + Extensions.instantiateArea(ExtensionAreas.IDEA_MODULE, this, null); + CoreEnvironment.registerExtensionPoint(Extensions.getArea(this), ModuleExtension.EP_NAME, ModuleExtension.class); + Disposer.register(parentDisposable, new Disposable() { + @Override + public void dispose() { + Extensions.disposeArea(CoreModule.this); + } + }); + + ModuleRootManagerImpl moduleRootManager = new ModuleRootManagerImpl(this, + DirectoryIndex.getInstance(project), + ProjectRootManagerImpl.getInstanceImpl(project), + VirtualFilePointerManager.getInstance()); + CoreEnvironment.registerComponentInstance(getPicoContainer(), ModuleRootManager.class, moduleRootManager); } @Override diff --git a/platform/projectModel-impl/src/com/intellij/core/ProjectModelEnvironment.java b/platform/projectModel-impl/src/com/intellij/core/ProjectModelEnvironment.java index 1c477a07814f..e56bb9becdd3 100644 --- a/platform/projectModel-impl/src/com/intellij/core/ProjectModelEnvironment.java +++ b/platform/projectModel-impl/src/com/intellij/core/ProjectModelEnvironment.java @@ -16,19 +16,33 @@ package com.intellij.core; import com.intellij.application.options.PathMacrosImpl; +import com.intellij.mock.MockProject; import com.intellij.openapi.application.PathMacros; +import com.intellij.openapi.components.ExtensionAreas; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.components.impl.ProjectPathMacroManager; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.impl.DirectoryIndex; +import com.intellij.openapi.roots.impl.DirectoryIndexExcludePolicy; +import com.intellij.openapi.roots.impl.DirectoryIndexImpl; +import com.intellij.openapi.roots.impl.ProjectRootManagerImpl; /** * @author yole */ public class ProjectModelEnvironment { public static void register(CoreEnvironment env) { + Extensions.registerAreaClass(ExtensionAreas.IDEA_MODULE, null); PathMacrosImpl pathMacros = new PathMacrosImpl(); env.registerApplicationComponent(PathMacros.class, pathMacros); - env.registerProjectComponent(ModuleManager.class, new CoreModuleManager(env.getProject(), env.getParentDisposable())); - env.registerProjectComponent(PathMacroManager.class, new ProjectPathMacroManager(pathMacros, env.getProject())); + final MockProject project = env.getProject(); + env.registerProjectComponent(ModuleManager.class, new CoreModuleManager(project, env.getParentDisposable())); + env.registerProjectComponent(PathMacroManager.class, new ProjectPathMacroManager(pathMacros, project)); + env.registerProjectExtensionPoint(DirectoryIndexExcludePolicy.EP_NAME, DirectoryIndexExcludePolicy.class); + DirectoryIndex index = new DirectoryIndexImpl(project); + env.registerProjectComponent(DirectoryIndex.class, index); + env.registerProjectComponent(ProjectRootManager.class, new ProjectRootManagerImpl(project, index)); } } From 306b9ada21abba52c07a429bbb39795529ccab8f Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Fri, 18 May 2012 16:07:44 +0400 Subject: [PATCH 10/63] use separate modificationCount for PSI and Document (fixes psifile-dependent CachedValues) --- .../src/com/intellij/psi/impl/source/PsiFileImpl.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index 2c05de57807b..5ba93fd8b982 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -73,6 +73,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF private IElementType myElementType; protected IElementType myContentElementType; + private long myModificationStamp; protected PsiFile myOriginalFile = null; private final FileViewProvider myViewProvider; @@ -354,7 +355,9 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF myStub = null; } - public void clearCaches() {} + public void clearCaches() { + myModificationStamp ++; + } @Override public String getText() { @@ -386,7 +389,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF @Override public long getModificationStamp() { - return getViewProvider().getModificationStamp(); + return myModificationStamp; } @Override From 7dd0bb241cc591ed8745ff3f7903e34d48b8275f Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 17 May 2012 19:02:38 +0400 Subject: [PATCH 11/63] cleanup --- .../TextEditorHighlightingPass.java | 2 ++ .../daemon/impl/LocalInspectionsPass.java | 3 ++- .../intellij/xml/actions/XmlSplitTagAction.java | 5 +++++ .../XmlSuppressableInspectionTool.java | 14 ++++++++++++-- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java b/platform/lang-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java index d40d70cb1723..fcda8e15f6b2 100644 --- a/platform/lang-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java +++ b/platform/lang-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java @@ -55,6 +55,7 @@ public abstract class TextEditorHighlightingPass implements HighlightingPass { this(project, document, true); } + @Override public final void collectInformation(ProgressIndicator progress) { if (!isValid()) return; //Document has changed. myDumb = DumbService.getInstance(myProject).isDumb(); @@ -88,6 +89,7 @@ public abstract class TextEditorHighlightingPass implements HighlightingPass { return true; } + @Override public final void applyInformationToEditor() { if (!isValid()) return; // Document has changed. if (DumbService.getInstance(myProject).isDumb() && !(this instanceof DumbAware)) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index f17a5504853a..ed110d1bd749 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -709,7 +709,8 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass return new ArrayList(result); } - List getInspectionTools(InspectionProfileWrapper profile) { + @NotNull + List getInspectionTools(@NotNull InspectionProfileWrapper profile) { final List tools = profile.getHighlightingLocalInspectionTools(myFile); for (Iterator iterator = tools.iterator(); iterator.hasNext(); ) { LocalInspectionToolWrapper tool = iterator.next(); diff --git a/xml/impl/src/com/intellij/xml/actions/XmlSplitTagAction.java b/xml/impl/src/com/intellij/xml/actions/XmlSplitTagAction.java index 8291ac3d4c9a..77ec93a89a50 100644 --- a/xml/impl/src/com/intellij/xml/actions/XmlSplitTagAction.java +++ b/xml/impl/src/com/intellij/xml/actions/XmlSplitTagAction.java @@ -36,16 +36,19 @@ import org.jetbrains.annotations.NotNull; */ public class XmlSplitTagAction implements IntentionAction { + @Override @NotNull public String getText() { return XmlBundle.message("xml.split.tag.intention.action"); } + @Override @NotNull public String getFamilyName() { return XmlBundle.message("xml.split.tag.intention.action"); } + @Override public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) { if (file instanceof XmlFile) { if (editor != null) { @@ -75,6 +78,7 @@ public class XmlSplitTagAction implements IntentionAction { return "html".equals(name) || "body".equals(name) || "title".equals(name); } + @Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { if (!CodeInsightUtilBase.prepareFileForWrite(file)) return; @@ -165,6 +169,7 @@ public class XmlSplitTagAction implements IntentionAction { return sb.toString(); } + @Override public boolean startInWriteAction() { return true; } diff --git a/xml/openapi/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java b/xml/openapi/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java index 26191bac3220..89a020872157 100644 --- a/xml/openapi/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java +++ b/xml/openapi/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java @@ -29,10 +29,12 @@ import org.jetbrains.annotations.NotNull; public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool implements CustomSuppressableInspectionTool { @NonNls static final String ALL = "ALL"; + @Override public SuppressIntentionAction[] getSuppressActions(final PsiElement element) { return new SuppressIntentionAction[]{new SuppressTag(), new SuppressForFile(getID()), new SuppressAllForFile()}; } + @Override public boolean isSuppressedFor(final PsiElement element) { return XmlSuppressionProvider.isSuppressed(element, getID()); } @@ -45,27 +47,30 @@ public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool } public static class SuppressTagStatic extends SuppressIntentionAction { - - private String id; + private final String id; public SuppressTagStatic(String id) { this.id = id; } + @Override @NotNull public String getText() { return InspectionsBundle.message("xml.suppressable.for.tag.title"); } + @Override @NotNull public String getFamilyName() { return getText(); } + @Override public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) { return PsiTreeUtil.getParentOfType(element, XmlTag.class) != null; } + @Override public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException { XmlSuppressionProvider.getProvider(element.getContainingFile()).suppressForTag(element, id); } @@ -78,20 +83,24 @@ public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool myInspectionId = inspectionId; } + @Override @NotNull public String getText() { return InspectionsBundle.message("xml.suppressable.for.file.title"); } + @Override @NotNull public String getFamilyName() { return getText(); } + @Override public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException { XmlSuppressionProvider.getProvider(element.getContainingFile()).suppressForFile(element, myInspectionId); } + @Override public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) { return element.isValid() && element.getContainingFile() instanceof XmlFile; } @@ -103,6 +112,7 @@ public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool super(ALL); } + @Override @NotNull public String getText() { return InspectionsBundle.message("xml.suppressable.all.for.file.title"); From a6657f836d2de9f0751d990f133a50f69e7bbc59 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 18 May 2012 13:09:28 +0400 Subject: [PATCH 12/63] rewire logic for ignoring changes in whitespace and comment into the ChangeLocalityDetector. --- .../impl/JavaChangeLocalityDetector.java | 11 ++++-- .../daemon/ChangeLocalityDetector.java | 10 +++++- .../impl/DefaultChangeLocalityDetector.java | 35 ++++++++++++++++++ .../daemon/impl/PsiChangeHandler.java | 24 ++++++------- .../src/META-INF/XmlPlugin.xml | 4 +-- .../xslt/impl/XsltChangeLocalityDetector.java | 3 +- resources/src/META-INF/IdeaPlugin.xml | 1 + .../xml/XmlChangeLocalityDetector.java | 36 +++++++++++++++++++ .../DefaultXmlSuppressionProvider.java | 9 ++++- 9 files changed, 112 insertions(+), 21 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java create mode 100644 xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java index 6a8f8244faca..1f06435e398a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java @@ -21,15 +21,20 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.daemon.ChangeLocalityDetector; import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class JavaChangeLocalityDetector implements ChangeLocalityDetector { @Override @Nullable - public PsiElement getChangeHighlightingDirtyScopeFor(final PsiElement element) { + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull final PsiElement element) { + // optimization PsiElement parent = element.getParent(); - if (element instanceof PsiCodeBlock && parent instanceof PsiMethod && !((PsiMethod)parent).isConstructor() && - parent.getParent() instanceof PsiClass && !(parent.getParent() instanceof PsiAnonymousClass)) { + if (element instanceof PsiCodeBlock + && parent instanceof PsiMethod + && !((PsiMethod)parent).isConstructor() + && parent.getParent() instanceof PsiClass + && !(parent.getParent() instanceof PsiAnonymousClass)) { // for changes inside method, rehighlight codeblock only // do not use this optimization for constructors and class initializers - to update non-initialized fields return parent; diff --git a/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java b/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java index b80a4b6fc9be..fedbd19f2f48 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java +++ b/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java @@ -20,9 +20,17 @@ package com.intellij.codeInsight.daemon; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public interface ChangeLocalityDetector { + /** + * @param changedElement + * @return the psi element (ancestor of the changedElement) which should be re-highlighted, or null if unsure. + * e.g. in Java we re-highlight enclosing code block only when element inside has changed. + * Note: do not traverse PSI tree upwards here, + * since this ChangeLocalityDetector will be called for the changed element and all its parents anyway. + */ @Nullable - PsiElement getChangeHighlightingDirtyScopeFor(PsiElement changedElement); + PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement); } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java new file mode 100644 index 000000000000..a822811aa845 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.daemon.impl; + +import com.intellij.codeInsight.daemon.ChangeLocalityDetector; +import com.intellij.codeInspection.SuppressionUtil; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import org.jetbrains.annotations.NotNull; + +public class DefaultChangeLocalityDetector implements ChangeLocalityDetector { + @Override + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement) { + if (changedElement instanceof PsiWhiteSpace || + changedElement instanceof PsiComment + && !changedElement.getText().contains(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) { + return changedElement; + } + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java index f148691cd732..956f39823ba5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java @@ -17,7 +17,6 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.daemon.ChangeLocalityDetector; -import com.intellij.codeInspection.SuppressionUtil; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; @@ -214,18 +213,9 @@ public class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable return; } - // optimization - if (whitespaceOptimizationAllowed && UpdateHighlightersUtil.isWhitespaceOptimizationAllowed(document)) { - if (child instanceof PsiWhiteSpace || - child instanceof PsiComment && !child.getText().contains(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) { - myFileStatusMap.markFileScopeDirty(document, child.getTextRange(), fileLength); - return; - } - } - - PsiElement element = child; + PsiElement element = whitespaceOptimizationAllowed && UpdateHighlightersUtil.isWhitespaceOptimizationAllowed(document) ? child : child.getParent(); while (true) { - if (element instanceof PsiFile || element instanceof PsiDirectory) { + if (element == null || element instanceof PsiFile || element instanceof PsiDirectory) { myFileStatusMap.markAllFilesDirty(); return; } @@ -242,10 +232,18 @@ public class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable @Nullable private static PsiElement getChangeHighlightingScope(PsiElement element) { + DefaultChangeLocalityDetector defaultDetector = null; for (ChangeLocalityDetector detector : Extensions.getExtensions(EP_NAME)) { + if (detector instanceof DefaultChangeLocalityDetector) { + // run default detector last + assert defaultDetector == null : defaultDetector; + defaultDetector = (DefaultChangeLocalityDetector)detector; + continue; + } final PsiElement scope = detector.getChangeHighlightingDirtyScopeFor(element); if (scope != null) return scope; } - return null; + assert defaultDetector != null : "com.intellij.codeInsight.daemon.impl.DefaultChangeLocalityDetector is unregistered"; + return defaultDetector.getChangeHighlightingDirtyScopeFor(element); } } diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index 6465f1f168f9..834e6e03ed0c 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -404,7 +404,7 @@ - + + diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java index c72f6ac58eb8..5b7dedcecae3 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java @@ -22,6 +22,7 @@ import com.intellij.psi.xml.XmlElementType; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; import org.intellij.lang.xpath.xslt.XsltSupport; +import org.jetbrains.annotations.NotNull; /* * Created by IntelliJ IDEA. @@ -30,7 +31,7 @@ import org.intellij.lang.xpath.xslt.XsltSupport; */ public class XsltChangeLocalityDetector implements ChangeLocalityDetector { @Override - public PsiElement getChangeHighlightingDirtyScopeFor(PsiElement changedElement) { + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement) { try { if (changedElement instanceof XmlToken && changedElement.getNode().getElementType() == XmlElementType.XML_ATTRIBUTE_VALUE_TOKEN) { final PsiElement grandParent = changedElement.getParent().getParent(); diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index cb3175edc39c..82372a8498d0 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -969,6 +969,7 @@ + diff --git a/xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java b/xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java new file mode 100644 index 000000000000..fb65aa55965d --- /dev/null +++ b/xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.xml; + +import com.intellij.codeInsight.daemon.ChangeLocalityDetector; +import com.intellij.codeInspection.DefaultXmlSuppressionProvider; +import com.intellij.lang.xml.XMLLanguage; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +public class XmlChangeLocalityDetector implements ChangeLocalityDetector { + @Override + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement) { + // rehighlight everything when inspection suppress comment changed + if (changedElement.getLanguage() instanceof XMLLanguage + && changedElement instanceof PsiComment + && changedElement.getText().contains(DefaultXmlSuppressionProvider.SUPPRESS_MARK)) { + return changedElement.getContainingFile(); + } + return null; + } +} diff --git a/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java b/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java index f1ce3969dfc2..6aa1a22ad909 100644 --- a/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java +++ b/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java @@ -37,16 +37,20 @@ import org.jetbrains.annotations.Nullable; */ public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider { + public static final String SUPPRESS_MARK = "suppress"; + @Override public boolean isProviderAvailable(PsiFile file) { return true; } + @Override public boolean isSuppressedFor(PsiElement element, String inspectionId) { final XmlTag tag = element instanceof XmlFile ? ((XmlFile)element).getRootTag() : PsiTreeUtil.getContextOfType(element, XmlTag.class, false); return tag != null && findSuppression(tag, inspectionId, element) != null; } + @Override public void suppressForFile(PsiElement element, String inspectionId) { final PsiFile file = element.getContainingFile(); final XmlDocument document = ((XmlFile)file).getDocument(); @@ -55,6 +59,7 @@ public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider { suppress(file, findFileSuppression(anchor, null, element), inspectionId, anchor.getTextRange().getStartOffset()); } + @Override public void suppressForTag(PsiElement element, String inspectionId) { final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class); assert tag != null; @@ -140,7 +145,9 @@ public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider { @NonNls protected String getPrefix() { - return "